1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  *
22*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
23*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
24*7c478bd9Sstevel@tonic-gate  */
25*7c478bd9Sstevel@tonic-gate 
26*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*7c478bd9Sstevel@tonic-gate 
28*7c478bd9Sstevel@tonic-gate /*
29*7c478bd9Sstevel@tonic-gate  * scsa2usb_ms_bulkonly.c:
30*7c478bd9Sstevel@tonic-gate  *
31*7c478bd9Sstevel@tonic-gate  * This file implements USB Mass Storage Class
32*7c478bd9Sstevel@tonic-gate  * Bulk Only (BO) transport v1.0
33*7c478bd9Sstevel@tonic-gate  * http://www.usb.org/developers/data/devclass/usbmassbulk_10.pdf
34*7c478bd9Sstevel@tonic-gate  */
35*7c478bd9Sstevel@tonic-gate #include <sys/usb/usba/usbai_version.h>
36*7c478bd9Sstevel@tonic-gate #include <sys/scsi/scsi.h>
37*7c478bd9Sstevel@tonic-gate #include <sys/callb.h>		/* needed by scsa2usb.h */
38*7c478bd9Sstevel@tonic-gate #include <sys/strsubr.h>
39*7c478bd9Sstevel@tonic-gate 
40*7c478bd9Sstevel@tonic-gate #include <sys/usb/usba.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/usb/usba/usba_private.h>
42*7c478bd9Sstevel@tonic-gate #include <sys/usb/usba/usba_ugen.h>
43*7c478bd9Sstevel@tonic-gate 
44*7c478bd9Sstevel@tonic-gate #include <sys/usb/clients/mass_storage/usb_bulkonly.h>
45*7c478bd9Sstevel@tonic-gate #include <sys/usb/scsa2usb/scsa2usb.h>
46*7c478bd9Sstevel@tonic-gate 
47*7c478bd9Sstevel@tonic-gate /*
48*7c478bd9Sstevel@tonic-gate  * Function Prototypes
49*7c478bd9Sstevel@tonic-gate  */
50*7c478bd9Sstevel@tonic-gate int		scsa2usb_bulk_only_transport(scsa2usb_state_t *,
51*7c478bd9Sstevel@tonic-gate 		    scsa2usb_cmd_t *);
52*7c478bd9Sstevel@tonic-gate static void	scsa2usb_fill_in_cbw(scsa2usb_state_t *, scsa2usb_cmd_t *,
53*7c478bd9Sstevel@tonic-gate 		    mblk_t *);
54*7c478bd9Sstevel@tonic-gate static void	scsa2usb_bulk_only_reset_recovery(scsa2usb_state_t *);
55*7c478bd9Sstevel@tonic-gate static void	scsa2usb_bulk_only_handle_error(scsa2usb_state_t *,
56*7c478bd9Sstevel@tonic-gate 		    usb_bulk_req_t *);
57*7c478bd9Sstevel@tonic-gate int		scsa2usb_bulk_only_get_max_lun(scsa2usb_state_t *);
58*7c478bd9Sstevel@tonic-gate static int	scsa2usb_handle_status_start(scsa2usb_state_t *,
59*7c478bd9Sstevel@tonic-gate 		    usb_bulk_req_t *);
60*7c478bd9Sstevel@tonic-gate static int	scsa2usb_handle_csw_result(scsa2usb_state_t *, mblk_t *);
61*7c478bd9Sstevel@tonic-gate 
62*7c478bd9Sstevel@tonic-gate 
63*7c478bd9Sstevel@tonic-gate /* extern functions */
64*7c478bd9Sstevel@tonic-gate extern void	scsa2usb_setup_next_xfer(scsa2usb_state_t *, scsa2usb_cmd_t *);
65*7c478bd9Sstevel@tonic-gate extern int	scsa2usb_handle_data_start(scsa2usb_state_t *,
66*7c478bd9Sstevel@tonic-gate 		    scsa2usb_cmd_t *, usb_bulk_req_t *);
67*7c478bd9Sstevel@tonic-gate extern void	scsa2usb_handle_data_done(scsa2usb_state_t *, scsa2usb_cmd_t *,
68*7c478bd9Sstevel@tonic-gate 		    usb_bulk_req_t *);
69*7c478bd9Sstevel@tonic-gate extern usb_bulk_req_t *scsa2usb_init_bulk_req(scsa2usb_state_t *,
70*7c478bd9Sstevel@tonic-gate 			    size_t, uint_t, usb_req_attrs_t, usb_flags_t);
71*7c478bd9Sstevel@tonic-gate extern int	scsa2usb_bulk_timeout(int);
72*7c478bd9Sstevel@tonic-gate extern int 	scsa2usb_clear_ept_stall(scsa2usb_state_t *, uint_t,
73*7c478bd9Sstevel@tonic-gate 		    usb_pipe_handle_t, char *);
74*7c478bd9Sstevel@tonic-gate extern void	scsa2usb_close_usb_pipes(scsa2usb_state_t *);
75*7c478bd9Sstevel@tonic-gate 
76*7c478bd9Sstevel@tonic-gate #ifdef DEBUG	/* debugging information */
77*7c478bd9Sstevel@tonic-gate extern void	scsa2usb_print_cdb(scsa2usb_state_t *, scsa2usb_cmd_t *);
78*7c478bd9Sstevel@tonic-gate #endif	/* DEBUG */
79*7c478bd9Sstevel@tonic-gate 
80*7c478bd9Sstevel@tonic-gate 
81*7c478bd9Sstevel@tonic-gate #ifdef	SCSA2USB_BULK_ONLY_TEST
82*7c478bd9Sstevel@tonic-gate /*
83*7c478bd9Sstevel@tonic-gate  * Test 13 cases. (See USB Mass Storage Class - Bulk Only Transport).
84*7c478bd9Sstevel@tonic-gate  * We are not covering test cases 1, 6, and 12 as these are the "good"
85*7c478bd9Sstevel@tonic-gate  * test cases and are tested as part of the normal drive access operations.
86*7c478bd9Sstevel@tonic-gate  *
87*7c478bd9Sstevel@tonic-gate  * NOTE: This is for testing only. It will be replaced by a uscsi test.
88*7c478bd9Sstevel@tonic-gate  */
89*7c478bd9Sstevel@tonic-gate static int scsa2usb_test_case_2 = 0;
90*7c478bd9Sstevel@tonic-gate static int scsa2usb_test_case_3 = 0;
91*7c478bd9Sstevel@tonic-gate static int scsa2usb_test_case_4 = 0;
92*7c478bd9Sstevel@tonic-gate static int scsa2usb_test_case_7 = 0;
93*7c478bd9Sstevel@tonic-gate extern int scsa2usb_test_case_8;
94*7c478bd9Sstevel@tonic-gate static int scsa2usb_test_case_9 = 0;
95*7c478bd9Sstevel@tonic-gate extern int scsa2usb_test_case_10;
96*7c478bd9Sstevel@tonic-gate static int scsa2usb_test_case_13 = 0;
97*7c478bd9Sstevel@tonic-gate #endif	/* SCSA2USB_BULK_ONLY_TEST */
98*7c478bd9Sstevel@tonic-gate 
99*7c478bd9Sstevel@tonic-gate 
100*7c478bd9Sstevel@tonic-gate /*
101*7c478bd9Sstevel@tonic-gate  * scsa2usb_bulk_only_transport:
102*7c478bd9Sstevel@tonic-gate  *	Implements the BO state machine by these steps:
103*7c478bd9Sstevel@tonic-gate  *	a) Issues CBW to a Bulk Only device.
104*7c478bd9Sstevel@tonic-gate  *	b) Start Data Phase if applicable
105*7c478bd9Sstevel@tonic-gate  *	c) Start Status Phase
106*7c478bd9Sstevel@tonic-gate  *
107*7c478bd9Sstevel@tonic-gate  *	returns TRAN_* values
108*7c478bd9Sstevel@tonic-gate  *
109*7c478bd9Sstevel@tonic-gate  * scsa2usb_bulk_only_state_machine:
110*7c478bd9Sstevel@tonic-gate  *
111*7c478bd9Sstevel@tonic-gate  * scsa2usb_bulk_only_transport() handles the normal transitions or
112*7c478bd9Sstevel@tonic-gate  * continuation after clearing stalls or error recovery.
113*7c478bd9Sstevel@tonic-gate  *
114*7c478bd9Sstevel@tonic-gate  * Command Phase:
115*7c478bd9Sstevel@tonic-gate  *	prepare a valid CBW and transport it on bulk-out pipe
116*7c478bd9Sstevel@tonic-gate  *	if error on bulkout:
117*7c478bd9Sstevel@tonic-gate  *		set pkt_reason to CMD_TRAN_ERR
118*7c478bd9Sstevel@tonic-gate  *		new pkt state is SCSA2USB_PKT_DO_COMP
119*7c478bd9Sstevel@tonic-gate  *		reset recovery synchronously
120*7c478bd9Sstevel@tonic-gate  *	else
121*7c478bd9Sstevel@tonic-gate  *		proceed to data phase
122*7c478bd9Sstevel@tonic-gate  *
123*7c478bd9Sstevel@tonic-gate  * Data Phase:
124*7c478bd9Sstevel@tonic-gate  *	if data in:
125*7c478bd9Sstevel@tonic-gate  *		setup data in on bulkin
126*7c478bd9Sstevel@tonic-gate  *	else if data out:
127*7c478bd9Sstevel@tonic-gate  *		setup data out on bulkout
128*7c478bd9Sstevel@tonic-gate  *
129*7c478bd9Sstevel@tonic-gate  *	data: (in)
130*7c478bd9Sstevel@tonic-gate  *		copy data transferred so far, no more data to transfer
131*7c478bd9Sstevel@tonic-gate  *
132*7c478bd9Sstevel@tonic-gate  *		if stall on bulkin pipe
133*7c478bd9Sstevel@tonic-gate  *			terminate data transfers, set cmd_done
134*7c478bd9Sstevel@tonic-gate  *			clear stall on bulkin syncrhonously
135*7c478bd9Sstevel@tonic-gate  *		else if other exception
136*7c478bd9Sstevel@tonic-gate  *			set pkt_reason to CMD_TRAN_ERR
137*7c478bd9Sstevel@tonic-gate  *			new pkt state is SCSA2USB_PKT_DO_COMP
138*7c478bd9Sstevel@tonic-gate  *			reset recovery syncrhonously
139*7c478bd9Sstevel@tonic-gate  *		else (no error)
140*7c478bd9Sstevel@tonic-gate  *			receive status
141*7c478bd9Sstevel@tonic-gate  *
142*7c478bd9Sstevel@tonic-gate  *	 data: (out)
143*7c478bd9Sstevel@tonic-gate  *		if stall on bulkout pipe
144*7c478bd9Sstevel@tonic-gate  *			terminate data transfers, set cmd_done
145*7c478bd9Sstevel@tonic-gate  *			clear stall on bulkout synchronously USBA
146*7c478bd9Sstevel@tonic-gate  *		else if other exception
147*7c478bd9Sstevel@tonic-gate  *			set pkt_reason to CMD_TRAN_ERR
148*7c478bd9Sstevel@tonic-gate  *			new pkt state is SCSA2USB_PKT_DO_COMP
149*7c478bd9Sstevel@tonic-gate  *			reset recovery synchronously
150*7c478bd9Sstevel@tonic-gate  *		else (no error)
151*7c478bd9Sstevel@tonic-gate  *			receive status
152*7c478bd9Sstevel@tonic-gate  *
153*7c478bd9Sstevel@tonic-gate  * Status Phase:
154*7c478bd9Sstevel@tonic-gate  *
155*7c478bd9Sstevel@tonic-gate  *	if stall (first attempt)
156*7c478bd9Sstevel@tonic-gate  *		new pkt state is SCSA2USB_PKT_PROCESS_CSW
157*7c478bd9Sstevel@tonic-gate  *		setup receiving status on bulkin
158*7c478bd9Sstevel@tonic-gate  *		if stall (second attempt)
159*7c478bd9Sstevel@tonic-gate  *			new pkt state is SCSA2USB_PKT_DO_COMP
160*7c478bd9Sstevel@tonic-gate  *			reset recovery synchronously, we are hosed.
161*7c478bd9Sstevel@tonic-gate  *		else
162*7c478bd9Sstevel@tonic-gate  *			goto check CSW
163*7c478bd9Sstevel@tonic-gate  *	else
164*7c478bd9Sstevel@tonic-gate  *		goto check CSW
165*7c478bd9Sstevel@tonic-gate  *
166*7c478bd9Sstevel@tonic-gate  * check CSW:
167*7c478bd9Sstevel@tonic-gate  *	- check length equals 13, signature, and matching tag
168*7c478bd9Sstevel@tonic-gate  *	- check status is less than or equal to 2
169*7c478bd9Sstevel@tonic-gate  *	- check residue is less than or equal to data length
170*7c478bd9Sstevel@tonic-gate  *		adjust residue based on if we got valid data
171*7c478bd9Sstevel@tonic-gate  *
172*7c478bd9Sstevel@tonic-gate  *	if not OK
173*7c478bd9Sstevel@tonic-gate  *		new pkt state is SCSA2USB_PKT_DO_COMP
174*7c478bd9Sstevel@tonic-gate  *		set pkt reason CMD_TRAN_ERR
175*7c478bd9Sstevel@tonic-gate  *		reset recovery synchronously, we are hosed
176*7c478bd9Sstevel@tonic-gate  *	else if phase error
177*7c478bd9Sstevel@tonic-gate  *		new pkt state is SCSA2USB_PKT_DO_COMP
178*7c478bd9Sstevel@tonic-gate  *		set pkt reason CMD_TRAN_ERR
179*7c478bd9Sstevel@tonic-gate  *		reset recovery synchronously
180*7c478bd9Sstevel@tonic-gate  *	else if (status < 2)
181*7c478bd9Sstevel@tonic-gate  *		if status is equal to 1
182*7c478bd9Sstevel@tonic-gate  *			set check condition
183*7c478bd9Sstevel@tonic-gate  *		if residue
184*7c478bd9Sstevel@tonic-gate  *			calculate residue from data xferred and DataResidue
185*7c478bd9Sstevel@tonic-gate  *
186*7c478bd9Sstevel@tonic-gate  *			set pkt_residue
187*7c478bd9Sstevel@tonic-gate  *		goto  SCSA2USB_PKT_DO_COMP
188*7c478bd9Sstevel@tonic-gate  *
189*7c478bd9Sstevel@tonic-gate  * The reset recovery walks sequentially thru device reset, clearing
190*7c478bd9Sstevel@tonic-gate  * stalls and pipe resets. When the reset recovery completes we return
191*7c478bd9Sstevel@tonic-gate  * to the taskq thread.
192*7c478bd9Sstevel@tonic-gate  *
193*7c478bd9Sstevel@tonic-gate  * Clearing stalls clears the stall condition, resets the pipe, and
194*7c478bd9Sstevel@tonic-gate  * then returns to the transport.
195*7c478bd9Sstevel@tonic-gate  */
196*7c478bd9Sstevel@tonic-gate int
197*7c478bd9Sstevel@tonic-gate scsa2usb_bulk_only_transport(scsa2usb_state_t *scsa2usbp, scsa2usb_cmd_t *cmd)
198*7c478bd9Sstevel@tonic-gate {
199*7c478bd9Sstevel@tonic-gate 	int	rval;
200*7c478bd9Sstevel@tonic-gate 	usb_bulk_req_t *req;
201*7c478bd9Sstevel@tonic-gate 
202*7c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
203*7c478bd9Sstevel@tonic-gate 
204*7c478bd9Sstevel@tonic-gate Cmd_Phase:
205*7c478bd9Sstevel@tonic-gate 	/*
206*7c478bd9Sstevel@tonic-gate 	 * Start Command Phase
207*7c478bd9Sstevel@tonic-gate 	 * Initialize a bulk_req_t
208*7c478bd9Sstevel@tonic-gate 	 */
209*7c478bd9Sstevel@tonic-gate 	req = scsa2usb_init_bulk_req(scsa2usbp, USB_BULK_CBWCMD_LEN,
210*7c478bd9Sstevel@tonic-gate 	    SCSA2USB_BULK_PIPE_TIMEOUT, USB_ATTRS_PIPE_RESET, USB_FLAGS_SLEEP);
211*7c478bd9Sstevel@tonic-gate 
212*7c478bd9Sstevel@tonic-gate 	scsa2usb_fill_in_cbw(scsa2usbp, cmd, req->bulk_data);	/* Fill CBW */
213*7c478bd9Sstevel@tonic-gate 	SCSA2USB_PRINT_CDB(scsa2usbp, cmd);			/* Print CDB */
214*7c478bd9Sstevel@tonic-gate 
215*7c478bd9Sstevel@tonic-gate 	/* Send a Bulk Command Block Wrapper (CBW) to the device */
216*7c478bd9Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
217*7c478bd9Sstevel@tonic-gate 
218*7c478bd9Sstevel@tonic-gate 	ASSERT(req->bulk_timeout);
219*7c478bd9Sstevel@tonic-gate 	rval = usb_pipe_bulk_xfer(scsa2usbp->scsa2usb_bulkout_pipe, req,
220*7c478bd9Sstevel@tonic-gate 	    USB_FLAGS_SLEEP);
221*7c478bd9Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
222*7c478bd9Sstevel@tonic-gate 
223*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
224*7c478bd9Sstevel@tonic-gate 	    "scsa2usb_bulk_only_transport: "
225*7c478bd9Sstevel@tonic-gate 	    "sent cmd = 0x%x Tag = 0x%x DataXferLen = 0x%lx rval = %d",
226*7c478bd9Sstevel@tonic-gate 	    cmd->cmd_cdb[SCSA2USB_OPCODE], cmd->cmd_tag, cmd->cmd_xfercount,
227*7c478bd9Sstevel@tonic-gate 	    rval);
228*7c478bd9Sstevel@tonic-gate 
229*7c478bd9Sstevel@tonic-gate 	if (rval != USB_SUCCESS) {
230*7c478bd9Sstevel@tonic-gate 		scsa2usb_bulk_only_handle_error(scsa2usbp, req);
231*7c478bd9Sstevel@tonic-gate 
232*7c478bd9Sstevel@tonic-gate 		return (TRAN_FATAL_ERROR);
233*7c478bd9Sstevel@tonic-gate 	}
234*7c478bd9Sstevel@tonic-gate 
235*7c478bd9Sstevel@tonic-gate 	/* free the data */
236*7c478bd9Sstevel@tonic-gate 	SCSA2USB_FREE_MSG(req->bulk_data);
237*7c478bd9Sstevel@tonic-gate 	req->bulk_data = NULL;
238*7c478bd9Sstevel@tonic-gate 
239*7c478bd9Sstevel@tonic-gate Data_Phase:
240*7c478bd9Sstevel@tonic-gate 	/*
241*7c478bd9Sstevel@tonic-gate 	 * Start Data Phase
242*7c478bd9Sstevel@tonic-gate 	 * re-set timeout
243*7c478bd9Sstevel@tonic-gate 	 */
244*7c478bd9Sstevel@tonic-gate 	req->bulk_timeout = scsa2usb_bulk_timeout(cmd->cmd_timeout);
245*7c478bd9Sstevel@tonic-gate 
246*7c478bd9Sstevel@tonic-gate 	/*
247*7c478bd9Sstevel@tonic-gate 	 * we've not transferred any data yet; updated in
248*7c478bd9Sstevel@tonic-gate 	 * scsa2usb_handle_data_done
249*7c478bd9Sstevel@tonic-gate 	 */
250*7c478bd9Sstevel@tonic-gate 	cmd->cmd_resid_xfercount = cmd->cmd_xfercount;
251*7c478bd9Sstevel@tonic-gate 
252*7c478bd9Sstevel@tonic-gate 	if (cmd->cmd_xfercount) {
253*7c478bd9Sstevel@tonic-gate 		/* start I/O to/from the device */
254*7c478bd9Sstevel@tonic-gate 		rval = scsa2usb_handle_data_start(scsa2usbp, cmd, req);
255*7c478bd9Sstevel@tonic-gate 
256*7c478bd9Sstevel@tonic-gate 		/* handle data returned, if any */
257*7c478bd9Sstevel@tonic-gate 		scsa2usb_handle_data_done(scsa2usbp, cmd, req);
258*7c478bd9Sstevel@tonic-gate 
259*7c478bd9Sstevel@tonic-gate 		if (rval != USB_SUCCESS) {
260*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_SCSA,
261*7c478bd9Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
262*7c478bd9Sstevel@tonic-gate 			    "data xfer phase, error =  %d, cr = %d",
263*7c478bd9Sstevel@tonic-gate 			    rval, req->bulk_completion_reason);
264*7c478bd9Sstevel@tonic-gate 			/*
265*7c478bd9Sstevel@tonic-gate 			 * we ran into an error
266*7c478bd9Sstevel@tonic-gate 			 */
267*7c478bd9Sstevel@tonic-gate 			if (req->bulk_completion_reason == USB_CR_STALL) {
268*7c478bd9Sstevel@tonic-gate 				if (scsa2usbp->scsa2usb_cur_pkt) {
269*7c478bd9Sstevel@tonic-gate 					scsa2usbp->scsa2usb_cur_pkt->
270*7c478bd9Sstevel@tonic-gate 						pkt_reason = CMD_TRAN_ERR;
271*7c478bd9Sstevel@tonic-gate 				}
272*7c478bd9Sstevel@tonic-gate 			} else {
273*7c478bd9Sstevel@tonic-gate 				scsa2usb_bulk_only_handle_error(scsa2usbp, req);
274*7c478bd9Sstevel@tonic-gate 
275*7c478bd9Sstevel@tonic-gate 				return (TRAN_FATAL_ERROR);
276*7c478bd9Sstevel@tonic-gate 			}
277*7c478bd9Sstevel@tonic-gate 		} /* end of else */
278*7c478bd9Sstevel@tonic-gate 
279*7c478bd9Sstevel@tonic-gate 		/* free the data */
280*7c478bd9Sstevel@tonic-gate 		SCSA2USB_FREE_MSG(req->bulk_data);
281*7c478bd9Sstevel@tonic-gate 		req->bulk_data = NULL;
282*7c478bd9Sstevel@tonic-gate 	}
283*7c478bd9Sstevel@tonic-gate 
284*7c478bd9Sstevel@tonic-gate Status_Phase:
285*7c478bd9Sstevel@tonic-gate 	/*
286*7c478bd9Sstevel@tonic-gate 	 * Start status phase
287*7c478bd9Sstevel@tonic-gate 	 * read in CSW
288*7c478bd9Sstevel@tonic-gate 	 */
289*7c478bd9Sstevel@tonic-gate 	if ((rval = scsa2usb_handle_status_start(scsa2usbp, req)) ==
290*7c478bd9Sstevel@tonic-gate 	    USB_SUCCESS) {
291*7c478bd9Sstevel@tonic-gate 		/* process CSW */
292*7c478bd9Sstevel@tonic-gate 		rval = scsa2usb_handle_csw_result(scsa2usbp, req->bulk_data);
293*7c478bd9Sstevel@tonic-gate 	} else {
294*7c478bd9Sstevel@tonic-gate 		/*
295*7c478bd9Sstevel@tonic-gate 		 * we ran into an error, check if it was a STALL
296*7c478bd9Sstevel@tonic-gate 		 */
297*7c478bd9Sstevel@tonic-gate 		if (req->bulk_completion_reason == USB_CR_STALL)  {
298*7c478bd9Sstevel@tonic-gate 			scsa2usbp->scsa2usb_pkt_state =
299*7c478bd9Sstevel@tonic-gate 					SCSA2USB_PKT_PROCESS_CSW;
300*7c478bd9Sstevel@tonic-gate 
301*7c478bd9Sstevel@tonic-gate 			goto Status_Phase;
302*7c478bd9Sstevel@tonic-gate 		} else {
303*7c478bd9Sstevel@tonic-gate 			scsa2usb_bulk_only_handle_error(scsa2usbp, req);
304*7c478bd9Sstevel@tonic-gate 
305*7c478bd9Sstevel@tonic-gate 			return (TRAN_FATAL_ERROR);
306*7c478bd9Sstevel@tonic-gate 		}
307*7c478bd9Sstevel@tonic-gate 	}
308*7c478bd9Sstevel@tonic-gate 
309*7c478bd9Sstevel@tonic-gate 	SCSA2USB_FREE_BULK_REQ(req);	/* free request */
310*7c478bd9Sstevel@tonic-gate 
311*7c478bd9Sstevel@tonic-gate 	if ((rval == USB_SUCCESS) &&		/* CSW was ok */
312*7c478bd9Sstevel@tonic-gate 	    (scsa2usbp->scsa2usb_cur_pkt->pkt_reason == CMD_CMPLT) &&
313*7c478bd9Sstevel@tonic-gate 	    (cmd->cmd_xfercount != 0) &&	/* more data to xfer */
314*7c478bd9Sstevel@tonic-gate 	    !cmd->cmd_done) {			/* we aren't done yet */
315*7c478bd9Sstevel@tonic-gate 		scsa2usb_setup_next_xfer(scsa2usbp, cmd);
316*7c478bd9Sstevel@tonic-gate 		goto Cmd_Phase;
317*7c478bd9Sstevel@tonic-gate 	}
318*7c478bd9Sstevel@tonic-gate 
319*7c478bd9Sstevel@tonic-gate 	return (rval == USB_SUCCESS ? TRAN_ACCEPT : TRAN_FATAL_ERROR);
320*7c478bd9Sstevel@tonic-gate }
321*7c478bd9Sstevel@tonic-gate 
322*7c478bd9Sstevel@tonic-gate 
323*7c478bd9Sstevel@tonic-gate /*
324*7c478bd9Sstevel@tonic-gate  * scsa2usb_fill_in_cbw:
325*7c478bd9Sstevel@tonic-gate  *	Fill in a CBW request packet. This
326*7c478bd9Sstevel@tonic-gate  *	packet is transported to the device
327*7c478bd9Sstevel@tonic-gate  */
328*7c478bd9Sstevel@tonic-gate static void
329*7c478bd9Sstevel@tonic-gate scsa2usb_fill_in_cbw(scsa2usb_state_t *scsa2usbp,
330*7c478bd9Sstevel@tonic-gate     scsa2usb_cmd_t *cmd, mblk_t *mp)
331*7c478bd9Sstevel@tonic-gate {
332*7c478bd9Sstevel@tonic-gate 	int	i;
333*7c478bd9Sstevel@tonic-gate 	int	len;
334*7c478bd9Sstevel@tonic-gate 	uchar_t dir, *cdb = (uchar_t *)(&cmd->cmd_cdb);
335*7c478bd9Sstevel@tonic-gate 
336*7c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
337*7c478bd9Sstevel@tonic-gate 
338*7c478bd9Sstevel@tonic-gate 	*mp->b_wptr++ = CBW_MSB(CBW_SIGNATURE);	/* CBW Signature */;
339*7c478bd9Sstevel@tonic-gate 	*mp->b_wptr++ = CBW_MID1(CBW_SIGNATURE);
340*7c478bd9Sstevel@tonic-gate 	*mp->b_wptr++ = CBW_MID2(CBW_SIGNATURE);
341*7c478bd9Sstevel@tonic-gate 	*mp->b_wptr++ = CBW_LSB(CBW_SIGNATURE);
342*7c478bd9Sstevel@tonic-gate 	*mp->b_wptr++ = CBW_LSB(cmd->cmd_tag);	/* CBW Tag */
343*7c478bd9Sstevel@tonic-gate 	*mp->b_wptr++ = CBW_MID2(cmd->cmd_tag);
344*7c478bd9Sstevel@tonic-gate 	*mp->b_wptr++ = CBW_MID1(cmd->cmd_tag);
345*7c478bd9Sstevel@tonic-gate 	*mp->b_wptr++ = CBW_MSB(cmd->cmd_tag);
346*7c478bd9Sstevel@tonic-gate 
347*7c478bd9Sstevel@tonic-gate 	dir = cmd->cmd_dir;
348*7c478bd9Sstevel@tonic-gate 	len = cmd->cmd_xfercount;
349*7c478bd9Sstevel@tonic-gate #ifdef	SCSA2USB_BULK_ONLY_TEST
350*7c478bd9Sstevel@tonic-gate 	if (scsa2usb_test_case_2 && (cdb[0] == SCMD_READ_CAPACITY)) {
351*7c478bd9Sstevel@tonic-gate 		/* Host expects no data. The device wants data. Hn < Di */
352*7c478bd9Sstevel@tonic-gate 		scsa2usb_test_case_2 = len = 0;
353*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L1(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
354*7c478bd9Sstevel@tonic-gate 		    "TEST 2: Hn < Di cdb: 0x%x len: 0x%x", cdb[0], len);
355*7c478bd9Sstevel@tonic-gate 	}
356*7c478bd9Sstevel@tonic-gate 
357*7c478bd9Sstevel@tonic-gate 	if (scsa2usb_test_case_3 && (cmd->cmd_dir == CBW_DIR_OUT)) {
358*7c478bd9Sstevel@tonic-gate 		/* Host expects no data. The device wants data. Hn < Do */
359*7c478bd9Sstevel@tonic-gate 		if (cdb[0] == SCMD_WRITE_G1) {
360*7c478bd9Sstevel@tonic-gate 			scsa2usb_test_case_3 = len = 0;
361*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_SCSA,
362*7c478bd9Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
363*7c478bd9Sstevel@tonic-gate 			    "TEST 3: Hn < Do cdb: 0x%x len:%x", cdb[0], len);
364*7c478bd9Sstevel@tonic-gate 		}
365*7c478bd9Sstevel@tonic-gate 	}
366*7c478bd9Sstevel@tonic-gate 
367*7c478bd9Sstevel@tonic-gate 	if (scsa2usb_test_case_4 && (cdb[0] == SCMD_READ_G1)) {
368*7c478bd9Sstevel@tonic-gate 		cdb[0] = 0x5e;
369*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L1(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
370*7c478bd9Sstevel@tonic-gate 		    "TEST 4: Hi > Dn: changed cdb to 0x%x", cdb[0]);
371*7c478bd9Sstevel@tonic-gate 		scsa2usb_test_case_4 = 0;
372*7c478bd9Sstevel@tonic-gate 	}
373*7c478bd9Sstevel@tonic-gate 
374*7c478bd9Sstevel@tonic-gate 	if (scsa2usb_test_case_7 && (cmd->cmd_cdb[0] == SCMD_READ_G1)) {
375*7c478bd9Sstevel@tonic-gate 		len -= 0x10;
376*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L1(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
377*7c478bd9Sstevel@tonic-gate 		    "TEST 7: Hi < Di cdb: 0x%x len: 0x%x", cdb[0], len);
378*7c478bd9Sstevel@tonic-gate 		scsa2usb_test_case_7 = 0;
379*7c478bd9Sstevel@tonic-gate 	}
380*7c478bd9Sstevel@tonic-gate 
381*7c478bd9Sstevel@tonic-gate 	if (scsa2usb_test_case_8 && (cdb[0] == SCMD_READ_G1)) {
382*7c478bd9Sstevel@tonic-gate 		dir = (dir == CBW_DIR_IN) ? CBW_DIR_OUT : dir;
383*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L1(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
384*7c478bd9Sstevel@tonic-gate 		    "TEST 8: Hi <> Do cdb: 0x%x dir: 0x%x", cdb[0], dir);
385*7c478bd9Sstevel@tonic-gate 	}
386*7c478bd9Sstevel@tonic-gate 
387*7c478bd9Sstevel@tonic-gate 	if (scsa2usb_test_case_9 && (cdb[0] == SCMD_WRITE_G1)) {
388*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L1(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
389*7c478bd9Sstevel@tonic-gate 		    "TEST 9: Ho <> Di (%x)", cdb[0]);
390*7c478bd9Sstevel@tonic-gate 		cdb[SCSA2USB_LEN_0] = cdb[SCSA2USB_LEN_1] = 0;
391*7c478bd9Sstevel@tonic-gate 		scsa2usb_test_case_9 = 0;
392*7c478bd9Sstevel@tonic-gate 	}
393*7c478bd9Sstevel@tonic-gate 
394*7c478bd9Sstevel@tonic-gate 	if (scsa2usb_test_case_10 && (cdb[0] == SCMD_WRITE_G1)) {
395*7c478bd9Sstevel@tonic-gate 		dir = (dir == CBW_DIR_OUT) ? CBW_DIR_IN : dir;
396*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L1(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
397*7c478bd9Sstevel@tonic-gate 		    "TEST 10: Ho <> Di cdb: 0x%x dir: 0x%x", cdb[0], dir);
398*7c478bd9Sstevel@tonic-gate 	}
399*7c478bd9Sstevel@tonic-gate 
400*7c478bd9Sstevel@tonic-gate 	/*
401*7c478bd9Sstevel@tonic-gate 	 * This case occurs when the device intends to receive
402*7c478bd9Sstevel@tonic-gate 	 * more data from the host than the host sends.
403*7c478bd9Sstevel@tonic-gate 	 */
404*7c478bd9Sstevel@tonic-gate 	if (scsa2usb_test_case_13) {
405*7c478bd9Sstevel@tonic-gate 		if ((cdb[0] == SCMD_WRITE_G1) || (cdb[0] == SCMD_READ_G1)) {
406*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_SCSA,
407*7c478bd9Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle, "TEST 13: Ho < Do");
408*7c478bd9Sstevel@tonic-gate 
409*7c478bd9Sstevel@tonic-gate 			len -= 30;
410*7c478bd9Sstevel@tonic-gate 			scsa2usb_test_case_13 = 0;
411*7c478bd9Sstevel@tonic-gate 		}
412*7c478bd9Sstevel@tonic-gate 	}
413*7c478bd9Sstevel@tonic-gate #endif	/* SCSA2USB_BULK_ONLY_TEST */
414*7c478bd9Sstevel@tonic-gate 
415*7c478bd9Sstevel@tonic-gate 	*mp->b_wptr++ = CBW_MSB(len);		/* Transfer Length */
416*7c478bd9Sstevel@tonic-gate 	*mp->b_wptr++ = CBW_MID1(len);
417*7c478bd9Sstevel@tonic-gate 	*mp->b_wptr++ = CBW_MID2(len);
418*7c478bd9Sstevel@tonic-gate 	*mp->b_wptr++ = CBW_LSB(len);
419*7c478bd9Sstevel@tonic-gate 
420*7c478bd9Sstevel@tonic-gate 	*mp->b_wptr++ = dir;			/* Transfer Direction */
421*7c478bd9Sstevel@tonic-gate 	*mp->b_wptr++ = cmd->cmd_pkt->pkt_address.a_lun;	/* Lun # */
422*7c478bd9Sstevel@tonic-gate 	*mp->b_wptr++ = cmd->cmd_actual_len;			/* CDB Len */
423*7c478bd9Sstevel@tonic-gate 
424*7c478bd9Sstevel@tonic-gate 	/* Copy the CDB out */
425*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < CBW_CDB_LEN; i++) {
426*7c478bd9Sstevel@tonic-gate 		*mp->b_wptr++ = *cdb++;
427*7c478bd9Sstevel@tonic-gate 	}
428*7c478bd9Sstevel@tonic-gate #ifdef DUMP_CWB
429*7c478bd9Sstevel@tonic-gate {
430*7c478bd9Sstevel@tonic-gate 	int len = mp->b_wptr - mp->b_rptr;
431*7c478bd9Sstevel@tonic-gate 	char *buf;
432*7c478bd9Sstevel@tonic-gate 
433*7c478bd9Sstevel@tonic-gate 	int i;
434*7c478bd9Sstevel@tonic-gate 
435*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "CWB: len=%d\n", len);
436*7c478bd9Sstevel@tonic-gate 	buf = kmem_zalloc(512, KM_SLEEP);
437*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < len; i++) {
438*7c478bd9Sstevel@tonic-gate 		sprintf(&buf[strlen(buf)], "%02x ", mp->b_rptr[i]);
439*7c478bd9Sstevel@tonic-gate 	}
440*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "%s\n", buf);
441*7c478bd9Sstevel@tonic-gate 	kmem_free(buf, 512);
442*7c478bd9Sstevel@tonic-gate }
443*7c478bd9Sstevel@tonic-gate #endif
444*7c478bd9Sstevel@tonic-gate 
445*7c478bd9Sstevel@tonic-gate }
446*7c478bd9Sstevel@tonic-gate 
447*7c478bd9Sstevel@tonic-gate 
448*7c478bd9Sstevel@tonic-gate /*
449*7c478bd9Sstevel@tonic-gate  * scsa2usb_bulk_only_handle_error:
450*7c478bd9Sstevel@tonic-gate  *	handle transport errors and start recovery
451*7c478bd9Sstevel@tonic-gate  */
452*7c478bd9Sstevel@tonic-gate static void
453*7c478bd9Sstevel@tonic-gate scsa2usb_bulk_only_handle_error(scsa2usb_state_t *scsa2usbp,
454*7c478bd9Sstevel@tonic-gate     usb_bulk_req_t *req)
455*7c478bd9Sstevel@tonic-gate {
456*7c478bd9Sstevel@tonic-gate 	struct scsi_pkt *pkt = scsa2usbp->scsa2usb_cur_pkt;
457*7c478bd9Sstevel@tonic-gate 
458*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
459*7c478bd9Sstevel@tonic-gate 	    "scsa2usb_bulk_only_handle_error: req = 0x%p, cr = 0x%x",
460*7c478bd9Sstevel@tonic-gate 	    req, (req ? req->bulk_completion_reason : 0));
461*7c478bd9Sstevel@tonic-gate 
462*7c478bd9Sstevel@tonic-gate 	if (req) {
463*7c478bd9Sstevel@tonic-gate 		SCSA2USB_SET_PKT_DO_COMP_STATE(scsa2usbp);
464*7c478bd9Sstevel@tonic-gate 
465*7c478bd9Sstevel@tonic-gate 		/* invoke reset recovery */
466*7c478bd9Sstevel@tonic-gate 		switch (req->bulk_completion_reason) {
467*7c478bd9Sstevel@tonic-gate 		case USB_CR_STALL:
468*7c478bd9Sstevel@tonic-gate 			if (pkt) {
469*7c478bd9Sstevel@tonic-gate 				pkt->pkt_reason = CMD_TRAN_ERR;
470*7c478bd9Sstevel@tonic-gate 			}
471*7c478bd9Sstevel@tonic-gate 			break;
472*7c478bd9Sstevel@tonic-gate 		case USB_CR_TIMEOUT:
473*7c478bd9Sstevel@tonic-gate 			if (pkt) {
474*7c478bd9Sstevel@tonic-gate 				pkt->pkt_reason = CMD_TIMEOUT;
475*7c478bd9Sstevel@tonic-gate 				pkt->pkt_statistics |= STAT_TIMEOUT;
476*7c478bd9Sstevel@tonic-gate 			}
477*7c478bd9Sstevel@tonic-gate 			break;
478*7c478bd9Sstevel@tonic-gate 		case USB_CR_DEV_NOT_RESP:
479*7c478bd9Sstevel@tonic-gate 			if (pkt) {
480*7c478bd9Sstevel@tonic-gate 				pkt->pkt_reason = CMD_DEV_GONE;
481*7c478bd9Sstevel@tonic-gate 				/* scsi_poll relies on this */
482*7c478bd9Sstevel@tonic-gate 				pkt->pkt_state = STATE_GOT_BUS;
483*7c478bd9Sstevel@tonic-gate 			}
484*7c478bd9Sstevel@tonic-gate 			break;
485*7c478bd9Sstevel@tonic-gate 		default:
486*7c478bd9Sstevel@tonic-gate 			if (pkt) {
487*7c478bd9Sstevel@tonic-gate 				pkt->pkt_reason = CMD_TRAN_ERR;
488*7c478bd9Sstevel@tonic-gate 			}
489*7c478bd9Sstevel@tonic-gate 		}
490*7c478bd9Sstevel@tonic-gate 		scsa2usb_bulk_only_reset_recovery(scsa2usbp);
491*7c478bd9Sstevel@tonic-gate 	}
492*7c478bd9Sstevel@tonic-gate 
493*7c478bd9Sstevel@tonic-gate 	SCSA2USB_FREE_BULK_REQ(req);
494*7c478bd9Sstevel@tonic-gate }
495*7c478bd9Sstevel@tonic-gate 
496*7c478bd9Sstevel@tonic-gate 
497*7c478bd9Sstevel@tonic-gate /*
498*7c478bd9Sstevel@tonic-gate  * scsa2usb_handle_status_start:
499*7c478bd9Sstevel@tonic-gate  *	Receive status data
500*7c478bd9Sstevel@tonic-gate  */
501*7c478bd9Sstevel@tonic-gate static int
502*7c478bd9Sstevel@tonic-gate scsa2usb_handle_status_start(scsa2usb_state_t *scsa2usbp,
503*7c478bd9Sstevel@tonic-gate     usb_bulk_req_t *req)
504*7c478bd9Sstevel@tonic-gate {
505*7c478bd9Sstevel@tonic-gate 	int rval;
506*7c478bd9Sstevel@tonic-gate 
507*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
508*7c478bd9Sstevel@tonic-gate 	    "scsa2usb_handle_status_start: req = 0x%p", req);
509*7c478bd9Sstevel@tonic-gate 
510*7c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
511*7c478bd9Sstevel@tonic-gate 
512*7c478bd9Sstevel@tonic-gate 	/* setup up for receiving CSW */
513*7c478bd9Sstevel@tonic-gate #ifdef	SCSA2USB_BULK_ONLY_TEST
514*7c478bd9Sstevel@tonic-gate 	req->bulk_attributes = 0;
515*7c478bd9Sstevel@tonic-gate #else
516*7c478bd9Sstevel@tonic-gate 	req->bulk_attributes = USB_ATTRS_SHORT_XFER_OK;
517*7c478bd9Sstevel@tonic-gate #endif	/* SCSA2USB_BULK_ONLY_TEST */
518*7c478bd9Sstevel@tonic-gate 	req->bulk_len = CSW_LEN;
519*7c478bd9Sstevel@tonic-gate 
520*7c478bd9Sstevel@tonic-gate 	SCSA2USB_FREE_MSG(req->bulk_data);
521*7c478bd9Sstevel@tonic-gate 	req->bulk_data = allocb_wait(req->bulk_len,
522*7c478bd9Sstevel@tonic-gate 	    BPRI_LO, STR_NOSIG, NULL);
523*7c478bd9Sstevel@tonic-gate 
524*7c478bd9Sstevel@tonic-gate 	/* Issue the request */
525*7c478bd9Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
526*7c478bd9Sstevel@tonic-gate 
527*7c478bd9Sstevel@tonic-gate 	ASSERT(req->bulk_timeout);
528*7c478bd9Sstevel@tonic-gate 	rval = usb_pipe_bulk_xfer(scsa2usbp->scsa2usb_bulkin_pipe, req,
529*7c478bd9Sstevel@tonic-gate 	    USB_FLAGS_SLEEP);
530*7c478bd9Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
531*7c478bd9Sstevel@tonic-gate 
532*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
533*7c478bd9Sstevel@tonic-gate 	    "scsa2usb_handle_status_start: END rval = 0x%x", rval);
534*7c478bd9Sstevel@tonic-gate 
535*7c478bd9Sstevel@tonic-gate 	if (rval != USB_SUCCESS) {
536*7c478bd9Sstevel@tonic-gate 		if (scsa2usbp->scsa2usb_pkt_state == SCSA2USB_PKT_PROCESS_CSW) {
537*7c478bd9Sstevel@tonic-gate 			scsa2usb_bulk_only_reset_recovery(scsa2usbp);
538*7c478bd9Sstevel@tonic-gate 
539*7c478bd9Sstevel@tonic-gate 			return (rval);
540*7c478bd9Sstevel@tonic-gate 		}
541*7c478bd9Sstevel@tonic-gate 
542*7c478bd9Sstevel@tonic-gate 		if (req->bulk_completion_reason == USB_CR_STALL) {
543*7c478bd9Sstevel@tonic-gate 			(void) scsa2usb_clear_ept_stall(scsa2usbp,
544*7c478bd9Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_bulkin_ept.bEndpointAddress,
545*7c478bd9Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_bulkin_pipe, "bulk-in");
546*7c478bd9Sstevel@tonic-gate 		}
547*7c478bd9Sstevel@tonic-gate 	}
548*7c478bd9Sstevel@tonic-gate 
549*7c478bd9Sstevel@tonic-gate 	return (rval);
550*7c478bd9Sstevel@tonic-gate }
551*7c478bd9Sstevel@tonic-gate 
552*7c478bd9Sstevel@tonic-gate 
553*7c478bd9Sstevel@tonic-gate /*
554*7c478bd9Sstevel@tonic-gate  * scsa2usb_handle_csw_result:
555*7c478bd9Sstevel@tonic-gate  *	Handle status results
556*7c478bd9Sstevel@tonic-gate  */
557*7c478bd9Sstevel@tonic-gate static int
558*7c478bd9Sstevel@tonic-gate scsa2usb_handle_csw_result(scsa2usb_state_t *scsa2usbp, mblk_t *data)
559*7c478bd9Sstevel@tonic-gate {
560*7c478bd9Sstevel@tonic-gate 	int		rval = USB_SUCCESS;
561*7c478bd9Sstevel@tonic-gate 	int		residue;
562*7c478bd9Sstevel@tonic-gate 	char		*msg = "CSW FAILED";
563*7c478bd9Sstevel@tonic-gate 	uint_t		signature, tag, status;
564*7c478bd9Sstevel@tonic-gate 	usb_bulk_csw_t	csw;
565*7c478bd9Sstevel@tonic-gate 	struct scsi_pkt *pkt = scsa2usbp->scsa2usb_cur_pkt;
566*7c478bd9Sstevel@tonic-gate 	scsa2usb_cmd_t	*cmd = PKT2CMD(pkt);
567*7c478bd9Sstevel@tonic-gate 
568*7c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
569*7c478bd9Sstevel@tonic-gate 
570*7c478bd9Sstevel@tonic-gate 	/*
571*7c478bd9Sstevel@tonic-gate 	 * This shouldn't happen. It implies the device's
572*7c478bd9Sstevel@tonic-gate 	 * firmware is bad and has returned NULL CSW.
573*7c478bd9Sstevel@tonic-gate 	 * return failure back.
574*7c478bd9Sstevel@tonic-gate 	 */
575*7c478bd9Sstevel@tonic-gate 	if (data == NULL) {
576*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
577*7c478bd9Sstevel@tonic-gate 		    "scsa2usb_handle_csw_result: data == NULL");
578*7c478bd9Sstevel@tonic-gate 
579*7c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
580*7c478bd9Sstevel@tonic-gate 	}
581*7c478bd9Sstevel@tonic-gate 
582*7c478bd9Sstevel@tonic-gate 	/* check if we got back CSW_LEN or not */
583*7c478bd9Sstevel@tonic-gate 	if ((data->b_wptr - data->b_rptr) != CSW_LEN) {
584*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
585*7c478bd9Sstevel@tonic-gate 		    "scsa2usb_handle_csw_result: no enough data (%d)",
586*7c478bd9Sstevel@tonic-gate 		    data->b_wptr - data->b_rptr);
587*7c478bd9Sstevel@tonic-gate 
588*7c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
589*7c478bd9Sstevel@tonic-gate 	}
590*7c478bd9Sstevel@tonic-gate 
591*7c478bd9Sstevel@tonic-gate 	/* Read into csw */
592*7c478bd9Sstevel@tonic-gate 	bcopy(data->b_rptr, &csw, CSW_LEN);
593*7c478bd9Sstevel@tonic-gate 
594*7c478bd9Sstevel@tonic-gate 	status = csw.csw_bCSWStatus;
595*7c478bd9Sstevel@tonic-gate 	signature = SCSA2USB_MK_32BIT(csw.csw_dCSWSignature3,
596*7c478bd9Sstevel@tonic-gate 	    csw.csw_dCSWSignature2, csw.csw_dCSWSignature1,
597*7c478bd9Sstevel@tonic-gate 	    csw.csw_dCSWSignature0);
598*7c478bd9Sstevel@tonic-gate 	residue = SCSA2USB_MK_32BIT(csw.csw_dCSWDataResidue3,
599*7c478bd9Sstevel@tonic-gate 	    csw.csw_dCSWDataResidue2, csw.csw_dCSWDataResidue1,
600*7c478bd9Sstevel@tonic-gate 	    csw.csw_dCSWDataResidue0);
601*7c478bd9Sstevel@tonic-gate 	tag = SCSA2USB_MK_32BIT(csw.csw_dCSWTag3, csw.csw_dCSWTag2,
602*7c478bd9Sstevel@tonic-gate 	    csw.csw_dCSWTag1, csw.csw_dCSWTag0);
603*7c478bd9Sstevel@tonic-gate 
604*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
605*7c478bd9Sstevel@tonic-gate 	    "CSW: Signature = 0x%x Status = 0%x Tag = 0x%x Residue = 0x%x",
606*7c478bd9Sstevel@tonic-gate 	    signature, status, tag,  residue);
607*7c478bd9Sstevel@tonic-gate 
608*7c478bd9Sstevel@tonic-gate 	/* Check for abnormal errors */
609*7c478bd9Sstevel@tonic-gate 	if ((signature != CSW_SIGNATURE) || (tag != cmd->cmd_tag) ||
610*7c478bd9Sstevel@tonic-gate 	    (status < CSW_STATUS_GOOD) || (status > CSW_STATUS_PHASE_ERROR)) {
611*7c478bd9Sstevel@tonic-gate 
612*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
613*7c478bd9Sstevel@tonic-gate 		    "CSW_ERR: Status = 0x%x, Tag = 0x%x xfercount = 0x%lx",
614*7c478bd9Sstevel@tonic-gate 		    status, cmd->cmd_tag, cmd->cmd_total_xfercount);
615*7c478bd9Sstevel@tonic-gate 
616*7c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
617*7c478bd9Sstevel@tonic-gate 	}
618*7c478bd9Sstevel@tonic-gate 
619*7c478bd9Sstevel@tonic-gate 	switch (status) {
620*7c478bd9Sstevel@tonic-gate 	case CSW_STATUS_GOOD:
621*7c478bd9Sstevel@tonic-gate 		/*
622*7c478bd9Sstevel@tonic-gate 		 * Fail the command if the device misbehaves and
623*7c478bd9Sstevel@tonic-gate 		 * gives a good status but doesn't transfer any data.
624*7c478bd9Sstevel@tonic-gate 		 * Otherwise we'll get into an infinite retry loop.
625*7c478bd9Sstevel@tonic-gate 		 *
626*7c478bd9Sstevel@tonic-gate 		 * We test only against cmd_total_xfercount here and
627*7c478bd9Sstevel@tonic-gate 		 * assume that this will not happen on a command that
628*7c478bd9Sstevel@tonic-gate 		 * transfers a large amount of data and therefore may
629*7c478bd9Sstevel@tonic-gate 		 * be split into separate transfers. For a large data
630*7c478bd9Sstevel@tonic-gate 		 * transfer it is assumed that the device will return
631*7c478bd9Sstevel@tonic-gate 		 * an error status if the transfer does not occur.
632*7c478bd9Sstevel@tonic-gate 		 * this isn't quite correct because a subsequent request
633*7c478bd9Sstevel@tonic-gate 		 * sense may not give a valid sense key.
634*7c478bd9Sstevel@tonic-gate 		 */
635*7c478bd9Sstevel@tonic-gate 		if (!cmd->cmd_done && residue &&
636*7c478bd9Sstevel@tonic-gate 		    (residue == cmd->cmd_total_xfercount)) {
637*7c478bd9Sstevel@tonic-gate 			*(pkt->pkt_scbp) = STATUS_CHECK;
638*7c478bd9Sstevel@tonic-gate 			cmd->cmd_xfercount = 0;
639*7c478bd9Sstevel@tonic-gate 			cmd->cmd_done = 1;
640*7c478bd9Sstevel@tonic-gate 		} else {
641*7c478bd9Sstevel@tonic-gate 			msg = "CSW GOOD";
642*7c478bd9Sstevel@tonic-gate 		}
643*7c478bd9Sstevel@tonic-gate 		break;
644*7c478bd9Sstevel@tonic-gate 	case CSW_STATUS_FAILED:
645*7c478bd9Sstevel@tonic-gate 		*(pkt->pkt_scbp) = STATUS_CHECK; /* Set check condition */
646*7c478bd9Sstevel@tonic-gate 		cmd->cmd_done = 1;
647*7c478bd9Sstevel@tonic-gate 		break;
648*7c478bd9Sstevel@tonic-gate 	case CSW_STATUS_PHASE_ERROR:
649*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
650*7c478bd9Sstevel@tonic-gate 		    "scsa2usb_handle_csw_result: Phase Error");
651*7c478bd9Sstevel@tonic-gate 
652*7c478bd9Sstevel@tonic-gate 		/* invoke reset recovery */
653*7c478bd9Sstevel@tonic-gate 		scsa2usb_bulk_only_handle_error(scsa2usbp, NULL);
654*7c478bd9Sstevel@tonic-gate 
655*7c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
656*7c478bd9Sstevel@tonic-gate 	default:	/* shouldn't happen anymore */
657*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
658*7c478bd9Sstevel@tonic-gate 		    "scsa2usb_handle_csw_result: Invalid CSW");
659*7c478bd9Sstevel@tonic-gate 
660*7c478bd9Sstevel@tonic-gate 		/* invoke reset recovery */
661*7c478bd9Sstevel@tonic-gate 		scsa2usb_bulk_only_handle_error(scsa2usbp, NULL);
662*7c478bd9Sstevel@tonic-gate 
663*7c478bd9Sstevel@tonic-gate 		return (USB_SUCCESS);
664*7c478bd9Sstevel@tonic-gate 	} /* end of switch */
665*7c478bd9Sstevel@tonic-gate 
666*7c478bd9Sstevel@tonic-gate 	/* Set resid */
667*7c478bd9Sstevel@tonic-gate 	if (residue || cmd->cmd_resid_xfercount) {
668*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA,
669*7c478bd9Sstevel@tonic-gate 		    scsa2usbp->scsa2usb_log_handle,
670*7c478bd9Sstevel@tonic-gate 		    "total=0x%lx cmd_xfercount=0x%lx residue=0x%x",
671*7c478bd9Sstevel@tonic-gate 		    cmd->cmd_total_xfercount, cmd->cmd_xfercount,
672*7c478bd9Sstevel@tonic-gate 		    residue);
673*7c478bd9Sstevel@tonic-gate 
674*7c478bd9Sstevel@tonic-gate 		/*
675*7c478bd9Sstevel@tonic-gate 		 * we need to adjust using the residue and
676*7c478bd9Sstevel@tonic-gate 		 * assume worst case. Some devices lie about
677*7c478bd9Sstevel@tonic-gate 		 * residue. some report a residue greater than
678*7c478bd9Sstevel@tonic-gate 		 * the residue we have calculated.
679*7c478bd9Sstevel@tonic-gate 		 * first adjust back the total_xfercount
680*7c478bd9Sstevel@tonic-gate 		 */
681*7c478bd9Sstevel@tonic-gate 		cmd->cmd_total_xfercount += cmd->cmd_xfercount -
682*7c478bd9Sstevel@tonic-gate 				cmd->cmd_resid_xfercount;
683*7c478bd9Sstevel@tonic-gate 
684*7c478bd9Sstevel@tonic-gate 		/*
685*7c478bd9Sstevel@tonic-gate 		 * now take the min of the reported residue by
686*7c478bd9Sstevel@tonic-gate 		 * the device and the requested xfer count
687*7c478bd9Sstevel@tonic-gate 		 * (just in case the device reported a residue greater
688*7c478bd9Sstevel@tonic-gate 		 * than our request count).
689*7c478bd9Sstevel@tonic-gate 		 * then take the max of this residue and the residue
690*7c478bd9Sstevel@tonic-gate 		 * that the HCD reported and subtract this from
691*7c478bd9Sstevel@tonic-gate 		 * the request count. This is the actual number
692*7c478bd9Sstevel@tonic-gate 		 * of valid bytes transferred during the last transfer
693*7c478bd9Sstevel@tonic-gate 		 * which we now subtract from the total_xfercount
694*7c478bd9Sstevel@tonic-gate 		 */
695*7c478bd9Sstevel@tonic-gate 		if ((residue < 0) ||
696*7c478bd9Sstevel@tonic-gate 		    (residue > cmd->cmd_total_xfercount)) {
697*7c478bd9Sstevel@tonic-gate 			/* some device have a negative resid, ignore */
698*7c478bd9Sstevel@tonic-gate 			residue = cmd->cmd_resid_xfercount;
699*7c478bd9Sstevel@tonic-gate 		}
700*7c478bd9Sstevel@tonic-gate 		cmd->cmd_total_xfercount -=
701*7c478bd9Sstevel@tonic-gate 		    cmd->cmd_xfercount -
702*7c478bd9Sstevel@tonic-gate 		    max(min(residue, cmd->cmd_xfercount),
703*7c478bd9Sstevel@tonic-gate 		    cmd->cmd_resid_xfercount);
704*7c478bd9Sstevel@tonic-gate 
705*7c478bd9Sstevel@tonic-gate 		pkt->pkt_resid = cmd->cmd_total_xfercount;
706*7c478bd9Sstevel@tonic-gate 	}
707*7c478bd9Sstevel@tonic-gate 
708*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
709*7c478bd9Sstevel@tonic-gate 	    "scsa2usb_handle_csw_result: %s, resid: 0x%lx",
710*7c478bd9Sstevel@tonic-gate 	    msg, pkt->pkt_resid);
711*7c478bd9Sstevel@tonic-gate 
712*7c478bd9Sstevel@tonic-gate 	/* we are done and ready to callback */
713*7c478bd9Sstevel@tonic-gate 	SCSA2USB_SET_PKT_DO_COMP_STATE(scsa2usbp);
714*7c478bd9Sstevel@tonic-gate 
715*7c478bd9Sstevel@tonic-gate 	return (rval);
716*7c478bd9Sstevel@tonic-gate }
717*7c478bd9Sstevel@tonic-gate 
718*7c478bd9Sstevel@tonic-gate 
719*7c478bd9Sstevel@tonic-gate /*
720*7c478bd9Sstevel@tonic-gate  * scsa2usb_bulk_only_reset_recovery:
721*7c478bd9Sstevel@tonic-gate  *	Reset the USB device step-wise in case of errors.
722*7c478bd9Sstevel@tonic-gate  *	NOTE that the order of reset is very important.
723*7c478bd9Sstevel@tonic-gate  */
724*7c478bd9Sstevel@tonic-gate static void
725*7c478bd9Sstevel@tonic-gate scsa2usb_bulk_only_reset_recovery(scsa2usb_state_t *scsa2usbp)
726*7c478bd9Sstevel@tonic-gate {
727*7c478bd9Sstevel@tonic-gate 	int		rval;
728*7c478bd9Sstevel@tonic-gate 	usb_cr_t	completion_reason;
729*7c478bd9Sstevel@tonic-gate 	usb_cb_flags_t	cb_flags;
730*7c478bd9Sstevel@tonic-gate 
731*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
732*7c478bd9Sstevel@tonic-gate 	    "scsa2usb_bulk_only_reset_recovery: scsa2usbp = 0x%p", scsa2usbp);
733*7c478bd9Sstevel@tonic-gate 
734*7c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
735*7c478bd9Sstevel@tonic-gate 
736*7c478bd9Sstevel@tonic-gate 	if (!(SCSA2USB_DEVICE_ACCESS_OK(scsa2usbp))) {
737*7c478bd9Sstevel@tonic-gate 
738*7c478bd9Sstevel@tonic-gate 		return;
739*7c478bd9Sstevel@tonic-gate 	}
740*7c478bd9Sstevel@tonic-gate 
741*7c478bd9Sstevel@tonic-gate 	/*
742*7c478bd9Sstevel@tonic-gate 	 * assume that the reset will be successful. if it isn't, retrying
743*7c478bd9Sstevel@tonic-gate 	 * from target driver won't help much
744*7c478bd9Sstevel@tonic-gate 	 */
745*7c478bd9Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_cur_pkt) {
746*7c478bd9Sstevel@tonic-gate 		scsa2usbp->scsa2usb_cur_pkt->pkt_statistics |= STAT_DEV_RESET;
747*7c478bd9Sstevel@tonic-gate 	}
748*7c478bd9Sstevel@tonic-gate 
749*7c478bd9Sstevel@tonic-gate 	/* set the reset condition */
750*7c478bd9Sstevel@tonic-gate 	scsa2usbp->scsa2usb_pipe_state = SCSA2USB_PIPE_DEV_RESET;
751*7c478bd9Sstevel@tonic-gate 
752*7c478bd9Sstevel@tonic-gate 	/* Send a sync DEVICE-RESET request to the device */
753*7c478bd9Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
754*7c478bd9Sstevel@tonic-gate 	rval = usb_pipe_sync_ctrl_xfer(scsa2usbp->scsa2usb_dip,
755*7c478bd9Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_default_pipe,
756*7c478bd9Sstevel@tonic-gate 	    USB_DEV_REQ_TYPE_CLASS | USB_DEV_REQ_RCPT_IF,
757*7c478bd9Sstevel@tonic-gate 	    (uint8_t)BULK_ONLY_RESET,		/* bRequest */
758*7c478bd9Sstevel@tonic-gate 	    0,					/* wValue */
759*7c478bd9Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_intfc_num,	/* wIndex */
760*7c478bd9Sstevel@tonic-gate 	    0,					/* wLength */
761*7c478bd9Sstevel@tonic-gate 	    NULL, 0, &completion_reason, &cb_flags, 0);
762*7c478bd9Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
763*7c478bd9Sstevel@tonic-gate 
764*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
765*7c478bd9Sstevel@tonic-gate 	    "\tbulk-only device-reset rval: %d", rval);
766*7c478bd9Sstevel@tonic-gate 	if (rval != USB_SUCCESS) {
767*7c478bd9Sstevel@tonic-gate 		goto exc_exit;
768*7c478bd9Sstevel@tonic-gate 	}
769*7c478bd9Sstevel@tonic-gate 
770*7c478bd9Sstevel@tonic-gate 	/* reset and clear STALL on bulk-in pipe */
771*7c478bd9Sstevel@tonic-gate 	rval = scsa2usb_clear_ept_stall(scsa2usbp,
772*7c478bd9Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_bulkin_ept.bEndpointAddress,
773*7c478bd9Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_bulkin_pipe, "bulk-in");
774*7c478bd9Sstevel@tonic-gate 
775*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
776*7c478bd9Sstevel@tonic-gate 	    "\tbulk-in pipe clear stall: %d", rval);
777*7c478bd9Sstevel@tonic-gate 	if (rval != USB_SUCCESS) {
778*7c478bd9Sstevel@tonic-gate 		goto exc_exit;
779*7c478bd9Sstevel@tonic-gate 	}
780*7c478bd9Sstevel@tonic-gate 
781*7c478bd9Sstevel@tonic-gate 	/* reset and clear STALL on bulk-out pipe */
782*7c478bd9Sstevel@tonic-gate 	rval = scsa2usb_clear_ept_stall(scsa2usbp,
783*7c478bd9Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_bulkout_ept.bEndpointAddress,
784*7c478bd9Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_bulkout_pipe, "bulk-out");
785*7c478bd9Sstevel@tonic-gate 
786*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
787*7c478bd9Sstevel@tonic-gate 	    "\tbulk-out pipe clear stall: %d", rval);
788*7c478bd9Sstevel@tonic-gate 
789*7c478bd9Sstevel@tonic-gate exc_exit:
790*7c478bd9Sstevel@tonic-gate 	/* clear the reset condition */
791*7c478bd9Sstevel@tonic-gate 	scsa2usbp->scsa2usb_pipe_state &= ~SCSA2USB_PIPE_DEV_RESET;
792*7c478bd9Sstevel@tonic-gate }
793*7c478bd9Sstevel@tonic-gate 
794*7c478bd9Sstevel@tonic-gate 
795*7c478bd9Sstevel@tonic-gate /*
796*7c478bd9Sstevel@tonic-gate  * scsa2usb_bulk_only_get_max_lun:
797*7c478bd9Sstevel@tonic-gate  *	this function returns the number of LUNs supported by the device
798*7c478bd9Sstevel@tonic-gate  */
799*7c478bd9Sstevel@tonic-gate int
800*7c478bd9Sstevel@tonic-gate scsa2usb_bulk_only_get_max_lun(scsa2usb_state_t *scsa2usbp)
801*7c478bd9Sstevel@tonic-gate {
802*7c478bd9Sstevel@tonic-gate 	int		luns = 1, rval;
803*7c478bd9Sstevel@tonic-gate 	mblk_t		*data = NULL;
804*7c478bd9Sstevel@tonic-gate 	usb_cr_t	completion_reason;
805*7c478bd9Sstevel@tonic-gate 	usb_cb_flags_t	cb_flags;
806*7c478bd9Sstevel@tonic-gate 
807*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
808*7c478bd9Sstevel@tonic-gate 	    "scsa2usb_bulk_only_get_max_lun:");
809*7c478bd9Sstevel@tonic-gate 
810*7c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
811*7c478bd9Sstevel@tonic-gate 
812*7c478bd9Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
813*7c478bd9Sstevel@tonic-gate 	rval = usb_pipe_sync_ctrl_xfer(scsa2usbp->scsa2usb_dip,
814*7c478bd9Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_default_pipe,
815*7c478bd9Sstevel@tonic-gate 	    BULK_ONLY_GET_MAXLUN_BMREQ,		/* bmRequestType */
816*7c478bd9Sstevel@tonic-gate 	    BULK_ONLY_GET_MAXLUN_REQ,		/* bRequest */
817*7c478bd9Sstevel@tonic-gate 	    0,					/* wValue */
818*7c478bd9Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_intfc_num,	/* wIndex */
819*7c478bd9Sstevel@tonic-gate 	    1,					/* wLength */
820*7c478bd9Sstevel@tonic-gate 	    &data, 0,
821*7c478bd9Sstevel@tonic-gate 	    &completion_reason, &cb_flags, 0);
822*7c478bd9Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
823*7c478bd9Sstevel@tonic-gate 
824*7c478bd9Sstevel@tonic-gate 	if (rval != USB_SUCCESS) {
825*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
826*7c478bd9Sstevel@tonic-gate 		    "get max lun failed, rval=%d cr=%d cb=0x%x data=0x%p",
827*7c478bd9Sstevel@tonic-gate 		    rval, completion_reason, cb_flags, data);
828*7c478bd9Sstevel@tonic-gate 	} else {
829*7c478bd9Sstevel@tonic-gate 		/*
830*7c478bd9Sstevel@tonic-gate 		 * This check ensures that we have valid data returned back.
831*7c478bd9Sstevel@tonic-gate 		 * Otherwise we assume that device supports only one LUN.
832*7c478bd9Sstevel@tonic-gate 		 */
833*7c478bd9Sstevel@tonic-gate 		if ((data->b_wptr - data->b_rptr) != 1) {
834*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_SCSA,
835*7c478bd9Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
836*7c478bd9Sstevel@tonic-gate 			    "device reported incorrect luns (adjusting to 1)");
837*7c478bd9Sstevel@tonic-gate 		} else {
838*7c478bd9Sstevel@tonic-gate 			/*
839*7c478bd9Sstevel@tonic-gate 			 * Set scsa2usb_n_luns to value returned by the device
840*7c478bd9Sstevel@tonic-gate 			 * plus 1. (See Section 3.2)
841*7c478bd9Sstevel@tonic-gate 			 */
842*7c478bd9Sstevel@tonic-gate 			luns = *data->b_rptr + 1;
843*7c478bd9Sstevel@tonic-gate 
844*7c478bd9Sstevel@tonic-gate 			/*
845*7c478bd9Sstevel@tonic-gate 			 * In case a device returns incorrect LUNs
846*7c478bd9Sstevel@tonic-gate 			 * which are more than 15 or negative or 0;
847*7c478bd9Sstevel@tonic-gate 			 * we assume 1.
848*7c478bd9Sstevel@tonic-gate 			 */
849*7c478bd9Sstevel@tonic-gate 			if ((luns >= SCSA2USB_MAX_LUNS) || (luns <= 0)) {
850*7c478bd9Sstevel@tonic-gate 				USB_DPRINTF_L1(DPRINT_MASK_SCSA,
851*7c478bd9Sstevel@tonic-gate 				    scsa2usbp->scsa2usb_log_handle,
852*7c478bd9Sstevel@tonic-gate 				    "device reported %d luns "
853*7c478bd9Sstevel@tonic-gate 				    "(adjusting to 1)", luns);
854*7c478bd9Sstevel@tonic-gate 				luns = 1;
855*7c478bd9Sstevel@tonic-gate 			}
856*7c478bd9Sstevel@tonic-gate 		}
857*7c478bd9Sstevel@tonic-gate 	}
858*7c478bd9Sstevel@tonic-gate 
859*7c478bd9Sstevel@tonic-gate 	SCSA2USB_FREE_MSG(data);	/* Free data */
860*7c478bd9Sstevel@tonic-gate 
861*7c478bd9Sstevel@tonic-gate 	return (luns);
862*7c478bd9Sstevel@tonic-gate }
863