xref: /onnv-gate/usr/src/uts/common/io/usb/scsa2usb/scsa2usb.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate  * scsa2usb bridge nexus driver:
31*0Sstevel@tonic-gate  *
32*0Sstevel@tonic-gate  * This driver supports the following wire transports:
33*0Sstevel@tonic-gate  * a. Bulk Only transport (see usb_ms_bulkonly.c)
34*0Sstevel@tonic-gate  * b. CB transport (see usb_ms_cbi.c)
35*0Sstevel@tonic-gate  * c. CBI transport with interrupt status completion (see usb_ms_cbi.c)
36*0Sstevel@tonic-gate  *
37*0Sstevel@tonic-gate  * It handles the following command sets:
38*0Sstevel@tonic-gate  * a. SCSI
39*0Sstevel@tonic-gate  * b. ATAPI command set (subset of SCSI command set)
40*0Sstevel@tonic-gate  * c. UFI command set (
41*0Sstevel@tonic-gate  *	http://www.usb.org/developers/devclass_docs/usbmass-ufi10.pdf)
42*0Sstevel@tonic-gate  *
43*0Sstevel@tonic-gate  * For details on USB Mass Storage Class overview:
44*0Sstevel@tonic-gate  *	http://www.usb.org/developers/devclass_docs/usbmassover_11.pdf
45*0Sstevel@tonic-gate  */
46*0Sstevel@tonic-gate #if defined(lint) && !defined(DEBUG)
47*0Sstevel@tonic-gate #define	DEBUG	1
48*0Sstevel@tonic-gate #endif
49*0Sstevel@tonic-gate 
50*0Sstevel@tonic-gate #include <sys/usb/usba/usbai_version.h>
51*0Sstevel@tonic-gate #include <sys/scsi/scsi.h>
52*0Sstevel@tonic-gate #include <sys/cdio.h>
53*0Sstevel@tonic-gate #include <sys/sunndi.h>
54*0Sstevel@tonic-gate #include <sys/esunddi.h>
55*0Sstevel@tonic-gate #include <sys/callb.h>
56*0Sstevel@tonic-gate #include <sys/kobj.h>
57*0Sstevel@tonic-gate #include <sys/kobj_lex.h>
58*0Sstevel@tonic-gate #include <sys/strsubr.h>
59*0Sstevel@tonic-gate #include <sys/sysmacros.h>
60*0Sstevel@tonic-gate 
61*0Sstevel@tonic-gate #include <sys/usb/usba.h>
62*0Sstevel@tonic-gate #include <sys/usb/usba/usba_ugen.h>
63*0Sstevel@tonic-gate 
64*0Sstevel@tonic-gate #include <sys/usb/usba/usba_private.h>
65*0Sstevel@tonic-gate #include <sys/usb/clients/mass_storage/usb_bulkonly.h>
66*0Sstevel@tonic-gate #include <sys/usb/scsa2usb/scsa2usb.h>
67*0Sstevel@tonic-gate 
68*0Sstevel@tonic-gate /*
69*0Sstevel@tonic-gate  * Function Prototypes
70*0Sstevel@tonic-gate  */
71*0Sstevel@tonic-gate static int	scsa2usb_attach(dev_info_t *, ddi_attach_cmd_t);
72*0Sstevel@tonic-gate static int	scsa2usb_info(dev_info_t *, ddi_info_cmd_t, void *,
73*0Sstevel@tonic-gate 						void **);
74*0Sstevel@tonic-gate static int	scsa2usb_detach(dev_info_t *, ddi_detach_cmd_t);
75*0Sstevel@tonic-gate static int	scsa2usb_cleanup(dev_info_t *, scsa2usb_state_t *);
76*0Sstevel@tonic-gate static void	scsa2usb_validate_attrs(scsa2usb_state_t *);
77*0Sstevel@tonic-gate static void	scsa2usb_create_luns(scsa2usb_state_t *);
78*0Sstevel@tonic-gate static int	scsa2usb_is_usb(dev_info_t *);
79*0Sstevel@tonic-gate static int	scsa2usb_fake_inquiry(scsa2usb_state_t *,
80*0Sstevel@tonic-gate 					scsa2usb_cmd_t *, uint_t);
81*0Sstevel@tonic-gate static void	scsa2usb_do_inquiry(scsa2usb_state_t *,
82*0Sstevel@tonic-gate 						uint_t, uint_t);
83*0Sstevel@tonic-gate 
84*0Sstevel@tonic-gate /* override property handling */
85*0Sstevel@tonic-gate static void	scsa2usb_override(scsa2usb_state_t *);
86*0Sstevel@tonic-gate static int	scsa2usb_parse_input_str(char *, scsa2usb_ov_t *,
87*0Sstevel@tonic-gate 		    scsa2usb_state_t *);
88*0Sstevel@tonic-gate static void	scsa2usb_override_error(char *, scsa2usb_state_t *);
89*0Sstevel@tonic-gate static char	*scsa2usb_strtok_r(char *, char *, char **);
90*0Sstevel@tonic-gate 
91*0Sstevel@tonic-gate 
92*0Sstevel@tonic-gate /* PANIC callback handling */
93*0Sstevel@tonic-gate static void	scsa2usb_panic_callb_init(scsa2usb_state_t *);
94*0Sstevel@tonic-gate static void	scsa2usb_panic_callb_fini(scsa2usb_state_t *);
95*0Sstevel@tonic-gate static boolean_t scsa2usb_panic_callb(void *, int);
96*0Sstevel@tonic-gate 
97*0Sstevel@tonic-gate /* SCSA support */
98*0Sstevel@tonic-gate static int	scsa2usb_scsi_tgt_probe(struct scsi_device *, int (*)(void));
99*0Sstevel@tonic-gate static int	scsa2usb_scsi_tgt_init(dev_info_t *, dev_info_t *,
100*0Sstevel@tonic-gate 		    scsi_hba_tran_t *, struct scsi_device *);
101*0Sstevel@tonic-gate static void	scsa2usb_scsi_tgt_free(dev_info_t *, dev_info_t *,
102*0Sstevel@tonic-gate 		    scsi_hba_tran_t *, struct scsi_device *);
103*0Sstevel@tonic-gate static struct	scsi_pkt *scsa2usb_scsi_init_pkt(struct scsi_address *,
104*0Sstevel@tonic-gate 		    struct scsi_pkt *, struct buf *, int, int,
105*0Sstevel@tonic-gate 		    int, int, int (*)(), caddr_t);
106*0Sstevel@tonic-gate static void	scsa2usb_scsi_destroy_pkt(struct scsi_address *,
107*0Sstevel@tonic-gate 		    struct scsi_pkt *);
108*0Sstevel@tonic-gate static int	scsa2usb_scsi_start(struct scsi_address *, struct scsi_pkt *);
109*0Sstevel@tonic-gate static int	scsa2usb_scsi_abort(struct scsi_address *, struct scsi_pkt *);
110*0Sstevel@tonic-gate static int	scsa2usb_scsi_reset(struct scsi_address *, int);
111*0Sstevel@tonic-gate static int	scsa2usb_scsi_getcap(struct scsi_address *, char *, int);
112*0Sstevel@tonic-gate static int	scsa2usb_scsi_setcap(struct scsi_address *, char *, int, int);
113*0Sstevel@tonic-gate static int	scsa2usb_scsi_bus_config(dev_info_t *, uint_t,
114*0Sstevel@tonic-gate 		    ddi_bus_config_op_t, void *, dev_info_t **);
115*0Sstevel@tonic-gate static int	scsa2usb_scsi_bus_unconfig(dev_info_t *, uint_t,
116*0Sstevel@tonic-gate 		    ddi_bus_config_op_t, void *);
117*0Sstevel@tonic-gate 
118*0Sstevel@tonic-gate /* functions for command and transport support */
119*0Sstevel@tonic-gate static void	scsa2usb_prepare_pkt(scsa2usb_state_t *, struct scsi_pkt *);
120*0Sstevel@tonic-gate static int	scsa2usb_cmd_transport(scsa2usb_state_t *, scsa2usb_cmd_t *);
121*0Sstevel@tonic-gate static int	scsa2usb_check_bulkonly_blacklist_attrs(scsa2usb_state_t *,
122*0Sstevel@tonic-gate 		    scsa2usb_cmd_t *, uchar_t);
123*0Sstevel@tonic-gate static int	scsa2usb_check_ufi_blacklist_attrs(scsa2usb_state_t *, uchar_t,
124*0Sstevel@tonic-gate 		    scsa2usb_cmd_t *);
125*0Sstevel@tonic-gate static int	scsa2usb_handle_scsi_cmd_sub_class(scsa2usb_state_t *,
126*0Sstevel@tonic-gate 		    scsa2usb_cmd_t *, struct scsi_pkt *);
127*0Sstevel@tonic-gate static int	scsa2usb_handle_ufi_subclass_cmd(scsa2usb_state_t *,
128*0Sstevel@tonic-gate 		    scsa2usb_cmd_t *, struct scsi_pkt *);
129*0Sstevel@tonic-gate 
130*0Sstevel@tonic-gate /* waitQ handling */
131*0Sstevel@tonic-gate static void	scsa2usb_work_thread(void *);
132*0Sstevel@tonic-gate static void	scsa2usb_transport_request(scsa2usb_state_t *, uint_t);
133*0Sstevel@tonic-gate static void	scsa2usb_flush_waitQ(scsa2usb_state_t *, uint_t, uchar_t);
134*0Sstevel@tonic-gate static int	scsa2usb_all_waitQs_empty(scsa2usb_state_t *);
135*0Sstevel@tonic-gate 
136*0Sstevel@tonic-gate /* auto request sense handling */
137*0Sstevel@tonic-gate static int	scsa2usb_create_arq_pkt(scsa2usb_state_t *,
138*0Sstevel@tonic-gate 		    struct scsi_address *);
139*0Sstevel@tonic-gate static void	scsa2usb_delete_arq_pkt(scsa2usb_state_t *);
140*0Sstevel@tonic-gate static void	scsa2usb_complete_arq_pkt(scsa2usb_state_t *, struct scsi_pkt *,
141*0Sstevel@tonic-gate 		    scsa2usb_cmd_t *, struct buf *);
142*0Sstevel@tonic-gate 
143*0Sstevel@tonic-gate /* utility functions for any transport */
144*0Sstevel@tonic-gate static int	scsa2usb_open_usb_pipes(scsa2usb_state_t *);
145*0Sstevel@tonic-gate void		scsa2usb_close_usb_pipes(scsa2usb_state_t *);
146*0Sstevel@tonic-gate 
147*0Sstevel@tonic-gate static void	scsa2usb_fill_up_cdb_len(scsa2usb_cmd_t *, int);
148*0Sstevel@tonic-gate static void	scsa2usb_fill_up_cdb_lba(scsa2usb_cmd_t *, int);
149*0Sstevel@tonic-gate static void	scsa2usb_fill_up_ReadCD_cdb_len(scsa2usb_cmd_t *, int, int);
150*0Sstevel@tonic-gate static void	scsa2usb_fill_up_12byte_cdb_len(scsa2usb_cmd_t *, int, int);
151*0Sstevel@tonic-gate static int	scsa2usb_read_cd_blk_size(uchar_t);
152*0Sstevel@tonic-gate int		scsa2usb_rw_transport(scsa2usb_state_t *, struct scsi_pkt *);
153*0Sstevel@tonic-gate void		scsa2usb_setup_next_xfer(scsa2usb_state_t *, scsa2usb_cmd_t *);
154*0Sstevel@tonic-gate 
155*0Sstevel@tonic-gate static mblk_t	*scsa2usb_bp_to_mblk(scsa2usb_state_t *);
156*0Sstevel@tonic-gate int		scsa2usb_handle_data_start(scsa2usb_state_t *,
157*0Sstevel@tonic-gate 		    scsa2usb_cmd_t *, usb_bulk_req_t *);
158*0Sstevel@tonic-gate void		scsa2usb_handle_data_done(scsa2usb_state_t *,
159*0Sstevel@tonic-gate 		    scsa2usb_cmd_t *cmd, usb_bulk_req_t *);
160*0Sstevel@tonic-gate 
161*0Sstevel@tonic-gate usb_bulk_req_t *scsa2usb_init_bulk_req(scsa2usb_state_t *,
162*0Sstevel@tonic-gate 			    size_t, uint_t, usb_req_attrs_t, usb_flags_t);
163*0Sstevel@tonic-gate int		scsa2usb_bulk_timeout(int);
164*0Sstevel@tonic-gate int		scsa2usb_clear_ept_stall(scsa2usb_state_t *, uint_t,
165*0Sstevel@tonic-gate 		    usb_pipe_handle_t, char *);
166*0Sstevel@tonic-gate static void	scsa2usb_pkt_completion(scsa2usb_state_t *, struct scsi_pkt *);
167*0Sstevel@tonic-gate 
168*0Sstevel@tonic-gate /* event handling */
169*0Sstevel@tonic-gate static int	scsa2usb_reconnect_event_cb(dev_info_t *);
170*0Sstevel@tonic-gate static int	scsa2usb_disconnect_event_cb(dev_info_t *);
171*0Sstevel@tonic-gate static int	scsa2usb_cpr_suspend(dev_info_t *);
172*0Sstevel@tonic-gate static void	scsa2usb_cpr_resume(dev_info_t *);
173*0Sstevel@tonic-gate static void	scsa2usb_restore_device_state(dev_info_t *, scsa2usb_state_t *);
174*0Sstevel@tonic-gate 
175*0Sstevel@tonic-gate /* PM handling */
176*0Sstevel@tonic-gate static void	scsa2usb_create_pm_components(dev_info_t *, scsa2usb_state_t *);
177*0Sstevel@tonic-gate static void	scsa2usb_raise_power(scsa2usb_state_t *);
178*0Sstevel@tonic-gate static int	scsa2usb_pwrlvl0(scsa2usb_state_t *);
179*0Sstevel@tonic-gate static int	scsa2usb_pwrlvl1(scsa2usb_state_t *);
180*0Sstevel@tonic-gate static int	scsa2usb_pwrlvl2(scsa2usb_state_t *);
181*0Sstevel@tonic-gate static int	scsa2usb_pwrlvl3(scsa2usb_state_t *);
182*0Sstevel@tonic-gate static int	scsa2usb_power(dev_info_t *, int comp, int level);
183*0Sstevel@tonic-gate static void	scsa2usb_pm_busy_component(scsa2usb_state_t *);
184*0Sstevel@tonic-gate static void	scsa2usb_pm_idle_component(scsa2usb_state_t *);
185*0Sstevel@tonic-gate 
186*0Sstevel@tonic-gate /* external functions for Bulk only (BO) support */
187*0Sstevel@tonic-gate extern int	scsa2usb_bulk_only_transport(scsa2usb_state_t *,
188*0Sstevel@tonic-gate 		    scsa2usb_cmd_t *);
189*0Sstevel@tonic-gate extern int	scsa2usb_bulk_only_get_max_lun(scsa2usb_state_t *);
190*0Sstevel@tonic-gate 
191*0Sstevel@tonic-gate /* external functions for CB/CBI support */
192*0Sstevel@tonic-gate extern int	scsa2usb_cbi_transport(scsa2usb_state_t *, scsa2usb_cmd_t *);
193*0Sstevel@tonic-gate extern void	scsa2usb_cbi_stop_intr_polling(scsa2usb_state_t *);
194*0Sstevel@tonic-gate 
195*0Sstevel@tonic-gate 
196*0Sstevel@tonic-gate /* cmd decoding */
197*0Sstevel@tonic-gate static char *scsa2usb_cmds[] = {
198*0Sstevel@tonic-gate 	"\000tur",
199*0Sstevel@tonic-gate 	"\001rezero",
200*0Sstevel@tonic-gate 	"\003rqsense",
201*0Sstevel@tonic-gate 	"\004format",
202*0Sstevel@tonic-gate 	"\014cartprot",
203*0Sstevel@tonic-gate 	"\022inquiry",
204*0Sstevel@tonic-gate 	"\026tranlba",
205*0Sstevel@tonic-gate 	"\030fmtverify",
206*0Sstevel@tonic-gate 	"\032modesense",
207*0Sstevel@tonic-gate 	"\033start",
208*0Sstevel@tonic-gate 	"\035snddiag",
209*0Sstevel@tonic-gate 	"\036doorlock",
210*0Sstevel@tonic-gate 	"\043formatcap",
211*0Sstevel@tonic-gate 	"\045readcap",
212*0Sstevel@tonic-gate 	"\050read10",
213*0Sstevel@tonic-gate 	"\052write10",
214*0Sstevel@tonic-gate 	"\053seek10",
215*0Sstevel@tonic-gate 	"\056writeverify",
216*0Sstevel@tonic-gate 	"\057verify",
217*0Sstevel@tonic-gate 	"\065synchcache",
218*0Sstevel@tonic-gate 	"\076readlong",
219*0Sstevel@tonic-gate 	"\077writelong",
220*0Sstevel@tonic-gate 	"\102readsubchan",
221*0Sstevel@tonic-gate 	"\103readtoc",
222*0Sstevel@tonic-gate 	"\104readhdr",
223*0Sstevel@tonic-gate 	"\105playaudio10",
224*0Sstevel@tonic-gate 	"\107playaudio_msf",
225*0Sstevel@tonic-gate 	"\110playaudio_ti",
226*0Sstevel@tonic-gate 	"\111playtrk_r10",
227*0Sstevel@tonic-gate 	"\112geteventnotify",
228*0Sstevel@tonic-gate 	"\113pause_resume",
229*0Sstevel@tonic-gate 	"\116stop/play_scan",
230*0Sstevel@tonic-gate 	"\121readdiscinfo",
231*0Sstevel@tonic-gate 	"\122readtrkinfo",
232*0Sstevel@tonic-gate 	"\123reservedtrk",
233*0Sstevel@tonic-gate 	"\124sendopcinfo",
234*0Sstevel@tonic-gate 	"\125modeselect",
235*0Sstevel@tonic-gate 	"\132modesense",
236*0Sstevel@tonic-gate 	"\133closetrksession",
237*0Sstevel@tonic-gate 	"\135sendcuesheet",
238*0Sstevel@tonic-gate 	"\136prin",
239*0Sstevel@tonic-gate 	"\137prout",
240*0Sstevel@tonic-gate 	"\241blankcd",
241*0Sstevel@tonic-gate 	"\245playaudio12",
242*0Sstevel@tonic-gate 	"\250read12",
243*0Sstevel@tonic-gate 	"\251playtrk12",
244*0Sstevel@tonic-gate 	"\252write12",
245*0Sstevel@tonic-gate 	"\254getperf",
246*0Sstevel@tonic-gate 	"\271readcdmsf",
247*0Sstevel@tonic-gate 	"\273setcdspeed",
248*0Sstevel@tonic-gate 	"\275mechanism_sts",
249*0Sstevel@tonic-gate 	"\276readcd",
250*0Sstevel@tonic-gate 	NULL
251*0Sstevel@tonic-gate };
252*0Sstevel@tonic-gate 
253*0Sstevel@tonic-gate 
254*0Sstevel@tonic-gate /*
255*0Sstevel@tonic-gate  * Mass-Storage devices masquerade as "sd" disks.
256*0Sstevel@tonic-gate  *
257*0Sstevel@tonic-gate  * These devices may not support all SCSI CDBs in their
258*0Sstevel@tonic-gate  * entirety due to their hardware implementation limitations.
259*0Sstevel@tonic-gate  *
260*0Sstevel@tonic-gate  * As such, following is a list of some of the black-listed
261*0Sstevel@tonic-gate  * devices w/ the attributes that they do not support.
262*0Sstevel@tonic-gate  * (See scsa2usb.h for description on each attribute)
263*0Sstevel@tonic-gate  */
264*0Sstevel@tonic-gate #define	X	((uint16_t)(-1))
265*0Sstevel@tonic-gate 
266*0Sstevel@tonic-gate static struct blacklist {
267*0Sstevel@tonic-gate 	uint16_t	idVendor;	/* vendor ID			*/
268*0Sstevel@tonic-gate 	uint16_t	idProduct;	/* product ID			*/
269*0Sstevel@tonic-gate 	uint16_t	bcdDevice;	/* device release number in bcd */
270*0Sstevel@tonic-gate 	uint16_t	attributes;	/* attributes to blacklist	*/
271*0Sstevel@tonic-gate } scsa2usb_blacklist[] = {
272*0Sstevel@tonic-gate 	/* Iomega Zip100 drive (prototype) with flaky bridge */
273*0Sstevel@tonic-gate 	{MS_IOMEGA_VID, MS_IOMEGA_PID1_ZIP100, 0,
274*0Sstevel@tonic-gate 	    SCSA2USB_ATTRS_GET_LUN | SCSA2USB_ATTRS_PM},
275*0Sstevel@tonic-gate 
276*0Sstevel@tonic-gate 	/* Iomega Zip100 drive (newer model) with flaky bridge */
277*0Sstevel@tonic-gate 	{MS_IOMEGA_VID, MS_IOMEGA_PID2_ZIP100, 0,
278*0Sstevel@tonic-gate 	    SCSA2USB_ATTRS_GET_LUN | SCSA2USB_ATTRS_PM},
279*0Sstevel@tonic-gate 
280*0Sstevel@tonic-gate 	/* Iomega Zip100 drive (newer model) with flaky bridge */
281*0Sstevel@tonic-gate 	{MS_IOMEGA_VID, MS_IOMEGA_PID3_ZIP100, 0,
282*0Sstevel@tonic-gate 	    SCSA2USB_ATTRS_GET_LUN | SCSA2USB_ATTRS_PM},
283*0Sstevel@tonic-gate 
284*0Sstevel@tonic-gate 	/* Iomega Zip250 drive */
285*0Sstevel@tonic-gate 	{MS_IOMEGA_VID, MS_IOMEGA_PID_ZIP250, 0, SCSA2USB_ATTRS_GET_LUN},
286*0Sstevel@tonic-gate 
287*0Sstevel@tonic-gate 	/* Iomega Clik! drive */
288*0Sstevel@tonic-gate 	{MS_IOMEGA_VID, MS_IOMEGA_PID_CLIK, 0,
289*0Sstevel@tonic-gate 	    SCSA2USB_ATTRS_GET_LUN | SCSA2USB_ATTRS_START_STOP},
290*0Sstevel@tonic-gate 
291*0Sstevel@tonic-gate 	/* SMSC floppy Device - and its clones */
292*0Sstevel@tonic-gate 	{MS_SMSC_VID, X, 0, SCSA2USB_ATTRS_START_STOP},
293*0Sstevel@tonic-gate 
294*0Sstevel@tonic-gate 	/* Hagiwara SmartMedia Device */
295*0Sstevel@tonic-gate 	{MS_HAGIWARA_SYS_COM_VID, MS_HAGIWARA_SYSCOM_PID1, 0,
296*0Sstevel@tonic-gate 	    SCSA2USB_ATTRS_GET_LUN | SCSA2USB_ATTRS_START_STOP},
297*0Sstevel@tonic-gate 
298*0Sstevel@tonic-gate 	/* Hagiwara CompactFlash Device */
299*0Sstevel@tonic-gate 	{MS_HAGIWARA_SYS_COM_VID, MS_HAGIWARA_SYSCOM_PID2, 0,
300*0Sstevel@tonic-gate 	    SCSA2USB_ATTRS_GET_LUN | SCSA2USB_ATTRS_START_STOP},
301*0Sstevel@tonic-gate 
302*0Sstevel@tonic-gate 	/* Hagiwara SmartMedia/CompactFlash Combo Device */
303*0Sstevel@tonic-gate 	{MS_HAGIWARA_SYS_COM_VID, MS_HAGIWARA_SYSCOM_PID3, 0,
304*0Sstevel@tonic-gate 	    SCSA2USB_ATTRS_START_STOP},
305*0Sstevel@tonic-gate 
306*0Sstevel@tonic-gate 	/* Hagiwara new SM Device */
307*0Sstevel@tonic-gate 	{MS_HAGIWARA_SYS_COM_VID, MS_HAGIWARA_SYSCOM_PID4, 0,
308*0Sstevel@tonic-gate 	    SCSA2USB_ATTRS_GET_LUN | SCSA2USB_ATTRS_START_STOP},
309*0Sstevel@tonic-gate 
310*0Sstevel@tonic-gate 	/* Hagiwara new CF Device */
311*0Sstevel@tonic-gate 	{MS_HAGIWARA_SYS_COM_VID, MS_HAGIWARA_SYSCOM_PID5, 0,
312*0Sstevel@tonic-gate 	    SCSA2USB_ATTRS_GET_LUN | SCSA2USB_ATTRS_START_STOP},
313*0Sstevel@tonic-gate 
314*0Sstevel@tonic-gate 	/* Mitsumi CD-RW Device(s) */
315*0Sstevel@tonic-gate 	{MS_MITSUMI_VID, X, X, SCSA2USB_ATTRS_BIG_TIMEOUT |
316*0Sstevel@tonic-gate 	    SCSA2USB_ATTRS_GET_CONF | SCSA2USB_ATTRS_GET_PERF},
317*0Sstevel@tonic-gate 
318*0Sstevel@tonic-gate 	/* Neodio Technologies Corporation SM/CF/MS/SD Combo Device */
319*0Sstevel@tonic-gate 	{MS_NEODIO_VID, MS_NEODIO_DEVICE_3050, 0,
320*0Sstevel@tonic-gate 	    SCSA2USB_ATTRS_MODE_SENSE },
321*0Sstevel@tonic-gate 
322*0Sstevel@tonic-gate 	/* dumb flash devices */
323*0Sstevel@tonic-gate 	{MS_SONY_FLASH_VID, MS_SONY_FLASH_PID, 0,
324*0Sstevel@tonic-gate 	    SCSA2USB_ATTRS_REDUCED_CMD},
325*0Sstevel@tonic-gate 
326*0Sstevel@tonic-gate 	{MS_TREK_FLASH_VID, MS_TREK_FLASH_PID, 0,
327*0Sstevel@tonic-gate 	    SCSA2USB_ATTRS_REDUCED_CMD},
328*0Sstevel@tonic-gate 
329*0Sstevel@tonic-gate 	{MS_PENN_FLASH_VID, MS_PENN_FLASH_PID, 0,
330*0Sstevel@tonic-gate 	    SCSA2USB_ATTRS_REDUCED_CMD},
331*0Sstevel@tonic-gate 
332*0Sstevel@tonic-gate 	/* SimpleTech UCF-100 CF Device */
333*0Sstevel@tonic-gate 	{MS_SIMPLETECH_VID, MS_SIMPLETECH_PID1, 0,
334*0Sstevel@tonic-gate 	    SCSA2USB_ATTRS_REDUCED_CMD},
335*0Sstevel@tonic-gate 
336*0Sstevel@tonic-gate 	{MS_ADDONICS_CARD_READER_VID, MS_ADDONICS_CARD_READER_PID,
337*0Sstevel@tonic-gate 	    0, SCSA2USB_ATTRS_REDUCED_CMD},
338*0Sstevel@tonic-gate };
339*0Sstevel@tonic-gate 
340*0Sstevel@tonic-gate 
341*0Sstevel@tonic-gate #define	N_SCSA2USB_BLACKLIST (sizeof (scsa2usb_blacklist))/ \
342*0Sstevel@tonic-gate 				sizeof (struct blacklist)
343*0Sstevel@tonic-gate 
344*0Sstevel@tonic-gate /*
345*0Sstevel@tonic-gate  * Attribute values can be overridden by values
346*0Sstevel@tonic-gate  * contained in the scsa2usb.conf file.
347*0Sstevel@tonic-gate  * These arrays define possible user input values.
348*0Sstevel@tonic-gate  */
349*0Sstevel@tonic-gate 
350*0Sstevel@tonic-gate struct scsa2usb_subclass_protocol_override {
351*0Sstevel@tonic-gate 	char	*name;
352*0Sstevel@tonic-gate 	int	value;
353*0Sstevel@tonic-gate };
354*0Sstevel@tonic-gate 
355*0Sstevel@tonic-gate static struct scsa2usb_subclass_protocol_override scsa2usb_protocol[] =  {
356*0Sstevel@tonic-gate 	{"CB", SCSA2USB_CB_PROTOCOL},
357*0Sstevel@tonic-gate 	{"CBI", SCSA2USB_CBI_PROTOCOL},
358*0Sstevel@tonic-gate 	{"BO", SCSA2USB_BULK_ONLY_PROTOCOL}
359*0Sstevel@tonic-gate };
360*0Sstevel@tonic-gate 
361*0Sstevel@tonic-gate static struct scsa2usb_subclass_protocol_override scsa2usb_subclass[] = {
362*0Sstevel@tonic-gate 	{"SCSI", SCSA2USB_SCSI_CMDSET},
363*0Sstevel@tonic-gate 	{"ATAPI", SCSA2USB_ATAPI_CMDSET},
364*0Sstevel@tonic-gate 	{"UFI", SCSA2USB_UFI_CMDSET}
365*0Sstevel@tonic-gate };
366*0Sstevel@tonic-gate 
367*0Sstevel@tonic-gate 
368*0Sstevel@tonic-gate #define	N_SCSA2USB_SUBC_OVERRIDE (sizeof (scsa2usb_subclass))/ \
369*0Sstevel@tonic-gate 			sizeof (struct scsa2usb_subclass_protocol_override)
370*0Sstevel@tonic-gate 
371*0Sstevel@tonic-gate #define	N_SCSA2USB_PROT_OVERRIDE (sizeof (scsa2usb_protocol))/ \
372*0Sstevel@tonic-gate 			sizeof (struct scsa2usb_subclass_protocol_override)
373*0Sstevel@tonic-gate 
374*0Sstevel@tonic-gate /* global variables */
375*0Sstevel@tonic-gate static void *scsa2usb_statep;				/* for soft state */
376*0Sstevel@tonic-gate static boolean_t scsa2usb_sync_message = B_TRUE;	/* for syncing */
377*0Sstevel@tonic-gate 
378*0Sstevel@tonic-gate /* for debug messages */
379*0Sstevel@tonic-gate static uint_t	scsa2usb_errmask	= (uint_t)DPRINT_MASK_ALL;
380*0Sstevel@tonic-gate static uint_t	scsa2usb_errlevel	= USB_LOG_L4;
381*0Sstevel@tonic-gate static uint_t	scsa2usb_instance_debug = (uint_t)-1;
382*0Sstevel@tonic-gate static uint_t	scsa2usb_scsi_bus_config_debug = 0;
383*0Sstevel@tonic-gate static uint_t	scsa2usb_long_timeout	= 50 * SCSA2USB_BULK_PIPE_TIMEOUT;
384*0Sstevel@tonic-gate 
385*0Sstevel@tonic-gate 
386*0Sstevel@tonic-gate /*
387*0Sstevel@tonic-gate  * Some devices have problems with big bulk transfers,
388*0Sstevel@tonic-gate  * transfers >= 128kbytes hang the device.  This tunable allows to
389*0Sstevel@tonic-gate  * limit the maximum bulk transfers rate.
390*0Sstevel@tonic-gate  */
391*0Sstevel@tonic-gate static uint_t	scsa2usb_max_bulk_xfer_size = SCSA2USB_MAX_BULK_XFER_SIZE;
392*0Sstevel@tonic-gate 
393*0Sstevel@tonic-gate 
394*0Sstevel@tonic-gate #ifdef	SCSA2USB_BULK_ONLY_TEST
395*0Sstevel@tonic-gate /*
396*0Sstevel@tonic-gate  * Test BO 13 cases. (See USB Mass Storage Class - Bulk Only Transport).
397*0Sstevel@tonic-gate  * We are not covering test cases 1, 6, and 12 as these are the "good"
398*0Sstevel@tonic-gate  * test cases and are tested as part of the normal drive access operations.
399*0Sstevel@tonic-gate  *
400*0Sstevel@tonic-gate  * NOTE: This is for testing only. It will be replaced by a uscsi test.
401*0Sstevel@tonic-gate  * Some are listed here while; other test cases are moved to usb_bulkonly.c
402*0Sstevel@tonic-gate  */
403*0Sstevel@tonic-gate static int scsa2usb_test_case_5 = 0;
404*0Sstevel@tonic-gate int scsa2usb_test_case_8 = 0;
405*0Sstevel@tonic-gate int scsa2usb_test_case_10 = 0;
406*0Sstevel@tonic-gate static int scsa2usb_test_case_11 = 0;
407*0Sstevel@tonic-gate 
408*0Sstevel@tonic-gate static void	scsa2usb_test_mblk(scsa2usb_state_t *, boolean_t);
409*0Sstevel@tonic-gate #endif	/* SCSA2USB_BULK_ONLY_TEST */
410*0Sstevel@tonic-gate 
411*0Sstevel@tonic-gate static int	scsa2usb_ugen_open(dev_t *, int, int, cred_t *);
412*0Sstevel@tonic-gate static int	scsa2usb_ugen_close(dev_t, int, int, cred_t *);
413*0Sstevel@tonic-gate static int	scsa2usb_ugen_strategy(struct buf *);
414*0Sstevel@tonic-gate static int	scsa2usb_ugen_read(dev_t, struct uio *, cred_t *);
415*0Sstevel@tonic-gate static int	scsa2usb_ugen_write(dev_t, struct uio *, cred_t *);
416*0Sstevel@tonic-gate static int	scsa2usb_ugen_poll(dev_t, short, int,  short *,
417*0Sstevel@tonic-gate 						struct pollhead **);
418*0Sstevel@tonic-gate 
419*0Sstevel@tonic-gate /* scsa2usb cb_ops */
420*0Sstevel@tonic-gate static struct cb_ops scsa2usb_cbops = {
421*0Sstevel@tonic-gate 	scsa2usb_ugen_open,	/* open  */
422*0Sstevel@tonic-gate 	scsa2usb_ugen_close,	/* close */
423*0Sstevel@tonic-gate 	nodev,			/* strategy */
424*0Sstevel@tonic-gate 	nodev,			/* print */
425*0Sstevel@tonic-gate 	nodev,			/* dump */
426*0Sstevel@tonic-gate 	scsa2usb_ugen_read,	/* read */
427*0Sstevel@tonic-gate 	scsa2usb_ugen_write,	/* write */
428*0Sstevel@tonic-gate 	NULL,			/* ioctl */
429*0Sstevel@tonic-gate 	nodev,			/* devmap */
430*0Sstevel@tonic-gate 	nodev,			/* mmap */
431*0Sstevel@tonic-gate 	nodev,			/* segmap */
432*0Sstevel@tonic-gate 	scsa2usb_ugen_poll,	/* poll */
433*0Sstevel@tonic-gate 	ddi_prop_op,		/* prop_op */
434*0Sstevel@tonic-gate 	NULL,			/* stream */
435*0Sstevel@tonic-gate 	D_MP,			/* cb_flag */
436*0Sstevel@tonic-gate 	CB_REV, 		/* rev */
437*0Sstevel@tonic-gate 	nodev,			/* int (*cb_aread)() */
438*0Sstevel@tonic-gate 	nodev			/* int (*cb_awrite)() */
439*0Sstevel@tonic-gate };
440*0Sstevel@tonic-gate 
441*0Sstevel@tonic-gate /* modloading support */
442*0Sstevel@tonic-gate static struct dev_ops scsa2usb_ops = {
443*0Sstevel@tonic-gate 	DEVO_REV,		/* devo_rev, */
444*0Sstevel@tonic-gate 	0,			/* refcnt  */
445*0Sstevel@tonic-gate 	scsa2usb_info,		/* info */
446*0Sstevel@tonic-gate 	nulldev,		/* identify */
447*0Sstevel@tonic-gate 	nulldev,		/* probe */
448*0Sstevel@tonic-gate 	scsa2usb_attach,	/* attach */
449*0Sstevel@tonic-gate 	scsa2usb_detach,	/* detach */
450*0Sstevel@tonic-gate 	nodev,			/* reset */
451*0Sstevel@tonic-gate 	&scsa2usb_cbops,	/* driver operations */
452*0Sstevel@tonic-gate 	NULL,			/* bus operations */
453*0Sstevel@tonic-gate 	scsa2usb_power		/* power */
454*0Sstevel@tonic-gate };
455*0Sstevel@tonic-gate 
456*0Sstevel@tonic-gate static struct modldrv modldrv = {
457*0Sstevel@tonic-gate 	&mod_driverops,			/* Module type. This one is a driver */
458*0Sstevel@tonic-gate 	"SCSA to USB Driver %I%",	/* Name of the module. */
459*0Sstevel@tonic-gate 	&scsa2usb_ops,			/* driver ops */
460*0Sstevel@tonic-gate };
461*0Sstevel@tonic-gate 
462*0Sstevel@tonic-gate static struct modlinkage modlinkage = {
463*0Sstevel@tonic-gate 	MODREV_1, (void *)&modldrv, NULL
464*0Sstevel@tonic-gate };
465*0Sstevel@tonic-gate 
466*0Sstevel@tonic-gate /* event support */
467*0Sstevel@tonic-gate static usb_event_t scsa2usb_events = {
468*0Sstevel@tonic-gate 	scsa2usb_disconnect_event_cb,
469*0Sstevel@tonic-gate 	scsa2usb_reconnect_event_cb,
470*0Sstevel@tonic-gate 	NULL, NULL
471*0Sstevel@tonic-gate };
472*0Sstevel@tonic-gate 
473*0Sstevel@tonic-gate int
474*0Sstevel@tonic-gate _init(void)
475*0Sstevel@tonic-gate {
476*0Sstevel@tonic-gate 	int rval;
477*0Sstevel@tonic-gate 
478*0Sstevel@tonic-gate 	if (((rval = ddi_soft_state_init(&scsa2usb_statep,
479*0Sstevel@tonic-gate 	    sizeof (scsa2usb_state_t), SCSA2USB_INITIAL_ALLOC)) != 0)) {
480*0Sstevel@tonic-gate 
481*0Sstevel@tonic-gate 		return (rval);
482*0Sstevel@tonic-gate 	}
483*0Sstevel@tonic-gate 
484*0Sstevel@tonic-gate 	if ((rval = scsi_hba_init(&modlinkage)) != 0) {
485*0Sstevel@tonic-gate 		ddi_soft_state_fini(&scsa2usb_statep);
486*0Sstevel@tonic-gate 
487*0Sstevel@tonic-gate 		return (rval);
488*0Sstevel@tonic-gate 	}
489*0Sstevel@tonic-gate 
490*0Sstevel@tonic-gate 	if ((rval = mod_install(&modlinkage)) != 0) {
491*0Sstevel@tonic-gate 		scsi_hba_fini(&modlinkage);
492*0Sstevel@tonic-gate 		ddi_soft_state_fini(&scsa2usb_statep);
493*0Sstevel@tonic-gate 
494*0Sstevel@tonic-gate 		return (rval);
495*0Sstevel@tonic-gate 	}
496*0Sstevel@tonic-gate 
497*0Sstevel@tonic-gate 	return (rval);
498*0Sstevel@tonic-gate }
499*0Sstevel@tonic-gate 
500*0Sstevel@tonic-gate 
501*0Sstevel@tonic-gate int
502*0Sstevel@tonic-gate _fini(void)
503*0Sstevel@tonic-gate {
504*0Sstevel@tonic-gate 	int	rval;
505*0Sstevel@tonic-gate 
506*0Sstevel@tonic-gate 	if ((rval = mod_remove(&modlinkage)) == 0) {
507*0Sstevel@tonic-gate 		scsi_hba_fini(&modlinkage);
508*0Sstevel@tonic-gate 		ddi_soft_state_fini(&scsa2usb_statep);
509*0Sstevel@tonic-gate 	}
510*0Sstevel@tonic-gate 
511*0Sstevel@tonic-gate 	return (rval);
512*0Sstevel@tonic-gate }
513*0Sstevel@tonic-gate 
514*0Sstevel@tonic-gate 
515*0Sstevel@tonic-gate int
516*0Sstevel@tonic-gate _info(struct modinfo *modinfop)
517*0Sstevel@tonic-gate {
518*0Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
519*0Sstevel@tonic-gate }
520*0Sstevel@tonic-gate 
521*0Sstevel@tonic-gate 
522*0Sstevel@tonic-gate /*
523*0Sstevel@tonic-gate  * scsa2usb_info :
524*0Sstevel@tonic-gate  *	Get minor number, soft state structure etc.
525*0Sstevel@tonic-gate  */
526*0Sstevel@tonic-gate /*ARGSUSED*/
527*0Sstevel@tonic-gate static int
528*0Sstevel@tonic-gate scsa2usb_info(dev_info_t *dip, ddi_info_cmd_t infocmd,
529*0Sstevel@tonic-gate     void *arg, void **result)
530*0Sstevel@tonic-gate {
531*0Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp = NULL;
532*0Sstevel@tonic-gate 	int error = DDI_FAILURE;
533*0Sstevel@tonic-gate 	int instance = SCSA2USB_MINOR_TO_INSTANCE(getminor((dev_t)arg));
534*0Sstevel@tonic-gate 
535*0Sstevel@tonic-gate 	switch (infocmd) {
536*0Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
537*0Sstevel@tonic-gate 		if (((scsa2usbp = ddi_get_soft_state(scsa2usb_statep,
538*0Sstevel@tonic-gate 		    instance)) != NULL) &&
539*0Sstevel@tonic-gate 		    scsa2usbp->scsa2usb_dip) {
540*0Sstevel@tonic-gate 			*result = scsa2usbp->scsa2usb_dip;
541*0Sstevel@tonic-gate 			error = DDI_SUCCESS;
542*0Sstevel@tonic-gate 		} else {
543*0Sstevel@tonic-gate 			*result = NULL;
544*0Sstevel@tonic-gate 		}
545*0Sstevel@tonic-gate 		break;
546*0Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
547*0Sstevel@tonic-gate 		*result = (void *)(uintptr_t)instance;
548*0Sstevel@tonic-gate 		error = DDI_SUCCESS;
549*0Sstevel@tonic-gate 		break;
550*0Sstevel@tonic-gate 	default:
551*0Sstevel@tonic-gate 		break;
552*0Sstevel@tonic-gate 	}
553*0Sstevel@tonic-gate 
554*0Sstevel@tonic-gate 	return (error);
555*0Sstevel@tonic-gate }
556*0Sstevel@tonic-gate 
557*0Sstevel@tonic-gate 
558*0Sstevel@tonic-gate /*
559*0Sstevel@tonic-gate  * scsa2usb_attach:
560*0Sstevel@tonic-gate  *	Attach driver
561*0Sstevel@tonic-gate  *	Allocate a "scsi_hba_tran" - call scsi_hba_tran_alloc()
562*0Sstevel@tonic-gate  *	Invoke scsi_hba_attach_setup
563*0Sstevel@tonic-gate  *	Get the serialno of the device
564*0Sstevel@tonic-gate  *	Open bulk pipes
565*0Sstevel@tonic-gate  *	Create disk child(ren)
566*0Sstevel@tonic-gate  *	Register events
567*0Sstevel@tonic-gate  *	Create and register panic callback
568*0Sstevel@tonic-gate  *
569*0Sstevel@tonic-gate  * NOTE: Replaced CBW_DIR_OUT with USB_EP_DIR_OUT and CBW_DIR_IN with
570*0Sstevel@tonic-gate  * USB_EP_DIR_IN as they are the same #defines.
571*0Sstevel@tonic-gate  */
572*0Sstevel@tonic-gate static int
573*0Sstevel@tonic-gate scsa2usb_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
574*0Sstevel@tonic-gate {
575*0Sstevel@tonic-gate 	int			instance = ddi_get_instance(dip);
576*0Sstevel@tonic-gate 	int			interface;
577*0Sstevel@tonic-gate 	uint_t			lun;
578*0Sstevel@tonic-gate 	boolean_t		ept_check = B_TRUE;
579*0Sstevel@tonic-gate 	scsi_hba_tran_t		*tran;		/* scsi transport */
580*0Sstevel@tonic-gate 	scsa2usb_state_t	*scsa2usbp;
581*0Sstevel@tonic-gate 	usb_log_handle_t	log_handle;
582*0Sstevel@tonic-gate 	usb_ep_data_t		*ep_data;
583*0Sstevel@tonic-gate 	usb_client_dev_data_t	*dev_data;
584*0Sstevel@tonic-gate 	usb_alt_if_data_t	*altif_data;
585*0Sstevel@tonic-gate 	usb_ugen_info_t 	usb_ugen_info;
586*0Sstevel@tonic-gate 
587*0Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, NULL,
588*0Sstevel@tonic-gate 	    "scsa2usb_attach: dip = 0x%p", dip);
589*0Sstevel@tonic-gate 
590*0Sstevel@tonic-gate 	switch (cmd) {
591*0Sstevel@tonic-gate 	case DDI_ATTACH:
592*0Sstevel@tonic-gate 		break;
593*0Sstevel@tonic-gate 	case DDI_RESUME:
594*0Sstevel@tonic-gate 		scsa2usb_cpr_resume(dip);
595*0Sstevel@tonic-gate 
596*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
597*0Sstevel@tonic-gate 	default:
598*0Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, NULL,
599*0Sstevel@tonic-gate 		    "scsa2usb_attach: failed");
600*0Sstevel@tonic-gate 
601*0Sstevel@tonic-gate 		return (DDI_FAILURE);
602*0Sstevel@tonic-gate 	}
603*0Sstevel@tonic-gate 
604*0Sstevel@tonic-gate 	/* Allocate softc information */
605*0Sstevel@tonic-gate 	if (ddi_soft_state_zalloc(scsa2usb_statep, instance) != DDI_SUCCESS) {
606*0Sstevel@tonic-gate 		ddi_prop_remove_all(dip);
607*0Sstevel@tonic-gate 
608*0Sstevel@tonic-gate 		return (DDI_FAILURE);
609*0Sstevel@tonic-gate 	}
610*0Sstevel@tonic-gate 
611*0Sstevel@tonic-gate 	/* get soft state space and initialize */
612*0Sstevel@tonic-gate 	if ((scsa2usbp = ddi_get_soft_state(scsa2usb_statep,
613*0Sstevel@tonic-gate 	    instance)) == NULL) {
614*0Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, NULL,
615*0Sstevel@tonic-gate 		    "scsa2usb%d: bad soft state", instance);
616*0Sstevel@tonic-gate 		ddi_prop_remove_all(dip);
617*0Sstevel@tonic-gate 
618*0Sstevel@tonic-gate 		return (DDI_FAILURE);
619*0Sstevel@tonic-gate 	}
620*0Sstevel@tonic-gate 
621*0Sstevel@tonic-gate 	scsa2usbp->scsa2usb_dip 	= dip;
622*0Sstevel@tonic-gate 	scsa2usbp->scsa2usb_instance	= instance;
623*0Sstevel@tonic-gate 
624*0Sstevel@tonic-gate 	/* allocate a log handle for debug/error messages */
625*0Sstevel@tonic-gate 	scsa2usbp->scsa2usb_log_handle = log_handle =
626*0Sstevel@tonic-gate 	    usb_alloc_log_hdl(dip, "s2u",
627*0Sstevel@tonic-gate 				&scsa2usb_errlevel,
628*0Sstevel@tonic-gate 				&scsa2usb_errmask, &scsa2usb_instance_debug,
629*0Sstevel@tonic-gate 				0);
630*0Sstevel@tonic-gate 
631*0Sstevel@tonic-gate 	/* attach to USBA */
632*0Sstevel@tonic-gate 	if (usb_client_attach(dip, USBDRV_VERSION, 0) != USB_SUCCESS) {
633*0Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, log_handle,
634*0Sstevel@tonic-gate 		    "usb_client_attach failed");
635*0Sstevel@tonic-gate 
636*0Sstevel@tonic-gate 		goto fail;
637*0Sstevel@tonic-gate 	}
638*0Sstevel@tonic-gate 	if (usb_get_dev_data(dip, &dev_data, USB_PARSE_LVL_IF, 0) !=
639*0Sstevel@tonic-gate 	    USB_SUCCESS) {
640*0Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, log_handle,
641*0Sstevel@tonic-gate 		    "usb_get_dev_data failed");
642*0Sstevel@tonic-gate 
643*0Sstevel@tonic-gate 		goto fail;
644*0Sstevel@tonic-gate 	}
645*0Sstevel@tonic-gate 
646*0Sstevel@tonic-gate 	/* initialize the mutex with the right cookie */
647*0Sstevel@tonic-gate 	mutex_init(&scsa2usbp->scsa2usb_mutex, NULL, MUTEX_DRIVER,
648*0Sstevel@tonic-gate 					dev_data->dev_iblock_cookie);
649*0Sstevel@tonic-gate 	cv_init(&scsa2usbp->scsa2usb_transport_busy_cv, NULL, CV_DRIVER, NULL);
650*0Sstevel@tonic-gate 
651*0Sstevel@tonic-gate 	for (lun = 0; lun < SCSA2USB_MAX_LUNS; lun++) {
652*0Sstevel@tonic-gate 		usba_init_list(&scsa2usbp->scsa2usb_waitQ[lun], NULL,
653*0Sstevel@tonic-gate 					dev_data->dev_iblock_cookie);
654*0Sstevel@tonic-gate 	}
655*0Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
656*0Sstevel@tonic-gate 	scsa2usbp->scsa2usb_dip 	= dip;
657*0Sstevel@tonic-gate 	scsa2usbp->scsa2usb_instance	= instance;
658*0Sstevel@tonic-gate 	scsa2usbp->scsa2usb_attrs	= SCSA2USB_ALL_ATTRS;
659*0Sstevel@tonic-gate 	scsa2usbp->scsa2usb_dev_data	= dev_data;
660*0Sstevel@tonic-gate 
661*0Sstevel@tonic-gate 
662*0Sstevel@tonic-gate 	/* save the default pipe handle */
663*0Sstevel@tonic-gate 	scsa2usbp->scsa2usb_default_pipe = dev_data->dev_default_ph;
664*0Sstevel@tonic-gate 
665*0Sstevel@tonic-gate 	/* basic inits are done */
666*0Sstevel@tonic-gate 	scsa2usbp->scsa2usb_flags |= SCSA2USB_FLAGS_LOCKS_INIT;
667*0Sstevel@tonic-gate 
668*0Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, log_handle,
669*0Sstevel@tonic-gate 	    "curr_cfg=%d, curr_if=%d",
670*0Sstevel@tonic-gate 	    dev_data->dev_curr_cfg - &dev_data->dev_cfg[0],
671*0Sstevel@tonic-gate 	    dev_data->dev_curr_if);
672*0Sstevel@tonic-gate 
673*0Sstevel@tonic-gate 	interface = dev_data->dev_curr_if;
674*0Sstevel@tonic-gate 	scsa2usbp->scsa2usb_intfc_num = dev_data->dev_curr_if;
675*0Sstevel@tonic-gate 
676*0Sstevel@tonic-gate 	/* now find out relevant descriptors for alternate 0 */
677*0Sstevel@tonic-gate 	altif_data = &dev_data->dev_curr_cfg->cfg_if[interface].if_alt[0];
678*0Sstevel@tonic-gate 
679*0Sstevel@tonic-gate 	if (altif_data->altif_n_ep == 0) {
680*0Sstevel@tonic-gate 		USB_DPRINTF_L1(DPRINT_MASK_SCSA, log_handle,
681*0Sstevel@tonic-gate 		    "invalid alt 0 for interface %d", interface);
682*0Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
683*0Sstevel@tonic-gate 
684*0Sstevel@tonic-gate 		goto fail;
685*0Sstevel@tonic-gate 	}
686*0Sstevel@tonic-gate 
687*0Sstevel@tonic-gate 	/* All CB/CBI, BO devices should have this value set */
688*0Sstevel@tonic-gate 	if (altif_data->altif_descr.bInterfaceClass !=
689*0Sstevel@tonic-gate 	    USB_CLASS_MASS_STORAGE) {
690*0Sstevel@tonic-gate 		USB_DPRINTF_L1(DPRINT_MASK_SCSA, log_handle,
691*0Sstevel@tonic-gate 		    "invalid interface class (0x%x)",
692*0Sstevel@tonic-gate 		    altif_data->altif_descr.bInterfaceClass);
693*0Sstevel@tonic-gate 	}
694*0Sstevel@tonic-gate 	scsa2usbp->scsa2usb_intfc_descr = altif_data->altif_descr;
695*0Sstevel@tonic-gate 
696*0Sstevel@tonic-gate 	/* figure out the endpoints and copy the descr */
697*0Sstevel@tonic-gate 	if ((ep_data = usb_lookup_ep_data(dip, dev_data, interface, 0, 0,
698*0Sstevel@tonic-gate 	    USB_EP_ATTR_BULK, USB_EP_DIR_OUT)) != NULL) {
699*0Sstevel@tonic-gate 		scsa2usbp->scsa2usb_bulkout_ept = ep_data->ep_descr;
700*0Sstevel@tonic-gate 	}
701*0Sstevel@tonic-gate 	if ((ep_data = usb_lookup_ep_data(dip, dev_data, interface, 0, 0,
702*0Sstevel@tonic-gate 	    USB_EP_ATTR_BULK, USB_EP_DIR_IN)) != NULL) {
703*0Sstevel@tonic-gate 		scsa2usbp->scsa2usb_bulkin_ept = ep_data->ep_descr;
704*0Sstevel@tonic-gate 	}
705*0Sstevel@tonic-gate 	if ((ep_data = usb_lookup_ep_data(dip, dev_data, interface, 0, 0,
706*0Sstevel@tonic-gate 	    USB_EP_ATTR_INTR, USB_EP_DIR_IN)) != NULL) {
707*0Sstevel@tonic-gate 		scsa2usbp->scsa2usb_intr_ept = ep_data->ep_descr;
708*0Sstevel@tonic-gate 	}
709*0Sstevel@tonic-gate 
710*0Sstevel@tonic-gate 	/*
711*0Sstevel@tonic-gate 	 * check here for protocol and subclass supported by this driver
712*0Sstevel@tonic-gate 	 *
713*0Sstevel@tonic-gate 	 * first check if conf file has override values
714*0Sstevel@tonic-gate 	 * Note: override values are not used if supplied values are legal
715*0Sstevel@tonic-gate 	 */
716*0Sstevel@tonic-gate 	scsa2usb_override(scsa2usbp);
717*0Sstevel@tonic-gate 
718*0Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_SCSA, log_handle,
719*0Sstevel@tonic-gate 	    "protocol=0x%x override=0x%x subclass=0x%x override=0x%x",
720*0Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_intfc_descr.bInterfaceProtocol,
721*0Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_protocol_override,
722*0Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_intfc_descr.bInterfaceSubClass,
723*0Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_subclass_override);
724*0Sstevel@tonic-gate 
725*0Sstevel@tonic-gate 	switch (scsa2usbp->scsa2usb_intfc_descr.bInterfaceProtocol) {
726*0Sstevel@tonic-gate 	case USB_PROTO_MS_CBI:
727*0Sstevel@tonic-gate 		scsa2usbp->scsa2usb_cmd_protocol |= SCSA2USB_CB_PROTOCOL;
728*0Sstevel@tonic-gate 		break;
729*0Sstevel@tonic-gate 	case USB_PROTO_MS_CBI_WC:
730*0Sstevel@tonic-gate 		scsa2usbp->scsa2usb_cmd_protocol |= SCSA2USB_CBI_PROTOCOL;
731*0Sstevel@tonic-gate 		break;
732*0Sstevel@tonic-gate 	case USB_PROTO_MS_ISD_1999_SILICN:
733*0Sstevel@tonic-gate 	case USB_PROTO_MS_BULK_ONLY:
734*0Sstevel@tonic-gate 		scsa2usbp->scsa2usb_cmd_protocol |= SCSA2USB_BULK_ONLY_PROTOCOL;
735*0Sstevel@tonic-gate 		break;
736*0Sstevel@tonic-gate 	default:
737*0Sstevel@tonic-gate 		if (scsa2usbp->scsa2usb_protocol_override) {
738*0Sstevel@tonic-gate 			scsa2usbp->scsa2usb_cmd_protocol |=
739*0Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_protocol_override;
740*0Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_SCSA, log_handle,
741*0Sstevel@tonic-gate 			    "overriding protocol %x",
742*0Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_intfc_descr.bInterfaceProtocol);
743*0Sstevel@tonic-gate 			break;
744*0Sstevel@tonic-gate 		}
745*0Sstevel@tonic-gate 
746*0Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, log_handle,
747*0Sstevel@tonic-gate 		    "unsupported protocol = %x",
748*0Sstevel@tonic-gate 		    scsa2usbp->scsa2usb_intfc_descr.bInterfaceProtocol);
749*0Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
750*0Sstevel@tonic-gate 
751*0Sstevel@tonic-gate 		goto fail;
752*0Sstevel@tonic-gate 	}
753*0Sstevel@tonic-gate 
754*0Sstevel@tonic-gate 	switch (scsa2usbp->scsa2usb_intfc_descr.bInterfaceSubClass) {
755*0Sstevel@tonic-gate 	case USB_SUBCLS_MS_SCSI:		/* transparent SCSI */
756*0Sstevel@tonic-gate 		scsa2usbp->scsa2usb_cmd_protocol |= SCSA2USB_SCSI_CMDSET;
757*0Sstevel@tonic-gate 		break;
758*0Sstevel@tonic-gate 	case USB_SUBCLS_MS_SFF8020I:
759*0Sstevel@tonic-gate 	case USB_SUBCLS_MS_SFF8070I:
760*0Sstevel@tonic-gate 		scsa2usbp->scsa2usb_cmd_protocol |= SCSA2USB_ATAPI_CMDSET;
761*0Sstevel@tonic-gate 		break;
762*0Sstevel@tonic-gate 	case USB_SUBCLS_MS_UFI:		/* UFI */
763*0Sstevel@tonic-gate 		scsa2usbp->scsa2usb_cmd_protocol |= SCSA2USB_UFI_CMDSET;
764*0Sstevel@tonic-gate 		break;
765*0Sstevel@tonic-gate 	default:
766*0Sstevel@tonic-gate 		if (scsa2usbp->scsa2usb_subclass_override) {
767*0Sstevel@tonic-gate 			scsa2usbp->scsa2usb_cmd_protocol |=
768*0Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_subclass_override;
769*0Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_SCSA, log_handle,
770*0Sstevel@tonic-gate 			    "overriding subclass %x",
771*0Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_intfc_descr.bInterfaceSubClass);
772*0Sstevel@tonic-gate 			break;
773*0Sstevel@tonic-gate 		}
774*0Sstevel@tonic-gate 
775*0Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, log_handle,
776*0Sstevel@tonic-gate 		    "unsupported subclass = %x",
777*0Sstevel@tonic-gate 		    scsa2usbp->scsa2usb_intfc_descr.bInterfaceSubClass);
778*0Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
779*0Sstevel@tonic-gate 
780*0Sstevel@tonic-gate 		goto fail;
781*0Sstevel@tonic-gate 	}
782*0Sstevel@tonic-gate 
783*0Sstevel@tonic-gate 	/* check that we have the right set of endpoint descriptors */
784*0Sstevel@tonic-gate 	if (SCSA2USB_IS_BULK_ONLY(scsa2usbp) || SCSA2USB_IS_CB(scsa2usbp)) {
785*0Sstevel@tonic-gate 		if ((scsa2usbp->scsa2usb_bulkout_ept.bLength == 0) ||
786*0Sstevel@tonic-gate 		    (scsa2usbp->scsa2usb_bulkin_ept.bLength == 0)) {
787*0Sstevel@tonic-gate 			ept_check = B_FALSE;
788*0Sstevel@tonic-gate 		}
789*0Sstevel@tonic-gate 	} else if (SCSA2USB_IS_CBI(scsa2usbp)) {
790*0Sstevel@tonic-gate 		if ((scsa2usbp->scsa2usb_bulkout_ept.bLength == 0) ||
791*0Sstevel@tonic-gate 		    (scsa2usbp->scsa2usb_bulkin_ept.bLength == 0) ||
792*0Sstevel@tonic-gate 		    (scsa2usbp->scsa2usb_intr_ept.bLength == 0)) {
793*0Sstevel@tonic-gate 			ept_check = B_FALSE;
794*0Sstevel@tonic-gate 		}
795*0Sstevel@tonic-gate 	}
796*0Sstevel@tonic-gate 
797*0Sstevel@tonic-gate 	if (ept_check == B_FALSE) {
798*0Sstevel@tonic-gate 		USB_DPRINTF_L1(DPRINT_MASK_SCSA, log_handle,
799*0Sstevel@tonic-gate 		    "scsa2usb%d doesn't support minimum required endpoints",
800*0Sstevel@tonic-gate 		    instance);
801*0Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
802*0Sstevel@tonic-gate 
803*0Sstevel@tonic-gate 		goto fail;
804*0Sstevel@tonic-gate 	}
805*0Sstevel@tonic-gate 
806*0Sstevel@tonic-gate 	/*
807*0Sstevel@tonic-gate 	 * Validate the black-listed attributes
808*0Sstevel@tonic-gate 	 */
809*0Sstevel@tonic-gate 	scsa2usb_validate_attrs(scsa2usbp);
810*0Sstevel@tonic-gate 
811*0Sstevel@tonic-gate 	/* Print the serial number from the registration data */
812*0Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_dev_data->dev_serial) {
813*0Sstevel@tonic-gate 		USB_DPRINTF_L4(DPRINT_MASK_SCSA,
814*0Sstevel@tonic-gate 		    scsa2usbp->scsa2usb_log_handle, "Serial Number = %s",
815*0Sstevel@tonic-gate 		    scsa2usbp->scsa2usb_dev_data->dev_serial);
816*0Sstevel@tonic-gate 	}
817*0Sstevel@tonic-gate 
818*0Sstevel@tonic-gate 	/*
819*0Sstevel@tonic-gate 	 * Allocate a SCSA transport structure
820*0Sstevel@tonic-gate 	 */
821*0Sstevel@tonic-gate 	tran = scsi_hba_tran_alloc(dip, SCSI_HBA_CANSLEEP);
822*0Sstevel@tonic-gate 	scsa2usbp->scsa2usb_tran = tran;
823*0Sstevel@tonic-gate 
824*0Sstevel@tonic-gate 	/*
825*0Sstevel@tonic-gate 	 * initialize transport structure
826*0Sstevel@tonic-gate 	 */
827*0Sstevel@tonic-gate 	tran->tran_hba_private		= scsa2usbp;
828*0Sstevel@tonic-gate 	tran->tran_tgt_private		= NULL;
829*0Sstevel@tonic-gate 	tran->tran_tgt_init		= scsa2usb_scsi_tgt_init;
830*0Sstevel@tonic-gate 	tran->tran_tgt_probe		= scsa2usb_scsi_tgt_probe;
831*0Sstevel@tonic-gate 	tran->tran_tgt_free		= scsa2usb_scsi_tgt_free;
832*0Sstevel@tonic-gate 	tran->tran_start		= scsa2usb_scsi_start;
833*0Sstevel@tonic-gate 	tran->tran_abort		= scsa2usb_scsi_abort;
834*0Sstevel@tonic-gate 	tran->tran_reset		= scsa2usb_scsi_reset;
835*0Sstevel@tonic-gate 	tran->tran_getcap		= scsa2usb_scsi_getcap;
836*0Sstevel@tonic-gate 	tran->tran_setcap		= scsa2usb_scsi_setcap;
837*0Sstevel@tonic-gate 	tran->tran_init_pkt		= scsa2usb_scsi_init_pkt;
838*0Sstevel@tonic-gate 	tran->tran_destroy_pkt		= scsa2usb_scsi_destroy_pkt;
839*0Sstevel@tonic-gate 	tran->tran_dmafree		= NULL;
840*0Sstevel@tonic-gate 	tran->tran_sync_pkt		= NULL;
841*0Sstevel@tonic-gate 	tran->tran_reset_notify		= NULL;
842*0Sstevel@tonic-gate 	tran->tran_get_bus_addr		= NULL;
843*0Sstevel@tonic-gate 	tran->tran_get_name		= NULL;
844*0Sstevel@tonic-gate 	tran->tran_quiesce		= NULL;
845*0Sstevel@tonic-gate 	tran->tran_unquiesce		= NULL;
846*0Sstevel@tonic-gate 	tran->tran_bus_reset		= NULL;
847*0Sstevel@tonic-gate 	tran->tran_add_eventcall	= NULL;
848*0Sstevel@tonic-gate 	tran->tran_get_eventcookie	= NULL;
849*0Sstevel@tonic-gate 	tran->tran_post_event		= NULL;
850*0Sstevel@tonic-gate 	tran->tran_remove_eventcall	= NULL;
851*0Sstevel@tonic-gate 	tran->tran_bus_config		= scsa2usb_scsi_bus_config;
852*0Sstevel@tonic-gate 	tran->tran_bus_unconfig		= scsa2usb_scsi_bus_unconfig;
853*0Sstevel@tonic-gate 
854*0Sstevel@tonic-gate 	/*
855*0Sstevel@tonic-gate 	 * register with SCSA as an HBA
856*0Sstevel@tonic-gate 	 * Note that the dma attributes are from parent nexus
857*0Sstevel@tonic-gate 	 */
858*0Sstevel@tonic-gate 	if (scsi_hba_attach_setup(dip, usba_get_hc_dma_attr(dip), tran, 0)) {
859*0Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, log_handle,
860*0Sstevel@tonic-gate 		    "scsi_hba_attach_setup failed");
861*0Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
862*0Sstevel@tonic-gate 
863*0Sstevel@tonic-gate 		goto fail;
864*0Sstevel@tonic-gate 	}
865*0Sstevel@tonic-gate 
866*0Sstevel@tonic-gate 	scsa2usbp->scsa2usb_flags |= SCSA2USB_FLAGS_HBA_ATTACH_SETUP;
867*0Sstevel@tonic-gate 
868*0Sstevel@tonic-gate 	/* create minor node */
869*0Sstevel@tonic-gate 	if (ddi_create_minor_node(dip, "scsa2usb", S_IFCHR,
870*0Sstevel@tonic-gate 	    instance << SCSA2USB_MINOR_INSTANCE_SHIFT,
871*0Sstevel@tonic-gate 	    DDI_NT_SCSI_NEXUS, 0) != DDI_SUCCESS) {
872*0Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
873*0Sstevel@tonic-gate 		    "scsi_attach: ddi_create_minor_node failed");
874*0Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
875*0Sstevel@tonic-gate 
876*0Sstevel@tonic-gate 		goto fail;
877*0Sstevel@tonic-gate 	}
878*0Sstevel@tonic-gate 
879*0Sstevel@tonic-gate 	/* open pipes and set scsa2usb_flags */
880*0Sstevel@tonic-gate 	if (scsa2usb_open_usb_pipes(scsa2usbp) == USB_FAILURE) {
881*0Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, log_handle,
882*0Sstevel@tonic-gate 		    "error opening pipes");
883*0Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
884*0Sstevel@tonic-gate 
885*0Sstevel@tonic-gate 		goto fail;
886*0Sstevel@tonic-gate 	}
887*0Sstevel@tonic-gate 
888*0Sstevel@tonic-gate 	/* set default block size. updated after read cap cmd */
889*0Sstevel@tonic-gate 	for (lun = 0; lun < SCSA2USB_MAX_LUNS; lun++) {
890*0Sstevel@tonic-gate 		scsa2usbp->scsa2usb_lbasize[lun] = DEV_BSIZE;
891*0Sstevel@tonic-gate 	}
892*0Sstevel@tonic-gate 
893*0Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
894*0Sstevel@tonic-gate 
895*0Sstevel@tonic-gate 	/* initialize PANIC callback */
896*0Sstevel@tonic-gate 	scsa2usb_panic_callb_init(scsa2usbp);
897*0Sstevel@tonic-gate 
898*0Sstevel@tonic-gate 	/* finally we are all done 'initializing' the device */
899*0Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
900*0Sstevel@tonic-gate 	scsa2usbp->scsa2usb_dev_state = USB_DEV_ONLINE;
901*0Sstevel@tonic-gate 
902*0Sstevel@tonic-gate 	/* enable PM, mutex needs to be held across this */
903*0Sstevel@tonic-gate 	scsa2usb_create_pm_components(dip, scsa2usbp);
904*0Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
905*0Sstevel@tonic-gate 
906*0Sstevel@tonic-gate 	/* register for connect/disconnect events */
907*0Sstevel@tonic-gate 	if (usb_register_event_cbs(scsa2usbp->scsa2usb_dip, &scsa2usb_events,
908*0Sstevel@tonic-gate 	    0) != USB_SUCCESS) {
909*0Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, log_handle,
910*0Sstevel@tonic-gate 		    "error cb registering");
911*0Sstevel@tonic-gate 		goto fail;
912*0Sstevel@tonic-gate 	}
913*0Sstevel@tonic-gate 
914*0Sstevel@tonic-gate 	/* free the dev_data tree, we no longer need it */
915*0Sstevel@tonic-gate 	usb_free_descr_tree(dip, dev_data);
916*0Sstevel@tonic-gate 
917*0Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
918*0Sstevel@tonic-gate 	scsa2usb_pm_idle_component(scsa2usbp);
919*0Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
920*0Sstevel@tonic-gate 
921*0Sstevel@tonic-gate 	/* log the conf file override string if there is one */
922*0Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_override_str) {
923*0Sstevel@tonic-gate 		USB_DPRINTF_L1(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
924*0Sstevel@tonic-gate 		    "scsa2usb.conf override: %s",
925*0Sstevel@tonic-gate 		    scsa2usbp->scsa2usb_override_str);
926*0Sstevel@tonic-gate 	}
927*0Sstevel@tonic-gate 
928*0Sstevel@tonic-gate 	if (usb_owns_device(dip)) {
929*0Sstevel@tonic-gate 		/* get a ugen handle */
930*0Sstevel@tonic-gate 		bzero(&usb_ugen_info, sizeof (usb_ugen_info));
931*0Sstevel@tonic-gate 		usb_ugen_info.usb_ugen_flags = 0;
932*0Sstevel@tonic-gate 		usb_ugen_info.usb_ugen_minor_node_ugen_bits_mask =
933*0Sstevel@tonic-gate 				(dev_t)SCSA2USB_MINOR_UGEN_BITS_MASK;
934*0Sstevel@tonic-gate 		usb_ugen_info.usb_ugen_minor_node_instance_mask =
935*0Sstevel@tonic-gate 				(dev_t)~SCSA2USB_MINOR_UGEN_BITS_MASK;
936*0Sstevel@tonic-gate 		scsa2usbp->scsa2usb_ugen_hdl =
937*0Sstevel@tonic-gate 					usb_ugen_get_hdl(dip, &usb_ugen_info);
938*0Sstevel@tonic-gate 
939*0Sstevel@tonic-gate 		if (usb_ugen_attach(scsa2usbp->scsa2usb_ugen_hdl, cmd) !=
940*0Sstevel@tonic-gate 		    USB_SUCCESS) {
941*0Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_SCSA,
942*0Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
943*0Sstevel@tonic-gate 			    "usb_ugen_attach failed");
944*0Sstevel@tonic-gate 
945*0Sstevel@tonic-gate 			usb_ugen_release_hdl(scsa2usbp->scsa2usb_ugen_hdl);
946*0Sstevel@tonic-gate 			scsa2usbp->scsa2usb_ugen_hdl = NULL;
947*0Sstevel@tonic-gate 		}
948*0Sstevel@tonic-gate 	}
949*0Sstevel@tonic-gate 
950*0Sstevel@tonic-gate 	/* report device */
951*0Sstevel@tonic-gate 	ddi_report_dev(dip);
952*0Sstevel@tonic-gate 
953*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
954*0Sstevel@tonic-gate 
955*0Sstevel@tonic-gate fail:
956*0Sstevel@tonic-gate 	if (scsa2usbp) {
957*0Sstevel@tonic-gate 		(void) scsa2usb_cleanup(dip, scsa2usbp);
958*0Sstevel@tonic-gate 	}
959*0Sstevel@tonic-gate 
960*0Sstevel@tonic-gate 	return (DDI_FAILURE);
961*0Sstevel@tonic-gate }
962*0Sstevel@tonic-gate 
963*0Sstevel@tonic-gate 
964*0Sstevel@tonic-gate /*
965*0Sstevel@tonic-gate  * scsa2usb_detach:
966*0Sstevel@tonic-gate  *	detach or suspend driver instance
967*0Sstevel@tonic-gate  */
968*0Sstevel@tonic-gate static int
969*0Sstevel@tonic-gate scsa2usb_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
970*0Sstevel@tonic-gate {
971*0Sstevel@tonic-gate 	scsi_hba_tran_t	*tran;
972*0Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp;
973*0Sstevel@tonic-gate 	int rval;
974*0Sstevel@tonic-gate 
975*0Sstevel@tonic-gate 	tran = ddi_get_driver_private(dip);
976*0Sstevel@tonic-gate 	ASSERT(tran != NULL);
977*0Sstevel@tonic-gate 
978*0Sstevel@tonic-gate 	scsa2usbp = (scsa2usb_state_t *)tran->tran_hba_private;
979*0Sstevel@tonic-gate 	ASSERT(scsa2usbp);
980*0Sstevel@tonic-gate 
981*0Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
982*0Sstevel@tonic-gate 	    "scsa2usb_detach: dip = 0x%p, cmd = %d", dip, cmd);
983*0Sstevel@tonic-gate 
984*0Sstevel@tonic-gate 	switch (cmd) {
985*0Sstevel@tonic-gate 	case DDI_DETACH:
986*0Sstevel@tonic-gate 
987*0Sstevel@tonic-gate 		if (scsa2usb_cleanup(dip, scsa2usbp) != USB_SUCCESS) {
988*0Sstevel@tonic-gate 
989*0Sstevel@tonic-gate 			return (DDI_FAILURE);
990*0Sstevel@tonic-gate 		}
991*0Sstevel@tonic-gate 
992*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
993*0Sstevel@tonic-gate 	case DDI_SUSPEND:
994*0Sstevel@tonic-gate 		rval = scsa2usb_cpr_suspend(dip);
995*0Sstevel@tonic-gate 
996*0Sstevel@tonic-gate 		return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
997*0Sstevel@tonic-gate 	default:
998*0Sstevel@tonic-gate 
999*0Sstevel@tonic-gate 		return (DDI_FAILURE);
1000*0Sstevel@tonic-gate 	}
1001*0Sstevel@tonic-gate }
1002*0Sstevel@tonic-gate 
1003*0Sstevel@tonic-gate 
1004*0Sstevel@tonic-gate /*
1005*0Sstevel@tonic-gate  * ugen support
1006*0Sstevel@tonic-gate  */
1007*0Sstevel@tonic-gate /*
1008*0Sstevel@tonic-gate  * scsa2usb_ugen_open()
1009*0Sstevel@tonic-gate  * (all ugen opens and pipe opens are by definition exclusive so it is OK
1010*0Sstevel@tonic-gate  * to count opens)
1011*0Sstevel@tonic-gate  */
1012*0Sstevel@tonic-gate static int
1013*0Sstevel@tonic-gate scsa2usb_ugen_open(dev_t *devp, int flag, int sflag, cred_t *cr)
1014*0Sstevel@tonic-gate {
1015*0Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp;
1016*0Sstevel@tonic-gate 	int		rval;
1017*0Sstevel@tonic-gate 
1018*0Sstevel@tonic-gate 	if ((scsa2usbp = ddi_get_soft_state(scsa2usb_statep,
1019*0Sstevel@tonic-gate 	    SCSA2USB_MINOR_TO_INSTANCE(getminor(*devp)))) == NULL) {
1020*0Sstevel@tonic-gate 		/* deferred detach */
1021*0Sstevel@tonic-gate 
1022*0Sstevel@tonic-gate 		return (ENXIO);
1023*0Sstevel@tonic-gate 	}
1024*0Sstevel@tonic-gate 
1025*0Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
1026*0Sstevel@tonic-gate 	    "scsa2usb_ugen_open: dev_t=0x%lx", *devp);
1027*0Sstevel@tonic-gate 
1028*0Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
1029*0Sstevel@tonic-gate 
1030*0Sstevel@tonic-gate 	/* if this is the first ugen open, check on transport busy */
1031*0Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_ugen_open_count == 0) {
1032*0Sstevel@tonic-gate 		while (scsa2usbp->scsa2usb_transport_busy ||
1033*0Sstevel@tonic-gate 		    (scsa2usb_all_waitQs_empty(scsa2usbp) !=
1034*0Sstevel@tonic-gate 		    USB_SUCCESS)) {
1035*0Sstevel@tonic-gate 			rval = cv_wait_sig(
1036*0Sstevel@tonic-gate 				&scsa2usbp->scsa2usb_transport_busy_cv,
1037*0Sstevel@tonic-gate 				&scsa2usbp->scsa2usb_mutex);
1038*0Sstevel@tonic-gate 			if (rval == 0) {
1039*0Sstevel@tonic-gate 				mutex_exit(&scsa2usbp->scsa2usb_mutex);
1040*0Sstevel@tonic-gate 
1041*0Sstevel@tonic-gate 				return (EINTR);
1042*0Sstevel@tonic-gate 			}
1043*0Sstevel@tonic-gate 		}
1044*0Sstevel@tonic-gate 		scsa2usbp->scsa2usb_transport_busy++;
1045*0Sstevel@tonic-gate 		scsa2usbp->scsa2usb_busy_thread = curthread;
1046*0Sstevel@tonic-gate 	}
1047*0Sstevel@tonic-gate 	scsa2usbp->scsa2usb_ugen_open_count++;
1048*0Sstevel@tonic-gate 
1049*0Sstevel@tonic-gate 	scsa2usb_raise_power(scsa2usbp);
1050*0Sstevel@tonic-gate 
1051*0Sstevel@tonic-gate 	scsa2usb_close_usb_pipes(scsa2usbp);
1052*0Sstevel@tonic-gate 
1053*0Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
1054*0Sstevel@tonic-gate 
1055*0Sstevel@tonic-gate 	rval = usb_ugen_open(scsa2usbp->scsa2usb_ugen_hdl, devp, flag,
1056*0Sstevel@tonic-gate 		sflag, cr);
1057*0Sstevel@tonic-gate 
1058*0Sstevel@tonic-gate 	if (rval) {
1059*0Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
1060*0Sstevel@tonic-gate 
1061*0Sstevel@tonic-gate 		/* reopen the pipes */
1062*0Sstevel@tonic-gate 		if (--scsa2usbp->scsa2usb_ugen_open_count == 0) {
1063*0Sstevel@tonic-gate 			scsa2usbp->scsa2usb_transport_busy--;
1064*0Sstevel@tonic-gate 			scsa2usbp->scsa2usb_busy_thread = NULL;
1065*0Sstevel@tonic-gate 			cv_signal(&scsa2usbp->scsa2usb_transport_busy_cv);
1066*0Sstevel@tonic-gate 		}
1067*0Sstevel@tonic-gate 		scsa2usb_pm_idle_component(scsa2usbp);
1068*0Sstevel@tonic-gate 
1069*0Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
1070*0Sstevel@tonic-gate 	}
1071*0Sstevel@tonic-gate 
1072*0Sstevel@tonic-gate 	return (rval);
1073*0Sstevel@tonic-gate }
1074*0Sstevel@tonic-gate 
1075*0Sstevel@tonic-gate 
1076*0Sstevel@tonic-gate /*
1077*0Sstevel@tonic-gate  * scsa2usb_ugen_close()
1078*0Sstevel@tonic-gate  */
1079*0Sstevel@tonic-gate static int
1080*0Sstevel@tonic-gate scsa2usb_ugen_close(dev_t dev, int flag, int otype, cred_t *cr)
1081*0Sstevel@tonic-gate {
1082*0Sstevel@tonic-gate 	int rval;
1083*0Sstevel@tonic-gate 
1084*0Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp = ddi_get_soft_state(scsa2usb_statep,
1085*0Sstevel@tonic-gate 			SCSA2USB_MINOR_TO_INSTANCE(getminor(dev)));
1086*0Sstevel@tonic-gate 
1087*0Sstevel@tonic-gate 	if (scsa2usbp == NULL) {
1088*0Sstevel@tonic-gate 
1089*0Sstevel@tonic-gate 		return (ENXIO);
1090*0Sstevel@tonic-gate 	}
1091*0Sstevel@tonic-gate 
1092*0Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
1093*0Sstevel@tonic-gate 	    "scsa2usb_ugen_close: dev_t=0x%lx", dev);
1094*0Sstevel@tonic-gate 
1095*0Sstevel@tonic-gate 	rval = usb_ugen_close(scsa2usbp->scsa2usb_ugen_hdl, dev, flag,
1096*0Sstevel@tonic-gate 		otype, cr);
1097*0Sstevel@tonic-gate 
1098*0Sstevel@tonic-gate 	if (rval == 0) {
1099*0Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
1100*0Sstevel@tonic-gate 
1101*0Sstevel@tonic-gate 		/* reopen the pipes */
1102*0Sstevel@tonic-gate 		if (--scsa2usbp->scsa2usb_ugen_open_count == 0) {
1103*0Sstevel@tonic-gate 			scsa2usbp->scsa2usb_transport_busy--;
1104*0Sstevel@tonic-gate 			scsa2usbp->scsa2usb_busy_thread = NULL;
1105*0Sstevel@tonic-gate 			cv_signal(&scsa2usbp->scsa2usb_transport_busy_cv);
1106*0Sstevel@tonic-gate 		}
1107*0Sstevel@tonic-gate 		scsa2usb_pm_idle_component(scsa2usbp);
1108*0Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
1109*0Sstevel@tonic-gate 	}
1110*0Sstevel@tonic-gate 
1111*0Sstevel@tonic-gate 	return (rval);
1112*0Sstevel@tonic-gate }
1113*0Sstevel@tonic-gate 
1114*0Sstevel@tonic-gate 
1115*0Sstevel@tonic-gate /*
1116*0Sstevel@tonic-gate  * scsa2usb_ugen_read/write()
1117*0Sstevel@tonic-gate  */
1118*0Sstevel@tonic-gate /*ARGSUSED*/
1119*0Sstevel@tonic-gate static int
1120*0Sstevel@tonic-gate scsa2usb_ugen_read(dev_t dev, struct uio *uiop, cred_t *credp)
1121*0Sstevel@tonic-gate {
1122*0Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp = ddi_get_soft_state(scsa2usb_statep,
1123*0Sstevel@tonic-gate 			SCSA2USB_MINOR_TO_INSTANCE(getminor(dev)));
1124*0Sstevel@tonic-gate 
1125*0Sstevel@tonic-gate 	if (scsa2usbp == NULL) {
1126*0Sstevel@tonic-gate 
1127*0Sstevel@tonic-gate 		return (ENXIO);
1128*0Sstevel@tonic-gate 	}
1129*0Sstevel@tonic-gate 
1130*0Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
1131*0Sstevel@tonic-gate 	    "scsa2usb_ugen_read: dev_t=0x%lx", dev);
1132*0Sstevel@tonic-gate 
1133*0Sstevel@tonic-gate 
1134*0Sstevel@tonic-gate 	return (usb_ugen_read(scsa2usbp->scsa2usb_ugen_hdl, dev,
1135*0Sstevel@tonic-gate 					uiop, credp));
1136*0Sstevel@tonic-gate }
1137*0Sstevel@tonic-gate 
1138*0Sstevel@tonic-gate 
1139*0Sstevel@tonic-gate /*ARGSUSED*/
1140*0Sstevel@tonic-gate static int
1141*0Sstevel@tonic-gate scsa2usb_ugen_write(dev_t dev, struct uio *uiop, cred_t *credp)
1142*0Sstevel@tonic-gate {
1143*0Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp = ddi_get_soft_state(scsa2usb_statep,
1144*0Sstevel@tonic-gate 			SCSA2USB_MINOR_TO_INSTANCE(getminor(dev)));
1145*0Sstevel@tonic-gate 
1146*0Sstevel@tonic-gate 	if (scsa2usbp == NULL) {
1147*0Sstevel@tonic-gate 
1148*0Sstevel@tonic-gate 		return (ENXIO);
1149*0Sstevel@tonic-gate 	}
1150*0Sstevel@tonic-gate 
1151*0Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
1152*0Sstevel@tonic-gate 	    "scsa2usb_ugen_write: dev_t=0x%lx", dev);
1153*0Sstevel@tonic-gate 
1154*0Sstevel@tonic-gate 	return (usb_ugen_write(scsa2usbp->scsa2usb_ugen_hdl,
1155*0Sstevel@tonic-gate 					dev, uiop, credp));
1156*0Sstevel@tonic-gate }
1157*0Sstevel@tonic-gate 
1158*0Sstevel@tonic-gate 
1159*0Sstevel@tonic-gate /*
1160*0Sstevel@tonic-gate  * scsa2usb_ugen_poll
1161*0Sstevel@tonic-gate  */
1162*0Sstevel@tonic-gate static int
1163*0Sstevel@tonic-gate scsa2usb_ugen_poll(dev_t dev, short events,
1164*0Sstevel@tonic-gate     int anyyet,  short *reventsp, struct pollhead **phpp)
1165*0Sstevel@tonic-gate {
1166*0Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp = ddi_get_soft_state(scsa2usb_statep,
1167*0Sstevel@tonic-gate 			SCSA2USB_MINOR_TO_INSTANCE(getminor(dev)));
1168*0Sstevel@tonic-gate 
1169*0Sstevel@tonic-gate 	if (scsa2usbp == NULL) {
1170*0Sstevel@tonic-gate 
1171*0Sstevel@tonic-gate 		return (ENXIO);
1172*0Sstevel@tonic-gate 	}
1173*0Sstevel@tonic-gate 
1174*0Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
1175*0Sstevel@tonic-gate 	    "scsa2usb_ugen_poll: dev_t=0x%lx", dev);
1176*0Sstevel@tonic-gate 
1177*0Sstevel@tonic-gate 	return (usb_ugen_poll(scsa2usbp->scsa2usb_ugen_hdl, dev, events,
1178*0Sstevel@tonic-gate 					anyyet, reventsp, phpp));
1179*0Sstevel@tonic-gate }
1180*0Sstevel@tonic-gate 
1181*0Sstevel@tonic-gate 
1182*0Sstevel@tonic-gate /*
1183*0Sstevel@tonic-gate  * scsa2usb_cleanup:
1184*0Sstevel@tonic-gate  *	cleanup whatever attach has setup
1185*0Sstevel@tonic-gate  */
1186*0Sstevel@tonic-gate static int
1187*0Sstevel@tonic-gate scsa2usb_cleanup(dev_info_t *dip, scsa2usb_state_t *scsa2usbp)
1188*0Sstevel@tonic-gate {
1189*0Sstevel@tonic-gate 	int		rval, i;
1190*0Sstevel@tonic-gate 	scsa2usb_power_t *pm;
1191*0Sstevel@tonic-gate 	uint_t		lun;
1192*0Sstevel@tonic-gate 
1193*0Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
1194*0Sstevel@tonic-gate 	    "scsa2usb_cleanup:");
1195*0Sstevel@tonic-gate 
1196*0Sstevel@tonic-gate 	/* wait till the work thread is done */
1197*0Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
1198*0Sstevel@tonic-gate 	for (i = 0; i < SCSA2USB_DRAIN_TIMEOUT; i++) {
1199*0Sstevel@tonic-gate 		if (scsa2usbp->scsa2usb_work_thread_id == NULL) {
1200*0Sstevel@tonic-gate 
1201*0Sstevel@tonic-gate 			break;
1202*0Sstevel@tonic-gate 		}
1203*0Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
1204*0Sstevel@tonic-gate 		delay(drv_usectohz(1000000));
1205*0Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
1206*0Sstevel@tonic-gate 	}
1207*0Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
1208*0Sstevel@tonic-gate 
1209*0Sstevel@tonic-gate 	if (i >= SCSA2USB_DRAIN_TIMEOUT) {
1210*0Sstevel@tonic-gate 
1211*0Sstevel@tonic-gate 		return (USB_FAILURE);
1212*0Sstevel@tonic-gate 	}
1213*0Sstevel@tonic-gate 
1214*0Sstevel@tonic-gate 	/*
1215*0Sstevel@tonic-gate 	 * Disable the event callbacks first, after this point, event
1216*0Sstevel@tonic-gate 	 * callbacks will never get called. Note we shouldn't hold
1217*0Sstevel@tonic-gate 	 * mutex while unregistering events because there may be a
1218*0Sstevel@tonic-gate 	 * competing event callback thread. Event callbacks are done
1219*0Sstevel@tonic-gate 	 * with ndi mutex held and this can cause a potential deadlock.
1220*0Sstevel@tonic-gate 	 */
1221*0Sstevel@tonic-gate 	usb_unregister_event_cbs(scsa2usbp->scsa2usb_dip, &scsa2usb_events);
1222*0Sstevel@tonic-gate 
1223*0Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_flags & SCSA2USB_FLAGS_LOCKS_INIT) {
1224*0Sstevel@tonic-gate 		/*
1225*0Sstevel@tonic-gate 		 * if a waitQ exists, get rid of it before destroying it
1226*0Sstevel@tonic-gate 		 */
1227*0Sstevel@tonic-gate 		for (lun = 0; lun < SCSA2USB_MAX_LUNS; lun++) {
1228*0Sstevel@tonic-gate 			scsa2usb_flush_waitQ(scsa2usbp, lun, CMD_TRAN_ERR);
1229*0Sstevel@tonic-gate 			usba_destroy_list(&scsa2usbp->scsa2usb_waitQ[lun]);
1230*0Sstevel@tonic-gate 		}
1231*0Sstevel@tonic-gate 
1232*0Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
1233*0Sstevel@tonic-gate 		if (scsa2usbp->scsa2usb_flags &
1234*0Sstevel@tonic-gate 		    SCSA2USB_FLAGS_HBA_ATTACH_SETUP) {
1235*0Sstevel@tonic-gate 			(void) scsi_hba_detach(dip);
1236*0Sstevel@tonic-gate 			scsi_hba_tran_free(scsa2usbp->scsa2usb_tran);
1237*0Sstevel@tonic-gate 		}
1238*0Sstevel@tonic-gate 
1239*0Sstevel@tonic-gate 		if (scsa2usbp->scsa2usb_flags &
1240*0Sstevel@tonic-gate 		    SCSA2USB_FLAGS_PIPES_OPENED) {
1241*0Sstevel@tonic-gate 			scsa2usb_close_usb_pipes(scsa2usbp);
1242*0Sstevel@tonic-gate 		}
1243*0Sstevel@tonic-gate 
1244*0Sstevel@tonic-gate 		/* Lower the power */
1245*0Sstevel@tonic-gate 		pm = scsa2usbp->scsa2usb_pm;
1246*0Sstevel@tonic-gate 
1247*0Sstevel@tonic-gate 		if (pm && (scsa2usbp->scsa2usb_dev_state !=
1248*0Sstevel@tonic-gate 		    USB_DEV_DISCONNECTED)) {
1249*0Sstevel@tonic-gate 			if (pm->scsa2usb_wakeup_enabled) {
1250*0Sstevel@tonic-gate 				mutex_exit(&scsa2usbp->scsa2usb_mutex);
1251*0Sstevel@tonic-gate 				(void) pm_raise_power(dip, 0,
1252*0Sstevel@tonic-gate 						USB_DEV_OS_FULL_PWR);
1253*0Sstevel@tonic-gate 
1254*0Sstevel@tonic-gate 				if ((rval = usb_handle_remote_wakeup(dip,
1255*0Sstevel@tonic-gate 				    USB_REMOTE_WAKEUP_DISABLE)) !=
1256*0Sstevel@tonic-gate 				    USB_SUCCESS) {
1257*0Sstevel@tonic-gate 					USB_DPRINTF_L1(DPRINT_MASK_SCSA,
1258*0Sstevel@tonic-gate 					    scsa2usbp->scsa2usb_log_handle,
1259*0Sstevel@tonic-gate 					    "disable remote wakeup failed "
1260*0Sstevel@tonic-gate 					    "(%d)", rval);
1261*0Sstevel@tonic-gate 				}
1262*0Sstevel@tonic-gate 			} else {
1263*0Sstevel@tonic-gate 				mutex_exit(&scsa2usbp->scsa2usb_mutex);
1264*0Sstevel@tonic-gate 			}
1265*0Sstevel@tonic-gate 
1266*0Sstevel@tonic-gate 			(void) pm_lower_power(dip, 0, USB_DEV_OS_PWR_OFF);
1267*0Sstevel@tonic-gate 
1268*0Sstevel@tonic-gate 			mutex_enter(&scsa2usbp->scsa2usb_mutex);
1269*0Sstevel@tonic-gate 		}
1270*0Sstevel@tonic-gate 
1271*0Sstevel@tonic-gate 		if (pm) {
1272*0Sstevel@tonic-gate 			kmem_free(pm, sizeof (scsa2usb_power_t));
1273*0Sstevel@tonic-gate 		}
1274*0Sstevel@tonic-gate 
1275*0Sstevel@tonic-gate 		if (scsa2usbp->scsa2usb_override_str) {
1276*0Sstevel@tonic-gate 			kmem_free(scsa2usbp->scsa2usb_override_str,
1277*0Sstevel@tonic-gate 			    strlen(scsa2usbp->scsa2usb_override_str) + 1);
1278*0Sstevel@tonic-gate 			scsa2usbp->scsa2usb_override_str = NULL;
1279*0Sstevel@tonic-gate 		}
1280*0Sstevel@tonic-gate 
1281*0Sstevel@tonic-gate 		/* remove the minor nodes */
1282*0Sstevel@tonic-gate 		ddi_remove_minor_node(dip, NULL);
1283*0Sstevel@tonic-gate 
1284*0Sstevel@tonic-gate 		/* Cancel the registered panic callback */
1285*0Sstevel@tonic-gate 		scsa2usb_panic_callb_fini(scsa2usbp);
1286*0Sstevel@tonic-gate 
1287*0Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
1288*0Sstevel@tonic-gate 
1289*0Sstevel@tonic-gate 		mutex_destroy(&scsa2usbp->scsa2usb_mutex);
1290*0Sstevel@tonic-gate 		cv_destroy(&scsa2usbp->scsa2usb_transport_busy_cv);
1291*0Sstevel@tonic-gate 	}
1292*0Sstevel@tonic-gate 
1293*0Sstevel@tonic-gate 	usb_client_detach(scsa2usbp->scsa2usb_dip,
1294*0Sstevel@tonic-gate 				scsa2usbp->scsa2usb_dev_data);
1295*0Sstevel@tonic-gate 
1296*0Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_ugen_hdl) {
1297*0Sstevel@tonic-gate 		(void) usb_ugen_detach(scsa2usbp->scsa2usb_ugen_hdl,
1298*0Sstevel@tonic-gate 							DDI_DETACH);
1299*0Sstevel@tonic-gate 		usb_ugen_release_hdl(scsa2usbp->scsa2usb_ugen_hdl);
1300*0Sstevel@tonic-gate 	}
1301*0Sstevel@tonic-gate 
1302*0Sstevel@tonic-gate 	usb_free_log_hdl(scsa2usbp->scsa2usb_log_handle);
1303*0Sstevel@tonic-gate 
1304*0Sstevel@tonic-gate 	ddi_prop_remove_all(dip);
1305*0Sstevel@tonic-gate 
1306*0Sstevel@tonic-gate 	ddi_soft_state_free(scsa2usb_statep, ddi_get_instance(dip));
1307*0Sstevel@tonic-gate 
1308*0Sstevel@tonic-gate 	return (USB_SUCCESS);
1309*0Sstevel@tonic-gate }
1310*0Sstevel@tonic-gate 
1311*0Sstevel@tonic-gate 
1312*0Sstevel@tonic-gate /*
1313*0Sstevel@tonic-gate  * scsa2usb_override:
1314*0Sstevel@tonic-gate  *	some devices may be attached even though their subclass or
1315*0Sstevel@tonic-gate  *	protocol info is not according to spec.
1316*0Sstevel@tonic-gate  *	these can be determined by the 'subclass-protocol-override'
1317*0Sstevel@tonic-gate  *	property set in the conf file.
1318*0Sstevel@tonic-gate  */
1319*0Sstevel@tonic-gate static void
1320*0Sstevel@tonic-gate scsa2usb_override(scsa2usb_state_t *scsa2usbp)
1321*0Sstevel@tonic-gate {
1322*0Sstevel@tonic-gate 	scsa2usb_ov_t ov;
1323*0Sstevel@tonic-gate 	char	**override_str = NULL;
1324*0Sstevel@tonic-gate 	char	*override_str_cpy;
1325*0Sstevel@tonic-gate 	uint_t	override_str_len, override_str_cpy_len;
1326*0Sstevel@tonic-gate 	uint_t	i;
1327*0Sstevel@tonic-gate 	usb_dev_descr_t *descr = scsa2usbp->scsa2usb_dev_data->dev_descr;
1328*0Sstevel@tonic-gate 
1329*0Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
1330*0Sstevel@tonic-gate 
1331*0Sstevel@tonic-gate 	scsa2usbp->scsa2usb_subclass_override =
1332*0Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_protocol_override = 0;
1333*0Sstevel@tonic-gate 
1334*0Sstevel@tonic-gate 	if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, scsa2usbp->scsa2usb_dip,
1335*0Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "attribute-override-list",
1336*0Sstevel@tonic-gate 	    &override_str, &override_str_len) != DDI_PROP_SUCCESS) {
1337*0Sstevel@tonic-gate 
1338*0Sstevel@tonic-gate 		return;
1339*0Sstevel@tonic-gate 	}
1340*0Sstevel@tonic-gate 
1341*0Sstevel@tonic-gate 	/* parse each string in the subclass-protocol-override property */
1342*0Sstevel@tonic-gate 	for (i = 0; i < override_str_len; i++) {
1343*0Sstevel@tonic-gate 
1344*0Sstevel@tonic-gate 		USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
1345*0Sstevel@tonic-gate 		    "override_str[%d] = %s", i, override_str[i]);
1346*0Sstevel@tonic-gate 
1347*0Sstevel@tonic-gate 		/*
1348*0Sstevel@tonic-gate 		 * save a copy of the override string for possible
1349*0Sstevel@tonic-gate 		 * inclusion in soft state later
1350*0Sstevel@tonic-gate 		 */
1351*0Sstevel@tonic-gate 		override_str_cpy_len = strlen(override_str[i]) + 1;
1352*0Sstevel@tonic-gate 		override_str_cpy = kmem_zalloc(override_str_cpy_len, KM_SLEEP);
1353*0Sstevel@tonic-gate 		(void) strcpy(override_str_cpy, override_str[i]);
1354*0Sstevel@tonic-gate 
1355*0Sstevel@tonic-gate 		bzero(&ov, sizeof (scsa2usb_ov_t));
1356*0Sstevel@tonic-gate 
1357*0Sstevel@tonic-gate 		if (scsa2usb_parse_input_str(override_str[i], &ov,
1358*0Sstevel@tonic-gate 		    scsa2usbp) == USB_FAILURE) {
1359*0Sstevel@tonic-gate 			kmem_free(override_str_cpy, override_str_cpy_len);
1360*0Sstevel@tonic-gate 			continue;
1361*0Sstevel@tonic-gate 		}
1362*0Sstevel@tonic-gate 
1363*0Sstevel@tonic-gate 		/*
1364*0Sstevel@tonic-gate 		 * see if subclass/protocol needs to be overridden for device
1365*0Sstevel@tonic-gate 		 * or if device should not be power managed
1366*0Sstevel@tonic-gate 		 * if there'a a match, save the override string in soft state
1367*0Sstevel@tonic-gate 		 */
1368*0Sstevel@tonic-gate 		if (((descr->idVendor == (uint16_t)ov.vid) || (ov.vid == 0)) &&
1369*0Sstevel@tonic-gate 		    ((descr->idProduct == (uint16_t)ov.pid) || (ov.pid == 0)) &&
1370*0Sstevel@tonic-gate 		    ((descr->bcdDevice == (uint16_t)ov.rev) || (ov.rev == 0))) {
1371*0Sstevel@tonic-gate 			scsa2usbp->scsa2usb_subclass_override = ov.subclass;
1372*0Sstevel@tonic-gate 			scsa2usbp->scsa2usb_protocol_override = ov.protocol;
1373*0Sstevel@tonic-gate 
1374*0Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_SCSA,
1375*0Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
1376*0Sstevel@tonic-gate 			    "vid=0x%x pid=0x%x rev=0x%x subclass=0x%x "
1377*0Sstevel@tonic-gate 			    "protocol=0x%x "
1378*0Sstevel@tonic-gate 			    "pmoff=%d not_removable=%d modesense=%d "
1379*0Sstevel@tonic-gate 			    "reduced-cmd-support=%d",
1380*0Sstevel@tonic-gate 			    ov.vid, ov.pid, ov.rev, ov.subclass, ov.protocol,
1381*0Sstevel@tonic-gate 			    ov.pmoff, ov.not_removable, ov.no_modesense,
1382*0Sstevel@tonic-gate 			    ov.reduced_cmd_support);
1383*0Sstevel@tonic-gate 
1384*0Sstevel@tonic-gate 			if (ov.pmoff) {
1385*0Sstevel@tonic-gate 				scsa2usbp->scsa2usb_attrs &= ~SCSA2USB_ATTRS_PM;
1386*0Sstevel@tonic-gate 			}
1387*0Sstevel@tonic-gate 			if (ov.not_removable) {
1388*0Sstevel@tonic-gate 				scsa2usbp->scsa2usb_attrs &=
1389*0Sstevel@tonic-gate 				    ~SCSA2USB_ATTRS_RMB;
1390*0Sstevel@tonic-gate 			}
1391*0Sstevel@tonic-gate 			if (ov.no_modesense) {
1392*0Sstevel@tonic-gate 				scsa2usbp->scsa2usb_attrs &=
1393*0Sstevel@tonic-gate 				    ~SCSA2USB_ATTRS_MODE_SENSE;
1394*0Sstevel@tonic-gate 			}
1395*0Sstevel@tonic-gate 			if (ov.reduced_cmd_support) {
1396*0Sstevel@tonic-gate 				scsa2usbp->scsa2usb_attrs &=
1397*0Sstevel@tonic-gate 				    ~SCSA2USB_ATTRS_REDUCED_CMD;
1398*0Sstevel@tonic-gate 			}
1399*0Sstevel@tonic-gate 			scsa2usbp->scsa2usb_override_str = override_str_cpy;
1400*0Sstevel@tonic-gate 			break;
1401*0Sstevel@tonic-gate 		} else {
1402*0Sstevel@tonic-gate 			kmem_free(override_str_cpy, override_str_cpy_len);
1403*0Sstevel@tonic-gate 		}
1404*0Sstevel@tonic-gate 	}
1405*0Sstevel@tonic-gate 
1406*0Sstevel@tonic-gate 	ddi_prop_free(override_str);
1407*0Sstevel@tonic-gate }
1408*0Sstevel@tonic-gate 
1409*0Sstevel@tonic-gate 
1410*0Sstevel@tonic-gate /*
1411*0Sstevel@tonic-gate  * scsa2usb_parse_input_str:
1412*0Sstevel@tonic-gate  *	parse one conf file subclass-protocol-override string
1413*0Sstevel@tonic-gate  *	return vendor id, product id, revision, subclass, protocol
1414*0Sstevel@tonic-gate  *	function return is success or failure
1415*0Sstevel@tonic-gate  */
1416*0Sstevel@tonic-gate static int
1417*0Sstevel@tonic-gate scsa2usb_parse_input_str(char *str, scsa2usb_ov_t *ovp,
1418*0Sstevel@tonic-gate     scsa2usb_state_t *scsa2usbp)
1419*0Sstevel@tonic-gate {
1420*0Sstevel@tonic-gate 	char		*input_field, *input_value;
1421*0Sstevel@tonic-gate 	char		*lasts;
1422*0Sstevel@tonic-gate 	uint_t		i;
1423*0Sstevel@tonic-gate 	u_longlong_t	value;
1424*0Sstevel@tonic-gate 
1425*0Sstevel@tonic-gate 	/* parse all the input pairs in the string */
1426*0Sstevel@tonic-gate 	for (input_field = scsa2usb_strtok_r(str, "=", &lasts);
1427*0Sstevel@tonic-gate 	    input_field != NULL;
1428*0Sstevel@tonic-gate 	    input_field = scsa2usb_strtok_r(lasts, "=", &lasts)) {
1429*0Sstevel@tonic-gate 
1430*0Sstevel@tonic-gate 		if ((input_value = scsa2usb_strtok_r(lasts, " ", &lasts)) ==
1431*0Sstevel@tonic-gate 		    NULL) {
1432*0Sstevel@tonic-gate 			scsa2usb_override_error("format", scsa2usbp);
1433*0Sstevel@tonic-gate 
1434*0Sstevel@tonic-gate 			return (USB_FAILURE);
1435*0Sstevel@tonic-gate 		}
1436*0Sstevel@tonic-gate 		/* if input value is a 'don't care', skip to the next pair */
1437*0Sstevel@tonic-gate 		if (strcmp(input_value, "*") == 0) {
1438*0Sstevel@tonic-gate 			continue;
1439*0Sstevel@tonic-gate 		}
1440*0Sstevel@tonic-gate 		if (strcasecmp(input_field, "vid") == 0) {
1441*0Sstevel@tonic-gate 			if (kobj_getvalue(input_value, &value) == -1) {
1442*0Sstevel@tonic-gate 				scsa2usb_override_error("vendor id", scsa2usbp);
1443*0Sstevel@tonic-gate 
1444*0Sstevel@tonic-gate 				return (USB_FAILURE);
1445*0Sstevel@tonic-gate 			}
1446*0Sstevel@tonic-gate 			ovp->vid = (int)value;
1447*0Sstevel@tonic-gate 		} else if (strcasecmp(input_field, "pid") == 0) {
1448*0Sstevel@tonic-gate 			if (kobj_getvalue(input_value, &value) == -1) {
1449*0Sstevel@tonic-gate 				scsa2usb_override_error("product id",
1450*0Sstevel@tonic-gate 				    scsa2usbp);
1451*0Sstevel@tonic-gate 
1452*0Sstevel@tonic-gate 				return (USB_FAILURE);
1453*0Sstevel@tonic-gate 			}
1454*0Sstevel@tonic-gate 			ovp->pid = (int)value;
1455*0Sstevel@tonic-gate 		} else if (strcasecmp(input_field, "rev") == 0) {
1456*0Sstevel@tonic-gate 			if (kobj_getvalue(input_value, &value) == -1) {
1457*0Sstevel@tonic-gate 				scsa2usb_override_error("revision id",
1458*0Sstevel@tonic-gate 				    scsa2usbp);
1459*0Sstevel@tonic-gate 
1460*0Sstevel@tonic-gate 				return (USB_FAILURE);
1461*0Sstevel@tonic-gate 			}
1462*0Sstevel@tonic-gate 			ovp->rev = (int)value;
1463*0Sstevel@tonic-gate 		} else if (strcasecmp(input_field, "subclass") == 0) {
1464*0Sstevel@tonic-gate 			for (i = 0; i < N_SCSA2USB_SUBC_OVERRIDE; i++) {
1465*0Sstevel@tonic-gate 				if (strcasecmp(input_value,
1466*0Sstevel@tonic-gate 				    scsa2usb_subclass[i].name) == 0) {
1467*0Sstevel@tonic-gate 					ovp->subclass =
1468*0Sstevel@tonic-gate 					    scsa2usb_subclass[i].value;
1469*0Sstevel@tonic-gate 					break;
1470*0Sstevel@tonic-gate 				}
1471*0Sstevel@tonic-gate 			}
1472*0Sstevel@tonic-gate 			if (ovp->subclass == 0) {
1473*0Sstevel@tonic-gate 				scsa2usb_override_error("subclass", scsa2usbp);
1474*0Sstevel@tonic-gate 
1475*0Sstevel@tonic-gate 				return (USB_FAILURE);
1476*0Sstevel@tonic-gate 			}
1477*0Sstevel@tonic-gate 		} else if (strcasecmp(input_field, "protocol") == 0) {
1478*0Sstevel@tonic-gate 			for (i = 0; i < N_SCSA2USB_PROT_OVERRIDE; i++) {
1479*0Sstevel@tonic-gate 				if (strcasecmp(input_value,
1480*0Sstevel@tonic-gate 				    scsa2usb_protocol[i].name) == 0) {
1481*0Sstevel@tonic-gate 					ovp->protocol =
1482*0Sstevel@tonic-gate 					    scsa2usb_protocol[i].value;
1483*0Sstevel@tonic-gate 					break;
1484*0Sstevel@tonic-gate 				}
1485*0Sstevel@tonic-gate 			}
1486*0Sstevel@tonic-gate 			if (ovp->protocol == 0) {
1487*0Sstevel@tonic-gate 				scsa2usb_override_error("protocol", scsa2usbp);
1488*0Sstevel@tonic-gate 
1489*0Sstevel@tonic-gate 				return (USB_FAILURE);
1490*0Sstevel@tonic-gate 			}
1491*0Sstevel@tonic-gate 		} else if (strcasecmp(input_field, "pm") == 0) {
1492*0Sstevel@tonic-gate 			if (strcasecmp(input_value, "off") == 0) {
1493*0Sstevel@tonic-gate 				ovp->pmoff = 1;
1494*0Sstevel@tonic-gate 				break;
1495*0Sstevel@tonic-gate 			} else {
1496*0Sstevel@tonic-gate 				scsa2usb_override_error("pm", scsa2usbp);
1497*0Sstevel@tonic-gate 
1498*0Sstevel@tonic-gate 				return (USB_FAILURE);
1499*0Sstevel@tonic-gate 			}
1500*0Sstevel@tonic-gate 		} else if (strcasecmp(input_field, "removable") == 0) {
1501*0Sstevel@tonic-gate 			if (strcasecmp(input_value, "false") == 0) {
1502*0Sstevel@tonic-gate 				ovp->not_removable = 1;
1503*0Sstevel@tonic-gate 				break;
1504*0Sstevel@tonic-gate 			} else {
1505*0Sstevel@tonic-gate 				scsa2usb_override_error("removable", scsa2usbp);
1506*0Sstevel@tonic-gate 
1507*0Sstevel@tonic-gate 				return (USB_FAILURE);
1508*0Sstevel@tonic-gate 			}
1509*0Sstevel@tonic-gate 		} else if (strcasecmp(input_field, "modesense") == 0) {
1510*0Sstevel@tonic-gate 			if (strcasecmp(input_value, "false") == 0) {
1511*0Sstevel@tonic-gate 				ovp->no_modesense = 1;
1512*0Sstevel@tonic-gate 				break;
1513*0Sstevel@tonic-gate 			} else {
1514*0Sstevel@tonic-gate 				scsa2usb_override_error("modesense",
1515*0Sstevel@tonic-gate 								scsa2usbp);
1516*0Sstevel@tonic-gate 
1517*0Sstevel@tonic-gate 				return (USB_FAILURE);
1518*0Sstevel@tonic-gate 			}
1519*0Sstevel@tonic-gate 		} else if (strcasecmp(input_field,
1520*0Sstevel@tonic-gate 		    "reduced-cmd-support") == 0) {
1521*0Sstevel@tonic-gate 			if (strcasecmp(input_value, "true") == 0) {
1522*0Sstevel@tonic-gate 				ovp->reduced_cmd_support = 1;
1523*0Sstevel@tonic-gate 				break;
1524*0Sstevel@tonic-gate 			} else {
1525*0Sstevel@tonic-gate 				scsa2usb_override_error(
1526*0Sstevel@tonic-gate 				    "reduced-cmd-support", scsa2usbp);
1527*0Sstevel@tonic-gate 
1528*0Sstevel@tonic-gate 				return (USB_FAILURE);
1529*0Sstevel@tonic-gate 			}
1530*0Sstevel@tonic-gate 		} else {
1531*0Sstevel@tonic-gate 			scsa2usb_override_error("entry", scsa2usbp);
1532*0Sstevel@tonic-gate 
1533*0Sstevel@tonic-gate 			return (USB_FAILURE);
1534*0Sstevel@tonic-gate 		}
1535*0Sstevel@tonic-gate 	}
1536*0Sstevel@tonic-gate 
1537*0Sstevel@tonic-gate 	return (USB_SUCCESS);
1538*0Sstevel@tonic-gate }
1539*0Sstevel@tonic-gate 
1540*0Sstevel@tonic-gate 
1541*0Sstevel@tonic-gate /*
1542*0Sstevel@tonic-gate  * scsa2usb_override_error:
1543*0Sstevel@tonic-gate  *	print an error message if conf file string is bad format
1544*0Sstevel@tonic-gate  */
1545*0Sstevel@tonic-gate static void
1546*0Sstevel@tonic-gate scsa2usb_override_error(char *input_field, scsa2usb_state_t *scsa2usbp)
1547*0Sstevel@tonic-gate {
1548*0Sstevel@tonic-gate 	USB_DPRINTF_L1(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
1549*0Sstevel@tonic-gate 	    "invalid %s in scsa2usb conf file entry", input_field);
1550*0Sstevel@tonic-gate }
1551*0Sstevel@tonic-gate 
1552*0Sstevel@tonic-gate /*
1553*0Sstevel@tonic-gate  * scsa2usb_strtok_r:
1554*0Sstevel@tonic-gate  *	parse a list of tokens
1555*0Sstevel@tonic-gate  */
1556*0Sstevel@tonic-gate static char *
1557*0Sstevel@tonic-gate scsa2usb_strtok_r(char *p, char *sep, char **lasts)
1558*0Sstevel@tonic-gate {
1559*0Sstevel@tonic-gate 	char	*e;
1560*0Sstevel@tonic-gate 	char	*tok = NULL;
1561*0Sstevel@tonic-gate 
1562*0Sstevel@tonic-gate 	if (p == 0 || *p == 0) {
1563*0Sstevel@tonic-gate 
1564*0Sstevel@tonic-gate 		return (NULL);
1565*0Sstevel@tonic-gate 	}
1566*0Sstevel@tonic-gate 
1567*0Sstevel@tonic-gate 	e = p+strlen(p);
1568*0Sstevel@tonic-gate 
1569*0Sstevel@tonic-gate 	do {
1570*0Sstevel@tonic-gate 		if (strchr(sep, *p) != NULL) {
1571*0Sstevel@tonic-gate 			if (tok != NULL) {
1572*0Sstevel@tonic-gate 				*p = 0;
1573*0Sstevel@tonic-gate 				*lasts = p+1;
1574*0Sstevel@tonic-gate 
1575*0Sstevel@tonic-gate 				return (tok);
1576*0Sstevel@tonic-gate 			}
1577*0Sstevel@tonic-gate 		} else if (tok == NULL) {
1578*0Sstevel@tonic-gate 			tok = p;
1579*0Sstevel@tonic-gate 		}
1580*0Sstevel@tonic-gate 	} while (++p < e);
1581*0Sstevel@tonic-gate 
1582*0Sstevel@tonic-gate 	*lasts = NULL;
1583*0Sstevel@tonic-gate 
1584*0Sstevel@tonic-gate 	return (tok);
1585*0Sstevel@tonic-gate }
1586*0Sstevel@tonic-gate 
1587*0Sstevel@tonic-gate 
1588*0Sstevel@tonic-gate /*
1589*0Sstevel@tonic-gate  * scsa2usb_validate_attrs:
1590*0Sstevel@tonic-gate  *	many devices have BO/CB/CBI protocol support issues.
1591*0Sstevel@tonic-gate  *	use vendor/product info to reset the
1592*0Sstevel@tonic-gate  *	individual erroneous attributes
1593*0Sstevel@tonic-gate  *
1594*0Sstevel@tonic-gate  * NOTE: we look at only device at a time (at attach time)
1595*0Sstevel@tonic-gate  */
1596*0Sstevel@tonic-gate static void
1597*0Sstevel@tonic-gate scsa2usb_validate_attrs(scsa2usb_state_t *scsa2usbp)
1598*0Sstevel@tonic-gate {
1599*0Sstevel@tonic-gate 	int i, mask;
1600*0Sstevel@tonic-gate 	usb_dev_descr_t *desc = scsa2usbp->scsa2usb_dev_data->dev_descr;
1601*0Sstevel@tonic-gate 
1602*0Sstevel@tonic-gate 	if (!SCSA2USB_IS_BULK_ONLY(scsa2usbp)) {
1603*0Sstevel@tonic-gate 		scsa2usbp->scsa2usb_attrs &= ~SCSA2USB_ATTRS_GET_LUN;
1604*0Sstevel@tonic-gate 	}
1605*0Sstevel@tonic-gate 
1606*0Sstevel@tonic-gate 	/* determine if this device is on the blacklist */
1607*0Sstevel@tonic-gate 	for (i = 0; i < N_SCSA2USB_BLACKLIST; i++) {
1608*0Sstevel@tonic-gate 		if ((scsa2usb_blacklist[i].idVendor == desc->idVendor) &&
1609*0Sstevel@tonic-gate 		    ((scsa2usb_blacklist[i].idProduct == desc->idProduct) ||
1610*0Sstevel@tonic-gate 		    (scsa2usb_blacklist[i].idProduct == X))) {
1611*0Sstevel@tonic-gate 			scsa2usbp->scsa2usb_attrs &=
1612*0Sstevel@tonic-gate 				~(scsa2usb_blacklist[i].attributes);
1613*0Sstevel@tonic-gate 			break;
1614*0Sstevel@tonic-gate 		}
1615*0Sstevel@tonic-gate 	}
1616*0Sstevel@tonic-gate 
1617*0Sstevel@tonic-gate 	/*
1618*0Sstevel@tonic-gate 	 * Mitsumi's CD-RW drives subclass isn't UFI.
1619*0Sstevel@tonic-gate 	 * But they support UFI command-set (this code ensures that)
1620*0Sstevel@tonic-gate 	 * NOTE: This is a special case, and is being called out so.
1621*0Sstevel@tonic-gate 	 */
1622*0Sstevel@tonic-gate 	if (desc->idVendor == MS_MITSUMI_VID) {
1623*0Sstevel@tonic-gate 		mask = scsa2usbp->scsa2usb_cmd_protocol & SCSA2USB_CMDSET_MASK;
1624*0Sstevel@tonic-gate 		if (mask) {
1625*0Sstevel@tonic-gate 			scsa2usbp->scsa2usb_cmd_protocol &= ~mask;
1626*0Sstevel@tonic-gate 		}
1627*0Sstevel@tonic-gate 		scsa2usbp->scsa2usb_cmd_protocol |= SCSA2USB_UFI_CMDSET;
1628*0Sstevel@tonic-gate 	}
1629*0Sstevel@tonic-gate 
1630*0Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_attrs != SCSA2USB_ALL_ATTRS) {
1631*0Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA,
1632*0Sstevel@tonic-gate 		    scsa2usbp->scsa2usb_log_handle,
1633*0Sstevel@tonic-gate 		    "scsa2usb attributes modified: 0x%x",
1634*0Sstevel@tonic-gate 		    scsa2usbp->scsa2usb_attrs);
1635*0Sstevel@tonic-gate 	}
1636*0Sstevel@tonic-gate }
1637*0Sstevel@tonic-gate 
1638*0Sstevel@tonic-gate 
1639*0Sstevel@tonic-gate /*
1640*0Sstevel@tonic-gate  * scsa2usb_create_luns:
1641*0Sstevel@tonic-gate  *	check the number of luns but continue if the check fails,
1642*0Sstevel@tonic-gate  *	create child nodes for each lun
1643*0Sstevel@tonic-gate  */
1644*0Sstevel@tonic-gate static void
1645*0Sstevel@tonic-gate scsa2usb_create_luns(scsa2usb_state_t *scsa2usbp)
1646*0Sstevel@tonic-gate {
1647*0Sstevel@tonic-gate 	int		lun, rval;
1648*0Sstevel@tonic-gate 	char		*compatible[MAX_COMPAT_NAMES];	/* compatible names */
1649*0Sstevel@tonic-gate 	dev_info_t	*cdip;
1650*0Sstevel@tonic-gate 	uchar_t		dtype;
1651*0Sstevel@tonic-gate 	char		*node_name;
1652*0Sstevel@tonic-gate 	char		*driver_name = NULL;
1653*0Sstevel@tonic-gate 
1654*0Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
1655*0Sstevel@tonic-gate 	    "scsa2usb_create_luns:");
1656*0Sstevel@tonic-gate 
1657*0Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
1658*0Sstevel@tonic-gate 
1659*0Sstevel@tonic-gate 	/* Set n_luns to 1 by default (for floppies and other devices) */
1660*0Sstevel@tonic-gate 	scsa2usbp->scsa2usb_n_luns = 1;
1661*0Sstevel@tonic-gate 
1662*0Sstevel@tonic-gate 	/*
1663*0Sstevel@tonic-gate 	 * Check if there are any device out there which don't
1664*0Sstevel@tonic-gate 	 * support the GET_MAX_LUN command. If so, don't issue
1665*0Sstevel@tonic-gate 	 * control request to them.
1666*0Sstevel@tonic-gate 	 */
1667*0Sstevel@tonic-gate 	if ((scsa2usbp->scsa2usb_attrs & SCSA2USB_ATTRS_GET_LUN) == 0) {
1668*0Sstevel@tonic-gate 		USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
1669*0Sstevel@tonic-gate 		    "get_max_lun cmd not supported");
1670*0Sstevel@tonic-gate 	} else {
1671*0Sstevel@tonic-gate 		if (SCSA2USB_IS_BULK_ONLY(scsa2usbp)) {
1672*0Sstevel@tonic-gate 			scsa2usbp->scsa2usb_n_luns =
1673*0Sstevel@tonic-gate 				scsa2usb_bulk_only_get_max_lun(scsa2usbp);
1674*0Sstevel@tonic-gate 		}
1675*0Sstevel@tonic-gate 	}
1676*0Sstevel@tonic-gate 
1677*0Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
1678*0Sstevel@tonic-gate 	    "scsa2usb_create_luns: %d luns found", scsa2usbp->scsa2usb_n_luns);
1679*0Sstevel@tonic-gate 
1680*0Sstevel@tonic-gate 	/*
1681*0Sstevel@tonic-gate 	 * create disk child for each lun
1682*0Sstevel@tonic-gate 	 */
1683*0Sstevel@tonic-gate 	for (lun = 0; lun < scsa2usbp->scsa2usb_n_luns; lun++) {
1684*0Sstevel@tonic-gate 		ASSERT(scsa2usbp->scsa2usb_lun_dip[lun] == NULL);
1685*0Sstevel@tonic-gate 
1686*0Sstevel@tonic-gate 		/* do an inquiry to get the dtype of this lun */
1687*0Sstevel@tonic-gate 		scsa2usb_do_inquiry(scsa2usbp, 0, lun);
1688*0Sstevel@tonic-gate 
1689*0Sstevel@tonic-gate 		dtype = scsa2usbp->scsa2usb_lun_inquiry[lun].
1690*0Sstevel@tonic-gate 						inq_dtype & DTYPE_MASK;
1691*0Sstevel@tonic-gate 
1692*0Sstevel@tonic-gate 		USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
1693*0Sstevel@tonic-gate 		    "dtype[%d]=0x%x", lun, dtype);
1694*0Sstevel@tonic-gate 
1695*0Sstevel@tonic-gate 		driver_name = NULL;
1696*0Sstevel@tonic-gate 
1697*0Sstevel@tonic-gate 		switch (dtype) {
1698*0Sstevel@tonic-gate 		case DTYPE_DIRECT:
1699*0Sstevel@tonic-gate 		case DTYPE_RODIRECT:
1700*0Sstevel@tonic-gate 		case DTYPE_OPTICAL:
1701*0Sstevel@tonic-gate 			node_name = "disk";
1702*0Sstevel@tonic-gate 			driver_name = "sd";
1703*0Sstevel@tonic-gate 
1704*0Sstevel@tonic-gate 			break;
1705*0Sstevel@tonic-gate 		case DTYPE_SEQUENTIAL:
1706*0Sstevel@tonic-gate 			node_name = "tape";
1707*0Sstevel@tonic-gate 			driver_name = "st";
1708*0Sstevel@tonic-gate 
1709*0Sstevel@tonic-gate 			break;
1710*0Sstevel@tonic-gate 		case DTYPE_PRINTER:
1711*0Sstevel@tonic-gate 			node_name = "printer";
1712*0Sstevel@tonic-gate 
1713*0Sstevel@tonic-gate 			break;
1714*0Sstevel@tonic-gate 		case DTYPE_PROCESSOR:
1715*0Sstevel@tonic-gate 			node_name = "processor";
1716*0Sstevel@tonic-gate 
1717*0Sstevel@tonic-gate 			break;
1718*0Sstevel@tonic-gate 		case DTYPE_WORM:
1719*0Sstevel@tonic-gate 			node_name = "worm";
1720*0Sstevel@tonic-gate 
1721*0Sstevel@tonic-gate 			break;
1722*0Sstevel@tonic-gate 		case DTYPE_SCANNER:
1723*0Sstevel@tonic-gate 			node_name = "scanner";
1724*0Sstevel@tonic-gate 
1725*0Sstevel@tonic-gate 			break;
1726*0Sstevel@tonic-gate 		case DTYPE_CHANGER:
1727*0Sstevel@tonic-gate 			node_name = "changer";
1728*0Sstevel@tonic-gate 
1729*0Sstevel@tonic-gate 			break;
1730*0Sstevel@tonic-gate 		case DTYPE_COMM:
1731*0Sstevel@tonic-gate 			node_name = "comm";
1732*0Sstevel@tonic-gate 
1733*0Sstevel@tonic-gate 			break;
1734*0Sstevel@tonic-gate 		case DTYPE_ARRAY_CTRL:
1735*0Sstevel@tonic-gate 			node_name = "array_ctrl";
1736*0Sstevel@tonic-gate 
1737*0Sstevel@tonic-gate 			break;
1738*0Sstevel@tonic-gate 		case DTYPE_ESI:
1739*0Sstevel@tonic-gate 			node_name = "esi";
1740*0Sstevel@tonic-gate 			driver_name = "ses";
1741*0Sstevel@tonic-gate 
1742*0Sstevel@tonic-gate 			break;
1743*0Sstevel@tonic-gate 		default:
1744*0Sstevel@tonic-gate 			node_name = "generic";
1745*0Sstevel@tonic-gate 
1746*0Sstevel@tonic-gate 			break;
1747*0Sstevel@tonic-gate 		}
1748*0Sstevel@tonic-gate 
1749*0Sstevel@tonic-gate 		if (driver_name) {
1750*0Sstevel@tonic-gate 			compatible[0] = driver_name;
1751*0Sstevel@tonic-gate 		}
1752*0Sstevel@tonic-gate 
1753*0Sstevel@tonic-gate 		ndi_devi_alloc_sleep(scsa2usbp->scsa2usb_dip, node_name,
1754*0Sstevel@tonic-gate 		    (dnode_t)DEVI_SID_NODEID, &cdip);
1755*0Sstevel@tonic-gate 
1756*0Sstevel@tonic-gate 		/* attach target & lun properties */
1757*0Sstevel@tonic-gate 		rval = ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "target", 0);
1758*0Sstevel@tonic-gate 		if (rval != DDI_PROP_SUCCESS) {
1759*0Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_SCSA,
1760*0Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
1761*0Sstevel@tonic-gate 			    "ndi_prop_update_int target failed %d", rval);
1762*0Sstevel@tonic-gate 			(void) ndi_devi_free(cdip);
1763*0Sstevel@tonic-gate 			continue;
1764*0Sstevel@tonic-gate 		}
1765*0Sstevel@tonic-gate 
1766*0Sstevel@tonic-gate 		rval = ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "lun", lun);
1767*0Sstevel@tonic-gate 		if (rval != DDI_PROP_SUCCESS) {
1768*0Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_SCSA,
1769*0Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
1770*0Sstevel@tonic-gate 			    "ndi_prop_update_int lun failed %d", rval);
1771*0Sstevel@tonic-gate 			ddi_prop_remove_all(cdip);
1772*0Sstevel@tonic-gate 			(void) ndi_devi_free(cdip);
1773*0Sstevel@tonic-gate 			continue;
1774*0Sstevel@tonic-gate 		}
1775*0Sstevel@tonic-gate 
1776*0Sstevel@tonic-gate 		if (driver_name) {
1777*0Sstevel@tonic-gate 			rval = ndi_prop_update_string_array(DDI_DEV_T_NONE,
1778*0Sstevel@tonic-gate 			    cdip, "compatible", (char **)compatible,
1779*0Sstevel@tonic-gate 			    MAX_COMPAT_NAMES);
1780*0Sstevel@tonic-gate 			if (rval != DDI_PROP_SUCCESS) {
1781*0Sstevel@tonic-gate 				USB_DPRINTF_L2(DPRINT_MASK_SCSA,
1782*0Sstevel@tonic-gate 				    scsa2usbp->scsa2usb_log_handle,
1783*0Sstevel@tonic-gate 				    "ndi_prop_update_string_array failed %d",
1784*0Sstevel@tonic-gate 				    rval);
1785*0Sstevel@tonic-gate 				ddi_prop_remove_all(cdip);
1786*0Sstevel@tonic-gate 				(void) ndi_devi_free(cdip);
1787*0Sstevel@tonic-gate 				continue;
1788*0Sstevel@tonic-gate 			}
1789*0Sstevel@tonic-gate 		}
1790*0Sstevel@tonic-gate 
1791*0Sstevel@tonic-gate 		/*
1792*0Sstevel@tonic-gate 		 * add property "usb" so we always verify that it is our child
1793*0Sstevel@tonic-gate 		 */
1794*0Sstevel@tonic-gate 		rval = ndi_prop_create_boolean(DDI_DEV_T_NONE, cdip, "usb");
1795*0Sstevel@tonic-gate 		if (rval != DDI_PROP_SUCCESS) {
1796*0Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_SCSA,
1797*0Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
1798*0Sstevel@tonic-gate 			    "ndi_prop_create_boolean failed %d", rval);
1799*0Sstevel@tonic-gate 			ddi_prop_remove_all(cdip);
1800*0Sstevel@tonic-gate 			(void) ndi_devi_free(cdip);
1801*0Sstevel@tonic-gate 			continue;
1802*0Sstevel@tonic-gate 		}
1803*0Sstevel@tonic-gate 
1804*0Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
1805*0Sstevel@tonic-gate 		(void) ddi_initchild(scsa2usbp->scsa2usb_dip, cdip);
1806*0Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
1807*0Sstevel@tonic-gate 
1808*0Sstevel@tonic-gate 		usba_set_usba_device(cdip,
1809*0Sstevel@tonic-gate 			usba_get_usba_device(scsa2usbp->scsa2usb_dip));
1810*0Sstevel@tonic-gate 	}
1811*0Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
1812*0Sstevel@tonic-gate }
1813*0Sstevel@tonic-gate 
1814*0Sstevel@tonic-gate 
1815*0Sstevel@tonic-gate /*
1816*0Sstevel@tonic-gate  * scsa2usb_is_usb:
1817*0Sstevel@tonic-gate  *	scsa2usb gets called for all possible sd children.
1818*0Sstevel@tonic-gate  *	we can only accept usb children
1819*0Sstevel@tonic-gate  */
1820*0Sstevel@tonic-gate static int
1821*0Sstevel@tonic-gate scsa2usb_is_usb(dev_info_t *dip)
1822*0Sstevel@tonic-gate {
1823*0Sstevel@tonic-gate 	if (dip) {
1824*0Sstevel@tonic-gate 		return (ddi_prop_exists(DDI_DEV_T_ANY, dip,
1825*0Sstevel@tonic-gate 		    DDI_PROP_DONTPASS, "usb"));
1826*0Sstevel@tonic-gate 	}
1827*0Sstevel@tonic-gate 	return (0);
1828*0Sstevel@tonic-gate }
1829*0Sstevel@tonic-gate 
1830*0Sstevel@tonic-gate 
1831*0Sstevel@tonic-gate /*
1832*0Sstevel@tonic-gate  * Panic Stuff
1833*0Sstevel@tonic-gate  * scsa2usb_panic_callb_init:
1834*0Sstevel@tonic-gate  *	initialize PANIC callb and free allocated resources
1835*0Sstevel@tonic-gate  */
1836*0Sstevel@tonic-gate static void
1837*0Sstevel@tonic-gate scsa2usb_panic_callb_init(scsa2usb_state_t *scsa2usbp)
1838*0Sstevel@tonic-gate {
1839*0Sstevel@tonic-gate 	/*
1840*0Sstevel@tonic-gate 	 * In case the system panics, the sync command flushes
1841*0Sstevel@tonic-gate 	 * dirty FS pages or buffers. This would cause a hang
1842*0Sstevel@tonic-gate 	 * in USB.
1843*0Sstevel@tonic-gate 	 * The reason for the failure is that we enter
1844*0Sstevel@tonic-gate 	 * polled mode (interrupts disabled) and HCD gets stuck
1845*0Sstevel@tonic-gate 	 * trying to execute bulk requests
1846*0Sstevel@tonic-gate 	 * The panic_callback registered below provides a warning
1847*0Sstevel@tonic-gate 	 * that a panic has occurred and from that point onwards, we
1848*0Sstevel@tonic-gate 	 * complete each request successfully and immediately. This
1849*0Sstevel@tonic-gate 	 * will fake successful syncing so at least the rest of the
1850*0Sstevel@tonic-gate 	 * filesystems complete syncing.
1851*0Sstevel@tonic-gate 	 */
1852*0Sstevel@tonic-gate 	scsa2usbp->scsa2usb_panic_info =
1853*0Sstevel@tonic-gate 		kmem_zalloc(sizeof (scsa2usb_cpr_t), KM_SLEEP);
1854*0Sstevel@tonic-gate 	mutex_init(&scsa2usbp->scsa2usb_panic_info->lockp,
1855*0Sstevel@tonic-gate 		NULL, MUTEX_DRIVER,
1856*0Sstevel@tonic-gate 		scsa2usbp->scsa2usb_dev_data->dev_iblock_cookie);
1857*0Sstevel@tonic-gate 	scsa2usbp->scsa2usb_panic_info->statep = scsa2usbp;
1858*0Sstevel@tonic-gate 	scsa2usbp->scsa2usb_panic_info->cpr.cc_lockp =
1859*0Sstevel@tonic-gate 				&scsa2usbp->scsa2usb_panic_info->lockp;
1860*0Sstevel@tonic-gate 	scsa2usbp->scsa2usb_panic_info->cpr.cc_id =
1861*0Sstevel@tonic-gate 			callb_add(scsa2usb_panic_callb,
1862*0Sstevel@tonic-gate 			    (void *)scsa2usbp->scsa2usb_panic_info,
1863*0Sstevel@tonic-gate 			    CB_CL_PANIC, "scsa2usb");
1864*0Sstevel@tonic-gate }
1865*0Sstevel@tonic-gate 
1866*0Sstevel@tonic-gate 
1867*0Sstevel@tonic-gate /*
1868*0Sstevel@tonic-gate  * scsa2usb_panic_callb_fini:
1869*0Sstevel@tonic-gate  *	cancel out PANIC callb and free allocated resources
1870*0Sstevel@tonic-gate  */
1871*0Sstevel@tonic-gate static void
1872*0Sstevel@tonic-gate scsa2usb_panic_callb_fini(scsa2usb_state_t *scsa2usbp)
1873*0Sstevel@tonic-gate {
1874*0Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_panic_info) {
1875*0Sstevel@tonic-gate 		SCSA2USB_CANCEL_CB(scsa2usbp->scsa2usb_panic_info->cpr.cc_id);
1876*0Sstevel@tonic-gate 		mutex_destroy(&scsa2usbp->scsa2usb_panic_info->lockp);
1877*0Sstevel@tonic-gate 		scsa2usbp->scsa2usb_panic_info->statep = NULL;
1878*0Sstevel@tonic-gate 		kmem_free(scsa2usbp->scsa2usb_panic_info,
1879*0Sstevel@tonic-gate 		    sizeof (scsa2usb_cpr_t));
1880*0Sstevel@tonic-gate 		scsa2usbp->scsa2usb_panic_info = NULL;
1881*0Sstevel@tonic-gate 	}
1882*0Sstevel@tonic-gate }
1883*0Sstevel@tonic-gate 
1884*0Sstevel@tonic-gate 
1885*0Sstevel@tonic-gate /*
1886*0Sstevel@tonic-gate  * scsa2usb_panic_callb:
1887*0Sstevel@tonic-gate  *	This routine is called when there is a system panic.
1888*0Sstevel@tonic-gate  */
1889*0Sstevel@tonic-gate /* ARGSUSED */
1890*0Sstevel@tonic-gate static boolean_t
1891*0Sstevel@tonic-gate scsa2usb_panic_callb(void *arg, int code)
1892*0Sstevel@tonic-gate {
1893*0Sstevel@tonic-gate 	scsa2usb_cpr_t *cpr_infop;
1894*0Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp;
1895*0Sstevel@tonic-gate 	uint_t		lun;
1896*0Sstevel@tonic-gate 
1897*0Sstevel@tonic-gate 	_NOTE(NO_COMPETING_THREADS_NOW);
1898*0Sstevel@tonic-gate 	cpr_infop = (scsa2usb_cpr_t *)arg;
1899*0Sstevel@tonic-gate 	scsa2usbp = (scsa2usb_state_t *)cpr_infop->statep;
1900*0Sstevel@tonic-gate 
1901*0Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
1902*0Sstevel@tonic-gate 	    "scsa2usb_panic_callb: code=%d", code);
1903*0Sstevel@tonic-gate 
1904*0Sstevel@tonic-gate 	/*
1905*0Sstevel@tonic-gate 	 * If we return error here, "sd" prints lots of error
1906*0Sstevel@tonic-gate 	 * messages and could retry the same pkt over and over again.
1907*0Sstevel@tonic-gate 	 * The sync recovery isn't "smooth" in that case. By faking
1908*0Sstevel@tonic-gate 	 * a success return, instead,  we force sync to complete.
1909*0Sstevel@tonic-gate 	 */
1910*0Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_cur_pkt) {
1911*0Sstevel@tonic-gate 		/*
1912*0Sstevel@tonic-gate 		 * Do not print the "no sync" warning here. it will then be
1913*0Sstevel@tonic-gate 		 * displayed before we actually start syncing. Also we don't
1914*0Sstevel@tonic-gate 		 * replace this code with a call to scsa2usb_pkt_completion().
1915*0Sstevel@tonic-gate 		 * NOTE: mutexes are disabled during panic.
1916*0Sstevel@tonic-gate 		 */
1917*0Sstevel@tonic-gate 		scsa2usbp->scsa2usb_cur_pkt->pkt_reason = CMD_CMPLT;
1918*0Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
1919*0Sstevel@tonic-gate 		scsa2usb_pkt_completion(scsa2usbp, scsa2usbp->scsa2usb_cur_pkt);
1920*0Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
1921*0Sstevel@tonic-gate 	}
1922*0Sstevel@tonic-gate 
1923*0Sstevel@tonic-gate 	/* get rid of waitQ */
1924*0Sstevel@tonic-gate 	for (lun = 0; lun < SCSA2USB_MAX_LUNS; lun++) {
1925*0Sstevel@tonic-gate 		scsa2usb_flush_waitQ(scsa2usbp, lun, CMD_CMPLT);
1926*0Sstevel@tonic-gate 	}
1927*0Sstevel@tonic-gate 
1928*0Sstevel@tonic-gate 	_NOTE(COMPETING_THREADS_NOW);
1929*0Sstevel@tonic-gate 
1930*0Sstevel@tonic-gate 	return (B_TRUE);
1931*0Sstevel@tonic-gate }
1932*0Sstevel@tonic-gate 
1933*0Sstevel@tonic-gate /*
1934*0Sstevel@tonic-gate  * scsa2usb_cpr_suspend
1935*0Sstevel@tonic-gate  *	determine if the device's state can be changed to SUSPENDED
1936*0Sstevel@tonic-gate  *	close pipes if there is no activity
1937*0Sstevel@tonic-gate  */
1938*0Sstevel@tonic-gate /* ARGSUSED */
1939*0Sstevel@tonic-gate static int
1940*0Sstevel@tonic-gate scsa2usb_cpr_suspend(dev_info_t *dip)
1941*0Sstevel@tonic-gate {
1942*0Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp;
1943*0Sstevel@tonic-gate 	int	prev_state;
1944*0Sstevel@tonic-gate 	int	rval = USB_FAILURE;
1945*0Sstevel@tonic-gate 
1946*0Sstevel@tonic-gate 	scsa2usbp = ddi_get_soft_state(scsa2usb_statep, ddi_get_instance(dip));
1947*0Sstevel@tonic-gate 
1948*0Sstevel@tonic-gate 	ASSERT(scsa2usbp != NULL);
1949*0Sstevel@tonic-gate 
1950*0Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
1951*0Sstevel@tonic-gate 	    "scsa2usb_cpr_suspend:");
1952*0Sstevel@tonic-gate 
1953*0Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
1954*0Sstevel@tonic-gate 	switch (scsa2usbp->scsa2usb_dev_state) {
1955*0Sstevel@tonic-gate 	case USB_DEV_ONLINE:
1956*0Sstevel@tonic-gate 	case USB_DEV_PWRED_DOWN:
1957*0Sstevel@tonic-gate 	case USB_DEV_DISCONNECTED:
1958*0Sstevel@tonic-gate 		prev_state = scsa2usbp->scsa2usb_dev_state;
1959*0Sstevel@tonic-gate 		scsa2usbp->scsa2usb_dev_state = USB_DEV_SUSPENDED;
1960*0Sstevel@tonic-gate 
1961*0Sstevel@tonic-gate 		/*
1962*0Sstevel@tonic-gate 		 * If the device is busy, we cannot suspend
1963*0Sstevel@tonic-gate 		 */
1964*0Sstevel@tonic-gate 		if (SCSA2USB_BUSY(scsa2usbp)) {
1965*0Sstevel@tonic-gate 			USB_DPRINTF_L3(DPRINT_MASK_SCSA,
1966*0Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
1967*0Sstevel@tonic-gate 			    "scsa2usb_cpr_suspend: I/O active");
1968*0Sstevel@tonic-gate 
1969*0Sstevel@tonic-gate 			/* fall back to previous state */
1970*0Sstevel@tonic-gate 			scsa2usbp->scsa2usb_dev_state = prev_state;
1971*0Sstevel@tonic-gate 		} else {
1972*0Sstevel@tonic-gate 			rval = USB_SUCCESS;
1973*0Sstevel@tonic-gate 		}
1974*0Sstevel@tonic-gate 
1975*0Sstevel@tonic-gate 		break;
1976*0Sstevel@tonic-gate 	case USB_DEV_SUSPENDED:
1977*0Sstevel@tonic-gate 	default:
1978*0Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
1979*0Sstevel@tonic-gate 		    "scsa2usb_cpr_suspend: Illegal dev state: %d",
1980*0Sstevel@tonic-gate 		    scsa2usbp->scsa2usb_dev_state);
1981*0Sstevel@tonic-gate 
1982*0Sstevel@tonic-gate 		break;
1983*0Sstevel@tonic-gate 	}
1984*0Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
1985*0Sstevel@tonic-gate 
1986*0Sstevel@tonic-gate 	if ((rval == USB_SUCCESS) && scsa2usbp->scsa2usb_ugen_hdl) {
1987*0Sstevel@tonic-gate 		rval = usb_ugen_detach(scsa2usbp->scsa2usb_ugen_hdl,
1988*0Sstevel@tonic-gate 							DDI_SUSPEND);
1989*0Sstevel@tonic-gate 	}
1990*0Sstevel@tonic-gate 
1991*0Sstevel@tonic-gate 	return (rval);
1992*0Sstevel@tonic-gate }
1993*0Sstevel@tonic-gate 
1994*0Sstevel@tonic-gate 
1995*0Sstevel@tonic-gate /*
1996*0Sstevel@tonic-gate  * scsa2usb_cpr_resume:
1997*0Sstevel@tonic-gate  *	restore device's state
1998*0Sstevel@tonic-gate  */
1999*0Sstevel@tonic-gate static void
2000*0Sstevel@tonic-gate scsa2usb_cpr_resume(dev_info_t *dip)
2001*0Sstevel@tonic-gate {
2002*0Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp =
2003*0Sstevel@tonic-gate 	    ddi_get_soft_state(scsa2usb_statep, ddi_get_instance(dip));
2004*0Sstevel@tonic-gate 
2005*0Sstevel@tonic-gate 	ASSERT(scsa2usbp != NULL);
2006*0Sstevel@tonic-gate 
2007*0Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
2008*0Sstevel@tonic-gate 	    "scsa2usb_cpr_resume: dip = 0x%p", dip);
2009*0Sstevel@tonic-gate 
2010*0Sstevel@tonic-gate 	scsa2usb_restore_device_state(dip, scsa2usbp);
2011*0Sstevel@tonic-gate 
2012*0Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_ugen_hdl) {
2013*0Sstevel@tonic-gate 		(void) usb_ugen_attach(scsa2usbp->scsa2usb_ugen_hdl,
2014*0Sstevel@tonic-gate 							DDI_RESUME);
2015*0Sstevel@tonic-gate 	}
2016*0Sstevel@tonic-gate }
2017*0Sstevel@tonic-gate 
2018*0Sstevel@tonic-gate 
2019*0Sstevel@tonic-gate /*
2020*0Sstevel@tonic-gate  * scsa2usb_restore_device_state:
2021*0Sstevel@tonic-gate  *	- raise the device's power
2022*0Sstevel@tonic-gate  *	- reopen all the pipes
2023*0Sstevel@tonic-gate  */
2024*0Sstevel@tonic-gate static void
2025*0Sstevel@tonic-gate scsa2usb_restore_device_state(dev_info_t *dip, scsa2usb_state_t *scsa2usbp)
2026*0Sstevel@tonic-gate {
2027*0Sstevel@tonic-gate 	uint_t	prev_state;
2028*0Sstevel@tonic-gate 
2029*0Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
2030*0Sstevel@tonic-gate 	    "scsa2usb_restore_device_state:");
2031*0Sstevel@tonic-gate 
2032*0Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
2033*0Sstevel@tonic-gate 	prev_state = scsa2usbp->scsa2usb_dev_state;
2034*0Sstevel@tonic-gate 
2035*0Sstevel@tonic-gate 	scsa2usb_raise_power(scsa2usbp);
2036*0Sstevel@tonic-gate 
2037*0Sstevel@tonic-gate 	ASSERT((prev_state == USB_DEV_DISCONNECTED) ||
2038*0Sstevel@tonic-gate 	    (prev_state == USB_DEV_SUSPENDED));
2039*0Sstevel@tonic-gate 
2040*0Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
2041*0Sstevel@tonic-gate 
2042*0Sstevel@tonic-gate 	/* Check for the same device */
2043*0Sstevel@tonic-gate 	if (usb_check_same_device(dip, scsa2usbp->scsa2usb_log_handle,
2044*0Sstevel@tonic-gate 	    USB_LOG_L0, DPRINT_MASK_ALL, USB_CHK_ALL, NULL) != USB_SUCCESS) {
2045*0Sstevel@tonic-gate 
2046*0Sstevel@tonic-gate 		/* change the flags to active */
2047*0Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
2048*0Sstevel@tonic-gate 		scsa2usbp->scsa2usb_dev_state = USB_DEV_DISCONNECTED;
2049*0Sstevel@tonic-gate 
2050*0Sstevel@tonic-gate 		scsa2usb_pm_idle_component(scsa2usbp);
2051*0Sstevel@tonic-gate 
2052*0Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
2053*0Sstevel@tonic-gate 
2054*0Sstevel@tonic-gate 		return;
2055*0Sstevel@tonic-gate 	}
2056*0Sstevel@tonic-gate 
2057*0Sstevel@tonic-gate 	USB_DPRINTF_L0(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
2058*0Sstevel@tonic-gate 	    "Reinserted device is accessible again.");
2059*0Sstevel@tonic-gate 
2060*0Sstevel@tonic-gate 	/*
2061*0Sstevel@tonic-gate 	 * if the device had remote wakeup earlier,
2062*0Sstevel@tonic-gate 	 * enable it again
2063*0Sstevel@tonic-gate 	 */
2064*0Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
2065*0Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_pm &&
2066*0Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_pm->scsa2usb_wakeup_enabled) {
2067*0Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
2068*0Sstevel@tonic-gate 		(void) usb_handle_remote_wakeup(scsa2usbp->scsa2usb_dip,
2069*0Sstevel@tonic-gate 		    USB_REMOTE_WAKEUP_ENABLE);
2070*0Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
2071*0Sstevel@tonic-gate 	}
2072*0Sstevel@tonic-gate 
2073*0Sstevel@tonic-gate 	scsa2usbp->scsa2usb_dev_state = USB_DEV_ONLINE;
2074*0Sstevel@tonic-gate 	scsa2usbp->scsa2usb_pkt_state = SCSA2USB_PKT_NONE;
2075*0Sstevel@tonic-gate 
2076*0Sstevel@tonic-gate 	scsa2usb_pm_idle_component(scsa2usbp);
2077*0Sstevel@tonic-gate 
2078*0Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
2079*0Sstevel@tonic-gate }
2080*0Sstevel@tonic-gate 
2081*0Sstevel@tonic-gate 
2082*0Sstevel@tonic-gate /*
2083*0Sstevel@tonic-gate  * SCSA entry points:
2084*0Sstevel@tonic-gate  *
2085*0Sstevel@tonic-gate  * scsa2usb_scsi_tgt_probe:
2086*0Sstevel@tonic-gate  * scsa functions are exported by means of the transport table
2087*0Sstevel@tonic-gate  * Issue a probe to get the inquiry data.
2088*0Sstevel@tonic-gate  */
2089*0Sstevel@tonic-gate /* ARGSUSED */
2090*0Sstevel@tonic-gate static int
2091*0Sstevel@tonic-gate scsa2usb_scsi_tgt_probe(struct scsi_device *sd, int (*waitfunc)(void))
2092*0Sstevel@tonic-gate {
2093*0Sstevel@tonic-gate 	scsi_hba_tran_t *tran;
2094*0Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp;
2095*0Sstevel@tonic-gate 	dev_info_t *dip = ddi_get_parent(sd->sd_dev);
2096*0Sstevel@tonic-gate 	int rval;
2097*0Sstevel@tonic-gate 
2098*0Sstevel@tonic-gate 	ASSERT(dip);
2099*0Sstevel@tonic-gate 
2100*0Sstevel@tonic-gate 	tran = ddi_get_driver_private(dip);
2101*0Sstevel@tonic-gate 	ASSERT(tran != NULL);
2102*0Sstevel@tonic-gate 	scsa2usbp = (scsa2usb_state_t *)tran->tran_hba_private;
2103*0Sstevel@tonic-gate 	ASSERT(scsa2usbp);
2104*0Sstevel@tonic-gate 
2105*0Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
2106*0Sstevel@tonic-gate 	    "scsa2usb_scsi_tgt_probe:");
2107*0Sstevel@tonic-gate 
2108*0Sstevel@tonic-gate 	/* if device is disconnected (ie. pipes closed), fail immediately */
2109*0Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
2110*0Sstevel@tonic-gate 	if (!(SCSA2USB_DEVICE_ACCESS_OK(scsa2usbp))) {
2111*0Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
2112*0Sstevel@tonic-gate 
2113*0Sstevel@tonic-gate 		return (SCSIPROBE_FAILURE);
2114*0Sstevel@tonic-gate 	}
2115*0Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
2116*0Sstevel@tonic-gate 
2117*0Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
2118*0Sstevel@tonic-gate 	    "scsa2usb_scsi_tgt_probe: scsi_device = 0x%p", sd);
2119*0Sstevel@tonic-gate 
2120*0Sstevel@tonic-gate 	if ((rval = scsi_hba_probe(sd, waitfunc)) == SCSIPROBE_EXISTS) {
2121*0Sstevel@tonic-gate 		/*
2122*0Sstevel@tonic-gate 		 * fake the removable bit on all USB storage devices
2123*0Sstevel@tonic-gate 		 * unless overridden by a scsa2usb.conf entry
2124*0Sstevel@tonic-gate 		 */
2125*0Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
2126*0Sstevel@tonic-gate 		if (scsa2usbp->scsa2usb_attrs & SCSA2USB_ATTRS_RMB) {
2127*0Sstevel@tonic-gate 			_NOTE(SCHEME_PROTECTS_DATA("unshared", scsi_inquiry))
2128*0Sstevel@tonic-gate 			sd->sd_inq->inq_rmb = 1;
2129*0Sstevel@tonic-gate 		}
2130*0Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
2131*0Sstevel@tonic-gate 	}
2132*0Sstevel@tonic-gate 
2133*0Sstevel@tonic-gate 	return (rval);
2134*0Sstevel@tonic-gate }
2135*0Sstevel@tonic-gate 
2136*0Sstevel@tonic-gate 
2137*0Sstevel@tonic-gate /*
2138*0Sstevel@tonic-gate  * scsa2usb_scsi_tgt_init:
2139*0Sstevel@tonic-gate  *	check whether we created this child ourselves
2140*0Sstevel@tonic-gate  */
2141*0Sstevel@tonic-gate /* ARGSUSED */
2142*0Sstevel@tonic-gate static int
2143*0Sstevel@tonic-gate scsa2usb_scsi_tgt_init(dev_info_t *dip, dev_info_t *cdip,
2144*0Sstevel@tonic-gate     scsi_hba_tran_t *tran, struct scsi_device *sd)
2145*0Sstevel@tonic-gate {
2146*0Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp = (scsa2usb_state_t *)
2147*0Sstevel@tonic-gate 					tran->tran_hba_private;
2148*0Sstevel@tonic-gate 	int lun;
2149*0Sstevel@tonic-gate 	int t_len = sizeof (lun);
2150*0Sstevel@tonic-gate 
2151*0Sstevel@tonic-gate 	if (ddi_prop_op(DDI_DEV_T_ANY, cdip, PROP_LEN_AND_VAL_BUF,
2152*0Sstevel@tonic-gate 	    DDI_PROP_DONTPASS|DDI_PROP_CANSLEEP, "lun", (caddr_t)&lun,
2153*0Sstevel@tonic-gate 	    &t_len) != DDI_PROP_SUCCESS) {
2154*0Sstevel@tonic-gate 
2155*0Sstevel@tonic-gate 		return (DDI_FAILURE);
2156*0Sstevel@tonic-gate 	}
2157*0Sstevel@tonic-gate 
2158*0Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
2159*0Sstevel@tonic-gate 	    "scsa2usb_scsi_tgt_init: %s, lun%d", ddi_driver_name(cdip), lun);
2160*0Sstevel@tonic-gate 
2161*0Sstevel@tonic-gate 	/* is this a child we created? */
2162*0Sstevel@tonic-gate 	if (scsa2usb_is_usb(cdip) == 0) {
2163*0Sstevel@tonic-gate 
2164*0Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
2165*0Sstevel@tonic-gate 		    "scsa2usb_scsi_tgt_init: new child %s%d",
2166*0Sstevel@tonic-gate 		    ddi_driver_name(cdip), ddi_get_instance(cdip));
2167*0Sstevel@tonic-gate 
2168*0Sstevel@tonic-gate 		/*
2169*0Sstevel@tonic-gate 		 * add property "usb" so we can always verify that it
2170*0Sstevel@tonic-gate 		 * is our child
2171*0Sstevel@tonic-gate 		 */
2172*0Sstevel@tonic-gate 		if (ndi_prop_create_boolean(DDI_DEV_T_NONE, cdip, "usb") !=
2173*0Sstevel@tonic-gate 		    DDI_PROP_SUCCESS) {
2174*0Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_SCSA,
2175*0Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
2176*0Sstevel@tonic-gate 			    "ndi_prop_create_boolean failed");
2177*0Sstevel@tonic-gate 
2178*0Sstevel@tonic-gate 			return (DDI_FAILURE);
2179*0Sstevel@tonic-gate 		}
2180*0Sstevel@tonic-gate 
2181*0Sstevel@tonic-gate 		usba_set_usba_device(cdip,
2182*0Sstevel@tonic-gate 			usba_get_usba_device(scsa2usbp->scsa2usb_dip));
2183*0Sstevel@tonic-gate 
2184*0Sstevel@tonic-gate 		/*
2185*0Sstevel@tonic-gate 		 * we don't store this dip in scsa2usb_lun_dip, there
2186*0Sstevel@tonic-gate 		 * might be multiple dips for the same device
2187*0Sstevel@tonic-gate 		 */
2188*0Sstevel@tonic-gate 
2189*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
2190*0Sstevel@tonic-gate 	}
2191*0Sstevel@tonic-gate 
2192*0Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
2193*0Sstevel@tonic-gate 	if ((lun >= scsa2usbp->scsa2usb_n_luns) ||
2194*0Sstevel@tonic-gate 	    (scsa2usbp->scsa2usb_lun_dip[lun] != NULL)) {
2195*0Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
2196*0Sstevel@tonic-gate 
2197*0Sstevel@tonic-gate 		return (DDI_FAILURE);
2198*0Sstevel@tonic-gate 	}
2199*0Sstevel@tonic-gate 
2200*0Sstevel@tonic-gate 	scsa2usbp->scsa2usb_lun_dip[lun] = cdip;
2201*0Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
2202*0Sstevel@tonic-gate 
2203*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
2204*0Sstevel@tonic-gate }
2205*0Sstevel@tonic-gate 
2206*0Sstevel@tonic-gate 
2207*0Sstevel@tonic-gate /*
2208*0Sstevel@tonic-gate  * scsa2usb_scsi_tgt_free:
2209*0Sstevel@tonic-gate  */
2210*0Sstevel@tonic-gate /* ARGSUSED */
2211*0Sstevel@tonic-gate static void
2212*0Sstevel@tonic-gate scsa2usb_scsi_tgt_free(dev_info_t *hba_dip, dev_info_t *cdip,
2213*0Sstevel@tonic-gate 	scsi_hba_tran_t *tran, struct scsi_device *sd)
2214*0Sstevel@tonic-gate {
2215*0Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp = (scsa2usb_state_t *)
2216*0Sstevel@tonic-gate 					tran->tran_hba_private;
2217*0Sstevel@tonic-gate 	int lun;
2218*0Sstevel@tonic-gate 	int t_len = sizeof (lun);
2219*0Sstevel@tonic-gate 
2220*0Sstevel@tonic-gate 	/* is this our child? */
2221*0Sstevel@tonic-gate 	if (scsa2usb_is_usb(cdip) == 0) {
2222*0Sstevel@tonic-gate 
2223*0Sstevel@tonic-gate 		return;
2224*0Sstevel@tonic-gate 	}
2225*0Sstevel@tonic-gate 
2226*0Sstevel@tonic-gate 	if (ddi_prop_op(DDI_DEV_T_ANY, cdip, PROP_LEN_AND_VAL_BUF,
2227*0Sstevel@tonic-gate 	    DDI_PROP_DONTPASS|DDI_PROP_CANSLEEP, "lun", (caddr_t)&lun,
2228*0Sstevel@tonic-gate 	    &t_len) != DDI_PROP_SUCCESS) {
2229*0Sstevel@tonic-gate 
2230*0Sstevel@tonic-gate 		return;
2231*0Sstevel@tonic-gate 	}
2232*0Sstevel@tonic-gate 
2233*0Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
2234*0Sstevel@tonic-gate 	    "scsa2usb_scsi_tgt_free: %s lun%d", ddi_driver_name(cdip), lun);
2235*0Sstevel@tonic-gate 
2236*0Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
2237*0Sstevel@tonic-gate 	if (lun < scsa2usbp->scsa2usb_n_luns) {
2238*0Sstevel@tonic-gate 		if (scsa2usbp->scsa2usb_lun_dip[lun] == cdip) {
2239*0Sstevel@tonic-gate 			scsa2usbp->scsa2usb_lun_dip[lun] = NULL;
2240*0Sstevel@tonic-gate 		}
2241*0Sstevel@tonic-gate 	}
2242*0Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
2243*0Sstevel@tonic-gate }
2244*0Sstevel@tonic-gate 
2245*0Sstevel@tonic-gate 
2246*0Sstevel@tonic-gate /*
2247*0Sstevel@tonic-gate  * bus enumeration entry points
2248*0Sstevel@tonic-gate  */
2249*0Sstevel@tonic-gate static int
2250*0Sstevel@tonic-gate scsa2usb_scsi_bus_config(dev_info_t *dip, uint_t flag, ddi_bus_config_op_t op,
2251*0Sstevel@tonic-gate     void *arg, dev_info_t **child)
2252*0Sstevel@tonic-gate {
2253*0Sstevel@tonic-gate 	int	circ;
2254*0Sstevel@tonic-gate 	int	rval;
2255*0Sstevel@tonic-gate 
2256*0Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp =
2257*0Sstevel@tonic-gate 	    ddi_get_soft_state(scsa2usb_statep, ddi_get_instance(dip));
2258*0Sstevel@tonic-gate 
2259*0Sstevel@tonic-gate 	ASSERT(scsa2usbp != NULL);
2260*0Sstevel@tonic-gate 
2261*0Sstevel@tonic-gate 	USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
2262*0Sstevel@tonic-gate 	    "scsa2usb_scsi_bus_config: op=%d", op);
2263*0Sstevel@tonic-gate 
2264*0Sstevel@tonic-gate 	if (scsa2usb_scsi_bus_config_debug) {
2265*0Sstevel@tonic-gate 		flag |= NDI_DEVI_DEBUG;
2266*0Sstevel@tonic-gate 	}
2267*0Sstevel@tonic-gate 
2268*0Sstevel@tonic-gate 	ndi_devi_enter(dip, &circ);
2269*0Sstevel@tonic-gate 	/* create children if necessary */
2270*0Sstevel@tonic-gate 	if (DEVI(dip)->devi_child == NULL) {
2271*0Sstevel@tonic-gate 		scsa2usb_create_luns(scsa2usbp);
2272*0Sstevel@tonic-gate 	}
2273*0Sstevel@tonic-gate 
2274*0Sstevel@tonic-gate 	rval = ndi_busop_bus_config(dip, flag, op, arg, child, 0);
2275*0Sstevel@tonic-gate 
2276*0Sstevel@tonic-gate 	ndi_devi_exit(dip, circ);
2277*0Sstevel@tonic-gate 
2278*0Sstevel@tonic-gate 	return (rval);
2279*0Sstevel@tonic-gate }
2280*0Sstevel@tonic-gate 
2281*0Sstevel@tonic-gate 
2282*0Sstevel@tonic-gate static int
2283*0Sstevel@tonic-gate scsa2usb_scsi_bus_unconfig(dev_info_t *dip, uint_t flag, ddi_bus_config_op_t op,
2284*0Sstevel@tonic-gate     void *arg)
2285*0Sstevel@tonic-gate {
2286*0Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp =
2287*0Sstevel@tonic-gate 	    ddi_get_soft_state(scsa2usb_statep, ddi_get_instance(dip));
2288*0Sstevel@tonic-gate 
2289*0Sstevel@tonic-gate 	int		circular_count;
2290*0Sstevel@tonic-gate 	int		rval = NDI_SUCCESS;
2291*0Sstevel@tonic-gate 	uint_t		save_flag = flag;
2292*0Sstevel@tonic-gate 
2293*0Sstevel@tonic-gate 	ASSERT(scsa2usbp != NULL);
2294*0Sstevel@tonic-gate 
2295*0Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
2296*0Sstevel@tonic-gate 	    "scsa2usb_scsi_bus_unconfig: op=%d", op);
2297*0Sstevel@tonic-gate 
2298*0Sstevel@tonic-gate 	if (scsa2usb_scsi_bus_config_debug) {
2299*0Sstevel@tonic-gate 		flag |= NDI_DEVI_DEBUG;
2300*0Sstevel@tonic-gate 	}
2301*0Sstevel@tonic-gate 
2302*0Sstevel@tonic-gate 	/*
2303*0Sstevel@tonic-gate 	 * first offline and if offlining successful, then
2304*0Sstevel@tonic-gate 	 * remove children
2305*0Sstevel@tonic-gate 	 */
2306*0Sstevel@tonic-gate 	if (op == BUS_UNCONFIG_ALL) {
2307*0Sstevel@tonic-gate 		flag &= ~(NDI_DEVI_REMOVE | NDI_UNCONFIG);
2308*0Sstevel@tonic-gate 	}
2309*0Sstevel@tonic-gate 
2310*0Sstevel@tonic-gate 	ndi_devi_enter(dip, &circular_count);
2311*0Sstevel@tonic-gate 	rval = ndi_busop_bus_unconfig(dip, flag, op, arg);
2312*0Sstevel@tonic-gate 
2313*0Sstevel@tonic-gate 	/*
2314*0Sstevel@tonic-gate 	 * If unconfig is successful and not part of modunload
2315*0Sstevel@tonic-gate 	 * daemon, attempt to remove children.
2316*0Sstevel@tonic-gate 	 */
2317*0Sstevel@tonic-gate 	if (op == BUS_UNCONFIG_ALL && rval == NDI_SUCCESS &&
2318*0Sstevel@tonic-gate 	    (flag & NDI_AUTODETACH) == 0) {
2319*0Sstevel@tonic-gate 		flag |= NDI_DEVI_REMOVE;
2320*0Sstevel@tonic-gate 		rval = ndi_busop_bus_unconfig(dip, flag, op, arg);
2321*0Sstevel@tonic-gate 	}
2322*0Sstevel@tonic-gate 	ndi_devi_exit(dip, circular_count);
2323*0Sstevel@tonic-gate 
2324*0Sstevel@tonic-gate 	if ((rval != NDI_SUCCESS) && (op == BUS_UNCONFIG_ALL) &&
2325*0Sstevel@tonic-gate 	    (save_flag & NDI_DEVI_REMOVE)) {
2326*0Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
2327*0Sstevel@tonic-gate 		if (scsa2usbp->scsa2usb_warning_given != B_TRUE) {
2328*0Sstevel@tonic-gate 			USB_DPRINTF_L0(DPRINT_MASK_SCSA,
2329*0Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
2330*0Sstevel@tonic-gate 			    "Disconnected device was busy, "
2331*0Sstevel@tonic-gate 			    "please reconnect.");
2332*0Sstevel@tonic-gate 			scsa2usbp->scsa2usb_warning_given = B_TRUE;
2333*0Sstevel@tonic-gate 		}
2334*0Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
2335*0Sstevel@tonic-gate 	}
2336*0Sstevel@tonic-gate 
2337*0Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
2338*0Sstevel@tonic-gate 	    "scsa2usb_scsi_bus_unconfig: rval=%d", rval);
2339*0Sstevel@tonic-gate 
2340*0Sstevel@tonic-gate 	return (rval);
2341*0Sstevel@tonic-gate }
2342*0Sstevel@tonic-gate 
2343*0Sstevel@tonic-gate 
2344*0Sstevel@tonic-gate /*
2345*0Sstevel@tonic-gate  * scsa2usb_scsi_init_pkt:
2346*0Sstevel@tonic-gate  *	Set up the scsi_pkt for transport. Also initialize
2347*0Sstevel@tonic-gate  *	scsa2usb_cmd struct for the transport.
2348*0Sstevel@tonic-gate  *	NOTE: We do not do any DMA setup here as USBA framework
2349*0Sstevel@tonic-gate  *	does that for us.
2350*0Sstevel@tonic-gate  */
2351*0Sstevel@tonic-gate static struct scsi_pkt *
2352*0Sstevel@tonic-gate scsa2usb_scsi_init_pkt(struct scsi_address *ap,
2353*0Sstevel@tonic-gate     struct scsi_pkt *pkt, struct buf *bp, int cmdlen, int statuslen,
2354*0Sstevel@tonic-gate     int tgtlen, int flags, int (*callback)(), caddr_t arg)
2355*0Sstevel@tonic-gate {
2356*0Sstevel@tonic-gate 	scsa2usb_cmd_t	 *cmd;
2357*0Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp;
2358*0Sstevel@tonic-gate 	struct scsi_pkt	 *in_pkt = pkt;
2359*0Sstevel@tonic-gate 
2360*0Sstevel@tonic-gate 	ASSERT(callback == NULL_FUNC || callback == SLEEP_FUNC);
2361*0Sstevel@tonic-gate 
2362*0Sstevel@tonic-gate 	scsa2usbp = (scsa2usb_state_t *)ADDR2SCSA2USB(ap);
2363*0Sstevel@tonic-gate 
2364*0Sstevel@tonic-gate 	/* Print sync message */
2365*0Sstevel@tonic-gate 	if (ddi_in_panic()) {
2366*0Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
2367*0Sstevel@tonic-gate 		SCSA2USB_PRINT_SYNC_MSG(scsa2usb_sync_message, scsa2usbp);
2368*0Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
2369*0Sstevel@tonic-gate 		/* continue so caller will not hang or complain */
2370*0Sstevel@tonic-gate 	}
2371*0Sstevel@tonic-gate 
2372*0Sstevel@tonic-gate 	/* allocate a pkt, if none already allocated */
2373*0Sstevel@tonic-gate 	if (pkt == NULL) {
2374*0Sstevel@tonic-gate 		if (statuslen < sizeof (struct scsi_arq_status)) {
2375*0Sstevel@tonic-gate 			statuslen = sizeof (struct scsi_arq_status);
2376*0Sstevel@tonic-gate 		}
2377*0Sstevel@tonic-gate 
2378*0Sstevel@tonic-gate 		pkt = scsi_hba_pkt_alloc(scsa2usbp->scsa2usb_dip, ap, cmdlen,
2379*0Sstevel@tonic-gate 			statuslen, tgtlen, sizeof (scsa2usb_cmd_t),
2380*0Sstevel@tonic-gate 			callback, arg);
2381*0Sstevel@tonic-gate 		if (pkt == NULL) {
2382*0Sstevel@tonic-gate 
2383*0Sstevel@tonic-gate 			return (NULL);
2384*0Sstevel@tonic-gate 		}
2385*0Sstevel@tonic-gate 
2386*0Sstevel@tonic-gate 		cmd = PKT2CMD(pkt);
2387*0Sstevel@tonic-gate 		cmd->cmd_pkt	= pkt; /* back link to pkt */
2388*0Sstevel@tonic-gate 		cmd->cmd_scblen	= statuslen;
2389*0Sstevel@tonic-gate 		cmd->cmd_cdblen	= (uchar_t)cmdlen;
2390*0Sstevel@tonic-gate 
2391*0Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
2392*0Sstevel@tonic-gate 		cmd->cmd_tag	= scsa2usbp->scsa2usb_tag++;
2393*0Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
2394*0Sstevel@tonic-gate 
2395*0Sstevel@tonic-gate 		cmd->cmd_bp	= bp;
2396*0Sstevel@tonic-gate 		pkt->pkt_scbp	= (opaque_t)&cmd->cmd_scb;
2397*0Sstevel@tonic-gate 
2398*0Sstevel@tonic-gate 		usba_init_list(&cmd->cmd_waitQ, (usb_opaque_t)cmd,
2399*0Sstevel@tonic-gate 			scsa2usbp->scsa2usb_dev_data->dev_iblock_cookie);
2400*0Sstevel@tonic-gate 	} else {
2401*0Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
2402*0Sstevel@tonic-gate 		    "scsa2usb: pkt != NULL");
2403*0Sstevel@tonic-gate 
2404*0Sstevel@tonic-gate 		/* nothing to do */
2405*0Sstevel@tonic-gate 	}
2406*0Sstevel@tonic-gate 
2407*0Sstevel@tonic-gate 	if (bp) {
2408*0Sstevel@tonic-gate 		if ((bp_mapin_common(bp, (callback == SLEEP_FUNC) ?
2409*0Sstevel@tonic-gate 		    VM_SLEEP : VM_NOSLEEP)) == NULL) {
2410*0Sstevel@tonic-gate 			if (pkt != in_pkt) {
2411*0Sstevel@tonic-gate 				scsi_hba_pkt_free(ap, pkt);
2412*0Sstevel@tonic-gate 			}
2413*0Sstevel@tonic-gate 
2414*0Sstevel@tonic-gate 			return (NULL);
2415*0Sstevel@tonic-gate 		}
2416*0Sstevel@tonic-gate 
2417*0Sstevel@tonic-gate 		USB_DPRINTF_L3(DPRINT_MASK_SCSA,
2418*0Sstevel@tonic-gate 		    scsa2usbp->scsa2usb_log_handle,
2419*0Sstevel@tonic-gate 		    "scsa2usb_scsi_init_pkt: mapped in 0x%p, addr=0x%p",
2420*0Sstevel@tonic-gate 		    bp, bp->b_un.b_addr);
2421*0Sstevel@tonic-gate 	}
2422*0Sstevel@tonic-gate 
2423*0Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
2424*0Sstevel@tonic-gate 	    "scsa2usb_scsi_init_pkt: ap = 0x%p pkt: 0x%p\n\t"
2425*0Sstevel@tonic-gate 	    "bp = 0x%p cmdlen = %x stlen = 0x%x tlen = 0x%x flags = 0x%x",
2426*0Sstevel@tonic-gate 	    ap, pkt, bp, cmdlen, statuslen, tgtlen, flags);
2427*0Sstevel@tonic-gate 
2428*0Sstevel@tonic-gate 	return (pkt);
2429*0Sstevel@tonic-gate }
2430*0Sstevel@tonic-gate 
2431*0Sstevel@tonic-gate 
2432*0Sstevel@tonic-gate /*
2433*0Sstevel@tonic-gate  * scsa2usb_scsi_destroy_pkt:
2434*0Sstevel@tonic-gate  *	We are done with the packet. Get rid of it.
2435*0Sstevel@tonic-gate  */
2436*0Sstevel@tonic-gate static void
2437*0Sstevel@tonic-gate scsa2usb_scsi_destroy_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
2438*0Sstevel@tonic-gate {
2439*0Sstevel@tonic-gate 	scsa2usb_cmd_t *cmd = PKT2CMD(pkt);
2440*0Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp = ADDR2SCSA2USB(ap);
2441*0Sstevel@tonic-gate 
2442*0Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
2443*0Sstevel@tonic-gate 	    "scsa2usb_scsi_destroy_pkt: pkt=0x%p", pkt);
2444*0Sstevel@tonic-gate 
2445*0Sstevel@tonic-gate 	usba_destroy_list(&cmd->cmd_waitQ);
2446*0Sstevel@tonic-gate 	scsi_hba_pkt_free(ap, pkt);
2447*0Sstevel@tonic-gate }
2448*0Sstevel@tonic-gate 
2449*0Sstevel@tonic-gate 
2450*0Sstevel@tonic-gate /*
2451*0Sstevel@tonic-gate  * scsa2usb_scsi_start:
2452*0Sstevel@tonic-gate  *	For each command being issued, build up the CDB
2453*0Sstevel@tonic-gate  *	and call scsi_transport to issue the command. This
2454*0Sstevel@tonic-gate  *	function is based on the assumption that USB allows
2455*0Sstevel@tonic-gate  *	a subset of SCSI commands. Other SCSI commands we fail.
2456*0Sstevel@tonic-gate  */
2457*0Sstevel@tonic-gate static int
2458*0Sstevel@tonic-gate scsa2usb_scsi_start(struct scsi_address *ap, struct scsi_pkt *pkt)
2459*0Sstevel@tonic-gate {
2460*0Sstevel@tonic-gate 	scsa2usb_cmd_t		*cmd;
2461*0Sstevel@tonic-gate 	scsa2usb_state_t	*scsa2usbp = ADDR2SCSA2USB(ap);
2462*0Sstevel@tonic-gate 	uint_t			lun = ap->a_lun;
2463*0Sstevel@tonic-gate 
2464*0Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
2465*0Sstevel@tonic-gate 
2466*0Sstevel@tonic-gate 	cmd = PKT2CMD(pkt);
2467*0Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
2468*0Sstevel@tonic-gate 	    "scsa2usb_scsi_start:\n\t"
2469*0Sstevel@tonic-gate 	    "bp: 0x%p ap: 0x%p pkt: 0x%p flag: 0x%x time: 0x%x\n\tcdb0: 0x%x "
2470*0Sstevel@tonic-gate 	    "dev_state: 0x%x pkt_state: 0x%x flags: 0x%x pipe_state: 0x%x",
2471*0Sstevel@tonic-gate 	    cmd->cmd_bp, ap, pkt, pkt->pkt_flags, pkt->pkt_time,
2472*0Sstevel@tonic-gate 	    pkt->pkt_cdbp[0], scsa2usbp->scsa2usb_dev_state,
2473*0Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_pkt_state, scsa2usbp->scsa2usb_flags,
2474*0Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_pipe_state);
2475*0Sstevel@tonic-gate 
2476*0Sstevel@tonic-gate 	if (pkt->pkt_time == 0) {
2477*0Sstevel@tonic-gate 		USB_DPRINTF_L1(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
2478*0Sstevel@tonic-gate 		    "pkt submitted with 0 timeout which may cause indefinite "
2479*0Sstevel@tonic-gate 		    "hangs");
2480*0Sstevel@tonic-gate 	}
2481*0Sstevel@tonic-gate 
2482*0Sstevel@tonic-gate 	/*
2483*0Sstevel@tonic-gate 	 * if we are in panic, we are in polled mode, so we can just
2484*0Sstevel@tonic-gate 	 * accept the request, drop it and return
2485*0Sstevel@tonic-gate 	 * if we fail this request, the rest of the file systems do not
2486*0Sstevel@tonic-gate 	 * get synced
2487*0Sstevel@tonic-gate 	 */
2488*0Sstevel@tonic-gate 	if (ddi_in_panic()) {
2489*0Sstevel@tonic-gate 		extern int do_polled_io;
2490*0Sstevel@tonic-gate 
2491*0Sstevel@tonic-gate 		ASSERT(do_polled_io);
2492*0Sstevel@tonic-gate 		scsa2usb_prepare_pkt(scsa2usbp, pkt);
2493*0Sstevel@tonic-gate 		SCSA2USB_PRINT_SYNC_MSG(scsa2usb_sync_message, scsa2usbp);
2494*0Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
2495*0Sstevel@tonic-gate 
2496*0Sstevel@tonic-gate 		return (TRAN_ACCEPT);
2497*0Sstevel@tonic-gate 	}
2498*0Sstevel@tonic-gate 
2499*0Sstevel@tonic-gate 	/* we cannot do polling, this should not happen */
2500*0Sstevel@tonic-gate 	if (pkt->pkt_flags & FLAG_NOINTR) {
2501*0Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
2502*0Sstevel@tonic-gate 		    "NOINTR packet: opcode = 0%x", pkt->pkt_cdbp[0]);
2503*0Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
2504*0Sstevel@tonic-gate 
2505*0Sstevel@tonic-gate 		return (TRAN_BADPKT);
2506*0Sstevel@tonic-gate 	}
2507*0Sstevel@tonic-gate 
2508*0Sstevel@tonic-gate 	/* is there a ugen open? */
2509*0Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_ugen_open_count) {
2510*0Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
2511*0Sstevel@tonic-gate 		    "ugen access in progress (count=%d)",
2512*0Sstevel@tonic-gate 		    scsa2usbp->scsa2usb_ugen_open_count);
2513*0Sstevel@tonic-gate 
2514*0Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
2515*0Sstevel@tonic-gate 
2516*0Sstevel@tonic-gate 		return (TRAN_BUSY);
2517*0Sstevel@tonic-gate 	}
2518*0Sstevel@tonic-gate 
2519*0Sstevel@tonic-gate 	/* prepare packet */
2520*0Sstevel@tonic-gate 	scsa2usb_prepare_pkt(scsa2usbp, pkt);
2521*0Sstevel@tonic-gate 
2522*0Sstevel@tonic-gate 	/* just queue up the requests in the waitQ if below max */
2523*0Sstevel@tonic-gate 	if (usba_list_entry_count(&scsa2usbp->scsa2usb_waitQ[lun]) >
2524*0Sstevel@tonic-gate 	    SCSA2USB_MAX_REQ_PER_LUN) {
2525*0Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA,
2526*0Sstevel@tonic-gate 		    scsa2usbp->scsa2usb_log_handle,
2527*0Sstevel@tonic-gate 		    "scsa2usb_scsi_start: limit (%d) exceeded",
2528*0Sstevel@tonic-gate 		    SCSA2USB_MAX_REQ_PER_LUN);
2529*0Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
2530*0Sstevel@tonic-gate 
2531*0Sstevel@tonic-gate 		return (TRAN_BUSY);
2532*0Sstevel@tonic-gate 	}
2533*0Sstevel@tonic-gate 
2534*0Sstevel@tonic-gate 	usba_add_to_list(&scsa2usbp->scsa2usb_waitQ[lun], &cmd->cmd_waitQ);
2535*0Sstevel@tonic-gate 
2536*0Sstevel@tonic-gate 	/* fire up a thread to start executing the protocol */
2537*0Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_work_thread_id == 0) {
2538*0Sstevel@tonic-gate 		if ((usb_async_req(scsa2usbp->scsa2usb_dip,
2539*0Sstevel@tonic-gate 		    scsa2usb_work_thread,
2540*0Sstevel@tonic-gate 		    (void *)scsa2usbp, USB_FLAGS_SLEEP)) != USB_SUCCESS) {
2541*0Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_SCSA,
2542*0Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
2543*0Sstevel@tonic-gate 			    "no work thread started");
2544*0Sstevel@tonic-gate 
2545*0Sstevel@tonic-gate 			if (usba_rm_from_list(
2546*0Sstevel@tonic-gate 			    &scsa2usbp->scsa2usb_waitQ[lun],
2547*0Sstevel@tonic-gate 			    &cmd->cmd_waitQ) == USB_SUCCESS) {
2548*0Sstevel@tonic-gate 				mutex_exit(&scsa2usbp->scsa2usb_mutex);
2549*0Sstevel@tonic-gate 
2550*0Sstevel@tonic-gate 				return (TRAN_BUSY);
2551*0Sstevel@tonic-gate 			} else {
2552*0Sstevel@tonic-gate 
2553*0Sstevel@tonic-gate 				mutex_exit(&scsa2usbp->scsa2usb_mutex);
2554*0Sstevel@tonic-gate 
2555*0Sstevel@tonic-gate 				return (TRAN_ACCEPT);
2556*0Sstevel@tonic-gate 			}
2557*0Sstevel@tonic-gate 		}
2558*0Sstevel@tonic-gate 		scsa2usbp->scsa2usb_work_thread_id = (kthread_t *)1;
2559*0Sstevel@tonic-gate 	}
2560*0Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
2561*0Sstevel@tonic-gate 
2562*0Sstevel@tonic-gate 	return (TRAN_ACCEPT);
2563*0Sstevel@tonic-gate }
2564*0Sstevel@tonic-gate 
2565*0Sstevel@tonic-gate 
2566*0Sstevel@tonic-gate /*
2567*0Sstevel@tonic-gate  * scsa2usb_scsi_abort:
2568*0Sstevel@tonic-gate  *	Issue SCSI abort command. This function is a NOP.
2569*0Sstevel@tonic-gate  */
2570*0Sstevel@tonic-gate /* ARGSUSED */
2571*0Sstevel@tonic-gate static int
2572*0Sstevel@tonic-gate scsa2usb_scsi_abort(struct scsi_address *ap, struct scsi_pkt *pkt)
2573*0Sstevel@tonic-gate {
2574*0Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp = (scsa2usb_state_t *)ADDR2SCSA2USB(ap);
2575*0Sstevel@tonic-gate 
2576*0Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
2577*0Sstevel@tonic-gate 	    "scsa2usb_scsi_abort: pkt = %p", pkt);
2578*0Sstevel@tonic-gate 
2579*0Sstevel@tonic-gate 	/* if device is disconnected (ie. pipes closed), fail immediately */
2580*0Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
2581*0Sstevel@tonic-gate 	if (!(SCSA2USB_DEVICE_ACCESS_OK(scsa2usbp))) {
2582*0Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
2583*0Sstevel@tonic-gate 
2584*0Sstevel@tonic-gate 		return (0);
2585*0Sstevel@tonic-gate 	}
2586*0Sstevel@tonic-gate 
2587*0Sstevel@tonic-gate 	/* flush waitQ if target and lun match */
2588*0Sstevel@tonic-gate 	if ((ap->a_target == pkt->pkt_address.a_target) &&
2589*0Sstevel@tonic-gate 	    (ap->a_lun == pkt->pkt_address.a_lun)) {
2590*0Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
2591*0Sstevel@tonic-gate 		scsa2usb_flush_waitQ(scsa2usbp, ap->a_lun, CMD_ABORTED);
2592*0Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
2593*0Sstevel@tonic-gate 	}
2594*0Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
2595*0Sstevel@tonic-gate 
2596*0Sstevel@tonic-gate 	return (0);
2597*0Sstevel@tonic-gate }
2598*0Sstevel@tonic-gate 
2599*0Sstevel@tonic-gate 
2600*0Sstevel@tonic-gate /*
2601*0Sstevel@tonic-gate  * scsa2usb_scsi_reset:
2602*0Sstevel@tonic-gate  *	device reset may turn the device into a brick and bus reset
2603*0Sstevel@tonic-gate  *	is not applicable.
2604*0Sstevel@tonic-gate  *	just flush the waitQ
2605*0Sstevel@tonic-gate  *	We return success, always.
2606*0Sstevel@tonic-gate  */
2607*0Sstevel@tonic-gate /* ARGSUSED */
2608*0Sstevel@tonic-gate static int
2609*0Sstevel@tonic-gate scsa2usb_scsi_reset(struct scsi_address *ap, int level)
2610*0Sstevel@tonic-gate {
2611*0Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp = (scsa2usb_state_t *)ADDR2SCSA2USB(ap);
2612*0Sstevel@tonic-gate 
2613*0Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
2614*0Sstevel@tonic-gate 	    "scsa2usb_scsi_reset: ap = 0x%p, level = %d", ap, level);
2615*0Sstevel@tonic-gate 
2616*0Sstevel@tonic-gate 	/* flush waitQ */
2617*0Sstevel@tonic-gate 	scsa2usb_flush_waitQ(scsa2usbp, ap->a_lun, CMD_RESET);
2618*0Sstevel@tonic-gate 
2619*0Sstevel@tonic-gate 	return (1);
2620*0Sstevel@tonic-gate }
2621*0Sstevel@tonic-gate 
2622*0Sstevel@tonic-gate 
2623*0Sstevel@tonic-gate /*
2624*0Sstevel@tonic-gate  * scsa2usb_scsi_getcap:
2625*0Sstevel@tonic-gate  *	Get SCSI capabilities.
2626*0Sstevel@tonic-gate  */
2627*0Sstevel@tonic-gate /* ARGSUSED */
2628*0Sstevel@tonic-gate static int
2629*0Sstevel@tonic-gate scsa2usb_scsi_getcap(struct scsi_address *ap, char *cap, int whom)
2630*0Sstevel@tonic-gate {
2631*0Sstevel@tonic-gate 	int rval = -1;
2632*0Sstevel@tonic-gate 	uint_t cidx;
2633*0Sstevel@tonic-gate 	size_t dev_bsize_cap;
2634*0Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp = (scsa2usb_state_t *)ADDR2SCSA2USB(ap);
2635*0Sstevel@tonic-gate 	ASSERT(scsa2usbp);
2636*0Sstevel@tonic-gate 
2637*0Sstevel@tonic-gate 	if (cap == NULL) {
2638*0Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
2639*0Sstevel@tonic-gate 		    "scsa2usb_scsi_getcap: invalid arg, "
2640*0Sstevel@tonic-gate 		    "cap = 0x%p whom = %d", cap, whom);
2641*0Sstevel@tonic-gate 
2642*0Sstevel@tonic-gate 		return (rval);
2643*0Sstevel@tonic-gate 	}
2644*0Sstevel@tonic-gate 
2645*0Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
2646*0Sstevel@tonic-gate 	    "scsa2usb_scsi_getcap: cap = %s", cap);
2647*0Sstevel@tonic-gate 
2648*0Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
2649*0Sstevel@tonic-gate 
2650*0Sstevel@tonic-gate 	/* if device is disconnected (ie. pipes closed), fail immediately */
2651*0Sstevel@tonic-gate 	if (!(SCSA2USB_DEVICE_ACCESS_OK(scsa2usbp))) {
2652*0Sstevel@tonic-gate 
2653*0Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
2654*0Sstevel@tonic-gate 
2655*0Sstevel@tonic-gate 		return (rval);
2656*0Sstevel@tonic-gate 	}
2657*0Sstevel@tonic-gate 
2658*0Sstevel@tonic-gate 	cidx =	scsi_hba_lookup_capstr(cap);
2659*0Sstevel@tonic-gate 	switch (cidx) {
2660*0Sstevel@tonic-gate 	case SCSI_CAP_GEOMETRY:
2661*0Sstevel@tonic-gate 		dev_bsize_cap = scsa2usbp->scsa2usb_totalsec[ap->a_lun];
2662*0Sstevel@tonic-gate 
2663*0Sstevel@tonic-gate 		if (scsa2usbp->scsa2usb_secsz[ap->a_lun] > DEV_BSIZE) {
2664*0Sstevel@tonic-gate 			dev_bsize_cap *=
2665*0Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_secsz[ap->a_lun] / DEV_BSIZE;
2666*0Sstevel@tonic-gate 		} else if (scsa2usbp->scsa2usb_secsz[ap->a_lun] <
2667*0Sstevel@tonic-gate 		    DEV_BSIZE) {
2668*0Sstevel@tonic-gate 			dev_bsize_cap /=
2669*0Sstevel@tonic-gate 			    DEV_BSIZE / scsa2usbp->scsa2usb_secsz[ap->a_lun];
2670*0Sstevel@tonic-gate 		}
2671*0Sstevel@tonic-gate 
2672*0Sstevel@tonic-gate 		if (dev_bsize_cap < 65536 * 2 * 18) {		/* < ~1GB */
2673*0Sstevel@tonic-gate 			/* unlabeled floppy, 18k per cylinder */
2674*0Sstevel@tonic-gate 			rval = ((2 << 16) | 18);
2675*0Sstevel@tonic-gate 		} else if (dev_bsize_cap < 65536 * 64 * 32) {	/* < 64GB */
2676*0Sstevel@tonic-gate 			/* 1024k per cylinder */
2677*0Sstevel@tonic-gate 			rval = ((64 << 16) | 32);
2678*0Sstevel@tonic-gate 		} else if (dev_bsize_cap < 65536 * 255 * 63) {	/* < ~500GB */
2679*0Sstevel@tonic-gate 			/* ~8m per cylinder */
2680*0Sstevel@tonic-gate 			rval = ((255 << 16) | 63);
2681*0Sstevel@tonic-gate 		} else {					/* .. 8TB */
2682*0Sstevel@tonic-gate 			/* 64m per cylinder */
2683*0Sstevel@tonic-gate 			rval = ((512 << 16) | 256);
2684*0Sstevel@tonic-gate 		}
2685*0Sstevel@tonic-gate 		break;
2686*0Sstevel@tonic-gate 
2687*0Sstevel@tonic-gate 	case SCSI_CAP_DMA_MAX:
2688*0Sstevel@tonic-gate 		rval = scsa2usbp->scsa2usb_max_bulk_xfer_size;
2689*0Sstevel@tonic-gate 		break;
2690*0Sstevel@tonic-gate 	case SCSI_CAP_SCSI_VERSION:
2691*0Sstevel@tonic-gate 		rval = SCSI_VERSION_2;
2692*0Sstevel@tonic-gate 		break;
2693*0Sstevel@tonic-gate 	case SCSI_CAP_INTERCONNECT_TYPE:
2694*0Sstevel@tonic-gate 		rval = INTERCONNECT_USB;
2695*0Sstevel@tonic-gate 		break;
2696*0Sstevel@tonic-gate 	case SCSI_CAP_ARQ:
2697*0Sstevel@tonic-gate 		/* FALLTHRU */
2698*0Sstevel@tonic-gate 	case SCSI_CAP_UNTAGGED_QING:
2699*0Sstevel@tonic-gate 		rval = 1;
2700*0Sstevel@tonic-gate 		break;
2701*0Sstevel@tonic-gate 	default:
2702*0Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
2703*0Sstevel@tonic-gate 		    "scsa2usb_scsi_getcap: unsupported cap = %s", cap);
2704*0Sstevel@tonic-gate 		break;
2705*0Sstevel@tonic-gate 	}
2706*0Sstevel@tonic-gate 
2707*0Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
2708*0Sstevel@tonic-gate 	    "scsa2usb_scsi_getcap: cap = %s, returned = %d", cap, rval);
2709*0Sstevel@tonic-gate 
2710*0Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
2711*0Sstevel@tonic-gate 
2712*0Sstevel@tonic-gate 	return (rval);
2713*0Sstevel@tonic-gate }
2714*0Sstevel@tonic-gate 
2715*0Sstevel@tonic-gate 
2716*0Sstevel@tonic-gate /*
2717*0Sstevel@tonic-gate  * scsa2usb_scsi_setcap:
2718*0Sstevel@tonic-gate  *	Set SCSI capabilities.
2719*0Sstevel@tonic-gate  */
2720*0Sstevel@tonic-gate /* ARGSUSED */
2721*0Sstevel@tonic-gate static int
2722*0Sstevel@tonic-gate scsa2usb_scsi_setcap(struct scsi_address *ap, char *cap, int value, int whom)
2723*0Sstevel@tonic-gate {
2724*0Sstevel@tonic-gate 	int rval = -1; /* default is cap undefined */
2725*0Sstevel@tonic-gate 	uint_t cidx;
2726*0Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp = (scsa2usb_state_t *)ADDR2SCSA2USB(ap);
2727*0Sstevel@tonic-gate 	ASSERT(scsa2usbp);
2728*0Sstevel@tonic-gate 
2729*0Sstevel@tonic-gate 	if (cap == NULL || whom == 0) {
2730*0Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
2731*0Sstevel@tonic-gate 		    "scsa2usb_scsi_setcap: invalid arg");
2732*0Sstevel@tonic-gate 
2733*0Sstevel@tonic-gate 		return (rval);
2734*0Sstevel@tonic-gate 	}
2735*0Sstevel@tonic-gate 
2736*0Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
2737*0Sstevel@tonic-gate 	/* if device is disconnected (ie. pipes closed), fail immediately */
2738*0Sstevel@tonic-gate 	if (!(SCSA2USB_DEVICE_ACCESS_OK(scsa2usbp))) {
2739*0Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
2740*0Sstevel@tonic-gate 
2741*0Sstevel@tonic-gate 		return (rval);
2742*0Sstevel@tonic-gate 	}
2743*0Sstevel@tonic-gate 
2744*0Sstevel@tonic-gate 	cidx =	scsi_hba_lookup_capstr(cap);
2745*0Sstevel@tonic-gate 	USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
2746*0Sstevel@tonic-gate 	    "scsa2usb_scsi_setcap: ap = 0x%p value = 0x%x whom = 0x%x "
2747*0Sstevel@tonic-gate 	    "cidx = 0x%x", ap, value, whom, cidx);
2748*0Sstevel@tonic-gate 
2749*0Sstevel@tonic-gate 	switch (cidx) {
2750*0Sstevel@tonic-gate 	case SCSI_CAP_SECTOR_SIZE:
2751*0Sstevel@tonic-gate 		if (value) {
2752*0Sstevel@tonic-gate 			scsa2usbp->scsa2usb_secsz[ap->a_lun] = value;
2753*0Sstevel@tonic-gate 		}
2754*0Sstevel@tonic-gate 		break;
2755*0Sstevel@tonic-gate 	case SCSI_CAP_TOTAL_SECTORS:
2756*0Sstevel@tonic-gate 		if (value) {
2757*0Sstevel@tonic-gate 			scsa2usbp->scsa2usb_totalsec[ap->a_lun] = value;
2758*0Sstevel@tonic-gate 		}
2759*0Sstevel@tonic-gate 		break;
2760*0Sstevel@tonic-gate 	case SCSI_CAP_ARQ:
2761*0Sstevel@tonic-gate 		rval = 1;
2762*0Sstevel@tonic-gate 		break;
2763*0Sstevel@tonic-gate 	case SCSI_CAP_DMA_MAX:
2764*0Sstevel@tonic-gate 	case SCSI_CAP_SCSI_VERSION:
2765*0Sstevel@tonic-gate 	case SCSI_CAP_INTERCONNECT_TYPE:
2766*0Sstevel@tonic-gate 	case SCSI_CAP_UNTAGGED_QING:
2767*0Sstevel@tonic-gate 		/* supported but not settable */
2768*0Sstevel@tonic-gate 		rval = 0;
2769*0Sstevel@tonic-gate 		break;
2770*0Sstevel@tonic-gate 	default:
2771*0Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
2772*0Sstevel@tonic-gate 		    "scsa2usb_scsi_setcap: unsupported cap = %s", cap);
2773*0Sstevel@tonic-gate 		break;
2774*0Sstevel@tonic-gate 	}
2775*0Sstevel@tonic-gate 
2776*0Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
2777*0Sstevel@tonic-gate 
2778*0Sstevel@tonic-gate 	return (rval);
2779*0Sstevel@tonic-gate }
2780*0Sstevel@tonic-gate 
2781*0Sstevel@tonic-gate 
2782*0Sstevel@tonic-gate /*
2783*0Sstevel@tonic-gate  * scsa2usb - cmd and transport stuff
2784*0Sstevel@tonic-gate  */
2785*0Sstevel@tonic-gate /*
2786*0Sstevel@tonic-gate  * scsa2usb_prepare_pkt:
2787*0Sstevel@tonic-gate  *	initialize some fields of the pkt and cmd
2788*0Sstevel@tonic-gate  *	(the pkt may have been resubmitted/retried)
2789*0Sstevel@tonic-gate  */
2790*0Sstevel@tonic-gate static void
2791*0Sstevel@tonic-gate scsa2usb_prepare_pkt(scsa2usb_state_t *scsa2usbp, struct scsi_pkt *pkt)
2792*0Sstevel@tonic-gate {
2793*0Sstevel@tonic-gate 	scsa2usb_cmd_t	*cmd = PKT2CMD(pkt);
2794*0Sstevel@tonic-gate 
2795*0Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
2796*0Sstevel@tonic-gate 	    "scsa2usb_prepare_pkt: pkt=0x%p cdb: 0x%x (%s)",
2797*0Sstevel@tonic-gate 	    pkt, pkt->pkt_cdbp[0],
2798*0Sstevel@tonic-gate 	    scsi_cname(pkt->pkt_cdbp[0], scsa2usb_cmds));
2799*0Sstevel@tonic-gate 
2800*0Sstevel@tonic-gate 	pkt->pkt_reason = CMD_CMPLT;	/* Set reason to pkt_complete */
2801*0Sstevel@tonic-gate 	pkt->pkt_state = 0;		/* Reset next three fields */
2802*0Sstevel@tonic-gate 	pkt->pkt_statistics = 0;
2803*0Sstevel@tonic-gate 	pkt->pkt_resid = 0;
2804*0Sstevel@tonic-gate 	bzero(pkt->pkt_scbp, cmd->cmd_scblen); /* Set status to good */
2805*0Sstevel@tonic-gate 
2806*0Sstevel@tonic-gate 	if (cmd) {
2807*0Sstevel@tonic-gate 		cmd->cmd_timeout = pkt->pkt_time;
2808*0Sstevel@tonic-gate 		cmd->cmd_xfercount = 0;		/* Reset the fields */
2809*0Sstevel@tonic-gate 		cmd->cmd_total_xfercount = 0;
2810*0Sstevel@tonic-gate 		cmd->cmd_lba = 0;
2811*0Sstevel@tonic-gate 		cmd->cmd_done = 0;
2812*0Sstevel@tonic-gate 		cmd->cmd_dir = 0;
2813*0Sstevel@tonic-gate 		cmd->cmd_offset = 0;
2814*0Sstevel@tonic-gate 		cmd->cmd_actual_len = cmd->cmd_cdblen;
2815*0Sstevel@tonic-gate 	}
2816*0Sstevel@tonic-gate }
2817*0Sstevel@tonic-gate 
2818*0Sstevel@tonic-gate 
2819*0Sstevel@tonic-gate /*
2820*0Sstevel@tonic-gate  * scsa2usb_force_invalid_request
2821*0Sstevel@tonic-gate  */
2822*0Sstevel@tonic-gate static void
2823*0Sstevel@tonic-gate scsa2usb_force_invalid_request(scsa2usb_state_t *scsa2usbp,
2824*0Sstevel@tonic-gate     scsa2usb_cmd_t *cmd)
2825*0Sstevel@tonic-gate {
2826*0Sstevel@tonic-gate 	struct scsi_arq_status	*arqp;
2827*0Sstevel@tonic-gate 
2828*0Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
2829*0Sstevel@tonic-gate 	    "scsa2usb_force_invalid_request: pkt = 0x%p", cmd->cmd_pkt);
2830*0Sstevel@tonic-gate 
2831*0Sstevel@tonic-gate 	if (cmd->cmd_scblen >= sizeof (struct scsi_arq_status)) {
2832*0Sstevel@tonic-gate 		arqp = (struct scsi_arq_status *)cmd->cmd_pkt->pkt_scbp;
2833*0Sstevel@tonic-gate 		bzero(arqp, cmd->cmd_scblen);
2834*0Sstevel@tonic-gate 
2835*0Sstevel@tonic-gate 		arqp->sts_status.sts_chk = 1;
2836*0Sstevel@tonic-gate 		arqp->sts_rqpkt_reason = CMD_CMPLT;
2837*0Sstevel@tonic-gate 		arqp->sts_rqpkt_state = STATE_XFERRED_DATA |
2838*0Sstevel@tonic-gate 		    STATE_GOT_BUS | STATE_GOT_STATUS;
2839*0Sstevel@tonic-gate 		arqp->sts_sensedata.es_valid = 1;
2840*0Sstevel@tonic-gate 		arqp->sts_sensedata.es_class = 7;
2841*0Sstevel@tonic-gate 		arqp->sts_sensedata.es_key = KEY_ILLEGAL_REQUEST;
2842*0Sstevel@tonic-gate 
2843*0Sstevel@tonic-gate 		cmd->cmd_pkt->pkt_state = STATE_ARQ_DONE |
2844*0Sstevel@tonic-gate 		    STATE_GOT_BUS | STATE_GOT_BUS | STATE_GOT_BUS |
2845*0Sstevel@tonic-gate 		    STATE_GOT_STATUS;
2846*0Sstevel@tonic-gate #ifdef DEBUG
2847*0Sstevel@tonic-gate 		{
2848*0Sstevel@tonic-gate 			uchar_t *p = (uchar_t *)(&arqp->sts_sensedata);
2849*0Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_SCSA,
2850*0Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
2851*0Sstevel@tonic-gate 			    "cdb: %x rqsense: "
2852*0Sstevel@tonic-gate 			    "%x %x %x %x %x %x %x %x %x %x "
2853*0Sstevel@tonic-gate 			    "%x %x %x %x %x %x %x %x %x %x",
2854*0Sstevel@tonic-gate 			    cmd->cmd_pkt->pkt_cdbp[0],
2855*0Sstevel@tonic-gate 			    p[0], p[1], p[2], p[3], p[4],
2856*0Sstevel@tonic-gate 			    p[5], p[6], p[7], p[8], p[9],
2857*0Sstevel@tonic-gate 			    p[10], p[11], p[12], p[13], p[14],
2858*0Sstevel@tonic-gate 			    p[15], p[16], p[17], p[18], p[19]);
2859*0Sstevel@tonic-gate 		}
2860*0Sstevel@tonic-gate #endif
2861*0Sstevel@tonic-gate 
2862*0Sstevel@tonic-gate 	}
2863*0Sstevel@tonic-gate }
2864*0Sstevel@tonic-gate 
2865*0Sstevel@tonic-gate 
2866*0Sstevel@tonic-gate /*
2867*0Sstevel@tonic-gate  * scsa2usb_cmd_transport:
2868*0Sstevel@tonic-gate  */
2869*0Sstevel@tonic-gate static int
2870*0Sstevel@tonic-gate scsa2usb_cmd_transport(scsa2usb_state_t *scsa2usbp, scsa2usb_cmd_t *cmd)
2871*0Sstevel@tonic-gate {
2872*0Sstevel@tonic-gate 	int rval, transport;
2873*0Sstevel@tonic-gate 	struct scsi_pkt *pkt;
2874*0Sstevel@tonic-gate 
2875*0Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
2876*0Sstevel@tonic-gate 	    "scsa2usb_cmd_transport: pkt: 0x%p, cur_pkt = 0x%p",
2877*0Sstevel@tonic-gate 	    cmd->cmd_pkt, scsa2usbp->scsa2usb_cur_pkt);
2878*0Sstevel@tonic-gate 
2879*0Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
2880*0Sstevel@tonic-gate 	ASSERT(scsa2usbp->scsa2usb_cur_pkt == NULL);
2881*0Sstevel@tonic-gate 
2882*0Sstevel@tonic-gate 	pkt = scsa2usbp->scsa2usb_cur_pkt = cmd->cmd_pkt;
2883*0Sstevel@tonic-gate 
2884*0Sstevel@tonic-gate 	/* check black-listed attrs first */
2885*0Sstevel@tonic-gate 	if (SCSA2USB_IS_BULK_ONLY(scsa2usbp)) {
2886*0Sstevel@tonic-gate 		transport = scsa2usb_check_bulkonly_blacklist_attrs(scsa2usbp,
2887*0Sstevel@tonic-gate 					cmd, pkt->pkt_cdbp[0]);
2888*0Sstevel@tonic-gate 	} else if (SCSA2USB_IS_CB(scsa2usbp) || SCSA2USB_IS_CBI(scsa2usbp)) {
2889*0Sstevel@tonic-gate 		transport =  scsa2usb_check_ufi_blacklist_attrs(scsa2usbp,
2890*0Sstevel@tonic-gate 					pkt->pkt_cdbp[0], cmd);
2891*0Sstevel@tonic-gate 	}
2892*0Sstevel@tonic-gate 
2893*0Sstevel@tonic-gate 	/* just accept the command */
2894*0Sstevel@tonic-gate 	if (transport == SCSA2USB_JUST_ACCEPT) {
2895*0Sstevel@tonic-gate 		SCSA2USB_SET_PKT_DO_COMP_STATE(scsa2usbp);
2896*0Sstevel@tonic-gate 
2897*0Sstevel@tonic-gate 		return (TRAN_ACCEPT);
2898*0Sstevel@tonic-gate 	}
2899*0Sstevel@tonic-gate 
2900*0Sstevel@tonic-gate 	/* check command set next */
2901*0Sstevel@tonic-gate 	if (SCSA2USB_IS_SCSI_CMDSET(scsa2usbp) ||
2902*0Sstevel@tonic-gate 	    SCSA2USB_IS_ATAPI_CMDSET(scsa2usbp)) {
2903*0Sstevel@tonic-gate 		transport =
2904*0Sstevel@tonic-gate 		    scsa2usb_handle_scsi_cmd_sub_class(scsa2usbp, cmd, pkt);
2905*0Sstevel@tonic-gate 	} else if (SCSA2USB_IS_UFI_CMDSET(scsa2usbp)) {
2906*0Sstevel@tonic-gate 		transport =
2907*0Sstevel@tonic-gate 		    scsa2usb_handle_ufi_subclass_cmd(scsa2usbp, cmd, pkt);
2908*0Sstevel@tonic-gate 	} else {
2909*0Sstevel@tonic-gate 		transport = SCSA2USB_REJECT;
2910*0Sstevel@tonic-gate 	}
2911*0Sstevel@tonic-gate 
2912*0Sstevel@tonic-gate 	if (transport == SCSA2USB_TRANSPORT) {
2913*0Sstevel@tonic-gate 		if (SCSA2USB_IS_BULK_ONLY(scsa2usbp)) {
2914*0Sstevel@tonic-gate 			rval = scsa2usb_bulk_only_transport(scsa2usbp, cmd);
2915*0Sstevel@tonic-gate 		} else if (SCSA2USB_IS_CB(scsa2usbp) ||
2916*0Sstevel@tonic-gate 		    SCSA2USB_IS_CBI(scsa2usbp)) {
2917*0Sstevel@tonic-gate 			rval = scsa2usb_cbi_transport(scsa2usbp, cmd);
2918*0Sstevel@tonic-gate 		} else {
2919*0Sstevel@tonic-gate 			rval = TRAN_FATAL_ERROR;
2920*0Sstevel@tonic-gate 		}
2921*0Sstevel@tonic-gate 	} else {
2922*0Sstevel@tonic-gate 		rval = TRAN_FATAL_ERROR;
2923*0Sstevel@tonic-gate 	}
2924*0Sstevel@tonic-gate 
2925*0Sstevel@tonic-gate 
2926*0Sstevel@tonic-gate 	return (rval);
2927*0Sstevel@tonic-gate }
2928*0Sstevel@tonic-gate 
2929*0Sstevel@tonic-gate 
2930*0Sstevel@tonic-gate /*
2931*0Sstevel@tonic-gate  * scsa2usb_check_bulkonly_blacklist_attrs:
2932*0Sstevel@tonic-gate  *	validate "scsa2usb_blacklist_attrs" (see scsa2usb.h)
2933*0Sstevel@tonic-gate  *	if blacklisted attrs match accept the request
2934*0Sstevel@tonic-gate  *	attributes checked are:-
2935*0Sstevel@tonic-gate  *		SCSA2USB_ATTRS_START_STOP
2936*0Sstevel@tonic-gate  */
2937*0Sstevel@tonic-gate int
2938*0Sstevel@tonic-gate scsa2usb_check_bulkonly_blacklist_attrs(scsa2usb_state_t *scsa2usbp,
2939*0Sstevel@tonic-gate     scsa2usb_cmd_t *cmd, uchar_t opcode)
2940*0Sstevel@tonic-gate {
2941*0Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
2942*0Sstevel@tonic-gate 	    "scsa2usb_check_bulkonly_blacklist_attrs: opcode = %s",
2943*0Sstevel@tonic-gate 	    scsi_cname(opcode, scsa2usb_cmds));
2944*0Sstevel@tonic-gate 
2945*0Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
2946*0Sstevel@tonic-gate 
2947*0Sstevel@tonic-gate 	/*
2948*0Sstevel@tonic-gate 	 * decode and convert the packet
2949*0Sstevel@tonic-gate 	 * for most cmds, we can bcopy the cdb
2950*0Sstevel@tonic-gate 	 */
2951*0Sstevel@tonic-gate 	switch (opcode) {
2952*0Sstevel@tonic-gate 	case SCMD_DOORLOCK:
2953*0Sstevel@tonic-gate 		if (!(scsa2usbp->scsa2usb_attrs & SCSA2USB_ATTRS_DOORLOCK)) {
2954*0Sstevel@tonic-gate 
2955*0Sstevel@tonic-gate 			return (SCSA2USB_JUST_ACCEPT);
2956*0Sstevel@tonic-gate 
2957*0Sstevel@tonic-gate 		} else if (scsa2usbp->scsa2usb_lun_inquiry[cmd->cmd_pkt->
2958*0Sstevel@tonic-gate 		    pkt_address.a_lun].inq_rmb) {
2959*0Sstevel@tonic-gate 
2960*0Sstevel@tonic-gate 			break;
2961*0Sstevel@tonic-gate 		}
2962*0Sstevel@tonic-gate 
2963*0Sstevel@tonic-gate 		return (SCSA2USB_JUST_ACCEPT);
2964*0Sstevel@tonic-gate 
2965*0Sstevel@tonic-gate 	case SCMD_START_STOP:
2966*0Sstevel@tonic-gate 		/*
2967*0Sstevel@tonic-gate 		 * these devices don't have mechanics that spin the
2968*0Sstevel@tonic-gate 		 * media up and down. So, it doesn't make much sense
2969*0Sstevel@tonic-gate 		 * to issue this cmd.
2970*0Sstevel@tonic-gate 		 *
2971*0Sstevel@tonic-gate 		 * Furthermore, Hagiwara devices do not handle these
2972*0Sstevel@tonic-gate 		 * cmds well. just accept this command as success.
2973*0Sstevel@tonic-gate 		 */
2974*0Sstevel@tonic-gate 		if (!(scsa2usbp->scsa2usb_attrs & SCSA2USB_ATTRS_START_STOP)) {
2975*0Sstevel@tonic-gate 
2976*0Sstevel@tonic-gate 			return (SCSA2USB_JUST_ACCEPT);
2977*0Sstevel@tonic-gate 
2978*0Sstevel@tonic-gate 		} else if (cmd->cmd_pkt->pkt_cdbp[4] & LOEJECT) {
2979*0Sstevel@tonic-gate 			/*
2980*0Sstevel@tonic-gate 			 * if the device is really a removable then
2981*0Sstevel@tonic-gate 			 * pass it on to the device, else just accept
2982*0Sstevel@tonic-gate 			 */
2983*0Sstevel@tonic-gate 			if (scsa2usbp->scsa2usb_lun_inquiry[cmd->cmd_pkt->
2984*0Sstevel@tonic-gate 			    pkt_address.a_lun].inq_rmb) {
2985*0Sstevel@tonic-gate 
2986*0Sstevel@tonic-gate 				break;
2987*0Sstevel@tonic-gate 			}
2988*0Sstevel@tonic-gate 
2989*0Sstevel@tonic-gate 			return (SCSA2USB_JUST_ACCEPT);
2990*0Sstevel@tonic-gate 
2991*0Sstevel@tonic-gate 		} else if (!scsa2usbp->scsa2usb_rcvd_not_ready) {
2992*0Sstevel@tonic-gate 			/*
2993*0Sstevel@tonic-gate 			 * if we have not received a NOT READY condition,
2994*0Sstevel@tonic-gate 			 * just accept since some device choke on this too.
2995*0Sstevel@tonic-gate 			 * we do have to let EJECT get through though
2996*0Sstevel@tonic-gate 			 */
2997*0Sstevel@tonic-gate 			return (SCSA2USB_JUST_ACCEPT);
2998*0Sstevel@tonic-gate 		}
2999*0Sstevel@tonic-gate 
3000*0Sstevel@tonic-gate 		break;
3001*0Sstevel@tonic-gate 	case SCMD_INQUIRY:
3002*0Sstevel@tonic-gate 		/*
3003*0Sstevel@tonic-gate 		 * Some devices do not handle the inquiry cmd well
3004*0Sstevel@tonic-gate 		 * so build an inquiry and accept this command as
3005*0Sstevel@tonic-gate 		 * success.
3006*0Sstevel@tonic-gate 		 */
3007*0Sstevel@tonic-gate 		if (!(scsa2usbp->scsa2usb_attrs & SCSA2USB_ATTRS_INQUIRY)) {
3008*0Sstevel@tonic-gate 			uchar_t evpd = 0x01;
3009*0Sstevel@tonic-gate 
3010*0Sstevel@tonic-gate 			if (cmd->cmd_cdb[1] & evpd) {
3011*0Sstevel@tonic-gate 
3012*0Sstevel@tonic-gate 				return (SCSA2USB_REJECT);
3013*0Sstevel@tonic-gate 			}
3014*0Sstevel@tonic-gate 			cmd->cmd_pkt->pkt_resid -=
3015*0Sstevel@tonic-gate 					scsa2usb_fake_inquiry(scsa2usbp, cmd,
3016*0Sstevel@tonic-gate 					cmd->cmd_pkt->pkt_address.a_lun);
3017*0Sstevel@tonic-gate 			cmd->cmd_pkt->pkt_state |= STATE_XFERRED_DATA;
3018*0Sstevel@tonic-gate 
3019*0Sstevel@tonic-gate 			return (SCSA2USB_JUST_ACCEPT);
3020*0Sstevel@tonic-gate 		}
3021*0Sstevel@tonic-gate 		break;
3022*0Sstevel@tonic-gate 
3023*0Sstevel@tonic-gate 	/*
3024*0Sstevel@tonic-gate 	 * Fake accepting the following two Opcodes
3025*0Sstevel@tonic-gate 	 * (as the drive doesn't support it.)
3026*0Sstevel@tonic-gate 	 * These are needed by format command.
3027*0Sstevel@tonic-gate 	 */
3028*0Sstevel@tonic-gate 	case SCMD_RESERVE:
3029*0Sstevel@tonic-gate 	case SCMD_RELEASE:
3030*0Sstevel@tonic-gate 	case SCMD_PERSISTENT_RESERVE_IN:
3031*0Sstevel@tonic-gate 	case SCMD_PERSISTENT_RESERVE_OUT:
3032*0Sstevel@tonic-gate 
3033*0Sstevel@tonic-gate 		return (SCSA2USB_JUST_ACCEPT);
3034*0Sstevel@tonic-gate 
3035*0Sstevel@tonic-gate 	case SCMD_MODE_SENSE:
3036*0Sstevel@tonic-gate 	case SCMD_MODE_SELECT:
3037*0Sstevel@tonic-gate 	case SCMD_MODE_SENSE_G1:
3038*0Sstevel@tonic-gate 	case SCMD_MODE_SELECT_G1:
3039*0Sstevel@tonic-gate 		if (!(scsa2usbp->scsa2usb_attrs & SCSA2USB_ATTRS_MODE_SENSE)) {
3040*0Sstevel@tonic-gate 			if (cmd->cmd_bp) {
3041*0Sstevel@tonic-gate 				cmd->cmd_pkt->pkt_resid = cmd->cmd_bp->
3042*0Sstevel@tonic-gate 								b_bcount;
3043*0Sstevel@tonic-gate 			}
3044*0Sstevel@tonic-gate 			scsa2usb_force_invalid_request(scsa2usbp, cmd);
3045*0Sstevel@tonic-gate 
3046*0Sstevel@tonic-gate 			return (SCSA2USB_JUST_ACCEPT);
3047*0Sstevel@tonic-gate 		}
3048*0Sstevel@tonic-gate 
3049*0Sstevel@tonic-gate 		break;
3050*0Sstevel@tonic-gate 	default:
3051*0Sstevel@tonic-gate 
3052*0Sstevel@tonic-gate 		break;
3053*0Sstevel@tonic-gate 	}
3054*0Sstevel@tonic-gate 
3055*0Sstevel@tonic-gate 	return (SCSA2USB_TRANSPORT);
3056*0Sstevel@tonic-gate }
3057*0Sstevel@tonic-gate 
3058*0Sstevel@tonic-gate 
3059*0Sstevel@tonic-gate /*
3060*0Sstevel@tonic-gate  * scsa2usb_handle_scsi_cmd_sub_class:
3061*0Sstevel@tonic-gate  *	prepare a scsi cmd
3062*0Sstevel@tonic-gate  *	returns SCSA2USB_TRANSPORT, SCSA2USB_REJECT, SCSA2USB_JUST_ACCEPT
3063*0Sstevel@tonic-gate  */
3064*0Sstevel@tonic-gate int
3065*0Sstevel@tonic-gate scsa2usb_handle_scsi_cmd_sub_class(scsa2usb_state_t *scsa2usbp,
3066*0Sstevel@tonic-gate     scsa2usb_cmd_t *cmd, struct scsi_pkt *pkt)
3067*0Sstevel@tonic-gate {
3068*0Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
3069*0Sstevel@tonic-gate 	    "scsa2usb_handle_scsi_cmd_sub_class: cmd = 0x%p pkt = 0x%p",
3070*0Sstevel@tonic-gate 	    cmd, pkt);
3071*0Sstevel@tonic-gate 
3072*0Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
3073*0Sstevel@tonic-gate 
3074*0Sstevel@tonic-gate 	bzero(&cmd->cmd_cdb, SCSI_CDB_SIZE);
3075*0Sstevel@tonic-gate 	cmd->cmd_cdb[SCSA2USB_OPCODE] = pkt->pkt_cdbp[0];   /* Set the opcode */
3076*0Sstevel@tonic-gate 	cmd->cmd_cdb[SCSA2USB_LUN] = pkt->pkt_cdbp[1];
3077*0Sstevel@tonic-gate 
3078*0Sstevel@tonic-gate 	/*
3079*0Sstevel@tonic-gate 	 * decode and convert the packet
3080*0Sstevel@tonic-gate 	 * for most cmds, we can bcopy the cdb
3081*0Sstevel@tonic-gate 	 */
3082*0Sstevel@tonic-gate 	switch (pkt->pkt_cdbp[0]) {
3083*0Sstevel@tonic-gate 	case SCMD_FORMAT:
3084*0Sstevel@tonic-gate 		/*
3085*0Sstevel@tonic-gate 		 * SCMD_FORMAT used to limit cmd->cmd_xfercount
3086*0Sstevel@tonic-gate 		 * to 4 bytes, but this hangs
3087*0Sstevel@tonic-gate 		 * formatting dvd media using cdrecord (that is,
3088*0Sstevel@tonic-gate 		 * a SCSI FORMAT UNIT command with a parameter list > 4 bytes)
3089*0Sstevel@tonic-gate 		 * (bit 4 in cdb1 is the Fmtdata bit)
3090*0Sstevel@tonic-gate 		 */
3091*0Sstevel@tonic-gate 		if ((pkt->pkt_cdbp[1] & 0x10) && cmd->cmd_bp) {
3092*0Sstevel@tonic-gate 			cmd->cmd_xfercount = cmd->cmd_bp->b_bcount;
3093*0Sstevel@tonic-gate 		} else {
3094*0Sstevel@tonic-gate 			cmd->cmd_xfercount = 4;
3095*0Sstevel@tonic-gate 		}
3096*0Sstevel@tonic-gate 		cmd->cmd_dir = CBW_DIR_OUT;
3097*0Sstevel@tonic-gate 		cmd->cmd_actual_len = CDB_GROUP0;
3098*0Sstevel@tonic-gate 		bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
3099*0Sstevel@tonic-gate 		break;
3100*0Sstevel@tonic-gate 
3101*0Sstevel@tonic-gate 	case SCMD_INQUIRY:
3102*0Sstevel@tonic-gate 		cmd->cmd_dir = CBW_DIR_IN;
3103*0Sstevel@tonic-gate 		cmd->cmd_actual_len = CDB_GROUP0;
3104*0Sstevel@tonic-gate 		cmd->cmd_cdb[SCSA2USB_LBA_0] = pkt->pkt_cdbp[2];
3105*0Sstevel@tonic-gate 		cmd->cmd_cdb[SCSA2USB_LBA_2] = cmd->cmd_xfercount =
3106*0Sstevel@tonic-gate 		    min(SCSA2USB_MAX_INQ_LEN,
3107*0Sstevel@tonic-gate 		    cmd->cmd_bp ? cmd->cmd_bp->b_bcount : 0);
3108*0Sstevel@tonic-gate 		break;
3109*0Sstevel@tonic-gate 
3110*0Sstevel@tonic-gate 	case SCMD_READ_CAPACITY:
3111*0Sstevel@tonic-gate 		cmd->cmd_dir = CBW_DIR_IN;
3112*0Sstevel@tonic-gate 		bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
3113*0Sstevel@tonic-gate 		cmd->cmd_xfercount = sizeof (scsa2usb_read_cap_t);
3114*0Sstevel@tonic-gate 		break;
3115*0Sstevel@tonic-gate 
3116*0Sstevel@tonic-gate 	/*
3117*0Sstevel@tonic-gate 	 * SCMD_READ/SCMD_WRITE are converted to G1 cmds
3118*0Sstevel@tonic-gate 	 * (as ATAPI devices don't recognize G0 commands)
3119*0Sstevel@tonic-gate 	 *
3120*0Sstevel@tonic-gate 	 * SCMD_READ_LONG/SCMD_WRITE_LONG are handled in
3121*0Sstevel@tonic-gate 	 * scsa2usb_rw_transport() along with other commands.
3122*0Sstevel@tonic-gate 	 *
3123*0Sstevel@tonic-gate 	 * USB Host Controllers cannot handle large (read/write)
3124*0Sstevel@tonic-gate 	 * xfers. We split the large request to chunks of
3125*0Sstevel@tonic-gate 	 * smaller ones to meet the HCD limitations.
3126*0Sstevel@tonic-gate 	 */
3127*0Sstevel@tonic-gate 	case SCMD_READ:
3128*0Sstevel@tonic-gate 	case SCMD_WRITE:
3129*0Sstevel@tonic-gate 	case SCMD_READ_G1:
3130*0Sstevel@tonic-gate 	case SCMD_WRITE_G1:
3131*0Sstevel@tonic-gate 	case SCMD_READ_G5:
3132*0Sstevel@tonic-gate 	case SCMD_WRITE_G5:
3133*0Sstevel@tonic-gate 	case SCMD_READ_LONG:
3134*0Sstevel@tonic-gate 	case SCMD_WRITE_LONG:
3135*0Sstevel@tonic-gate 	case SCMD_READ_CD:
3136*0Sstevel@tonic-gate 		switch (scsa2usbp->
3137*0Sstevel@tonic-gate 		    scsa2usb_lun_inquiry[pkt->pkt_address.a_lun].
3138*0Sstevel@tonic-gate 		    inq_dtype & DTYPE_MASK) {
3139*0Sstevel@tonic-gate 		case DTYPE_DIRECT:
3140*0Sstevel@tonic-gate 		case DTYPE_RODIRECT:
3141*0Sstevel@tonic-gate 		case DTYPE_OPTICAL:
3142*0Sstevel@tonic-gate 			return (scsa2usb_rw_transport(
3143*0Sstevel@tonic-gate 					scsa2usbp, pkt));
3144*0Sstevel@tonic-gate 		default:
3145*0Sstevel@tonic-gate 			bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
3146*0Sstevel@tonic-gate 			if (cmd->cmd_bp) {
3147*0Sstevel@tonic-gate 				cmd->cmd_dir =
3148*0Sstevel@tonic-gate 				    (cmd->cmd_bp->b_flags & B_READ) ?
3149*0Sstevel@tonic-gate 				    CBW_DIR_IN : CBW_DIR_OUT;
3150*0Sstevel@tonic-gate 				cmd->cmd_xfercount =
3151*0Sstevel@tonic-gate 				    cmd->cmd_bp->b_bcount;
3152*0Sstevel@tonic-gate 			}
3153*0Sstevel@tonic-gate 			break;
3154*0Sstevel@tonic-gate 		}
3155*0Sstevel@tonic-gate 		break;
3156*0Sstevel@tonic-gate 
3157*0Sstevel@tonic-gate 	case SCMD_REQUEST_SENSE:
3158*0Sstevel@tonic-gate 		cmd->cmd_dir = CBW_DIR_IN;
3159*0Sstevel@tonic-gate 		cmd->cmd_xfercount = pkt->pkt_cdbp[4];
3160*0Sstevel@tonic-gate 		cmd->cmd_cdb[SCSA2USB_LBA_2] = pkt->pkt_cdbp[4];
3161*0Sstevel@tonic-gate 		cmd->cmd_actual_len = CDB_GROUP0;
3162*0Sstevel@tonic-gate 		break;
3163*0Sstevel@tonic-gate 
3164*0Sstevel@tonic-gate 	/*
3165*0Sstevel@tonic-gate 	 * do not convert SCMD_MODE_SENSE/SELECT to G1 cmds because
3166*0Sstevel@tonic-gate 	 * the mode header is different as well
3167*0Sstevel@tonic-gate 	 */
3168*0Sstevel@tonic-gate 
3169*0Sstevel@tonic-gate 	case SCMD_DOORLOCK:
3170*0Sstevel@tonic-gate 	case SCMD_START_STOP:
3171*0Sstevel@tonic-gate 	case SCMD_TEST_UNIT_READY:
3172*0Sstevel@tonic-gate 		bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
3173*0Sstevel@tonic-gate 		break;
3174*0Sstevel@tonic-gate 
3175*0Sstevel@tonic-gate 	/*
3176*0Sstevel@tonic-gate 	 * Needed by zip protocol to reset the device
3177*0Sstevel@tonic-gate 	 */
3178*0Sstevel@tonic-gate 	case SCMD_SDIAG:
3179*0Sstevel@tonic-gate 	case SCMD_REZERO_UNIT:
3180*0Sstevel@tonic-gate 		bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
3181*0Sstevel@tonic-gate 		cmd->cmd_actual_len = CDB_GROUP1;
3182*0Sstevel@tonic-gate 		break;
3183*0Sstevel@tonic-gate 
3184*0Sstevel@tonic-gate 	case SCMD_WRITE_VERIFY:
3185*0Sstevel@tonic-gate 		bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
3186*0Sstevel@tonic-gate 		cmd->cmd_dir = CBW_DIR_OUT;
3187*0Sstevel@tonic-gate 		cmd->cmd_xfercount = (pkt->pkt_cdbp[7] << 8) | pkt->pkt_cdbp[8];
3188*0Sstevel@tonic-gate 		cmd->cmd_actual_len = CDB_GROUP1;
3189*0Sstevel@tonic-gate 		break;
3190*0Sstevel@tonic-gate 
3191*0Sstevel@tonic-gate 	/*
3192*0Sstevel@tonic-gate 	 * Next command does not have a SCSI equivalent as
3193*0Sstevel@tonic-gate 	 * it is vendor specific.
3194*0Sstevel@tonic-gate 	 * It was listed in the vendor's ATAPI Zip specs.
3195*0Sstevel@tonic-gate 	 */
3196*0Sstevel@tonic-gate 	case SCMD_READ_FORMAT_CAP:
3197*0Sstevel@tonic-gate 		bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
3198*0Sstevel@tonic-gate 		cmd->cmd_dir = CBW_DIR_IN;
3199*0Sstevel@tonic-gate 		cmd->cmd_xfercount = (pkt->pkt_cdbp[7] << 8) | pkt->pkt_cdbp[8];
3200*0Sstevel@tonic-gate 		cmd->cmd_actual_len = CDB_GROUP1;
3201*0Sstevel@tonic-gate 		break;
3202*0Sstevel@tonic-gate 	case IOMEGA_CMD_CARTRIDGE_PROTECT:
3203*0Sstevel@tonic-gate 		cmd->cmd_dir = CBW_DIR_OUT;
3204*0Sstevel@tonic-gate 		cmd->cmd_cdb[SCSA2USB_LBA_2] = pkt->pkt_cdbp[4];
3205*0Sstevel@tonic-gate 		cmd->cmd_cdb[SCSA2USB_LBA_2] &= ~1;	/* Make it even */
3206*0Sstevel@tonic-gate 		cmd->cmd_cdb[SCSA2USB_LUN] = pkt->pkt_cdbp[1];
3207*0Sstevel@tonic-gate 		cmd->cmd_actual_len = CDB_GROUP0;
3208*0Sstevel@tonic-gate 		cmd->cmd_xfercount = pkt->pkt_cdbp[4]; /* Length of password */
3209*0Sstevel@tonic-gate 		break;
3210*0Sstevel@tonic-gate 
3211*0Sstevel@tonic-gate 	default:
3212*0Sstevel@tonic-gate 		/*
3213*0Sstevel@tonic-gate 		 * an unknown command may be a uscsi cmd which we
3214*0Sstevel@tonic-gate 		 * should let go thru without mapping
3215*0Sstevel@tonic-gate 		 */
3216*0Sstevel@tonic-gate 		bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
3217*0Sstevel@tonic-gate 		if (cmd->cmd_bp) {
3218*0Sstevel@tonic-gate 			cmd->cmd_dir = (cmd->cmd_bp->b_flags & B_READ) ?
3219*0Sstevel@tonic-gate 						CBW_DIR_IN : CBW_DIR_OUT;
3220*0Sstevel@tonic-gate 			cmd->cmd_xfercount = cmd->cmd_bp->b_bcount;
3221*0Sstevel@tonic-gate 		}
3222*0Sstevel@tonic-gate 
3223*0Sstevel@tonic-gate 		break;
3224*0Sstevel@tonic-gate 	} /* end of switch */
3225*0Sstevel@tonic-gate 
3226*0Sstevel@tonic-gate 	USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
3227*0Sstevel@tonic-gate 	    "scsa2usb_handle_scsi_cmd_sub_class: opcode = 0x%x count = 0x%lx",
3228*0Sstevel@tonic-gate 	    pkt->pkt_cdbp[SCSA2USB_OPCODE], cmd->cmd_xfercount);
3229*0Sstevel@tonic-gate 
3230*0Sstevel@tonic-gate 	cmd->cmd_total_xfercount = cmd->cmd_xfercount;
3231*0Sstevel@tonic-gate 
3232*0Sstevel@tonic-gate 	return (SCSA2USB_TRANSPORT);
3233*0Sstevel@tonic-gate }
3234*0Sstevel@tonic-gate 
3235*0Sstevel@tonic-gate 
3236*0Sstevel@tonic-gate /*
3237*0Sstevel@tonic-gate  * scsa2usb_check_ufi_blacklist_attrs:
3238*0Sstevel@tonic-gate  *	validate "scsa2usb_blacklist_attrs" (see scsa2usb.h)
3239*0Sstevel@tonic-gate  *	if blacklisted attrs match accept the request
3240*0Sstevel@tonic-gate  *	attributes checked are:-
3241*0Sstevel@tonic-gate  *		SCSA2USB_ATTRS_GET_CONF
3242*0Sstevel@tonic-gate  *		SCSA2USB_ATTRS_GET_PERF
3243*0Sstevel@tonic-gate  *		SCSA2USB_ATTRS_GET_START_STOP
3244*0Sstevel@tonic-gate  */
3245*0Sstevel@tonic-gate static int
3246*0Sstevel@tonic-gate scsa2usb_check_ufi_blacklist_attrs(scsa2usb_state_t *scsa2usbp, uchar_t opcode,
3247*0Sstevel@tonic-gate     scsa2usb_cmd_t *cmd)
3248*0Sstevel@tonic-gate {
3249*0Sstevel@tonic-gate 	int	rval = SCSA2USB_TRANSPORT;
3250*0Sstevel@tonic-gate 
3251*0Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
3252*0Sstevel@tonic-gate 
3253*0Sstevel@tonic-gate 	switch (opcode) {
3254*0Sstevel@tonic-gate 	case SCMD_PRIN:
3255*0Sstevel@tonic-gate 	case SCMD_PROUT:
3256*0Sstevel@tonic-gate 		rval = SCSA2USB_JUST_ACCEPT;
3257*0Sstevel@tonic-gate 		break;
3258*0Sstevel@tonic-gate 	case SCMD_MODE_SENSE:
3259*0Sstevel@tonic-gate 	case SCMD_MODE_SELECT:
3260*0Sstevel@tonic-gate 		if (cmd->cmd_bp) {
3261*0Sstevel@tonic-gate 			cmd->cmd_pkt->pkt_resid = cmd->cmd_bp->b_bcount;
3262*0Sstevel@tonic-gate 		}
3263*0Sstevel@tonic-gate 		scsa2usb_force_invalid_request(scsa2usbp, cmd);
3264*0Sstevel@tonic-gate 		rval = SCSA2USB_JUST_ACCEPT;
3265*0Sstevel@tonic-gate 		break;
3266*0Sstevel@tonic-gate 	case SCMD_GET_CONFIGURATION:
3267*0Sstevel@tonic-gate 		if (!(scsa2usbp->scsa2usb_attrs & SCSA2USB_ATTRS_GET_CONF)) {
3268*0Sstevel@tonic-gate 			rval = SCSA2USB_JUST_ACCEPT;
3269*0Sstevel@tonic-gate 		}
3270*0Sstevel@tonic-gate 		break;
3271*0Sstevel@tonic-gate 	case SCMD_GET_PERFORMANCE:
3272*0Sstevel@tonic-gate 		if (!(scsa2usbp->scsa2usb_attrs & SCSA2USB_ATTRS_GET_PERF)) {
3273*0Sstevel@tonic-gate 			rval = SCSA2USB_JUST_ACCEPT;
3274*0Sstevel@tonic-gate 		}
3275*0Sstevel@tonic-gate 		break;
3276*0Sstevel@tonic-gate 	case SCMD_START_STOP:
3277*0Sstevel@tonic-gate 		/*
3278*0Sstevel@tonic-gate 		 * some CB/CBI devices don't have mechanics that spin the
3279*0Sstevel@tonic-gate 		 * media up and down. So, it doesn't make much sense
3280*0Sstevel@tonic-gate 		 * to issue this cmd to those devices.
3281*0Sstevel@tonic-gate 		 */
3282*0Sstevel@tonic-gate 		if (!(scsa2usbp->scsa2usb_attrs & SCSA2USB_ATTRS_START_STOP)) {
3283*0Sstevel@tonic-gate 			rval = SCSA2USB_JUST_ACCEPT;
3284*0Sstevel@tonic-gate 		}
3285*0Sstevel@tonic-gate 		break;
3286*0Sstevel@tonic-gate 	default:
3287*0Sstevel@tonic-gate 		break;
3288*0Sstevel@tonic-gate 	}
3289*0Sstevel@tonic-gate 
3290*0Sstevel@tonic-gate 	return (rval);
3291*0Sstevel@tonic-gate }
3292*0Sstevel@tonic-gate 
3293*0Sstevel@tonic-gate 
3294*0Sstevel@tonic-gate /*
3295*0Sstevel@tonic-gate  * scsa2usb_handle_ufi_subclass_cmd:
3296*0Sstevel@tonic-gate  *	prepare a UFI cmd
3297*0Sstevel@tonic-gate  *	returns SCSA2USB_TRANSPORT, SCSA2USB_REJECT
3298*0Sstevel@tonic-gate  */
3299*0Sstevel@tonic-gate int
3300*0Sstevel@tonic-gate scsa2usb_handle_ufi_subclass_cmd(scsa2usb_state_t *scsa2usbp,
3301*0Sstevel@tonic-gate     scsa2usb_cmd_t *cmd, struct scsi_pkt *pkt)
3302*0Sstevel@tonic-gate {
3303*0Sstevel@tonic-gate 	uchar_t opcode =  pkt->pkt_cdbp[0];
3304*0Sstevel@tonic-gate 
3305*0Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
3306*0Sstevel@tonic-gate 	    "scsa2usb_handle_ufi_subclass_cmd: cmd = 0x%p pkt = 0x%p",
3307*0Sstevel@tonic-gate 	    cmd, pkt);
3308*0Sstevel@tonic-gate 
3309*0Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
3310*0Sstevel@tonic-gate 
3311*0Sstevel@tonic-gate 	bzero(&cmd->cmd_cdb, SCSI_CDB_SIZE);
3312*0Sstevel@tonic-gate 	cmd->cmd_cdb[SCSA2USB_OPCODE] = opcode;   /* Set the opcode */
3313*0Sstevel@tonic-gate 	cmd->cmd_cdb[SCSA2USB_LUN] = pkt->pkt_cdbp[1];
3314*0Sstevel@tonic-gate 
3315*0Sstevel@tonic-gate 	/*
3316*0Sstevel@tonic-gate 	 * decode and convert the packet if necessary
3317*0Sstevel@tonic-gate 	 * for most cmds, we can bcopy the cdb
3318*0Sstevel@tonic-gate 	 */
3319*0Sstevel@tonic-gate 	switch (opcode) {
3320*0Sstevel@tonic-gate 	case SCMD_FORMAT:
3321*0Sstevel@tonic-gate 		/* if parameter list is specified */
3322*0Sstevel@tonic-gate 		if (pkt->pkt_cdbp[1] & 0x10) {
3323*0Sstevel@tonic-gate 			cmd->cmd_xfercount =
3324*0Sstevel@tonic-gate 				(pkt->pkt_cdbp[7] << 8) | pkt->pkt_cdbp[8];
3325*0Sstevel@tonic-gate 			cmd->cmd_dir = USB_EP_DIR_OUT;
3326*0Sstevel@tonic-gate 			cmd->cmd_actual_len = CDB_GROUP5;
3327*0Sstevel@tonic-gate 		}
3328*0Sstevel@tonic-gate 		bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
3329*0Sstevel@tonic-gate 		break;
3330*0Sstevel@tonic-gate 	case SCMD_INQUIRY:
3331*0Sstevel@tonic-gate 		cmd->cmd_dir = USB_EP_DIR_IN;
3332*0Sstevel@tonic-gate 		cmd->cmd_actual_len = CDB_GROUP0;
3333*0Sstevel@tonic-gate 		cmd->cmd_cdb[SCSA2USB_LBA_0] = pkt->pkt_cdbp[2];
3334*0Sstevel@tonic-gate 		cmd->cmd_cdb[SCSA2USB_LBA_2] = cmd->cmd_xfercount =
3335*0Sstevel@tonic-gate 		    min(SCSA2USB_MAX_INQ_LEN,
3336*0Sstevel@tonic-gate 		    cmd->cmd_bp ? cmd->cmd_bp->b_bcount : 0);
3337*0Sstevel@tonic-gate 		break;
3338*0Sstevel@tonic-gate 	case SCMD_READ_CAPACITY:
3339*0Sstevel@tonic-gate 		cmd->cmd_dir = USB_EP_DIR_IN;
3340*0Sstevel@tonic-gate 		bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
3341*0Sstevel@tonic-gate 		cmd->cmd_xfercount = sizeof (scsa2usb_read_cap_t);
3342*0Sstevel@tonic-gate 		break;
3343*0Sstevel@tonic-gate 	case SCMD_REQUEST_SENSE:
3344*0Sstevel@tonic-gate 		cmd->cmd_dir = USB_EP_DIR_IN;
3345*0Sstevel@tonic-gate 		cmd->cmd_xfercount = pkt->pkt_cdbp[4];
3346*0Sstevel@tonic-gate 		cmd->cmd_cdb[SCSA2USB_LBA_2] = pkt->pkt_cdbp[4];
3347*0Sstevel@tonic-gate 		cmd->cmd_actual_len = CDB_GROUP0;
3348*0Sstevel@tonic-gate 		break;
3349*0Sstevel@tonic-gate 
3350*0Sstevel@tonic-gate 	/*
3351*0Sstevel@tonic-gate 	 * do not convert SCMD_MODE_SENSE/SELECT because the
3352*0Sstevel@tonic-gate 	 * mode header is different as well
3353*0Sstevel@tonic-gate 	 */
3354*0Sstevel@tonic-gate 
3355*0Sstevel@tonic-gate 	/*
3356*0Sstevel@tonic-gate 	 * see usb_bulkonly.c for comments on the next set of commands
3357*0Sstevel@tonic-gate 	 */
3358*0Sstevel@tonic-gate 	case SCMD_READ:
3359*0Sstevel@tonic-gate 	case SCMD_WRITE:
3360*0Sstevel@tonic-gate 	case SCMD_READ_G1:
3361*0Sstevel@tonic-gate 	case SCMD_WRITE_G1:
3362*0Sstevel@tonic-gate 	case SCMD_READ_G5:
3363*0Sstevel@tonic-gate 	case SCMD_WRITE_G5:
3364*0Sstevel@tonic-gate 	case SCMD_READ_LONG:
3365*0Sstevel@tonic-gate 	case SCMD_WRITE_LONG:
3366*0Sstevel@tonic-gate 	case SCMD_READ_CD:
3367*0Sstevel@tonic-gate 
3368*0Sstevel@tonic-gate 		return (scsa2usb_rw_transport(scsa2usbp, pkt));
3369*0Sstevel@tonic-gate 
3370*0Sstevel@tonic-gate 	case SCMD_TEST_UNIT_READY:
3371*0Sstevel@tonic-gate 		/*
3372*0Sstevel@tonic-gate 		 * Some CB/CBI devices may not support TUR.
3373*0Sstevel@tonic-gate 		 */
3374*0Sstevel@tonic-gate 		bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
3375*0Sstevel@tonic-gate 		break;
3376*0Sstevel@tonic-gate 	case SCMD_READ_FORMAT_CAP:
3377*0Sstevel@tonic-gate 		bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
3378*0Sstevel@tonic-gate 		cmd->cmd_dir = USB_EP_DIR_IN;
3379*0Sstevel@tonic-gate 		cmd->cmd_actual_len = CDB_GROUP1;
3380*0Sstevel@tonic-gate 		cmd->cmd_xfercount = (pkt->pkt_cdbp[7] << 8) | pkt->pkt_cdbp[8];
3381*0Sstevel@tonic-gate 		break;
3382*0Sstevel@tonic-gate 	case SCMD_WRITE_VERIFY:
3383*0Sstevel@tonic-gate 		bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
3384*0Sstevel@tonic-gate 		cmd->cmd_dir = USB_EP_DIR_OUT;
3385*0Sstevel@tonic-gate 		cmd->cmd_actual_len = CDB_GROUP1;
3386*0Sstevel@tonic-gate 		cmd->cmd_xfercount = (pkt->pkt_cdbp[7] << 8) | pkt->pkt_cdbp[8];
3387*0Sstevel@tonic-gate 		break;
3388*0Sstevel@tonic-gate 	case SCMD_START_STOP:
3389*0Sstevel@tonic-gate 		/* A larger timeout is needed for 'flaky' CD-RW devices */
3390*0Sstevel@tonic-gate 		if (!(scsa2usbp->scsa2usb_attrs & SCSA2USB_ATTRS_BIG_TIMEOUT)) {
3391*0Sstevel@tonic-gate 			cmd->cmd_timeout = max(cmd->cmd_timeout,
3392*0Sstevel@tonic-gate 					20 * SCSA2USB_BULK_PIPE_TIMEOUT);
3393*0Sstevel@tonic-gate 		}
3394*0Sstevel@tonic-gate 		/* FALLTHRU */
3395*0Sstevel@tonic-gate 	default:
3396*0Sstevel@tonic-gate 		/*
3397*0Sstevel@tonic-gate 		 * all other commands don't need special mapping
3398*0Sstevel@tonic-gate 		 */
3399*0Sstevel@tonic-gate 		bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
3400*0Sstevel@tonic-gate 		if (cmd->cmd_bp) {
3401*0Sstevel@tonic-gate 			cmd->cmd_dir = (cmd->cmd_bp->b_flags & B_READ) ?
3402*0Sstevel@tonic-gate 						CBW_DIR_IN : CBW_DIR_OUT;
3403*0Sstevel@tonic-gate 			cmd->cmd_xfercount = cmd->cmd_bp->b_bcount;
3404*0Sstevel@tonic-gate 		}
3405*0Sstevel@tonic-gate 		break;
3406*0Sstevel@tonic-gate 
3407*0Sstevel@tonic-gate 	} /* end of switch */
3408*0Sstevel@tonic-gate 
3409*0Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
3410*0Sstevel@tonic-gate 	    "scsa2usb_handle_ufi_subclass_cmd: opcode = 0x%x count = 0x%lx",
3411*0Sstevel@tonic-gate 	    opcode, cmd->cmd_xfercount);
3412*0Sstevel@tonic-gate 
3413*0Sstevel@tonic-gate 	cmd->cmd_total_xfercount = cmd->cmd_xfercount;
3414*0Sstevel@tonic-gate 
3415*0Sstevel@tonic-gate 	return (SCSA2USB_TRANSPORT);
3416*0Sstevel@tonic-gate }
3417*0Sstevel@tonic-gate 
3418*0Sstevel@tonic-gate 
3419*0Sstevel@tonic-gate /*
3420*0Sstevel@tonic-gate  * scsa2usb_rw_transport:
3421*0Sstevel@tonic-gate  *	Handle splitting READ and WRITE requests to the
3422*0Sstevel@tonic-gate  *	device to a size that the host controller allows.
3423*0Sstevel@tonic-gate  *
3424*0Sstevel@tonic-gate  *	returns TRAN_* values and not USB_SUCCESS/FAILURE
3425*0Sstevel@tonic-gate  *
3426*0Sstevel@tonic-gate  * To support CD-R/CD-RW/DVD media, we need to support a
3427*0Sstevel@tonic-gate  * variety of block sizes for the different types of CD
3428*0Sstevel@tonic-gate  * data (audio, data, video, CD-XA, yellowbook, redbook etc.)
3429*0Sstevel@tonic-gate  *
3430*0Sstevel@tonic-gate  * Some of the block sizes used are:- 512, 1k, 2k, 2056, 2336
3431*0Sstevel@tonic-gate  * 2340, 2352, 2368, 2448, 2646, 2647 etc.
3432*0Sstevel@tonic-gate  *
3433*0Sstevel@tonic-gate  * NOTE: the driver could be entertaining a SCSI CDB that uses
3434*0Sstevel@tonic-gate  * any of the above listed block sizes at a given time, and a
3435*0Sstevel@tonic-gate  * totally different block size at any other given time for a
3436*0Sstevel@tonic-gate  * different CDB.
3437*0Sstevel@tonic-gate  *
3438*0Sstevel@tonic-gate  * We need to compute block size every time and figure out
3439*0Sstevel@tonic-gate  * matching LBA and LEN accordingly.
3440*0Sstevel@tonic-gate  *
3441*0Sstevel@tonic-gate  * Also UHCI has a limitation that it can only xfer 32k at a
3442*0Sstevel@tonic-gate  * given time. So, with "odd" sized blocks and a limitation of
3443*0Sstevel@tonic-gate  * how much we can xfer per shot, we need to compute xfer_count
3444*0Sstevel@tonic-gate  * as well each time.
3445*0Sstevel@tonic-gate  *
3446*0Sstevel@tonic-gate  * The same computation is also done in the function
3447*0Sstevel@tonic-gate  * scsa2usb_setup_next_xfer().	To save computing block_size in
3448*0Sstevel@tonic-gate  * this function, I am saving block_size in "cmd" now.
3449*0Sstevel@tonic-gate  */
3450*0Sstevel@tonic-gate int
3451*0Sstevel@tonic-gate scsa2usb_rw_transport(scsa2usb_state_t *scsa2usbp, struct scsi_pkt *pkt)
3452*0Sstevel@tonic-gate {
3453*0Sstevel@tonic-gate 	scsa2usb_cmd_t *cmd = PKT2CMD(pkt);
3454*0Sstevel@tonic-gate 	int lba, dir, opcode;
3455*0Sstevel@tonic-gate 	struct buf *bp = cmd->cmd_bp;
3456*0Sstevel@tonic-gate 	size_t len, xfer_count;
3457*0Sstevel@tonic-gate 	size_t blk_size;	/* calculate the block size to be used */
3458*0Sstevel@tonic-gate 	int sz;
3459*0Sstevel@tonic-gate 
3460*0Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
3461*0Sstevel@tonic-gate 	    "scsa2usb_rw_transport:");
3462*0Sstevel@tonic-gate 
3463*0Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
3464*0Sstevel@tonic-gate 
3465*0Sstevel@tonic-gate 	opcode = pkt->pkt_cdbp[0];
3466*0Sstevel@tonic-gate 	blk_size  = scsa2usbp->scsa2usb_lbasize[pkt->pkt_address.a_lun];
3467*0Sstevel@tonic-gate 						/* set to default */
3468*0Sstevel@tonic-gate 
3469*0Sstevel@tonic-gate 	switch (opcode) {
3470*0Sstevel@tonic-gate 	case SCMD_READ:
3471*0Sstevel@tonic-gate 		/*
3472*0Sstevel@tonic-gate 		 * Note that READ/WRITE(6) are not supported by the drive.
3473*0Sstevel@tonic-gate 		 * convert it into a 10 byte read/write.
3474*0Sstevel@tonic-gate 		 */
3475*0Sstevel@tonic-gate 		lba = SCSA2USB_LBA_6BYTE(pkt);
3476*0Sstevel@tonic-gate 		len = SCSA2USB_LEN_6BYTE(pkt);
3477*0Sstevel@tonic-gate 		opcode = SCMD_READ_G1;	/* Overwrite it w/ byte 10 cmd val */
3478*0Sstevel@tonic-gate 		dir = USB_EP_DIR_IN;
3479*0Sstevel@tonic-gate 		break;
3480*0Sstevel@tonic-gate 	case SCMD_WRITE:
3481*0Sstevel@tonic-gate 		lba = SCSA2USB_LBA_6BYTE(pkt);
3482*0Sstevel@tonic-gate 		len = SCSA2USB_LEN_6BYTE(pkt);
3483*0Sstevel@tonic-gate 		opcode = SCMD_WRITE_G1;	/* Overwrite it w/ byte 10 cmd val */
3484*0Sstevel@tonic-gate 		dir = USB_EP_DIR_OUT;
3485*0Sstevel@tonic-gate 		break;
3486*0Sstevel@tonic-gate 	case SCMD_READ_G1:
3487*0Sstevel@tonic-gate 	case SCMD_READ_LONG:
3488*0Sstevel@tonic-gate 		lba = SCSA2USB_LBA_10BYTE(pkt);
3489*0Sstevel@tonic-gate 		len = SCSA2USB_LEN_10BYTE(pkt);
3490*0Sstevel@tonic-gate 		dir = USB_EP_DIR_IN;
3491*0Sstevel@tonic-gate 		break;
3492*0Sstevel@tonic-gate 	case SCMD_WRITE_G1:
3493*0Sstevel@tonic-gate 	case SCMD_WRITE_LONG:
3494*0Sstevel@tonic-gate 		lba = SCSA2USB_LBA_10BYTE(pkt);
3495*0Sstevel@tonic-gate 		len = SCSA2USB_LEN_10BYTE(pkt);
3496*0Sstevel@tonic-gate 		dir = USB_EP_DIR_OUT;
3497*0Sstevel@tonic-gate 		if (len) {
3498*0Sstevel@tonic-gate 			sz = SCSA2USB_CDRW_BLKSZ(bp ? bp->b_bcount : 0, len);
3499*0Sstevel@tonic-gate 			if (SCSA2USB_VALID_CDRW_BLKSZ(sz)) {
3500*0Sstevel@tonic-gate 				blk_size = sz;	/* change it accordingly */
3501*0Sstevel@tonic-gate 			}
3502*0Sstevel@tonic-gate 		}
3503*0Sstevel@tonic-gate 		break;
3504*0Sstevel@tonic-gate 	case SCMD_READ_CD:
3505*0Sstevel@tonic-gate 		lba = SCSA2USB_LBA_10BYTE(pkt);
3506*0Sstevel@tonic-gate 		len = SCSA2USB_LEN_READ_CD(pkt);
3507*0Sstevel@tonic-gate 		dir = USB_EP_DIR_IN;
3508*0Sstevel@tonic-gate 
3509*0Sstevel@tonic-gate 		/* Figure out the block size */
3510*0Sstevel@tonic-gate 		blk_size = scsa2usb_read_cd_blk_size(pkt->pkt_cdbp[1] >> 2);
3511*0Sstevel@tonic-gate 		break;
3512*0Sstevel@tonic-gate 	case SCMD_READ_G5:
3513*0Sstevel@tonic-gate 		lba = SCSA2USB_LBA_12BYTE(pkt);
3514*0Sstevel@tonic-gate 		len = SCSA2USB_LEN_12BYTE(pkt);
3515*0Sstevel@tonic-gate 		dir = USB_EP_DIR_IN;
3516*0Sstevel@tonic-gate 		break;
3517*0Sstevel@tonic-gate 	case SCMD_WRITE_G5:
3518*0Sstevel@tonic-gate 		lba = SCSA2USB_LBA_12BYTE(pkt);
3519*0Sstevel@tonic-gate 		len = SCSA2USB_LEN_12BYTE(pkt);
3520*0Sstevel@tonic-gate 		dir = USB_EP_DIR_OUT;
3521*0Sstevel@tonic-gate 		break;
3522*0Sstevel@tonic-gate 	}
3523*0Sstevel@tonic-gate 
3524*0Sstevel@tonic-gate 	cmd->cmd_total_xfercount = xfer_count = len * blk_size;
3525*0Sstevel@tonic-gate 
3526*0Sstevel@tonic-gate 	/* reduce xfer count if necessary */
3527*0Sstevel@tonic-gate 	if (blk_size &&
3528*0Sstevel@tonic-gate 	    (xfer_count > scsa2usbp->scsa2usb_max_bulk_xfer_size)) {
3529*0Sstevel@tonic-gate 		/*
3530*0Sstevel@tonic-gate 		 * For CD-RW devices reduce the xfer count based
3531*0Sstevel@tonic-gate 		 * on the block size used by these devices. The
3532*0Sstevel@tonic-gate 		 * block size could change for READ_CD and WRITE
3533*0Sstevel@tonic-gate 		 * opcodes.
3534*0Sstevel@tonic-gate 		 *
3535*0Sstevel@tonic-gate 		 * Also as UHCI allows a max xfer of 32k at a time;
3536*0Sstevel@tonic-gate 		 * compute the xfer_count based on the new block_size.
3537*0Sstevel@tonic-gate 		 *
3538*0Sstevel@tonic-gate 		 * The len part of the cdb changes as a result of that.
3539*0Sstevel@tonic-gate 		 */
3540*0Sstevel@tonic-gate 		if (SCSA2USB_VALID_CDRW_BLKSZ(blk_size)) {
3541*0Sstevel@tonic-gate 			xfer_count = ((scsa2usbp->scsa2usb_max_bulk_xfer_size/
3542*0Sstevel@tonic-gate 					blk_size) * blk_size);
3543*0Sstevel@tonic-gate 			len = xfer_count/blk_size;
3544*0Sstevel@tonic-gate 			xfer_count = blk_size * len;
3545*0Sstevel@tonic-gate 		} else {
3546*0Sstevel@tonic-gate 			xfer_count = scsa2usbp->scsa2usb_max_bulk_xfer_size;
3547*0Sstevel@tonic-gate 			len = xfer_count/blk_size;
3548*0Sstevel@tonic-gate 		}
3549*0Sstevel@tonic-gate 	}
3550*0Sstevel@tonic-gate 
3551*0Sstevel@tonic-gate 	cmd->cmd_xfercount = xfer_count;
3552*0Sstevel@tonic-gate 	cmd->cmd_dir = (uchar_t)dir;
3553*0Sstevel@tonic-gate 	cmd->cmd_blksize = blk_size;
3554*0Sstevel@tonic-gate 
3555*0Sstevel@tonic-gate 	/*
3556*0Sstevel@tonic-gate 	 * Having figure out the 'partial' xfer len based on he
3557*0Sstevel@tonic-gate 	 * block size; fill it in to the cmd->cmd_cdb
3558*0Sstevel@tonic-gate 	 */
3559*0Sstevel@tonic-gate 	cmd->cmd_cdb[SCSA2USB_OPCODE] = (uchar_t)opcode;
3560*0Sstevel@tonic-gate 	switch (opcode) {
3561*0Sstevel@tonic-gate 	case SCMD_READ_CD:
3562*0Sstevel@tonic-gate 		bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
3563*0Sstevel@tonic-gate 		scsa2usb_fill_up_ReadCD_cdb_len(cmd, len, CDB_GROUP5);
3564*0Sstevel@tonic-gate 		break;
3565*0Sstevel@tonic-gate 	case SCMD_WRITE_G5:
3566*0Sstevel@tonic-gate 	case SCMD_READ_G5:
3567*0Sstevel@tonic-gate 		scsa2usb_fill_up_12byte_cdb_len(cmd, len, CDB_GROUP5);
3568*0Sstevel@tonic-gate 		break;
3569*0Sstevel@tonic-gate 	default:
3570*0Sstevel@tonic-gate 		scsa2usb_fill_up_cdb_len(cmd, len);
3571*0Sstevel@tonic-gate 		cmd->cmd_actual_len = CDB_GROUP1;
3572*0Sstevel@tonic-gate 		break;
3573*0Sstevel@tonic-gate 	}
3574*0Sstevel@tonic-gate 
3575*0Sstevel@tonic-gate 	scsa2usb_fill_up_cdb_lba(cmd, lba);
3576*0Sstevel@tonic-gate 
3577*0Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
3578*0Sstevel@tonic-gate 	    "bcount=0x%lx lba=0x%x len=0x%lx xfercount=0x%lx total=0x%lx",
3579*0Sstevel@tonic-gate 	    bp ? bp->b_bcount : 0, lba, len, cmd->cmd_xfercount,
3580*0Sstevel@tonic-gate 	    cmd->cmd_total_xfercount);
3581*0Sstevel@tonic-gate 
3582*0Sstevel@tonic-gate 	/* Set the timeout value as per command request */
3583*0Sstevel@tonic-gate 	if ((opcode == SCMD_WRITE_G1) && SCSA2USB_VALID_CDRW_BLKSZ(blk_size)) {
3584*0Sstevel@tonic-gate 		/*
3585*0Sstevel@tonic-gate 		 * We increase the time as CD-RW writes have two things
3586*0Sstevel@tonic-gate 		 * to do. After writing out the data to the media, a
3587*0Sstevel@tonic-gate 		 * TOC needs to be filled up at the beginning of the media
3588*0Sstevel@tonic-gate 		 * This is when the write gets "finalized".
3589*0Sstevel@tonic-gate 		 * Hence the actual write could take longer than the
3590*0Sstevel@tonic-gate 		 * value specified in cmd->cmd_timeout.
3591*0Sstevel@tonic-gate 		 */
3592*0Sstevel@tonic-gate 		cmd->cmd_timeout *= 4;
3593*0Sstevel@tonic-gate 
3594*0Sstevel@tonic-gate 		USB_DPRINTF_L4(DPRINT_MASK_SCSA,
3595*0Sstevel@tonic-gate 		    scsa2usbp->scsa2usb_log_handle,
3596*0Sstevel@tonic-gate 		    "new timeout value = 0x%x", cmd->cmd_timeout);
3597*0Sstevel@tonic-gate 	}
3598*0Sstevel@tonic-gate 
3599*0Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
3600*0Sstevel@tonic-gate 	    "lba 0x%x len 0x%lx xfercount 0x%lx total 0x%lx",
3601*0Sstevel@tonic-gate 	    lba, len, cmd->cmd_xfercount, cmd->cmd_total_xfercount);
3602*0Sstevel@tonic-gate 
3603*0Sstevel@tonic-gate 	return (SCSA2USB_TRANSPORT);
3604*0Sstevel@tonic-gate }
3605*0Sstevel@tonic-gate 
3606*0Sstevel@tonic-gate 
3607*0Sstevel@tonic-gate /*
3608*0Sstevel@tonic-gate  * scsa2usb_setup_next_xfer:
3609*0Sstevel@tonic-gate  *	For READs and WRITEs we split up the transfer in terms of
3610*0Sstevel@tonic-gate  *	HCD understood units. This function handles the split transfers.
3611*0Sstevel@tonic-gate  *
3612*0Sstevel@tonic-gate  * See comments in the previous function scsa2usb_rw_transport
3613*0Sstevel@tonic-gate  *
3614*0Sstevel@tonic-gate  * The lba computation was being done based on scsa2usb_max_bulk_xfer_size
3615*0Sstevel@tonic-gate  * earlier. With CD-RW devices, the xfer_count and the block_size may
3616*0Sstevel@tonic-gate  * no longer be a multiple of scsa2usb_max_bulk_xfer_size. So compute
3617*0Sstevel@tonic-gate  * xfer_count all over again. Adjust lba, based on the previous requests'
3618*0Sstevel@tonic-gate  * len. Find out the len and add it to cmd->cmd_lba to get the new lba
3619*0Sstevel@tonic-gate  */
3620*0Sstevel@tonic-gate void
3621*0Sstevel@tonic-gate scsa2usb_setup_next_xfer(scsa2usb_state_t *scsa2usbp, scsa2usb_cmd_t *cmd)
3622*0Sstevel@tonic-gate {
3623*0Sstevel@tonic-gate 	int xfer_len = min(scsa2usbp->scsa2usb_max_bulk_xfer_size,
3624*0Sstevel@tonic-gate 			cmd->cmd_total_xfercount);
3625*0Sstevel@tonic-gate 	int cdb_len;
3626*0Sstevel@tonic-gate 	size_t blk_size;
3627*0Sstevel@tonic-gate 
3628*0Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
3629*0Sstevel@tonic-gate 
3630*0Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
3631*0Sstevel@tonic-gate 	    "scsa2usb_setup_next_xfer: opcode = 0x%x lba = 0x%x "
3632*0Sstevel@tonic-gate 	    "total count = 0x%lx", cmd->cmd_cdb[SCSA2USB_OPCODE],
3633*0Sstevel@tonic-gate 	    cmd->cmd_lba, cmd->cmd_total_xfercount);
3634*0Sstevel@tonic-gate 
3635*0Sstevel@tonic-gate 	ASSERT(cmd->cmd_total_xfercount > 0);
3636*0Sstevel@tonic-gate 	cmd->cmd_xfercount = xfer_len;
3637*0Sstevel@tonic-gate 	blk_size = scsa2usbp->scsa2usb_lbasize[
3638*0Sstevel@tonic-gate 				cmd->cmd_pkt->pkt_address.a_lun];
3639*0Sstevel@tonic-gate 
3640*0Sstevel@tonic-gate 	/*
3641*0Sstevel@tonic-gate 	 * For CD-RW devices reduce the xfer count based on the
3642*0Sstevel@tonic-gate 	 * block_size used by these devices. See changes below
3643*0Sstevel@tonic-gate 	 * where xfer_count is being adjusted.
3644*0Sstevel@tonic-gate 	 *
3645*0Sstevel@tonic-gate 	 * Also adjust len/lba based on the block_size and xfer_count.
3646*0Sstevel@tonic-gate 	 * NOTE: Always calculate lba first, as it based on previous
3647*0Sstevel@tonic-gate 	 * commands' values.
3648*0Sstevel@tonic-gate 	 */
3649*0Sstevel@tonic-gate 	switch (cmd->cmd_cdb[SCSA2USB_OPCODE]) {
3650*0Sstevel@tonic-gate 	case SCMD_READ_CD:
3651*0Sstevel@tonic-gate 		/* calculate lba = current_lba + len_of_prev_cmd */
3652*0Sstevel@tonic-gate 		cmd->cmd_lba += (cmd->cmd_cdb[6] << 16) +
3653*0Sstevel@tonic-gate 		    (cmd->cmd_cdb[7] << 8) + cmd->cmd_cdb[8];
3654*0Sstevel@tonic-gate 		cdb_len = xfer_len/cmd->cmd_blksize;
3655*0Sstevel@tonic-gate 		cmd->cmd_cdb[SCSA2USB_READ_CD_LEN_2] = (uchar_t)cdb_len;
3656*0Sstevel@tonic-gate 		/* re-adjust xfer count */
3657*0Sstevel@tonic-gate 		cmd->cmd_xfercount = cdb_len * cmd->cmd_blksize;
3658*0Sstevel@tonic-gate 		break;
3659*0Sstevel@tonic-gate 	case SCMD_WRITE_G5:
3660*0Sstevel@tonic-gate 	case SCMD_READ_G5:
3661*0Sstevel@tonic-gate 		/* calculate lba = current_lba + len_of_prev_cmd */
3662*0Sstevel@tonic-gate 		cmd->cmd_lba += (cmd->cmd_cdb[6] << 24) +
3663*0Sstevel@tonic-gate 		    (cmd->cmd_cdb[7] << 16) + (cmd->cmd_cdb[8] << 8) +
3664*0Sstevel@tonic-gate 		    cmd->cmd_cdb[9];
3665*0Sstevel@tonic-gate 		if (blk_size) {
3666*0Sstevel@tonic-gate 			xfer_len /= blk_size;
3667*0Sstevel@tonic-gate 		}
3668*0Sstevel@tonic-gate 		scsa2usb_fill_up_12byte_cdb_len(cmd, xfer_len, CDB_GROUP5);
3669*0Sstevel@tonic-gate 		break;
3670*0Sstevel@tonic-gate 	case SCMD_WRITE_G1:
3671*0Sstevel@tonic-gate 	case SCMD_WRITE_LONG:
3672*0Sstevel@tonic-gate 		/* calculate lba = current_lba + len_of_prev_cmd */
3673*0Sstevel@tonic-gate 		cmd->cmd_lba += (cmd->cmd_cdb[7] << 8) + cmd->cmd_cdb[8];
3674*0Sstevel@tonic-gate 		if (SCSA2USB_VALID_CDRW_BLKSZ(cmd->cmd_blksize)) {
3675*0Sstevel@tonic-gate 			blk_size = cmd->cmd_blksize;
3676*0Sstevel@tonic-gate 		}
3677*0Sstevel@tonic-gate 		cdb_len = xfer_len/blk_size;
3678*0Sstevel@tonic-gate 		scsa2usb_fill_up_cdb_len(cmd, cdb_len);
3679*0Sstevel@tonic-gate 		/* re-adjust xfer count */
3680*0Sstevel@tonic-gate 		cmd->cmd_xfercount = cdb_len * blk_size;
3681*0Sstevel@tonic-gate 		break;
3682*0Sstevel@tonic-gate 	default:
3683*0Sstevel@tonic-gate 		if (blk_size) {
3684*0Sstevel@tonic-gate 			xfer_len /= blk_size;
3685*0Sstevel@tonic-gate 		}
3686*0Sstevel@tonic-gate 		scsa2usb_fill_up_cdb_len(cmd, xfer_len);
3687*0Sstevel@tonic-gate 		cmd->cmd_lba += scsa2usbp->scsa2usb_max_bulk_xfer_size/blk_size;
3688*0Sstevel@tonic-gate 	}
3689*0Sstevel@tonic-gate 
3690*0Sstevel@tonic-gate 	/* fill in the lba */
3691*0Sstevel@tonic-gate 	scsa2usb_fill_up_cdb_lba(cmd, cmd->cmd_lba);
3692*0Sstevel@tonic-gate 
3693*0Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
3694*0Sstevel@tonic-gate 	    "scsa2usb_setup_next_xfer:\n\tlba = 0x%x xfer_len = 0x%x "
3695*0Sstevel@tonic-gate 	    "xfercount = 0x%lx total = 0x%lx", cmd->cmd_lba, xfer_len,
3696*0Sstevel@tonic-gate 	    cmd->cmd_xfercount, cmd->cmd_total_xfercount);
3697*0Sstevel@tonic-gate }
3698*0Sstevel@tonic-gate 
3699*0Sstevel@tonic-gate 
3700*0Sstevel@tonic-gate /*
3701*0Sstevel@tonic-gate  * take one request from the lun's waitQ and transport it
3702*0Sstevel@tonic-gate  */
3703*0Sstevel@tonic-gate static void
3704*0Sstevel@tonic-gate scsa2usb_transport_request(scsa2usb_state_t *scsa2usbp, uint_t lun)
3705*0Sstevel@tonic-gate {
3706*0Sstevel@tonic-gate 	int			rval;
3707*0Sstevel@tonic-gate 	struct scsi_pkt		*pkt;
3708*0Sstevel@tonic-gate 	struct scsa2usb_cmd	*cmd, *arqcmd;
3709*0Sstevel@tonic-gate 
3710*0Sstevel@tonic-gate 	if ((cmd = (scsa2usb_cmd_t *)
3711*0Sstevel@tonic-gate 	    usba_rm_first_pvt_from_list(
3712*0Sstevel@tonic-gate 	    &scsa2usbp->scsa2usb_waitQ[lun])) == NULL) {
3713*0Sstevel@tonic-gate 
3714*0Sstevel@tonic-gate 		return;
3715*0Sstevel@tonic-gate 	}
3716*0Sstevel@tonic-gate 	pkt = cmd->cmd_pkt;
3717*0Sstevel@tonic-gate 
3718*0Sstevel@tonic-gate 	/*
3719*0Sstevel@tonic-gate 	 * if device has been disconnected, just complete it
3720*0Sstevel@tonic-gate 	 */
3721*0Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_dev_state == USB_DEV_DISCONNECTED) {
3722*0Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
3723*0Sstevel@tonic-gate 		    "device not accessible");
3724*0Sstevel@tonic-gate 		pkt->pkt_reason = CMD_DEV_GONE;
3725*0Sstevel@tonic-gate 		SCSA2USB_SET_PKT_DO_COMP_STATE(scsa2usbp);
3726*0Sstevel@tonic-gate 		scsa2usb_pkt_completion(scsa2usbp, pkt);
3727*0Sstevel@tonic-gate 
3728*0Sstevel@tonic-gate 		return;
3729*0Sstevel@tonic-gate 	}
3730*0Sstevel@tonic-gate 
3731*0Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA,
3732*0Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_log_handle,
3733*0Sstevel@tonic-gate 	    "scsa2usb_transport_request: cmd=0x%p bp=0x%p addr=0x%p",
3734*0Sstevel@tonic-gate 	    cmd, cmd->cmd_bp,
3735*0Sstevel@tonic-gate 	    (cmd->cmd_bp ? cmd->cmd_bp->b_un.b_addr : NULL));
3736*0Sstevel@tonic-gate 
3737*0Sstevel@tonic-gate 	rval = scsa2usb_cmd_transport(scsa2usbp, cmd);
3738*0Sstevel@tonic-gate 
3739*0Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_SCSA,
3740*0Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_log_handle,
3741*0Sstevel@tonic-gate 	    "scsa2usb_transport_request: transport rval = %d",
3742*0Sstevel@tonic-gate 	    rval);
3743*0Sstevel@tonic-gate 
3744*0Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_cur_pkt == NULL) {
3745*0Sstevel@tonic-gate 
3746*0Sstevel@tonic-gate 		return;
3747*0Sstevel@tonic-gate 	}
3748*0Sstevel@tonic-gate 
3749*0Sstevel@tonic-gate 	ASSERT(pkt == scsa2usbp->scsa2usb_cur_pkt);
3750*0Sstevel@tonic-gate 
3751*0Sstevel@tonic-gate 	if (ddi_in_panic()) {
3752*0Sstevel@tonic-gate 		pkt->pkt_reason = CMD_CMPLT;
3753*0Sstevel@tonic-gate 		scsa2usb_pkt_completion(scsa2usbp, pkt);
3754*0Sstevel@tonic-gate 
3755*0Sstevel@tonic-gate 		return;
3756*0Sstevel@tonic-gate 	}
3757*0Sstevel@tonic-gate 
3758*0Sstevel@tonic-gate 	/*
3759*0Sstevel@tonic-gate 	 * start an auto-request sense iff
3760*0Sstevel@tonic-gate 	 * there was a check condition, we have enough
3761*0Sstevel@tonic-gate 	 * space in the status block, and we have not
3762*0Sstevel@tonic-gate 	 * faked an auto request sense
3763*0Sstevel@tonic-gate 	 */
3764*0Sstevel@tonic-gate 	if ((*(pkt->pkt_scbp) == STATUS_CHECK) &&
3765*0Sstevel@tonic-gate 	    (cmd->cmd_scblen >= sizeof (struct scsi_arq_status)) &&
3766*0Sstevel@tonic-gate 	    ((pkt->pkt_state & STATE_ARQ_DONE) == 0) &&
3767*0Sstevel@tonic-gate 	    (scsa2usb_create_arq_pkt(scsa2usbp,
3768*0Sstevel@tonic-gate 	    &pkt->pkt_address) == USB_SUCCESS)) {
3769*0Sstevel@tonic-gate 		arqcmd = scsa2usbp->scsa2usb_arq_cmd;
3770*0Sstevel@tonic-gate 
3771*0Sstevel@tonic-gate 		/*
3772*0Sstevel@tonic-gate 		 * copy the timeout from the
3773*0Sstevel@tonic-gate 		 * original packet
3774*0Sstevel@tonic-gate 		 * for lack of a better value
3775*0Sstevel@tonic-gate 		 */
3776*0Sstevel@tonic-gate 		arqcmd->cmd_pkt->pkt_time = pkt->pkt_time;
3777*0Sstevel@tonic-gate 		scsa2usb_prepare_pkt(scsa2usbp,
3778*0Sstevel@tonic-gate 			    arqcmd->cmd_pkt);
3779*0Sstevel@tonic-gate 
3780*0Sstevel@tonic-gate 		scsa2usbp->scsa2usb_cur_pkt = NULL;
3781*0Sstevel@tonic-gate 		if (scsa2usb_cmd_transport(
3782*0Sstevel@tonic-gate 		    scsa2usbp, arqcmd) == TRAN_ACCEPT) {
3783*0Sstevel@tonic-gate 
3784*0Sstevel@tonic-gate 			/* finish w/ this packet */
3785*0Sstevel@tonic-gate 			scsa2usb_complete_arq_pkt(
3786*0Sstevel@tonic-gate 			    scsa2usbp, arqcmd->cmd_pkt, cmd,
3787*0Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_arq_bp);
3788*0Sstevel@tonic-gate 
3789*0Sstevel@tonic-gate 			/*
3790*0Sstevel@tonic-gate 			 * we have valid request sense
3791*0Sstevel@tonic-gate 			 * data so clear the pkt_reason
3792*0Sstevel@tonic-gate 			 */
3793*0Sstevel@tonic-gate 			pkt->pkt_reason = CMD_CMPLT;
3794*0Sstevel@tonic-gate 		}
3795*0Sstevel@tonic-gate 		scsa2usbp->scsa2usb_cur_pkt = pkt;
3796*0Sstevel@tonic-gate 		scsa2usb_delete_arq_pkt(scsa2usbp);
3797*0Sstevel@tonic-gate 	}
3798*0Sstevel@tonic-gate 
3799*0Sstevel@tonic-gate 	if ((rval != TRAN_ACCEPT) &&
3800*0Sstevel@tonic-gate 	    (pkt->pkt_reason == CMD_CMPLT)) {
3801*0Sstevel@tonic-gate 		pkt->pkt_reason = CMD_TRAN_ERR;
3802*0Sstevel@tonic-gate 	}
3803*0Sstevel@tonic-gate 
3804*0Sstevel@tonic-gate 	SCSA2USB_SET_PKT_DO_COMP_STATE(scsa2usbp);
3805*0Sstevel@tonic-gate 	scsa2usb_pkt_completion(scsa2usbp, pkt);
3806*0Sstevel@tonic-gate 
3807*0Sstevel@tonic-gate 	ASSERT(scsa2usbp->scsa2usb_cur_pkt == NULL);
3808*0Sstevel@tonic-gate }
3809*0Sstevel@tonic-gate 
3810*0Sstevel@tonic-gate 
3811*0Sstevel@tonic-gate /*
3812*0Sstevel@tonic-gate  * scsa2usb_work_thread:
3813*0Sstevel@tonic-gate  *	The taskq thread that kicks off the transport (BO and CB/CBI)
3814*0Sstevel@tonic-gate  */
3815*0Sstevel@tonic-gate static void
3816*0Sstevel@tonic-gate scsa2usb_work_thread(void *arg)
3817*0Sstevel@tonic-gate {
3818*0Sstevel@tonic-gate 	scsa2usb_state_t	*scsa2usbp = (scsa2usb_state_t *)arg;
3819*0Sstevel@tonic-gate 	uint_t			lun;
3820*0Sstevel@tonic-gate 	uint_t			count;
3821*0Sstevel@tonic-gate 
3822*0Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
3823*0Sstevel@tonic-gate 	    "scsa2usb_work_thread:");
3824*0Sstevel@tonic-gate 
3825*0Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
3826*0Sstevel@tonic-gate 	ASSERT(scsa2usbp->scsa2usb_work_thread_id == (kthread_t *)1);
3827*0Sstevel@tonic-gate 	scsa2usbp->scsa2usb_work_thread_id = curthread;
3828*0Sstevel@tonic-gate 
3829*0Sstevel@tonic-gate 	/* exclude ugen accesses */
3830*0Sstevel@tonic-gate 	while (scsa2usbp->scsa2usb_transport_busy) {
3831*0Sstevel@tonic-gate 		cv_wait(&scsa2usbp->scsa2usb_transport_busy_cv,
3832*0Sstevel@tonic-gate 		    &scsa2usbp->scsa2usb_mutex);
3833*0Sstevel@tonic-gate 	}
3834*0Sstevel@tonic-gate 	ASSERT(scsa2usbp->scsa2usb_ugen_open_count == 0);
3835*0Sstevel@tonic-gate 	scsa2usbp->scsa2usb_transport_busy++;
3836*0Sstevel@tonic-gate 	scsa2usbp->scsa2usb_busy_thread = curthread;
3837*0Sstevel@tonic-gate 
3838*0Sstevel@tonic-gate 	scsa2usb_raise_power(scsa2usbp);
3839*0Sstevel@tonic-gate 
3840*0Sstevel@tonic-gate 	/* reopen the pipes if necessary */
3841*0Sstevel@tonic-gate 	(void) scsa2usb_open_usb_pipes(scsa2usbp);
3842*0Sstevel@tonic-gate 
3843*0Sstevel@tonic-gate 	for (;;) {
3844*0Sstevel@tonic-gate 		ASSERT(scsa2usbp->scsa2usb_ugen_open_count == 0);
3845*0Sstevel@tonic-gate 		for (lun = 0; lun < scsa2usbp->scsa2usb_n_luns; lun++) {
3846*0Sstevel@tonic-gate 			scsa2usb_transport_request(scsa2usbp, lun);
3847*0Sstevel@tonic-gate 		}
3848*0Sstevel@tonic-gate 		count = 0;
3849*0Sstevel@tonic-gate 		for (lun = 0; lun < SCSA2USB_MAX_LUNS; lun++) {
3850*0Sstevel@tonic-gate 			count += usba_list_entry_count(
3851*0Sstevel@tonic-gate 				&scsa2usbp->scsa2usb_waitQ[lun]);
3852*0Sstevel@tonic-gate 		}
3853*0Sstevel@tonic-gate 
3854*0Sstevel@tonic-gate 		if (count == 0) {
3855*0Sstevel@tonic-gate 
3856*0Sstevel@tonic-gate 			break;
3857*0Sstevel@tonic-gate 		}
3858*0Sstevel@tonic-gate 	}
3859*0Sstevel@tonic-gate 
3860*0Sstevel@tonic-gate 	scsa2usb_pm_idle_component(scsa2usbp);
3861*0Sstevel@tonic-gate 
3862*0Sstevel@tonic-gate 	scsa2usbp->scsa2usb_work_thread_id = 0;
3863*0Sstevel@tonic-gate 
3864*0Sstevel@tonic-gate 	ASSERT(scsa2usbp->scsa2usb_ugen_open_count == 0);
3865*0Sstevel@tonic-gate 
3866*0Sstevel@tonic-gate 	scsa2usbp->scsa2usb_transport_busy--;
3867*0Sstevel@tonic-gate 	scsa2usbp->scsa2usb_busy_thread = NULL;
3868*0Sstevel@tonic-gate 	cv_signal(&scsa2usbp->scsa2usb_transport_busy_cv);
3869*0Sstevel@tonic-gate 
3870*0Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
3871*0Sstevel@tonic-gate 
3872*0Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
3873*0Sstevel@tonic-gate 	    "scsa2usb_work_thread: exit");
3874*0Sstevel@tonic-gate }
3875*0Sstevel@tonic-gate 
3876*0Sstevel@tonic-gate 
3877*0Sstevel@tonic-gate /*
3878*0Sstevel@tonic-gate  * scsa2usb_flush_waitQ:
3879*0Sstevel@tonic-gate  *	empties the entire waitQ with errors asap.
3880*0Sstevel@tonic-gate  *
3881*0Sstevel@tonic-gate  * It is called from scsa2usb_scsi_reset and scsa2usb_panic_callb.
3882*0Sstevel@tonic-gate  * If the device is reset; we should empty the waitQ right away.
3883*0Sstevel@tonic-gate  * If the system has paniced; we should empty the waitQ right away.
3884*0Sstevel@tonic-gate  *
3885*0Sstevel@tonic-gate  * CPR suspend will only succeed if device is idle. No need to call
3886*0Sstevel@tonic-gate  * this function for CPR suspend case.
3887*0Sstevel@tonic-gate  */
3888*0Sstevel@tonic-gate static void
3889*0Sstevel@tonic-gate scsa2usb_flush_waitQ(scsa2usb_state_t *scsa2usbp, uint_t lun,
3890*0Sstevel@tonic-gate     uchar_t error)
3891*0Sstevel@tonic-gate {
3892*0Sstevel@tonic-gate 	struct scsi_pkt		*pkt;
3893*0Sstevel@tonic-gate 	struct scsa2usb_cmd	*cmd;
3894*0Sstevel@tonic-gate 	usba_list_entry_t	head;
3895*0Sstevel@tonic-gate 
3896*0Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
3897*0Sstevel@tonic-gate 
3898*0Sstevel@tonic-gate 	usba_move_list(&scsa2usbp->scsa2usb_waitQ[lun], &head,
3899*0Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_dev_data->dev_iblock_cookie);
3900*0Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
3901*0Sstevel@tonic-gate 
3902*0Sstevel@tonic-gate 	while ((cmd = (scsa2usb_cmd_t *)usba_rm_first_pvt_from_list(&head)) !=
3903*0Sstevel@tonic-gate 	    NULL) {
3904*0Sstevel@tonic-gate 		pkt = cmd->cmd_pkt;
3905*0Sstevel@tonic-gate 		pkt->pkt_reason = error;	/* set error */
3906*0Sstevel@tonic-gate 
3907*0Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
3908*0Sstevel@tonic-gate 		scsa2usbp->scsa2usb_pkt_state = SCSA2USB_PKT_DO_COMP;
3909*0Sstevel@tonic-gate 		scsa2usb_pkt_completion(scsa2usbp, pkt);
3910*0Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
3911*0Sstevel@tonic-gate 	} /* end of while */
3912*0Sstevel@tonic-gate }
3913*0Sstevel@tonic-gate 
3914*0Sstevel@tonic-gate 
3915*0Sstevel@tonic-gate /*
3916*0Sstevel@tonic-gate  * scsa2usb_do_inquiry is performed before INIT CHILD and we have
3917*0Sstevel@tonic-gate  * to fake a few things normally done by SCSA
3918*0Sstevel@tonic-gate  */
3919*0Sstevel@tonic-gate static void
3920*0Sstevel@tonic-gate scsa2usb_do_inquiry(scsa2usb_state_t *scsa2usbp, uint_t target, uint_t lun)
3921*0Sstevel@tonic-gate {
3922*0Sstevel@tonic-gate 	struct buf	*bp;
3923*0Sstevel@tonic-gate 	struct scsi_pkt *pkt;
3924*0Sstevel@tonic-gate 	struct scsi_address ap;
3925*0Sstevel@tonic-gate 	int		len = SCSA2USB_MAX_INQ_LEN;
3926*0Sstevel@tonic-gate 
3927*0Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
3928*0Sstevel@tonic-gate 	    "scsa2usb_do_inquiry: %d bytes", len);
3929*0Sstevel@tonic-gate 
3930*0Sstevel@tonic-gate 	/* is it inquiry-challenged? */
3931*0Sstevel@tonic-gate 	if (!(scsa2usbp->scsa2usb_attrs & SCSA2USB_ATTRS_INQUIRY)) {
3932*0Sstevel@tonic-gate 		(void) scsa2usb_fake_inquiry(scsa2usbp, NULL, lun);
3933*0Sstevel@tonic-gate 
3934*0Sstevel@tonic-gate 		return;
3935*0Sstevel@tonic-gate 	}
3936*0Sstevel@tonic-gate 
3937*0Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
3938*0Sstevel@tonic-gate 
3939*0Sstevel@tonic-gate 	bzero(&ap, sizeof (struct scsi_address));
3940*0Sstevel@tonic-gate 	ap.a_hba_tran = scsa2usbp->scsa2usb_tran;
3941*0Sstevel@tonic-gate 	ap.a_target = target;
3942*0Sstevel@tonic-gate 	ap.a_lun = lun;
3943*0Sstevel@tonic-gate 
3944*0Sstevel@tonic-gate 	/* limit inquiry to 36 bytes */
3945*0Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
3946*0Sstevel@tonic-gate 	if ((bp = scsi_alloc_consistent_buf(&ap, (struct buf *)NULL,
3947*0Sstevel@tonic-gate 	    len, B_READ, SLEEP_FUNC, NULL)) == NULL) {
3948*0Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
3949*0Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA,
3950*0Sstevel@tonic-gate 		    scsa2usbp->scsa2usb_log_handle,
3951*0Sstevel@tonic-gate 		    "scsa2usb_do_inquiry: failed");
3952*0Sstevel@tonic-gate 
3953*0Sstevel@tonic-gate 		return;
3954*0Sstevel@tonic-gate 	}
3955*0Sstevel@tonic-gate 
3956*0Sstevel@tonic-gate 	pkt = scsi_init_pkt(&ap, NULL, bp, CDB_GROUP0, 1,
3957*0Sstevel@tonic-gate 	    PKT_PRIV_LEN, PKT_CONSISTENT, SLEEP_FUNC, NULL);
3958*0Sstevel@tonic-gate 
3959*0Sstevel@tonic-gate 	RQ_MAKECOM_G0(pkt, FLAG_NOINTR, (char)SCMD_INQUIRY, 0, len);
3960*0Sstevel@tonic-gate 
3961*0Sstevel@tonic-gate 	pkt->pkt_comp = NULL;
3962*0Sstevel@tonic-gate 	pkt->pkt_time = 5;
3963*0Sstevel@tonic-gate 	bzero(bp->b_un.b_addr, len);
3964*0Sstevel@tonic-gate 
3965*0Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
3966*0Sstevel@tonic-gate 	    "scsa2usb_do_inquiry:INQUIRY");
3967*0Sstevel@tonic-gate 
3968*0Sstevel@tonic-gate 	(void) scsi_transport(pkt);
3969*0Sstevel@tonic-gate 
3970*0Sstevel@tonic-gate 	if (pkt->pkt_reason) {
3971*0Sstevel@tonic-gate 		USB_DPRINTF_L0(DPRINT_MASK_SCSA,
3972*0Sstevel@tonic-gate 		    scsa2usbp->scsa2usb_log_handle,
3973*0Sstevel@tonic-gate 		    "INQUIRY failed, cannot determine device type, "
3974*0Sstevel@tonic-gate 		    "pkt_reason=0x%x", pkt->pkt_reason);
3975*0Sstevel@tonic-gate 
3976*0Sstevel@tonic-gate 		/* not much hope for other cmds, reduce */
3977*0Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
3978*0Sstevel@tonic-gate 		scsa2usbp->scsa2usb_attrs &=
3979*0Sstevel@tonic-gate 					~SCSA2USB_ATTRS_REDUCED_CMD;
3980*0Sstevel@tonic-gate 		(void) scsa2usb_fake_inquiry(scsa2usbp, NULL, lun);
3981*0Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
3982*0Sstevel@tonic-gate 	}
3983*0Sstevel@tonic-gate 
3984*0Sstevel@tonic-gate 	scsi_destroy_pkt(pkt);
3985*0Sstevel@tonic-gate 	scsi_free_consistent_buf(bp);
3986*0Sstevel@tonic-gate 
3987*0Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
3988*0Sstevel@tonic-gate }
3989*0Sstevel@tonic-gate 
3990*0Sstevel@tonic-gate 
3991*0Sstevel@tonic-gate /*
3992*0Sstevel@tonic-gate  * scsa2usb_fake_inquiry:
3993*0Sstevel@tonic-gate  *    build an inquiry for a given device that doesnt like inquiry
3994*0Sstevel@tonic-gate  *    commands.
3995*0Sstevel@tonic-gate  */
3996*0Sstevel@tonic-gate static int
3997*0Sstevel@tonic-gate scsa2usb_fake_inquiry(scsa2usb_state_t *scsa2usbp, scsa2usb_cmd_t *cmd,
3998*0Sstevel@tonic-gate     uint_t lun)
3999*0Sstevel@tonic-gate {
4000*0Sstevel@tonic-gate 	usb_client_dev_data_t *dev_data = scsa2usbp->scsa2usb_dev_data;
4001*0Sstevel@tonic-gate 	struct scsi_inquiry *inqp;
4002*0Sstevel@tonic-gate 	int len;
4003*0Sstevel@tonic-gate 
4004*0Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
4005*0Sstevel@tonic-gate 	    "scsa2usb_fake_inquiry:");
4006*0Sstevel@tonic-gate 
4007*0Sstevel@tonic-gate 	if (cmd) {
4008*0Sstevel@tonic-gate 		inqp = (struct scsi_inquiry *)cmd->cmd_bp->b_un.b_addr;
4009*0Sstevel@tonic-gate 	} else {
4010*0Sstevel@tonic-gate 		inqp = &scsa2usbp->scsa2usb_lun_inquiry[lun];
4011*0Sstevel@tonic-gate 	}
4012*0Sstevel@tonic-gate 	bzero(inqp, sizeof (struct scsi_inquiry));
4013*0Sstevel@tonic-gate 	for (len = 0; len < sizeof (inqp->inq_vid); len++) {
4014*0Sstevel@tonic-gate 		*(inqp->inq_vid + len) = ' ';
4015*0Sstevel@tonic-gate 	}
4016*0Sstevel@tonic-gate 
4017*0Sstevel@tonic-gate 	for (len = 0; len < sizeof (inqp->inq_pid); len++) {
4018*0Sstevel@tonic-gate 		*(inqp->inq_pid + len) = ' ';
4019*0Sstevel@tonic-gate 	}
4020*0Sstevel@tonic-gate 
4021*0Sstevel@tonic-gate 	inqp->inq_dtype = DTYPE_DIRECT;
4022*0Sstevel@tonic-gate 	inqp->inq_rmb = 1;
4023*0Sstevel@tonic-gate 	inqp->inq_ansi = 2;
4024*0Sstevel@tonic-gate 	inqp->inq_rdf = RDF_SCSI2;
4025*0Sstevel@tonic-gate 	inqp->inq_len = sizeof (struct scsi_inquiry)-4;
4026*0Sstevel@tonic-gate 
4027*0Sstevel@tonic-gate 	/* Fill in the Vendor id/Product id strings */
4028*0Sstevel@tonic-gate 	if (dev_data->dev_mfg) {
4029*0Sstevel@tonic-gate 		if ((len = strlen(dev_data->dev_mfg)) >
4030*0Sstevel@tonic-gate 		    sizeof (inqp->inq_vid)) {
4031*0Sstevel@tonic-gate 			len = sizeof (inqp->inq_vid);
4032*0Sstevel@tonic-gate 		}
4033*0Sstevel@tonic-gate 		bcopy(dev_data->dev_mfg, inqp->inq_vid, len);
4034*0Sstevel@tonic-gate 	}
4035*0Sstevel@tonic-gate 
4036*0Sstevel@tonic-gate 	if (dev_data->dev_product) {
4037*0Sstevel@tonic-gate 		if ((len = strlen(dev_data->dev_product)) >
4038*0Sstevel@tonic-gate 		    sizeof (inqp->inq_pid)) {
4039*0Sstevel@tonic-gate 			len = sizeof (inqp->inq_pid);
4040*0Sstevel@tonic-gate 		}
4041*0Sstevel@tonic-gate 		bcopy(dev_data->dev_product, inqp->inq_pid, len);
4042*0Sstevel@tonic-gate 	}
4043*0Sstevel@tonic-gate 
4044*0Sstevel@tonic-gate 	/* Set the Revision to the Device */
4045*0Sstevel@tonic-gate 	inqp->inq_revision[0] = 0x30 +
4046*0Sstevel@tonic-gate 		((dev_data->dev_descr->bcdDevice>>12) & 0xF);
4047*0Sstevel@tonic-gate 	inqp->inq_revision[1] = 0x30 +
4048*0Sstevel@tonic-gate 		((dev_data->dev_descr->bcdDevice>>8) & 0xF);
4049*0Sstevel@tonic-gate 	inqp->inq_revision[2] = 0x30 +
4050*0Sstevel@tonic-gate 		((dev_data->dev_descr->bcdDevice>>4) & 0xF);
4051*0Sstevel@tonic-gate 	inqp->inq_revision[3] = 0x30 +
4052*0Sstevel@tonic-gate 		((dev_data->dev_descr->bcdDevice) & 0xF);
4053*0Sstevel@tonic-gate 
4054*0Sstevel@tonic-gate 	/* Copy inquiry data in to soft state */
4055*0Sstevel@tonic-gate 	bcopy(inqp, &scsa2usbp->scsa2usb_lun_inquiry[lun],
4056*0Sstevel@tonic-gate 	    sizeof (struct scsi_inquiry));
4057*0Sstevel@tonic-gate 
4058*0Sstevel@tonic-gate 	return (sizeof (struct scsi_inquiry));
4059*0Sstevel@tonic-gate }
4060*0Sstevel@tonic-gate 
4061*0Sstevel@tonic-gate 
4062*0Sstevel@tonic-gate /*
4063*0Sstevel@tonic-gate  * scsa2usb_create_arq_pkt:
4064*0Sstevel@tonic-gate  *	Create and ARQ packet to get request sense data
4065*0Sstevel@tonic-gate  */
4066*0Sstevel@tonic-gate static int
4067*0Sstevel@tonic-gate scsa2usb_create_arq_pkt(scsa2usb_state_t *scsa2usbp, struct scsi_address *ap)
4068*0Sstevel@tonic-gate {
4069*0Sstevel@tonic-gate 	struct buf *bp;
4070*0Sstevel@tonic-gate 	scsa2usb_cmd_t *arq_cmd;
4071*0Sstevel@tonic-gate 
4072*0Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
4073*0Sstevel@tonic-gate 	    "scsa2usb_create_arq_pkt: scsa2usbp: %p, ap: %p", scsa2usbp, ap);
4074*0Sstevel@tonic-gate 
4075*0Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
4076*0Sstevel@tonic-gate 
4077*0Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
4078*0Sstevel@tonic-gate 	if ((bp = scsi_alloc_consistent_buf(ap, (struct buf *)NULL,
4079*0Sstevel@tonic-gate 	    SENSE_LENGTH, B_READ, SLEEP_FUNC, NULL)) == NULL) {
4080*0Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
4081*0Sstevel@tonic-gate 
4082*0Sstevel@tonic-gate 		return (USB_FAILURE);
4083*0Sstevel@tonic-gate 	}
4084*0Sstevel@tonic-gate 
4085*0Sstevel@tonic-gate 	arq_cmd = PKT2CMD(scsi_init_pkt(ap, NULL, bp, CDB_GROUP0, 1,
4086*0Sstevel@tonic-gate 	    PKT_PRIV_LEN, PKT_CONSISTENT, SLEEP_FUNC, NULL));
4087*0Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
4088*0Sstevel@tonic-gate 
4089*0Sstevel@tonic-gate 	RQ_MAKECOM_G0(arq_cmd->cmd_pkt,
4090*0Sstevel@tonic-gate 	    FLAG_SENSING | FLAG_HEAD | FLAG_NODISCON,
4091*0Sstevel@tonic-gate 	    (char)SCMD_REQUEST_SENSE, 0, (char)SENSE_LENGTH);
4092*0Sstevel@tonic-gate 
4093*0Sstevel@tonic-gate 	arq_cmd->cmd_pkt->pkt_ha_private = arq_cmd;
4094*0Sstevel@tonic-gate 	scsa2usbp->scsa2usb_arq_cmd = arq_cmd;
4095*0Sstevel@tonic-gate 	scsa2usbp->scsa2usb_arq_bp = bp;
4096*0Sstevel@tonic-gate 	arq_cmd->cmd_pkt->pkt_comp = NULL;
4097*0Sstevel@tonic-gate 	bzero(bp->b_un.b_addr, SENSE_LENGTH);
4098*0Sstevel@tonic-gate 
4099*0Sstevel@tonic-gate 	return (USB_SUCCESS);
4100*0Sstevel@tonic-gate }
4101*0Sstevel@tonic-gate 
4102*0Sstevel@tonic-gate 
4103*0Sstevel@tonic-gate /*
4104*0Sstevel@tonic-gate  * scsa2usb_delete_arq_pkt:
4105*0Sstevel@tonic-gate  *	Destroy the ARQ packet
4106*0Sstevel@tonic-gate  */
4107*0Sstevel@tonic-gate static void
4108*0Sstevel@tonic-gate scsa2usb_delete_arq_pkt(scsa2usb_state_t *scsa2usbp)
4109*0Sstevel@tonic-gate {
4110*0Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
4111*0Sstevel@tonic-gate 	    "scsa2usb_delete_arq_pkt: cmd: 0x%p", scsa2usbp->scsa2usb_arq_cmd);
4112*0Sstevel@tonic-gate 
4113*0Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
4114*0Sstevel@tonic-gate 
4115*0Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_arq_cmd != NULL) {
4116*0Sstevel@tonic-gate 		scsi_destroy_pkt(scsa2usbp->scsa2usb_arq_cmd->cmd_pkt);
4117*0Sstevel@tonic-gate 		scsi_free_consistent_buf(scsa2usbp->scsa2usb_arq_bp);
4118*0Sstevel@tonic-gate 	}
4119*0Sstevel@tonic-gate 	scsa2usbp->scsa2usb_arq_cmd = NULL;
4120*0Sstevel@tonic-gate 	scsa2usbp->scsa2usb_arq_bp = NULL;
4121*0Sstevel@tonic-gate }
4122*0Sstevel@tonic-gate 
4123*0Sstevel@tonic-gate 
4124*0Sstevel@tonic-gate /*
4125*0Sstevel@tonic-gate  * scsa2usb_complete_arq_pkt:
4126*0Sstevel@tonic-gate  *	finish processing the arq packet
4127*0Sstevel@tonic-gate  */
4128*0Sstevel@tonic-gate static void
4129*0Sstevel@tonic-gate scsa2usb_complete_arq_pkt(scsa2usb_state_t *scsa2usbp,
4130*0Sstevel@tonic-gate     struct scsi_pkt *pkt, scsa2usb_cmd_t *ssp, struct buf *bp)
4131*0Sstevel@tonic-gate {
4132*0Sstevel@tonic-gate 	scsa2usb_cmd_t		*sp = pkt->pkt_ha_private;
4133*0Sstevel@tonic-gate 	struct scsi_arq_status	*arqp;
4134*0Sstevel@tonic-gate 
4135*0Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
4136*0Sstevel@tonic-gate 
4137*0Sstevel@tonic-gate 	arqp = (struct scsi_arq_status *)(ssp->cmd_pkt->pkt_scbp);
4138*0Sstevel@tonic-gate 	arqp->sts_rqpkt_status = *((struct scsi_status *)
4139*0Sstevel@tonic-gate 		(sp->cmd_pkt->pkt_scbp));
4140*0Sstevel@tonic-gate 	arqp->sts_rqpkt_reason = CMD_CMPLT;
4141*0Sstevel@tonic-gate 	arqp->sts_rqpkt_state |= STATE_XFERRED_DATA;
4142*0Sstevel@tonic-gate 	arqp->sts_rqpkt_statistics = arqp->sts_rqpkt_resid = 0;
4143*0Sstevel@tonic-gate 
4144*0Sstevel@tonic-gate 	/* is this meaningful sense data */
4145*0Sstevel@tonic-gate 	if (*(bp->b_un.b_addr) != 0) {
4146*0Sstevel@tonic-gate 		bcopy(bp->b_un.b_addr, &arqp->sts_sensedata, sp->cmd_scblen);
4147*0Sstevel@tonic-gate 		ssp->cmd_pkt->pkt_state |= STATE_ARQ_DONE;
4148*0Sstevel@tonic-gate 	}
4149*0Sstevel@tonic-gate 
4150*0Sstevel@tonic-gate 	/* we will not sense start cmd until we receive a NOT READY */
4151*0Sstevel@tonic-gate 	if (arqp->sts_sensedata.es_key == KEY_NOT_READY) {
4152*0Sstevel@tonic-gate 		scsa2usbp->scsa2usb_rcvd_not_ready = B_TRUE;
4153*0Sstevel@tonic-gate 	}
4154*0Sstevel@tonic-gate }
4155*0Sstevel@tonic-gate 
4156*0Sstevel@tonic-gate 
4157*0Sstevel@tonic-gate /*
4158*0Sstevel@tonic-gate  * Miscellaneous functions for any command/transport
4159*0Sstevel@tonic-gate  */
4160*0Sstevel@tonic-gate /*
4161*0Sstevel@tonic-gate  * scsa2usb_open_usb_pipes:
4162*0Sstevel@tonic-gate  *	set up a pipe policy
4163*0Sstevel@tonic-gate  *	open usb bulk pipes (BO and CB/CBI)
4164*0Sstevel@tonic-gate  *	open usb interrupt pipe (CBI)
4165*0Sstevel@tonic-gate  */
4166*0Sstevel@tonic-gate static int
4167*0Sstevel@tonic-gate scsa2usb_open_usb_pipes(scsa2usb_state_t *scsa2usbp)
4168*0Sstevel@tonic-gate {
4169*0Sstevel@tonic-gate 	int			rval;
4170*0Sstevel@tonic-gate 	usb_pipe_policy_t	policy;	/* bulk pipe policy */
4171*0Sstevel@tonic-gate 	size_t			sz;
4172*0Sstevel@tonic-gate 
4173*0Sstevel@tonic-gate 	ASSERT(scsa2usbp);
4174*0Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
4175*0Sstevel@tonic-gate 
4176*0Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
4177*0Sstevel@tonic-gate 	    "scsa2usb_open_usb_pipes: dip = 0x%p flag = 0x%x",
4178*0Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_dip, scsa2usbp->scsa2usb_flags);
4179*0Sstevel@tonic-gate 
4180*0Sstevel@tonic-gate 	if (!(scsa2usbp->scsa2usb_flags & SCSA2USB_FLAGS_PIPES_OPENED)) {
4181*0Sstevel@tonic-gate 
4182*0Sstevel@tonic-gate 		/*
4183*0Sstevel@tonic-gate 		 * one pipe policy for all bulk pipes
4184*0Sstevel@tonic-gate 		 */
4185*0Sstevel@tonic-gate 		bzero(&policy, sizeof (usb_pipe_policy_t));
4186*0Sstevel@tonic-gate 		/* at least 2, for the normal and exceptional callbacks */
4187*0Sstevel@tonic-gate 		policy.pp_max_async_reqs = 1;
4188*0Sstevel@tonic-gate 
4189*0Sstevel@tonic-gate 		USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
4190*0Sstevel@tonic-gate 		    "scsa2usb_open_usb_pipes: opening bulk pipes");
4191*0Sstevel@tonic-gate 
4192*0Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
4193*0Sstevel@tonic-gate 
4194*0Sstevel@tonic-gate 		/* Open the USB bulk-in pipe */
4195*0Sstevel@tonic-gate 		if ((rval = usb_pipe_open(scsa2usbp->scsa2usb_dip,
4196*0Sstevel@tonic-gate 		    &scsa2usbp->scsa2usb_bulkin_ept, &policy, USB_FLAGS_SLEEP,
4197*0Sstevel@tonic-gate 		    &scsa2usbp->scsa2usb_bulkin_pipe)) != USB_SUCCESS) {
4198*0Sstevel@tonic-gate 			mutex_enter(&scsa2usbp->scsa2usb_mutex);
4199*0Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_SCSA,
4200*0Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
4201*0Sstevel@tonic-gate 			    "scsa2usb_open_usb_pipes: bulk/in pipe open "
4202*0Sstevel@tonic-gate 			    " failed rval = %d", rval);
4203*0Sstevel@tonic-gate 
4204*0Sstevel@tonic-gate 			return (USB_FAILURE);
4205*0Sstevel@tonic-gate 		}
4206*0Sstevel@tonic-gate 
4207*0Sstevel@tonic-gate 		/* Open the bulk-out pipe  using the same policy */
4208*0Sstevel@tonic-gate 		if ((rval = usb_pipe_open(scsa2usbp->scsa2usb_dip,
4209*0Sstevel@tonic-gate 		    &scsa2usbp->scsa2usb_bulkout_ept, &policy, USB_FLAGS_SLEEP,
4210*0Sstevel@tonic-gate 		    &scsa2usbp->scsa2usb_bulkout_pipe)) != USB_SUCCESS) {
4211*0Sstevel@tonic-gate 			usb_pipe_close(scsa2usbp->scsa2usb_dip,
4212*0Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_bulkin_pipe,
4213*0Sstevel@tonic-gate 			    USB_FLAGS_SLEEP, NULL, NULL);
4214*0Sstevel@tonic-gate 
4215*0Sstevel@tonic-gate 			mutex_enter(&scsa2usbp->scsa2usb_mutex);
4216*0Sstevel@tonic-gate 			scsa2usbp->scsa2usb_bulkin_pipe = NULL;
4217*0Sstevel@tonic-gate 
4218*0Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_SCSA,
4219*0Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
4220*0Sstevel@tonic-gate 			    "scsa2usb_open_usb_pipes: bulk/out pipe open"
4221*0Sstevel@tonic-gate 			    " failed rval = %d", rval);
4222*0Sstevel@tonic-gate 
4223*0Sstevel@tonic-gate 			return (USB_FAILURE);
4224*0Sstevel@tonic-gate 		}
4225*0Sstevel@tonic-gate 
4226*0Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
4227*0Sstevel@tonic-gate 
4228*0Sstevel@tonic-gate 		/* open interrupt pipe for CBI protocol */
4229*0Sstevel@tonic-gate 		if (SCSA2USB_IS_CBI(scsa2usbp)) {
4230*0Sstevel@tonic-gate 			mutex_exit(&scsa2usbp->scsa2usb_mutex);
4231*0Sstevel@tonic-gate 
4232*0Sstevel@tonic-gate 			if ((rval = usb_pipe_open(scsa2usbp->scsa2usb_dip,
4233*0Sstevel@tonic-gate 			    &scsa2usbp->scsa2usb_intr_ept, &policy,
4234*0Sstevel@tonic-gate 			    USB_FLAGS_SLEEP, &scsa2usbp->scsa2usb_intr_pipe)) !=
4235*0Sstevel@tonic-gate 			    USB_SUCCESS) {
4236*0Sstevel@tonic-gate 				usb_pipe_close(scsa2usbp->scsa2usb_dip,
4237*0Sstevel@tonic-gate 				    scsa2usbp->scsa2usb_bulkin_pipe,
4238*0Sstevel@tonic-gate 				    USB_FLAGS_SLEEP, NULL, NULL);
4239*0Sstevel@tonic-gate 
4240*0Sstevel@tonic-gate 				usb_pipe_close(scsa2usbp->scsa2usb_dip,
4241*0Sstevel@tonic-gate 				    scsa2usbp->scsa2usb_bulkout_pipe,
4242*0Sstevel@tonic-gate 				    USB_FLAGS_SLEEP, NULL, NULL);
4243*0Sstevel@tonic-gate 
4244*0Sstevel@tonic-gate 				mutex_enter(&scsa2usbp->scsa2usb_mutex);
4245*0Sstevel@tonic-gate 				scsa2usbp->scsa2usb_bulkin_pipe = NULL;
4246*0Sstevel@tonic-gate 				scsa2usbp->scsa2usb_bulkout_pipe = NULL;
4247*0Sstevel@tonic-gate 
4248*0Sstevel@tonic-gate 				USB_DPRINTF_L2(DPRINT_MASK_SCSA,
4249*0Sstevel@tonic-gate 				    scsa2usbp->scsa2usb_log_handle,
4250*0Sstevel@tonic-gate 				    "scsa2usb_open_usb_pipes: intr pipe open"
4251*0Sstevel@tonic-gate 				    " failed rval = %d", rval);
4252*0Sstevel@tonic-gate 
4253*0Sstevel@tonic-gate 				return (USB_FAILURE);
4254*0Sstevel@tonic-gate 			}
4255*0Sstevel@tonic-gate 
4256*0Sstevel@tonic-gate 			mutex_enter(&scsa2usbp->scsa2usb_mutex);
4257*0Sstevel@tonic-gate 		}
4258*0Sstevel@tonic-gate 
4259*0Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
4260*0Sstevel@tonic-gate 
4261*0Sstevel@tonic-gate 		/* get the max transfer size of the bulk pipe */
4262*0Sstevel@tonic-gate 		if (usb_pipe_get_max_bulk_transfer_size(scsa2usbp->scsa2usb_dip,
4263*0Sstevel@tonic-gate 		    &sz) == USB_SUCCESS) {
4264*0Sstevel@tonic-gate 			mutex_enter(&scsa2usbp->scsa2usb_mutex);
4265*0Sstevel@tonic-gate 			scsa2usbp->scsa2usb_max_bulk_xfer_size = sz;
4266*0Sstevel@tonic-gate 		} else {
4267*0Sstevel@tonic-gate 			mutex_enter(&scsa2usbp->scsa2usb_mutex);
4268*0Sstevel@tonic-gate 			scsa2usbp->scsa2usb_max_bulk_xfer_size = DEV_BSIZE;
4269*0Sstevel@tonic-gate 		}
4270*0Sstevel@tonic-gate 
4271*0Sstevel@tonic-gate 		/* limit the xfer size */
4272*0Sstevel@tonic-gate 		scsa2usbp->scsa2usb_max_bulk_xfer_size = min(
4273*0Sstevel@tonic-gate 			scsa2usbp->scsa2usb_max_bulk_xfer_size,
4274*0Sstevel@tonic-gate 			scsa2usb_max_bulk_xfer_size);
4275*0Sstevel@tonic-gate 
4276*0Sstevel@tonic-gate 		USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
4277*0Sstevel@tonic-gate 		    "scsa2usb_open_usb_pipes: max bulk transfer size = %lx",
4278*0Sstevel@tonic-gate 		    scsa2usbp->scsa2usb_max_bulk_xfer_size);
4279*0Sstevel@tonic-gate 
4280*0Sstevel@tonic-gate 		/* Set the pipes opened flag */
4281*0Sstevel@tonic-gate 		scsa2usbp->scsa2usb_flags |= SCSA2USB_FLAGS_PIPES_OPENED;
4282*0Sstevel@tonic-gate 
4283*0Sstevel@tonic-gate 		scsa2usbp->scsa2usb_pipe_state = SCSA2USB_PIPE_NORMAL;
4284*0Sstevel@tonic-gate 
4285*0Sstevel@tonic-gate 		/* Set the state to NONE */
4286*0Sstevel@tonic-gate 		scsa2usbp->scsa2usb_pkt_state = SCSA2USB_PKT_NONE;
4287*0Sstevel@tonic-gate 	}
4288*0Sstevel@tonic-gate 
4289*0Sstevel@tonic-gate 	return (USB_SUCCESS);
4290*0Sstevel@tonic-gate }
4291*0Sstevel@tonic-gate 
4292*0Sstevel@tonic-gate 
4293*0Sstevel@tonic-gate /*
4294*0Sstevel@tonic-gate  * scsa2usb_close_usb_pipes:
4295*0Sstevel@tonic-gate  *	close all pipes synchronously
4296*0Sstevel@tonic-gate  */
4297*0Sstevel@tonic-gate void
4298*0Sstevel@tonic-gate scsa2usb_close_usb_pipes(scsa2usb_state_t *scsa2usbp)
4299*0Sstevel@tonic-gate {
4300*0Sstevel@tonic-gate 	usb_flags_t flags = USB_FLAGS_SLEEP;
4301*0Sstevel@tonic-gate 
4302*0Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
4303*0Sstevel@tonic-gate 	    "scsa2usb_close_usb_pipes: scsa2usb_state = 0x%p", scsa2usbp);
4304*0Sstevel@tonic-gate 
4305*0Sstevel@tonic-gate 	ASSERT(scsa2usbp);
4306*0Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
4307*0Sstevel@tonic-gate 
4308*0Sstevel@tonic-gate 	if ((scsa2usbp->scsa2usb_flags & SCSA2USB_FLAGS_PIPES_OPENED) == 0) {
4309*0Sstevel@tonic-gate 
4310*0Sstevel@tonic-gate 		return;
4311*0Sstevel@tonic-gate 	}
4312*0Sstevel@tonic-gate 
4313*0Sstevel@tonic-gate 	scsa2usbp->scsa2usb_pipe_state = SCSA2USB_PIPE_CLOSING;
4314*0Sstevel@tonic-gate 	/* to avoid races, reset the flag first */
4315*0Sstevel@tonic-gate 	scsa2usbp->scsa2usb_flags &= ~SCSA2USB_FLAGS_PIPES_OPENED;
4316*0Sstevel@tonic-gate 
4317*0Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
4318*0Sstevel@tonic-gate 
4319*0Sstevel@tonic-gate 	usb_pipe_close(scsa2usbp->scsa2usb_dip,
4320*0Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_bulkout_pipe, flags, NULL, NULL);
4321*0Sstevel@tonic-gate 
4322*0Sstevel@tonic-gate 	usb_pipe_close(scsa2usbp->scsa2usb_dip,
4323*0Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_bulkin_pipe, flags, NULL, NULL);
4324*0Sstevel@tonic-gate 
4325*0Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
4326*0Sstevel@tonic-gate 	if (SCSA2USB_IS_CBI(scsa2usbp)) {
4327*0Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
4328*0Sstevel@tonic-gate 		usb_pipe_close(scsa2usbp->scsa2usb_dip,
4329*0Sstevel@tonic-gate 		    scsa2usbp->scsa2usb_intr_pipe, flags, NULL, NULL);
4330*0Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
4331*0Sstevel@tonic-gate 	}
4332*0Sstevel@tonic-gate 	scsa2usbp->scsa2usb_bulkout_pipe = NULL;
4333*0Sstevel@tonic-gate 	scsa2usbp->scsa2usb_bulkin_pipe = NULL;
4334*0Sstevel@tonic-gate 	scsa2usbp->scsa2usb_intr_pipe = NULL;
4335*0Sstevel@tonic-gate 
4336*0Sstevel@tonic-gate 	scsa2usbp->scsa2usb_pipe_state = SCSA2USB_PIPE_NORMAL;
4337*0Sstevel@tonic-gate }
4338*0Sstevel@tonic-gate 
4339*0Sstevel@tonic-gate 
4340*0Sstevel@tonic-gate /*
4341*0Sstevel@tonic-gate  * scsa2usb_fill_up_cdb_lba:
4342*0Sstevel@tonic-gate  *	fill up command CDBs' LBA part
4343*0Sstevel@tonic-gate  */
4344*0Sstevel@tonic-gate static void
4345*0Sstevel@tonic-gate scsa2usb_fill_up_cdb_lba(scsa2usb_cmd_t *cmd, int lba)
4346*0Sstevel@tonic-gate {
4347*0Sstevel@tonic-gate 	/* zero cdb1, lba bits so they won't get copied in the new cdb */
4348*0Sstevel@tonic-gate 	cmd->cmd_cdb[SCSA2USB_LUN] &= 0xE0;
4349*0Sstevel@tonic-gate 	cmd->cmd_cdb[SCSA2USB_LBA_0] = lba >> 24;
4350*0Sstevel@tonic-gate 	cmd->cmd_cdb[SCSA2USB_LBA_1] = lba >> 16;
4351*0Sstevel@tonic-gate 	cmd->cmd_cdb[SCSA2USB_LBA_2] = lba >> 8;
4352*0Sstevel@tonic-gate 	cmd->cmd_cdb[SCSA2USB_LBA_3] = (uchar_t)lba;
4353*0Sstevel@tonic-gate 	cmd->cmd_lba = lba;
4354*0Sstevel@tonic-gate }
4355*0Sstevel@tonic-gate 
4356*0Sstevel@tonic-gate 
4357*0Sstevel@tonic-gate /*
4358*0Sstevel@tonic-gate  * scsa2usb_fill_up_ReadCD_cdb_len:
4359*0Sstevel@tonic-gate  *	fill up READ_CD command CDBs' len part
4360*0Sstevel@tonic-gate  */
4361*0Sstevel@tonic-gate static void
4362*0Sstevel@tonic-gate scsa2usb_fill_up_ReadCD_cdb_len(scsa2usb_cmd_t *cmd, int len, int actual_len)
4363*0Sstevel@tonic-gate {
4364*0Sstevel@tonic-gate 	cmd->cmd_cdb[SCSA2USB_READ_CD_LEN_0] = len >> 16;
4365*0Sstevel@tonic-gate 	cmd->cmd_cdb[SCSA2USB_READ_CD_LEN_1] = len >> 8;
4366*0Sstevel@tonic-gate 	cmd->cmd_cdb[SCSA2USB_READ_CD_LEN_2] = (uchar_t)len;
4367*0Sstevel@tonic-gate 	cmd->cmd_actual_len = (uchar_t)actual_len;
4368*0Sstevel@tonic-gate }
4369*0Sstevel@tonic-gate 
4370*0Sstevel@tonic-gate 
4371*0Sstevel@tonic-gate /*
4372*0Sstevel@tonic-gate  * scsa2usb_fill_up_12byte_cdb_len:
4373*0Sstevel@tonic-gate  *	fill up generic 12-byte command CDBs' len part
4374*0Sstevel@tonic-gate  */
4375*0Sstevel@tonic-gate static void
4376*0Sstevel@tonic-gate scsa2usb_fill_up_12byte_cdb_len(scsa2usb_cmd_t *cmd, int len, int actual_len)
4377*0Sstevel@tonic-gate {
4378*0Sstevel@tonic-gate 	cmd->cmd_cdb[6] = len >> 24;
4379*0Sstevel@tonic-gate 	cmd->cmd_cdb[7] = len >> 16;
4380*0Sstevel@tonic-gate 	cmd->cmd_cdb[8] = len >> 8;
4381*0Sstevel@tonic-gate 	cmd->cmd_cdb[9] = (uchar_t)len;
4382*0Sstevel@tonic-gate 	cmd->cmd_actual_len = (uchar_t)actual_len;
4383*0Sstevel@tonic-gate }
4384*0Sstevel@tonic-gate 
4385*0Sstevel@tonic-gate 
4386*0Sstevel@tonic-gate /*
4387*0Sstevel@tonic-gate  * scsa2usb_fill_up_cdb_len:
4388*0Sstevel@tonic-gate  *	fill up generic 10-byte command CDBs' len part
4389*0Sstevel@tonic-gate  */
4390*0Sstevel@tonic-gate static void
4391*0Sstevel@tonic-gate scsa2usb_fill_up_cdb_len(scsa2usb_cmd_t *cmd, int len)
4392*0Sstevel@tonic-gate {
4393*0Sstevel@tonic-gate 	cmd->cmd_cdb[SCSA2USB_LEN_0] = len >> 8;
4394*0Sstevel@tonic-gate 	cmd->cmd_cdb[SCSA2USB_LEN_1] = (uchar_t)len;
4395*0Sstevel@tonic-gate }
4396*0Sstevel@tonic-gate 
4397*0Sstevel@tonic-gate 
4398*0Sstevel@tonic-gate /*
4399*0Sstevel@tonic-gate  * scsa2usb_read_cd_blk_size:
4400*0Sstevel@tonic-gate  *	For SCMD_READ_CD opcode (0xbe). Figure out the
4401*0Sstevel@tonic-gate  *	block size based on expected sector type field
4402*0Sstevel@tonic-gate  *	definition. See MMC SCSI Specs section 6.1.15
4403*0Sstevel@tonic-gate  *
4404*0Sstevel@tonic-gate  *	Based on the value of the "expected_sector_type"
4405*0Sstevel@tonic-gate  *	field, the block size could be different.
4406*0Sstevel@tonic-gate  */
4407*0Sstevel@tonic-gate static int
4408*0Sstevel@tonic-gate scsa2usb_read_cd_blk_size(uchar_t expected_sector_type)
4409*0Sstevel@tonic-gate {
4410*0Sstevel@tonic-gate 	int blk_size;
4411*0Sstevel@tonic-gate 
4412*0Sstevel@tonic-gate 	switch (expected_sector_type) {
4413*0Sstevel@tonic-gate 	case READ_CD_EST_CDDA:
4414*0Sstevel@tonic-gate 		blk_size = CDROM_BLK_2352;
4415*0Sstevel@tonic-gate 		break;
4416*0Sstevel@tonic-gate 	case READ_CD_EST_MODE2:
4417*0Sstevel@tonic-gate 		blk_size = CDROM_BLK_2336;
4418*0Sstevel@tonic-gate 		break;
4419*0Sstevel@tonic-gate 	case READ_CD_EST_MODE2FORM2:
4420*0Sstevel@tonic-gate 		blk_size = CDROM_BLK_2324;
4421*0Sstevel@tonic-gate 		break;
4422*0Sstevel@tonic-gate 	case READ_CD_EST_MODE2FORM1:
4423*0Sstevel@tonic-gate 	case READ_CD_EST_ALLTYPE:
4424*0Sstevel@tonic-gate 	case READ_CD_EST_MODE1:
4425*0Sstevel@tonic-gate 	default:
4426*0Sstevel@tonic-gate 		blk_size = CDROM_BLK_2048;
4427*0Sstevel@tonic-gate 	}
4428*0Sstevel@tonic-gate 
4429*0Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, NULL, "scsa2usb_read_cd_blk_size: "
4430*0Sstevel@tonic-gate 	    "est = 0x%x blk_size = %d", expected_sector_type, blk_size);
4431*0Sstevel@tonic-gate 
4432*0Sstevel@tonic-gate 	return (blk_size);
4433*0Sstevel@tonic-gate }
4434*0Sstevel@tonic-gate 
4435*0Sstevel@tonic-gate 
4436*0Sstevel@tonic-gate /* needed for esballoc_wait() */
4437*0Sstevel@tonic-gate /*ARGSUSED*/
4438*0Sstevel@tonic-gate static void
4439*0Sstevel@tonic-gate scsa2usb_null_free(char *arg)
4440*0Sstevel@tonic-gate {
4441*0Sstevel@tonic-gate }
4442*0Sstevel@tonic-gate 
4443*0Sstevel@tonic-gate static frtn_t fr = {
4444*0Sstevel@tonic-gate 	scsa2usb_null_free,
4445*0Sstevel@tonic-gate 	NULL
4446*0Sstevel@tonic-gate };
4447*0Sstevel@tonic-gate 
4448*0Sstevel@tonic-gate 
4449*0Sstevel@tonic-gate /*
4450*0Sstevel@tonic-gate  * scsa2usb_bp_to_mblk:
4451*0Sstevel@tonic-gate  *	Convert a bp to mblk_t. USBA framework understands mblk_t.
4452*0Sstevel@tonic-gate  */
4453*0Sstevel@tonic-gate static mblk_t *
4454*0Sstevel@tonic-gate scsa2usb_bp_to_mblk(scsa2usb_state_t *scsa2usbp)
4455*0Sstevel@tonic-gate {
4456*0Sstevel@tonic-gate 	size_t		size;
4457*0Sstevel@tonic-gate 	mblk_t		*mp;
4458*0Sstevel@tonic-gate 	struct buf	*bp;
4459*0Sstevel@tonic-gate 	scsa2usb_cmd_t	*cmd = PKT2CMD(scsa2usbp->scsa2usb_cur_pkt);
4460*0Sstevel@tonic-gate 
4461*0Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
4462*0Sstevel@tonic-gate 	    "scsa2usb_bp_to_mblk: ");
4463*0Sstevel@tonic-gate 
4464*0Sstevel@tonic-gate 	ASSERT(scsa2usbp->scsa2usb_cur_pkt);
4465*0Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
4466*0Sstevel@tonic-gate 
4467*0Sstevel@tonic-gate 	bp = cmd->cmd_bp;
4468*0Sstevel@tonic-gate 
4469*0Sstevel@tonic-gate 	if (bp && (bp->b_bcount > 0)) {
4470*0Sstevel@tonic-gate 		size = ((bp->b_bcount > cmd->cmd_xfercount) ?
4471*0Sstevel@tonic-gate 				cmd->cmd_xfercount : bp->b_bcount);
4472*0Sstevel@tonic-gate 	} else {
4473*0Sstevel@tonic-gate 
4474*0Sstevel@tonic-gate 		return (NULL);
4475*0Sstevel@tonic-gate 	}
4476*0Sstevel@tonic-gate 
4477*0Sstevel@tonic-gate 	mp = esballoc_wait((uchar_t *)bp->b_un.b_addr + cmd->cmd_offset,
4478*0Sstevel@tonic-gate 						size, BPRI_LO, &fr);
4479*0Sstevel@tonic-gate 
4480*0Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
4481*0Sstevel@tonic-gate 	    "scsa2usb_bp_to_mblk: "
4482*0Sstevel@tonic-gate 	    "mp=0x%p bp=0x%p pkt=0x%p off=0x%lx sz=%lu add=0x%p", mp,
4483*0Sstevel@tonic-gate 	    (void *)bp, scsa2usbp->scsa2usb_cur_pkt, cmd->cmd_offset,
4484*0Sstevel@tonic-gate 	    bp->b_bcount - cmd->cmd_offset,
4485*0Sstevel@tonic-gate 	    bp->b_un.b_addr);
4486*0Sstevel@tonic-gate 
4487*0Sstevel@tonic-gate 	mp->b_wptr += size;
4488*0Sstevel@tonic-gate 	cmd->cmd_offset += size;
4489*0Sstevel@tonic-gate 
4490*0Sstevel@tonic-gate 	return (mp);
4491*0Sstevel@tonic-gate }
4492*0Sstevel@tonic-gate 
4493*0Sstevel@tonic-gate 
4494*0Sstevel@tonic-gate /*
4495*0Sstevel@tonic-gate  * scsa2usb_handle_data_start:
4496*0Sstevel@tonic-gate  *	Initiate the data xfer. It could be IN/OUT direction.
4497*0Sstevel@tonic-gate  *
4498*0Sstevel@tonic-gate  *	Data IN:
4499*0Sstevel@tonic-gate  *		Send out the bulk-xfer request
4500*0Sstevel@tonic-gate  *		if rval implies STALL
4501*0Sstevel@tonic-gate  *			clear endpoint stall and reset bulk-in pipe
4502*0Sstevel@tonic-gate  *			handle data read in so far; set cmd->cmd_done
4503*0Sstevel@tonic-gate  *			also adjust data xfer length accordingly
4504*0Sstevel@tonic-gate  *		else other error
4505*0Sstevel@tonic-gate  *			report back to transport
4506*0Sstevel@tonic-gate  *			typically transport will call reset recovery
4507*0Sstevel@tonic-gate  *		else (no error)
4508*0Sstevel@tonic-gate  *			return success
4509*0Sstevel@tonic-gate  *
4510*0Sstevel@tonic-gate  *	Data OUT:
4511*0Sstevel@tonic-gate  *		Send out the bulk-xfer request
4512*0Sstevel@tonic-gate  *		if rval implies STALL
4513*0Sstevel@tonic-gate  *			clear endpoint stall and reset bulk-in pipe
4514*0Sstevel@tonic-gate  *			adjust data xfer length
4515*0Sstevel@tonic-gate  *		else other error
4516*0Sstevel@tonic-gate  *			report back to transport
4517*0Sstevel@tonic-gate  *			typically transport will call reset recovery
4518*0Sstevel@tonic-gate  *		else (no error)
4519*0Sstevel@tonic-gate  *			return success
4520*0Sstevel@tonic-gate  *
4521*0Sstevel@tonic-gate  *	NOTE: We call this function only if there is xfercount.
4522*0Sstevel@tonic-gate  */
4523*0Sstevel@tonic-gate int
4524*0Sstevel@tonic-gate scsa2usb_handle_data_start(scsa2usb_state_t *scsa2usbp,
4525*0Sstevel@tonic-gate     scsa2usb_cmd_t *cmd, usb_bulk_req_t *req)
4526*0Sstevel@tonic-gate {
4527*0Sstevel@tonic-gate 	int		rval = USB_SUCCESS;
4528*0Sstevel@tonic-gate 	uint_t		ept_addr;
4529*0Sstevel@tonic-gate 	usb_flags_t	flags = USB_FLAGS_SLEEP;
4530*0Sstevel@tonic-gate #ifdef	SCSA2USB_BULK_ONLY_TEST
4531*0Sstevel@tonic-gate 	usb_req_attrs_t	attrs = 0;
4532*0Sstevel@tonic-gate #else
4533*0Sstevel@tonic-gate 	usb_req_attrs_t	attrs = USB_ATTRS_SHORT_XFER_OK;
4534*0Sstevel@tonic-gate #endif
4535*0Sstevel@tonic-gate 
4536*0Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
4537*0Sstevel@tonic-gate 	    "scsa2usb_handle_data_start: BEGIN cmd = %p, req = %p", cmd, req);
4538*0Sstevel@tonic-gate 
4539*0Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
4540*0Sstevel@tonic-gate 
4541*0Sstevel@tonic-gate 	switch (cmd->cmd_dir) {
4542*0Sstevel@tonic-gate 	case USB_EP_DIR_IN:
4543*0Sstevel@tonic-gate #ifdef	SCSA2USB_BULK_ONLY_TEST
4544*0Sstevel@tonic-gate 		/*
4545*0Sstevel@tonic-gate 		 * This case occurs when the host expects to receive
4546*0Sstevel@tonic-gate 		 * more data than the device actually transfers. Hi > Di
4547*0Sstevel@tonic-gate 		 */
4548*0Sstevel@tonic-gate 		if (scsa2usb_test_case_5) {
4549*0Sstevel@tonic-gate 			usb_bulk_req_t *req2;
4550*0Sstevel@tonic-gate 
4551*0Sstevel@tonic-gate 			req->bulk_len = cmd->cmd_xfercount - 1;
4552*0Sstevel@tonic-gate 			req->bulk_attributes = 0;
4553*0Sstevel@tonic-gate 			mutex_exit(&scsa2usbp->scsa2usb_mutex);
4554*0Sstevel@tonic-gate 			SCSA2USB_FREE_MSG(req->bulk_data);
4555*0Sstevel@tonic-gate 			req->bulk_data = allocb_wait(req->bulk_len, BPRI_LO,
4556*0Sstevel@tonic-gate 			    STR_NOSIG, NULL);
4557*0Sstevel@tonic-gate 
4558*0Sstevel@tonic-gate 			ASSERT(req->bulk_timeout);
4559*0Sstevel@tonic-gate 			rval = usb_pipe_bulk_xfer(
4560*0Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_bulkin_pipe, req, flags);
4561*0Sstevel@tonic-gate 			mutex_enter(&scsa2usbp->scsa2usb_mutex);
4562*0Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_SCSA,
4563*0Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle, "rval = %x", rval);
4564*0Sstevel@tonic-gate 
4565*0Sstevel@tonic-gate 			req2 = scsa2usb_init_bulk_req(scsa2usbp,
4566*0Sstevel@tonic-gate 			    cmd->cmd_xfercount + 2,
4567*0Sstevel@tonic-gate 			    cmd->cmd_timeout, 0, flags);
4568*0Sstevel@tonic-gate 			req2->bulk_len = cmd->cmd_xfercount + 2;
4569*0Sstevel@tonic-gate 			mutex_exit(&scsa2usbp->scsa2usb_mutex);
4570*0Sstevel@tonic-gate 
4571*0Sstevel@tonic-gate 			ASSERT(req2->bulk_timeout);
4572*0Sstevel@tonic-gate 			rval = usb_pipe_bulk_xfer(
4573*0Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_bulkin_pipe, req2, flags);
4574*0Sstevel@tonic-gate 			mutex_enter(&scsa2usbp->scsa2usb_mutex);
4575*0Sstevel@tonic-gate 
4576*0Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_SCSA,
4577*0Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
4578*0Sstevel@tonic-gate 			    "TEST 5: Hi > Di: rval = 0x%x", rval);
4579*0Sstevel@tonic-gate 			scsa2usb_test_case_5 = 0;
4580*0Sstevel@tonic-gate 			usb_free_bulk_req(req2);
4581*0Sstevel@tonic-gate 
4582*0Sstevel@tonic-gate 			return (rval);
4583*0Sstevel@tonic-gate 		}
4584*0Sstevel@tonic-gate 
4585*0Sstevel@tonic-gate 		/*
4586*0Sstevel@tonic-gate 		 * This happens when the host expects to send data to the
4587*0Sstevel@tonic-gate 		 * device while the device intends to send data to the host.
4588*0Sstevel@tonic-gate 		 */
4589*0Sstevel@tonic-gate 		if (scsa2usb_test_case_8 && (cmd->cmd_cdb[0] == SCMD_READ_G1)) {
4590*0Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_SCSA,
4591*0Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
4592*0Sstevel@tonic-gate 			    "TEST 8: Hi <> Do: Step 2");
4593*0Sstevel@tonic-gate 			scsa2usb_test_mblk(scsa2usbp, B_TRUE);
4594*0Sstevel@tonic-gate 			scsa2usb_test_case_8 = 0;
4595*0Sstevel@tonic-gate 
4596*0Sstevel@tonic-gate 			return (rval);
4597*0Sstevel@tonic-gate 		}
4598*0Sstevel@tonic-gate #endif	/* SCSA2USB_BULK_ONLY_TEST */
4599*0Sstevel@tonic-gate 
4600*0Sstevel@tonic-gate 		ept_addr = scsa2usbp->scsa2usb_bulkin_ept.bEndpointAddress;
4601*0Sstevel@tonic-gate 		req->bulk_len = cmd->cmd_xfercount;
4602*0Sstevel@tonic-gate 		req->bulk_attributes = attrs;
4603*0Sstevel@tonic-gate 		SCSA2USB_FREE_MSG(req->bulk_data);
4604*0Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
4605*0Sstevel@tonic-gate 
4606*0Sstevel@tonic-gate 
4607*0Sstevel@tonic-gate 		ASSERT(cmd->cmd_bp->b_bcount >= req->bulk_len);
4608*0Sstevel@tonic-gate 
4609*0Sstevel@tonic-gate 		req->bulk_data = esballoc_wait(
4610*0Sstevel@tonic-gate 				(uchar_t *)cmd->cmd_bp->b_un.b_addr +
4611*0Sstevel@tonic-gate 				cmd->cmd_offset,
4612*0Sstevel@tonic-gate 				req->bulk_len, BPRI_LO, &fr);
4613*0Sstevel@tonic-gate 
4614*0Sstevel@tonic-gate 		ASSERT(req->bulk_timeout);
4615*0Sstevel@tonic-gate 		rval = usb_pipe_bulk_xfer(scsa2usbp->scsa2usb_bulkin_pipe,
4616*0Sstevel@tonic-gate 								req, flags);
4617*0Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
4618*0Sstevel@tonic-gate 
4619*0Sstevel@tonic-gate 		break;
4620*0Sstevel@tonic-gate 
4621*0Sstevel@tonic-gate 	case USB_EP_DIR_OUT:
4622*0Sstevel@tonic-gate #ifdef	SCSA2USB_BULK_ONLY_TEST
4623*0Sstevel@tonic-gate 		/*
4624*0Sstevel@tonic-gate 		 * This happens when the host expects to receive data
4625*0Sstevel@tonic-gate 		 * from the device while the device intends to receive
4626*0Sstevel@tonic-gate 		 * data from the host.
4627*0Sstevel@tonic-gate 		 */
4628*0Sstevel@tonic-gate 		if (scsa2usb_test_case_10 &&
4629*0Sstevel@tonic-gate 		    (cmd->cmd_cdb[0] == SCMD_WRITE_G1)) {
4630*0Sstevel@tonic-gate 			req->bulk_len = CSW_LEN;
4631*0Sstevel@tonic-gate 			mutex_exit(&scsa2usbp->scsa2usb_mutex);
4632*0Sstevel@tonic-gate 
4633*0Sstevel@tonic-gate 			ASSERT(req->bulk_timeout);
4634*0Sstevel@tonic-gate 			rval = usb_pipe_bulk_xfer(
4635*0Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_bulkin_pipe, req, flags);
4636*0Sstevel@tonic-gate 			mutex_enter(&scsa2usbp->scsa2usb_mutex);
4637*0Sstevel@tonic-gate 
4638*0Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_SCSA,
4639*0Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
4640*0Sstevel@tonic-gate 			    "TEST 10: Ho <> Di: done rval = 0x%x",  rval);
4641*0Sstevel@tonic-gate 			scsa2usb_test_case_10 = 0;
4642*0Sstevel@tonic-gate 
4643*0Sstevel@tonic-gate 			return (rval);
4644*0Sstevel@tonic-gate 		}
4645*0Sstevel@tonic-gate #endif	/* SCSA2USB_BULK_ONLY_TEST */
4646*0Sstevel@tonic-gate 
4647*0Sstevel@tonic-gate 		req->bulk_data = scsa2usb_bp_to_mblk(scsa2usbp);
4648*0Sstevel@tonic-gate 		if (req->bulk_data == NULL) {
4649*0Sstevel@tonic-gate 
4650*0Sstevel@tonic-gate 			return (USB_FAILURE);
4651*0Sstevel@tonic-gate 		}
4652*0Sstevel@tonic-gate 
4653*0Sstevel@tonic-gate #ifdef	SCSA2USB_BULK_ONLY_TEST
4654*0Sstevel@tonic-gate 		if (scsa2usb_test_case_11) {
4655*0Sstevel@tonic-gate 			/*
4656*0Sstevel@tonic-gate 			 * Host expects to send data to the device and
4657*0Sstevel@tonic-gate 			 * device doesn't expect to receive any data
4658*0Sstevel@tonic-gate 			 */
4659*0Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_SCSA,
4660*0Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle, "TEST 11: Ho > Do");
4661*0Sstevel@tonic-gate 
4662*0Sstevel@tonic-gate 			scsa2usb_test_mblk(scsa2usbp, B_FALSE);
4663*0Sstevel@tonic-gate 			scsa2usb_test_case_11 = 0;
4664*0Sstevel@tonic-gate 		}
4665*0Sstevel@tonic-gate #endif	/* SCSA2USB_BULK_ONLY_TEST */
4666*0Sstevel@tonic-gate 
4667*0Sstevel@tonic-gate 		ept_addr = scsa2usbp->scsa2usb_bulkout_ept.bEndpointAddress;
4668*0Sstevel@tonic-gate 		req->bulk_len = req->bulk_data->b_wptr - req->bulk_data->b_rptr;
4669*0Sstevel@tonic-gate 		req->bulk_timeout = scsa2usb_bulk_timeout(cmd->cmd_timeout);
4670*0Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
4671*0Sstevel@tonic-gate 
4672*0Sstevel@tonic-gate 		ASSERT(req->bulk_timeout);
4673*0Sstevel@tonic-gate 		rval = usb_pipe_bulk_xfer(scsa2usbp->scsa2usb_bulkout_pipe,
4674*0Sstevel@tonic-gate 								req, flags);
4675*0Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
4676*0Sstevel@tonic-gate 		break;
4677*0Sstevel@tonic-gate 	}
4678*0Sstevel@tonic-gate 
4679*0Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_SCSA,
4680*0Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_log_handle,
4681*0Sstevel@tonic-gate 	    "scsa2usb_handle_data_start: rval=%d cr=%d", rval,
4682*0Sstevel@tonic-gate 	    req->bulk_completion_reason);
4683*0Sstevel@tonic-gate 
4684*0Sstevel@tonic-gate 	if (rval != USB_SUCCESS) {
4685*0Sstevel@tonic-gate 		/* Handle Errors now */
4686*0Sstevel@tonic-gate 		if (req->bulk_completion_reason == USB_CR_STALL) {
4687*0Sstevel@tonic-gate 			if (cmd->cmd_dir == USB_EP_DIR_IN) {
4688*0Sstevel@tonic-gate 				(void) scsa2usb_clear_ept_stall(
4689*0Sstevel@tonic-gate 				    scsa2usbp, ept_addr,
4690*0Sstevel@tonic-gate 				    scsa2usbp-> scsa2usb_bulkin_pipe,
4691*0Sstevel@tonic-gate 				    "bulk-in");
4692*0Sstevel@tonic-gate 			} else {
4693*0Sstevel@tonic-gate 				(void) scsa2usb_clear_ept_stall(
4694*0Sstevel@tonic-gate 				    scsa2usbp, ept_addr,
4695*0Sstevel@tonic-gate 				    scsa2usbp-> scsa2usb_bulkout_pipe,
4696*0Sstevel@tonic-gate 				    "bulk-out");
4697*0Sstevel@tonic-gate 			}
4698*0Sstevel@tonic-gate 		}
4699*0Sstevel@tonic-gate 
4700*0Sstevel@tonic-gate 		/* no more data to transfer after this */
4701*0Sstevel@tonic-gate 		cmd->cmd_done = 1;
4702*0Sstevel@tonic-gate 	}
4703*0Sstevel@tonic-gate 
4704*0Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
4705*0Sstevel@tonic-gate 	    "scsa2usb_handle_data_start: END %s data rval = %d",
4706*0Sstevel@tonic-gate 	    (cmd->cmd_dir == USB_EP_DIR_IN) ? "bulk-in" : "bulk-out", rval);
4707*0Sstevel@tonic-gate 
4708*0Sstevel@tonic-gate 	return (rval);
4709*0Sstevel@tonic-gate }
4710*0Sstevel@tonic-gate 
4711*0Sstevel@tonic-gate 
4712*0Sstevel@tonic-gate /*
4713*0Sstevel@tonic-gate  * scsa2usb_handle_data_done:
4714*0Sstevel@tonic-gate  *	This function handles the completion of the data xfer.
4715*0Sstevel@tonic-gate  *	It also massages the inquiry data. This function may
4716*0Sstevel@tonic-gate  *	also be called after a stall.
4717*0Sstevel@tonic-gate  */
4718*0Sstevel@tonic-gate void
4719*0Sstevel@tonic-gate scsa2usb_handle_data_done(scsa2usb_state_t *scsa2usbp,
4720*0Sstevel@tonic-gate     scsa2usb_cmd_t *cmd, usb_bulk_req_t *req)
4721*0Sstevel@tonic-gate {
4722*0Sstevel@tonic-gate 	struct buf	*bp = cmd->cmd_bp;
4723*0Sstevel@tonic-gate 	struct scsi_pkt	*pkt = scsa2usbp->scsa2usb_cur_pkt;
4724*0Sstevel@tonic-gate 	mblk_t		*data = req->bulk_data;
4725*0Sstevel@tonic-gate 	int		len = data ? (data->b_wptr - data->b_rptr) : 0;
4726*0Sstevel@tonic-gate 
4727*0Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
4728*0Sstevel@tonic-gate 
4729*0Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
4730*0Sstevel@tonic-gate 	    "scsa2usb_handle_data_done:\n\tcmd = 0x%p data = 0x%p len = 0x%x",
4731*0Sstevel@tonic-gate 	    cmd, data, len);
4732*0Sstevel@tonic-gate 
4733*0Sstevel@tonic-gate 	cmd->cmd_resid_xfercount = cmd->cmd_xfercount - len;
4734*0Sstevel@tonic-gate 
4735*0Sstevel@tonic-gate 	if (len)  {
4736*0Sstevel@tonic-gate 		uchar_t	*p;
4737*0Sstevel@tonic-gate 		scsa2usb_read_cap_t *cap;
4738*0Sstevel@tonic-gate 
4739*0Sstevel@tonic-gate 		switch (cmd->cmd_cdb[SCSA2USB_OPCODE]) {
4740*0Sstevel@tonic-gate 		case SCMD_INQUIRY:
4741*0Sstevel@tonic-gate 			/*
4742*0Sstevel@tonic-gate 			 * cache a copy of the inquiry data for our own use
4743*0Sstevel@tonic-gate 			 * but ensure that we have at least up to
4744*0Sstevel@tonic-gate 			 * inq_revision, inq_serial is not required.
4745*0Sstevel@tonic-gate 			 * ignore inquiry data returned for inquiry commands
4746*0Sstevel@tonic-gate 			 * with SCSI-3 EVPD, CmdDt bits set.
4747*0Sstevel@tonic-gate 			 */
4748*0Sstevel@tonic-gate 			if (((cmd->cmd_cdb[SCSA2USB_LUN] & 0x1f) == 0) &&
4749*0Sstevel@tonic-gate 			    (len >= SCSA2USB_MAX_INQ_LEN)) {
4750*0Sstevel@tonic-gate 				bzero(&scsa2usbp->scsa2usb_lun_inquiry
4751*0Sstevel@tonic-gate 				    [pkt->pkt_address.a_lun],
4752*0Sstevel@tonic-gate 				    sizeof (struct scsi_inquiry));
4753*0Sstevel@tonic-gate 				bcopy(data->b_rptr,
4754*0Sstevel@tonic-gate 				    &scsa2usbp->scsa2usb_lun_inquiry
4755*0Sstevel@tonic-gate 				    [pkt->pkt_address.a_lun], len);
4756*0Sstevel@tonic-gate 			}
4757*0Sstevel@tonic-gate 
4758*0Sstevel@tonic-gate 			USB_DPRINTF_L3(DPRINT_MASK_SCSA,
4759*0Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
4760*0Sstevel@tonic-gate 			    "scsi inquiry type = 0x%x",
4761*0Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_lun_inquiry
4762*0Sstevel@tonic-gate 			    [pkt->pkt_address.a_lun].inq_dtype);
4763*0Sstevel@tonic-gate 
4764*0Sstevel@tonic-gate 			cmd->cmd_done = 1;
4765*0Sstevel@tonic-gate 			goto handle_data;
4766*0Sstevel@tonic-gate 
4767*0Sstevel@tonic-gate 		case SCMD_READ_CAPACITY:
4768*0Sstevel@tonic-gate 			cap = (scsa2usb_read_cap_t *)data->b_rptr;
4769*0Sstevel@tonic-gate 
4770*0Sstevel@tonic-gate 			/* Figure out the logical block size */
4771*0Sstevel@tonic-gate 			if ((len >= sizeof (struct scsa2usb_read_cap)) &&
4772*0Sstevel@tonic-gate 			    (req->bulk_completion_reason == USB_CR_OK)) {
4773*0Sstevel@tonic-gate 				scsa2usbp->
4774*0Sstevel@tonic-gate 				    scsa2usb_lbasize[pkt->pkt_address.a_lun] =
4775*0Sstevel@tonic-gate 				    SCSA2USB_MK_32BIT(
4776*0Sstevel@tonic-gate 					    cap->scsa2usb_read_cap_blen3,
4777*0Sstevel@tonic-gate 					    cap->scsa2usb_read_cap_blen2,
4778*0Sstevel@tonic-gate 					    cap->scsa2usb_read_cap_blen1,
4779*0Sstevel@tonic-gate 					    cap->scsa2usb_read_cap_blen0);
4780*0Sstevel@tonic-gate 
4781*0Sstevel@tonic-gate 				USB_DPRINTF_L3(DPRINT_MASK_SCSA,
4782*0Sstevel@tonic-gate 				    scsa2usbp->scsa2usb_log_handle,
4783*0Sstevel@tonic-gate 				    "lbasize=%d", scsa2usbp->
4784*0Sstevel@tonic-gate 				    scsa2usb_lbasize[pkt->pkt_address.a_lun]);
4785*0Sstevel@tonic-gate 			}
4786*0Sstevel@tonic-gate 			cmd->cmd_done = 1;
4787*0Sstevel@tonic-gate 			goto handle_data;
4788*0Sstevel@tonic-gate 
4789*0Sstevel@tonic-gate 		case SCMD_REQUEST_SENSE:
4790*0Sstevel@tonic-gate 			p = data->b_rptr;
4791*0Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_SCSA,
4792*0Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
4793*0Sstevel@tonic-gate 			    "cdb: %x rqsense: "
4794*0Sstevel@tonic-gate 			    "%x %x %x %x %x %x %x %x %x %x\n\t"
4795*0Sstevel@tonic-gate 			    "%x %x %x %x %x %x %x %x %x %x",
4796*0Sstevel@tonic-gate 			    cmd->cmd_cdb[0],
4797*0Sstevel@tonic-gate 			    p[0], p[1], p[2], p[3], p[4],
4798*0Sstevel@tonic-gate 			    p[5], p[6], p[7], p[8], p[9],
4799*0Sstevel@tonic-gate 			    p[10], p[11], p[12], p[13], p[14],
4800*0Sstevel@tonic-gate 			    p[15], p[16], p[17], p[18], p[19]);
4801*0Sstevel@tonic-gate 
4802*0Sstevel@tonic-gate 			scsa2usbp->scsa2usb_last_cmd.status = p[2];
4803*0Sstevel@tonic-gate 			cmd->cmd_done = 1;
4804*0Sstevel@tonic-gate 			/* FALLTHROUGH */
4805*0Sstevel@tonic-gate 
4806*0Sstevel@tonic-gate 		default:
4807*0Sstevel@tonic-gate handle_data:
4808*0Sstevel@tonic-gate 			if (bp && len && (cmd->cmd_dir == USB_EP_DIR_IN)) {
4809*0Sstevel@tonic-gate 				/*
4810*0Sstevel@tonic-gate 				 * we don't have to copy the data, the
4811*0Sstevel@tonic-gate 				 * data pointers for the mblk_t for
4812*0Sstevel@tonic-gate 				 * the bulk-in xfer points to the
4813*0Sstevel@tonic-gate 				 * struct buf * data.
4814*0Sstevel@tonic-gate 				 */
4815*0Sstevel@tonic-gate 				cmd->cmd_offset += len;
4816*0Sstevel@tonic-gate 			}
4817*0Sstevel@tonic-gate 
4818*0Sstevel@tonic-gate 			USB_DPRINTF_L3(DPRINT_MASK_SCSA,
4819*0Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
4820*0Sstevel@tonic-gate 			    "len = 0x%x total = 0x%lx",
4821*0Sstevel@tonic-gate 			    len, cmd->cmd_total_xfercount);
4822*0Sstevel@tonic-gate 
4823*0Sstevel@tonic-gate 			/*
4824*0Sstevel@tonic-gate 			 * update total_xfercount now but it may be
4825*0Sstevel@tonic-gate 			 * adjusted after receiving the residue
4826*0Sstevel@tonic-gate 			 */
4827*0Sstevel@tonic-gate 			cmd->cmd_total_xfercount -= len;
4828*0Sstevel@tonic-gate 
4829*0Sstevel@tonic-gate 			if ((req->bulk_completion_reason != USB_CR_OK) ||
4830*0Sstevel@tonic-gate 			    (cmd->cmd_resid_xfercount != 0) ||
4831*0Sstevel@tonic-gate 			    (cmd->cmd_total_xfercount == 0)) {
4832*0Sstevel@tonic-gate 				/* set pkt_resid to total to be sure */
4833*0Sstevel@tonic-gate 				pkt->pkt_resid = cmd->cmd_total_xfercount;
4834*0Sstevel@tonic-gate 				cmd->cmd_done = 1;
4835*0Sstevel@tonic-gate 			}
4836*0Sstevel@tonic-gate 
4837*0Sstevel@tonic-gate 			break;
4838*0Sstevel@tonic-gate 		}
4839*0Sstevel@tonic-gate 	} else {
4840*0Sstevel@tonic-gate 		if (cmd->cmd_dir == USB_EP_DIR_OUT) {
4841*0Sstevel@tonic-gate 			if (cmd->cmd_total_xfercount == 0) {
4842*0Sstevel@tonic-gate 				cmd->cmd_done = 1;
4843*0Sstevel@tonic-gate 			}
4844*0Sstevel@tonic-gate 		}
4845*0Sstevel@tonic-gate 	}
4846*0Sstevel@tonic-gate }
4847*0Sstevel@tonic-gate 
4848*0Sstevel@tonic-gate 
4849*0Sstevel@tonic-gate /*
4850*0Sstevel@tonic-gate  * scsa2usb_init_bulk_req:
4851*0Sstevel@tonic-gate  *	Allocate (synchronously) and fill in a bulk-request
4852*0Sstevel@tonic-gate  */
4853*0Sstevel@tonic-gate usb_bulk_req_t *
4854*0Sstevel@tonic-gate scsa2usb_init_bulk_req(scsa2usb_state_t *scsa2usbp, size_t length,
4855*0Sstevel@tonic-gate     uint_t timeout, usb_req_attrs_t attrs, usb_flags_t flags)
4856*0Sstevel@tonic-gate {
4857*0Sstevel@tonic-gate 	usb_bulk_req_t	*req;
4858*0Sstevel@tonic-gate 
4859*0Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
4860*0Sstevel@tonic-gate 
4861*0Sstevel@tonic-gate 	req = usb_alloc_bulk_req(scsa2usbp->scsa2usb_dip, length,
4862*0Sstevel@tonic-gate 	    flags | USB_FLAGS_SLEEP);
4863*0Sstevel@tonic-gate 
4864*0Sstevel@tonic-gate 	req->bulk_len = length;			/* xfer length */
4865*0Sstevel@tonic-gate 	req->bulk_timeout = scsa2usb_bulk_timeout(timeout); /* xfer timeout */
4866*0Sstevel@tonic-gate 	req->bulk_attributes = attrs;		/* xfer attrs */
4867*0Sstevel@tonic-gate 	req->bulk_client_private = (usb_opaque_t)scsa2usbp; /* statep */
4868*0Sstevel@tonic-gate 
4869*0Sstevel@tonic-gate 	return (req);
4870*0Sstevel@tonic-gate }
4871*0Sstevel@tonic-gate 
4872*0Sstevel@tonic-gate 
4873*0Sstevel@tonic-gate /*
4874*0Sstevel@tonic-gate  * scsa2usb_bulk_timeout:
4875*0Sstevel@tonic-gate  *	ensure that bulk requests do not have infinite timeout values
4876*0Sstevel@tonic-gate  */
4877*0Sstevel@tonic-gate int
4878*0Sstevel@tonic-gate scsa2usb_bulk_timeout(int timeout)
4879*0Sstevel@tonic-gate {
4880*0Sstevel@tonic-gate 	return ((timeout == 0) ? scsa2usb_long_timeout : timeout);
4881*0Sstevel@tonic-gate }
4882*0Sstevel@tonic-gate 
4883*0Sstevel@tonic-gate 
4884*0Sstevel@tonic-gate /*
4885*0Sstevel@tonic-gate  * scsa2usb_clear_ept_stall:
4886*0Sstevel@tonic-gate  *	clear endpoint stall and reset pipes
4887*0Sstevel@tonic-gate  */
4888*0Sstevel@tonic-gate int
4889*0Sstevel@tonic-gate scsa2usb_clear_ept_stall(scsa2usb_state_t *scsa2usbp, uint_t ept_addr,
4890*0Sstevel@tonic-gate     usb_pipe_handle_t ph, char *what)
4891*0Sstevel@tonic-gate {
4892*0Sstevel@tonic-gate 	int rval;
4893*0Sstevel@tonic-gate 	dev_info_t *dip = scsa2usbp->scsa2usb_dip;
4894*0Sstevel@tonic-gate 
4895*0Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
4896*0Sstevel@tonic-gate 	if (!(SCSA2USB_DEVICE_ACCESS_OK(scsa2usbp))) {
4897*0Sstevel@tonic-gate 
4898*0Sstevel@tonic-gate 		return (USB_FAILURE);
4899*0Sstevel@tonic-gate 	}
4900*0Sstevel@tonic-gate 
4901*0Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
4902*0Sstevel@tonic-gate 	rval = usb_clr_feature(dip, USB_DEV_REQ_RCPT_EP, 0, ept_addr,
4903*0Sstevel@tonic-gate 	    USB_FLAGS_SLEEP, NULL, NULL);
4904*0Sstevel@tonic-gate 
4905*0Sstevel@tonic-gate 	usb_pipe_reset(dip, ph, USB_FLAGS_SLEEP, NULL, NULL);
4906*0Sstevel@tonic-gate 
4907*0Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
4908*0Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
4909*0Sstevel@tonic-gate 	    "scsa2usb_clear_ept_stall: on %s: ept = 0x%x rval = %d",
4910*0Sstevel@tonic-gate 	    what, ept_addr, rval);
4911*0Sstevel@tonic-gate 
4912*0Sstevel@tonic-gate 	return (rval);
4913*0Sstevel@tonic-gate }
4914*0Sstevel@tonic-gate 
4915*0Sstevel@tonic-gate 
4916*0Sstevel@tonic-gate /*
4917*0Sstevel@tonic-gate  * scsa2usb_pkt_completion:
4918*0Sstevel@tonic-gate  *	Handle pkt completion.
4919*0Sstevel@tonic-gate  */
4920*0Sstevel@tonic-gate static void
4921*0Sstevel@tonic-gate scsa2usb_pkt_completion(scsa2usb_state_t *scsa2usbp, struct scsi_pkt *pkt)
4922*0Sstevel@tonic-gate {
4923*0Sstevel@tonic-gate 	scsa2usb_cmd_t *cmd = PKT2CMD(pkt);
4924*0Sstevel@tonic-gate 
4925*0Sstevel@tonic-gate 	ASSERT(pkt);
4926*0Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
4927*0Sstevel@tonic-gate 
4928*0Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
4929*0Sstevel@tonic-gate 	    "scsa2usb_pkt_completion:\n\tscsa2usbp = 0x%p "
4930*0Sstevel@tonic-gate 	    "reason=%d, status=%d state=0x%x stats=0x%x resid=0x%lx",
4931*0Sstevel@tonic-gate 	    scsa2usbp, pkt->pkt_reason, *(pkt->pkt_scbp),
4932*0Sstevel@tonic-gate 	    pkt->pkt_state, pkt->pkt_statistics, pkt->pkt_resid);
4933*0Sstevel@tonic-gate 
4934*0Sstevel@tonic-gate 	if (pkt->pkt_reason == CMD_CMPLT) {
4935*0Sstevel@tonic-gate 		pkt->pkt_state |= STATE_GOT_BUS | STATE_GOT_TARGET |
4936*0Sstevel@tonic-gate 					STATE_SENT_CMD | STATE_GOT_STATUS;
4937*0Sstevel@tonic-gate 		if (cmd->cmd_xfercount) {
4938*0Sstevel@tonic-gate 			pkt->pkt_state |= STATE_XFERRED_DATA;
4939*0Sstevel@tonic-gate 		}
4940*0Sstevel@tonic-gate 	} else {
4941*0Sstevel@tonic-gate 		pkt->pkt_state |= STATE_GOT_BUS | STATE_GOT_TARGET |
4942*0Sstevel@tonic-gate 					STATE_SENT_CMD;
4943*0Sstevel@tonic-gate 	}
4944*0Sstevel@tonic-gate 
4945*0Sstevel@tonic-gate 	/*
4946*0Sstevel@tonic-gate 	 * don't zap the current state when in panic as this will
4947*0Sstevel@tonic-gate 	 * make debugging harder
4948*0Sstevel@tonic-gate 	 */
4949*0Sstevel@tonic-gate 	if ((scsa2usbp->scsa2usb_cur_pkt == pkt) && !ddi_in_panic()) {
4950*0Sstevel@tonic-gate 		SCSA2USB_RESET_CUR_PKT(scsa2usbp);
4951*0Sstevel@tonic-gate 
4952*0Sstevel@tonic-gate 		/* save the last command */
4953*0Sstevel@tonic-gate 		bcopy(pkt->pkt_cdbp, scsa2usbp->scsa2usb_last_cmd.cdb,
4954*0Sstevel@tonic-gate 		    sizeof (scsa2usbp->scsa2usb_last_cmd.cdb));
4955*0Sstevel@tonic-gate 
4956*0Sstevel@tonic-gate 		/* reset the scsa2usb_last_cmd.status value */
4957*0Sstevel@tonic-gate 		if ((pkt->pkt_cdbp[0] != SCMD_REQUEST_SENSE) &&
4958*0Sstevel@tonic-gate 		    (pkt->pkt_cdbp[0] != SCMD_INQUIRY)) {
4959*0Sstevel@tonic-gate 			scsa2usbp->scsa2usb_last_cmd.status = 0;
4960*0Sstevel@tonic-gate 		}
4961*0Sstevel@tonic-gate 
4962*0Sstevel@tonic-gate 		/*
4963*0Sstevel@tonic-gate 		 * set pkt state to NONE *before* calling back as the target
4964*0Sstevel@tonic-gate 		 * driver will immediately submit the next packet
4965*0Sstevel@tonic-gate 		 */
4966*0Sstevel@tonic-gate 		scsa2usbp->scsa2usb_pkt_state = SCSA2USB_PKT_NONE;
4967*0Sstevel@tonic-gate 	}
4968*0Sstevel@tonic-gate 
4969*0Sstevel@tonic-gate 	if (pkt->pkt_comp) {
4970*0Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
4971*0Sstevel@tonic-gate 		pkt->pkt_comp(pkt);
4972*0Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
4973*0Sstevel@tonic-gate 
4974*0Sstevel@tonic-gate 	}
4975*0Sstevel@tonic-gate }
4976*0Sstevel@tonic-gate 
4977*0Sstevel@tonic-gate 
4978*0Sstevel@tonic-gate /*
4979*0Sstevel@tonic-gate  * Even handling functions:
4980*0Sstevel@tonic-gate  *
4981*0Sstevel@tonic-gate  * scsa2usb_reconnect_event_cb:
4982*0Sstevel@tonic-gate  *	event handling
4983*0Sstevel@tonic-gate  */
4984*0Sstevel@tonic-gate static int
4985*0Sstevel@tonic-gate scsa2usb_reconnect_event_cb(dev_info_t *dip)
4986*0Sstevel@tonic-gate {
4987*0Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp =
4988*0Sstevel@tonic-gate 	    ddi_get_soft_state(scsa2usb_statep, ddi_get_instance(dip));
4989*0Sstevel@tonic-gate 	dev_info_t	*cdip;
4990*0Sstevel@tonic-gate 	int		circ;
4991*0Sstevel@tonic-gate 	int		rval = USB_SUCCESS;
4992*0Sstevel@tonic-gate 
4993*0Sstevel@tonic-gate 	ASSERT(scsa2usbp != NULL);
4994*0Sstevel@tonic-gate 
4995*0Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
4996*0Sstevel@tonic-gate 	    "scsa2usb_reconnect_event_cb: dip = 0x%p", dip);
4997*0Sstevel@tonic-gate 
4998*0Sstevel@tonic-gate 	scsa2usb_restore_device_state(dip, scsa2usbp);
4999*0Sstevel@tonic-gate 
5000*0Sstevel@tonic-gate 	ndi_devi_enter(dip, &circ);
5001*0Sstevel@tonic-gate 	for (cdip = ddi_get_child(dip); cdip; ) {
5002*0Sstevel@tonic-gate 		dev_info_t *next = ddi_get_next_sibling(cdip);
5003*0Sstevel@tonic-gate 
5004*0Sstevel@tonic-gate 		mutex_enter(&DEVI(cdip)->devi_lock);
5005*0Sstevel@tonic-gate 		DEVI_SET_DEVICE_REINSERTED(cdip);
5006*0Sstevel@tonic-gate 		mutex_exit(&DEVI(cdip)->devi_lock);
5007*0Sstevel@tonic-gate 
5008*0Sstevel@tonic-gate 		cdip = next;
5009*0Sstevel@tonic-gate 	}
5010*0Sstevel@tonic-gate 	ndi_devi_exit(dip, circ);
5011*0Sstevel@tonic-gate 
5012*0Sstevel@tonic-gate 	/* stop suppressing warnings */
5013*0Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
5014*0Sstevel@tonic-gate 	scsa2usbp->scsa2usb_warning_given = B_FALSE;
5015*0Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
5016*0Sstevel@tonic-gate 
5017*0Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_ugen_hdl) {
5018*0Sstevel@tonic-gate 		rval = usb_ugen_reconnect_ev_cb(
5019*0Sstevel@tonic-gate 			scsa2usbp->scsa2usb_ugen_hdl);
5020*0Sstevel@tonic-gate 	}
5021*0Sstevel@tonic-gate 
5022*0Sstevel@tonic-gate 	return (rval);
5023*0Sstevel@tonic-gate }
5024*0Sstevel@tonic-gate 
5025*0Sstevel@tonic-gate 
5026*0Sstevel@tonic-gate /*
5027*0Sstevel@tonic-gate  * scsa2usb_all_waitQs_empty:
5028*0Sstevel@tonic-gate  *	check if all waitQs empty
5029*0Sstevel@tonic-gate  */
5030*0Sstevel@tonic-gate static int
5031*0Sstevel@tonic-gate scsa2usb_all_waitQs_empty(scsa2usb_state_t *scsa2usbp)
5032*0Sstevel@tonic-gate {
5033*0Sstevel@tonic-gate 	uint_t	lun;
5034*0Sstevel@tonic-gate 
5035*0Sstevel@tonic-gate 	for (lun = 0; lun < SCSA2USB_MAX_LUNS; lun++) {
5036*0Sstevel@tonic-gate 		if (usba_list_entry_count(
5037*0Sstevel@tonic-gate 		    &scsa2usbp->scsa2usb_waitQ[lun])) {
5038*0Sstevel@tonic-gate 
5039*0Sstevel@tonic-gate 			return (USB_FAILURE);
5040*0Sstevel@tonic-gate 		}
5041*0Sstevel@tonic-gate 	}
5042*0Sstevel@tonic-gate 
5043*0Sstevel@tonic-gate 	return (USB_SUCCESS);
5044*0Sstevel@tonic-gate }
5045*0Sstevel@tonic-gate 
5046*0Sstevel@tonic-gate 
5047*0Sstevel@tonic-gate /*
5048*0Sstevel@tonic-gate  * scsa2usb_disconnect_event_cb:
5049*0Sstevel@tonic-gate  *	callback for disconnect events
5050*0Sstevel@tonic-gate  */
5051*0Sstevel@tonic-gate static int
5052*0Sstevel@tonic-gate scsa2usb_disconnect_event_cb(dev_info_t *dip)
5053*0Sstevel@tonic-gate {
5054*0Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp =
5055*0Sstevel@tonic-gate 	    ddi_get_soft_state(scsa2usb_statep, ddi_get_instance(dip));
5056*0Sstevel@tonic-gate 	dev_info_t	*cdip;
5057*0Sstevel@tonic-gate 	int		circ, i;
5058*0Sstevel@tonic-gate 	int		rval = USB_SUCCESS;
5059*0Sstevel@tonic-gate 
5060*0Sstevel@tonic-gate 	ASSERT(scsa2usbp != NULL);
5061*0Sstevel@tonic-gate 
5062*0Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
5063*0Sstevel@tonic-gate 	    "scsa2usb_disconnect_event_cb: dip = 0x%p", dip);
5064*0Sstevel@tonic-gate 
5065*0Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
5066*0Sstevel@tonic-gate 	scsa2usbp->scsa2usb_dev_state = USB_DEV_DISCONNECTED;
5067*0Sstevel@tonic-gate 
5068*0Sstevel@tonic-gate 	/*
5069*0Sstevel@tonic-gate 	 * wait till the work thread is done, carry on regardless
5070*0Sstevel@tonic-gate 	 * if not.
5071*0Sstevel@tonic-gate 	 */
5072*0Sstevel@tonic-gate 	for (i = 0; i < SCSA2USB_DRAIN_TIMEOUT; i++) {
5073*0Sstevel@tonic-gate 		if ((scsa2usbp->scsa2usb_work_thread_id == NULL) &&
5074*0Sstevel@tonic-gate 		    (scsa2usbp->scsa2usb_cur_pkt == NULL) &&
5075*0Sstevel@tonic-gate 		    (scsa2usb_all_waitQs_empty(scsa2usbp) ==
5076*0Sstevel@tonic-gate 		    USB_SUCCESS)) {
5077*0Sstevel@tonic-gate 
5078*0Sstevel@tonic-gate 			break;
5079*0Sstevel@tonic-gate 		}
5080*0Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
5081*0Sstevel@tonic-gate 		delay(drv_usectohz(1000000));
5082*0Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
5083*0Sstevel@tonic-gate 	}
5084*0Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
5085*0Sstevel@tonic-gate 
5086*0Sstevel@tonic-gate 	ndi_devi_enter(dip, &circ);
5087*0Sstevel@tonic-gate 	for (cdip = ddi_get_child(dip); cdip; ) {
5088*0Sstevel@tonic-gate 		dev_info_t *next = ddi_get_next_sibling(cdip);
5089*0Sstevel@tonic-gate 
5090*0Sstevel@tonic-gate 		mutex_enter(&DEVI(cdip)->devi_lock);
5091*0Sstevel@tonic-gate 		DEVI_SET_DEVICE_REMOVED(cdip);
5092*0Sstevel@tonic-gate 		mutex_exit(&DEVI(cdip)->devi_lock);
5093*0Sstevel@tonic-gate 
5094*0Sstevel@tonic-gate 		cdip = next;
5095*0Sstevel@tonic-gate 	}
5096*0Sstevel@tonic-gate 	ndi_devi_exit(dip, circ);
5097*0Sstevel@tonic-gate 
5098*0Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_ugen_hdl) {
5099*0Sstevel@tonic-gate 		rval = usb_ugen_disconnect_ev_cb(
5100*0Sstevel@tonic-gate 					scsa2usbp->scsa2usb_ugen_hdl);
5101*0Sstevel@tonic-gate 	}
5102*0Sstevel@tonic-gate 
5103*0Sstevel@tonic-gate 	return (rval);
5104*0Sstevel@tonic-gate }
5105*0Sstevel@tonic-gate 
5106*0Sstevel@tonic-gate 
5107*0Sstevel@tonic-gate /*
5108*0Sstevel@tonic-gate  * PM support
5109*0Sstevel@tonic-gate  *
5110*0Sstevel@tonic-gate  * scsa2usb_create_pm_components:
5111*0Sstevel@tonic-gate  *	create the pm components required for power management
5112*0Sstevel@tonic-gate  *	no mutex is need when calling USBA interfaces
5113*0Sstevel@tonic-gate  */
5114*0Sstevel@tonic-gate static void
5115*0Sstevel@tonic-gate scsa2usb_create_pm_components(dev_info_t *dip, scsa2usb_state_t *scsa2usbp)
5116*0Sstevel@tonic-gate {
5117*0Sstevel@tonic-gate 	scsa2usb_power_t *pm;
5118*0Sstevel@tonic-gate 	uint_t		pwr_states;
5119*0Sstevel@tonic-gate 
5120*0Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
5121*0Sstevel@tonic-gate 
5122*0Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_PM, scsa2usbp->scsa2usb_log_handle,
5123*0Sstevel@tonic-gate 	    "scsa2usb_create_pm_components: dip = 0x%p, scsa2usbp = 0x%p",
5124*0Sstevel@tonic-gate 	    dip, scsa2usbp);
5125*0Sstevel@tonic-gate 
5126*0Sstevel@tonic-gate 	/*
5127*0Sstevel@tonic-gate 	 * determine if this device is on the blacklist
5128*0Sstevel@tonic-gate 	 * or if a conf file entry has disabled PM
5129*0Sstevel@tonic-gate 	 */
5130*0Sstevel@tonic-gate 	if ((scsa2usbp->scsa2usb_attrs & SCSA2USB_ATTRS_PM) == 0) {
5131*0Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_PM, scsa2usbp->scsa2usb_log_handle,
5132*0Sstevel@tonic-gate 		    "device cannot be power managed");
5133*0Sstevel@tonic-gate 
5134*0Sstevel@tonic-gate 		return;
5135*0Sstevel@tonic-gate 	}
5136*0Sstevel@tonic-gate 
5137*0Sstevel@tonic-gate 	/* Allocate the PM state structure */
5138*0Sstevel@tonic-gate 	pm = kmem_zalloc(sizeof (scsa2usb_power_t), KM_SLEEP);
5139*0Sstevel@tonic-gate 
5140*0Sstevel@tonic-gate 	scsa2usbp->scsa2usb_pm = pm;
5141*0Sstevel@tonic-gate 	pm->scsa2usb_current_power = USB_DEV_OS_FULL_PWR;
5142*0Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
5143*0Sstevel@tonic-gate 
5144*0Sstevel@tonic-gate 	if (usb_create_pm_components(dip, &pwr_states) ==
5145*0Sstevel@tonic-gate 	    USB_SUCCESS) {
5146*0Sstevel@tonic-gate 		if (usb_handle_remote_wakeup(dip,
5147*0Sstevel@tonic-gate 		    USB_REMOTE_WAKEUP_ENABLE) == USB_SUCCESS) {
5148*0Sstevel@tonic-gate 			pm->scsa2usb_wakeup_enabled = 1;
5149*0Sstevel@tonic-gate 		}
5150*0Sstevel@tonic-gate 
5151*0Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
5152*0Sstevel@tonic-gate 		pm->scsa2usb_pwr_states = (uint8_t)pwr_states;
5153*0Sstevel@tonic-gate 		scsa2usb_pm_busy_component(scsa2usbp);
5154*0Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
5155*0Sstevel@tonic-gate 
5156*0Sstevel@tonic-gate 		(void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
5157*0Sstevel@tonic-gate 	}
5158*0Sstevel@tonic-gate 
5159*0Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
5160*0Sstevel@tonic-gate }
5161*0Sstevel@tonic-gate 
5162*0Sstevel@tonic-gate 
5163*0Sstevel@tonic-gate /*
5164*0Sstevel@tonic-gate  * scsa2usb_raise_power:
5165*0Sstevel@tonic-gate  *	check if the device is using full power or not
5166*0Sstevel@tonic-gate  */
5167*0Sstevel@tonic-gate static void
5168*0Sstevel@tonic-gate scsa2usb_raise_power(scsa2usb_state_t *scsa2usbp)
5169*0Sstevel@tonic-gate {
5170*0Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_PM, scsa2usbp->scsa2usb_log_handle,
5171*0Sstevel@tonic-gate 	    "scsa2usb_raise_power:");
5172*0Sstevel@tonic-gate 
5173*0Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
5174*0Sstevel@tonic-gate 
5175*0Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_pm) {
5176*0Sstevel@tonic-gate 		scsa2usb_pm_busy_component(scsa2usbp);
5177*0Sstevel@tonic-gate 		if (scsa2usbp->scsa2usb_pm->scsa2usb_current_power ==
5178*0Sstevel@tonic-gate 		    USB_DEV_OS_PWR_OFF) {
5179*0Sstevel@tonic-gate 			mutex_exit(&scsa2usbp->scsa2usb_mutex);
5180*0Sstevel@tonic-gate 			(void) pm_raise_power(scsa2usbp->scsa2usb_dip,
5181*0Sstevel@tonic-gate 			    0, USB_DEV_OS_FULL_PWR);
5182*0Sstevel@tonic-gate 			mutex_enter(&scsa2usbp->scsa2usb_mutex);
5183*0Sstevel@tonic-gate 		}
5184*0Sstevel@tonic-gate 	}
5185*0Sstevel@tonic-gate }
5186*0Sstevel@tonic-gate 
5187*0Sstevel@tonic-gate 
5188*0Sstevel@tonic-gate /*
5189*0Sstevel@tonic-gate  * functions to handle power transition for OS levels 0 -> 3
5190*0Sstevel@tonic-gate  */
5191*0Sstevel@tonic-gate static int
5192*0Sstevel@tonic-gate scsa2usb_pwrlvl0(scsa2usb_state_t *scsa2usbp)
5193*0Sstevel@tonic-gate {
5194*0Sstevel@tonic-gate 	int	rval;
5195*0Sstevel@tonic-gate 
5196*0Sstevel@tonic-gate 	switch (scsa2usbp->scsa2usb_dev_state) {
5197*0Sstevel@tonic-gate 	case USB_DEV_ONLINE:
5198*0Sstevel@tonic-gate 		/* Deny the powerdown request if the device is busy */
5199*0Sstevel@tonic-gate 		if (scsa2usbp->scsa2usb_pm->scsa2usb_pm_busy != 0) {
5200*0Sstevel@tonic-gate 
5201*0Sstevel@tonic-gate 			return (USB_FAILURE);
5202*0Sstevel@tonic-gate 		}
5203*0Sstevel@tonic-gate 
5204*0Sstevel@tonic-gate 		/*
5205*0Sstevel@tonic-gate 		 * stop polling on interrupt pipe
5206*0Sstevel@tonic-gate 		 */
5207*0Sstevel@tonic-gate 		scsa2usb_cbi_stop_intr_polling(scsa2usbp);
5208*0Sstevel@tonic-gate 
5209*0Sstevel@tonic-gate 		/* Issue USB D3 command to the device here */
5210*0Sstevel@tonic-gate 		rval = usb_set_device_pwrlvl3(scsa2usbp->scsa2usb_dip);
5211*0Sstevel@tonic-gate 		ASSERT(rval == USB_SUCCESS);
5212*0Sstevel@tonic-gate 
5213*0Sstevel@tonic-gate 		scsa2usbp->scsa2usb_dev_state = USB_DEV_PWRED_DOWN;
5214*0Sstevel@tonic-gate 
5215*0Sstevel@tonic-gate 		/* FALLTHRU */
5216*0Sstevel@tonic-gate 	case USB_DEV_DISCONNECTED:
5217*0Sstevel@tonic-gate 	case USB_DEV_SUSPENDED:
5218*0Sstevel@tonic-gate 	case USB_DEV_PWRED_DOWN:
5219*0Sstevel@tonic-gate 	default:
5220*0Sstevel@tonic-gate 		scsa2usbp->scsa2usb_pm->scsa2usb_current_power =
5221*0Sstevel@tonic-gate 						USB_DEV_OS_PWR_OFF;
5222*0Sstevel@tonic-gate 
5223*0Sstevel@tonic-gate 		return (USB_SUCCESS);
5224*0Sstevel@tonic-gate 	}
5225*0Sstevel@tonic-gate }
5226*0Sstevel@tonic-gate 
5227*0Sstevel@tonic-gate 
5228*0Sstevel@tonic-gate static int
5229*0Sstevel@tonic-gate scsa2usb_pwrlvl1(scsa2usb_state_t *scsa2usbp)
5230*0Sstevel@tonic-gate {
5231*0Sstevel@tonic-gate 	int	rval;
5232*0Sstevel@tonic-gate 
5233*0Sstevel@tonic-gate 	/* Issue USB D2 command to the device here */
5234*0Sstevel@tonic-gate 	rval = usb_set_device_pwrlvl2(scsa2usbp->scsa2usb_dip);
5235*0Sstevel@tonic-gate 	ASSERT(rval == USB_SUCCESS);
5236*0Sstevel@tonic-gate 
5237*0Sstevel@tonic-gate 	return (DDI_FAILURE);
5238*0Sstevel@tonic-gate }
5239*0Sstevel@tonic-gate 
5240*0Sstevel@tonic-gate 
5241*0Sstevel@tonic-gate static int
5242*0Sstevel@tonic-gate scsa2usb_pwrlvl2(scsa2usb_state_t *scsa2usbp)
5243*0Sstevel@tonic-gate {
5244*0Sstevel@tonic-gate 	int	rval;
5245*0Sstevel@tonic-gate 
5246*0Sstevel@tonic-gate 	/* Issue USB D1 command to the device here */
5247*0Sstevel@tonic-gate 	rval = usb_set_device_pwrlvl1(scsa2usbp->scsa2usb_dip);
5248*0Sstevel@tonic-gate 	ASSERT(rval == USB_SUCCESS);
5249*0Sstevel@tonic-gate 
5250*0Sstevel@tonic-gate 	return (DDI_FAILURE);
5251*0Sstevel@tonic-gate }
5252*0Sstevel@tonic-gate 
5253*0Sstevel@tonic-gate 
5254*0Sstevel@tonic-gate static int
5255*0Sstevel@tonic-gate scsa2usb_pwrlvl3(scsa2usb_state_t *scsa2usbp)
5256*0Sstevel@tonic-gate {
5257*0Sstevel@tonic-gate 	int	rval;
5258*0Sstevel@tonic-gate 
5259*0Sstevel@tonic-gate 	/*
5260*0Sstevel@tonic-gate 	 * PM framework tries to put us in full power
5261*0Sstevel@tonic-gate 	 * during system shutdown. If we are disconnected
5262*0Sstevel@tonic-gate 	 * return success anyways
5263*0Sstevel@tonic-gate 	 */
5264*0Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_dev_state != USB_DEV_DISCONNECTED) {
5265*0Sstevel@tonic-gate 		/* Issue USB D0 command to the device here */
5266*0Sstevel@tonic-gate 		rval = usb_set_device_pwrlvl0(scsa2usbp->scsa2usb_dip);
5267*0Sstevel@tonic-gate 		ASSERT(rval == USB_SUCCESS);
5268*0Sstevel@tonic-gate 
5269*0Sstevel@tonic-gate 		scsa2usbp->scsa2usb_dev_state = USB_DEV_ONLINE;
5270*0Sstevel@tonic-gate 	}
5271*0Sstevel@tonic-gate 	scsa2usbp->scsa2usb_pm->scsa2usb_current_power = USB_DEV_OS_FULL_PWR;
5272*0Sstevel@tonic-gate 
5273*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
5274*0Sstevel@tonic-gate }
5275*0Sstevel@tonic-gate 
5276*0Sstevel@tonic-gate 
5277*0Sstevel@tonic-gate /*
5278*0Sstevel@tonic-gate  * scsa2usb_power:
5279*0Sstevel@tonic-gate  *	power entry point
5280*0Sstevel@tonic-gate  */
5281*0Sstevel@tonic-gate /* ARGSUSED */
5282*0Sstevel@tonic-gate static int
5283*0Sstevel@tonic-gate scsa2usb_power(dev_info_t *dip, int comp, int level)
5284*0Sstevel@tonic-gate {
5285*0Sstevel@tonic-gate 	scsa2usb_state_t	*scsa2usbp;
5286*0Sstevel@tonic-gate 	scsa2usb_power_t	*pm;
5287*0Sstevel@tonic-gate 	int			rval = DDI_FAILURE;
5288*0Sstevel@tonic-gate 
5289*0Sstevel@tonic-gate 	scsa2usbp = ddi_get_soft_state(scsa2usb_statep, ddi_get_instance(dip));
5290*0Sstevel@tonic-gate 
5291*0Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_PM, scsa2usbp->scsa2usb_log_handle,
5292*0Sstevel@tonic-gate 	    "scsa2usb_power: Begin scsa2usbp (%p): level = %d",
5293*0Sstevel@tonic-gate 	    scsa2usbp, level);
5294*0Sstevel@tonic-gate 
5295*0Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
5296*0Sstevel@tonic-gate 	if (SCSA2USB_BUSY(scsa2usbp)) {
5297*0Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_PM, scsa2usbp->scsa2usb_log_handle,
5298*0Sstevel@tonic-gate 		    "scsa2usb_power: busy");
5299*0Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
5300*0Sstevel@tonic-gate 
5301*0Sstevel@tonic-gate 		return (rval);
5302*0Sstevel@tonic-gate 	}
5303*0Sstevel@tonic-gate 
5304*0Sstevel@tonic-gate 	pm = scsa2usbp->scsa2usb_pm;
5305*0Sstevel@tonic-gate 	if (pm == NULL) {
5306*0Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_PM, scsa2usbp->scsa2usb_log_handle,
5307*0Sstevel@tonic-gate 		    "scsa2usb_power: pm NULL");
5308*0Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
5309*0Sstevel@tonic-gate 
5310*0Sstevel@tonic-gate 		return (rval);
5311*0Sstevel@tonic-gate 	}
5312*0Sstevel@tonic-gate 
5313*0Sstevel@tonic-gate 	/* check if we are transitioning to a legal power level */
5314*0Sstevel@tonic-gate 	if (USB_DEV_PWRSTATE_OK(pm->scsa2usb_pwr_states, level)) {
5315*0Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_PM, scsa2usbp->scsa2usb_log_handle,
5316*0Sstevel@tonic-gate 		    "scsa2usb_power: illegal power level = %d "
5317*0Sstevel@tonic-gate 		    "pwr_states: %x", level, pm->scsa2usb_pwr_states);
5318*0Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
5319*0Sstevel@tonic-gate 
5320*0Sstevel@tonic-gate 		return (rval);
5321*0Sstevel@tonic-gate 	}
5322*0Sstevel@tonic-gate 
5323*0Sstevel@tonic-gate 	switch (level) {
5324*0Sstevel@tonic-gate 	case USB_DEV_OS_PWR_OFF :
5325*0Sstevel@tonic-gate 		rval = scsa2usb_pwrlvl0(scsa2usbp);
5326*0Sstevel@tonic-gate 		break;
5327*0Sstevel@tonic-gate 	case USB_DEV_OS_PWR_1 :
5328*0Sstevel@tonic-gate 		rval = scsa2usb_pwrlvl1(scsa2usbp);
5329*0Sstevel@tonic-gate 		break;
5330*0Sstevel@tonic-gate 	case USB_DEV_OS_PWR_2 :
5331*0Sstevel@tonic-gate 		rval = scsa2usb_pwrlvl2(scsa2usbp);
5332*0Sstevel@tonic-gate 		break;
5333*0Sstevel@tonic-gate 	case USB_DEV_OS_FULL_PWR :
5334*0Sstevel@tonic-gate 		rval = scsa2usb_pwrlvl3(scsa2usbp);
5335*0Sstevel@tonic-gate 		break;
5336*0Sstevel@tonic-gate 	}
5337*0Sstevel@tonic-gate 
5338*0Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
5339*0Sstevel@tonic-gate 
5340*0Sstevel@tonic-gate 	return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
5341*0Sstevel@tonic-gate }
5342*0Sstevel@tonic-gate 
5343*0Sstevel@tonic-gate 
5344*0Sstevel@tonic-gate static void
5345*0Sstevel@tonic-gate scsa2usb_pm_busy_component(scsa2usb_state_t *scsa2usb_statep)
5346*0Sstevel@tonic-gate {
5347*0Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usb_statep->scsa2usb_mutex));
5348*0Sstevel@tonic-gate 
5349*0Sstevel@tonic-gate 	scsa2usb_statep->scsa2usb_pm->scsa2usb_pm_busy++;
5350*0Sstevel@tonic-gate 	mutex_exit(&scsa2usb_statep->scsa2usb_mutex);
5351*0Sstevel@tonic-gate 
5352*0Sstevel@tonic-gate 	if (pm_busy_component(scsa2usb_statep->scsa2usb_dip, 0) !=
5353*0Sstevel@tonic-gate 	    DDI_SUCCESS) {
5354*0Sstevel@tonic-gate 		mutex_enter(&scsa2usb_statep->scsa2usb_mutex);
5355*0Sstevel@tonic-gate 		ASSERT(scsa2usb_statep->scsa2usb_pm->scsa2usb_pm_busy > 0);
5356*0Sstevel@tonic-gate 		scsa2usb_statep->scsa2usb_pm->scsa2usb_pm_busy--;
5357*0Sstevel@tonic-gate 		mutex_exit(&scsa2usb_statep->scsa2usb_mutex);
5358*0Sstevel@tonic-gate 	}
5359*0Sstevel@tonic-gate 
5360*0Sstevel@tonic-gate 	mutex_enter(&scsa2usb_statep->scsa2usb_mutex);
5361*0Sstevel@tonic-gate 
5362*0Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_PM, scsa2usb_statep->scsa2usb_log_handle,
5363*0Sstevel@tonic-gate 	    "scsa2usb_pm_busy : %d",
5364*0Sstevel@tonic-gate 	    scsa2usb_statep->scsa2usb_pm->scsa2usb_pm_busy);
5365*0Sstevel@tonic-gate }
5366*0Sstevel@tonic-gate 
5367*0Sstevel@tonic-gate 
5368*0Sstevel@tonic-gate /*
5369*0Sstevel@tonic-gate  * scsa2usb_pm_idle_component:
5370*0Sstevel@tonic-gate  *	idles the device
5371*0Sstevel@tonic-gate  */
5372*0Sstevel@tonic-gate static void
5373*0Sstevel@tonic-gate scsa2usb_pm_idle_component(scsa2usb_state_t *scsa2usbp)
5374*0Sstevel@tonic-gate {
5375*0Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
5376*0Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_pm) {
5377*0Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
5378*0Sstevel@tonic-gate 		if (pm_idle_component(scsa2usbp->scsa2usb_dip, 0) ==
5379*0Sstevel@tonic-gate 		    DDI_SUCCESS) {
5380*0Sstevel@tonic-gate 			mutex_enter(&scsa2usbp->scsa2usb_mutex);
5381*0Sstevel@tonic-gate 			ASSERT(scsa2usbp->scsa2usb_pm->scsa2usb_pm_busy > 0);
5382*0Sstevel@tonic-gate 			scsa2usbp->scsa2usb_pm->scsa2usb_pm_busy--;
5383*0Sstevel@tonic-gate 			mutex_exit(&scsa2usbp->scsa2usb_mutex);
5384*0Sstevel@tonic-gate 		}
5385*0Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
5386*0Sstevel@tonic-gate 		USB_DPRINTF_L4(DPRINT_MASK_PM,
5387*0Sstevel@tonic-gate 		    scsa2usbp->scsa2usb_log_handle,
5388*0Sstevel@tonic-gate 		    "scsa2usb_pm_busy : %d",
5389*0Sstevel@tonic-gate 		    scsa2usbp->scsa2usb_pm->scsa2usb_pm_busy);
5390*0Sstevel@tonic-gate 	}
5391*0Sstevel@tonic-gate }
5392*0Sstevel@tonic-gate 
5393*0Sstevel@tonic-gate 
5394*0Sstevel@tonic-gate #ifdef	DEBUG
5395*0Sstevel@tonic-gate /*
5396*0Sstevel@tonic-gate  * scsa2usb_print_cdb:
5397*0Sstevel@tonic-gate  *	prints CDB
5398*0Sstevel@tonic-gate  */
5399*0Sstevel@tonic-gate void
5400*0Sstevel@tonic-gate scsa2usb_print_cdb(scsa2usb_state_t *scsa2usbp, scsa2usb_cmd_t *cmd)
5401*0Sstevel@tonic-gate {
5402*0Sstevel@tonic-gate 	uchar_t *c = (uchar_t *)&cmd->cmd_cdb;
5403*0Sstevel@tonic-gate 
5404*0Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
5405*0Sstevel@tonic-gate 	    "cmd = 0x%p opcode=%s "
5406*0Sstevel@tonic-gate 	    "cdb: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x",
5407*0Sstevel@tonic-gate 	    cmd, scsi_cname(cmd->cmd_cdb[SCSA2USB_OPCODE], scsa2usb_cmds),
5408*0Sstevel@tonic-gate 	    c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7], c[8],
5409*0Sstevel@tonic-gate 	    c[9], c[10], c[11], c[12], c[13], c[14], c[15]);
5410*0Sstevel@tonic-gate }
5411*0Sstevel@tonic-gate #endif	/* DEBUG */
5412*0Sstevel@tonic-gate 
5413*0Sstevel@tonic-gate 
5414*0Sstevel@tonic-gate #ifdef	SCSA2USB_BULK_ONLY_TEST
5415*0Sstevel@tonic-gate /*
5416*0Sstevel@tonic-gate  * scsa2usb_test_mblk:
5417*0Sstevel@tonic-gate  *	This function sends a dummy data mblk_t to simulate
5418*0Sstevel@tonic-gate  *	the following test cases: 5 and 11.
5419*0Sstevel@tonic-gate  */
5420*0Sstevel@tonic-gate static void
5421*0Sstevel@tonic-gate scsa2usb_test_mblk(scsa2usb_state_t *scsa2usbp, boolean_t large)
5422*0Sstevel@tonic-gate {
5423*0Sstevel@tonic-gate 	int			i, rval;
5424*0Sstevel@tonic-gate 	size_t			len;
5425*0Sstevel@tonic-gate 	usb_flags_t		flags = USB_FLAGS_SLEEP;
5426*0Sstevel@tonic-gate 	usb_bulk_req_t		*req;
5427*0Sstevel@tonic-gate 
5428*0Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
5429*0Sstevel@tonic-gate 
5430*0Sstevel@tonic-gate 	/* should we create a larger mblk? */
5431*0Sstevel@tonic-gate 	len = (large == B_TRUE) ? DEV_BSIZE : USB_BULK_CBWCMD_LEN;
5432*0Sstevel@tonic-gate 
5433*0Sstevel@tonic-gate 	req = scsa2usb_init_bulk_req(scsa2usbp, len,
5434*0Sstevel@tonic-gate 		SCSA2USB_BULK_PIPE_TIMEOUT, 0, flags);
5435*0Sstevel@tonic-gate 
5436*0Sstevel@tonic-gate 	/* fill up the data mblk */
5437*0Sstevel@tonic-gate 	for (i = 0; i < len; i++) {
5438*0Sstevel@tonic-gate 		*req->bulk_data->b_wptr++ = (uchar_t)i;
5439*0Sstevel@tonic-gate 	}
5440*0Sstevel@tonic-gate 
5441*0Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
5442*0Sstevel@tonic-gate 	ASSERT(req->bulk_timeout);
5443*0Sstevel@tonic-gate 	rval = usb_pipe_bulk_xfer(scsa2usbp->scsa2usb_bulkout_pipe, req, flags);
5444*0Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
5445*0Sstevel@tonic-gate 
5446*0Sstevel@tonic-gate 	USB_DPRINTF_L1(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
5447*0Sstevel@tonic-gate 	    "scsa2usb_test_mblk: Sent Data Out rval = 0x%x", rval);
5448*0Sstevel@tonic-gate 
5449*0Sstevel@tonic-gate 	usb_free_bulk_req(req);
5450*0Sstevel@tonic-gate }
5451*0Sstevel@tonic-gate #endif	/* SCSA2USB_BULK_ONLY_TEST */
5452