xref: /illumos-gate/usr/src/uts/common/io/usb/scsa2usb/usb_ms_cbi.c (revision 22f5594a529d50114d839d4ddecc2c499731a3d7)
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  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
22  * Use is subject to license terms.
23  */
24 
25 #pragma ident	"%Z%%M%	%I%	%E% SMI"
26 
27 /*
28  * scsa2usb_ms_cbi.c:
29  *
30  * This file implements USB Mass Storage Class
31  * Control Bulk Interrupt (CB/CBI) transport v1.0
32  * http://www.usb.org/developers/data/devclass/usbmass-cbi10.pdf
33  */
34 #include <sys/usb/usba/usbai_version.h>
35 #include <sys/scsi/scsi.h>
36 #include <sys/callb.h>		/* needed by scsa2usb.h */
37 #include <sys/strsubr.h>
38 
39 #include <sys/usb/usba.h>
40 #include <sys/usb/usba/usba_private.h>
41 #include <sys/usb/usba/usba_ugen.h>
42 
43 #include <sys/usb/clients/mass_storage/usb_cbi.h>
44 #include <sys/usb/scsa2usb/scsa2usb.h>
45 
46 /*
47  * Function Prototypes
48  */
49 int		scsa2usb_cbi_transport(scsa2usb_state_t *, scsa2usb_cmd_t *);
50 static int	scsa2usb_handle_cbi_status(usb_intr_req_t *);
51 static void	scsa2usb_cbi_reset_recovery(scsa2usb_state_t *);
52 static void	scsa2usb_cbi_handle_error(scsa2usb_state_t *, int, usb_cr_t);
53 static usb_intr_req_t *scsa2usb_cbi_start_intr_polling(scsa2usb_state_t *);
54 void		scsa2usb_cbi_stop_intr_polling(scsa2usb_state_t *);
55 
56 /* extern functions */
57 extern void	scsa2usb_setup_next_xfer(scsa2usb_state_t *, scsa2usb_cmd_t *);
58 extern int	scsa2usb_handle_data_start(scsa2usb_state_t *,
59 		    scsa2usb_cmd_t *, usb_bulk_req_t *);
60 extern void	scsa2usb_handle_data_done(scsa2usb_state_t *, scsa2usb_cmd_t *,
61 		    usb_bulk_req_t *);
62 extern usb_bulk_req_t *scsa2usb_init_bulk_req(scsa2usb_state_t *,
63 			    size_t, uint_t, usb_req_attrs_t, usb_flags_t);
64 extern int	scsa2usb_clear_ept_stall(scsa2usb_state_t *, uint_t,
65 		    usb_pipe_handle_t, char *);
66 extern void	scsa2usb_close_usb_pipes(scsa2usb_state_t *);
67 
68 #ifdef DEBUG	/* debugging information */
69 extern void	scsa2usb_print_cdb(scsa2usb_state_t *, scsa2usb_cmd_t *);
70 #endif	/* DEBUG */
71 
72 
73 /*
74  * scsa2usb_cbi_transport:
75  *	Implements the CB/CBI state machine by these steps:
76  *	a) Issues command to the device over control pipe.
77  *	b) Start Data Phase if applicable
78  *	c) Start Status Phase
79  *
80  *	returns TRAN_* values and not USB_SUCCESS/FAILURE
81  *
82  * scsa2usb_cbi_transport() handles the normal transitions or
83  * continuation after clearing stalls or error recovery.
84  *
85  * Command Phase:
86  *	prepare a valid command and transport it on default pipe
87  *	if error on default-pipe:
88  *		set pkt_reason to CMD_TRAN_ERR
89  *		new pkt state is SCSA2USB_PKT_DO_COMP
90  *		do reset recovery synchronously
91  *	else
92  *		proceed to data phase
93  *
94  * Data Phase:
95  *	if data in:
96  *		setup data in on bulkin
97  *	else if data out:
98  *		setup data out on bulkout
99  *
100  *	data: (in)
101  *		copy data transferred so far, no more data to transfer
102  *
103  *		if stall on bulkin pipe
104  *			terminate data transfers, set cmd_done
105  *			clear stall on bulkin syncrhonously
106  *		else if other exception
107  *			set pkt_reason to CMD_TRAN_ERR
108  *			new pkt state is SCSA2USB_PKT_DO_COMP
109  *			do reset recovery synchronously
110  *		else (no error)
111  *			receive status
112  *
113  *	 data: (out)
114  *		if stall on bulkout pipe
115  *			terminate data transfers
116  *			clear stall on bulkout synchronously USBA
117  *		else if other exception
118  *			set pkt_reason to CMD_TRAN_ERR
119  *			new pkt state is SCSA2USB_PKT_DO_COMP
120  *			do reset recovery synchronously
121  *		else (no error)
122  *			receive status
123  *
124  * Status Phase: (on Interrupt pipe for CBI devices only)
125  *	if error
126  *		if stall
127  *			new pkt state is SCSA2USB_PKT_DO_COMP
128  *			clear stall on interrupt pipe
129  *		else
130  *			set pkt_reason to CMD_TRAN_ERR
131  *			new pkt state is SCSA2USB_PKT_DO_COMP
132  *			do reset recovery synchronously
133  *	else (no error)
134  *		goto read status
135  *
136  * read status:
137  *	if not OK or phase error
138  *		new pkt state is SCSA2USB_PKT_DO_COMP
139  *		set pkt reason CMD_TRAN_ERR
140  *		reset recovery synchronously
141  *	else (status ok)
142  *		goto  SCSA2USB_PKT_DO_COMP
143  *
144  * The reset recovery walks sequentially thru device reset, clearing
145  * stalls and pipe resets. When the reset recovery completes we return
146  * to the taskq thread.
147  *
148  * Clearing stalls clears the stall condition, resets the pipe, and
149  * then returns to the transport.
150  */
151 int
152 scsa2usb_cbi_transport(scsa2usb_state_t *scsa2usbp, scsa2usb_cmd_t *cmd)
153 {
154 	int			i, rval = TRAN_ACCEPT;
155 	mblk_t			*data;
156 	usb_cr_t		completion_reason;
157 	usb_cb_flags_t		cb_flags;
158 	usb_bulk_req_t		*data_req;
159 	usb_intr_req_t		*status_req;
160 
161 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
162 	    "scsa2usb_cbi_transport: cmd = 0x%p", (void *)cmd);
163 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
164 
165 Cmd_Phase:
166 	if (!(SCSA2USB_DEVICE_ACCESS_OK(scsa2usbp))) {
167 
168 		return (TRAN_FATAL_ERROR);
169 	}
170 
171 	/*
172 	 * Start command phase (C - in CBI)
173 	 */
174 	data = allocb_wait(CBI_CLASS_CMD_LEN, BPRI_LO, STR_NOSIG, NULL);
175 
176 	/* Initialize the data */
177 	for (i = 0; i < CBI_CLASS_CMD_LEN; i++) {
178 		*data->b_wptr++ = cmd->cmd_cdb[i];
179 	}
180 
181 	SCSA2USB_PRINT_CDB(scsa2usbp, cmd);	/* print the CDB */
182 
183 	/* Send the Command to the device */
184 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
185 	rval = usb_pipe_sync_ctrl_xfer(scsa2usbp->scsa2usb_dip,
186 	    scsa2usbp->scsa2usb_default_pipe,
187 	    CBI_REQUEST_TYPE,			/* bmRequestType */
188 	    0,					/* bRequest */
189 	    CBI_WVALUE,				/* wValue */
190 	    scsa2usbp->scsa2usb_intfc_num,	/* wIndex */
191 	    CBI_CLASS_CMD_LEN,			/* wLength */
192 	    &data,				/* data */
193 	    USB_ATTRS_PIPE_RESET,		/* attributes */
194 	    &completion_reason, &cb_flags, USB_FLAGS_SLEEP);
195 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
196 
197 	USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
198 	    "scsa2usb_cbi_transport: sent cmd = 0x%x  rval = %d",
199 	    cmd->cmd_cdb[SCSA2USB_OPCODE], rval);
200 
201 	SCSA2USB_FREE_MSG(data);	/* get rid of the data */
202 	if (rval != USB_SUCCESS) {
203 		scsa2usb_cbi_handle_error(scsa2usbp, rval, completion_reason);
204 
205 		return (TRAN_FATAL_ERROR);
206 	}
207 
208 	/*
209 	 * Xferred command to the device.
210 	 * Start data phase (B - in CBI)
211 	 */
212 
213 	/*
214 	 * we've not transferred any data yet; updated in
215 	 * scsa2usb_handle_data_done
216 	 */
217 	cmd->cmd_resid_xfercount = 0;
218 
219 	/* if data to be xferred ? */
220 	if (cmd->cmd_xfercount) {
221 
222 		/* Initialize a bulk_req_t */
223 		data_req = scsa2usb_init_bulk_req(scsa2usbp, 0,
224 		    cmd->cmd_timeout, USB_ATTRS_PIPE_RESET, USB_FLAGS_SLEEP);
225 
226 		/* start I/O to/from the device */
227 		rval = scsa2usb_handle_data_start(scsa2usbp, cmd,
228 		    data_req);
229 		/* handle data returned */
230 		scsa2usb_handle_data_done(scsa2usbp, cmd,
231 		    data_req);
232 		if (rval != USB_SUCCESS) {
233 			/*
234 			 * we ran into an error and it wasn't a STALL
235 			 */
236 			if (data_req->bulk_completion_reason == USB_CR_STALL) {
237 				if (scsa2usbp->scsa2usb_cur_pkt) {
238 					scsa2usbp->scsa2usb_cur_pkt->
239 					    pkt_reason = CMD_TRAN_ERR;
240 				}
241 			} else {
242 				scsa2usb_cbi_handle_error(scsa2usbp,
243 				    rval, data_req->bulk_completion_reason);
244 
245 				/* get rid of req */
246 				SCSA2USB_FREE_BULK_REQ(data_req);
247 
248 				return (TRAN_FATAL_ERROR);
249 			}
250 		}
251 
252 		SCSA2USB_FREE_BULK_REQ(data_req); /* get rid of bulk_req */
253 	}
254 
255 	/* CB devices don't do status over interrupt pipe */
256 	if (SCSA2USB_IS_CB(scsa2usbp)) {
257 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
258 		    "scsa2usb_cbi_transport: CB done rval = %d", rval);
259 		goto end_it;
260 	}
261 
262 	/*
263 	 * Start status phase (I - in CBI)
264 	 */
265 
266 	/* Get Status over interrupt pipe */
267 	if ((status_req = scsa2usb_cbi_start_intr_polling(scsa2usbp)) == NULL) {
268 
269 		return (TRAN_FATAL_ERROR); /* lack of better return code */
270 	}
271 
272 	rval = scsa2usb_handle_cbi_status(status_req);
273 
274 	usb_free_intr_req(status_req);
275 
276 	/* stop interrupt pipe polling (CBI only) */
277 	if (SCSA2USB_IS_CBI(scsa2usbp)) {
278 		scsa2usb_cbi_stop_intr_polling(scsa2usbp);
279 	}
280 
281 end_it:
282 	if ((rval == USB_SUCCESS) &&		/* CSW was ok */
283 	    (scsa2usbp->scsa2usb_cur_pkt->pkt_reason == CMD_CMPLT) &&
284 	    (cmd->cmd_xfercount != 0) &&	/* more data to xfer */
285 	    !cmd->cmd_done) {			/* we aren't done yet */
286 		scsa2usb_setup_next_xfer(scsa2usbp, cmd);
287 		goto Cmd_Phase;
288 	} else {
289 		if (SCSA2USB_IS_CB(scsa2usbp)) {
290 			cmd->cmd_done = 1;
291 			SCSA2USB_SET_PKT_DO_COMP_STATE(scsa2usbp);
292 		}
293 	}
294 
295 	return (rval == USB_SUCCESS ? TRAN_ACCEPT : TRAN_FATAL_ERROR);
296 }
297 
298 
299 /*
300  * scsa2usb_cbi_handle_error:
301  *	handle errors from transport that are not STALL conditions
302  */
303 static void
304 scsa2usb_cbi_handle_error(scsa2usb_state_t *scsa2usbp, int rval, usb_cr_t cr)
305 {
306 	struct scsi_pkt	*pkt = scsa2usbp->scsa2usb_cur_pkt;
307 
308 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
309 	    "scsa2usb_cbi_handle_error: data error %d cr = %d", rval, cr);
310 
311 	SCSA2USB_SET_PKT_DO_COMP_STATE(scsa2usbp);
312 
313 	/* do reset error recovery */
314 	switch (cr) {
315 	case USB_CR_STALL:
316 		if (pkt) {
317 			pkt->pkt_reason = CMD_TRAN_ERR;
318 			*(pkt->pkt_scbp) = STATUS_CHECK;
319 		}
320 		break;
321 	case USB_CR_TIMEOUT:
322 		if (pkt) {
323 			pkt->pkt_reason = CMD_TIMEOUT;
324 			pkt->pkt_statistics |= STAT_TIMEOUT;
325 		}
326 		break;
327 	case USB_CR_DEV_NOT_RESP:
328 		scsa2usb_cbi_stop_intr_polling(scsa2usbp);
329 		if (pkt) {
330 			pkt->pkt_reason = CMD_DEV_GONE;
331 			/* scsi_poll relies on this */
332 			pkt->pkt_state = STATE_GOT_BUS;
333 		}
334 		break;
335 	default:
336 		if (pkt) {
337 			pkt->pkt_reason = CMD_TRAN_ERR;
338 		}
339 		scsa2usb_cbi_reset_recovery(scsa2usbp);
340 	}
341 }
342 
343 
344 /*
345  * scsa2usb_cbi_start_intr_polling:
346  *	start polling asynchronously without notification
347  */
348 static usb_intr_req_t *
349 scsa2usb_cbi_start_intr_polling(scsa2usb_state_t *scsa2usbp)
350 {
351 	int rval;
352 	usb_pipe_state_t   pipe_state;
353 	usb_intr_req_t *req = NULL;
354 
355 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
356 	    "scsa2usb_cbi_start_intr_polling:");
357 
358 	if (!SCSA2USB_IS_CBI(scsa2usbp)) {
359 
360 		return (NULL);
361 	}
362 
363 	req = usb_alloc_intr_req(scsa2usbp->scsa2usb_dip, 0, USB_FLAGS_SLEEP);
364 	req->intr_client_private = (usb_opaque_t)scsa2usbp;
365 	req->intr_attributes = USB_ATTRS_ONE_XFER | USB_ATTRS_PIPE_RESET |
366 	    USB_ATTRS_SHORT_XFER_OK;
367 	req->intr_len = scsa2usbp->scsa2usb_intr_ept.wMaxPacketSize;
368 	req->intr_timeout = 20;	/* arbitrary large for now */
369 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
370 
371 	if ((rval = usb_pipe_intr_xfer(scsa2usbp->scsa2usb_intr_pipe, req,
372 	    USB_FLAGS_SLEEP)) != USB_SUCCESS) {
373 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
374 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
375 		    "polling failed rval: %d", rval);
376 
377 		/* clear stall */
378 		if (req->intr_completion_reason == USB_CR_STALL) {
379 			(void) scsa2usb_clear_ept_stall(scsa2usbp,
380 			    scsa2usbp->scsa2usb_intr_ept.bEndpointAddress,
381 			    scsa2usbp->scsa2usb_intr_pipe, "intr");
382 		}
383 
384 		/* handle other errors here */
385 		scsa2usb_cbi_handle_error(scsa2usbp, rval,
386 		    req->intr_completion_reason);
387 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
388 
389 		usb_free_intr_req(req);
390 		req = NULL;
391 	}
392 
393 	rval = usb_pipe_get_state(scsa2usbp->scsa2usb_intr_pipe,
394 	    &pipe_state, USB_FLAGS_SLEEP);
395 	if (pipe_state != USB_PIPE_STATE_ACTIVE) {
396 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
397 		    "intr pipes state: %d, rval: %d", pipe_state, rval);
398 	}
399 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
400 
401 	return (req);
402 }
403 
404 
405 /*
406  * scsa2usb_cbi_stop_intr_polling:
407  *	Stop polling on interrupt pipe (for status)
408  */
409 void
410 scsa2usb_cbi_stop_intr_polling(scsa2usb_state_t *scsa2usbp)
411 {
412 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
413 	    "scsa2usb_cbi_stop_intr_polling:");
414 
415 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
416 
417 	if (!SCSA2USB_IS_CBI(scsa2usbp)) {
418 
419 		return;
420 	}
421 
422 	if (scsa2usbp->scsa2usb_intr_pipe) {
423 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
424 		usb_pipe_stop_intr_polling(scsa2usbp->scsa2usb_intr_pipe,
425 		    USB_FLAGS_SLEEP);
426 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
427 	}
428 }
429 
430 
431 /*
432  * scsa2usb_handle_cbi_status:
433  *	Handle CBI status results
434  */
435 static int
436 scsa2usb_handle_cbi_status(usb_intr_req_t *req)
437 {
438 	int rval = USB_SUCCESS;
439 	int status;
440 	char *msg;
441 	scsa2usb_cmd_t *cmd;
442 	scsa2usb_state_t *scsa2usbp = (scsa2usb_state_t *)
443 	    req->intr_client_private;
444 
445 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
446 	    "scsa2usb_handle_cbi_status: req: 0x%p", (void *)req);
447 
448 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
449 	ASSERT(req->intr_data != NULL);
450 
451 	cmd = PKT2CMD(scsa2usbp->scsa2usb_cur_pkt);
452 	status = *(req->intr_data->b_rptr + 1) & CBI_STATUS_MASK;
453 
454 	/*
455 	 * CBI status contains ASC and ASCQ.
456 	 * SCMD_REQUEST_SENSE and SCMD_INQUIRY don't affect the sense data
457 	 * on CBI devices. So, we can ignore that info for these 2 commands.
458 	 *
459 	 * (See details in UFI spec section 3.5 - that says that INQUIRY,
460 	 * SEND_DIAG, and REQUEST_SENSE ought to be supported by any deivce
461 	 * irrespective).
462 	 */
463 	if ((cmd->cmd_cdb[SCSA2USB_OPCODE] == SCMD_REQUEST_SENSE) ||
464 	    (cmd->cmd_cdb[SCSA2USB_OPCODE] == SCMD_INQUIRY)) {
465 		USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
466 		    "scsa2usb_handle_cbi_status: CBI STATUS = (0x%x, 0x%x)",
467 		    *(req->intr_data->b_rptr), *(req->intr_data->b_rptr+1));
468 
469 		SCSA2USB_SET_PKT_DO_COMP_STATE(scsa2usbp);
470 
471 		return (USB_SUCCESS);
472 	}
473 
474 	switch (status) {
475 	case CBI_STATUS_PASS:
476 		msg = "PASSED";
477 		/* non-zero command completion interrupt */
478 		if (*(req->intr_data->b_rptr)) {
479 			*(scsa2usbp->scsa2usb_cur_pkt->pkt_scbp) = STATUS_CHECK;
480 			cmd->cmd_done = 1;
481 		}
482 		break;
483 	case CBI_STATUS_FAILED:
484 	case CBI_STATUS_PERSISTENT_FAIL:
485 		msg = (status == CBI_STATUS_PERSISTENT_FAIL) ?
486 		    "PERSISTENT_FAILURE" : "FAILED";
487 		*(scsa2usbp->scsa2usb_cur_pkt->pkt_scbp) = STATUS_CHECK;
488 		cmd->cmd_done = 1;
489 		break;
490 	case CBI_STATUS_PHASE_ERR:
491 		msg = "PHASE_ERR";
492 		scsa2usb_cbi_reset_recovery(scsa2usbp);
493 		rval = USB_FAILURE;
494 		break;
495 	}
496 
497 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
498 	    "CBI STATUS = 0x%x %s (0x%x, 0x%x)", status, msg,
499 	    *(req->intr_data->b_rptr), *(req->intr_data->b_rptr+1));
500 
501 	/* we are done and ready to callback */
502 	SCSA2USB_SET_PKT_DO_COMP_STATE(scsa2usbp);
503 
504 	return (rval);
505 }
506 
507 
508 /*
509  * scsa2usb_cbi_reset_recovery:
510  *	Reset the USB device in case of errors.
511  */
512 static void
513 scsa2usb_cbi_reset_recovery(scsa2usb_state_t *scsa2usbp)
514 {
515 	int		i, rval;
516 	mblk_t		*cdb;
517 	usb_cr_t	completion_reason;
518 	usb_cb_flags_t	cb_flags;
519 
520 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
521 	    "scsa2usb_cbi_reset_recovery: (0x%p)", (void *)scsa2usbp);
522 
523 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
524 
525 	if (!(SCSA2USB_DEVICE_ACCESS_OK(scsa2usbp))) {
526 
527 		return;
528 	}
529 
530 	if (scsa2usbp->scsa2usb_cur_pkt) {
531 		scsa2usbp->scsa2usb_cur_pkt->pkt_statistics |= STAT_DEV_RESET;
532 	}
533 
534 	/* Allocate an mblk for CBR */
535 	cdb = allocb_wait(CBI_CLASS_CMD_LEN, BPRI_LO, STR_NOSIG, NULL);
536 
537 	*cdb->b_wptr++ = SCMD_SDIAG;	/* Set it to DIAG */
538 	*cdb->b_wptr++ = CBI_SELF_TEST;	/* Set it to reset */
539 	for (i = 2; i < CBI_CLASS_CMD_LEN; i++) {
540 		*cdb->b_wptr++ = CBI_CBR_VALUE;	/* Set it to 0xff */
541 	}
542 
543 	scsa2usbp->scsa2usb_pipe_state = SCSA2USB_PIPE_DEV_RESET;
544 
545 	/*
546 	 * Send a Reset request to the device
547 	 */
548 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
549 	rval = usb_pipe_sync_ctrl_xfer(scsa2usbp->scsa2usb_dip,
550 	    scsa2usbp->scsa2usb_default_pipe,
551 	    CBI_REQUEST_TYPE,			/* bmRequestType */
552 	    0,					/* bRequest */
553 	    CBI_WVALUE,				/* wValue */
554 	    scsa2usbp->scsa2usb_intfc_num,	/* wIndex address */
555 	    CBI_CLASS_CMD_LEN,			/* wLength */
556 	    &cdb,				/* data to be sent */
557 	    0, &completion_reason, &cb_flags, 0);
558 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
559 
560 	USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
561 	    "\tCBI RESET: rval = %x cr = %x", rval, completion_reason);
562 	if (rval != USB_SUCCESS) {
563 		goto exc_exit;
564 	}
565 
566 	/* reset and clear STALL on bulk-in pipe */
567 	rval = scsa2usb_clear_ept_stall(scsa2usbp,
568 	    scsa2usbp->scsa2usb_bulkin_ept.bEndpointAddress,
569 	    scsa2usbp->scsa2usb_bulkin_pipe, "bulk-in");
570 	USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
571 	    "\tclear stall on bulk-in pipe: %d", rval);
572 	if (rval != USB_SUCCESS) {
573 		goto exc_exit;
574 	}
575 
576 	/* reset and clear STALL on bulk-out pipe */
577 	rval = scsa2usb_clear_ept_stall(scsa2usbp,
578 	    scsa2usbp->scsa2usb_bulkout_ept.bEndpointAddress,
579 	    scsa2usbp->scsa2usb_bulkout_pipe, "bulk-out");
580 	USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
581 	    "\tclear stall on bulk-out pipe: %d", rval);
582 	if (rval != USB_SUCCESS) {
583 		goto exc_exit;
584 	}
585 
586 	/* reset and clear STALL on interrupt pipe */
587 	if (SCSA2USB_IS_CBI(scsa2usbp)) {
588 		rval = scsa2usb_clear_ept_stall(scsa2usbp,
589 		    scsa2usbp->scsa2usb_intr_ept.bEndpointAddress,
590 		    scsa2usbp->scsa2usb_intr_pipe, "intr");
591 
592 		USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
593 		    "\tclear stall on intr pipe:  %d", rval);
594 	}
595 
596 exc_exit:
597 	SCSA2USB_FREE_MSG(cdb);	/* Free the data */
598 	scsa2usbp->scsa2usb_pipe_state &= ~SCSA2USB_PIPE_DEV_RESET;
599 }
600