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  *
21*b5a2ac7bSfb  * Copyright 2009 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>
37d29f5a71Szhigang 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
scsa2usb_bulk_only_transport(scsa2usb_state_t * scsa2usbp,scsa2usb_cmd_t * cmd)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 	 */
2896d9a41ffSqz 	for (nretry = 0; nretry < SCSA2USB_STATUS_RETRIES; nretry++) {
2906d9a41ffSqz 		rval = scsa2usb_handle_status_start(scsa2usbp, req);
2917c478bd9Sstevel@tonic-gate 
2926d9a41ffSqz 		if ((rval != USB_SUCCESS) &&
2936d9a41ffSqz 		    (req->bulk_completion_reason == USB_CR_STALL)) {
2946d9a41ffSqz 			/*
2956d9a41ffSqz 			 * We ran into STALL condition here.
2966d9a41ffSqz 			 * If the condition cannot be cleared
2976d9a41ffSqz 			 * successfully, retry for limited times.
2986d9a41ffSqz 			 */
2996d9a41ffSqz 			scsa2usbp->scsa2usb_pkt_state =
30063602c90Sfb 			    SCSA2USB_PKT_PROCESS_CSW;
3017c478bd9Sstevel@tonic-gate 		} else {
3027c478bd9Sstevel@tonic-gate 
3036d9a41ffSqz 			break;
3047c478bd9Sstevel@tonic-gate 		}
3057c478bd9Sstevel@tonic-gate 	}
3067c478bd9Sstevel@tonic-gate 
3076d9a41ffSqz 	if (rval == USB_SUCCESS) {
3086d9a41ffSqz 		/* process CSW */
3096d9a41ffSqz 		rval = scsa2usb_handle_csw_result(scsa2usbp, req->bulk_data);
3106d9a41ffSqz 	} else {
3116d9a41ffSqz 		scsa2usb_bulk_only_handle_error(scsa2usbp, req);
3126d9a41ffSqz 
3136d9a41ffSqz 		return (TRAN_FATAL_ERROR);
3146d9a41ffSqz 	}
3156d9a41ffSqz 
3167c478bd9Sstevel@tonic-gate 	SCSA2USB_FREE_BULK_REQ(req);	/* free request */
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate 	if ((rval == USB_SUCCESS) &&		/* CSW was ok */
3197c478bd9Sstevel@tonic-gate 	    (scsa2usbp->scsa2usb_cur_pkt->pkt_reason == CMD_CMPLT) &&
3207c478bd9Sstevel@tonic-gate 	    (cmd->cmd_xfercount != 0) &&	/* more data to xfer */
3217c478bd9Sstevel@tonic-gate 	    !cmd->cmd_done) {			/* we aren't done yet */
3227c478bd9Sstevel@tonic-gate 		scsa2usb_setup_next_xfer(scsa2usbp, cmd);
3237c478bd9Sstevel@tonic-gate 		goto Cmd_Phase;
3247c478bd9Sstevel@tonic-gate 	}
3257c478bd9Sstevel@tonic-gate 
3267c478bd9Sstevel@tonic-gate 	return (rval == USB_SUCCESS ? TRAN_ACCEPT : TRAN_FATAL_ERROR);
3277c478bd9Sstevel@tonic-gate }
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate /*
3317c478bd9Sstevel@tonic-gate  * scsa2usb_fill_in_cbw:
3327c478bd9Sstevel@tonic-gate  *	Fill in a CBW request packet. This
3337c478bd9Sstevel@tonic-gate  *	packet is transported to the device
3347c478bd9Sstevel@tonic-gate  */
3357c478bd9Sstevel@tonic-gate static void
scsa2usb_fill_in_cbw(scsa2usb_state_t * scsa2usbp,scsa2usb_cmd_t * cmd,mblk_t * mp)3367c478bd9Sstevel@tonic-gate scsa2usb_fill_in_cbw(scsa2usb_state_t *scsa2usbp,
3377c478bd9Sstevel@tonic-gate     scsa2usb_cmd_t *cmd, mblk_t *mp)
3387c478bd9Sstevel@tonic-gate {
3397c478bd9Sstevel@tonic-gate 	int	i;
3407c478bd9Sstevel@tonic-gate 	int	len;
3417c478bd9Sstevel@tonic-gate 	uchar_t dir, *cdb = (uchar_t *)(&cmd->cmd_cdb);
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate 	*mp->b_wptr++ = CBW_MSB(CBW_SIGNATURE);	/* CBW Signature */;
3467c478bd9Sstevel@tonic-gate 	*mp->b_wptr++ = CBW_MID1(CBW_SIGNATURE);
3477c478bd9Sstevel@tonic-gate 	*mp->b_wptr++ = CBW_MID2(CBW_SIGNATURE);
3487c478bd9Sstevel@tonic-gate 	*mp->b_wptr++ = CBW_LSB(CBW_SIGNATURE);
3497c478bd9Sstevel@tonic-gate 	*mp->b_wptr++ = CBW_LSB(cmd->cmd_tag);	/* CBW Tag */
3507c478bd9Sstevel@tonic-gate 	*mp->b_wptr++ = CBW_MID2(cmd->cmd_tag);
3517c478bd9Sstevel@tonic-gate 	*mp->b_wptr++ = CBW_MID1(cmd->cmd_tag);
3527c478bd9Sstevel@tonic-gate 	*mp->b_wptr++ = CBW_MSB(cmd->cmd_tag);
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate 	dir = cmd->cmd_dir;
3557c478bd9Sstevel@tonic-gate 	len = cmd->cmd_xfercount;
3567c478bd9Sstevel@tonic-gate #ifdef	SCSA2USB_BULK_ONLY_TEST
3577c478bd9Sstevel@tonic-gate 	if (scsa2usb_test_case_2 && (cdb[0] == SCMD_READ_CAPACITY)) {
3587c478bd9Sstevel@tonic-gate 		/* Host expects no data. The device wants data. Hn < Di */
3597c478bd9Sstevel@tonic-gate 		scsa2usb_test_case_2 = len = 0;
3607c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L1(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
3617c478bd9Sstevel@tonic-gate 		    "TEST 2: Hn < Di cdb: 0x%x len: 0x%x", cdb[0], len);
3627c478bd9Sstevel@tonic-gate 	}
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate 	if (scsa2usb_test_case_3 && (cmd->cmd_dir == CBW_DIR_OUT)) {
3657c478bd9Sstevel@tonic-gate 		/* Host expects no data. The device wants data. Hn < Do */
3667c478bd9Sstevel@tonic-gate 		if (cdb[0] == SCMD_WRITE_G1) {
3677c478bd9Sstevel@tonic-gate 			scsa2usb_test_case_3 = len = 0;
3687c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_SCSA,
3697c478bd9Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
3707c478bd9Sstevel@tonic-gate 			    "TEST 3: Hn < Do cdb: 0x%x len:%x", cdb[0], len);
3717c478bd9Sstevel@tonic-gate 		}
3727c478bd9Sstevel@tonic-gate 	}
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate 	if (scsa2usb_test_case_4 && (cdb[0] == SCMD_READ_G1)) {
3757c478bd9Sstevel@tonic-gate 		cdb[0] = 0x5e;
3767c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L1(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
3777c478bd9Sstevel@tonic-gate 		    "TEST 4: Hi > Dn: changed cdb to 0x%x", cdb[0]);
3787c478bd9Sstevel@tonic-gate 		scsa2usb_test_case_4 = 0;
3797c478bd9Sstevel@tonic-gate 	}
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate 	if (scsa2usb_test_case_7 && (cmd->cmd_cdb[0] == SCMD_READ_G1)) {
3827c478bd9Sstevel@tonic-gate 		len -= 0x10;
3837c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L1(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
3847c478bd9Sstevel@tonic-gate 		    "TEST 7: Hi < Di cdb: 0x%x len: 0x%x", cdb[0], len);
3857c478bd9Sstevel@tonic-gate 		scsa2usb_test_case_7 = 0;
3867c478bd9Sstevel@tonic-gate 	}
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate 	if (scsa2usb_test_case_8 && (cdb[0] == SCMD_READ_G1)) {
3897c478bd9Sstevel@tonic-gate 		dir = (dir == CBW_DIR_IN) ? CBW_DIR_OUT : dir;
3907c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L1(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
3917c478bd9Sstevel@tonic-gate 		    "TEST 8: Hi <> Do cdb: 0x%x dir: 0x%x", cdb[0], dir);
3927c478bd9Sstevel@tonic-gate 	}
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 	if (scsa2usb_test_case_9 && (cdb[0] == SCMD_WRITE_G1)) {
3957c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L1(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
3967c478bd9Sstevel@tonic-gate 		    "TEST 9: Ho <> Di (%x)", cdb[0]);
3977c478bd9Sstevel@tonic-gate 		cdb[SCSA2USB_LEN_0] = cdb[SCSA2USB_LEN_1] = 0;
3987c478bd9Sstevel@tonic-gate 		scsa2usb_test_case_9 = 0;
3997c478bd9Sstevel@tonic-gate 	}
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate 	if (scsa2usb_test_case_10 && (cdb[0] == SCMD_WRITE_G1)) {
4027c478bd9Sstevel@tonic-gate 		dir = (dir == CBW_DIR_OUT) ? CBW_DIR_IN : dir;
4037c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L1(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
4047c478bd9Sstevel@tonic-gate 		    "TEST 10: Ho <> Di cdb: 0x%x dir: 0x%x", cdb[0], dir);
4057c478bd9Sstevel@tonic-gate 	}
4067c478bd9Sstevel@tonic-gate 
4077c478bd9Sstevel@tonic-gate 	/*
4087c478bd9Sstevel@tonic-gate 	 * This case occurs when the device intends to receive
4097c478bd9Sstevel@tonic-gate 	 * more data from the host than the host sends.
4107c478bd9Sstevel@tonic-gate 	 */
4117c478bd9Sstevel@tonic-gate 	if (scsa2usb_test_case_13) {
4127c478bd9Sstevel@tonic-gate 		if ((cdb[0] == SCMD_WRITE_G1) || (cdb[0] == SCMD_READ_G1)) {
4137c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_SCSA,
4147c478bd9Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle, "TEST 13: Ho < Do");
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate 			len -= 30;
4177c478bd9Sstevel@tonic-gate 			scsa2usb_test_case_13 = 0;
4187c478bd9Sstevel@tonic-gate 		}
4197c478bd9Sstevel@tonic-gate 	}
4207c478bd9Sstevel@tonic-gate #endif	/* SCSA2USB_BULK_ONLY_TEST */
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate 	*mp->b_wptr++ = CBW_MSB(len);		/* Transfer Length */
4237c478bd9Sstevel@tonic-gate 	*mp->b_wptr++ = CBW_MID1(len);
4247c478bd9Sstevel@tonic-gate 	*mp->b_wptr++ = CBW_MID2(len);
4257c478bd9Sstevel@tonic-gate 	*mp->b_wptr++ = CBW_LSB(len);
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate 	*mp->b_wptr++ = dir;			/* Transfer Direction */
4287c478bd9Sstevel@tonic-gate 	*mp->b_wptr++ = cmd->cmd_pkt->pkt_address.a_lun;	/* Lun # */
4297c478bd9Sstevel@tonic-gate 	*mp->b_wptr++ = cmd->cmd_actual_len;			/* CDB Len */
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate 	/* Copy the CDB out */
4327c478bd9Sstevel@tonic-gate 	for (i = 0; i < CBW_CDB_LEN; i++) {
4337c478bd9Sstevel@tonic-gate 		*mp->b_wptr++ = *cdb++;
4347c478bd9Sstevel@tonic-gate 	}
4357c478bd9Sstevel@tonic-gate #ifdef DUMP_CWB
4367c478bd9Sstevel@tonic-gate {
4377c478bd9Sstevel@tonic-gate 	int len = mp->b_wptr - mp->b_rptr;
4387c478bd9Sstevel@tonic-gate 	char *buf;
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate 	int i;
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "CWB: len=%d\n", len);
4437c478bd9Sstevel@tonic-gate 	buf = kmem_zalloc(512, KM_SLEEP);
4447c478bd9Sstevel@tonic-gate 	for (i = 0; i < len; i++) {
4457c478bd9Sstevel@tonic-gate 		sprintf(&buf[strlen(buf)], "%02x ", mp->b_rptr[i]);
4467c478bd9Sstevel@tonic-gate 	}
4477c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "%s\n", buf);
4487c478bd9Sstevel@tonic-gate 	kmem_free(buf, 512);
4497c478bd9Sstevel@tonic-gate }
4507c478bd9Sstevel@tonic-gate #endif
4517c478bd9Sstevel@tonic-gate 
4527c478bd9Sstevel@tonic-gate }
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate 
4557c478bd9Sstevel@tonic-gate /*
4567c478bd9Sstevel@tonic-gate  * scsa2usb_bulk_only_handle_error:
4577c478bd9Sstevel@tonic-gate  *	handle transport errors and start recovery
4587c478bd9Sstevel@tonic-gate  */
4597c478bd9Sstevel@tonic-gate static void
scsa2usb_bulk_only_handle_error(scsa2usb_state_t * scsa2usbp,usb_bulk_req_t * req)4607c478bd9Sstevel@tonic-gate scsa2usb_bulk_only_handle_error(scsa2usb_state_t *scsa2usbp,
4617c478bd9Sstevel@tonic-gate     usb_bulk_req_t *req)
4627c478bd9Sstevel@tonic-gate {
4637c478bd9Sstevel@tonic-gate 	struct scsi_pkt *pkt = scsa2usbp->scsa2usb_cur_pkt;
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
4667c478bd9Sstevel@tonic-gate 	    "scsa2usb_bulk_only_handle_error: req = 0x%p, cr = 0x%x",
467112116d8Sfb 	    (void *)req, (req ? req->bulk_completion_reason : 0));
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate 	if (req) {
4707c478bd9Sstevel@tonic-gate 		SCSA2USB_SET_PKT_DO_COMP_STATE(scsa2usbp);
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate 		/* invoke reset recovery */
4737c478bd9Sstevel@tonic-gate 		switch (req->bulk_completion_reason) {
4747c478bd9Sstevel@tonic-gate 		case USB_CR_STALL:
4757c478bd9Sstevel@tonic-gate 			if (pkt) {
4767c478bd9Sstevel@tonic-gate 				pkt->pkt_reason = CMD_TRAN_ERR;
4777c478bd9Sstevel@tonic-gate 			}
4787c478bd9Sstevel@tonic-gate 			break;
4797c478bd9Sstevel@tonic-gate 		case USB_CR_TIMEOUT:
4807c478bd9Sstevel@tonic-gate 			if (pkt) {
4817c478bd9Sstevel@tonic-gate 				pkt->pkt_reason = CMD_TIMEOUT;
4827c478bd9Sstevel@tonic-gate 				pkt->pkt_statistics |= STAT_TIMEOUT;
4837c478bd9Sstevel@tonic-gate 			}
4847c478bd9Sstevel@tonic-gate 			break;
4857c478bd9Sstevel@tonic-gate 		case USB_CR_DEV_NOT_RESP:
4867c478bd9Sstevel@tonic-gate 			if (pkt) {
4877c478bd9Sstevel@tonic-gate 				pkt->pkt_reason = CMD_DEV_GONE;
4887c478bd9Sstevel@tonic-gate 				/* scsi_poll relies on this */
4897c478bd9Sstevel@tonic-gate 				pkt->pkt_state = STATE_GOT_BUS;
4907c478bd9Sstevel@tonic-gate 			}
4917c478bd9Sstevel@tonic-gate 			break;
4927c478bd9Sstevel@tonic-gate 		default:
4937c478bd9Sstevel@tonic-gate 			if (pkt) {
4947c478bd9Sstevel@tonic-gate 				pkt->pkt_reason = CMD_TRAN_ERR;
4957c478bd9Sstevel@tonic-gate 			}
4967c478bd9Sstevel@tonic-gate 		}
4977c478bd9Sstevel@tonic-gate 		scsa2usb_bulk_only_reset_recovery(scsa2usbp);
4987c478bd9Sstevel@tonic-gate 	}
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate 	SCSA2USB_FREE_BULK_REQ(req);
5017c478bd9Sstevel@tonic-gate }
5027c478bd9Sstevel@tonic-gate 
5037c478bd9Sstevel@tonic-gate 
5047c478bd9Sstevel@tonic-gate /*
5057c478bd9Sstevel@tonic-gate  * scsa2usb_handle_status_start:
5067c478bd9Sstevel@tonic-gate  *	Receive status data
5077c478bd9Sstevel@tonic-gate  */
5087c478bd9Sstevel@tonic-gate static int
scsa2usb_handle_status_start(scsa2usb_state_t * scsa2usbp,usb_bulk_req_t * req)5097c478bd9Sstevel@tonic-gate scsa2usb_handle_status_start(scsa2usb_state_t *scsa2usbp,
5107c478bd9Sstevel@tonic-gate     usb_bulk_req_t *req)
5117c478bd9Sstevel@tonic-gate {
5127c478bd9Sstevel@tonic-gate 	int rval;
5137c478bd9Sstevel@tonic-gate 
5147c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
515112116d8Sfb 	    "scsa2usb_handle_status_start: req = 0x%p", (void *)req);
5167c478bd9Sstevel@tonic-gate 
5177c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
5187c478bd9Sstevel@tonic-gate 
5197c478bd9Sstevel@tonic-gate 	/* setup up for receiving CSW */
5207c478bd9Sstevel@tonic-gate #ifdef	SCSA2USB_BULK_ONLY_TEST
5217c478bd9Sstevel@tonic-gate 	req->bulk_attributes = 0;
5227c478bd9Sstevel@tonic-gate #else
5237c478bd9Sstevel@tonic-gate 	req->bulk_attributes = USB_ATTRS_SHORT_XFER_OK;
5247c478bd9Sstevel@tonic-gate #endif	/* SCSA2USB_BULK_ONLY_TEST */
5257c478bd9Sstevel@tonic-gate 	req->bulk_len = CSW_LEN;
5267c478bd9Sstevel@tonic-gate 
5277c478bd9Sstevel@tonic-gate 	SCSA2USB_FREE_MSG(req->bulk_data);
5287c478bd9Sstevel@tonic-gate 	req->bulk_data = allocb_wait(req->bulk_len,
5297c478bd9Sstevel@tonic-gate 	    BPRI_LO, STR_NOSIG, NULL);
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate 	/* Issue the request */
5327c478bd9Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate 	ASSERT(req->bulk_timeout);
5357c478bd9Sstevel@tonic-gate 	rval = usb_pipe_bulk_xfer(scsa2usbp->scsa2usb_bulkin_pipe, req,
5367c478bd9Sstevel@tonic-gate 	    USB_FLAGS_SLEEP);
5377c478bd9Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
5387c478bd9Sstevel@tonic-gate 
5397c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
5407c478bd9Sstevel@tonic-gate 	    "scsa2usb_handle_status_start: END rval = 0x%x", rval);
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate 	if (rval != USB_SUCCESS) {
5437c478bd9Sstevel@tonic-gate 		if (scsa2usbp->scsa2usb_pkt_state == SCSA2USB_PKT_PROCESS_CSW) {
5447c478bd9Sstevel@tonic-gate 			scsa2usb_bulk_only_reset_recovery(scsa2usbp);
5457c478bd9Sstevel@tonic-gate 
5467c478bd9Sstevel@tonic-gate 			return (rval);
5477c478bd9Sstevel@tonic-gate 		}
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate 		if (req->bulk_completion_reason == USB_CR_STALL) {
5507c478bd9Sstevel@tonic-gate 			(void) scsa2usb_clear_ept_stall(scsa2usbp,
5517c478bd9Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_bulkin_ept.bEndpointAddress,
5527c478bd9Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_bulkin_pipe, "bulk-in");
5537c478bd9Sstevel@tonic-gate 		}
5547c478bd9Sstevel@tonic-gate 	}
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate 	return (rval);
5577c478bd9Sstevel@tonic-gate }
5587c478bd9Sstevel@tonic-gate 
5597c478bd9Sstevel@tonic-gate 
5607c478bd9Sstevel@tonic-gate /*
5617c478bd9Sstevel@tonic-gate  * scsa2usb_handle_csw_result:
5627c478bd9Sstevel@tonic-gate  *	Handle status results
5637c478bd9Sstevel@tonic-gate  */
5647c478bd9Sstevel@tonic-gate static int
scsa2usb_handle_csw_result(scsa2usb_state_t * scsa2usbp,mblk_t * data)5657c478bd9Sstevel@tonic-gate scsa2usb_handle_csw_result(scsa2usb_state_t *scsa2usbp, mblk_t *data)
5667c478bd9Sstevel@tonic-gate {
5677c478bd9Sstevel@tonic-gate 	int		rval = USB_SUCCESS;
5687c478bd9Sstevel@tonic-gate 	int		residue;
5697c478bd9Sstevel@tonic-gate 	char		*msg = "CSW FAILED";
5707c478bd9Sstevel@tonic-gate 	uint_t		signature, tag, status;
5717c478bd9Sstevel@tonic-gate 	usb_bulk_csw_t	csw;
5727c478bd9Sstevel@tonic-gate 	struct scsi_pkt *pkt = scsa2usbp->scsa2usb_cur_pkt;
5737c478bd9Sstevel@tonic-gate 	scsa2usb_cmd_t	*cmd = PKT2CMD(pkt);
5747c478bd9Sstevel@tonic-gate 
5757c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
5767c478bd9Sstevel@tonic-gate 
5777c478bd9Sstevel@tonic-gate 	/*
5787c478bd9Sstevel@tonic-gate 	 * This shouldn't happen. It implies the device's
5797c478bd9Sstevel@tonic-gate 	 * firmware is bad and has returned NULL CSW.
5807c478bd9Sstevel@tonic-gate 	 * return failure back.
5817c478bd9Sstevel@tonic-gate 	 */
5827c478bd9Sstevel@tonic-gate 	if (data == NULL) {
5837c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
5847c478bd9Sstevel@tonic-gate 		    "scsa2usb_handle_csw_result: data == NULL");
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
5877c478bd9Sstevel@tonic-gate 	}
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate 	/* check if we got back CSW_LEN or not */
590d29f5a71Szhigang lu - Sun Microsystems - Beijing China 	if (MBLKL(data) != CSW_LEN) {
5917c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
592112116d8Sfb 		    "scsa2usb_handle_csw_result: no enough data (%ld)",
593d29f5a71Szhigang lu - Sun Microsystems - Beijing China 		    (long)(MBLKL(data)));
5947c478bd9Sstevel@tonic-gate 
5957c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
5967c478bd9Sstevel@tonic-gate 	}
5977c478bd9Sstevel@tonic-gate 
5987c478bd9Sstevel@tonic-gate 	/* Read into csw */
5997c478bd9Sstevel@tonic-gate 	bcopy(data->b_rptr, &csw, CSW_LEN);
6007c478bd9Sstevel@tonic-gate 
6017c478bd9Sstevel@tonic-gate 	status = csw.csw_bCSWStatus;
6027c478bd9Sstevel@tonic-gate 	signature = SCSA2USB_MK_32BIT(csw.csw_dCSWSignature3,
6037c478bd9Sstevel@tonic-gate 	    csw.csw_dCSWSignature2, csw.csw_dCSWSignature1,
6047c478bd9Sstevel@tonic-gate 	    csw.csw_dCSWSignature0);
6057c478bd9Sstevel@tonic-gate 	residue = SCSA2USB_MK_32BIT(csw.csw_dCSWDataResidue3,
6067c478bd9Sstevel@tonic-gate 	    csw.csw_dCSWDataResidue2, csw.csw_dCSWDataResidue1,
6077c478bd9Sstevel@tonic-gate 	    csw.csw_dCSWDataResidue0);
6087c478bd9Sstevel@tonic-gate 	tag = SCSA2USB_MK_32BIT(csw.csw_dCSWTag3, csw.csw_dCSWTag2,
6097c478bd9Sstevel@tonic-gate 	    csw.csw_dCSWTag1, csw.csw_dCSWTag0);
6107c478bd9Sstevel@tonic-gate 
6117c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
6127c478bd9Sstevel@tonic-gate 	    "CSW: Signature = 0x%x Status = 0%x Tag = 0x%x Residue = 0x%x",
6137c478bd9Sstevel@tonic-gate 	    signature, status, tag,  residue);
6147c478bd9Sstevel@tonic-gate 
6157c478bd9Sstevel@tonic-gate 	/* Check for abnormal errors */
6167c478bd9Sstevel@tonic-gate 	if ((signature != CSW_SIGNATURE) || (tag != cmd->cmd_tag) ||
617d29f5a71Szhigang lu - Sun Microsystems - Beijing China 	    (status > CSW_STATUS_PHASE_ERROR)) {
6187c478bd9Sstevel@tonic-gate 
6197c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
6207c478bd9Sstevel@tonic-gate 		    "CSW_ERR: Status = 0x%x, Tag = 0x%x xfercount = 0x%lx",
6217c478bd9Sstevel@tonic-gate 		    status, cmd->cmd_tag, cmd->cmd_total_xfercount);
6227c478bd9Sstevel@tonic-gate 
6237c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
6247c478bd9Sstevel@tonic-gate 	}
6257c478bd9Sstevel@tonic-gate 
6267c478bd9Sstevel@tonic-gate 	switch (status) {
6277c478bd9Sstevel@tonic-gate 	case CSW_STATUS_GOOD:
6287c478bd9Sstevel@tonic-gate 		/*
6297c478bd9Sstevel@tonic-gate 		 * Fail the command if the device misbehaves and
6307c478bd9Sstevel@tonic-gate 		 * gives a good status but doesn't transfer any data.
6317c478bd9Sstevel@tonic-gate 		 * Otherwise we'll get into an infinite retry loop.
6327c478bd9Sstevel@tonic-gate 		 *
6337c478bd9Sstevel@tonic-gate 		 * We test only against cmd_total_xfercount here and
6347c478bd9Sstevel@tonic-gate 		 * assume that this will not happen on a command that
6357c478bd9Sstevel@tonic-gate 		 * transfers a large amount of data and therefore may
6367c478bd9Sstevel@tonic-gate 		 * be split into separate transfers. For a large data
6377c478bd9Sstevel@tonic-gate 		 * transfer it is assumed that the device will return
6387c478bd9Sstevel@tonic-gate 		 * an error status if the transfer does not occur.
6397c478bd9Sstevel@tonic-gate 		 * this isn't quite correct because a subsequent request
6407c478bd9Sstevel@tonic-gate 		 * sense may not give a valid sense key.
6417c478bd9Sstevel@tonic-gate 		 */
6427c478bd9Sstevel@tonic-gate 		if (!cmd->cmd_done && residue &&
6437c478bd9Sstevel@tonic-gate 		    (residue == cmd->cmd_total_xfercount)) {
6447c478bd9Sstevel@tonic-gate 			*(pkt->pkt_scbp) = STATUS_CHECK;
6457c478bd9Sstevel@tonic-gate 			cmd->cmd_xfercount = 0;
6467c478bd9Sstevel@tonic-gate 			cmd->cmd_done = 1;
6477c478bd9Sstevel@tonic-gate 		} else {
6487c478bd9Sstevel@tonic-gate 			msg = "CSW GOOD";
6497c478bd9Sstevel@tonic-gate 		}
6507c478bd9Sstevel@tonic-gate 		break;
6517c478bd9Sstevel@tonic-gate 	case CSW_STATUS_FAILED:
6527c478bd9Sstevel@tonic-gate 		*(pkt->pkt_scbp) = STATUS_CHECK; /* Set check condition */
6537c478bd9Sstevel@tonic-gate 		cmd->cmd_done = 1;
6547c478bd9Sstevel@tonic-gate 		break;
6557c478bd9Sstevel@tonic-gate 	case CSW_STATUS_PHASE_ERROR:
6567c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
6577c478bd9Sstevel@tonic-gate 		    "scsa2usb_handle_csw_result: Phase Error");
6587c478bd9Sstevel@tonic-gate 
6597c478bd9Sstevel@tonic-gate 		/* invoke reset recovery */
6607c478bd9Sstevel@tonic-gate 		scsa2usb_bulk_only_handle_error(scsa2usbp, NULL);
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
6637c478bd9Sstevel@tonic-gate 	default:	/* shouldn't happen anymore */
6647c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
6657c478bd9Sstevel@tonic-gate 		    "scsa2usb_handle_csw_result: Invalid CSW");
6667c478bd9Sstevel@tonic-gate 
6677c478bd9Sstevel@tonic-gate 		/* invoke reset recovery */
6687c478bd9Sstevel@tonic-gate 		scsa2usb_bulk_only_handle_error(scsa2usbp, NULL);
6697c478bd9Sstevel@tonic-gate 
6707c478bd9Sstevel@tonic-gate 		return (USB_SUCCESS);
6717c478bd9Sstevel@tonic-gate 	} /* end of switch */
6727c478bd9Sstevel@tonic-gate 
6737c478bd9Sstevel@tonic-gate 	/* Set resid */
6747c478bd9Sstevel@tonic-gate 	if (residue || cmd->cmd_resid_xfercount) {
6757c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA,
6767c478bd9Sstevel@tonic-gate 		    scsa2usbp->scsa2usb_log_handle,
6773fbbb872Ssl 		    "total=0x%lx cmd_xfercount=0x%lx residue=0x%x "
6783fbbb872Ssl 		    "cmd_offset=0x%lx",
6797c478bd9Sstevel@tonic-gate 		    cmd->cmd_total_xfercount, cmd->cmd_xfercount,
6803fbbb872Ssl 		    residue, cmd->cmd_offset);
6817c478bd9Sstevel@tonic-gate 
6827c478bd9Sstevel@tonic-gate 		/*
6837c478bd9Sstevel@tonic-gate 		 * we need to adjust using the residue and
6847c478bd9Sstevel@tonic-gate 		 * assume worst case. Some devices lie about
6857c478bd9Sstevel@tonic-gate 		 * residue. some report a residue greater than
6867c478bd9Sstevel@tonic-gate 		 * the residue we have calculated.
6877c478bd9Sstevel@tonic-gate 		 * first adjust back the total_xfercount
6887c478bd9Sstevel@tonic-gate 		 */
6897c478bd9Sstevel@tonic-gate 		cmd->cmd_total_xfercount += cmd->cmd_xfercount -
69063602c90Sfb 		    cmd->cmd_resid_xfercount;
6913fbbb872Ssl 		/*
6923fbbb872Ssl 		 * we need to adjust cmd_offset as well, or the data
6933fbbb872Ssl 		 * buffer for subsequent transfer may exceed the buffer
6943fbbb872Ssl 		 * boundary
6953fbbb872Ssl 		 */
6963fbbb872Ssl 		cmd->cmd_offset -= cmd->cmd_xfercount -
6973fbbb872Ssl 		    cmd->cmd_resid_xfercount;
6987c478bd9Sstevel@tonic-gate 
6997c478bd9Sstevel@tonic-gate 		/*
7007c478bd9Sstevel@tonic-gate 		 * now take the min of the reported residue by
7017c478bd9Sstevel@tonic-gate 		 * the device and the requested xfer count
7027c478bd9Sstevel@tonic-gate 		 * (just in case the device reported a residue greater
7037c478bd9Sstevel@tonic-gate 		 * than our request count).
7047c478bd9Sstevel@tonic-gate 		 * then take the max of this residue and the residue
7057c478bd9Sstevel@tonic-gate 		 * that the HCD reported and subtract this from
7067c478bd9Sstevel@tonic-gate 		 * the request count. This is the actual number
7077c478bd9Sstevel@tonic-gate 		 * of valid bytes transferred during the last transfer
7087c478bd9Sstevel@tonic-gate 		 * which we now subtract from the total_xfercount
7097c478bd9Sstevel@tonic-gate 		 */
7102115f0c6Ssl 		if ((!(scsa2usbp->scsa2usb_attrs &
7112115f0c6Ssl 		    SCSA2USB_ATTRS_USE_CSW_RESIDUE)) ||
7122115f0c6Ssl 		    (residue < 0) ||
7137c478bd9Sstevel@tonic-gate 		    (residue > cmd->cmd_total_xfercount)) {
7142115f0c6Ssl 			/* some devices lie about the resid, ignore */
7152115f0c6Ssl 			cmd->cmd_total_xfercount -=
7162115f0c6Ssl 			    cmd->cmd_xfercount - cmd->cmd_resid_xfercount;
7173fbbb872Ssl 			cmd->cmd_offset +=
7183fbbb872Ssl 			    cmd->cmd_xfercount - cmd->cmd_resid_xfercount;
7192115f0c6Ssl 		} else {
7202115f0c6Ssl 			cmd->cmd_total_xfercount -=
7212115f0c6Ssl 			    cmd->cmd_xfercount -
7222115f0c6Ssl 			    max(min(residue, cmd->cmd_xfercount),
7232115f0c6Ssl 			    cmd->cmd_resid_xfercount);
7243fbbb872Ssl 			cmd->cmd_offset +=
7253fbbb872Ssl 			    cmd->cmd_xfercount -
7263fbbb872Ssl 			    max(min(residue, cmd->cmd_xfercount),
7273fbbb872Ssl 			    cmd->cmd_resid_xfercount);
7283fbbb872Ssl 			/*
7293fbbb872Ssl 			 * if HCD does not report residue while the device
7303fbbb872Ssl 			 * reports a residue equivalent to the xfercount,
7313fbbb872Ssl 			 * it is very likely the device lies about the
7323fbbb872Ssl 			 * residue. we need to stop the command, or we'll
7333fbbb872Ssl 			 * get into an infinite retry loop.
7343fbbb872Ssl 			 */
7353fbbb872Ssl 			if ((cmd->cmd_resid_xfercount == 0) &&
7363fbbb872Ssl 			    (residue == cmd->cmd_xfercount)) {
7373fbbb872Ssl 				cmd->cmd_xfercount = 0;
7383fbbb872Ssl 				cmd->cmd_done = 1;
7393fbbb872Ssl 			}
7407c478bd9Sstevel@tonic-gate 		}
7417c478bd9Sstevel@tonic-gate 
7427c478bd9Sstevel@tonic-gate 		pkt->pkt_resid = cmd->cmd_total_xfercount;
7437c478bd9Sstevel@tonic-gate 	}
7447c478bd9Sstevel@tonic-gate 
7457c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
7467c478bd9Sstevel@tonic-gate 	    "scsa2usb_handle_csw_result: %s, resid: 0x%lx",
7477c478bd9Sstevel@tonic-gate 	    msg, pkt->pkt_resid);
7487c478bd9Sstevel@tonic-gate 
7497c478bd9Sstevel@tonic-gate 	/* we are done and ready to callback */
7507c478bd9Sstevel@tonic-gate 	SCSA2USB_SET_PKT_DO_COMP_STATE(scsa2usbp);
7517c478bd9Sstevel@tonic-gate 
7527c478bd9Sstevel@tonic-gate 	return (rval);
7537c478bd9Sstevel@tonic-gate }
7547c478bd9Sstevel@tonic-gate 
7557c478bd9Sstevel@tonic-gate 
7567c478bd9Sstevel@tonic-gate /*
7577c478bd9Sstevel@tonic-gate  * scsa2usb_bulk_only_reset_recovery:
7587c478bd9Sstevel@tonic-gate  *	Reset the USB device step-wise in case of errors.
7597c478bd9Sstevel@tonic-gate  *	NOTE that the order of reset is very important.
7607c478bd9Sstevel@tonic-gate  */
7617c478bd9Sstevel@tonic-gate static void
scsa2usb_bulk_only_reset_recovery(scsa2usb_state_t * scsa2usbp)7627c478bd9Sstevel@tonic-gate scsa2usb_bulk_only_reset_recovery(scsa2usb_state_t *scsa2usbp)
7637c478bd9Sstevel@tonic-gate {
7647c478bd9Sstevel@tonic-gate 	int		rval;
7657c478bd9Sstevel@tonic-gate 	usb_cr_t	completion_reason;
7667c478bd9Sstevel@tonic-gate 	usb_cb_flags_t	cb_flags;
7677c478bd9Sstevel@tonic-gate 
7687c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
769112116d8Sfb 	    "scsa2usb_bulk_only_reset_recovery: scsa2usbp = 0x%p",
770112116d8Sfb 	    (void *)scsa2usbp);
7717c478bd9Sstevel@tonic-gate 
7727c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
7737c478bd9Sstevel@tonic-gate 
7747c478bd9Sstevel@tonic-gate 	if (!(SCSA2USB_DEVICE_ACCESS_OK(scsa2usbp))) {
7757c478bd9Sstevel@tonic-gate 
7767c478bd9Sstevel@tonic-gate 		return;
7777c478bd9Sstevel@tonic-gate 	}
7787c478bd9Sstevel@tonic-gate 
7797c478bd9Sstevel@tonic-gate 	/*
7807c478bd9Sstevel@tonic-gate 	 * assume that the reset will be successful. if it isn't, retrying
7817c478bd9Sstevel@tonic-gate 	 * from target driver won't help much
7827c478bd9Sstevel@tonic-gate 	 */
7837c478bd9Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_cur_pkt) {
7847c478bd9Sstevel@tonic-gate 		scsa2usbp->scsa2usb_cur_pkt->pkt_statistics |= STAT_DEV_RESET;
7857c478bd9Sstevel@tonic-gate 	}
7867c478bd9Sstevel@tonic-gate 
7877c478bd9Sstevel@tonic-gate 	/* set the reset condition */
7887c478bd9Sstevel@tonic-gate 	scsa2usbp->scsa2usb_pipe_state = SCSA2USB_PIPE_DEV_RESET;
7897c478bd9Sstevel@tonic-gate 
7907c478bd9Sstevel@tonic-gate 	/* Send a sync DEVICE-RESET request to the device */
7917c478bd9Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
7927c478bd9Sstevel@tonic-gate 	rval = usb_pipe_sync_ctrl_xfer(scsa2usbp->scsa2usb_dip,
7937c478bd9Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_default_pipe,
7947c478bd9Sstevel@tonic-gate 	    USB_DEV_REQ_TYPE_CLASS | USB_DEV_REQ_RCPT_IF,
7957c478bd9Sstevel@tonic-gate 	    (uint8_t)BULK_ONLY_RESET,		/* bRequest */
7967c478bd9Sstevel@tonic-gate 	    0,					/* wValue */
7977c478bd9Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_intfc_num,	/* wIndex */
7987c478bd9Sstevel@tonic-gate 	    0,					/* wLength */
7997c478bd9Sstevel@tonic-gate 	    NULL, 0, &completion_reason, &cb_flags, 0);
8007c478bd9Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
8017c478bd9Sstevel@tonic-gate 
8027c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
8037c478bd9Sstevel@tonic-gate 	    "\tbulk-only device-reset rval: %d", rval);
8047c478bd9Sstevel@tonic-gate 	if (rval != USB_SUCCESS) {
8057c478bd9Sstevel@tonic-gate 		goto exc_exit;
8067c478bd9Sstevel@tonic-gate 	}
8077c478bd9Sstevel@tonic-gate 
8087c478bd9Sstevel@tonic-gate 	/* reset and clear STALL on bulk-in pipe */
8097c478bd9Sstevel@tonic-gate 	rval = scsa2usb_clear_ept_stall(scsa2usbp,
8107c478bd9Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_bulkin_ept.bEndpointAddress,
8117c478bd9Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_bulkin_pipe, "bulk-in");
8127c478bd9Sstevel@tonic-gate 
8137c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
8147c478bd9Sstevel@tonic-gate 	    "\tbulk-in pipe clear stall: %d", rval);
8157c478bd9Sstevel@tonic-gate 	if (rval != USB_SUCCESS) {
8167c478bd9Sstevel@tonic-gate 		goto exc_exit;
8177c478bd9Sstevel@tonic-gate 	}
8187c478bd9Sstevel@tonic-gate 
8197c478bd9Sstevel@tonic-gate 	/* reset and clear STALL on bulk-out pipe */
8207c478bd9Sstevel@tonic-gate 	rval = scsa2usb_clear_ept_stall(scsa2usbp,
8217c478bd9Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_bulkout_ept.bEndpointAddress,
8227c478bd9Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_bulkout_pipe, "bulk-out");
8237c478bd9Sstevel@tonic-gate 
8247c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
8257c478bd9Sstevel@tonic-gate 	    "\tbulk-out pipe clear stall: %d", rval);
8267c478bd9Sstevel@tonic-gate 
8277c478bd9Sstevel@tonic-gate exc_exit:
8287c478bd9Sstevel@tonic-gate 	/* clear the reset condition */
8297c478bd9Sstevel@tonic-gate 	scsa2usbp->scsa2usb_pipe_state &= ~SCSA2USB_PIPE_DEV_RESET;
8307c478bd9Sstevel@tonic-gate }
8317c478bd9Sstevel@tonic-gate 
8327c478bd9Sstevel@tonic-gate 
8337c478bd9Sstevel@tonic-gate /*
8347c478bd9Sstevel@tonic-gate  * scsa2usb_bulk_only_get_max_lun:
8357c478bd9Sstevel@tonic-gate  *	this function returns the number of LUNs supported by the device
8367c478bd9Sstevel@tonic-gate  */
8377c478bd9Sstevel@tonic-gate int
scsa2usb_bulk_only_get_max_lun(scsa2usb_state_t * scsa2usbp)8387c478bd9Sstevel@tonic-gate scsa2usb_bulk_only_get_max_lun(scsa2usb_state_t *scsa2usbp)
8397c478bd9Sstevel@tonic-gate {
8407c478bd9Sstevel@tonic-gate 	int		luns = 1, rval;
8417c478bd9Sstevel@tonic-gate 	mblk_t		*data = NULL;
8427c478bd9Sstevel@tonic-gate 	usb_cr_t	completion_reason;
8437c478bd9Sstevel@tonic-gate 	usb_cb_flags_t	cb_flags;
8447c478bd9Sstevel@tonic-gate 
8457c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
8467c478bd9Sstevel@tonic-gate 	    "scsa2usb_bulk_only_get_max_lun:");
8477c478bd9Sstevel@tonic-gate 
8487c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
8497c478bd9Sstevel@tonic-gate 
8507c478bd9Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
8517c478bd9Sstevel@tonic-gate 	rval = usb_pipe_sync_ctrl_xfer(scsa2usbp->scsa2usb_dip,
8527c478bd9Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_default_pipe,
8537c478bd9Sstevel@tonic-gate 	    BULK_ONLY_GET_MAXLUN_BMREQ,		/* bmRequestType */
8547c478bd9Sstevel@tonic-gate 	    BULK_ONLY_GET_MAXLUN_REQ,		/* bRequest */
8557c478bd9Sstevel@tonic-gate 	    0,					/* wValue */
8567c478bd9Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_intfc_num,	/* wIndex */
8577c478bd9Sstevel@tonic-gate 	    1,					/* wLength */
8587c478bd9Sstevel@tonic-gate 	    &data, 0,
8597c478bd9Sstevel@tonic-gate 	    &completion_reason, &cb_flags, 0);
8607c478bd9Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
8617c478bd9Sstevel@tonic-gate 
8627c478bd9Sstevel@tonic-gate 	if (rval != USB_SUCCESS) {
8637c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
8647c478bd9Sstevel@tonic-gate 		    "get max lun failed, rval=%d cr=%d cb=0x%x data=0x%p",
865112116d8Sfb 		    rval, completion_reason, cb_flags, (void *)data);
8667c478bd9Sstevel@tonic-gate 	} else {
8677c478bd9Sstevel@tonic-gate 		/*
8687c478bd9Sstevel@tonic-gate 		 * This check ensures that we have valid data returned back.
8697c478bd9Sstevel@tonic-gate 		 * Otherwise we assume that device supports only one LUN.
8707c478bd9Sstevel@tonic-gate 		 */
871d29f5a71Szhigang lu - Sun Microsystems - Beijing China 		if (MBLKL(data) != 1) {
872d291d9f2Sfrits 			USB_DPRINTF_L2(DPRINT_MASK_SCSA,
8737c478bd9Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
8747c478bd9Sstevel@tonic-gate 			    "device reported incorrect luns (adjusting to 1)");
8757c478bd9Sstevel@tonic-gate 		} else {
8767c478bd9Sstevel@tonic-gate 			/*
8777c478bd9Sstevel@tonic-gate 			 * Set scsa2usb_n_luns to value returned by the device
8787c478bd9Sstevel@tonic-gate 			 * plus 1. (See Section 3.2)
8797c478bd9Sstevel@tonic-gate 			 */
8807c478bd9Sstevel@tonic-gate 			luns = *data->b_rptr + 1;
8817c478bd9Sstevel@tonic-gate 
8827c478bd9Sstevel@tonic-gate 			/*
8837c478bd9Sstevel@tonic-gate 			 * In case a device returns incorrect LUNs
8847c478bd9Sstevel@tonic-gate 			 * which are more than 15 or negative or 0;
8857c478bd9Sstevel@tonic-gate 			 * we assume 1.
8867c478bd9Sstevel@tonic-gate 			 */
8877c478bd9Sstevel@tonic-gate 			if ((luns >= SCSA2USB_MAX_LUNS) || (luns <= 0)) {
888d291d9f2Sfrits 				USB_DPRINTF_L2(DPRINT_MASK_SCSA,
8897c478bd9Sstevel@tonic-gate 				    scsa2usbp->scsa2usb_log_handle,
8907c478bd9Sstevel@tonic-gate 				    "device reported %d luns "
8917c478bd9Sstevel@tonic-gate 				    "(adjusting to 1)", luns);
8927c478bd9Sstevel@tonic-gate 				luns = 1;
8937c478bd9Sstevel@tonic-gate 			}
8947c478bd9Sstevel@tonic-gate 		}
8957c478bd9Sstevel@tonic-gate 	}
8967c478bd9Sstevel@tonic-gate 
8977c478bd9Sstevel@tonic-gate 	SCSA2USB_FREE_MSG(data);	/* Free data */
8987c478bd9Sstevel@tonic-gate 
8997c478bd9Sstevel@tonic-gate 	return (luns);
9007c478bd9Sstevel@tonic-gate }
901