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  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * Main Transport Routine for SCSA
30  */
31 #include <sys/scsi/scsi.h>
32 #include <sys/thread.h>
33 #include <sys/bitmap.h>
34 
35 #define	A_TO_TRAN(ap)	((ap)->a_hba_tran)
36 #define	P_TO_TRAN(pkt)	((pkt)->pkt_address.a_hba_tran)
37 #define	P_TO_ADDR(pkt)	(&((pkt)->pkt_address))
38 
39 #ifdef DEBUG
40 #define	SCSI_POLL_STAT
41 #endif
42 
43 #ifdef SCSI_POLL_STAT
44 int	scsi_poll_user;
45 int	scsi_poll_intr;
46 #endif
47 
48 int			scsi_pkt_bad_alloc_msg = 1;
49 extern	ulong_t		*scsi_pkt_bad_alloc_bitmap;
50 extern	kmutex_t	scsi_flag_nointr_mutex;
51 extern	kcondvar_t	scsi_flag_nointr_cv;
52 
53 extern int		do_polled_io;
54 
55 /*
56  * we used to set the callback_done value to NULL after the callback
57  * but this interfered with esp/fas drivers that also set the callback
58  * to NULL to prevent callbacks during error recovery
59  * to prevent confusion, create a truly unique value
60  */
61 static int scsi_callback_done;
62 #define	CALLBACK_DONE ((void (*)(struct scsi_pkt *))(&scsi_callback_done))
63 
64 static void
65 scsi_flag_nointr_comp(struct scsi_pkt *pkt)
66 {
67 	mutex_enter(&scsi_flag_nointr_mutex);
68 	pkt->pkt_comp = CALLBACK_DONE;
69 	/*
70 	 * We need cv_broadcast, because there can be more
71 	 * than one thread sleeping on the cv. We
72 	 * will wake all of them. The correct  one will
73 	 * continue and the rest will again go to sleep.
74 	 */
75 	cv_broadcast(&scsi_flag_nointr_cv);
76 	mutex_exit(&scsi_flag_nointr_mutex);
77 }
78 
79 static void
80 scsi_consistent_comp(struct scsi_pkt *pkt)
81 {
82 	struct scsi_pkt_cache_wrapper *pcw =
83 	    (struct scsi_pkt_cache_wrapper *)pkt;
84 
85 	pkt->pkt_comp = pcw->pcw_orig_comp;
86 	scsi_sync_pkt(pkt);
87 	(*pkt->pkt_comp)(pkt);
88 }
89 
90 /*
91  * A packet can have FLAG_NOINTR set because of target driver or
92  * scsi_poll(). If FLAG_NOINTR is set and we are in user context,
93  * we can avoid busy waiting in HBA by replacing the callback
94  * function with our own function and resetting FLAG_NOINTR. We
95  * can't do this in interrupt context because cv_wait will
96  * sleep with CPU priority raised high and in case of some failure,
97  * the CPU will be stuck in high priority.
98  */
99 
100 int
101 scsi_transport(struct scsi_pkt *pkt)
102 {
103 	struct scsi_address	*ap = P_TO_ADDR(pkt);
104 	int			rval = TRAN_ACCEPT;
105 	major_t			major;
106 
107 	/*
108 	 * The DDI does not allow drivers to allocate their own scsi_pkt(9S),
109 	 * a driver can't have *any* compiled in dependencies on the
110 	 * "sizeof (struct scsi_pkt)". While this has been the case for years,
111 	 * many drivers have still not been fixed (or have regressed - tempted
112 	 * by kmem_cache_alloc()).  The correct way to allocate a scsi_pkt
113 	 * is by calling scsi_hba_pkt_alloc(9F), or by implementing the
114 	 * tran_setup_pkt(9E) interfaces.
115 	 *
116 	 * The code below will identify drivers that violate this rule, and
117 	 * print a message. The message will identify broken drivers, and
118 	 * encourage getting these drivers fixed - after which this code
119 	 * can be removed. Getting HBA drivers fixed is important because
120 	 * broken drivers are an impediment to SCSA enhancement.
121 	 *
122 	 * We use the scsi_pkt_allocated_correctly() to determine if the
123 	 * scsi_pkt we are about to start was correctly allocated. The
124 	 * scsi_pkt_bad_alloc_bitmap is used to limit messages to one per
125 	 * driver per reboot, and with non-debug code we only check the
126 	 * first scsi_pkt.
127 	 */
128 	if (scsi_pkt_bad_alloc_msg) {
129 		major = ddi_driver_major(P_TO_TRAN(pkt)->tran_hba_dip);
130 		if (!BT_TEST(scsi_pkt_bad_alloc_bitmap, major) &&
131 		    !scsi_pkt_allocated_correctly(pkt)) {
132 			BT_SET(scsi_pkt_bad_alloc_bitmap, major);
133 			cmn_err(CE_WARN, "%s: violates DDI scsi_pkt(9S) "
134 			    "allocation rules",
135 			    ddi_driver_name(P_TO_TRAN(pkt)->tran_hba_dip));
136 		}
137 #ifndef	DEBUG
138 		/* On non-debug kernel, only check the first packet */
139 		BT_SET(scsi_pkt_bad_alloc_bitmap, major);
140 #endif	/* DEBUG */
141 	}
142 
143 	/* determine if we need to sync the data on the HBA's behalf */
144 	if ((pkt->pkt_dma_flags & DDI_DMA_CONSISTENT) &&
145 	    ((pkt->pkt_comp) != NULL) &&
146 	    ((P_TO_TRAN(pkt)->tran_setup_pkt) != NULL)) {
147 		struct scsi_pkt_cache_wrapper *pcw =
148 		    (struct scsi_pkt_cache_wrapper *)pkt;
149 
150 		_NOTE(SCHEME_PROTECTS_DATA("unique per pkt", \
151 			scsi_pkt_cache_wrapper::pcw_orig_comp));
152 
153 		pcw->pcw_orig_comp = pkt->pkt_comp;
154 		pkt->pkt_comp = scsi_consistent_comp;
155 	}
156 	/*
157 	 * Check if we are required to do polled I/O. We can
158 	 * get scsi_pkts that don't have the FLAG_NOINTR bit
159 	 * set in the pkt_flags. When do_polled_io is set
160 	 * we will probably be at a high IPL and not get any
161 	 * command completion interrupts. We force polled I/Os
162 	 * for such packets and do a callback of the completion
163 	 * routine ourselves.
164 	 */
165 	if (!do_polled_io && ((pkt->pkt_flags & FLAG_NOINTR) == 0)) {
166 		return (*A_TO_TRAN(ap)->tran_start)(ap, pkt);
167 	} else if ((curthread->t_flag & T_INTR_THREAD) || do_polled_io) {
168 #ifdef SCSI_POLL_STAT
169 		mutex_enter(&scsi_flag_nointr_mutex);
170 		scsi_poll_intr++;
171 		mutex_exit(&scsi_flag_nointr_mutex);
172 #endif
173 		/*
174 		 * If its an interrupt thread or we already have the
175 		 * the FLAG_NOINTR flag set, we go ahead and call the
176 		 * the hba's start routine directly. We force polling
177 		 * only if we have do_polled_io set and FLAG_NOINTR
178 		 * not set.
179 		 */
180 		if (!do_polled_io || (pkt->pkt_flags & FLAG_NOINTR)) {
181 			return ((*A_TO_TRAN(ap)->tran_start)(ap, pkt));
182 		} else {
183 			uint_t		savef;
184 			void		(*savec)();
185 			/*
186 			 * save the completion routine and pkt_flags
187 			 */
188 			savef = pkt->pkt_flags;
189 			savec = pkt->pkt_comp;
190 			pkt->pkt_flags |= FLAG_NOINTR;
191 			pkt->pkt_comp = 0;
192 
193 			rval = (*A_TO_TRAN(ap)->tran_start)(ap, pkt);
194 
195 			/* only continue of transport accepted request */
196 			if (rval == TRAN_ACCEPT) {
197 				/*
198 				 * Restore the pkt_completion routine
199 				 * and pkt flags and call the completion
200 				 * routine.
201 				 */
202 				pkt->pkt_comp = savec;
203 				pkt->pkt_flags = savef;
204 
205 				if (pkt->pkt_comp != NULL) {
206 					(*pkt->pkt_comp)(pkt);
207 				}
208 
209 				return (rval);
210 			}
211 
212 			/*
213 			 * rval was not TRAN_ACCEPT -- don't want command
214 			 * to be retried
215 			 */
216 			return (TRAN_FATAL_ERROR);
217 		}
218 	} else {
219 		uint_t	savef;
220 		void	(*savec)();
221 		int	status;
222 
223 #ifdef SCSI_POLL_STAT
224 		mutex_enter(&scsi_flag_nointr_mutex);
225 		scsi_poll_user++;
226 		mutex_exit(&scsi_flag_nointr_mutex);
227 #endif
228 		savef = pkt->pkt_flags;
229 		savec = pkt->pkt_comp;
230 
231 		pkt->pkt_comp = scsi_flag_nointr_comp;
232 		pkt->pkt_flags &= ~FLAG_NOINTR;
233 		pkt->pkt_flags |= FLAG_IMMEDIATE_CB;
234 
235 		if ((status = (*A_TO_TRAN(ap)->tran_start)(ap, pkt)) ==
236 		    TRAN_ACCEPT) {
237 			mutex_enter(&scsi_flag_nointr_mutex);
238 			while (pkt->pkt_comp != CALLBACK_DONE) {
239 				cv_wait(&scsi_flag_nointr_cv,
240 				    &scsi_flag_nointr_mutex);
241 			}
242 			mutex_exit(&scsi_flag_nointr_mutex);
243 		}
244 
245 		pkt->pkt_flags = savef;
246 		pkt->pkt_comp = savec;
247 		return (status);
248 	}
249 }
250