1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright (c) 1996,1999-2000 by Sun Microsystems, Inc.
24 * All rights reserved.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 /*
30 * Main Transport Routine for DADA.
31 *
32 */
33
34 #include <sys/dada/dada.h>
35 #include <sys/thread.h>
36
37
38 #define A_TO_TRAN(ap) ((ap)->a_hba_tran)
39 #define P_TO_TRAN(pkt) ((pkt)->pkt_address.a_hba_tran)
40 #define P_TO_ADDR(pkt) (&((pkt)->pkt_address))
41
42
43 extern kmutex_t dcd_flag_nointr_mutex;
44 extern kcondvar_t dcd_flag_nointr_cv;
45
46 static void
dcd_flag_nointr_comp(struct dcd_pkt * pkt)47 dcd_flag_nointr_comp(struct dcd_pkt *pkt)
48 {
49
50 mutex_enter(&dcd_flag_nointr_mutex);
51
52 pkt->pkt_comp = NULL;
53
54 /*
55 * We need cv_broadcast, because there can be more than
56 * one thread sleeping on the cv. We will wake all of them.
57 * The correct one will continue and the reset will again go to
58 * sleep.
59 */
60 cv_broadcast(&dcd_flag_nointr_cv);
61 mutex_exit(&dcd_flag_nointr_mutex);
62 }
63
64
65 int
dcd_transport(struct dcd_pkt * pkt)66 dcd_transport(struct dcd_pkt *pkt)
67 {
68
69 struct dcd_address *ap = P_TO_ADDR(pkt);
70 extern int do_polled_io;
71 int rval;
72
73 /*
74 * Check if we are required to do polled I/O. We can
75 * get dcd_pkts that don't have the FLAG_NOINTR bit
76 * set in the pkt_flags. When do_polled_io is set
77 * we will probably be at a high IPL and not get any
78 * command completion interrupts. We force polled I/Os
79 * for such packets and do a callback of the completion
80 * routine ourselves.
81 */
82 if (!do_polled_io && ((pkt->pkt_flags & FLAG_NOINTR) == 0)) {
83 return ((*A_TO_TRAN(ap)->tran_start)(ap, pkt));
84 } else if ((curthread->t_flag & T_INTR_THREAD) || (do_polled_io) ||
85 (pkt->pkt_flags & FLAG_FORCENOINTR)) {
86
87 if (pkt->pkt_flags & FLAG_FORCENOINTR) {
88 /*
89 * FLAG_FORCENOINTR means we do not want to rely on
90 * device interrupts. Set the FLAG_NOINTR
91 * so the command gets completed in polled mode.
92 */
93 pkt->pkt_flags &= ~FLAG_FORCENOINTR;
94 pkt->pkt_flags |= FLAG_NOINTR;
95 }
96
97 /*
98 * If its an interrupt thread or we already have the
99 * the FLAG_NOINTR flag set, we go ahead and call the
100 * the hba's start routine directly. We force polling
101 * only if we have do_polled_io set and FLAG_NOINTR
102 * not set.
103 */
104 if (!do_polled_io || (pkt->pkt_flags & FLAG_NOINTR)) {
105 return ((*A_TO_TRAN(ap)->tran_start)(ap, pkt));
106 } else {
107 uint_t savef;
108 void (*savec)();
109 /*
110 * save the completion routine and pkt_flags
111 */
112 savef = pkt->pkt_flags;
113 savec = pkt->pkt_comp;
114 pkt->pkt_flags |= FLAG_NOINTR;
115 pkt->pkt_comp = 0;
116
117 rval = (*A_TO_TRAN(ap)->tran_start)(ap, pkt);
118
119 /*
120 * Restore the pkt_completion routine
121 * and pkt flags and call the completion
122 * routine.
123 */
124 pkt->pkt_comp = savec;
125 pkt->pkt_flags = savef;
126 (*pkt->pkt_comp)(pkt);
127 return (rval);
128 }
129 } else {
130 uint_t savef;
131 void (*savec)();
132 int status;
133
134 savef = pkt->pkt_flags;
135 savec = pkt->pkt_comp;
136
137 pkt->pkt_comp = dcd_flag_nointr_comp;
138 pkt->pkt_flags &= ~FLAG_NOINTR;
139 pkt->pkt_flags |= FLAG_IMMEDIATE_CB;
140
141 if ((status = (*A_TO_TRAN(ap)->tran_start)(ap, pkt)) ==
142 TRAN_ACCEPT) {
143 mutex_enter(& dcd_flag_nointr_mutex);
144 while (pkt->pkt_comp != NULL) {
145 cv_wait(&dcd_flag_nointr_cv,
146 &dcd_flag_nointr_mutex);
147 }
148 mutex_exit(&dcd_flag_nointr_mutex);
149 }
150 pkt->pkt_flags = savef;
151 pkt->pkt_comp = savec;
152 return (status);
153 }
154 }
155