xref: /titanic_50/usr/src/uts/common/io/scsi/impl/scsi_transport.c (revision 5bd3d01749cd2765999b591219b6bec291869744)
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 (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 /*
27  * Main Transport Routine for SCSA
28  */
29 #include <sys/scsi/scsi.h>
30 #include <sys/thread.h>
31 #include <sys/bitmap.h>
32 
33 #define	A_TO_TRAN(ap)	((ap)->a_hba_tran)
34 #define	P_TO_TRAN(pkt)	((pkt)->pkt_address.a_hba_tran)
35 #define	P_TO_ADDR(pkt)	(&((pkt)->pkt_address))
36 
37 #ifdef DEBUG
38 #define	SCSI_POLL_STAT
39 #endif
40 
41 #ifdef SCSI_POLL_STAT
42 int	scsi_poll_user;
43 int	scsi_poll_intr;
44 #endif
45 
46 int			scsi_pkt_bad_alloc_msg = 1;
47 extern	ulong_t		*scsi_pkt_bad_alloc_bitmap;
48 extern	kmutex_t	scsi_flag_nointr_mutex;
49 extern	kcondvar_t	scsi_flag_nointr_cv;
50 
51 extern int		do_polled_io;
52 
53 extern int		scsi_pkt_allow_naca;
54 extern uchar_t		scsi_cdb_size[];
55 #define	NACA_IS_SET(cdb)						\
56 	(((cdb)[scsi_cdb_size[GETGROUP((union scsi_cdb *)(cdb))] - 1]	\
57 	& CDB_FLAG_NACA) ? 1 : 0)
58 
59 /*
60  * we used to set the callback_done value to NULL after the callback
61  * but this interfered with esp/fas drivers that also set the callback
62  * to NULL to prevent callbacks during error recovery
63  * to prevent confusion, create a truly unique value.
64  * The scsi_callback_done() function is used to detect a packet
65  * completion being called a second time.
66  */
67 /* ARGSUSED */
68 void
scsi_callback_done(struct scsi_pkt * pkt)69 scsi_callback_done(struct scsi_pkt *pkt)
70 {
71 	cmn_err(CE_PANIC,
72 	    "%s: duplicate scsi_callback_done() on same scsi_pkt(9s)",
73 	    mod_containing_pc(caller()));
74 }
75 
76 #define	CALLBACK_DONE (scsi_callback_done)
77 
78 static void
scsi_flag_nointr_comp(struct scsi_pkt * pkt)79 scsi_flag_nointr_comp(struct scsi_pkt *pkt)
80 {
81 	mutex_enter(&scsi_flag_nointr_mutex);
82 	pkt->pkt_comp = CALLBACK_DONE;
83 	/*
84 	 * We need cv_broadcast, because there can be more
85 	 * than one thread sleeping on the cv. We
86 	 * will wake all of them. The correct  one will
87 	 * continue and the rest will again go to sleep.
88 	 */
89 	cv_broadcast(&scsi_flag_nointr_cv);
90 	mutex_exit(&scsi_flag_nointr_mutex);
91 }
92 
93 /*
94  * A packet can have FLAG_NOINTR set because of target driver or
95  * scsi_poll(). If FLAG_NOINTR is set and we are in user context,
96  * we can avoid busy waiting in HBA by replacing the callback
97  * function with our own function and resetting FLAG_NOINTR. We
98  * can't do this in interrupt context because cv_wait will
99  * sleep with CPU priority raised high and in case of some failure,
100  * the CPU will be stuck in high priority.
101  */
102 
103 int
scsi_transport(struct scsi_pkt * pkt)104 scsi_transport(struct scsi_pkt *pkt)
105 {
106 	struct scsi_address	*ap = P_TO_ADDR(pkt);
107 	int			rval = TRAN_ACCEPT;
108 	major_t			major;
109 
110 	/*
111 	 * Add an assertion check for debugging as use of the NACA flag
112 	 * can cause problems. If an initiator sets it but does not clear
113 	 * it, other initiators would end up waiting indefinitely for the
114 	 * first to clear ACA.
115 	 */
116 	if (!scsi_pkt_allow_naca) {
117 		ASSERT(!NACA_IS_SET(pkt->pkt_cdbp));
118 	}
119 
120 	/*
121 	 * The DDI does not allow drivers to allocate their own scsi_pkt(9S),
122 	 * a driver can't have *any* compiled in dependencies on the
123 	 * "sizeof (struct scsi_pkt)". While this has been the case for years,
124 	 * many drivers have still not been fixed (or have regressed - tempted
125 	 * by kmem_cache_alloc()).  The correct way to allocate a scsi_pkt
126 	 * is by calling scsi_hba_pkt_alloc(9F), or by implementing the
127 	 * tran_setup_pkt(9E) interfaces.
128 	 *
129 	 * The code below will identify drivers that violate this rule, and
130 	 * print a message. The message will identify broken drivers, and
131 	 * encourage getting these drivers fixed - after which this code
132 	 * can be removed. Getting HBA drivers fixed is important because
133 	 * broken drivers are an impediment to SCSA enhancement.
134 	 *
135 	 * We use the scsi_pkt_allocated_correctly() to determine if the
136 	 * scsi_pkt we are about to start was correctly allocated. The
137 	 * scsi_pkt_bad_alloc_bitmap is used to limit messages to one per
138 	 * driver per reboot, and with non-debug code we only check the
139 	 * first scsi_pkt.
140 	 */
141 	if (scsi_pkt_bad_alloc_msg) {
142 		major = ddi_driver_major(P_TO_TRAN(pkt)->tran_hba_dip);
143 		if (!BT_TEST(scsi_pkt_bad_alloc_bitmap, major) &&
144 		    !scsi_pkt_allocated_correctly(pkt)) {
145 			BT_SET(scsi_pkt_bad_alloc_bitmap, major);
146 			cmn_err(CE_WARN, "%s: violates DDI scsi_pkt(9S) "
147 			    "allocation rules",
148 			    ddi_driver_name(P_TO_TRAN(pkt)->tran_hba_dip));
149 		}
150 #ifndef	DEBUG
151 		/* On non-debug kernel, only check the first packet */
152 		BT_SET(scsi_pkt_bad_alloc_bitmap, major);
153 #endif	/* DEBUG */
154 	}
155 
156 	/* Some retryed packets come with this flag not cleared */
157 	pkt->pkt_flags &= ~FLAG_PKT_COMP_CALLED;
158 
159 	/*
160 	 * Check if we are required to do polled I/O. We can
161 	 * get scsi_pkts that don't have the FLAG_NOINTR bit
162 	 * set in the pkt_flags. When do_polled_io is set
163 	 * we will probably be at a high IPL and not get any
164 	 * command completion interrupts. We force polled I/Os
165 	 * for such packets and do a callback of the completion
166 	 * routine ourselves.
167 	 */
168 	if (!do_polled_io && ((pkt->pkt_flags & FLAG_NOINTR) == 0)) {
169 		return (*A_TO_TRAN(ap)->tran_start)(ap, pkt);
170 	} else if ((curthread->t_flag & T_INTR_THREAD) || do_polled_io) {
171 #ifdef SCSI_POLL_STAT
172 		mutex_enter(&scsi_flag_nointr_mutex);
173 		scsi_poll_intr++;
174 		mutex_exit(&scsi_flag_nointr_mutex);
175 #endif
176 		/*
177 		 * If its an interrupt thread or we already have the
178 		 * the FLAG_NOINTR flag set, we go ahead and call the
179 		 * the hba's start routine directly. We force polling
180 		 * only if we have do_polled_io set and FLAG_NOINTR
181 		 * not set.
182 		 */
183 		if (!do_polled_io || (pkt->pkt_flags & FLAG_NOINTR)) {
184 			return ((*A_TO_TRAN(ap)->tran_start)(ap, pkt));
185 		} else {
186 			uint_t		savef;
187 			void		(*savec)();
188 			/*
189 			 * save the completion routine and pkt_flags
190 			 */
191 			savef = pkt->pkt_flags;
192 			savec = pkt->pkt_comp;
193 			pkt->pkt_flags |= FLAG_NOINTR;
194 			pkt->pkt_comp = 0;
195 
196 			rval = (*A_TO_TRAN(ap)->tran_start)(ap, pkt);
197 
198 			/* only continue of transport accepted request */
199 			if (rval == TRAN_ACCEPT) {
200 				/*
201 				 * Restore the pkt_completion routine
202 				 * and pkt flags and call the completion
203 				 * routine.
204 				 */
205 				pkt->pkt_comp = savec;
206 				pkt->pkt_flags = savef;
207 				scsi_hba_pkt_comp(pkt);
208 				return (rval);
209 			}
210 
211 			/*
212 			 * rval was not TRAN_ACCEPT -- don't want command
213 			 * to be retried
214 			 */
215 			return (TRAN_FATAL_ERROR);
216 		}
217 	} else {
218 		uint_t	savef;
219 		void	(*savec)();
220 
221 #ifdef SCSI_POLL_STAT
222 		mutex_enter(&scsi_flag_nointr_mutex);
223 		scsi_poll_user++;
224 		mutex_exit(&scsi_flag_nointr_mutex);
225 #endif
226 		savef = pkt->pkt_flags;
227 		savec = pkt->pkt_comp;
228 
229 		pkt->pkt_comp = scsi_flag_nointr_comp;
230 		pkt->pkt_flags &= ~FLAG_NOINTR;
231 		pkt->pkt_flags |= FLAG_IMMEDIATE_CB;
232 
233 		if ((rval = (*A_TO_TRAN(ap)->tran_start)(ap, pkt)) ==
234 		    TRAN_ACCEPT) {
235 			mutex_enter(&scsi_flag_nointr_mutex);
236 			while (pkt->pkt_comp != CALLBACK_DONE) {
237 				cv_wait(&scsi_flag_nointr_cv,
238 				    &scsi_flag_nointr_mutex);
239 			}
240 			mutex_exit(&scsi_flag_nointr_mutex);
241 		}
242 
243 		pkt->pkt_flags = savef;
244 		pkt->pkt_comp = savec;
245 		return (rval);
246 	}
247 }
248