10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
54834Sfb209375 * Common Development and Distribution License (the "License").
64834Sfb209375 * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate *
21*9511SFen-Ye.Bao@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
220Sstevel@tonic-gate * Use is subject to license terms.
230Sstevel@tonic-gate */
240Sstevel@tonic-gate
250Sstevel@tonic-gate
260Sstevel@tonic-gate /*
270Sstevel@tonic-gate * scsa2usb_ms_bulkonly.c:
280Sstevel@tonic-gate *
290Sstevel@tonic-gate * This file implements USB Mass Storage Class
300Sstevel@tonic-gate * Bulk Only (BO) transport v1.0
310Sstevel@tonic-gate * http://www.usb.org/developers/data/devclass/usbmassbulk_10.pdf
320Sstevel@tonic-gate */
330Sstevel@tonic-gate #include <sys/usb/usba/usbai_version.h>
340Sstevel@tonic-gate #include <sys/scsi/scsi.h>
350Sstevel@tonic-gate #include <sys/callb.h> /* needed by scsa2usb.h */
360Sstevel@tonic-gate #include <sys/strsubr.h>
377492SZhigang.Lu@Sun.COM #include <sys/strsun.h>
380Sstevel@tonic-gate
390Sstevel@tonic-gate #include <sys/usb/usba.h>
400Sstevel@tonic-gate #include <sys/usb/usba/usba_private.h>
410Sstevel@tonic-gate #include <sys/usb/usba/usba_ugen.h>
420Sstevel@tonic-gate
430Sstevel@tonic-gate #include <sys/usb/clients/mass_storage/usb_bulkonly.h>
440Sstevel@tonic-gate #include <sys/usb/scsa2usb/scsa2usb.h>
450Sstevel@tonic-gate
460Sstevel@tonic-gate /*
470Sstevel@tonic-gate * Function Prototypes
480Sstevel@tonic-gate */
490Sstevel@tonic-gate int scsa2usb_bulk_only_transport(scsa2usb_state_t *,
500Sstevel@tonic-gate scsa2usb_cmd_t *);
510Sstevel@tonic-gate static void scsa2usb_fill_in_cbw(scsa2usb_state_t *, scsa2usb_cmd_t *,
520Sstevel@tonic-gate mblk_t *);
530Sstevel@tonic-gate static void scsa2usb_bulk_only_reset_recovery(scsa2usb_state_t *);
540Sstevel@tonic-gate static void scsa2usb_bulk_only_handle_error(scsa2usb_state_t *,
550Sstevel@tonic-gate usb_bulk_req_t *);
560Sstevel@tonic-gate int scsa2usb_bulk_only_get_max_lun(scsa2usb_state_t *);
570Sstevel@tonic-gate static int scsa2usb_handle_status_start(scsa2usb_state_t *,
580Sstevel@tonic-gate usb_bulk_req_t *);
590Sstevel@tonic-gate static int scsa2usb_handle_csw_result(scsa2usb_state_t *, mblk_t *);
600Sstevel@tonic-gate
610Sstevel@tonic-gate
620Sstevel@tonic-gate /* extern functions */
630Sstevel@tonic-gate extern void scsa2usb_setup_next_xfer(scsa2usb_state_t *, scsa2usb_cmd_t *);
640Sstevel@tonic-gate extern int scsa2usb_handle_data_start(scsa2usb_state_t *,
650Sstevel@tonic-gate scsa2usb_cmd_t *, usb_bulk_req_t *);
660Sstevel@tonic-gate extern void scsa2usb_handle_data_done(scsa2usb_state_t *, scsa2usb_cmd_t *,
670Sstevel@tonic-gate usb_bulk_req_t *);
680Sstevel@tonic-gate extern usb_bulk_req_t *scsa2usb_init_bulk_req(scsa2usb_state_t *,
690Sstevel@tonic-gate size_t, uint_t, usb_req_attrs_t, usb_flags_t);
700Sstevel@tonic-gate extern int scsa2usb_bulk_timeout(int);
714834Sfb209375 extern int scsa2usb_clear_ept_stall(scsa2usb_state_t *, uint_t,
720Sstevel@tonic-gate usb_pipe_handle_t, char *);
730Sstevel@tonic-gate extern void scsa2usb_close_usb_pipes(scsa2usb_state_t *);
740Sstevel@tonic-gate
750Sstevel@tonic-gate #ifdef DEBUG /* debugging information */
760Sstevel@tonic-gate extern void scsa2usb_print_cdb(scsa2usb_state_t *, scsa2usb_cmd_t *);
770Sstevel@tonic-gate #endif /* DEBUG */
780Sstevel@tonic-gate
790Sstevel@tonic-gate
800Sstevel@tonic-gate #ifdef SCSA2USB_BULK_ONLY_TEST
810Sstevel@tonic-gate /*
820Sstevel@tonic-gate * Test 13 cases. (See USB Mass Storage Class - Bulk Only Transport).
830Sstevel@tonic-gate * We are not covering test cases 1, 6, and 12 as these are the "good"
840Sstevel@tonic-gate * test cases and are tested as part of the normal drive access operations.
850Sstevel@tonic-gate *
860Sstevel@tonic-gate * NOTE: This is for testing only. It will be replaced by a uscsi test.
870Sstevel@tonic-gate */
88880Sfrits int scsa2usb_test_case_2 = 0;
89880Sfrits int scsa2usb_test_case_3 = 0;
90880Sfrits int scsa2usb_test_case_4 = 0;
91880Sfrits int scsa2usb_test_case_7 = 0;
920Sstevel@tonic-gate extern int scsa2usb_test_case_8;
93880Sfrits int scsa2usb_test_case_9 = 0;
940Sstevel@tonic-gate extern int scsa2usb_test_case_10;
95880Sfrits int scsa2usb_test_case_13 = 0;
960Sstevel@tonic-gate #endif /* SCSA2USB_BULK_ONLY_TEST */
970Sstevel@tonic-gate
980Sstevel@tonic-gate
990Sstevel@tonic-gate /*
1000Sstevel@tonic-gate * scsa2usb_bulk_only_transport:
1010Sstevel@tonic-gate * Implements the BO state machine by these steps:
1020Sstevel@tonic-gate * a) Issues CBW to a Bulk Only device.
1030Sstevel@tonic-gate * b) Start Data Phase if applicable
1040Sstevel@tonic-gate * c) Start Status Phase
1050Sstevel@tonic-gate *
1060Sstevel@tonic-gate * returns TRAN_* values
1070Sstevel@tonic-gate *
1080Sstevel@tonic-gate * scsa2usb_bulk_only_state_machine:
1090Sstevel@tonic-gate *
1100Sstevel@tonic-gate * scsa2usb_bulk_only_transport() handles the normal transitions or
1110Sstevel@tonic-gate * continuation after clearing stalls or error recovery.
1120Sstevel@tonic-gate *
1130Sstevel@tonic-gate * Command Phase:
1140Sstevel@tonic-gate * prepare a valid CBW and transport it on bulk-out pipe
1150Sstevel@tonic-gate * if error on bulkout:
1160Sstevel@tonic-gate * set pkt_reason to CMD_TRAN_ERR
1170Sstevel@tonic-gate * new pkt state is SCSA2USB_PKT_DO_COMP
1180Sstevel@tonic-gate * reset recovery synchronously
1190Sstevel@tonic-gate * else
1200Sstevel@tonic-gate * proceed to data phase
1210Sstevel@tonic-gate *
1220Sstevel@tonic-gate * Data Phase:
1230Sstevel@tonic-gate * if data in:
1240Sstevel@tonic-gate * setup data in on bulkin
1250Sstevel@tonic-gate * else if data out:
1260Sstevel@tonic-gate * setup data out on bulkout
1270Sstevel@tonic-gate *
1280Sstevel@tonic-gate * data: (in)
1290Sstevel@tonic-gate * copy data transferred so far, no more data to transfer
1300Sstevel@tonic-gate *
1310Sstevel@tonic-gate * if stall on bulkin pipe
1320Sstevel@tonic-gate * terminate data transfers, set cmd_done
1330Sstevel@tonic-gate * clear stall on bulkin syncrhonously
1340Sstevel@tonic-gate * else if other exception
1350Sstevel@tonic-gate * set pkt_reason to CMD_TRAN_ERR
1360Sstevel@tonic-gate * new pkt state is SCSA2USB_PKT_DO_COMP
1370Sstevel@tonic-gate * reset recovery syncrhonously
1380Sstevel@tonic-gate * else (no error)
1390Sstevel@tonic-gate * receive status
1400Sstevel@tonic-gate *
1410Sstevel@tonic-gate * data: (out)
1420Sstevel@tonic-gate * if stall on bulkout pipe
1430Sstevel@tonic-gate * terminate data transfers, set cmd_done
1440Sstevel@tonic-gate * clear stall on bulkout synchronously USBA
1450Sstevel@tonic-gate * else if other exception
1460Sstevel@tonic-gate * set pkt_reason to CMD_TRAN_ERR
1470Sstevel@tonic-gate * new pkt state is SCSA2USB_PKT_DO_COMP
1480Sstevel@tonic-gate * reset recovery synchronously
1490Sstevel@tonic-gate * else (no error)
1500Sstevel@tonic-gate * receive status
1510Sstevel@tonic-gate *
1520Sstevel@tonic-gate * Status Phase:
1530Sstevel@tonic-gate *
1540Sstevel@tonic-gate * if stall (first attempt)
1550Sstevel@tonic-gate * new pkt state is SCSA2USB_PKT_PROCESS_CSW
1560Sstevel@tonic-gate * setup receiving status on bulkin
1570Sstevel@tonic-gate * if stall (second attempt)
1580Sstevel@tonic-gate * new pkt state is SCSA2USB_PKT_DO_COMP
1590Sstevel@tonic-gate * reset recovery synchronously, we are hosed.
1600Sstevel@tonic-gate * else
1610Sstevel@tonic-gate * goto check CSW
1620Sstevel@tonic-gate * else
1630Sstevel@tonic-gate * goto check CSW
1640Sstevel@tonic-gate *
1650Sstevel@tonic-gate * check CSW:
1660Sstevel@tonic-gate * - check length equals 13, signature, and matching tag
1670Sstevel@tonic-gate * - check status is less than or equal to 2
1680Sstevel@tonic-gate * - check residue is less than or equal to data length
1690Sstevel@tonic-gate * adjust residue based on if we got valid data
1700Sstevel@tonic-gate *
1710Sstevel@tonic-gate * if not OK
1720Sstevel@tonic-gate * new pkt state is SCSA2USB_PKT_DO_COMP
1730Sstevel@tonic-gate * set pkt reason CMD_TRAN_ERR
1740Sstevel@tonic-gate * reset recovery synchronously, we are hosed
1750Sstevel@tonic-gate * else if phase error
1760Sstevel@tonic-gate * new pkt state is SCSA2USB_PKT_DO_COMP
1770Sstevel@tonic-gate * set pkt reason CMD_TRAN_ERR
1780Sstevel@tonic-gate * reset recovery synchronously
1790Sstevel@tonic-gate * else if (status < 2)
1800Sstevel@tonic-gate * if status is equal to 1
1810Sstevel@tonic-gate * set check condition
1820Sstevel@tonic-gate * if residue
1830Sstevel@tonic-gate * calculate residue from data xferred and DataResidue
1840Sstevel@tonic-gate *
1850Sstevel@tonic-gate * set pkt_residue
1860Sstevel@tonic-gate * goto SCSA2USB_PKT_DO_COMP
1870Sstevel@tonic-gate *
1880Sstevel@tonic-gate * The reset recovery walks sequentially thru device reset, clearing
1890Sstevel@tonic-gate * stalls and pipe resets. When the reset recovery completes we return
1900Sstevel@tonic-gate * to the taskq thread.
1910Sstevel@tonic-gate *
1920Sstevel@tonic-gate * Clearing stalls clears the stall condition, resets the pipe, and
1930Sstevel@tonic-gate * then returns to the transport.
1940Sstevel@tonic-gate */
1950Sstevel@tonic-gate int
scsa2usb_bulk_only_transport(scsa2usb_state_t * scsa2usbp,scsa2usb_cmd_t * cmd)1960Sstevel@tonic-gate scsa2usb_bulk_only_transport(scsa2usb_state_t *scsa2usbp, scsa2usb_cmd_t *cmd)
1970Sstevel@tonic-gate {
1980Sstevel@tonic-gate int rval;
199918Sqz150045 int nretry;
2000Sstevel@tonic-gate usb_bulk_req_t *req;
2010Sstevel@tonic-gate
2020Sstevel@tonic-gate ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
2030Sstevel@tonic-gate
2040Sstevel@tonic-gate Cmd_Phase:
2050Sstevel@tonic-gate /*
2060Sstevel@tonic-gate * Start Command Phase
2070Sstevel@tonic-gate * Initialize a bulk_req_t
2080Sstevel@tonic-gate */
2090Sstevel@tonic-gate req = scsa2usb_init_bulk_req(scsa2usbp, USB_BULK_CBWCMD_LEN,
2100Sstevel@tonic-gate SCSA2USB_BULK_PIPE_TIMEOUT, USB_ATTRS_PIPE_RESET, USB_FLAGS_SLEEP);
2110Sstevel@tonic-gate
2120Sstevel@tonic-gate scsa2usb_fill_in_cbw(scsa2usbp, cmd, req->bulk_data); /* Fill CBW */
2130Sstevel@tonic-gate SCSA2USB_PRINT_CDB(scsa2usbp, cmd); /* Print CDB */
2140Sstevel@tonic-gate
2150Sstevel@tonic-gate /* Send a Bulk Command Block Wrapper (CBW) to the device */
2160Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
2170Sstevel@tonic-gate
2180Sstevel@tonic-gate ASSERT(req->bulk_timeout);
2190Sstevel@tonic-gate rval = usb_pipe_bulk_xfer(scsa2usbp->scsa2usb_bulkout_pipe, req,
2200Sstevel@tonic-gate USB_FLAGS_SLEEP);
2210Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
2220Sstevel@tonic-gate
2230Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
2240Sstevel@tonic-gate "scsa2usb_bulk_only_transport: "
2250Sstevel@tonic-gate "sent cmd = 0x%x Tag = 0x%x DataXferLen = 0x%lx rval = %d",
2260Sstevel@tonic-gate cmd->cmd_cdb[SCSA2USB_OPCODE], cmd->cmd_tag, cmd->cmd_xfercount,
2270Sstevel@tonic-gate rval);
2280Sstevel@tonic-gate
2290Sstevel@tonic-gate if (rval != USB_SUCCESS) {
2300Sstevel@tonic-gate scsa2usb_bulk_only_handle_error(scsa2usbp, req);
2310Sstevel@tonic-gate
2320Sstevel@tonic-gate return (TRAN_FATAL_ERROR);
2330Sstevel@tonic-gate }
2340Sstevel@tonic-gate
2350Sstevel@tonic-gate /* free the data */
2360Sstevel@tonic-gate SCSA2USB_FREE_MSG(req->bulk_data);
2370Sstevel@tonic-gate req->bulk_data = NULL;
2380Sstevel@tonic-gate
2390Sstevel@tonic-gate Data_Phase:
2400Sstevel@tonic-gate /*
2410Sstevel@tonic-gate * Start Data Phase
2420Sstevel@tonic-gate * re-set timeout
2430Sstevel@tonic-gate */
2440Sstevel@tonic-gate req->bulk_timeout = scsa2usb_bulk_timeout(cmd->cmd_timeout);
2450Sstevel@tonic-gate
2460Sstevel@tonic-gate /*
2470Sstevel@tonic-gate * we've not transferred any data yet; updated in
2480Sstevel@tonic-gate * scsa2usb_handle_data_done
2490Sstevel@tonic-gate */
2500Sstevel@tonic-gate cmd->cmd_resid_xfercount = cmd->cmd_xfercount;
2510Sstevel@tonic-gate
2520Sstevel@tonic-gate if (cmd->cmd_xfercount) {
2530Sstevel@tonic-gate /* start I/O to/from the device */
2540Sstevel@tonic-gate rval = scsa2usb_handle_data_start(scsa2usbp, cmd, req);
2550Sstevel@tonic-gate
2560Sstevel@tonic-gate /* handle data returned, if any */
2570Sstevel@tonic-gate scsa2usb_handle_data_done(scsa2usbp, cmd, req);
2580Sstevel@tonic-gate
2590Sstevel@tonic-gate if (rval != USB_SUCCESS) {
2600Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_SCSA,
2610Sstevel@tonic-gate scsa2usbp->scsa2usb_log_handle,
2620Sstevel@tonic-gate "data xfer phase, error = %d, cr = %d",
2630Sstevel@tonic-gate rval, req->bulk_completion_reason);
2640Sstevel@tonic-gate /*
2650Sstevel@tonic-gate * we ran into an error
2660Sstevel@tonic-gate */
2670Sstevel@tonic-gate if (req->bulk_completion_reason == USB_CR_STALL) {
2680Sstevel@tonic-gate if (scsa2usbp->scsa2usb_cur_pkt) {
2690Sstevel@tonic-gate scsa2usbp->scsa2usb_cur_pkt->
2704834Sfb209375 pkt_reason = CMD_TRAN_ERR;
2710Sstevel@tonic-gate }
2720Sstevel@tonic-gate } else {
2730Sstevel@tonic-gate scsa2usb_bulk_only_handle_error(scsa2usbp, req);
2740Sstevel@tonic-gate
2750Sstevel@tonic-gate return (TRAN_FATAL_ERROR);
2760Sstevel@tonic-gate }
2770Sstevel@tonic-gate } /* end of else */
2780Sstevel@tonic-gate
2790Sstevel@tonic-gate /* free the data */
2800Sstevel@tonic-gate SCSA2USB_FREE_MSG(req->bulk_data);
2810Sstevel@tonic-gate req->bulk_data = NULL;
2820Sstevel@tonic-gate }
2830Sstevel@tonic-gate
2840Sstevel@tonic-gate Status_Phase:
2850Sstevel@tonic-gate /*
2860Sstevel@tonic-gate * Start status phase
2870Sstevel@tonic-gate * read in CSW
2880Sstevel@tonic-gate */
289918Sqz150045 for (nretry = 0; nretry < SCSA2USB_STATUS_RETRIES; nretry++) {
290918Sqz150045 rval = scsa2usb_handle_status_start(scsa2usbp, req);
291918Sqz150045
292918Sqz150045 if ((rval != USB_SUCCESS) &&
293918Sqz150045 (req->bulk_completion_reason == USB_CR_STALL)) {
294918Sqz150045 /*
295918Sqz150045 * We ran into STALL condition here.
296918Sqz150045 * If the condition cannot be cleared
297918Sqz150045 * successfully, retry for limited times.
298918Sqz150045 */
299918Sqz150045 scsa2usbp->scsa2usb_pkt_state =
3004834Sfb209375 SCSA2USB_PKT_PROCESS_CSW;
301918Sqz150045 } else {
302918Sqz150045
303918Sqz150045 break;
304918Sqz150045 }
305918Sqz150045 }
306918Sqz150045
307918Sqz150045 if (rval == USB_SUCCESS) {
3080Sstevel@tonic-gate /* process CSW */
3090Sstevel@tonic-gate rval = scsa2usb_handle_csw_result(scsa2usbp, req->bulk_data);
3100Sstevel@tonic-gate } else {
311918Sqz150045 scsa2usb_bulk_only_handle_error(scsa2usbp, req);
3120Sstevel@tonic-gate
313918Sqz150045 return (TRAN_FATAL_ERROR);
3140Sstevel@tonic-gate }
3150Sstevel@tonic-gate
3160Sstevel@tonic-gate SCSA2USB_FREE_BULK_REQ(req); /* free request */
3170Sstevel@tonic-gate
3180Sstevel@tonic-gate if ((rval == USB_SUCCESS) && /* CSW was ok */
3190Sstevel@tonic-gate (scsa2usbp->scsa2usb_cur_pkt->pkt_reason == CMD_CMPLT) &&
3200Sstevel@tonic-gate (cmd->cmd_xfercount != 0) && /* more data to xfer */
3210Sstevel@tonic-gate !cmd->cmd_done) { /* we aren't done yet */
3220Sstevel@tonic-gate scsa2usb_setup_next_xfer(scsa2usbp, cmd);
3230Sstevel@tonic-gate goto Cmd_Phase;
3240Sstevel@tonic-gate }
3250Sstevel@tonic-gate
3260Sstevel@tonic-gate return (rval == USB_SUCCESS ? TRAN_ACCEPT : TRAN_FATAL_ERROR);
3270Sstevel@tonic-gate }
3280Sstevel@tonic-gate
3290Sstevel@tonic-gate
3300Sstevel@tonic-gate /*
3310Sstevel@tonic-gate * scsa2usb_fill_in_cbw:
3320Sstevel@tonic-gate * Fill in a CBW request packet. This
3330Sstevel@tonic-gate * packet is transported to the device
3340Sstevel@tonic-gate */
3350Sstevel@tonic-gate static void
scsa2usb_fill_in_cbw(scsa2usb_state_t * scsa2usbp,scsa2usb_cmd_t * cmd,mblk_t * mp)3360Sstevel@tonic-gate scsa2usb_fill_in_cbw(scsa2usb_state_t *scsa2usbp,
3370Sstevel@tonic-gate scsa2usb_cmd_t *cmd, mblk_t *mp)
3380Sstevel@tonic-gate {
3390Sstevel@tonic-gate int i;
3400Sstevel@tonic-gate int len;
3410Sstevel@tonic-gate uchar_t dir, *cdb = (uchar_t *)(&cmd->cmd_cdb);
3420Sstevel@tonic-gate
3430Sstevel@tonic-gate ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
3440Sstevel@tonic-gate
3450Sstevel@tonic-gate *mp->b_wptr++ = CBW_MSB(CBW_SIGNATURE); /* CBW Signature */;
3460Sstevel@tonic-gate *mp->b_wptr++ = CBW_MID1(CBW_SIGNATURE);
3470Sstevel@tonic-gate *mp->b_wptr++ = CBW_MID2(CBW_SIGNATURE);
3480Sstevel@tonic-gate *mp->b_wptr++ = CBW_LSB(CBW_SIGNATURE);
3490Sstevel@tonic-gate *mp->b_wptr++ = CBW_LSB(cmd->cmd_tag); /* CBW Tag */
3500Sstevel@tonic-gate *mp->b_wptr++ = CBW_MID2(cmd->cmd_tag);
3510Sstevel@tonic-gate *mp->b_wptr++ = CBW_MID1(cmd->cmd_tag);
3520Sstevel@tonic-gate *mp->b_wptr++ = CBW_MSB(cmd->cmd_tag);
3530Sstevel@tonic-gate
3540Sstevel@tonic-gate dir = cmd->cmd_dir;
3550Sstevel@tonic-gate len = cmd->cmd_xfercount;
3560Sstevel@tonic-gate #ifdef SCSA2USB_BULK_ONLY_TEST
3570Sstevel@tonic-gate if (scsa2usb_test_case_2 && (cdb[0] == SCMD_READ_CAPACITY)) {
3580Sstevel@tonic-gate /* Host expects no data. The device wants data. Hn < Di */
3590Sstevel@tonic-gate scsa2usb_test_case_2 = len = 0;
3600Sstevel@tonic-gate USB_DPRINTF_L1(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
3610Sstevel@tonic-gate "TEST 2: Hn < Di cdb: 0x%x len: 0x%x", cdb[0], len);
3620Sstevel@tonic-gate }
3630Sstevel@tonic-gate
3640Sstevel@tonic-gate if (scsa2usb_test_case_3 && (cmd->cmd_dir == CBW_DIR_OUT)) {
3650Sstevel@tonic-gate /* Host expects no data. The device wants data. Hn < Do */
3660Sstevel@tonic-gate if (cdb[0] == SCMD_WRITE_G1) {
3670Sstevel@tonic-gate scsa2usb_test_case_3 = len = 0;
3680Sstevel@tonic-gate USB_DPRINTF_L1(DPRINT_MASK_SCSA,
3690Sstevel@tonic-gate scsa2usbp->scsa2usb_log_handle,
3700Sstevel@tonic-gate "TEST 3: Hn < Do cdb: 0x%x len:%x", cdb[0], len);
3710Sstevel@tonic-gate }
3720Sstevel@tonic-gate }
3730Sstevel@tonic-gate
3740Sstevel@tonic-gate if (scsa2usb_test_case_4 && (cdb[0] == SCMD_READ_G1)) {
3750Sstevel@tonic-gate cdb[0] = 0x5e;
3760Sstevel@tonic-gate USB_DPRINTF_L1(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
3770Sstevel@tonic-gate "TEST 4: Hi > Dn: changed cdb to 0x%x", cdb[0]);
3780Sstevel@tonic-gate scsa2usb_test_case_4 = 0;
3790Sstevel@tonic-gate }
3800Sstevel@tonic-gate
3810Sstevel@tonic-gate if (scsa2usb_test_case_7 && (cmd->cmd_cdb[0] == SCMD_READ_G1)) {
3820Sstevel@tonic-gate len -= 0x10;
3830Sstevel@tonic-gate USB_DPRINTF_L1(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
3840Sstevel@tonic-gate "TEST 7: Hi < Di cdb: 0x%x len: 0x%x", cdb[0], len);
3850Sstevel@tonic-gate scsa2usb_test_case_7 = 0;
3860Sstevel@tonic-gate }
3870Sstevel@tonic-gate
3880Sstevel@tonic-gate if (scsa2usb_test_case_8 && (cdb[0] == SCMD_READ_G1)) {
3890Sstevel@tonic-gate dir = (dir == CBW_DIR_IN) ? CBW_DIR_OUT : dir;
3900Sstevel@tonic-gate USB_DPRINTF_L1(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
3910Sstevel@tonic-gate "TEST 8: Hi <> Do cdb: 0x%x dir: 0x%x", cdb[0], dir);
3920Sstevel@tonic-gate }
3930Sstevel@tonic-gate
3940Sstevel@tonic-gate if (scsa2usb_test_case_9 && (cdb[0] == SCMD_WRITE_G1)) {
3950Sstevel@tonic-gate USB_DPRINTF_L1(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
3960Sstevel@tonic-gate "TEST 9: Ho <> Di (%x)", cdb[0]);
3970Sstevel@tonic-gate cdb[SCSA2USB_LEN_0] = cdb[SCSA2USB_LEN_1] = 0;
3980Sstevel@tonic-gate scsa2usb_test_case_9 = 0;
3990Sstevel@tonic-gate }
4000Sstevel@tonic-gate
4010Sstevel@tonic-gate if (scsa2usb_test_case_10 && (cdb[0] == SCMD_WRITE_G1)) {
4020Sstevel@tonic-gate dir = (dir == CBW_DIR_OUT) ? CBW_DIR_IN : dir;
4030Sstevel@tonic-gate USB_DPRINTF_L1(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
4040Sstevel@tonic-gate "TEST 10: Ho <> Di cdb: 0x%x dir: 0x%x", cdb[0], dir);
4050Sstevel@tonic-gate }
4060Sstevel@tonic-gate
4070Sstevel@tonic-gate /*
4080Sstevel@tonic-gate * This case occurs when the device intends to receive
4090Sstevel@tonic-gate * more data from the host than the host sends.
4100Sstevel@tonic-gate */
4110Sstevel@tonic-gate if (scsa2usb_test_case_13) {
4120Sstevel@tonic-gate if ((cdb[0] == SCMD_WRITE_G1) || (cdb[0] == SCMD_READ_G1)) {
4130Sstevel@tonic-gate USB_DPRINTF_L1(DPRINT_MASK_SCSA,
4140Sstevel@tonic-gate scsa2usbp->scsa2usb_log_handle, "TEST 13: Ho < Do");
4150Sstevel@tonic-gate
4160Sstevel@tonic-gate len -= 30;
4170Sstevel@tonic-gate scsa2usb_test_case_13 = 0;
4180Sstevel@tonic-gate }
4190Sstevel@tonic-gate }
4200Sstevel@tonic-gate #endif /* SCSA2USB_BULK_ONLY_TEST */
4210Sstevel@tonic-gate
4220Sstevel@tonic-gate *mp->b_wptr++ = CBW_MSB(len); /* Transfer Length */
4230Sstevel@tonic-gate *mp->b_wptr++ = CBW_MID1(len);
4240Sstevel@tonic-gate *mp->b_wptr++ = CBW_MID2(len);
4250Sstevel@tonic-gate *mp->b_wptr++ = CBW_LSB(len);
4260Sstevel@tonic-gate
4270Sstevel@tonic-gate *mp->b_wptr++ = dir; /* Transfer Direction */
4280Sstevel@tonic-gate *mp->b_wptr++ = cmd->cmd_pkt->pkt_address.a_lun; /* Lun # */
4290Sstevel@tonic-gate *mp->b_wptr++ = cmd->cmd_actual_len; /* CDB Len */
4300Sstevel@tonic-gate
4310Sstevel@tonic-gate /* Copy the CDB out */
4320Sstevel@tonic-gate for (i = 0; i < CBW_CDB_LEN; i++) {
4330Sstevel@tonic-gate *mp->b_wptr++ = *cdb++;
4340Sstevel@tonic-gate }
4350Sstevel@tonic-gate #ifdef DUMP_CWB
4360Sstevel@tonic-gate {
4370Sstevel@tonic-gate int len = mp->b_wptr - mp->b_rptr;
4380Sstevel@tonic-gate char *buf;
4390Sstevel@tonic-gate
4400Sstevel@tonic-gate int i;
4410Sstevel@tonic-gate
4420Sstevel@tonic-gate cmn_err(CE_CONT, "CWB: len=%d\n", len);
4430Sstevel@tonic-gate buf = kmem_zalloc(512, KM_SLEEP);
4440Sstevel@tonic-gate for (i = 0; i < len; i++) {
4450Sstevel@tonic-gate sprintf(&buf[strlen(buf)], "%02x ", mp->b_rptr[i]);
4460Sstevel@tonic-gate }
4470Sstevel@tonic-gate cmn_err(CE_CONT, "%s\n", buf);
4480Sstevel@tonic-gate kmem_free(buf, 512);
4490Sstevel@tonic-gate }
4500Sstevel@tonic-gate #endif
4510Sstevel@tonic-gate
4520Sstevel@tonic-gate }
4530Sstevel@tonic-gate
4540Sstevel@tonic-gate
4550Sstevel@tonic-gate /*
4560Sstevel@tonic-gate * scsa2usb_bulk_only_handle_error:
4570Sstevel@tonic-gate * handle transport errors and start recovery
4580Sstevel@tonic-gate */
4590Sstevel@tonic-gate static void
scsa2usb_bulk_only_handle_error(scsa2usb_state_t * scsa2usbp,usb_bulk_req_t * req)4600Sstevel@tonic-gate scsa2usb_bulk_only_handle_error(scsa2usb_state_t *scsa2usbp,
4610Sstevel@tonic-gate usb_bulk_req_t *req)
4620Sstevel@tonic-gate {
4630Sstevel@tonic-gate struct scsi_pkt *pkt = scsa2usbp->scsa2usb_cur_pkt;
4640Sstevel@tonic-gate
4650Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
4660Sstevel@tonic-gate "scsa2usb_bulk_only_handle_error: req = 0x%p, cr = 0x%x",
4676898Sfb209375 (void *)req, (req ? req->bulk_completion_reason : 0));
4680Sstevel@tonic-gate
4690Sstevel@tonic-gate if (req) {
4700Sstevel@tonic-gate SCSA2USB_SET_PKT_DO_COMP_STATE(scsa2usbp);
4710Sstevel@tonic-gate
4720Sstevel@tonic-gate /* invoke reset recovery */
4730Sstevel@tonic-gate switch (req->bulk_completion_reason) {
4740Sstevel@tonic-gate case USB_CR_STALL:
4750Sstevel@tonic-gate if (pkt) {
4760Sstevel@tonic-gate pkt->pkt_reason = CMD_TRAN_ERR;
4770Sstevel@tonic-gate }
4780Sstevel@tonic-gate break;
4790Sstevel@tonic-gate case USB_CR_TIMEOUT:
4800Sstevel@tonic-gate if (pkt) {
4810Sstevel@tonic-gate pkt->pkt_reason = CMD_TIMEOUT;
4820Sstevel@tonic-gate pkt->pkt_statistics |= STAT_TIMEOUT;
4830Sstevel@tonic-gate }
4840Sstevel@tonic-gate break;
4850Sstevel@tonic-gate case USB_CR_DEV_NOT_RESP:
4860Sstevel@tonic-gate if (pkt) {
4870Sstevel@tonic-gate pkt->pkt_reason = CMD_DEV_GONE;
4880Sstevel@tonic-gate /* scsi_poll relies on this */
4890Sstevel@tonic-gate pkt->pkt_state = STATE_GOT_BUS;
4900Sstevel@tonic-gate }
4910Sstevel@tonic-gate break;
4920Sstevel@tonic-gate default:
4930Sstevel@tonic-gate if (pkt) {
4940Sstevel@tonic-gate pkt->pkt_reason = CMD_TRAN_ERR;
4950Sstevel@tonic-gate }
4960Sstevel@tonic-gate }
4970Sstevel@tonic-gate scsa2usb_bulk_only_reset_recovery(scsa2usbp);
4980Sstevel@tonic-gate }
4990Sstevel@tonic-gate
5000Sstevel@tonic-gate SCSA2USB_FREE_BULK_REQ(req);
5010Sstevel@tonic-gate }
5020Sstevel@tonic-gate
5030Sstevel@tonic-gate
5040Sstevel@tonic-gate /*
5050Sstevel@tonic-gate * scsa2usb_handle_status_start:
5060Sstevel@tonic-gate * Receive status data
5070Sstevel@tonic-gate */
5080Sstevel@tonic-gate static int
scsa2usb_handle_status_start(scsa2usb_state_t * scsa2usbp,usb_bulk_req_t * req)5090Sstevel@tonic-gate scsa2usb_handle_status_start(scsa2usb_state_t *scsa2usbp,
5100Sstevel@tonic-gate usb_bulk_req_t *req)
5110Sstevel@tonic-gate {
5120Sstevel@tonic-gate int rval;
5130Sstevel@tonic-gate
5140Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
5156898Sfb209375 "scsa2usb_handle_status_start: req = 0x%p", (void *)req);
5160Sstevel@tonic-gate
5170Sstevel@tonic-gate ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
5180Sstevel@tonic-gate
5190Sstevel@tonic-gate /* setup up for receiving CSW */
5200Sstevel@tonic-gate #ifdef SCSA2USB_BULK_ONLY_TEST
5210Sstevel@tonic-gate req->bulk_attributes = 0;
5220Sstevel@tonic-gate #else
5230Sstevel@tonic-gate req->bulk_attributes = USB_ATTRS_SHORT_XFER_OK;
5240Sstevel@tonic-gate #endif /* SCSA2USB_BULK_ONLY_TEST */
5250Sstevel@tonic-gate req->bulk_len = CSW_LEN;
5260Sstevel@tonic-gate
5270Sstevel@tonic-gate SCSA2USB_FREE_MSG(req->bulk_data);
5280Sstevel@tonic-gate req->bulk_data = allocb_wait(req->bulk_len,
5290Sstevel@tonic-gate BPRI_LO, STR_NOSIG, NULL);
5300Sstevel@tonic-gate
5310Sstevel@tonic-gate /* Issue the request */
5320Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
5330Sstevel@tonic-gate
5340Sstevel@tonic-gate ASSERT(req->bulk_timeout);
5350Sstevel@tonic-gate rval = usb_pipe_bulk_xfer(scsa2usbp->scsa2usb_bulkin_pipe, req,
5360Sstevel@tonic-gate USB_FLAGS_SLEEP);
5370Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
5380Sstevel@tonic-gate
5390Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
5400Sstevel@tonic-gate "scsa2usb_handle_status_start: END rval = 0x%x", rval);
5410Sstevel@tonic-gate
5420Sstevel@tonic-gate if (rval != USB_SUCCESS) {
5430Sstevel@tonic-gate if (scsa2usbp->scsa2usb_pkt_state == SCSA2USB_PKT_PROCESS_CSW) {
5440Sstevel@tonic-gate scsa2usb_bulk_only_reset_recovery(scsa2usbp);
5450Sstevel@tonic-gate
5460Sstevel@tonic-gate return (rval);
5470Sstevel@tonic-gate }
5480Sstevel@tonic-gate
5490Sstevel@tonic-gate if (req->bulk_completion_reason == USB_CR_STALL) {
5500Sstevel@tonic-gate (void) scsa2usb_clear_ept_stall(scsa2usbp,
5510Sstevel@tonic-gate scsa2usbp->scsa2usb_bulkin_ept.bEndpointAddress,
5520Sstevel@tonic-gate scsa2usbp->scsa2usb_bulkin_pipe, "bulk-in");
5530Sstevel@tonic-gate }
5540Sstevel@tonic-gate }
5550Sstevel@tonic-gate
5560Sstevel@tonic-gate return (rval);
5570Sstevel@tonic-gate }
5580Sstevel@tonic-gate
5590Sstevel@tonic-gate
5600Sstevel@tonic-gate /*
5610Sstevel@tonic-gate * scsa2usb_handle_csw_result:
5620Sstevel@tonic-gate * Handle status results
5630Sstevel@tonic-gate */
5640Sstevel@tonic-gate static int
scsa2usb_handle_csw_result(scsa2usb_state_t * scsa2usbp,mblk_t * data)5650Sstevel@tonic-gate scsa2usb_handle_csw_result(scsa2usb_state_t *scsa2usbp, mblk_t *data)
5660Sstevel@tonic-gate {
5670Sstevel@tonic-gate int rval = USB_SUCCESS;
5680Sstevel@tonic-gate int residue;
5690Sstevel@tonic-gate char *msg = "CSW FAILED";
5700Sstevel@tonic-gate uint_t signature, tag, status;
5710Sstevel@tonic-gate usb_bulk_csw_t csw;
5720Sstevel@tonic-gate struct scsi_pkt *pkt = scsa2usbp->scsa2usb_cur_pkt;
5730Sstevel@tonic-gate scsa2usb_cmd_t *cmd = PKT2CMD(pkt);
5740Sstevel@tonic-gate
5750Sstevel@tonic-gate ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
5760Sstevel@tonic-gate
5770Sstevel@tonic-gate /*
5780Sstevel@tonic-gate * This shouldn't happen. It implies the device's
5790Sstevel@tonic-gate * firmware is bad and has returned NULL CSW.
5800Sstevel@tonic-gate * return failure back.
5810Sstevel@tonic-gate */
5820Sstevel@tonic-gate if (data == NULL) {
5830Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
5840Sstevel@tonic-gate "scsa2usb_handle_csw_result: data == NULL");
5850Sstevel@tonic-gate
5860Sstevel@tonic-gate return (USB_FAILURE);
5870Sstevel@tonic-gate }
5880Sstevel@tonic-gate
5890Sstevel@tonic-gate /* check if we got back CSW_LEN or not */
5907492SZhigang.Lu@Sun.COM if (MBLKL(data) != CSW_LEN) {
5910Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
5926898Sfb209375 "scsa2usb_handle_csw_result: no enough data (%ld)",
5937492SZhigang.Lu@Sun.COM (long)(MBLKL(data)));
5940Sstevel@tonic-gate
5950Sstevel@tonic-gate return (USB_FAILURE);
5960Sstevel@tonic-gate }
5970Sstevel@tonic-gate
5980Sstevel@tonic-gate /* Read into csw */
5990Sstevel@tonic-gate bcopy(data->b_rptr, &csw, CSW_LEN);
6000Sstevel@tonic-gate
6010Sstevel@tonic-gate status = csw.csw_bCSWStatus;
6020Sstevel@tonic-gate signature = SCSA2USB_MK_32BIT(csw.csw_dCSWSignature3,
6030Sstevel@tonic-gate csw.csw_dCSWSignature2, csw.csw_dCSWSignature1,
6040Sstevel@tonic-gate csw.csw_dCSWSignature0);
6050Sstevel@tonic-gate residue = SCSA2USB_MK_32BIT(csw.csw_dCSWDataResidue3,
6060Sstevel@tonic-gate csw.csw_dCSWDataResidue2, csw.csw_dCSWDataResidue1,
6070Sstevel@tonic-gate csw.csw_dCSWDataResidue0);
6080Sstevel@tonic-gate tag = SCSA2USB_MK_32BIT(csw.csw_dCSWTag3, csw.csw_dCSWTag2,
6090Sstevel@tonic-gate csw.csw_dCSWTag1, csw.csw_dCSWTag0);
6100Sstevel@tonic-gate
6110Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
6120Sstevel@tonic-gate "CSW: Signature = 0x%x Status = 0%x Tag = 0x%x Residue = 0x%x",
6130Sstevel@tonic-gate signature, status, tag, residue);
6140Sstevel@tonic-gate
6150Sstevel@tonic-gate /* Check for abnormal errors */
6160Sstevel@tonic-gate if ((signature != CSW_SIGNATURE) || (tag != cmd->cmd_tag) ||
6177492SZhigang.Lu@Sun.COM (status > CSW_STATUS_PHASE_ERROR)) {
6180Sstevel@tonic-gate
6190Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
6200Sstevel@tonic-gate "CSW_ERR: Status = 0x%x, Tag = 0x%x xfercount = 0x%lx",
6210Sstevel@tonic-gate status, cmd->cmd_tag, cmd->cmd_total_xfercount);
6220Sstevel@tonic-gate
6230Sstevel@tonic-gate return (USB_FAILURE);
6240Sstevel@tonic-gate }
6250Sstevel@tonic-gate
6260Sstevel@tonic-gate switch (status) {
6270Sstevel@tonic-gate case CSW_STATUS_GOOD:
6280Sstevel@tonic-gate /*
6290Sstevel@tonic-gate * Fail the command if the device misbehaves and
6300Sstevel@tonic-gate * gives a good status but doesn't transfer any data.
6310Sstevel@tonic-gate * Otherwise we'll get into an infinite retry loop.
6320Sstevel@tonic-gate *
6330Sstevel@tonic-gate * We test only against cmd_total_xfercount here and
6340Sstevel@tonic-gate * assume that this will not happen on a command that
6350Sstevel@tonic-gate * transfers a large amount of data and therefore may
6360Sstevel@tonic-gate * be split into separate transfers. For a large data
6370Sstevel@tonic-gate * transfer it is assumed that the device will return
6380Sstevel@tonic-gate * an error status if the transfer does not occur.
6390Sstevel@tonic-gate * this isn't quite correct because a subsequent request
6400Sstevel@tonic-gate * sense may not give a valid sense key.
6410Sstevel@tonic-gate */
6420Sstevel@tonic-gate if (!cmd->cmd_done && residue &&
6430Sstevel@tonic-gate (residue == cmd->cmd_total_xfercount)) {
6440Sstevel@tonic-gate *(pkt->pkt_scbp) = STATUS_CHECK;
6450Sstevel@tonic-gate cmd->cmd_xfercount = 0;
6460Sstevel@tonic-gate cmd->cmd_done = 1;
6470Sstevel@tonic-gate } else {
6480Sstevel@tonic-gate msg = "CSW GOOD";
6490Sstevel@tonic-gate }
6500Sstevel@tonic-gate break;
6510Sstevel@tonic-gate case CSW_STATUS_FAILED:
6520Sstevel@tonic-gate *(pkt->pkt_scbp) = STATUS_CHECK; /* Set check condition */
6530Sstevel@tonic-gate cmd->cmd_done = 1;
6540Sstevel@tonic-gate break;
6550Sstevel@tonic-gate case CSW_STATUS_PHASE_ERROR:
6560Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
6570Sstevel@tonic-gate "scsa2usb_handle_csw_result: Phase Error");
6580Sstevel@tonic-gate
6590Sstevel@tonic-gate /* invoke reset recovery */
6600Sstevel@tonic-gate scsa2usb_bulk_only_handle_error(scsa2usbp, NULL);
6610Sstevel@tonic-gate
6620Sstevel@tonic-gate return (USB_FAILURE);
6630Sstevel@tonic-gate default: /* shouldn't happen anymore */
6640Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
6650Sstevel@tonic-gate "scsa2usb_handle_csw_result: Invalid CSW");
6660Sstevel@tonic-gate
6670Sstevel@tonic-gate /* invoke reset recovery */
6680Sstevel@tonic-gate scsa2usb_bulk_only_handle_error(scsa2usbp, NULL);
6690Sstevel@tonic-gate
6700Sstevel@tonic-gate return (USB_SUCCESS);
6710Sstevel@tonic-gate } /* end of switch */
6720Sstevel@tonic-gate
6730Sstevel@tonic-gate /* Set resid */
6740Sstevel@tonic-gate if (residue || cmd->cmd_resid_xfercount) {
6750Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_SCSA,
6760Sstevel@tonic-gate scsa2usbp->scsa2usb_log_handle,
6775789Ssl147100 "total=0x%lx cmd_xfercount=0x%lx residue=0x%x "
6785789Ssl147100 "cmd_offset=0x%lx",
6790Sstevel@tonic-gate cmd->cmd_total_xfercount, cmd->cmd_xfercount,
6805789Ssl147100 residue, cmd->cmd_offset);
6810Sstevel@tonic-gate
6820Sstevel@tonic-gate /*
6830Sstevel@tonic-gate * we need to adjust using the residue and
6840Sstevel@tonic-gate * assume worst case. Some devices lie about
6850Sstevel@tonic-gate * residue. some report a residue greater than
6860Sstevel@tonic-gate * the residue we have calculated.
6870Sstevel@tonic-gate * first adjust back the total_xfercount
6880Sstevel@tonic-gate */
6890Sstevel@tonic-gate cmd->cmd_total_xfercount += cmd->cmd_xfercount -
6904834Sfb209375 cmd->cmd_resid_xfercount;
6915789Ssl147100 /*
6925789Ssl147100 * we need to adjust cmd_offset as well, or the data
6935789Ssl147100 * buffer for subsequent transfer may exceed the buffer
6945789Ssl147100 * boundary
6955789Ssl147100 */
6965789Ssl147100 cmd->cmd_offset -= cmd->cmd_xfercount -
6975789Ssl147100 cmd->cmd_resid_xfercount;
6980Sstevel@tonic-gate
6990Sstevel@tonic-gate /*
7000Sstevel@tonic-gate * now take the min of the reported residue by
7010Sstevel@tonic-gate * the device and the requested xfer count
7020Sstevel@tonic-gate * (just in case the device reported a residue greater
7030Sstevel@tonic-gate * than our request count).
7040Sstevel@tonic-gate * then take the max of this residue and the residue
7050Sstevel@tonic-gate * that the HCD reported and subtract this from
7060Sstevel@tonic-gate * the request count. This is the actual number
7070Sstevel@tonic-gate * of valid bytes transferred during the last transfer
7080Sstevel@tonic-gate * which we now subtract from the total_xfercount
7090Sstevel@tonic-gate */
7101101Ssl147100 if ((!(scsa2usbp->scsa2usb_attrs &
7111101Ssl147100 SCSA2USB_ATTRS_USE_CSW_RESIDUE)) ||
7121101Ssl147100 (residue < 0) ||
7130Sstevel@tonic-gate (residue > cmd->cmd_total_xfercount)) {
7141101Ssl147100 /* some devices lie about the resid, ignore */
7151101Ssl147100 cmd->cmd_total_xfercount -=
7161101Ssl147100 cmd->cmd_xfercount - cmd->cmd_resid_xfercount;
7175789Ssl147100 cmd->cmd_offset +=
7185789Ssl147100 cmd->cmd_xfercount - cmd->cmd_resid_xfercount;
7191101Ssl147100 } else {
7201101Ssl147100 cmd->cmd_total_xfercount -=
7211101Ssl147100 cmd->cmd_xfercount -
7221101Ssl147100 max(min(residue, cmd->cmd_xfercount),
7231101Ssl147100 cmd->cmd_resid_xfercount);
7245789Ssl147100 cmd->cmd_offset +=
7255789Ssl147100 cmd->cmd_xfercount -
7265789Ssl147100 max(min(residue, cmd->cmd_xfercount),
7275789Ssl147100 cmd->cmd_resid_xfercount);
7285789Ssl147100 /*
7295789Ssl147100 * if HCD does not report residue while the device
7305789Ssl147100 * reports a residue equivalent to the xfercount,
7315789Ssl147100 * it is very likely the device lies about the
7325789Ssl147100 * residue. we need to stop the command, or we'll
7335789Ssl147100 * get into an infinite retry loop.
7345789Ssl147100 */
7355789Ssl147100 if ((cmd->cmd_resid_xfercount == 0) &&
7365789Ssl147100 (residue == cmd->cmd_xfercount)) {
7375789Ssl147100 cmd->cmd_xfercount = 0;
7385789Ssl147100 cmd->cmd_done = 1;
7395789Ssl147100 }
7400Sstevel@tonic-gate }
7410Sstevel@tonic-gate
7420Sstevel@tonic-gate pkt->pkt_resid = cmd->cmd_total_xfercount;
7430Sstevel@tonic-gate }
7440Sstevel@tonic-gate
7450Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
7460Sstevel@tonic-gate "scsa2usb_handle_csw_result: %s, resid: 0x%lx",
7470Sstevel@tonic-gate msg, pkt->pkt_resid);
7480Sstevel@tonic-gate
7490Sstevel@tonic-gate /* we are done and ready to callback */
7500Sstevel@tonic-gate SCSA2USB_SET_PKT_DO_COMP_STATE(scsa2usbp);
7510Sstevel@tonic-gate
7520Sstevel@tonic-gate return (rval);
7530Sstevel@tonic-gate }
7540Sstevel@tonic-gate
7550Sstevel@tonic-gate
7560Sstevel@tonic-gate /*
7570Sstevel@tonic-gate * scsa2usb_bulk_only_reset_recovery:
7580Sstevel@tonic-gate * Reset the USB device step-wise in case of errors.
7590Sstevel@tonic-gate * NOTE that the order of reset is very important.
7600Sstevel@tonic-gate */
7610Sstevel@tonic-gate static void
scsa2usb_bulk_only_reset_recovery(scsa2usb_state_t * scsa2usbp)7620Sstevel@tonic-gate scsa2usb_bulk_only_reset_recovery(scsa2usb_state_t *scsa2usbp)
7630Sstevel@tonic-gate {
7640Sstevel@tonic-gate int rval;
7650Sstevel@tonic-gate usb_cr_t completion_reason;
7660Sstevel@tonic-gate usb_cb_flags_t cb_flags;
7670Sstevel@tonic-gate
7680Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
7696898Sfb209375 "scsa2usb_bulk_only_reset_recovery: scsa2usbp = 0x%p",
7706898Sfb209375 (void *)scsa2usbp);
7710Sstevel@tonic-gate
7720Sstevel@tonic-gate ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
7730Sstevel@tonic-gate
7740Sstevel@tonic-gate if (!(SCSA2USB_DEVICE_ACCESS_OK(scsa2usbp))) {
7750Sstevel@tonic-gate
7760Sstevel@tonic-gate return;
7770Sstevel@tonic-gate }
7780Sstevel@tonic-gate
7790Sstevel@tonic-gate /*
7800Sstevel@tonic-gate * assume that the reset will be successful. if it isn't, retrying
7810Sstevel@tonic-gate * from target driver won't help much
7820Sstevel@tonic-gate */
7830Sstevel@tonic-gate if (scsa2usbp->scsa2usb_cur_pkt) {
7840Sstevel@tonic-gate scsa2usbp->scsa2usb_cur_pkt->pkt_statistics |= STAT_DEV_RESET;
7850Sstevel@tonic-gate }
7860Sstevel@tonic-gate
7870Sstevel@tonic-gate /* set the reset condition */
7880Sstevel@tonic-gate scsa2usbp->scsa2usb_pipe_state = SCSA2USB_PIPE_DEV_RESET;
7890Sstevel@tonic-gate
7900Sstevel@tonic-gate /* Send a sync DEVICE-RESET request to the device */
7910Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
7920Sstevel@tonic-gate rval = usb_pipe_sync_ctrl_xfer(scsa2usbp->scsa2usb_dip,
7930Sstevel@tonic-gate scsa2usbp->scsa2usb_default_pipe,
7940Sstevel@tonic-gate USB_DEV_REQ_TYPE_CLASS | USB_DEV_REQ_RCPT_IF,
7950Sstevel@tonic-gate (uint8_t)BULK_ONLY_RESET, /* bRequest */
7960Sstevel@tonic-gate 0, /* wValue */
7970Sstevel@tonic-gate scsa2usbp->scsa2usb_intfc_num, /* wIndex */
7980Sstevel@tonic-gate 0, /* wLength */
7990Sstevel@tonic-gate NULL, 0, &completion_reason, &cb_flags, 0);
8000Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
8010Sstevel@tonic-gate
8020Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
8030Sstevel@tonic-gate "\tbulk-only device-reset rval: %d", rval);
8040Sstevel@tonic-gate if (rval != USB_SUCCESS) {
8050Sstevel@tonic-gate goto exc_exit;
8060Sstevel@tonic-gate }
8070Sstevel@tonic-gate
8080Sstevel@tonic-gate /* reset and clear STALL on bulk-in pipe */
8090Sstevel@tonic-gate rval = scsa2usb_clear_ept_stall(scsa2usbp,
8100Sstevel@tonic-gate scsa2usbp->scsa2usb_bulkin_ept.bEndpointAddress,
8110Sstevel@tonic-gate scsa2usbp->scsa2usb_bulkin_pipe, "bulk-in");
8120Sstevel@tonic-gate
8130Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
8140Sstevel@tonic-gate "\tbulk-in pipe clear stall: %d", rval);
8150Sstevel@tonic-gate if (rval != USB_SUCCESS) {
8160Sstevel@tonic-gate goto exc_exit;
8170Sstevel@tonic-gate }
8180Sstevel@tonic-gate
8190Sstevel@tonic-gate /* reset and clear STALL on bulk-out pipe */
8200Sstevel@tonic-gate rval = scsa2usb_clear_ept_stall(scsa2usbp,
8210Sstevel@tonic-gate scsa2usbp->scsa2usb_bulkout_ept.bEndpointAddress,
8220Sstevel@tonic-gate scsa2usbp->scsa2usb_bulkout_pipe, "bulk-out");
8230Sstevel@tonic-gate
8240Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
8250Sstevel@tonic-gate "\tbulk-out pipe clear stall: %d", rval);
8260Sstevel@tonic-gate
8270Sstevel@tonic-gate exc_exit:
8280Sstevel@tonic-gate /* clear the reset condition */
8290Sstevel@tonic-gate scsa2usbp->scsa2usb_pipe_state &= ~SCSA2USB_PIPE_DEV_RESET;
8300Sstevel@tonic-gate }
8310Sstevel@tonic-gate
8320Sstevel@tonic-gate
8330Sstevel@tonic-gate /*
8340Sstevel@tonic-gate * scsa2usb_bulk_only_get_max_lun:
8350Sstevel@tonic-gate * this function returns the number of LUNs supported by the device
8360Sstevel@tonic-gate */
8370Sstevel@tonic-gate int
scsa2usb_bulk_only_get_max_lun(scsa2usb_state_t * scsa2usbp)8380Sstevel@tonic-gate scsa2usb_bulk_only_get_max_lun(scsa2usb_state_t *scsa2usbp)
8390Sstevel@tonic-gate {
8400Sstevel@tonic-gate int luns = 1, rval;
8410Sstevel@tonic-gate mblk_t *data = NULL;
8420Sstevel@tonic-gate usb_cr_t completion_reason;
8430Sstevel@tonic-gate usb_cb_flags_t cb_flags;
8440Sstevel@tonic-gate
8450Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
8460Sstevel@tonic-gate "scsa2usb_bulk_only_get_max_lun:");
8470Sstevel@tonic-gate
8480Sstevel@tonic-gate ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
8490Sstevel@tonic-gate
8500Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
8510Sstevel@tonic-gate rval = usb_pipe_sync_ctrl_xfer(scsa2usbp->scsa2usb_dip,
8520Sstevel@tonic-gate scsa2usbp->scsa2usb_default_pipe,
8530Sstevel@tonic-gate BULK_ONLY_GET_MAXLUN_BMREQ, /* bmRequestType */
8540Sstevel@tonic-gate BULK_ONLY_GET_MAXLUN_REQ, /* bRequest */
8550Sstevel@tonic-gate 0, /* wValue */
8560Sstevel@tonic-gate scsa2usbp->scsa2usb_intfc_num, /* wIndex */
8570Sstevel@tonic-gate 1, /* wLength */
8580Sstevel@tonic-gate &data, 0,
8590Sstevel@tonic-gate &completion_reason, &cb_flags, 0);
8600Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
8610Sstevel@tonic-gate
8620Sstevel@tonic-gate if (rval != USB_SUCCESS) {
8630Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
8640Sstevel@tonic-gate "get max lun failed, rval=%d cr=%d cb=0x%x data=0x%p",
8656898Sfb209375 rval, completion_reason, cb_flags, (void *)data);
8660Sstevel@tonic-gate } else {
8670Sstevel@tonic-gate /*
8680Sstevel@tonic-gate * This check ensures that we have valid data returned back.
8690Sstevel@tonic-gate * Otherwise we assume that device supports only one LUN.
8700Sstevel@tonic-gate */
8717492SZhigang.Lu@Sun.COM if (MBLKL(data) != 1) {
872978Sfrits USB_DPRINTF_L2(DPRINT_MASK_SCSA,
8730Sstevel@tonic-gate scsa2usbp->scsa2usb_log_handle,
8740Sstevel@tonic-gate "device reported incorrect luns (adjusting to 1)");
8750Sstevel@tonic-gate } else {
8760Sstevel@tonic-gate /*
8770Sstevel@tonic-gate * Set scsa2usb_n_luns to value returned by the device
8780Sstevel@tonic-gate * plus 1. (See Section 3.2)
8790Sstevel@tonic-gate */
8800Sstevel@tonic-gate luns = *data->b_rptr + 1;
8810Sstevel@tonic-gate
8820Sstevel@tonic-gate /*
8830Sstevel@tonic-gate * In case a device returns incorrect LUNs
8840Sstevel@tonic-gate * which are more than 15 or negative or 0;
8850Sstevel@tonic-gate * we assume 1.
8860Sstevel@tonic-gate */
8870Sstevel@tonic-gate if ((luns >= SCSA2USB_MAX_LUNS) || (luns <= 0)) {
888978Sfrits USB_DPRINTF_L2(DPRINT_MASK_SCSA,
8890Sstevel@tonic-gate scsa2usbp->scsa2usb_log_handle,
8900Sstevel@tonic-gate "device reported %d luns "
8910Sstevel@tonic-gate "(adjusting to 1)", luns);
8920Sstevel@tonic-gate luns = 1;
8930Sstevel@tonic-gate }
8940Sstevel@tonic-gate }
8950Sstevel@tonic-gate }
8960Sstevel@tonic-gate
8970Sstevel@tonic-gate SCSA2USB_FREE_MSG(data); /* Free data */
8980Sstevel@tonic-gate
8990Sstevel@tonic-gate return (luns);
9000Sstevel@tonic-gate }
901