17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
563602c90Sfb  * Common Development and Distribution License (the "License").
663602c90Sfb  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  *
213fbbb872Ssl  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
227c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
237c478bd9Sstevel@tonic-gate  */
247c478bd9Sstevel@tonic-gate 
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  * scsa2usb_ms_bulkonly.c:
287c478bd9Sstevel@tonic-gate  *
297c478bd9Sstevel@tonic-gate  * This file implements USB Mass Storage Class
307c478bd9Sstevel@tonic-gate  * Bulk Only (BO) transport v1.0
317c478bd9Sstevel@tonic-gate  * http://www.usb.org/developers/data/devclass/usbmassbulk_10.pdf
327c478bd9Sstevel@tonic-gate  */
337c478bd9Sstevel@tonic-gate #include <sys/usb/usba/usbai_version.h>
347c478bd9Sstevel@tonic-gate #include <sys/scsi/scsi.h>
357c478bd9Sstevel@tonic-gate #include <sys/callb.h>		/* needed by scsa2usb.h */
367c478bd9Sstevel@tonic-gate #include <sys/strsubr.h>
37*d29f5a71Szhigang lu - Sun Microsystems - Beijing China #include <sys/strsun.h>
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate #include <sys/usb/usba.h>
407c478bd9Sstevel@tonic-gate #include <sys/usb/usba/usba_private.h>
417c478bd9Sstevel@tonic-gate #include <sys/usb/usba/usba_ugen.h>
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate #include <sys/usb/clients/mass_storage/usb_bulkonly.h>
447c478bd9Sstevel@tonic-gate #include <sys/usb/scsa2usb/scsa2usb.h>
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate /*
477c478bd9Sstevel@tonic-gate  * Function Prototypes
487c478bd9Sstevel@tonic-gate  */
497c478bd9Sstevel@tonic-gate int		scsa2usb_bulk_only_transport(scsa2usb_state_t *,
507c478bd9Sstevel@tonic-gate 		    scsa2usb_cmd_t *);
517c478bd9Sstevel@tonic-gate static void	scsa2usb_fill_in_cbw(scsa2usb_state_t *, scsa2usb_cmd_t *,
527c478bd9Sstevel@tonic-gate 		    mblk_t *);
537c478bd9Sstevel@tonic-gate static void	scsa2usb_bulk_only_reset_recovery(scsa2usb_state_t *);
547c478bd9Sstevel@tonic-gate static void	scsa2usb_bulk_only_handle_error(scsa2usb_state_t *,
557c478bd9Sstevel@tonic-gate 		    usb_bulk_req_t *);
567c478bd9Sstevel@tonic-gate int		scsa2usb_bulk_only_get_max_lun(scsa2usb_state_t *);
577c478bd9Sstevel@tonic-gate static int	scsa2usb_handle_status_start(scsa2usb_state_t *,
587c478bd9Sstevel@tonic-gate 		    usb_bulk_req_t *);
597c478bd9Sstevel@tonic-gate static int	scsa2usb_handle_csw_result(scsa2usb_state_t *, mblk_t *);
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate /* extern functions */
637c478bd9Sstevel@tonic-gate extern void	scsa2usb_setup_next_xfer(scsa2usb_state_t *, scsa2usb_cmd_t *);
647c478bd9Sstevel@tonic-gate extern int	scsa2usb_handle_data_start(scsa2usb_state_t *,
657c478bd9Sstevel@tonic-gate 		    scsa2usb_cmd_t *, usb_bulk_req_t *);
667c478bd9Sstevel@tonic-gate extern void	scsa2usb_handle_data_done(scsa2usb_state_t *, scsa2usb_cmd_t *,
677c478bd9Sstevel@tonic-gate 		    usb_bulk_req_t *);
687c478bd9Sstevel@tonic-gate extern usb_bulk_req_t *scsa2usb_init_bulk_req(scsa2usb_state_t *,
697c478bd9Sstevel@tonic-gate 			    size_t, uint_t, usb_req_attrs_t, usb_flags_t);
707c478bd9Sstevel@tonic-gate extern int	scsa2usb_bulk_timeout(int);
7163602c90Sfb extern int	scsa2usb_clear_ept_stall(scsa2usb_state_t *, uint_t,
727c478bd9Sstevel@tonic-gate 		    usb_pipe_handle_t, char *);
737c478bd9Sstevel@tonic-gate extern void	scsa2usb_close_usb_pipes(scsa2usb_state_t *);
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate #ifdef DEBUG	/* debugging information */
767c478bd9Sstevel@tonic-gate extern void	scsa2usb_print_cdb(scsa2usb_state_t *, scsa2usb_cmd_t *);
777c478bd9Sstevel@tonic-gate #endif	/* DEBUG */
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate #ifdef	SCSA2USB_BULK_ONLY_TEST
817c478bd9Sstevel@tonic-gate /*
827c478bd9Sstevel@tonic-gate  * Test 13 cases. (See USB Mass Storage Class - Bulk Only Transport).
837c478bd9Sstevel@tonic-gate  * We are not covering test cases 1, 6, and 12 as these are the "good"
847c478bd9Sstevel@tonic-gate  * test cases and are tested as part of the normal drive access operations.
857c478bd9Sstevel@tonic-gate  *
867c478bd9Sstevel@tonic-gate  * NOTE: This is for testing only. It will be replaced by a uscsi test.
877c478bd9Sstevel@tonic-gate  */
884610e4a0Sfrits int scsa2usb_test_case_2 = 0;
894610e4a0Sfrits int scsa2usb_test_case_3 = 0;
904610e4a0Sfrits int scsa2usb_test_case_4 = 0;
914610e4a0Sfrits int scsa2usb_test_case_7 = 0;
927c478bd9Sstevel@tonic-gate extern int scsa2usb_test_case_8;
934610e4a0Sfrits int scsa2usb_test_case_9 = 0;
947c478bd9Sstevel@tonic-gate extern int scsa2usb_test_case_10;
954610e4a0Sfrits int scsa2usb_test_case_13 = 0;
967c478bd9Sstevel@tonic-gate #endif	/* SCSA2USB_BULK_ONLY_TEST */
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate /*
1007c478bd9Sstevel@tonic-gate  * scsa2usb_bulk_only_transport:
1017c478bd9Sstevel@tonic-gate  *	Implements the BO state machine by these steps:
1027c478bd9Sstevel@tonic-gate  *	a) Issues CBW to a Bulk Only device.
1037c478bd9Sstevel@tonic-gate  *	b) Start Data Phase if applicable
1047c478bd9Sstevel@tonic-gate  *	c) Start Status Phase
1057c478bd9Sstevel@tonic-gate  *
1067c478bd9Sstevel@tonic-gate  *	returns TRAN_* values
1077c478bd9Sstevel@tonic-gate  *
1087c478bd9Sstevel@tonic-gate  * scsa2usb_bulk_only_state_machine:
1097c478bd9Sstevel@tonic-gate  *
1107c478bd9Sstevel@tonic-gate  * scsa2usb_bulk_only_transport() handles the normal transitions or
1117c478bd9Sstevel@tonic-gate  * continuation after clearing stalls or error recovery.
1127c478bd9Sstevel@tonic-gate  *
1137c478bd9Sstevel@tonic-gate  * Command Phase:
1147c478bd9Sstevel@tonic-gate  *	prepare a valid CBW and transport it on bulk-out pipe
1157c478bd9Sstevel@tonic-gate  *	if error on bulkout:
1167c478bd9Sstevel@tonic-gate  *		set pkt_reason to CMD_TRAN_ERR
1177c478bd9Sstevel@tonic-gate  *		new pkt state is SCSA2USB_PKT_DO_COMP
1187c478bd9Sstevel@tonic-gate  *		reset recovery synchronously
1197c478bd9Sstevel@tonic-gate  *	else
1207c478bd9Sstevel@tonic-gate  *		proceed to data phase
1217c478bd9Sstevel@tonic-gate  *
1227c478bd9Sstevel@tonic-gate  * Data Phase:
1237c478bd9Sstevel@tonic-gate  *	if data in:
1247c478bd9Sstevel@tonic-gate  *		setup data in on bulkin
1257c478bd9Sstevel@tonic-gate  *	else if data out:
1267c478bd9Sstevel@tonic-gate  *		setup data out on bulkout
1277c478bd9Sstevel@tonic-gate  *
1287c478bd9Sstevel@tonic-gate  *	data: (in)
1297c478bd9Sstevel@tonic-gate  *		copy data transferred so far, no more data to transfer
1307c478bd9Sstevel@tonic-gate  *
1317c478bd9Sstevel@tonic-gate  *		if stall on bulkin pipe
1327c478bd9Sstevel@tonic-gate  *			terminate data transfers, set cmd_done
1337c478bd9Sstevel@tonic-gate  *			clear stall on bulkin syncrhonously
1347c478bd9Sstevel@tonic-gate  *		else if other exception
1357c478bd9Sstevel@tonic-gate  *			set pkt_reason to CMD_TRAN_ERR
1367c478bd9Sstevel@tonic-gate  *			new pkt state is SCSA2USB_PKT_DO_COMP
1377c478bd9Sstevel@tonic-gate  *			reset recovery syncrhonously
1387c478bd9Sstevel@tonic-gate  *		else (no error)
1397c478bd9Sstevel@tonic-gate  *			receive status
1407c478bd9Sstevel@tonic-gate  *
1417c478bd9Sstevel@tonic-gate  *	 data: (out)
1427c478bd9Sstevel@tonic-gate  *		if stall on bulkout pipe
1437c478bd9Sstevel@tonic-gate  *			terminate data transfers, set cmd_done
1447c478bd9Sstevel@tonic-gate  *			clear stall on bulkout synchronously USBA
1457c478bd9Sstevel@tonic-gate  *		else if other exception
1467c478bd9Sstevel@tonic-gate  *			set pkt_reason to CMD_TRAN_ERR
1477c478bd9Sstevel@tonic-gate  *			new pkt state is SCSA2USB_PKT_DO_COMP
1487c478bd9Sstevel@tonic-gate  *			reset recovery synchronously
1497c478bd9Sstevel@tonic-gate  *		else (no error)
1507c478bd9Sstevel@tonic-gate  *			receive status
1517c478bd9Sstevel@tonic-gate  *
1527c478bd9Sstevel@tonic-gate  * Status Phase:
1537c478bd9Sstevel@tonic-gate  *
1547c478bd9Sstevel@tonic-gate  *	if stall (first attempt)
1557c478bd9Sstevel@tonic-gate  *		new pkt state is SCSA2USB_PKT_PROCESS_CSW
1567c478bd9Sstevel@tonic-gate  *		setup receiving status on bulkin
1577c478bd9Sstevel@tonic-gate  *		if stall (second attempt)
1587c478bd9Sstevel@tonic-gate  *			new pkt state is SCSA2USB_PKT_DO_COMP
1597c478bd9Sstevel@tonic-gate  *			reset recovery synchronously, we are hosed.
1607c478bd9Sstevel@tonic-gate  *		else
1617c478bd9Sstevel@tonic-gate  *			goto check CSW
1627c478bd9Sstevel@tonic-gate  *	else
1637c478bd9Sstevel@tonic-gate  *		goto check CSW
1647c478bd9Sstevel@tonic-gate  *
1657c478bd9Sstevel@tonic-gate  * check CSW:
1667c478bd9Sstevel@tonic-gate  *	- check length equals 13, signature, and matching tag
1677c478bd9Sstevel@tonic-gate  *	- check status is less than or equal to 2
1687c478bd9Sstevel@tonic-gate  *	- check residue is less than or equal to data length
1697c478bd9Sstevel@tonic-gate  *		adjust residue based on if we got valid data
1707c478bd9Sstevel@tonic-gate  *
1717c478bd9Sstevel@tonic-gate  *	if not OK
1727c478bd9Sstevel@tonic-gate  *		new pkt state is SCSA2USB_PKT_DO_COMP
1737c478bd9Sstevel@tonic-gate  *		set pkt reason CMD_TRAN_ERR
1747c478bd9Sstevel@tonic-gate  *		reset recovery synchronously, we are hosed
1757c478bd9Sstevel@tonic-gate  *	else if phase error
1767c478bd9Sstevel@tonic-gate  *		new pkt state is SCSA2USB_PKT_DO_COMP
1777c478bd9Sstevel@tonic-gate  *		set pkt reason CMD_TRAN_ERR
1787c478bd9Sstevel@tonic-gate  *		reset recovery synchronously
1797c478bd9Sstevel@tonic-gate  *	else if (status < 2)
1807c478bd9Sstevel@tonic-gate  *		if status is equal to 1
1817c478bd9Sstevel@tonic-gate  *			set check condition
1827c478bd9Sstevel@tonic-gate  *		if residue
1837c478bd9Sstevel@tonic-gate  *			calculate residue from data xferred and DataResidue
1847c478bd9Sstevel@tonic-gate  *
1857c478bd9Sstevel@tonic-gate  *			set pkt_residue
1867c478bd9Sstevel@tonic-gate  *		goto  SCSA2USB_PKT_DO_COMP
1877c478bd9Sstevel@tonic-gate  *
1887c478bd9Sstevel@tonic-gate  * The reset recovery walks sequentially thru device reset, clearing
1897c478bd9Sstevel@tonic-gate  * stalls and pipe resets. When the reset recovery completes we return
1907c478bd9Sstevel@tonic-gate  * to the taskq thread.
1917c478bd9Sstevel@tonic-gate  *
1927c478bd9Sstevel@tonic-gate  * Clearing stalls clears the stall condition, resets the pipe, and
1937c478bd9Sstevel@tonic-gate  * then returns to the transport.
1947c478bd9Sstevel@tonic-gate  */
1957c478bd9Sstevel@tonic-gate int
1967c478bd9Sstevel@tonic-gate scsa2usb_bulk_only_transport(scsa2usb_state_t *scsa2usbp, scsa2usb_cmd_t *cmd)
1977c478bd9Sstevel@tonic-gate {
1987c478bd9Sstevel@tonic-gate 	int	rval;
1996d9a41ffSqz 	int	nretry;
2007c478bd9Sstevel@tonic-gate 	usb_bulk_req_t *req;
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate Cmd_Phase:
2057c478bd9Sstevel@tonic-gate 	/*
2067c478bd9Sstevel@tonic-gate 	 * Start Command Phase
2077c478bd9Sstevel@tonic-gate 	 * Initialize a bulk_req_t
2087c478bd9Sstevel@tonic-gate 	 */
2097c478bd9Sstevel@tonic-gate 	req = scsa2usb_init_bulk_req(scsa2usbp, USB_BULK_CBWCMD_LEN,
2107c478bd9Sstevel@tonic-gate 	    SCSA2USB_BULK_PIPE_TIMEOUT, USB_ATTRS_PIPE_RESET, USB_FLAGS_SLEEP);
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate 	scsa2usb_fill_in_cbw(scsa2usbp, cmd, req->bulk_data);	/* Fill CBW */
2137c478bd9Sstevel@tonic-gate 	SCSA2USB_PRINT_CDB(scsa2usbp, cmd);			/* Print CDB */
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate 	/* Send a Bulk Command Block Wrapper (CBW) to the device */
2167c478bd9Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate 	ASSERT(req->bulk_timeout);
2197c478bd9Sstevel@tonic-gate 	rval = usb_pipe_bulk_xfer(scsa2usbp->scsa2usb_bulkout_pipe, req,
2207c478bd9Sstevel@tonic-gate 	    USB_FLAGS_SLEEP);
2217c478bd9Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
2247c478bd9Sstevel@tonic-gate 	    "scsa2usb_bulk_only_transport: "
2257c478bd9Sstevel@tonic-gate 	    "sent cmd = 0x%x Tag = 0x%x DataXferLen = 0x%lx rval = %d",
2267c478bd9Sstevel@tonic-gate 	    cmd->cmd_cdb[SCSA2USB_OPCODE], cmd->cmd_tag, cmd->cmd_xfercount,
2277c478bd9Sstevel@tonic-gate 	    rval);
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate 	if (rval != USB_SUCCESS) {
2307c478bd9Sstevel@tonic-gate 		scsa2usb_bulk_only_handle_error(scsa2usbp, req);
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate 		return (TRAN_FATAL_ERROR);
2337c478bd9Sstevel@tonic-gate 	}
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 	/* free the data */
2367c478bd9Sstevel@tonic-gate 	SCSA2USB_FREE_MSG(req->bulk_data);
2377c478bd9Sstevel@tonic-gate 	req->bulk_data = NULL;
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate Data_Phase:
2407c478bd9Sstevel@tonic-gate 	/*
2417c478bd9Sstevel@tonic-gate 	 * Start Data Phase
2427c478bd9Sstevel@tonic-gate 	 * re-set timeout
2437c478bd9Sstevel@tonic-gate 	 */
2447c478bd9Sstevel@tonic-gate 	req->bulk_timeout = scsa2usb_bulk_timeout(cmd->cmd_timeout);
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate 	/*
2477c478bd9Sstevel@tonic-gate 	 * we've not transferred any data yet; updated in
2487c478bd9Sstevel@tonic-gate 	 * scsa2usb_handle_data_done
2497c478bd9Sstevel@tonic-gate 	 */
2507c478bd9Sstevel@tonic-gate 	cmd->cmd_resid_xfercount = cmd->cmd_xfercount;
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate 	if (cmd->cmd_xfercount) {
2537c478bd9Sstevel@tonic-gate 		/* start I/O to/from the device */
2547c478bd9Sstevel@tonic-gate 		rval = scsa2usb_handle_data_start(scsa2usbp, cmd, req);
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate 		/* handle data returned, if any */
2577c478bd9Sstevel@tonic-gate 		scsa2usb_handle_data_done(scsa2usbp, cmd, req);
2587c478bd9Sstevel@tonic-gate 
2597c478bd9Sstevel@tonic-gate 		if (rval != USB_SUCCESS) {
2607c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_SCSA,
2617c478bd9Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
2627c478bd9Sstevel@tonic-gate 			    "data xfer phase, error =  %d, cr = %d",
2637c478bd9Sstevel@tonic-gate 			    rval, req->bulk_completion_reason);
2647c478bd9Sstevel@tonic-gate 			/*
2657c478bd9Sstevel@tonic-gate 			 * we ran into an error
2667c478bd9Sstevel@tonic-gate 			 */
2677c478bd9Sstevel@tonic-gate 			if (req->bulk_completion_reason == USB_CR_STALL) {
2687c478bd9Sstevel@tonic-gate 				if (scsa2usbp->scsa2usb_cur_pkt) {
2697c478bd9Sstevel@tonic-gate 					scsa2usbp->scsa2usb_cur_pkt->
27063602c90Sfb 					    pkt_reason = CMD_TRAN_ERR;
2717c478bd9Sstevel@tonic-gate 				}
2727c478bd9Sstevel@tonic-gate 			} else {
2737c478bd9Sstevel@tonic-gate 				scsa2usb_bulk_only_handle_error(scsa2usbp, req);
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate 				return (TRAN_FATAL_ERROR);
2767c478bd9Sstevel@tonic-gate 			}
2777c478bd9Sstevel@tonic-gate 		} /* end of else */
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate 		/* free the data */
2807c478bd9Sstevel@tonic-gate 		SCSA2USB_FREE_MSG(req->bulk_data);
2817c478bd9Sstevel@tonic-gate 		req->bulk_data = NULL;
2827c478bd9Sstevel@tonic-gate 	}
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate Status_Phase:
2857c478bd9Sstevel@tonic-gate 	/*
2867c478bd9Sstevel@tonic-gate 	 * Start status phase
2877c478bd9Sstevel@tonic-gate 	 * read in CSW
2887c478bd9Sstevel@tonic-gate 	 */
28963602c90Sfb 	req->bulk_timeout = scsa2usb_bulk_timeout(SCSA2USB_BULK_PIPE_TIMEOUT);
29063602c90Sfb 
2916d9a41ffSqz 	for (nretry = 0; nretry < SCSA2USB_STATUS_RETRIES; nretry++) {
2926d9a41ffSqz 		rval = scsa2usb_handle_status_start(scsa2usbp, req);
2937c478bd9Sstevel@tonic-gate 
2946d9a41ffSqz 		if ((rval != USB_SUCCESS) &&
2956d9a41ffSqz 		    (req->bulk_completion_reason == USB_CR_STALL)) {
2966d9a41ffSqz 			/*
2976d9a41ffSqz 			 * We ran into STALL condition here.
2986d9a41ffSqz 			 * If the condition cannot be cleared
2996d9a41ffSqz 			 * successfully, retry for limited times.
3006d9a41ffSqz 			 */
3016d9a41ffSqz 			scsa2usbp->scsa2usb_pkt_state =
30263602c90Sfb 			    SCSA2USB_PKT_PROCESS_CSW;
3037c478bd9Sstevel@tonic-gate 		} else {
3047c478bd9Sstevel@tonic-gate 
3056d9a41ffSqz 			break;
3067c478bd9Sstevel@tonic-gate 		}
3077c478bd9Sstevel@tonic-gate 	}
3087c478bd9Sstevel@tonic-gate 
3096d9a41ffSqz 	if (rval == USB_SUCCESS) {
3106d9a41ffSqz 		/* process CSW */
3116d9a41ffSqz 		rval = scsa2usb_handle_csw_result(scsa2usbp, req->bulk_data);
3126d9a41ffSqz 	} else {
3136d9a41ffSqz 		scsa2usb_bulk_only_handle_error(scsa2usbp, req);
3146d9a41ffSqz 
3156d9a41ffSqz 		return (TRAN_FATAL_ERROR);
3166d9a41ffSqz 	}
3176d9a41ffSqz 
3187c478bd9Sstevel@tonic-gate 	SCSA2USB_FREE_BULK_REQ(req);	/* free request */
3197c478bd9Sstevel@tonic-gate 
3207c478bd9Sstevel@tonic-gate 	if ((rval == USB_SUCCESS) &&		/* CSW was ok */
3217c478bd9Sstevel@tonic-gate 	    (scsa2usbp->scsa2usb_cur_pkt->pkt_reason == CMD_CMPLT) &&
3227c478bd9Sstevel@tonic-gate 	    (cmd->cmd_xfercount != 0) &&	/* more data to xfer */
3237c478bd9Sstevel@tonic-gate 	    !cmd->cmd_done) {			/* we aren't done yet */
3247c478bd9Sstevel@tonic-gate 		scsa2usb_setup_next_xfer(scsa2usbp, cmd);
3257c478bd9Sstevel@tonic-gate 		goto Cmd_Phase;
3267c478bd9Sstevel@tonic-gate 	}
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate 	return (rval == USB_SUCCESS ? TRAN_ACCEPT : TRAN_FATAL_ERROR);
3297c478bd9Sstevel@tonic-gate }
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate /*
3337c478bd9Sstevel@tonic-gate  * scsa2usb_fill_in_cbw:
3347c478bd9Sstevel@tonic-gate  *	Fill in a CBW request packet. This
3357c478bd9Sstevel@tonic-gate  *	packet is transported to the device
3367c478bd9Sstevel@tonic-gate  */
3377c478bd9Sstevel@tonic-gate static void
3387c478bd9Sstevel@tonic-gate scsa2usb_fill_in_cbw(scsa2usb_state_t *scsa2usbp,
3397c478bd9Sstevel@tonic-gate     scsa2usb_cmd_t *cmd, mblk_t *mp)
3407c478bd9Sstevel@tonic-gate {
3417c478bd9Sstevel@tonic-gate 	int	i;
3427c478bd9Sstevel@tonic-gate 	int	len;
3437c478bd9Sstevel@tonic-gate 	uchar_t dir, *cdb = (uchar_t *)(&cmd->cmd_cdb);
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate 	*mp->b_wptr++ = CBW_MSB(CBW_SIGNATURE);	/* CBW Signature */;
3487c478bd9Sstevel@tonic-gate 	*mp->b_wptr++ = CBW_MID1(CBW_SIGNATURE);
3497c478bd9Sstevel@tonic-gate 	*mp->b_wptr++ = CBW_MID2(CBW_SIGNATURE);
3507c478bd9Sstevel@tonic-gate 	*mp->b_wptr++ = CBW_LSB(CBW_SIGNATURE);
3517c478bd9Sstevel@tonic-gate 	*mp->b_wptr++ = CBW_LSB(cmd->cmd_tag);	/* CBW Tag */
3527c478bd9Sstevel@tonic-gate 	*mp->b_wptr++ = CBW_MID2(cmd->cmd_tag);
3537c478bd9Sstevel@tonic-gate 	*mp->b_wptr++ = CBW_MID1(cmd->cmd_tag);
3547c478bd9Sstevel@tonic-gate 	*mp->b_wptr++ = CBW_MSB(cmd->cmd_tag);
3557c478bd9Sstevel@tonic-gate 
3567c478bd9Sstevel@tonic-gate 	dir = cmd->cmd_dir;
3577c478bd9Sstevel@tonic-gate 	len = cmd->cmd_xfercount;
3587c478bd9Sstevel@tonic-gate #ifdef	SCSA2USB_BULK_ONLY_TEST
3597c478bd9Sstevel@tonic-gate 	if (scsa2usb_test_case_2 && (cdb[0] == SCMD_READ_CAPACITY)) {
3607c478bd9Sstevel@tonic-gate 		/* Host expects no data. The device wants data. Hn < Di */
3617c478bd9Sstevel@tonic-gate 		scsa2usb_test_case_2 = len = 0;
3627c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L1(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
3637c478bd9Sstevel@tonic-gate 		    "TEST 2: Hn < Di cdb: 0x%x len: 0x%x", cdb[0], len);
3647c478bd9Sstevel@tonic-gate 	}
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate 	if (scsa2usb_test_case_3 && (cmd->cmd_dir == CBW_DIR_OUT)) {
3677c478bd9Sstevel@tonic-gate 		/* Host expects no data. The device wants data. Hn < Do */
3687c478bd9Sstevel@tonic-gate 		if (cdb[0] == SCMD_WRITE_G1) {
3697c478bd9Sstevel@tonic-gate 			scsa2usb_test_case_3 = len = 0;
3707c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_SCSA,
3717c478bd9Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
3727c478bd9Sstevel@tonic-gate 			    "TEST 3: Hn < Do cdb: 0x%x len:%x", cdb[0], len);
3737c478bd9Sstevel@tonic-gate 		}
3747c478bd9Sstevel@tonic-gate 	}
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate 	if (scsa2usb_test_case_4 && (cdb[0] == SCMD_READ_G1)) {
3777c478bd9Sstevel@tonic-gate 		cdb[0] = 0x5e;
3787c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L1(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
3797c478bd9Sstevel@tonic-gate 		    "TEST 4: Hi > Dn: changed cdb to 0x%x", cdb[0]);
3807c478bd9Sstevel@tonic-gate 		scsa2usb_test_case_4 = 0;
3817c478bd9Sstevel@tonic-gate 	}
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate 	if (scsa2usb_test_case_7 && (cmd->cmd_cdb[0] == SCMD_READ_G1)) {
3847c478bd9Sstevel@tonic-gate 		len -= 0x10;
3857c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L1(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
3867c478bd9Sstevel@tonic-gate 		    "TEST 7: Hi < Di cdb: 0x%x len: 0x%x", cdb[0], len);
3877c478bd9Sstevel@tonic-gate 		scsa2usb_test_case_7 = 0;
3887c478bd9Sstevel@tonic-gate 	}
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate 	if (scsa2usb_test_case_8 && (cdb[0] == SCMD_READ_G1)) {
3917c478bd9Sstevel@tonic-gate 		dir = (dir == CBW_DIR_IN) ? CBW_DIR_OUT : dir;
3927c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L1(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
3937c478bd9Sstevel@tonic-gate 		    "TEST 8: Hi <> Do cdb: 0x%x dir: 0x%x", cdb[0], dir);
3947c478bd9Sstevel@tonic-gate 	}
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate 	if (scsa2usb_test_case_9 && (cdb[0] == SCMD_WRITE_G1)) {
3977c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L1(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
3987c478bd9Sstevel@tonic-gate 		    "TEST 9: Ho <> Di (%x)", cdb[0]);
3997c478bd9Sstevel@tonic-gate 		cdb[SCSA2USB_LEN_0] = cdb[SCSA2USB_LEN_1] = 0;
4007c478bd9Sstevel@tonic-gate 		scsa2usb_test_case_9 = 0;
4017c478bd9Sstevel@tonic-gate 	}
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate 	if (scsa2usb_test_case_10 && (cdb[0] == SCMD_WRITE_G1)) {
4047c478bd9Sstevel@tonic-gate 		dir = (dir == CBW_DIR_OUT) ? CBW_DIR_IN : dir;
4057c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L1(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
4067c478bd9Sstevel@tonic-gate 		    "TEST 10: Ho <> Di cdb: 0x%x dir: 0x%x", cdb[0], dir);
4077c478bd9Sstevel@tonic-gate 	}
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate 	/*
4107c478bd9Sstevel@tonic-gate 	 * This case occurs when the device intends to receive
4117c478bd9Sstevel@tonic-gate 	 * more data from the host than the host sends.
4127c478bd9Sstevel@tonic-gate 	 */
4137c478bd9Sstevel@tonic-gate 	if (scsa2usb_test_case_13) {
4147c478bd9Sstevel@tonic-gate 		if ((cdb[0] == SCMD_WRITE_G1) || (cdb[0] == SCMD_READ_G1)) {
4157c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_SCSA,
4167c478bd9Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle, "TEST 13: Ho < Do");
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate 			len -= 30;
4197c478bd9Sstevel@tonic-gate 			scsa2usb_test_case_13 = 0;
4207c478bd9Sstevel@tonic-gate 		}
4217c478bd9Sstevel@tonic-gate 	}
4227c478bd9Sstevel@tonic-gate #endif	/* SCSA2USB_BULK_ONLY_TEST */
4237c478bd9Sstevel@tonic-gate 
4247c478bd9Sstevel@tonic-gate 	*mp->b_wptr++ = CBW_MSB(len);		/* Transfer Length */
4257c478bd9Sstevel@tonic-gate 	*mp->b_wptr++ = CBW_MID1(len);
4267c478bd9Sstevel@tonic-gate 	*mp->b_wptr++ = CBW_MID2(len);
4277c478bd9Sstevel@tonic-gate 	*mp->b_wptr++ = CBW_LSB(len);
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate 	*mp->b_wptr++ = dir;			/* Transfer Direction */
4307c478bd9Sstevel@tonic-gate 	*mp->b_wptr++ = cmd->cmd_pkt->pkt_address.a_lun;	/* Lun # */
4317c478bd9Sstevel@tonic-gate 	*mp->b_wptr++ = cmd->cmd_actual_len;			/* CDB Len */
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate 	/* Copy the CDB out */
4347c478bd9Sstevel@tonic-gate 	for (i = 0; i < CBW_CDB_LEN; i++) {
4357c478bd9Sstevel@tonic-gate 		*mp->b_wptr++ = *cdb++;
4367c478bd9Sstevel@tonic-gate 	}
4377c478bd9Sstevel@tonic-gate #ifdef DUMP_CWB
4387c478bd9Sstevel@tonic-gate {
4397c478bd9Sstevel@tonic-gate 	int len = mp->b_wptr - mp->b_rptr;
4407c478bd9Sstevel@tonic-gate 	char *buf;
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate 	int i;
4437c478bd9Sstevel@tonic-gate 
4447c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "CWB: len=%d\n", len);
4457c478bd9Sstevel@tonic-gate 	buf = kmem_zalloc(512, KM_SLEEP);
4467c478bd9Sstevel@tonic-gate 	for (i = 0; i < len; i++) {
4477c478bd9Sstevel@tonic-gate 		sprintf(&buf[strlen(buf)], "%02x ", mp->b_rptr[i]);
4487c478bd9Sstevel@tonic-gate 	}
4497c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "%s\n", buf);
4507c478bd9Sstevel@tonic-gate 	kmem_free(buf, 512);
4517c478bd9Sstevel@tonic-gate }
4527c478bd9Sstevel@tonic-gate #endif
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate }
4557c478bd9Sstevel@tonic-gate 
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate /*
4587c478bd9Sstevel@tonic-gate  * scsa2usb_bulk_only_handle_error:
4597c478bd9Sstevel@tonic-gate  *	handle transport errors and start recovery
4607c478bd9Sstevel@tonic-gate  */
4617c478bd9Sstevel@tonic-gate static void
4627c478bd9Sstevel@tonic-gate scsa2usb_bulk_only_handle_error(scsa2usb_state_t *scsa2usbp,
4637c478bd9Sstevel@tonic-gate     usb_bulk_req_t *req)
4647c478bd9Sstevel@tonic-gate {
4657c478bd9Sstevel@tonic-gate 	struct scsi_pkt *pkt = scsa2usbp->scsa2usb_cur_pkt;
4667c478bd9Sstevel@tonic-gate 
4677c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
4687c478bd9Sstevel@tonic-gate 	    "scsa2usb_bulk_only_handle_error: req = 0x%p, cr = 0x%x",
469112116d8Sfb 	    (void *)req, (req ? req->bulk_completion_reason : 0));
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 	if (req) {
4727c478bd9Sstevel@tonic-gate 		SCSA2USB_SET_PKT_DO_COMP_STATE(scsa2usbp);
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate 		/* invoke reset recovery */
4757c478bd9Sstevel@tonic-gate 		switch (req->bulk_completion_reason) {
4767c478bd9Sstevel@tonic-gate 		case USB_CR_STALL:
4777c478bd9Sstevel@tonic-gate 			if (pkt) {
4787c478bd9Sstevel@tonic-gate 				pkt->pkt_reason = CMD_TRAN_ERR;
4797c478bd9Sstevel@tonic-gate 			}
4807c478bd9Sstevel@tonic-gate 			break;
4817c478bd9Sstevel@tonic-gate 		case USB_CR_TIMEOUT:
4827c478bd9Sstevel@tonic-gate 			if (pkt) {
4837c478bd9Sstevel@tonic-gate 				pkt->pkt_reason = CMD_TIMEOUT;
4847c478bd9Sstevel@tonic-gate 				pkt->pkt_statistics |= STAT_TIMEOUT;
4857c478bd9Sstevel@tonic-gate 			}
4867c478bd9Sstevel@tonic-gate 			break;
4877c478bd9Sstevel@tonic-gate 		case USB_CR_DEV_NOT_RESP:
4887c478bd9Sstevel@tonic-gate 			if (pkt) {
4897c478bd9Sstevel@tonic-gate 				pkt->pkt_reason = CMD_DEV_GONE;
4907c478bd9Sstevel@tonic-gate 				/* scsi_poll relies on this */
4917c478bd9Sstevel@tonic-gate 				pkt->pkt_state = STATE_GOT_BUS;
4927c478bd9Sstevel@tonic-gate 			}
4937c478bd9Sstevel@tonic-gate 			break;
4947c478bd9Sstevel@tonic-gate 		default:
4957c478bd9Sstevel@tonic-gate 			if (pkt) {
4967c478bd9Sstevel@tonic-gate 				pkt->pkt_reason = CMD_TRAN_ERR;
4977c478bd9Sstevel@tonic-gate 			}
4987c478bd9Sstevel@tonic-gate 		}
4997c478bd9Sstevel@tonic-gate 		scsa2usb_bulk_only_reset_recovery(scsa2usbp);
5007c478bd9Sstevel@tonic-gate 	}
5017c478bd9Sstevel@tonic-gate 
5027c478bd9Sstevel@tonic-gate 	SCSA2USB_FREE_BULK_REQ(req);
5037c478bd9Sstevel@tonic-gate }
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate 
5067c478bd9Sstevel@tonic-gate /*
5077c478bd9Sstevel@tonic-gate  * scsa2usb_handle_status_start:
5087c478bd9Sstevel@tonic-gate  *	Receive status data
5097c478bd9Sstevel@tonic-gate  */
5107c478bd9Sstevel@tonic-gate static int
5117c478bd9Sstevel@tonic-gate scsa2usb_handle_status_start(scsa2usb_state_t *scsa2usbp,
5127c478bd9Sstevel@tonic-gate     usb_bulk_req_t *req)
5137c478bd9Sstevel@tonic-gate {
5147c478bd9Sstevel@tonic-gate 	int rval;
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
517112116d8Sfb 	    "scsa2usb_handle_status_start: req = 0x%p", (void *)req);
5187c478bd9Sstevel@tonic-gate 
5197c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate 	/* setup up for receiving CSW */
5227c478bd9Sstevel@tonic-gate #ifdef	SCSA2USB_BULK_ONLY_TEST
5237c478bd9Sstevel@tonic-gate 	req->bulk_attributes = 0;
5247c478bd9Sstevel@tonic-gate #else
5257c478bd9Sstevel@tonic-gate 	req->bulk_attributes = USB_ATTRS_SHORT_XFER_OK;
5267c478bd9Sstevel@tonic-gate #endif	/* SCSA2USB_BULK_ONLY_TEST */
5277c478bd9Sstevel@tonic-gate 	req->bulk_len = CSW_LEN;
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate 	SCSA2USB_FREE_MSG(req->bulk_data);
5307c478bd9Sstevel@tonic-gate 	req->bulk_data = allocb_wait(req->bulk_len,
5317c478bd9Sstevel@tonic-gate 	    BPRI_LO, STR_NOSIG, NULL);
5327c478bd9Sstevel@tonic-gate 
5337c478bd9Sstevel@tonic-gate 	/* Issue the request */
5347c478bd9Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate 	ASSERT(req->bulk_timeout);
5377c478bd9Sstevel@tonic-gate 	rval = usb_pipe_bulk_xfer(scsa2usbp->scsa2usb_bulkin_pipe, req,
5387c478bd9Sstevel@tonic-gate 	    USB_FLAGS_SLEEP);
5397c478bd9Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
5407c478bd9Sstevel@tonic-gate 
5417c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
5427c478bd9Sstevel@tonic-gate 	    "scsa2usb_handle_status_start: END rval = 0x%x", rval);
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate 	if (rval != USB_SUCCESS) {
5457c478bd9Sstevel@tonic-gate 		if (scsa2usbp->scsa2usb_pkt_state == SCSA2USB_PKT_PROCESS_CSW) {
5467c478bd9Sstevel@tonic-gate 			scsa2usb_bulk_only_reset_recovery(scsa2usbp);
5477c478bd9Sstevel@tonic-gate 
5487c478bd9Sstevel@tonic-gate 			return (rval);
5497c478bd9Sstevel@tonic-gate 		}
5507c478bd9Sstevel@tonic-gate 
5517c478bd9Sstevel@tonic-gate 		if (req->bulk_completion_reason == USB_CR_STALL) {
5527c478bd9Sstevel@tonic-gate 			(void) scsa2usb_clear_ept_stall(scsa2usbp,
5537c478bd9Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_bulkin_ept.bEndpointAddress,
5547c478bd9Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_bulkin_pipe, "bulk-in");
5557c478bd9Sstevel@tonic-gate 		}
5567c478bd9Sstevel@tonic-gate 	}
5577c478bd9Sstevel@tonic-gate 
5587c478bd9Sstevel@tonic-gate 	return (rval);
5597c478bd9Sstevel@tonic-gate }
5607c478bd9Sstevel@tonic-gate 
5617c478bd9Sstevel@tonic-gate 
5627c478bd9Sstevel@tonic-gate /*
5637c478bd9Sstevel@tonic-gate  * scsa2usb_handle_csw_result:
5647c478bd9Sstevel@tonic-gate  *	Handle status results
5657c478bd9Sstevel@tonic-gate  */
5667c478bd9Sstevel@tonic-gate static int
5677c478bd9Sstevel@tonic-gate scsa2usb_handle_csw_result(scsa2usb_state_t *scsa2usbp, mblk_t *data)
5687c478bd9Sstevel@tonic-gate {
5697c478bd9Sstevel@tonic-gate 	int		rval = USB_SUCCESS;
5707c478bd9Sstevel@tonic-gate 	int		residue;
5717c478bd9Sstevel@tonic-gate 	char		*msg = "CSW FAILED";
5727c478bd9Sstevel@tonic-gate 	uint_t		signature, tag, status;
5737c478bd9Sstevel@tonic-gate 	usb_bulk_csw_t	csw;
5747c478bd9Sstevel@tonic-gate 	struct scsi_pkt *pkt = scsa2usbp->scsa2usb_cur_pkt;
5757c478bd9Sstevel@tonic-gate 	scsa2usb_cmd_t	*cmd = PKT2CMD(pkt);
5767c478bd9Sstevel@tonic-gate 
5777c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate 	/*
5807c478bd9Sstevel@tonic-gate 	 * This shouldn't happen. It implies the device's
5817c478bd9Sstevel@tonic-gate 	 * firmware is bad and has returned NULL CSW.
5827c478bd9Sstevel@tonic-gate 	 * return failure back.
5837c478bd9Sstevel@tonic-gate 	 */
5847c478bd9Sstevel@tonic-gate 	if (data == NULL) {
5857c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
5867c478bd9Sstevel@tonic-gate 		    "scsa2usb_handle_csw_result: data == NULL");
5877c478bd9Sstevel@tonic-gate 
5887c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
5897c478bd9Sstevel@tonic-gate 	}
5907c478bd9Sstevel@tonic-gate 
5917c478bd9Sstevel@tonic-gate 	/* check if we got back CSW_LEN or not */
592*d29f5a71Szhigang lu - Sun Microsystems - Beijing China 	if (MBLKL(data) != CSW_LEN) {
5937c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
594112116d8Sfb 		    "scsa2usb_handle_csw_result: no enough data (%ld)",
595*d29f5a71Szhigang lu - Sun Microsystems - Beijing China 		    (long)(MBLKL(data)));
5967c478bd9Sstevel@tonic-gate 
5977c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
5987c478bd9Sstevel@tonic-gate 	}
5997c478bd9Sstevel@tonic-gate 
6007c478bd9Sstevel@tonic-gate 	/* Read into csw */
6017c478bd9Sstevel@tonic-gate 	bcopy(data->b_rptr, &csw, CSW_LEN);
6027c478bd9Sstevel@tonic-gate 
6037c478bd9Sstevel@tonic-gate 	status = csw.csw_bCSWStatus;
6047c478bd9Sstevel@tonic-gate 	signature = SCSA2USB_MK_32BIT(csw.csw_dCSWSignature3,
6057c478bd9Sstevel@tonic-gate 	    csw.csw_dCSWSignature2, csw.csw_dCSWSignature1,
6067c478bd9Sstevel@tonic-gate 	    csw.csw_dCSWSignature0);
6077c478bd9Sstevel@tonic-gate 	residue = SCSA2USB_MK_32BIT(csw.csw_dCSWDataResidue3,
6087c478bd9Sstevel@tonic-gate 	    csw.csw_dCSWDataResidue2, csw.csw_dCSWDataResidue1,
6097c478bd9Sstevel@tonic-gate 	    csw.csw_dCSWDataResidue0);
6107c478bd9Sstevel@tonic-gate 	tag = SCSA2USB_MK_32BIT(csw.csw_dCSWTag3, csw.csw_dCSWTag2,
6117c478bd9Sstevel@tonic-gate 	    csw.csw_dCSWTag1, csw.csw_dCSWTag0);
6127c478bd9Sstevel@tonic-gate 
6137c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
6147c478bd9Sstevel@tonic-gate 	    "CSW: Signature = 0x%x Status = 0%x Tag = 0x%x Residue = 0x%x",
6157c478bd9Sstevel@tonic-gate 	    signature, status, tag,  residue);
6167c478bd9Sstevel@tonic-gate 
6177c478bd9Sstevel@tonic-gate 	/* Check for abnormal errors */
6187c478bd9Sstevel@tonic-gate 	if ((signature != CSW_SIGNATURE) || (tag != cmd->cmd_tag) ||
619*d29f5a71Szhigang lu - Sun Microsystems - Beijing China 	    (status > CSW_STATUS_PHASE_ERROR)) {
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
6227c478bd9Sstevel@tonic-gate 		    "CSW_ERR: Status = 0x%x, Tag = 0x%x xfercount = 0x%lx",
6237c478bd9Sstevel@tonic-gate 		    status, cmd->cmd_tag, cmd->cmd_total_xfercount);
6247c478bd9Sstevel@tonic-gate 
6257c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
6267c478bd9Sstevel@tonic-gate 	}
6277c478bd9Sstevel@tonic-gate 
6287c478bd9Sstevel@tonic-gate 	switch (status) {
6297c478bd9Sstevel@tonic-gate 	case CSW_STATUS_GOOD:
6307c478bd9Sstevel@tonic-gate 		/*
6317c478bd9Sstevel@tonic-gate 		 * Fail the command if the device misbehaves and
6327c478bd9Sstevel@tonic-gate 		 * gives a good status but doesn't transfer any data.
6337c478bd9Sstevel@tonic-gate 		 * Otherwise we'll get into an infinite retry loop.
6347c478bd9Sstevel@tonic-gate 		 *
6357c478bd9Sstevel@tonic-gate 		 * We test only against cmd_total_xfercount here and
6367c478bd9Sstevel@tonic-gate 		 * assume that this will not happen on a command that
6377c478bd9Sstevel@tonic-gate 		 * transfers a large amount of data and therefore may
6387c478bd9Sstevel@tonic-gate 		 * be split into separate transfers. For a large data
6397c478bd9Sstevel@tonic-gate 		 * transfer it is assumed that the device will return
6407c478bd9Sstevel@tonic-gate 		 * an error status if the transfer does not occur.
6417c478bd9Sstevel@tonic-gate 		 * this isn't quite correct because a subsequent request
6427c478bd9Sstevel@tonic-gate 		 * sense may not give a valid sense key.
6437c478bd9Sstevel@tonic-gate 		 */
6447c478bd9Sstevel@tonic-gate 		if (!cmd->cmd_done && residue &&
6457c478bd9Sstevel@tonic-gate 		    (residue == cmd->cmd_total_xfercount)) {
6467c478bd9Sstevel@tonic-gate 			*(pkt->pkt_scbp) = STATUS_CHECK;
6477c478bd9Sstevel@tonic-gate 			cmd->cmd_xfercount = 0;
6487c478bd9Sstevel@tonic-gate 			cmd->cmd_done = 1;
6497c478bd9Sstevel@tonic-gate 		} else {
6507c478bd9Sstevel@tonic-gate 			msg = "CSW GOOD";
6517c478bd9Sstevel@tonic-gate 		}
6527c478bd9Sstevel@tonic-gate 		break;
6537c478bd9Sstevel@tonic-gate 	case CSW_STATUS_FAILED:
6547c478bd9Sstevel@tonic-gate 		*(pkt->pkt_scbp) = STATUS_CHECK; /* Set check condition */
6557c478bd9Sstevel@tonic-gate 		cmd->cmd_done = 1;
6567c478bd9Sstevel@tonic-gate 		break;
6577c478bd9Sstevel@tonic-gate 	case CSW_STATUS_PHASE_ERROR:
6587c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
6597c478bd9Sstevel@tonic-gate 		    "scsa2usb_handle_csw_result: Phase Error");
6607c478bd9Sstevel@tonic-gate 
6617c478bd9Sstevel@tonic-gate 		/* invoke reset recovery */
6627c478bd9Sstevel@tonic-gate 		scsa2usb_bulk_only_handle_error(scsa2usbp, NULL);
6637c478bd9Sstevel@tonic-gate 
6647c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
6657c478bd9Sstevel@tonic-gate 	default:	/* shouldn't happen anymore */
6667c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
6677c478bd9Sstevel@tonic-gate 		    "scsa2usb_handle_csw_result: Invalid CSW");
6687c478bd9Sstevel@tonic-gate 
6697c478bd9Sstevel@tonic-gate 		/* invoke reset recovery */
6707c478bd9Sstevel@tonic-gate 		scsa2usb_bulk_only_handle_error(scsa2usbp, NULL);
6717c478bd9Sstevel@tonic-gate 
6727c478bd9Sstevel@tonic-gate 		return (USB_SUCCESS);
6737c478bd9Sstevel@tonic-gate 	} /* end of switch */
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate 	/* Set resid */
6767c478bd9Sstevel@tonic-gate 	if (residue || cmd->cmd_resid_xfercount) {
6777c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA,
6787c478bd9Sstevel@tonic-gate 		    scsa2usbp->scsa2usb_log_handle,
6793fbbb872Ssl 		    "total=0x%lx cmd_xfercount=0x%lx residue=0x%x "
6803fbbb872Ssl 		    "cmd_offset=0x%lx",
6817c478bd9Sstevel@tonic-gate 		    cmd->cmd_total_xfercount, cmd->cmd_xfercount,
6823fbbb872Ssl 		    residue, cmd->cmd_offset);
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate 		/*
6857c478bd9Sstevel@tonic-gate 		 * we need to adjust using the residue and
6867c478bd9Sstevel@tonic-gate 		 * assume worst case. Some devices lie about
6877c478bd9Sstevel@tonic-gate 		 * residue. some report a residue greater than
6887c478bd9Sstevel@tonic-gate 		 * the residue we have calculated.
6897c478bd9Sstevel@tonic-gate 		 * first adjust back the total_xfercount
6907c478bd9Sstevel@tonic-gate 		 */
6917c478bd9Sstevel@tonic-gate 		cmd->cmd_total_xfercount += cmd->cmd_xfercount -
69263602c90Sfb 		    cmd->cmd_resid_xfercount;
6933fbbb872Ssl 		/*
6943fbbb872Ssl 		 * we need to adjust cmd_offset as well, or the data
6953fbbb872Ssl 		 * buffer for subsequent transfer may exceed the buffer
6963fbbb872Ssl 		 * boundary
6973fbbb872Ssl 		 */
6983fbbb872Ssl 		cmd->cmd_offset -= cmd->cmd_xfercount -
6993fbbb872Ssl 		    cmd->cmd_resid_xfercount;
7007c478bd9Sstevel@tonic-gate 
7017c478bd9Sstevel@tonic-gate 		/*
7027c478bd9Sstevel@tonic-gate 		 * now take the min of the reported residue by
7037c478bd9Sstevel@tonic-gate 		 * the device and the requested xfer count
7047c478bd9Sstevel@tonic-gate 		 * (just in case the device reported a residue greater
7057c478bd9Sstevel@tonic-gate 		 * than our request count).
7067c478bd9Sstevel@tonic-gate 		 * then take the max of this residue and the residue
7077c478bd9Sstevel@tonic-gate 		 * that the HCD reported and subtract this from
7087c478bd9Sstevel@tonic-gate 		 * the request count. This is the actual number
7097c478bd9Sstevel@tonic-gate 		 * of valid bytes transferred during the last transfer
7107c478bd9Sstevel@tonic-gate 		 * which we now subtract from the total_xfercount
7117c478bd9Sstevel@tonic-gate 		 */
7122115f0c6Ssl 		if ((!(scsa2usbp->scsa2usb_attrs &
7132115f0c6Ssl 		    SCSA2USB_ATTRS_USE_CSW_RESIDUE)) ||
7142115f0c6Ssl 		    (residue < 0) ||
7157c478bd9Sstevel@tonic-gate 		    (residue > cmd->cmd_total_xfercount)) {
7162115f0c6Ssl 			/* some devices lie about the resid, ignore */
7172115f0c6Ssl 			cmd->cmd_total_xfercount -=
7182115f0c6Ssl 			    cmd->cmd_xfercount - cmd->cmd_resid_xfercount;
7193fbbb872Ssl 			cmd->cmd_offset +=
7203fbbb872Ssl 			    cmd->cmd_xfercount - cmd->cmd_resid_xfercount;
7212115f0c6Ssl 		} else {
7222115f0c6Ssl 			cmd->cmd_total_xfercount -=
7232115f0c6Ssl 			    cmd->cmd_xfercount -
7242115f0c6Ssl 			    max(min(residue, cmd->cmd_xfercount),
7252115f0c6Ssl 			    cmd->cmd_resid_xfercount);
7263fbbb872Ssl 			cmd->cmd_offset +=
7273fbbb872Ssl 			    cmd->cmd_xfercount -
7283fbbb872Ssl 			    max(min(residue, cmd->cmd_xfercount),
7293fbbb872Ssl 			    cmd->cmd_resid_xfercount);
7303fbbb872Ssl 			/*
7313fbbb872Ssl 			 * if HCD does not report residue while the device
7323fbbb872Ssl 			 * reports a residue equivalent to the xfercount,
7333fbbb872Ssl 			 * it is very likely the device lies about the
7343fbbb872Ssl 			 * residue. we need to stop the command, or we'll
7353fbbb872Ssl 			 * get into an infinite retry loop.
7363fbbb872Ssl 			 */
7373fbbb872Ssl 			if ((cmd->cmd_resid_xfercount == 0) &&
7383fbbb872Ssl 			    (residue == cmd->cmd_xfercount)) {
7393fbbb872Ssl 				cmd->cmd_xfercount = 0;
7403fbbb872Ssl 				cmd->cmd_done = 1;
7413fbbb872Ssl 			}
7427c478bd9Sstevel@tonic-gate 		}
7437c478bd9Sstevel@tonic-gate 
7447c478bd9Sstevel@tonic-gate 		pkt->pkt_resid = cmd->cmd_total_xfercount;
7457c478bd9Sstevel@tonic-gate 	}
7467c478bd9Sstevel@tonic-gate 
7477c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
7487c478bd9Sstevel@tonic-gate 	    "scsa2usb_handle_csw_result: %s, resid: 0x%lx",
7497c478bd9Sstevel@tonic-gate 	    msg, pkt->pkt_resid);
7507c478bd9Sstevel@tonic-gate 
7517c478bd9Sstevel@tonic-gate 	/* we are done and ready to callback */
7527c478bd9Sstevel@tonic-gate 	SCSA2USB_SET_PKT_DO_COMP_STATE(scsa2usbp);
7537c478bd9Sstevel@tonic-gate 
7547c478bd9Sstevel@tonic-gate 	return (rval);
7557c478bd9Sstevel@tonic-gate }
7567c478bd9Sstevel@tonic-gate 
7577c478bd9Sstevel@tonic-gate 
7587c478bd9Sstevel@tonic-gate /*
7597c478bd9Sstevel@tonic-gate  * scsa2usb_bulk_only_reset_recovery:
7607c478bd9Sstevel@tonic-gate  *	Reset the USB device step-wise in case of errors.
7617c478bd9Sstevel@tonic-gate  *	NOTE that the order of reset is very important.
7627c478bd9Sstevel@tonic-gate  */
7637c478bd9Sstevel@tonic-gate static void
7647c478bd9Sstevel@tonic-gate scsa2usb_bulk_only_reset_recovery(scsa2usb_state_t *scsa2usbp)
7657c478bd9Sstevel@tonic-gate {
7667c478bd9Sstevel@tonic-gate 	int		rval;
7677c478bd9Sstevel@tonic-gate 	usb_cr_t	completion_reason;
7687c478bd9Sstevel@tonic-gate 	usb_cb_flags_t	cb_flags;
7697c478bd9Sstevel@tonic-gate 
7707c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
771112116d8Sfb 	    "scsa2usb_bulk_only_reset_recovery: scsa2usbp = 0x%p",
772112116d8Sfb 	    (void *)scsa2usbp);
7737c478bd9Sstevel@tonic-gate 
7747c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
7757c478bd9Sstevel@tonic-gate 
7767c478bd9Sstevel@tonic-gate 	if (!(SCSA2USB_DEVICE_ACCESS_OK(scsa2usbp))) {
7777c478bd9Sstevel@tonic-gate 
7787c478bd9Sstevel@tonic-gate 		return;
7797c478bd9Sstevel@tonic-gate 	}
7807c478bd9Sstevel@tonic-gate 
7817c478bd9Sstevel@tonic-gate 	/*
7827c478bd9Sstevel@tonic-gate 	 * assume that the reset will be successful. if it isn't, retrying
7837c478bd9Sstevel@tonic-gate 	 * from target driver won't help much
7847c478bd9Sstevel@tonic-gate 	 */
7857c478bd9Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_cur_pkt) {
7867c478bd9Sstevel@tonic-gate 		scsa2usbp->scsa2usb_cur_pkt->pkt_statistics |= STAT_DEV_RESET;
7877c478bd9Sstevel@tonic-gate 	}
7887c478bd9Sstevel@tonic-gate 
7897c478bd9Sstevel@tonic-gate 	/* set the reset condition */
7907c478bd9Sstevel@tonic-gate 	scsa2usbp->scsa2usb_pipe_state = SCSA2USB_PIPE_DEV_RESET;
7917c478bd9Sstevel@tonic-gate 
7927c478bd9Sstevel@tonic-gate 	/* Send a sync DEVICE-RESET request to the device */
7937c478bd9Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
7947c478bd9Sstevel@tonic-gate 	rval = usb_pipe_sync_ctrl_xfer(scsa2usbp->scsa2usb_dip,
7957c478bd9Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_default_pipe,
7967c478bd9Sstevel@tonic-gate 	    USB_DEV_REQ_TYPE_CLASS | USB_DEV_REQ_RCPT_IF,
7977c478bd9Sstevel@tonic-gate 	    (uint8_t)BULK_ONLY_RESET,		/* bRequest */
7987c478bd9Sstevel@tonic-gate 	    0,					/* wValue */
7997c478bd9Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_intfc_num,	/* wIndex */
8007c478bd9Sstevel@tonic-gate 	    0,					/* wLength */
8017c478bd9Sstevel@tonic-gate 	    NULL, 0, &completion_reason, &cb_flags, 0);
8027c478bd9Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
8037c478bd9Sstevel@tonic-gate 
8047c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
8057c478bd9Sstevel@tonic-gate 	    "\tbulk-only device-reset rval: %d", rval);
8067c478bd9Sstevel@tonic-gate 	if (rval != USB_SUCCESS) {
8077c478bd9Sstevel@tonic-gate 		goto exc_exit;
8087c478bd9Sstevel@tonic-gate 	}
8097c478bd9Sstevel@tonic-gate 
8107c478bd9Sstevel@tonic-gate 	/* reset and clear STALL on bulk-in pipe */
8117c478bd9Sstevel@tonic-gate 	rval = scsa2usb_clear_ept_stall(scsa2usbp,
8127c478bd9Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_bulkin_ept.bEndpointAddress,
8137c478bd9Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_bulkin_pipe, "bulk-in");
8147c478bd9Sstevel@tonic-gate 
8157c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
8167c478bd9Sstevel@tonic-gate 	    "\tbulk-in pipe clear stall: %d", rval);
8177c478bd9Sstevel@tonic-gate 	if (rval != USB_SUCCESS) {
8187c478bd9Sstevel@tonic-gate 		goto exc_exit;
8197c478bd9Sstevel@tonic-gate 	}
8207c478bd9Sstevel@tonic-gate 
8217c478bd9Sstevel@tonic-gate 	/* reset and clear STALL on bulk-out pipe */
8227c478bd9Sstevel@tonic-gate 	rval = scsa2usb_clear_ept_stall(scsa2usbp,
8237c478bd9Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_bulkout_ept.bEndpointAddress,
8247c478bd9Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_bulkout_pipe, "bulk-out");
8257c478bd9Sstevel@tonic-gate 
8267c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
8277c478bd9Sstevel@tonic-gate 	    "\tbulk-out pipe clear stall: %d", rval);
8287c478bd9Sstevel@tonic-gate 
8297c478bd9Sstevel@tonic-gate exc_exit:
8307c478bd9Sstevel@tonic-gate 	/* clear the reset condition */
8317c478bd9Sstevel@tonic-gate 	scsa2usbp->scsa2usb_pipe_state &= ~SCSA2USB_PIPE_DEV_RESET;
8327c478bd9Sstevel@tonic-gate }
8337c478bd9Sstevel@tonic-gate 
8347c478bd9Sstevel@tonic-gate 
8357c478bd9Sstevel@tonic-gate /*
8367c478bd9Sstevel@tonic-gate  * scsa2usb_bulk_only_get_max_lun:
8377c478bd9Sstevel@tonic-gate  *	this function returns the number of LUNs supported by the device
8387c478bd9Sstevel@tonic-gate  */
8397c478bd9Sstevel@tonic-gate int
8407c478bd9Sstevel@tonic-gate scsa2usb_bulk_only_get_max_lun(scsa2usb_state_t *scsa2usbp)
8417c478bd9Sstevel@tonic-gate {
8427c478bd9Sstevel@tonic-gate 	int		luns = 1, rval;
8437c478bd9Sstevel@tonic-gate 	mblk_t		*data = NULL;
8447c478bd9Sstevel@tonic-gate 	usb_cr_t	completion_reason;
8457c478bd9Sstevel@tonic-gate 	usb_cb_flags_t	cb_flags;
8467c478bd9Sstevel@tonic-gate 
8477c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
8487c478bd9Sstevel@tonic-gate 	    "scsa2usb_bulk_only_get_max_lun:");
8497c478bd9Sstevel@tonic-gate 
8507c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
8517c478bd9Sstevel@tonic-gate 
8527c478bd9Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
8537c478bd9Sstevel@tonic-gate 	rval = usb_pipe_sync_ctrl_xfer(scsa2usbp->scsa2usb_dip,
8547c478bd9Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_default_pipe,
8557c478bd9Sstevel@tonic-gate 	    BULK_ONLY_GET_MAXLUN_BMREQ,		/* bmRequestType */
8567c478bd9Sstevel@tonic-gate 	    BULK_ONLY_GET_MAXLUN_REQ,		/* bRequest */
8577c478bd9Sstevel@tonic-gate 	    0,					/* wValue */
8587c478bd9Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_intfc_num,	/* wIndex */
8597c478bd9Sstevel@tonic-gate 	    1,					/* wLength */
8607c478bd9Sstevel@tonic-gate 	    &data, 0,
8617c478bd9Sstevel@tonic-gate 	    &completion_reason, &cb_flags, 0);
8627c478bd9Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
8637c478bd9Sstevel@tonic-gate 
8647c478bd9Sstevel@tonic-gate 	if (rval != USB_SUCCESS) {
8657c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
8667c478bd9Sstevel@tonic-gate 		    "get max lun failed, rval=%d cr=%d cb=0x%x data=0x%p",
867112116d8Sfb 		    rval, completion_reason, cb_flags, (void *)data);
8687c478bd9Sstevel@tonic-gate 	} else {
8697c478bd9Sstevel@tonic-gate 		/*
8707c478bd9Sstevel@tonic-gate 		 * This check ensures that we have valid data returned back.
8717c478bd9Sstevel@tonic-gate 		 * Otherwise we assume that device supports only one LUN.
8727c478bd9Sstevel@tonic-gate 		 */
873*d29f5a71Szhigang lu - Sun Microsystems - Beijing China 		if (MBLKL(data) != 1) {
874d291d9f2Sfrits 			USB_DPRINTF_L2(DPRINT_MASK_SCSA,
8757c478bd9Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
8767c478bd9Sstevel@tonic-gate 			    "device reported incorrect luns (adjusting to 1)");
8777c478bd9Sstevel@tonic-gate 		} else {
8787c478bd9Sstevel@tonic-gate 			/*
8797c478bd9Sstevel@tonic-gate 			 * Set scsa2usb_n_luns to value returned by the device
8807c478bd9Sstevel@tonic-gate 			 * plus 1. (See Section 3.2)
8817c478bd9Sstevel@tonic-gate 			 */
8827c478bd9Sstevel@tonic-gate 			luns = *data->b_rptr + 1;
8837c478bd9Sstevel@tonic-gate 
8847c478bd9Sstevel@tonic-gate 			/*
8857c478bd9Sstevel@tonic-gate 			 * In case a device returns incorrect LUNs
8867c478bd9Sstevel@tonic-gate 			 * which are more than 15 or negative or 0;
8877c478bd9Sstevel@tonic-gate 			 * we assume 1.
8887c478bd9Sstevel@tonic-gate 			 */
8897c478bd9Sstevel@tonic-gate 			if ((luns >= SCSA2USB_MAX_LUNS) || (luns <= 0)) {
890d291d9f2Sfrits 				USB_DPRINTF_L2(DPRINT_MASK_SCSA,
8917c478bd9Sstevel@tonic-gate 				    scsa2usbp->scsa2usb_log_handle,
8927c478bd9Sstevel@tonic-gate 				    "device reported %d luns "
8937c478bd9Sstevel@tonic-gate 				    "(adjusting to 1)", luns);
8947c478bd9Sstevel@tonic-gate 				luns = 1;
8957c478bd9Sstevel@tonic-gate 			}
8967c478bd9Sstevel@tonic-gate 		}
8977c478bd9Sstevel@tonic-gate 	}
8987c478bd9Sstevel@tonic-gate 
8997c478bd9Sstevel@tonic-gate 	SCSA2USB_FREE_MSG(data);	/* Free data */
9007c478bd9Sstevel@tonic-gate 
9017c478bd9Sstevel@tonic-gate 	return (luns);
9027c478bd9Sstevel@tonic-gate }
903