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