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