xref: /onnv-gate/usr/src/uts/common/io/usb/scsa2usb/scsa2usb.c (revision 11282:cf14d34d606b)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51984Scg149915  * Common Development and Distribution License (the "License").
61984Scg149915  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
229106SSrivijitha.Dugganapalli@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate 
270Sstevel@tonic-gate /*
280Sstevel@tonic-gate  * scsa2usb bridge nexus driver:
290Sstevel@tonic-gate  *
300Sstevel@tonic-gate  * This driver supports the following wire transports:
310Sstevel@tonic-gate  * a. Bulk Only transport (see usb_ms_bulkonly.c)
320Sstevel@tonic-gate  * b. CB transport (see usb_ms_cbi.c)
330Sstevel@tonic-gate  * c. CBI transport with interrupt status completion (see usb_ms_cbi.c)
340Sstevel@tonic-gate  *
350Sstevel@tonic-gate  * It handles the following command sets:
360Sstevel@tonic-gate  * a. SCSI
370Sstevel@tonic-gate  * b. ATAPI command set (subset of SCSI command set)
380Sstevel@tonic-gate  * c. UFI command set (
390Sstevel@tonic-gate  *	http://www.usb.org/developers/devclass_docs/usbmass-ufi10.pdf)
400Sstevel@tonic-gate  *
410Sstevel@tonic-gate  * For details on USB Mass Storage Class overview:
420Sstevel@tonic-gate  *	http://www.usb.org/developers/devclass_docs/usbmassover_11.pdf
430Sstevel@tonic-gate  */
440Sstevel@tonic-gate #if defined(lint) && !defined(DEBUG)
450Sstevel@tonic-gate #define	DEBUG	1
460Sstevel@tonic-gate #endif
470Sstevel@tonic-gate 
480Sstevel@tonic-gate #include <sys/usb/usba/usbai_version.h>
490Sstevel@tonic-gate #include <sys/scsi/scsi.h>
500Sstevel@tonic-gate #include <sys/cdio.h>
510Sstevel@tonic-gate #include <sys/sunndi.h>
520Sstevel@tonic-gate #include <sys/esunddi.h>
530Sstevel@tonic-gate #include <sys/callb.h>
540Sstevel@tonic-gate #include <sys/kobj.h>
550Sstevel@tonic-gate #include <sys/kobj_lex.h>
560Sstevel@tonic-gate #include <sys/strsubr.h>
577492SZhigang.Lu@Sun.COM #include <sys/strsun.h>
580Sstevel@tonic-gate #include <sys/sysmacros.h>
590Sstevel@tonic-gate 
600Sstevel@tonic-gate #include <sys/usb/usba.h>
610Sstevel@tonic-gate #include <sys/usb/usba/usba_ugen.h>
620Sstevel@tonic-gate 
630Sstevel@tonic-gate #include <sys/usb/usba/usba_private.h>
640Sstevel@tonic-gate #include <sys/usb/clients/mass_storage/usb_bulkonly.h>
650Sstevel@tonic-gate #include <sys/usb/scsa2usb/scsa2usb.h>
660Sstevel@tonic-gate 
670Sstevel@tonic-gate /*
680Sstevel@tonic-gate  * Function Prototypes
690Sstevel@tonic-gate  */
700Sstevel@tonic-gate static int	scsa2usb_attach(dev_info_t *, ddi_attach_cmd_t);
710Sstevel@tonic-gate static int	scsa2usb_info(dev_info_t *, ddi_info_cmd_t, void *,
720Sstevel@tonic-gate 						void **);
730Sstevel@tonic-gate static int	scsa2usb_detach(dev_info_t *, ddi_detach_cmd_t);
740Sstevel@tonic-gate static int	scsa2usb_cleanup(dev_info_t *, scsa2usb_state_t *);
750Sstevel@tonic-gate static void	scsa2usb_validate_attrs(scsa2usb_state_t *);
760Sstevel@tonic-gate static void	scsa2usb_create_luns(scsa2usb_state_t *);
770Sstevel@tonic-gate static int	scsa2usb_is_usb(dev_info_t *);
788003SVitezslav.Batrla@Sun.COM static void	scsa2usb_fake_inquiry(scsa2usb_state_t *,
798003SVitezslav.Batrla@Sun.COM 		    struct scsi_inquiry *);
800Sstevel@tonic-gate static void	scsa2usb_do_inquiry(scsa2usb_state_t *,
810Sstevel@tonic-gate 						uint_t, uint_t);
822506Ssl147100 static int	scsa2usb_do_tur(scsa2usb_state_t *, struct scsi_address *);
830Sstevel@tonic-gate 
840Sstevel@tonic-gate /* override property handling */
850Sstevel@tonic-gate static void	scsa2usb_override(scsa2usb_state_t *);
860Sstevel@tonic-gate static int	scsa2usb_parse_input_str(char *, scsa2usb_ov_t *,
870Sstevel@tonic-gate 		    scsa2usb_state_t *);
880Sstevel@tonic-gate static void	scsa2usb_override_error(char *, scsa2usb_state_t *);
890Sstevel@tonic-gate static char	*scsa2usb_strtok_r(char *, char *, char **);
900Sstevel@tonic-gate 
910Sstevel@tonic-gate 
920Sstevel@tonic-gate /* PANIC callback handling */
930Sstevel@tonic-gate static void	scsa2usb_panic_callb_init(scsa2usb_state_t *);
940Sstevel@tonic-gate static void	scsa2usb_panic_callb_fini(scsa2usb_state_t *);
950Sstevel@tonic-gate static boolean_t scsa2usb_panic_callb(void *, int);
960Sstevel@tonic-gate 
970Sstevel@tonic-gate /* SCSA support */
980Sstevel@tonic-gate static int	scsa2usb_scsi_tgt_probe(struct scsi_device *, int (*)(void));
990Sstevel@tonic-gate static int	scsa2usb_scsi_tgt_init(dev_info_t *, dev_info_t *,
1000Sstevel@tonic-gate 		    scsi_hba_tran_t *, struct scsi_device *);
1010Sstevel@tonic-gate static void	scsa2usb_scsi_tgt_free(dev_info_t *, dev_info_t *,
1020Sstevel@tonic-gate 		    scsi_hba_tran_t *, struct scsi_device *);
1030Sstevel@tonic-gate static struct	scsi_pkt *scsa2usb_scsi_init_pkt(struct scsi_address *,
1040Sstevel@tonic-gate 		    struct scsi_pkt *, struct buf *, int, int,
1050Sstevel@tonic-gate 		    int, int, int (*)(), caddr_t);
1060Sstevel@tonic-gate static void	scsa2usb_scsi_destroy_pkt(struct scsi_address *,
1070Sstevel@tonic-gate 		    struct scsi_pkt *);
1080Sstevel@tonic-gate static int	scsa2usb_scsi_start(struct scsi_address *, struct scsi_pkt *);
1090Sstevel@tonic-gate static int	scsa2usb_scsi_abort(struct scsi_address *, struct scsi_pkt *);
1100Sstevel@tonic-gate static int	scsa2usb_scsi_reset(struct scsi_address *, int);
1110Sstevel@tonic-gate static int	scsa2usb_scsi_getcap(struct scsi_address *, char *, int);
1120Sstevel@tonic-gate static int	scsa2usb_scsi_setcap(struct scsi_address *, char *, int, int);
1130Sstevel@tonic-gate static int	scsa2usb_scsi_bus_config(dev_info_t *, uint_t,
1140Sstevel@tonic-gate 		    ddi_bus_config_op_t, void *, dev_info_t **);
1150Sstevel@tonic-gate static int	scsa2usb_scsi_bus_unconfig(dev_info_t *, uint_t,
1160Sstevel@tonic-gate 		    ddi_bus_config_op_t, void *);
1170Sstevel@tonic-gate 
1180Sstevel@tonic-gate /* functions for command and transport support */
1190Sstevel@tonic-gate static void	scsa2usb_prepare_pkt(scsa2usb_state_t *, struct scsi_pkt *);
1200Sstevel@tonic-gate static int	scsa2usb_cmd_transport(scsa2usb_state_t *, scsa2usb_cmd_t *);
1210Sstevel@tonic-gate static int	scsa2usb_check_bulkonly_blacklist_attrs(scsa2usb_state_t *,
1220Sstevel@tonic-gate 		    scsa2usb_cmd_t *, uchar_t);
1230Sstevel@tonic-gate static int	scsa2usb_check_ufi_blacklist_attrs(scsa2usb_state_t *, uchar_t,
1240Sstevel@tonic-gate 		    scsa2usb_cmd_t *);
1250Sstevel@tonic-gate static int	scsa2usb_handle_scsi_cmd_sub_class(scsa2usb_state_t *,
1260Sstevel@tonic-gate 		    scsa2usb_cmd_t *, struct scsi_pkt *);
1270Sstevel@tonic-gate static int	scsa2usb_handle_ufi_subclass_cmd(scsa2usb_state_t *,
1280Sstevel@tonic-gate 		    scsa2usb_cmd_t *, struct scsi_pkt *);
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate /* waitQ handling */
1310Sstevel@tonic-gate static void	scsa2usb_work_thread(void *);
1320Sstevel@tonic-gate static void	scsa2usb_transport_request(scsa2usb_state_t *, uint_t);
1330Sstevel@tonic-gate static void	scsa2usb_flush_waitQ(scsa2usb_state_t *, uint_t, uchar_t);
1340Sstevel@tonic-gate static int	scsa2usb_all_waitQs_empty(scsa2usb_state_t *);
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate /* auto request sense handling */
1370Sstevel@tonic-gate static int	scsa2usb_create_arq_pkt(scsa2usb_state_t *,
1380Sstevel@tonic-gate 		    struct scsi_address *);
1390Sstevel@tonic-gate static void	scsa2usb_delete_arq_pkt(scsa2usb_state_t *);
1400Sstevel@tonic-gate static void	scsa2usb_complete_arq_pkt(scsa2usb_state_t *, struct scsi_pkt *,
1410Sstevel@tonic-gate 		    scsa2usb_cmd_t *, struct buf *);
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate /* utility functions for any transport */
1440Sstevel@tonic-gate static int	scsa2usb_open_usb_pipes(scsa2usb_state_t *);
1450Sstevel@tonic-gate void		scsa2usb_close_usb_pipes(scsa2usb_state_t *);
1460Sstevel@tonic-gate 
1470Sstevel@tonic-gate static void	scsa2usb_fill_up_cdb_len(scsa2usb_cmd_t *, int);
1480Sstevel@tonic-gate static void	scsa2usb_fill_up_cdb_lba(scsa2usb_cmd_t *, int);
1490Sstevel@tonic-gate static void	scsa2usb_fill_up_ReadCD_cdb_len(scsa2usb_cmd_t *, int, int);
1500Sstevel@tonic-gate static void	scsa2usb_fill_up_12byte_cdb_len(scsa2usb_cmd_t *, int, int);
1510Sstevel@tonic-gate static int	scsa2usb_read_cd_blk_size(uchar_t);
1520Sstevel@tonic-gate int		scsa2usb_rw_transport(scsa2usb_state_t *, struct scsi_pkt *);
1530Sstevel@tonic-gate void		scsa2usb_setup_next_xfer(scsa2usb_state_t *, scsa2usb_cmd_t *);
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate static mblk_t	*scsa2usb_bp_to_mblk(scsa2usb_state_t *);
1560Sstevel@tonic-gate int		scsa2usb_handle_data_start(scsa2usb_state_t *,
1570Sstevel@tonic-gate 		    scsa2usb_cmd_t *, usb_bulk_req_t *);
1580Sstevel@tonic-gate void		scsa2usb_handle_data_done(scsa2usb_state_t *,
1590Sstevel@tonic-gate 		    scsa2usb_cmd_t *cmd, usb_bulk_req_t *);
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate usb_bulk_req_t *scsa2usb_init_bulk_req(scsa2usb_state_t *,
1620Sstevel@tonic-gate 			    size_t, uint_t, usb_req_attrs_t, usb_flags_t);
1630Sstevel@tonic-gate int		scsa2usb_bulk_timeout(int);
1640Sstevel@tonic-gate int		scsa2usb_clear_ept_stall(scsa2usb_state_t *, uint_t,
1650Sstevel@tonic-gate 		    usb_pipe_handle_t, char *);
1660Sstevel@tonic-gate static void	scsa2usb_pkt_completion(scsa2usb_state_t *, struct scsi_pkt *);
1670Sstevel@tonic-gate 
1680Sstevel@tonic-gate /* event handling */
1690Sstevel@tonic-gate static int	scsa2usb_reconnect_event_cb(dev_info_t *);
1700Sstevel@tonic-gate static int	scsa2usb_disconnect_event_cb(dev_info_t *);
1710Sstevel@tonic-gate static int	scsa2usb_cpr_suspend(dev_info_t *);
1720Sstevel@tonic-gate static void	scsa2usb_cpr_resume(dev_info_t *);
1730Sstevel@tonic-gate static void	scsa2usb_restore_device_state(dev_info_t *, scsa2usb_state_t *);
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate /* PM handling */
1760Sstevel@tonic-gate static void	scsa2usb_create_pm_components(dev_info_t *, scsa2usb_state_t *);
1770Sstevel@tonic-gate static void	scsa2usb_raise_power(scsa2usb_state_t *);
1780Sstevel@tonic-gate static int	scsa2usb_pwrlvl0(scsa2usb_state_t *);
1790Sstevel@tonic-gate static int	scsa2usb_pwrlvl1(scsa2usb_state_t *);
1800Sstevel@tonic-gate static int	scsa2usb_pwrlvl2(scsa2usb_state_t *);
1810Sstevel@tonic-gate static int	scsa2usb_pwrlvl3(scsa2usb_state_t *);
1820Sstevel@tonic-gate static int	scsa2usb_power(dev_info_t *, int comp, int level);
1830Sstevel@tonic-gate static void	scsa2usb_pm_busy_component(scsa2usb_state_t *);
1840Sstevel@tonic-gate static void	scsa2usb_pm_idle_component(scsa2usb_state_t *);
1850Sstevel@tonic-gate 
1860Sstevel@tonic-gate /* external functions for Bulk only (BO) support */
1870Sstevel@tonic-gate extern int	scsa2usb_bulk_only_transport(scsa2usb_state_t *,
1880Sstevel@tonic-gate 		    scsa2usb_cmd_t *);
1890Sstevel@tonic-gate extern int	scsa2usb_bulk_only_get_max_lun(scsa2usb_state_t *);
1900Sstevel@tonic-gate 
1910Sstevel@tonic-gate /* external functions for CB/CBI support */
1920Sstevel@tonic-gate extern int	scsa2usb_cbi_transport(scsa2usb_state_t *, scsa2usb_cmd_t *);
1930Sstevel@tonic-gate extern void	scsa2usb_cbi_stop_intr_polling(scsa2usb_state_t *);
1940Sstevel@tonic-gate 
1950Sstevel@tonic-gate 
1960Sstevel@tonic-gate /* cmd decoding */
1970Sstevel@tonic-gate static char *scsa2usb_cmds[] = {
1980Sstevel@tonic-gate 	"\000tur",
1990Sstevel@tonic-gate 	"\001rezero",
2000Sstevel@tonic-gate 	"\003rqsense",
2010Sstevel@tonic-gate 	"\004format",
2020Sstevel@tonic-gate 	"\014cartprot",
2030Sstevel@tonic-gate 	"\022inquiry",
2040Sstevel@tonic-gate 	"\026tranlba",
2050Sstevel@tonic-gate 	"\030fmtverify",
2060Sstevel@tonic-gate 	"\032modesense",
2070Sstevel@tonic-gate 	"\033start",
2080Sstevel@tonic-gate 	"\035snddiag",
2090Sstevel@tonic-gate 	"\036doorlock",
2100Sstevel@tonic-gate 	"\043formatcap",
2110Sstevel@tonic-gate 	"\045readcap",
2120Sstevel@tonic-gate 	"\050read10",
2130Sstevel@tonic-gate 	"\052write10",
2140Sstevel@tonic-gate 	"\053seek10",
2150Sstevel@tonic-gate 	"\056writeverify",
2160Sstevel@tonic-gate 	"\057verify",
2170Sstevel@tonic-gate 	"\065synchcache",
2180Sstevel@tonic-gate 	"\076readlong",
2190Sstevel@tonic-gate 	"\077writelong",
2200Sstevel@tonic-gate 	"\102readsubchan",
2210Sstevel@tonic-gate 	"\103readtoc",
2220Sstevel@tonic-gate 	"\104readhdr",
2230Sstevel@tonic-gate 	"\105playaudio10",
2240Sstevel@tonic-gate 	"\107playaudio_msf",
2250Sstevel@tonic-gate 	"\110playaudio_ti",
2260Sstevel@tonic-gate 	"\111playtrk_r10",
2270Sstevel@tonic-gate 	"\112geteventnotify",
2280Sstevel@tonic-gate 	"\113pause_resume",
2290Sstevel@tonic-gate 	"\116stop/play_scan",
2300Sstevel@tonic-gate 	"\121readdiscinfo",
2310Sstevel@tonic-gate 	"\122readtrkinfo",
2320Sstevel@tonic-gate 	"\123reservedtrk",
2330Sstevel@tonic-gate 	"\124sendopcinfo",
2340Sstevel@tonic-gate 	"\125modeselect",
2350Sstevel@tonic-gate 	"\132modesense",
2360Sstevel@tonic-gate 	"\133closetrksession",
2370Sstevel@tonic-gate 	"\135sendcuesheet",
2380Sstevel@tonic-gate 	"\136prin",
2390Sstevel@tonic-gate 	"\137prout",
2400Sstevel@tonic-gate 	"\241blankcd",
2410Sstevel@tonic-gate 	"\245playaudio12",
2420Sstevel@tonic-gate 	"\250read12",
2430Sstevel@tonic-gate 	"\251playtrk12",
2440Sstevel@tonic-gate 	"\252write12",
2450Sstevel@tonic-gate 	"\254getperf",
2460Sstevel@tonic-gate 	"\271readcdmsf",
2470Sstevel@tonic-gate 	"\273setcdspeed",
2480Sstevel@tonic-gate 	"\275mechanism_sts",
2490Sstevel@tonic-gate 	"\276readcd",
2500Sstevel@tonic-gate 	NULL
2510Sstevel@tonic-gate };
2520Sstevel@tonic-gate 
2530Sstevel@tonic-gate 
2540Sstevel@tonic-gate /*
2550Sstevel@tonic-gate  * Mass-Storage devices masquerade as "sd" disks.
2560Sstevel@tonic-gate  *
2570Sstevel@tonic-gate  * These devices may not support all SCSI CDBs in their
2580Sstevel@tonic-gate  * entirety due to their hardware implementation limitations.
2590Sstevel@tonic-gate  *
2600Sstevel@tonic-gate  * As such, following is a list of some of the black-listed
2610Sstevel@tonic-gate  * devices w/ the attributes that they do not support.
2620Sstevel@tonic-gate  * (See scsa2usb.h for description on each attribute)
2630Sstevel@tonic-gate  */
2640Sstevel@tonic-gate #define	X	((uint16_t)(-1))
2650Sstevel@tonic-gate 
2660Sstevel@tonic-gate static struct blacklist {
2670Sstevel@tonic-gate 	uint16_t	idVendor;	/* vendor ID			*/
2680Sstevel@tonic-gate 	uint16_t	idProduct;	/* product ID			*/
2690Sstevel@tonic-gate 	uint16_t	bcdDevice;	/* device release number in bcd */
2700Sstevel@tonic-gate 	uint16_t	attributes;	/* attributes to blacklist	*/
2710Sstevel@tonic-gate } scsa2usb_blacklist[] = {
2720Sstevel@tonic-gate 	/* Iomega Zip100 drive (prototype) with flaky bridge */
2730Sstevel@tonic-gate 	{MS_IOMEGA_VID, MS_IOMEGA_PID1_ZIP100, 0,
2740Sstevel@tonic-gate 	    SCSA2USB_ATTRS_GET_LUN | SCSA2USB_ATTRS_PM},
2750Sstevel@tonic-gate 
2760Sstevel@tonic-gate 	/* Iomega Zip100 drive (newer model) with flaky bridge */
2770Sstevel@tonic-gate 	{MS_IOMEGA_VID, MS_IOMEGA_PID2_ZIP100, 0,
2780Sstevel@tonic-gate 	    SCSA2USB_ATTRS_GET_LUN | SCSA2USB_ATTRS_PM},
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate 	/* Iomega Zip100 drive (newer model) with flaky bridge */
2810Sstevel@tonic-gate 	{MS_IOMEGA_VID, MS_IOMEGA_PID3_ZIP100, 0,
2820Sstevel@tonic-gate 	    SCSA2USB_ATTRS_GET_LUN | SCSA2USB_ATTRS_PM},
2830Sstevel@tonic-gate 
2840Sstevel@tonic-gate 	/* Iomega Zip250 drive */
2850Sstevel@tonic-gate 	{MS_IOMEGA_VID, MS_IOMEGA_PID_ZIP250, 0, SCSA2USB_ATTRS_GET_LUN},
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate 	/* Iomega Clik! drive */
2880Sstevel@tonic-gate 	{MS_IOMEGA_VID, MS_IOMEGA_PID_CLIK, 0,
2890Sstevel@tonic-gate 	    SCSA2USB_ATTRS_GET_LUN | SCSA2USB_ATTRS_START_STOP},
2900Sstevel@tonic-gate 
2919729SBinzi.Cao@Sun.COM 	/* Kingston DataTraveler Stick / PNY Attache Stick */
2929729SBinzi.Cao@Sun.COM 	{MS_TOSHIBA_VID, MS_TOSHIBA_PID0, 0,
2939729SBinzi.Cao@Sun.COM 	    SCSA2USB_ATTRS_GET_LUN},
2949729SBinzi.Cao@Sun.COM 
2959729SBinzi.Cao@Sun.COM 	/* PNY Floppy drive */
2969729SBinzi.Cao@Sun.COM 	{MS_PNY_VID, MS_PNY_PID0, 0,
2979729SBinzi.Cao@Sun.COM 	    SCSA2USB_ATTRS_GET_LUN},
2989729SBinzi.Cao@Sun.COM 
2990Sstevel@tonic-gate 	/* SMSC floppy Device - and its clones */
3000Sstevel@tonic-gate 	{MS_SMSC_VID, X, 0, SCSA2USB_ATTRS_START_STOP},
3010Sstevel@tonic-gate 
3020Sstevel@tonic-gate 	/* Hagiwara SmartMedia Device */
3030Sstevel@tonic-gate 	{MS_HAGIWARA_SYS_COM_VID, MS_HAGIWARA_SYSCOM_PID1, 0,
3040Sstevel@tonic-gate 	    SCSA2USB_ATTRS_GET_LUN | SCSA2USB_ATTRS_START_STOP},
3050Sstevel@tonic-gate 
3060Sstevel@tonic-gate 	/* Hagiwara CompactFlash Device */
3070Sstevel@tonic-gate 	{MS_HAGIWARA_SYS_COM_VID, MS_HAGIWARA_SYSCOM_PID2, 0,
3080Sstevel@tonic-gate 	    SCSA2USB_ATTRS_GET_LUN | SCSA2USB_ATTRS_START_STOP},
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate 	/* Hagiwara SmartMedia/CompactFlash Combo Device */
3110Sstevel@tonic-gate 	{MS_HAGIWARA_SYS_COM_VID, MS_HAGIWARA_SYSCOM_PID3, 0,
3120Sstevel@tonic-gate 	    SCSA2USB_ATTRS_START_STOP},
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate 	/* Hagiwara new SM Device */
3150Sstevel@tonic-gate 	{MS_HAGIWARA_SYS_COM_VID, MS_HAGIWARA_SYSCOM_PID4, 0,
3160Sstevel@tonic-gate 	    SCSA2USB_ATTRS_GET_LUN | SCSA2USB_ATTRS_START_STOP},
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate 	/* Hagiwara new CF Device */
3190Sstevel@tonic-gate 	{MS_HAGIWARA_SYS_COM_VID, MS_HAGIWARA_SYSCOM_PID5, 0,
3200Sstevel@tonic-gate 	    SCSA2USB_ATTRS_GET_LUN | SCSA2USB_ATTRS_START_STOP},
3210Sstevel@tonic-gate 
3220Sstevel@tonic-gate 	/* Mitsumi CD-RW Device(s) */
3230Sstevel@tonic-gate 	{MS_MITSUMI_VID, X, X, SCSA2USB_ATTRS_BIG_TIMEOUT |
3240Sstevel@tonic-gate 	    SCSA2USB_ATTRS_GET_CONF | SCSA2USB_ATTRS_GET_PERF},
3250Sstevel@tonic-gate 
3260Sstevel@tonic-gate 	/* Neodio Technologies Corporation SM/CF/MS/SD Combo Device */
3270Sstevel@tonic-gate 	{MS_NEODIO_VID, MS_NEODIO_DEVICE_3050, 0,
3280Sstevel@tonic-gate 	    SCSA2USB_ATTRS_MODE_SENSE },
3290Sstevel@tonic-gate 
3300Sstevel@tonic-gate 	/* dumb flash devices */
3310Sstevel@tonic-gate 	{MS_SONY_FLASH_VID, MS_SONY_FLASH_PID, 0,
3320Sstevel@tonic-gate 	    SCSA2USB_ATTRS_REDUCED_CMD},
3330Sstevel@tonic-gate 
3340Sstevel@tonic-gate 	{MS_TREK_FLASH_VID, MS_TREK_FLASH_PID, 0,
3350Sstevel@tonic-gate 	    SCSA2USB_ATTRS_REDUCED_CMD},
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate 	{MS_PENN_FLASH_VID, MS_PENN_FLASH_PID, 0,
3380Sstevel@tonic-gate 	    SCSA2USB_ATTRS_REDUCED_CMD},
3390Sstevel@tonic-gate 
3400Sstevel@tonic-gate 	/* SimpleTech UCF-100 CF Device */
3410Sstevel@tonic-gate 	{MS_SIMPLETECH_VID, MS_SIMPLETECH_PID1, 0,
3420Sstevel@tonic-gate 	    SCSA2USB_ATTRS_REDUCED_CMD},
3430Sstevel@tonic-gate 
3440Sstevel@tonic-gate 	{MS_ADDONICS_CARD_READER_VID, MS_ADDONICS_CARD_READER_PID,
3450Sstevel@tonic-gate 	    0, SCSA2USB_ATTRS_REDUCED_CMD},
3461101Ssl147100 
3471101Ssl147100 	/* Acomdata 80GB USB/1394 Hard Disk */
3481101Ssl147100 	{MS_ACOMDATA_VID, MS_ACOMDATA_PID1, 0,
3491101Ssl147100 	    SCSA2USB_ATTRS_USE_CSW_RESIDUE},
3501101Ssl147100 
3511101Ssl147100 	/* OTi6828 Flash Disk */
3521101Ssl147100 	{MS_OTI_VID, MS_OTI_DEVICE_6828, 0,
3531101Ssl147100 	    SCSA2USB_ATTRS_USE_CSW_RESIDUE},
3542506Ssl147100 
3552506Ssl147100 	/* AMI Virtual Floppy */
3562506Ssl147100 	{MS_AMI_VID, MS_AMI_VIRTUAL_FLOPPY, 0,
3572506Ssl147100 	    SCSA2USB_ATTRS_NO_MEDIA_CHECK},
3584834Sfb209375 
3594834Sfb209375 	/* ScanLogic USB Storage Device */
3604834Sfb209375 	{MS_SCANLOGIC_VID, MS_SCANLOGIC_PID1, 0,
3615789Ssl147100 	    SCSA2USB_ATTRS_NO_CAP_ADJUST},
3625789Ssl147100 
3635789Ssl147100 	/* Super Top USB 2.0 IDE Device */
3645789Ssl147100 	{MS_SUPERTOP_VID, MS_SUPERTOP_DEVICE_6600, 0,
3657231Slg150142 	    SCSA2USB_ATTRS_USE_CSW_RESIDUE},
3667231Slg150142 
3677231Slg150142 	/* Aigo Miniking Device NEHFSP14 */
3687231Slg150142 	{MS_AIGO_VID, MS_AIGO_DEVICE_6981, 0,
3698075SGuoqing.Zhu@Sun.COM 	    SCSA2USB_ATTRS_USE_CSW_RESIDUE},
3708075SGuoqing.Zhu@Sun.COM 
3718075SGuoqing.Zhu@Sun.COM 	/* Alcor Micro Corp 6387 flash disk */
3728075SGuoqing.Zhu@Sun.COM 	{MS_ALCOR_VID, MS_ALCOR_PID0, 0,
37310678SGuoqing.Zhu@Sun.COM 	    SCSA2USB_ATTRS_GET_LUN | SCSA2USB_ATTRS_USE_CSW_RESIDUE},
37410678SGuoqing.Zhu@Sun.COM 
37510678SGuoqing.Zhu@Sun.COM 	/* Western Digital External HDD */
37610678SGuoqing.Zhu@Sun.COM 	{MS_WD_VID, MS_WD_PID, 0,
37710678SGuoqing.Zhu@Sun.COM 	    SCSA2USB_ATTRS_INQUIRY_EVPD}
3780Sstevel@tonic-gate };
3790Sstevel@tonic-gate 
3800Sstevel@tonic-gate 
3810Sstevel@tonic-gate #define	N_SCSA2USB_BLACKLIST (sizeof (scsa2usb_blacklist))/ \
3820Sstevel@tonic-gate 				sizeof (struct blacklist)
3830Sstevel@tonic-gate 
3840Sstevel@tonic-gate /*
3850Sstevel@tonic-gate  * Attribute values can be overridden by values
3860Sstevel@tonic-gate  * contained in the scsa2usb.conf file.
3870Sstevel@tonic-gate  * These arrays define possible user input values.
3880Sstevel@tonic-gate  */
3890Sstevel@tonic-gate 
3900Sstevel@tonic-gate struct scsa2usb_subclass_protocol_override {
3910Sstevel@tonic-gate 	char	*name;
3920Sstevel@tonic-gate 	int	value;
3930Sstevel@tonic-gate };
3940Sstevel@tonic-gate 
3950Sstevel@tonic-gate static struct scsa2usb_subclass_protocol_override scsa2usb_protocol[] =  {
3960Sstevel@tonic-gate 	{"CB", SCSA2USB_CB_PROTOCOL},
3970Sstevel@tonic-gate 	{"CBI", SCSA2USB_CBI_PROTOCOL},
3980Sstevel@tonic-gate 	{"BO", SCSA2USB_BULK_ONLY_PROTOCOL}
3990Sstevel@tonic-gate };
4000Sstevel@tonic-gate 
4010Sstevel@tonic-gate static struct scsa2usb_subclass_protocol_override scsa2usb_subclass[] = {
4020Sstevel@tonic-gate 	{"SCSI", SCSA2USB_SCSI_CMDSET},
4030Sstevel@tonic-gate 	{"ATAPI", SCSA2USB_ATAPI_CMDSET},
4040Sstevel@tonic-gate 	{"UFI", SCSA2USB_UFI_CMDSET}
4050Sstevel@tonic-gate };
4060Sstevel@tonic-gate 
4070Sstevel@tonic-gate 
4080Sstevel@tonic-gate #define	N_SCSA2USB_SUBC_OVERRIDE (sizeof (scsa2usb_subclass))/ \
4090Sstevel@tonic-gate 			sizeof (struct scsa2usb_subclass_protocol_override)
4100Sstevel@tonic-gate 
4110Sstevel@tonic-gate #define	N_SCSA2USB_PROT_OVERRIDE (sizeof (scsa2usb_protocol))/ \
4120Sstevel@tonic-gate 			sizeof (struct scsa2usb_subclass_protocol_override)
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate /* global variables */
4150Sstevel@tonic-gate static void *scsa2usb_statep;				/* for soft state */
4160Sstevel@tonic-gate static boolean_t scsa2usb_sync_message = B_TRUE;	/* for syncing */
4170Sstevel@tonic-gate 
4180Sstevel@tonic-gate /* for debug messages */
419880Sfrits uint_t	scsa2usb_errmask	= (uint_t)DPRINT_MASK_ALL;
420880Sfrits uint_t	scsa2usb_errlevel	= USB_LOG_L4;
421880Sfrits uint_t	scsa2usb_instance_debug = (uint_t)-1;
422880Sfrits uint_t	scsa2usb_scsi_bus_config_debug = 0;
423880Sfrits uint_t	scsa2usb_long_timeout	= 50 * SCSA2USB_BULK_PIPE_TIMEOUT;
4240Sstevel@tonic-gate 
4250Sstevel@tonic-gate 
4260Sstevel@tonic-gate /*
4270Sstevel@tonic-gate  * Some devices have problems with big bulk transfers,
4280Sstevel@tonic-gate  * transfers >= 128kbytes hang the device.  This tunable allows to
4290Sstevel@tonic-gate  * limit the maximum bulk transfers rate.
4300Sstevel@tonic-gate  */
431880Sfrits uint_t	scsa2usb_max_bulk_xfer_size = SCSA2USB_MAX_BULK_XFER_SIZE;
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate 
4340Sstevel@tonic-gate #ifdef	SCSA2USB_BULK_ONLY_TEST
4350Sstevel@tonic-gate /*
4360Sstevel@tonic-gate  * Test BO 13 cases. (See USB Mass Storage Class - Bulk Only Transport).
4370Sstevel@tonic-gate  * We are not covering test cases 1, 6, and 12 as these are the "good"
4380Sstevel@tonic-gate  * test cases and are tested as part of the normal drive access operations.
4390Sstevel@tonic-gate  *
4400Sstevel@tonic-gate  * NOTE: This is for testing only. It will be replaced by a uscsi test.
4410Sstevel@tonic-gate  * Some are listed here while; other test cases are moved to usb_bulkonly.c
4420Sstevel@tonic-gate  */
4430Sstevel@tonic-gate static int scsa2usb_test_case_5 = 0;
4440Sstevel@tonic-gate int scsa2usb_test_case_8 = 0;
4450Sstevel@tonic-gate int scsa2usb_test_case_10 = 0;
4460Sstevel@tonic-gate static int scsa2usb_test_case_11 = 0;
4470Sstevel@tonic-gate 
4480Sstevel@tonic-gate static void	scsa2usb_test_mblk(scsa2usb_state_t *, boolean_t);
4490Sstevel@tonic-gate #endif	/* SCSA2USB_BULK_ONLY_TEST */
4500Sstevel@tonic-gate 
4510Sstevel@tonic-gate static int	scsa2usb_ugen_open(dev_t *, int, int, cred_t *);
4520Sstevel@tonic-gate static int	scsa2usb_ugen_close(dev_t, int, int, cred_t *);
4530Sstevel@tonic-gate static int	scsa2usb_ugen_read(dev_t, struct uio *, cred_t *);
4540Sstevel@tonic-gate static int	scsa2usb_ugen_write(dev_t, struct uio *, cred_t *);
4550Sstevel@tonic-gate static int	scsa2usb_ugen_poll(dev_t, short, int,  short *,
4560Sstevel@tonic-gate 						struct pollhead **);
4570Sstevel@tonic-gate 
4580Sstevel@tonic-gate /* scsa2usb cb_ops */
4590Sstevel@tonic-gate static struct cb_ops scsa2usb_cbops = {
4600Sstevel@tonic-gate 	scsa2usb_ugen_open,	/* open  */
4610Sstevel@tonic-gate 	scsa2usb_ugen_close,	/* close */
4620Sstevel@tonic-gate 	nodev,			/* strategy */
4630Sstevel@tonic-gate 	nodev,			/* print */
4640Sstevel@tonic-gate 	nodev,			/* dump */
4650Sstevel@tonic-gate 	scsa2usb_ugen_read,	/* read */
4660Sstevel@tonic-gate 	scsa2usb_ugen_write,	/* write */
4676910Svb160487 	nodev,			/* ioctl */
4680Sstevel@tonic-gate 	nodev,			/* devmap */
4690Sstevel@tonic-gate 	nodev,			/* mmap */
4700Sstevel@tonic-gate 	nodev,			/* segmap */
4710Sstevel@tonic-gate 	scsa2usb_ugen_poll,	/* poll */
4720Sstevel@tonic-gate 	ddi_prop_op,		/* prop_op */
4730Sstevel@tonic-gate 	NULL,			/* stream */
4740Sstevel@tonic-gate 	D_MP,			/* cb_flag */
4750Sstevel@tonic-gate 	CB_REV, 		/* rev */
4760Sstevel@tonic-gate 	nodev,			/* int (*cb_aread)() */
4770Sstevel@tonic-gate 	nodev			/* int (*cb_awrite)() */
4780Sstevel@tonic-gate };
4790Sstevel@tonic-gate 
4800Sstevel@tonic-gate /* modloading support */
4810Sstevel@tonic-gate static struct dev_ops scsa2usb_ops = {
4820Sstevel@tonic-gate 	DEVO_REV,		/* devo_rev, */
4830Sstevel@tonic-gate 	0,			/* refcnt  */
4840Sstevel@tonic-gate 	scsa2usb_info,		/* info */
4850Sstevel@tonic-gate 	nulldev,		/* identify */
4860Sstevel@tonic-gate 	nulldev,		/* probe */
4870Sstevel@tonic-gate 	scsa2usb_attach,	/* attach */
4880Sstevel@tonic-gate 	scsa2usb_detach,	/* detach */
4890Sstevel@tonic-gate 	nodev,			/* reset */
4900Sstevel@tonic-gate 	&scsa2usb_cbops,	/* driver operations */
4910Sstevel@tonic-gate 	NULL,			/* bus operations */
4927656SSherry.Moore@Sun.COM 	scsa2usb_power,		/* power */
4937656SSherry.Moore@Sun.COM 	ddi_quiesce_not_needed,		/* quiesce */
4940Sstevel@tonic-gate };
4950Sstevel@tonic-gate 
4960Sstevel@tonic-gate static struct modldrv modldrv = {
4970Sstevel@tonic-gate 	&mod_driverops,			/* Module type. This one is a driver */
4987015Sbc224572 	"SCSA to USB Driver",	/* Name of the module. */
4990Sstevel@tonic-gate 	&scsa2usb_ops,			/* driver ops */
5000Sstevel@tonic-gate };
5010Sstevel@tonic-gate 
5020Sstevel@tonic-gate static struct modlinkage modlinkage = {
5030Sstevel@tonic-gate 	MODREV_1, (void *)&modldrv, NULL
5040Sstevel@tonic-gate };
5050Sstevel@tonic-gate 
5060Sstevel@tonic-gate /* event support */
5070Sstevel@tonic-gate static usb_event_t scsa2usb_events = {
5080Sstevel@tonic-gate 	scsa2usb_disconnect_event_cb,
5090Sstevel@tonic-gate 	scsa2usb_reconnect_event_cb,
5100Sstevel@tonic-gate 	NULL, NULL
5110Sstevel@tonic-gate };
5120Sstevel@tonic-gate 
5130Sstevel@tonic-gate int
5140Sstevel@tonic-gate _init(void)
5150Sstevel@tonic-gate {
5160Sstevel@tonic-gate 	int rval;
5170Sstevel@tonic-gate 
5180Sstevel@tonic-gate 	if (((rval = ddi_soft_state_init(&scsa2usb_statep,
5190Sstevel@tonic-gate 	    sizeof (scsa2usb_state_t), SCSA2USB_INITIAL_ALLOC)) != 0)) {
5200Sstevel@tonic-gate 
5210Sstevel@tonic-gate 		return (rval);
5220Sstevel@tonic-gate 	}
5230Sstevel@tonic-gate 
5240Sstevel@tonic-gate 	if ((rval = scsi_hba_init(&modlinkage)) != 0) {
5250Sstevel@tonic-gate 		ddi_soft_state_fini(&scsa2usb_statep);
5260Sstevel@tonic-gate 
5270Sstevel@tonic-gate 		return (rval);
5280Sstevel@tonic-gate 	}
5290Sstevel@tonic-gate 
5300Sstevel@tonic-gate 	if ((rval = mod_install(&modlinkage)) != 0) {
5310Sstevel@tonic-gate 		scsi_hba_fini(&modlinkage);
5320Sstevel@tonic-gate 		ddi_soft_state_fini(&scsa2usb_statep);
5330Sstevel@tonic-gate 
5340Sstevel@tonic-gate 		return (rval);
5350Sstevel@tonic-gate 	}
5360Sstevel@tonic-gate 
5370Sstevel@tonic-gate 	return (rval);
5380Sstevel@tonic-gate }
5390Sstevel@tonic-gate 
5400Sstevel@tonic-gate 
5410Sstevel@tonic-gate int
5420Sstevel@tonic-gate _fini(void)
5430Sstevel@tonic-gate {
5440Sstevel@tonic-gate 	int	rval;
5450Sstevel@tonic-gate 
5460Sstevel@tonic-gate 	if ((rval = mod_remove(&modlinkage)) == 0) {
5470Sstevel@tonic-gate 		scsi_hba_fini(&modlinkage);
5480Sstevel@tonic-gate 		ddi_soft_state_fini(&scsa2usb_statep);
5490Sstevel@tonic-gate 	}
5500Sstevel@tonic-gate 
5510Sstevel@tonic-gate 	return (rval);
5520Sstevel@tonic-gate }
5530Sstevel@tonic-gate 
5540Sstevel@tonic-gate 
5550Sstevel@tonic-gate int
5560Sstevel@tonic-gate _info(struct modinfo *modinfop)
5570Sstevel@tonic-gate {
5580Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
5590Sstevel@tonic-gate }
5600Sstevel@tonic-gate 
5610Sstevel@tonic-gate 
5620Sstevel@tonic-gate /*
5630Sstevel@tonic-gate  * scsa2usb_info :
5640Sstevel@tonic-gate  *	Get minor number, soft state structure etc.
5650Sstevel@tonic-gate  */
5660Sstevel@tonic-gate /*ARGSUSED*/
5670Sstevel@tonic-gate static int
5680Sstevel@tonic-gate scsa2usb_info(dev_info_t *dip, ddi_info_cmd_t infocmd,
5690Sstevel@tonic-gate     void *arg, void **result)
5700Sstevel@tonic-gate {
5710Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp = NULL;
5720Sstevel@tonic-gate 	int error = DDI_FAILURE;
5730Sstevel@tonic-gate 	int instance = SCSA2USB_MINOR_TO_INSTANCE(getminor((dev_t)arg));
5740Sstevel@tonic-gate 
5750Sstevel@tonic-gate 	switch (infocmd) {
5760Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
5770Sstevel@tonic-gate 		if (((scsa2usbp = ddi_get_soft_state(scsa2usb_statep,
5780Sstevel@tonic-gate 		    instance)) != NULL) &&
5790Sstevel@tonic-gate 		    scsa2usbp->scsa2usb_dip) {
5800Sstevel@tonic-gate 			*result = scsa2usbp->scsa2usb_dip;
5810Sstevel@tonic-gate 			error = DDI_SUCCESS;
5820Sstevel@tonic-gate 		} else {
5830Sstevel@tonic-gate 			*result = NULL;
5840Sstevel@tonic-gate 		}
5850Sstevel@tonic-gate 		break;
5860Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
5870Sstevel@tonic-gate 		*result = (void *)(uintptr_t)instance;
5880Sstevel@tonic-gate 		error = DDI_SUCCESS;
5890Sstevel@tonic-gate 		break;
5900Sstevel@tonic-gate 	default:
5910Sstevel@tonic-gate 		break;
5920Sstevel@tonic-gate 	}
5930Sstevel@tonic-gate 
5940Sstevel@tonic-gate 	return (error);
5950Sstevel@tonic-gate }
5960Sstevel@tonic-gate 
5970Sstevel@tonic-gate 
5980Sstevel@tonic-gate /*
5990Sstevel@tonic-gate  * scsa2usb_attach:
6000Sstevel@tonic-gate  *	Attach driver
6010Sstevel@tonic-gate  *	Allocate a "scsi_hba_tran" - call scsi_hba_tran_alloc()
6020Sstevel@tonic-gate  *	Invoke scsi_hba_attach_setup
6030Sstevel@tonic-gate  *	Get the serialno of the device
6040Sstevel@tonic-gate  *	Open bulk pipes
6050Sstevel@tonic-gate  *	Create disk child(ren)
6060Sstevel@tonic-gate  *	Register events
6070Sstevel@tonic-gate  *	Create and register panic callback
6080Sstevel@tonic-gate  *
6090Sstevel@tonic-gate  * NOTE: Replaced CBW_DIR_OUT with USB_EP_DIR_OUT and CBW_DIR_IN with
6100Sstevel@tonic-gate  * USB_EP_DIR_IN as they are the same #defines.
6110Sstevel@tonic-gate  */
6120Sstevel@tonic-gate static int
6130Sstevel@tonic-gate scsa2usb_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
6140Sstevel@tonic-gate {
6150Sstevel@tonic-gate 	int			instance = ddi_get_instance(dip);
6160Sstevel@tonic-gate 	int			interface;
6170Sstevel@tonic-gate 	uint_t			lun;
6180Sstevel@tonic-gate 	boolean_t		ept_check = B_TRUE;
6190Sstevel@tonic-gate 	scsi_hba_tran_t		*tran;		/* scsi transport */
6200Sstevel@tonic-gate 	scsa2usb_state_t	*scsa2usbp;
6210Sstevel@tonic-gate 	usb_log_handle_t	log_handle;
6220Sstevel@tonic-gate 	usb_ep_data_t		*ep_data;
6230Sstevel@tonic-gate 	usb_client_dev_data_t	*dev_data;
6240Sstevel@tonic-gate 	usb_alt_if_data_t	*altif_data;
6250Sstevel@tonic-gate 	usb_ugen_info_t 	usb_ugen_info;
6260Sstevel@tonic-gate 
6270Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, NULL,
6286898Sfb209375 	    "scsa2usb_attach: dip = 0x%p", (void *)dip);
6290Sstevel@tonic-gate 
6300Sstevel@tonic-gate 	switch (cmd) {
6310Sstevel@tonic-gate 	case DDI_ATTACH:
6320Sstevel@tonic-gate 		break;
6330Sstevel@tonic-gate 	case DDI_RESUME:
6340Sstevel@tonic-gate 		scsa2usb_cpr_resume(dip);
6350Sstevel@tonic-gate 
6360Sstevel@tonic-gate 		return (DDI_SUCCESS);
6370Sstevel@tonic-gate 	default:
6380Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, NULL,
6390Sstevel@tonic-gate 		    "scsa2usb_attach: failed");
6400Sstevel@tonic-gate 
6410Sstevel@tonic-gate 		return (DDI_FAILURE);
6420Sstevel@tonic-gate 	}
6430Sstevel@tonic-gate 
6440Sstevel@tonic-gate 	/* Allocate softc information */
6450Sstevel@tonic-gate 	if (ddi_soft_state_zalloc(scsa2usb_statep, instance) != DDI_SUCCESS) {
6460Sstevel@tonic-gate 		ddi_prop_remove_all(dip);
6470Sstevel@tonic-gate 
6480Sstevel@tonic-gate 		return (DDI_FAILURE);
6490Sstevel@tonic-gate 	}
6500Sstevel@tonic-gate 
6510Sstevel@tonic-gate 	/* get soft state space and initialize */
6520Sstevel@tonic-gate 	if ((scsa2usbp = ddi_get_soft_state(scsa2usb_statep,
6530Sstevel@tonic-gate 	    instance)) == NULL) {
6540Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, NULL,
6550Sstevel@tonic-gate 		    "scsa2usb%d: bad soft state", instance);
6560Sstevel@tonic-gate 		ddi_prop_remove_all(dip);
6570Sstevel@tonic-gate 
6580Sstevel@tonic-gate 		return (DDI_FAILURE);
6590Sstevel@tonic-gate 	}
6600Sstevel@tonic-gate 
6610Sstevel@tonic-gate 	scsa2usbp->scsa2usb_dip 	= dip;
6620Sstevel@tonic-gate 	scsa2usbp->scsa2usb_instance	= instance;
6630Sstevel@tonic-gate 
6640Sstevel@tonic-gate 	/* allocate a log handle for debug/error messages */
6650Sstevel@tonic-gate 	scsa2usbp->scsa2usb_log_handle = log_handle =
6660Sstevel@tonic-gate 	    usb_alloc_log_hdl(dip, "s2u",
6674700Sfb209375 	    &scsa2usb_errlevel,
6684700Sfb209375 	    &scsa2usb_errmask, &scsa2usb_instance_debug,
6694700Sfb209375 	    0);
6700Sstevel@tonic-gate 
6710Sstevel@tonic-gate 	/* attach to USBA */
6720Sstevel@tonic-gate 	if (usb_client_attach(dip, USBDRV_VERSION, 0) != USB_SUCCESS) {
6730Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, log_handle,
6740Sstevel@tonic-gate 		    "usb_client_attach failed");
6750Sstevel@tonic-gate 
6760Sstevel@tonic-gate 		goto fail;
6770Sstevel@tonic-gate 	}
6780Sstevel@tonic-gate 	if (usb_get_dev_data(dip, &dev_data, USB_PARSE_LVL_IF, 0) !=
6790Sstevel@tonic-gate 	    USB_SUCCESS) {
6800Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, log_handle,
6810Sstevel@tonic-gate 		    "usb_get_dev_data failed");
6820Sstevel@tonic-gate 
6830Sstevel@tonic-gate 		goto fail;
6840Sstevel@tonic-gate 	}
6850Sstevel@tonic-gate 
6860Sstevel@tonic-gate 	/* initialize the mutex with the right cookie */
6870Sstevel@tonic-gate 	mutex_init(&scsa2usbp->scsa2usb_mutex, NULL, MUTEX_DRIVER,
6884700Sfb209375 	    dev_data->dev_iblock_cookie);
6890Sstevel@tonic-gate 	cv_init(&scsa2usbp->scsa2usb_transport_busy_cv, NULL, CV_DRIVER, NULL);
6900Sstevel@tonic-gate 
6910Sstevel@tonic-gate 	for (lun = 0; lun < SCSA2USB_MAX_LUNS; lun++) {
6920Sstevel@tonic-gate 		usba_init_list(&scsa2usbp->scsa2usb_waitQ[lun], NULL,
6934700Sfb209375 		    dev_data->dev_iblock_cookie);
6940Sstevel@tonic-gate 	}
6950Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
6960Sstevel@tonic-gate 	scsa2usbp->scsa2usb_dip 	= dip;
6970Sstevel@tonic-gate 	scsa2usbp->scsa2usb_instance	= instance;
6980Sstevel@tonic-gate 	scsa2usbp->scsa2usb_attrs	= SCSA2USB_ALL_ATTRS;
6990Sstevel@tonic-gate 	scsa2usbp->scsa2usb_dev_data	= dev_data;
7000Sstevel@tonic-gate 
7010Sstevel@tonic-gate 
7020Sstevel@tonic-gate 	/* save the default pipe handle */
7030Sstevel@tonic-gate 	scsa2usbp->scsa2usb_default_pipe = dev_data->dev_default_ph;
7040Sstevel@tonic-gate 
7050Sstevel@tonic-gate 	/* basic inits are done */
7060Sstevel@tonic-gate 	scsa2usbp->scsa2usb_flags |= SCSA2USB_FLAGS_LOCKS_INIT;
7070Sstevel@tonic-gate 
7080Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, log_handle,
7096898Sfb209375 	    "curr_cfg=%ld, curr_if=%d",
7106898Sfb209375 	    (long)(dev_data->dev_curr_cfg - &dev_data->dev_cfg[0]),
7110Sstevel@tonic-gate 	    dev_data->dev_curr_if);
7120Sstevel@tonic-gate 
7130Sstevel@tonic-gate 	interface = dev_data->dev_curr_if;
7140Sstevel@tonic-gate 	scsa2usbp->scsa2usb_intfc_num = dev_data->dev_curr_if;
7150Sstevel@tonic-gate 
7160Sstevel@tonic-gate 	/* now find out relevant descriptors for alternate 0 */
7170Sstevel@tonic-gate 	altif_data = &dev_data->dev_curr_cfg->cfg_if[interface].if_alt[0];
7180Sstevel@tonic-gate 
7190Sstevel@tonic-gate 	if (altif_data->altif_n_ep == 0) {
720978Sfrits 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, log_handle,
7210Sstevel@tonic-gate 		    "invalid alt 0 for interface %d", interface);
7220Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
7230Sstevel@tonic-gate 
7240Sstevel@tonic-gate 		goto fail;
7250Sstevel@tonic-gate 	}
7260Sstevel@tonic-gate 
7270Sstevel@tonic-gate 	/* All CB/CBI, BO devices should have this value set */
7280Sstevel@tonic-gate 	if (altif_data->altif_descr.bInterfaceClass !=
7290Sstevel@tonic-gate 	    USB_CLASS_MASS_STORAGE) {
730978Sfrits 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, log_handle,
7310Sstevel@tonic-gate 		    "invalid interface class (0x%x)",
7320Sstevel@tonic-gate 		    altif_data->altif_descr.bInterfaceClass);
7330Sstevel@tonic-gate 	}
7340Sstevel@tonic-gate 	scsa2usbp->scsa2usb_intfc_descr = altif_data->altif_descr;
7350Sstevel@tonic-gate 
7360Sstevel@tonic-gate 	/* figure out the endpoints and copy the descr */
7370Sstevel@tonic-gate 	if ((ep_data = usb_lookup_ep_data(dip, dev_data, interface, 0, 0,
7380Sstevel@tonic-gate 	    USB_EP_ATTR_BULK, USB_EP_DIR_OUT)) != NULL) {
7390Sstevel@tonic-gate 		scsa2usbp->scsa2usb_bulkout_ept = ep_data->ep_descr;
7400Sstevel@tonic-gate 	}
7410Sstevel@tonic-gate 	if ((ep_data = usb_lookup_ep_data(dip, dev_data, interface, 0, 0,
7420Sstevel@tonic-gate 	    USB_EP_ATTR_BULK, USB_EP_DIR_IN)) != NULL) {
7430Sstevel@tonic-gate 		scsa2usbp->scsa2usb_bulkin_ept = ep_data->ep_descr;
7440Sstevel@tonic-gate 	}
7450Sstevel@tonic-gate 	if ((ep_data = usb_lookup_ep_data(dip, dev_data, interface, 0, 0,
7460Sstevel@tonic-gate 	    USB_EP_ATTR_INTR, USB_EP_DIR_IN)) != NULL) {
7470Sstevel@tonic-gate 		scsa2usbp->scsa2usb_intr_ept = ep_data->ep_descr;
7480Sstevel@tonic-gate 	}
7490Sstevel@tonic-gate 
7500Sstevel@tonic-gate 	/*
7510Sstevel@tonic-gate 	 * check here for protocol and subclass supported by this driver
7520Sstevel@tonic-gate 	 *
7530Sstevel@tonic-gate 	 * first check if conf file has override values
7540Sstevel@tonic-gate 	 * Note: override values are not used if supplied values are legal
7550Sstevel@tonic-gate 	 */
7560Sstevel@tonic-gate 	scsa2usb_override(scsa2usbp);
7570Sstevel@tonic-gate 
7580Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_SCSA, log_handle,
7590Sstevel@tonic-gate 	    "protocol=0x%x override=0x%x subclass=0x%x override=0x%x",
7600Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_intfc_descr.bInterfaceProtocol,
7610Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_protocol_override,
7620Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_intfc_descr.bInterfaceSubClass,
7630Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_subclass_override);
7640Sstevel@tonic-gate 
7650Sstevel@tonic-gate 	switch (scsa2usbp->scsa2usb_intfc_descr.bInterfaceProtocol) {
7660Sstevel@tonic-gate 	case USB_PROTO_MS_CBI:
7670Sstevel@tonic-gate 		scsa2usbp->scsa2usb_cmd_protocol |= SCSA2USB_CB_PROTOCOL;
7680Sstevel@tonic-gate 		break;
7690Sstevel@tonic-gate 	case USB_PROTO_MS_CBI_WC:
7700Sstevel@tonic-gate 		scsa2usbp->scsa2usb_cmd_protocol |= SCSA2USB_CBI_PROTOCOL;
7710Sstevel@tonic-gate 		break;
7720Sstevel@tonic-gate 	case USB_PROTO_MS_ISD_1999_SILICN:
7730Sstevel@tonic-gate 	case USB_PROTO_MS_BULK_ONLY:
7740Sstevel@tonic-gate 		scsa2usbp->scsa2usb_cmd_protocol |= SCSA2USB_BULK_ONLY_PROTOCOL;
7750Sstevel@tonic-gate 		break;
7760Sstevel@tonic-gate 	default:
7770Sstevel@tonic-gate 		if (scsa2usbp->scsa2usb_protocol_override) {
7780Sstevel@tonic-gate 			scsa2usbp->scsa2usb_cmd_protocol |=
7790Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_protocol_override;
780978Sfrits 			USB_DPRINTF_L2(DPRINT_MASK_SCSA, log_handle,
7810Sstevel@tonic-gate 			    "overriding protocol %x",
7820Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_intfc_descr.bInterfaceProtocol);
7830Sstevel@tonic-gate 			break;
7840Sstevel@tonic-gate 		}
7850Sstevel@tonic-gate 
7860Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, log_handle,
7870Sstevel@tonic-gate 		    "unsupported protocol = %x",
7880Sstevel@tonic-gate 		    scsa2usbp->scsa2usb_intfc_descr.bInterfaceProtocol);
7890Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
7900Sstevel@tonic-gate 
7910Sstevel@tonic-gate 		goto fail;
7920Sstevel@tonic-gate 	}
7930Sstevel@tonic-gate 
7940Sstevel@tonic-gate 	switch (scsa2usbp->scsa2usb_intfc_descr.bInterfaceSubClass) {
7950Sstevel@tonic-gate 	case USB_SUBCLS_MS_SCSI:		/* transparent SCSI */
7960Sstevel@tonic-gate 		scsa2usbp->scsa2usb_cmd_protocol |= SCSA2USB_SCSI_CMDSET;
7970Sstevel@tonic-gate 		break;
7980Sstevel@tonic-gate 	case USB_SUBCLS_MS_SFF8020I:
7990Sstevel@tonic-gate 	case USB_SUBCLS_MS_SFF8070I:
8000Sstevel@tonic-gate 		scsa2usbp->scsa2usb_cmd_protocol |= SCSA2USB_ATAPI_CMDSET;
8010Sstevel@tonic-gate 		break;
8020Sstevel@tonic-gate 	case USB_SUBCLS_MS_UFI:		/* UFI */
8030Sstevel@tonic-gate 		scsa2usbp->scsa2usb_cmd_protocol |= SCSA2USB_UFI_CMDSET;
8040Sstevel@tonic-gate 		break;
8050Sstevel@tonic-gate 	default:
8060Sstevel@tonic-gate 		if (scsa2usbp->scsa2usb_subclass_override) {
8070Sstevel@tonic-gate 			scsa2usbp->scsa2usb_cmd_protocol |=
8080Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_subclass_override;
809978Sfrits 			USB_DPRINTF_L2(DPRINT_MASK_SCSA, log_handle,
8100Sstevel@tonic-gate 			    "overriding subclass %x",
8110Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_intfc_descr.bInterfaceSubClass);
8120Sstevel@tonic-gate 			break;
8130Sstevel@tonic-gate 		}
8140Sstevel@tonic-gate 
8150Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, log_handle,
8160Sstevel@tonic-gate 		    "unsupported subclass = %x",
8170Sstevel@tonic-gate 		    scsa2usbp->scsa2usb_intfc_descr.bInterfaceSubClass);
8180Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
8190Sstevel@tonic-gate 
8200Sstevel@tonic-gate 		goto fail;
8210Sstevel@tonic-gate 	}
8220Sstevel@tonic-gate 
8230Sstevel@tonic-gate 	/* check that we have the right set of endpoint descriptors */
8240Sstevel@tonic-gate 	if (SCSA2USB_IS_BULK_ONLY(scsa2usbp) || SCSA2USB_IS_CB(scsa2usbp)) {
8250Sstevel@tonic-gate 		if ((scsa2usbp->scsa2usb_bulkout_ept.bLength == 0) ||
8260Sstevel@tonic-gate 		    (scsa2usbp->scsa2usb_bulkin_ept.bLength == 0)) {
8270Sstevel@tonic-gate 			ept_check = B_FALSE;
8280Sstevel@tonic-gate 		}
8290Sstevel@tonic-gate 	} else if (SCSA2USB_IS_CBI(scsa2usbp)) {
8300Sstevel@tonic-gate 		if ((scsa2usbp->scsa2usb_bulkout_ept.bLength == 0) ||
8310Sstevel@tonic-gate 		    (scsa2usbp->scsa2usb_bulkin_ept.bLength == 0) ||
8320Sstevel@tonic-gate 		    (scsa2usbp->scsa2usb_intr_ept.bLength == 0)) {
8330Sstevel@tonic-gate 			ept_check = B_FALSE;
8340Sstevel@tonic-gate 		}
8350Sstevel@tonic-gate 	}
8360Sstevel@tonic-gate 
8370Sstevel@tonic-gate 	if (ept_check == B_FALSE) {
838978Sfrits 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, log_handle,
8390Sstevel@tonic-gate 		    "scsa2usb%d doesn't support minimum required endpoints",
8400Sstevel@tonic-gate 		    instance);
8410Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
8420Sstevel@tonic-gate 
8430Sstevel@tonic-gate 		goto fail;
8440Sstevel@tonic-gate 	}
8450Sstevel@tonic-gate 
8460Sstevel@tonic-gate 	/*
8470Sstevel@tonic-gate 	 * Validate the black-listed attributes
8480Sstevel@tonic-gate 	 */
8490Sstevel@tonic-gate 	scsa2usb_validate_attrs(scsa2usbp);
8500Sstevel@tonic-gate 
8510Sstevel@tonic-gate 	/* Print the serial number from the registration data */
8520Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_dev_data->dev_serial) {
8530Sstevel@tonic-gate 		USB_DPRINTF_L4(DPRINT_MASK_SCSA,
8540Sstevel@tonic-gate 		    scsa2usbp->scsa2usb_log_handle, "Serial Number = %s",
8550Sstevel@tonic-gate 		    scsa2usbp->scsa2usb_dev_data->dev_serial);
8560Sstevel@tonic-gate 	}
8570Sstevel@tonic-gate 
8580Sstevel@tonic-gate 	/*
8590Sstevel@tonic-gate 	 * Allocate a SCSA transport structure
8600Sstevel@tonic-gate 	 */
8610Sstevel@tonic-gate 	tran = scsi_hba_tran_alloc(dip, SCSI_HBA_CANSLEEP);
8620Sstevel@tonic-gate 	scsa2usbp->scsa2usb_tran = tran;
8630Sstevel@tonic-gate 
8640Sstevel@tonic-gate 	/*
8650Sstevel@tonic-gate 	 * initialize transport structure
8660Sstevel@tonic-gate 	 */
8670Sstevel@tonic-gate 	tran->tran_hba_private		= scsa2usbp;
8680Sstevel@tonic-gate 	tran->tran_tgt_private		= NULL;
8690Sstevel@tonic-gate 	tran->tran_tgt_init		= scsa2usb_scsi_tgt_init;
8700Sstevel@tonic-gate 	tran->tran_tgt_probe		= scsa2usb_scsi_tgt_probe;
8710Sstevel@tonic-gate 	tran->tran_tgt_free		= scsa2usb_scsi_tgt_free;
8720Sstevel@tonic-gate 	tran->tran_start		= scsa2usb_scsi_start;
8730Sstevel@tonic-gate 	tran->tran_abort		= scsa2usb_scsi_abort;
8740Sstevel@tonic-gate 	tran->tran_reset		= scsa2usb_scsi_reset;
8750Sstevel@tonic-gate 	tran->tran_getcap		= scsa2usb_scsi_getcap;
8760Sstevel@tonic-gate 	tran->tran_setcap		= scsa2usb_scsi_setcap;
8770Sstevel@tonic-gate 	tran->tran_init_pkt		= scsa2usb_scsi_init_pkt;
8780Sstevel@tonic-gate 	tran->tran_destroy_pkt		= scsa2usb_scsi_destroy_pkt;
8790Sstevel@tonic-gate 	tran->tran_dmafree		= NULL;
8800Sstevel@tonic-gate 	tran->tran_sync_pkt		= NULL;
8810Sstevel@tonic-gate 	tran->tran_reset_notify		= NULL;
8820Sstevel@tonic-gate 	tran->tran_get_bus_addr		= NULL;
8830Sstevel@tonic-gate 	tran->tran_get_name		= NULL;
8840Sstevel@tonic-gate 	tran->tran_quiesce		= NULL;
8850Sstevel@tonic-gate 	tran->tran_unquiesce		= NULL;
8860Sstevel@tonic-gate 	tran->tran_bus_reset		= NULL;
8870Sstevel@tonic-gate 	tran->tran_add_eventcall	= NULL;
8880Sstevel@tonic-gate 	tran->tran_get_eventcookie	= NULL;
8890Sstevel@tonic-gate 	tran->tran_post_event		= NULL;
8900Sstevel@tonic-gate 	tran->tran_remove_eventcall	= NULL;
8910Sstevel@tonic-gate 	tran->tran_bus_config		= scsa2usb_scsi_bus_config;
8920Sstevel@tonic-gate 	tran->tran_bus_unconfig		= scsa2usb_scsi_bus_unconfig;
8930Sstevel@tonic-gate 
8940Sstevel@tonic-gate 	/*
8950Sstevel@tonic-gate 	 * register with SCSA as an HBA
8960Sstevel@tonic-gate 	 * Note that the dma attributes are from parent nexus
8970Sstevel@tonic-gate 	 */
8980Sstevel@tonic-gate 	if (scsi_hba_attach_setup(dip, usba_get_hc_dma_attr(dip), tran, 0)) {
8990Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, log_handle,
9000Sstevel@tonic-gate 		    "scsi_hba_attach_setup failed");
9010Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
9020Sstevel@tonic-gate 
9030Sstevel@tonic-gate 		goto fail;
9040Sstevel@tonic-gate 	}
9050Sstevel@tonic-gate 
9060Sstevel@tonic-gate 	scsa2usbp->scsa2usb_flags |= SCSA2USB_FLAGS_HBA_ATTACH_SETUP;
9070Sstevel@tonic-gate 
9080Sstevel@tonic-gate 	/* create minor node */
9090Sstevel@tonic-gate 	if (ddi_create_minor_node(dip, "scsa2usb", S_IFCHR,
9100Sstevel@tonic-gate 	    instance << SCSA2USB_MINOR_INSTANCE_SHIFT,
9110Sstevel@tonic-gate 	    DDI_NT_SCSI_NEXUS, 0) != DDI_SUCCESS) {
9120Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
9130Sstevel@tonic-gate 		    "scsi_attach: ddi_create_minor_node failed");
9140Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
9150Sstevel@tonic-gate 
9160Sstevel@tonic-gate 		goto fail;
9170Sstevel@tonic-gate 	}
9180Sstevel@tonic-gate 
9190Sstevel@tonic-gate 	/* open pipes and set scsa2usb_flags */
9200Sstevel@tonic-gate 	if (scsa2usb_open_usb_pipes(scsa2usbp) == USB_FAILURE) {
9210Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, log_handle,
9220Sstevel@tonic-gate 		    "error opening pipes");
9230Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
9240Sstevel@tonic-gate 
9250Sstevel@tonic-gate 		goto fail;
9260Sstevel@tonic-gate 	}
9270Sstevel@tonic-gate 
9280Sstevel@tonic-gate 	/* set default block size. updated after read cap cmd */
9290Sstevel@tonic-gate 	for (lun = 0; lun < SCSA2USB_MAX_LUNS; lun++) {
9300Sstevel@tonic-gate 		scsa2usbp->scsa2usb_lbasize[lun] = DEV_BSIZE;
9310Sstevel@tonic-gate 	}
9320Sstevel@tonic-gate 
9330Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
9340Sstevel@tonic-gate 
9350Sstevel@tonic-gate 	/* initialize PANIC callback */
9360Sstevel@tonic-gate 	scsa2usb_panic_callb_init(scsa2usbp);
9370Sstevel@tonic-gate 
9380Sstevel@tonic-gate 	/* finally we are all done 'initializing' the device */
9390Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
9400Sstevel@tonic-gate 	scsa2usbp->scsa2usb_dev_state = USB_DEV_ONLINE;
9410Sstevel@tonic-gate 
9420Sstevel@tonic-gate 	/* enable PM, mutex needs to be held across this */
9430Sstevel@tonic-gate 	scsa2usb_create_pm_components(dip, scsa2usbp);
9440Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
9450Sstevel@tonic-gate 
9460Sstevel@tonic-gate 	/* register for connect/disconnect events */
9470Sstevel@tonic-gate 	if (usb_register_event_cbs(scsa2usbp->scsa2usb_dip, &scsa2usb_events,
9480Sstevel@tonic-gate 	    0) != USB_SUCCESS) {
9490Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, log_handle,
9500Sstevel@tonic-gate 		    "error cb registering");
9510Sstevel@tonic-gate 		goto fail;
9520Sstevel@tonic-gate 	}
9530Sstevel@tonic-gate 
9540Sstevel@tonic-gate 	/* free the dev_data tree, we no longer need it */
9550Sstevel@tonic-gate 	usb_free_descr_tree(dip, dev_data);
9560Sstevel@tonic-gate 
9570Sstevel@tonic-gate 	scsa2usb_pm_idle_component(scsa2usbp);
9580Sstevel@tonic-gate 
9590Sstevel@tonic-gate 	/* log the conf file override string if there is one */
9600Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_override_str) {
961978Sfrits 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
9620Sstevel@tonic-gate 		    "scsa2usb.conf override: %s",
9630Sstevel@tonic-gate 		    scsa2usbp->scsa2usb_override_str);
9640Sstevel@tonic-gate 	}
9650Sstevel@tonic-gate 
9660Sstevel@tonic-gate 	if (usb_owns_device(dip)) {
9670Sstevel@tonic-gate 		/* get a ugen handle */
9680Sstevel@tonic-gate 		bzero(&usb_ugen_info, sizeof (usb_ugen_info));
9690Sstevel@tonic-gate 		usb_ugen_info.usb_ugen_flags = 0;
9700Sstevel@tonic-gate 		usb_ugen_info.usb_ugen_minor_node_ugen_bits_mask =
9714700Sfb209375 		    (dev_t)SCSA2USB_MINOR_UGEN_BITS_MASK;
9720Sstevel@tonic-gate 		usb_ugen_info.usb_ugen_minor_node_instance_mask =
9734700Sfb209375 		    (dev_t)~SCSA2USB_MINOR_UGEN_BITS_MASK;
9740Sstevel@tonic-gate 		scsa2usbp->scsa2usb_ugen_hdl =
9754700Sfb209375 		    usb_ugen_get_hdl(dip, &usb_ugen_info);
9760Sstevel@tonic-gate 
9770Sstevel@tonic-gate 		if (usb_ugen_attach(scsa2usbp->scsa2usb_ugen_hdl, cmd) !=
9780Sstevel@tonic-gate 		    USB_SUCCESS) {
9790Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_SCSA,
9800Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
9810Sstevel@tonic-gate 			    "usb_ugen_attach failed");
9820Sstevel@tonic-gate 
9830Sstevel@tonic-gate 			usb_ugen_release_hdl(scsa2usbp->scsa2usb_ugen_hdl);
9840Sstevel@tonic-gate 			scsa2usbp->scsa2usb_ugen_hdl = NULL;
9850Sstevel@tonic-gate 		}
9860Sstevel@tonic-gate 	}
9870Sstevel@tonic-gate 
9880Sstevel@tonic-gate 	/* report device */
9890Sstevel@tonic-gate 	ddi_report_dev(dip);
9900Sstevel@tonic-gate 
9910Sstevel@tonic-gate 	return (DDI_SUCCESS);
9920Sstevel@tonic-gate 
9930Sstevel@tonic-gate fail:
9940Sstevel@tonic-gate 	if (scsa2usbp) {
9950Sstevel@tonic-gate 		(void) scsa2usb_cleanup(dip, scsa2usbp);
9960Sstevel@tonic-gate 	}
9970Sstevel@tonic-gate 
9980Sstevel@tonic-gate 	return (DDI_FAILURE);
9990Sstevel@tonic-gate }
10000Sstevel@tonic-gate 
10010Sstevel@tonic-gate 
10020Sstevel@tonic-gate /*
10030Sstevel@tonic-gate  * scsa2usb_detach:
10040Sstevel@tonic-gate  *	detach or suspend driver instance
10050Sstevel@tonic-gate  */
10060Sstevel@tonic-gate static int
10070Sstevel@tonic-gate scsa2usb_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
10080Sstevel@tonic-gate {
10090Sstevel@tonic-gate 	scsi_hba_tran_t	*tran;
10100Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp;
10110Sstevel@tonic-gate 	int rval;
10120Sstevel@tonic-gate 
10130Sstevel@tonic-gate 	tran = ddi_get_driver_private(dip);
10140Sstevel@tonic-gate 	ASSERT(tran != NULL);
10150Sstevel@tonic-gate 
10160Sstevel@tonic-gate 	scsa2usbp = (scsa2usb_state_t *)tran->tran_hba_private;
10170Sstevel@tonic-gate 	ASSERT(scsa2usbp);
10180Sstevel@tonic-gate 
10190Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
10206898Sfb209375 	    "scsa2usb_detach: dip = 0x%p, cmd = %d", (void *)dip, cmd);
10210Sstevel@tonic-gate 
10220Sstevel@tonic-gate 	switch (cmd) {
10230Sstevel@tonic-gate 	case DDI_DETACH:
10240Sstevel@tonic-gate 
10250Sstevel@tonic-gate 		if (scsa2usb_cleanup(dip, scsa2usbp) != USB_SUCCESS) {
10260Sstevel@tonic-gate 
10270Sstevel@tonic-gate 			return (DDI_FAILURE);
10280Sstevel@tonic-gate 		}
10290Sstevel@tonic-gate 
10300Sstevel@tonic-gate 		return (DDI_SUCCESS);
10310Sstevel@tonic-gate 	case DDI_SUSPEND:
10320Sstevel@tonic-gate 		rval = scsa2usb_cpr_suspend(dip);
10330Sstevel@tonic-gate 
10340Sstevel@tonic-gate 		return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
10350Sstevel@tonic-gate 	default:
10360Sstevel@tonic-gate 
10370Sstevel@tonic-gate 		return (DDI_FAILURE);
10380Sstevel@tonic-gate 	}
10390Sstevel@tonic-gate }
10400Sstevel@tonic-gate 
10410Sstevel@tonic-gate /*
10420Sstevel@tonic-gate  * ugen support
10430Sstevel@tonic-gate  */
10440Sstevel@tonic-gate /*
10450Sstevel@tonic-gate  * scsa2usb_ugen_open()
10460Sstevel@tonic-gate  * (all ugen opens and pipe opens are by definition exclusive so it is OK
10470Sstevel@tonic-gate  * to count opens)
10480Sstevel@tonic-gate  */
10490Sstevel@tonic-gate static int
10500Sstevel@tonic-gate scsa2usb_ugen_open(dev_t *devp, int flag, int sflag, cred_t *cr)
10510Sstevel@tonic-gate {
10520Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp;
10530Sstevel@tonic-gate 	int		rval;
10540Sstevel@tonic-gate 
10550Sstevel@tonic-gate 	if ((scsa2usbp = ddi_get_soft_state(scsa2usb_statep,
10560Sstevel@tonic-gate 	    SCSA2USB_MINOR_TO_INSTANCE(getminor(*devp)))) == NULL) {
10570Sstevel@tonic-gate 		/* deferred detach */
10580Sstevel@tonic-gate 
10590Sstevel@tonic-gate 		return (ENXIO);
10600Sstevel@tonic-gate 	}
10610Sstevel@tonic-gate 
10620Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
10630Sstevel@tonic-gate 	    "scsa2usb_ugen_open: dev_t=0x%lx", *devp);
10640Sstevel@tonic-gate 
10650Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
10660Sstevel@tonic-gate 
10670Sstevel@tonic-gate 	/* if this is the first ugen open, check on transport busy */
10680Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_ugen_open_count == 0) {
10690Sstevel@tonic-gate 		while (scsa2usbp->scsa2usb_transport_busy ||
10700Sstevel@tonic-gate 		    (scsa2usb_all_waitQs_empty(scsa2usbp) !=
10710Sstevel@tonic-gate 		    USB_SUCCESS)) {
10720Sstevel@tonic-gate 			rval = cv_wait_sig(
10734700Sfb209375 			    &scsa2usbp->scsa2usb_transport_busy_cv,
10744700Sfb209375 			    &scsa2usbp->scsa2usb_mutex);
10750Sstevel@tonic-gate 			if (rval == 0) {
10760Sstevel@tonic-gate 				mutex_exit(&scsa2usbp->scsa2usb_mutex);
10770Sstevel@tonic-gate 
10780Sstevel@tonic-gate 				return (EINTR);
10790Sstevel@tonic-gate 			}
10800Sstevel@tonic-gate 		}
10810Sstevel@tonic-gate 		scsa2usbp->scsa2usb_transport_busy++;
10820Sstevel@tonic-gate 		scsa2usbp->scsa2usb_busy_thread = curthread;
10830Sstevel@tonic-gate 	}
10840Sstevel@tonic-gate 	scsa2usbp->scsa2usb_ugen_open_count++;
10850Sstevel@tonic-gate 
10860Sstevel@tonic-gate 	scsa2usb_raise_power(scsa2usbp);
10870Sstevel@tonic-gate 
10880Sstevel@tonic-gate 	scsa2usb_close_usb_pipes(scsa2usbp);
10890Sstevel@tonic-gate 
10900Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
10910Sstevel@tonic-gate 
10920Sstevel@tonic-gate 	rval = usb_ugen_open(scsa2usbp->scsa2usb_ugen_hdl, devp, flag,
10934700Sfb209375 	    sflag, cr);
10940Sstevel@tonic-gate 
10950Sstevel@tonic-gate 	if (rval) {
10960Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
10970Sstevel@tonic-gate 
10980Sstevel@tonic-gate 		/* reopen the pipes */
10990Sstevel@tonic-gate 		if (--scsa2usbp->scsa2usb_ugen_open_count == 0) {
11000Sstevel@tonic-gate 			scsa2usbp->scsa2usb_transport_busy--;
11010Sstevel@tonic-gate 			scsa2usbp->scsa2usb_busy_thread = NULL;
11020Sstevel@tonic-gate 			cv_signal(&scsa2usbp->scsa2usb_transport_busy_cv);
11030Sstevel@tonic-gate 		}
1104189Sfrits 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
1105189Sfrits 
11060Sstevel@tonic-gate 		scsa2usb_pm_idle_component(scsa2usbp);
11070Sstevel@tonic-gate 	}
11080Sstevel@tonic-gate 
11090Sstevel@tonic-gate 	return (rval);
11100Sstevel@tonic-gate }
11110Sstevel@tonic-gate 
11120Sstevel@tonic-gate 
11130Sstevel@tonic-gate /*
11140Sstevel@tonic-gate  * scsa2usb_ugen_close()
11150Sstevel@tonic-gate  */
11160Sstevel@tonic-gate static int
11170Sstevel@tonic-gate scsa2usb_ugen_close(dev_t dev, int flag, int otype, cred_t *cr)
11180Sstevel@tonic-gate {
11190Sstevel@tonic-gate 	int rval;
11200Sstevel@tonic-gate 
11210Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp = ddi_get_soft_state(scsa2usb_statep,
11224700Sfb209375 	    SCSA2USB_MINOR_TO_INSTANCE(getminor(dev)));
11230Sstevel@tonic-gate 
11240Sstevel@tonic-gate 	if (scsa2usbp == NULL) {
11250Sstevel@tonic-gate 
11260Sstevel@tonic-gate 		return (ENXIO);
11270Sstevel@tonic-gate 	}
11280Sstevel@tonic-gate 
11290Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
11300Sstevel@tonic-gate 	    "scsa2usb_ugen_close: dev_t=0x%lx", dev);
11310Sstevel@tonic-gate 
11320Sstevel@tonic-gate 	rval = usb_ugen_close(scsa2usbp->scsa2usb_ugen_hdl, dev, flag,
11334700Sfb209375 	    otype, cr);
11340Sstevel@tonic-gate 
11350Sstevel@tonic-gate 	if (rval == 0) {
11360Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
11370Sstevel@tonic-gate 
11380Sstevel@tonic-gate 		/* reopen the pipes */
11390Sstevel@tonic-gate 		if (--scsa2usbp->scsa2usb_ugen_open_count == 0) {
11400Sstevel@tonic-gate 			scsa2usbp->scsa2usb_transport_busy--;
11410Sstevel@tonic-gate 			scsa2usbp->scsa2usb_busy_thread = NULL;
11420Sstevel@tonic-gate 			cv_signal(&scsa2usbp->scsa2usb_transport_busy_cv);
11430Sstevel@tonic-gate 		}
1144189Sfrits 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
1145189Sfrits 
11460Sstevel@tonic-gate 		scsa2usb_pm_idle_component(scsa2usbp);
11470Sstevel@tonic-gate 	}
11480Sstevel@tonic-gate 
11490Sstevel@tonic-gate 	return (rval);
11500Sstevel@tonic-gate }
11510Sstevel@tonic-gate 
11520Sstevel@tonic-gate 
11530Sstevel@tonic-gate /*
11540Sstevel@tonic-gate  * scsa2usb_ugen_read/write()
11550Sstevel@tonic-gate  */
11560Sstevel@tonic-gate /*ARGSUSED*/
11570Sstevel@tonic-gate static int
11580Sstevel@tonic-gate scsa2usb_ugen_read(dev_t dev, struct uio *uiop, cred_t *credp)
11590Sstevel@tonic-gate {
11600Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp = ddi_get_soft_state(scsa2usb_statep,
11614700Sfb209375 	    SCSA2USB_MINOR_TO_INSTANCE(getminor(dev)));
11620Sstevel@tonic-gate 
11630Sstevel@tonic-gate 	if (scsa2usbp == NULL) {
11640Sstevel@tonic-gate 
11650Sstevel@tonic-gate 		return (ENXIO);
11660Sstevel@tonic-gate 	}
11670Sstevel@tonic-gate 
11680Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
11690Sstevel@tonic-gate 	    "scsa2usb_ugen_read: dev_t=0x%lx", dev);
11700Sstevel@tonic-gate 
11710Sstevel@tonic-gate 
11720Sstevel@tonic-gate 	return (usb_ugen_read(scsa2usbp->scsa2usb_ugen_hdl, dev,
11734700Sfb209375 	    uiop, credp));
11740Sstevel@tonic-gate }
11750Sstevel@tonic-gate 
11760Sstevel@tonic-gate 
11770Sstevel@tonic-gate /*ARGSUSED*/
11780Sstevel@tonic-gate static int
11790Sstevel@tonic-gate scsa2usb_ugen_write(dev_t dev, struct uio *uiop, cred_t *credp)
11800Sstevel@tonic-gate {
11810Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp = ddi_get_soft_state(scsa2usb_statep,
11824700Sfb209375 	    SCSA2USB_MINOR_TO_INSTANCE(getminor(dev)));
11830Sstevel@tonic-gate 
11840Sstevel@tonic-gate 	if (scsa2usbp == NULL) {
11850Sstevel@tonic-gate 
11860Sstevel@tonic-gate 		return (ENXIO);
11870Sstevel@tonic-gate 	}
11880Sstevel@tonic-gate 
11890Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
11900Sstevel@tonic-gate 	    "scsa2usb_ugen_write: dev_t=0x%lx", dev);
11910Sstevel@tonic-gate 
11920Sstevel@tonic-gate 	return (usb_ugen_write(scsa2usbp->scsa2usb_ugen_hdl,
11934700Sfb209375 	    dev, uiop, credp));
11940Sstevel@tonic-gate }
11950Sstevel@tonic-gate 
11960Sstevel@tonic-gate 
11970Sstevel@tonic-gate /*
11980Sstevel@tonic-gate  * scsa2usb_ugen_poll
11990Sstevel@tonic-gate  */
12000Sstevel@tonic-gate static int
12010Sstevel@tonic-gate scsa2usb_ugen_poll(dev_t dev, short events,
12020Sstevel@tonic-gate     int anyyet,  short *reventsp, struct pollhead **phpp)
12030Sstevel@tonic-gate {
12040Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp = ddi_get_soft_state(scsa2usb_statep,
12054700Sfb209375 	    SCSA2USB_MINOR_TO_INSTANCE(getminor(dev)));
12060Sstevel@tonic-gate 
12070Sstevel@tonic-gate 	if (scsa2usbp == NULL) {
12080Sstevel@tonic-gate 
12090Sstevel@tonic-gate 		return (ENXIO);
12100Sstevel@tonic-gate 	}
12110Sstevel@tonic-gate 
12120Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
12130Sstevel@tonic-gate 	    "scsa2usb_ugen_poll: dev_t=0x%lx", dev);
12140Sstevel@tonic-gate 
12150Sstevel@tonic-gate 	return (usb_ugen_poll(scsa2usbp->scsa2usb_ugen_hdl, dev, events,
12164700Sfb209375 	    anyyet, reventsp, phpp));
12170Sstevel@tonic-gate }
12180Sstevel@tonic-gate 
12190Sstevel@tonic-gate 
12200Sstevel@tonic-gate /*
12210Sstevel@tonic-gate  * scsa2usb_cleanup:
12220Sstevel@tonic-gate  *	cleanup whatever attach has setup
12230Sstevel@tonic-gate  */
12240Sstevel@tonic-gate static int
12250Sstevel@tonic-gate scsa2usb_cleanup(dev_info_t *dip, scsa2usb_state_t *scsa2usbp)
12260Sstevel@tonic-gate {
12270Sstevel@tonic-gate 	int		rval, i;
12280Sstevel@tonic-gate 	scsa2usb_power_t *pm;
12290Sstevel@tonic-gate 	uint_t		lun;
12300Sstevel@tonic-gate 
12310Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
12320Sstevel@tonic-gate 	    "scsa2usb_cleanup:");
12330Sstevel@tonic-gate 
12340Sstevel@tonic-gate 	/* wait till the work thread is done */
12350Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
12360Sstevel@tonic-gate 	for (i = 0; i < SCSA2USB_DRAIN_TIMEOUT; i++) {
12370Sstevel@tonic-gate 		if (scsa2usbp->scsa2usb_work_thread_id == NULL) {
12380Sstevel@tonic-gate 
12390Sstevel@tonic-gate 			break;
12400Sstevel@tonic-gate 		}
12410Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
12420Sstevel@tonic-gate 		delay(drv_usectohz(1000000));
12430Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
12440Sstevel@tonic-gate 	}
12450Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
12460Sstevel@tonic-gate 
12470Sstevel@tonic-gate 	if (i >= SCSA2USB_DRAIN_TIMEOUT) {
12480Sstevel@tonic-gate 
12490Sstevel@tonic-gate 		return (USB_FAILURE);
12500Sstevel@tonic-gate 	}
12510Sstevel@tonic-gate 
12520Sstevel@tonic-gate 	/*
12530Sstevel@tonic-gate 	 * Disable the event callbacks first, after this point, event
12540Sstevel@tonic-gate 	 * callbacks will never get called. Note we shouldn't hold
12550Sstevel@tonic-gate 	 * mutex while unregistering events because there may be a
12560Sstevel@tonic-gate 	 * competing event callback thread. Event callbacks are done
12570Sstevel@tonic-gate 	 * with ndi mutex held and this can cause a potential deadlock.
12580Sstevel@tonic-gate 	 */
12590Sstevel@tonic-gate 	usb_unregister_event_cbs(scsa2usbp->scsa2usb_dip, &scsa2usb_events);
12600Sstevel@tonic-gate 
12610Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_flags & SCSA2USB_FLAGS_LOCKS_INIT) {
12620Sstevel@tonic-gate 		/*
12630Sstevel@tonic-gate 		 * if a waitQ exists, get rid of it before destroying it
12640Sstevel@tonic-gate 		 */
12650Sstevel@tonic-gate 		for (lun = 0; lun < SCSA2USB_MAX_LUNS; lun++) {
12660Sstevel@tonic-gate 			scsa2usb_flush_waitQ(scsa2usbp, lun, CMD_TRAN_ERR);
12670Sstevel@tonic-gate 			usba_destroy_list(&scsa2usbp->scsa2usb_waitQ[lun]);
12680Sstevel@tonic-gate 		}
12690Sstevel@tonic-gate 
12700Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
12710Sstevel@tonic-gate 		if (scsa2usbp->scsa2usb_flags &
12720Sstevel@tonic-gate 		    SCSA2USB_FLAGS_HBA_ATTACH_SETUP) {
12730Sstevel@tonic-gate 			(void) scsi_hba_detach(dip);
12740Sstevel@tonic-gate 			scsi_hba_tran_free(scsa2usbp->scsa2usb_tran);
12750Sstevel@tonic-gate 		}
12760Sstevel@tonic-gate 
12770Sstevel@tonic-gate 		if (scsa2usbp->scsa2usb_flags &
12780Sstevel@tonic-gate 		    SCSA2USB_FLAGS_PIPES_OPENED) {
12790Sstevel@tonic-gate 			scsa2usb_close_usb_pipes(scsa2usbp);
12800Sstevel@tonic-gate 		}
12810Sstevel@tonic-gate 
12820Sstevel@tonic-gate 		/* Lower the power */
12830Sstevel@tonic-gate 		pm = scsa2usbp->scsa2usb_pm;
12840Sstevel@tonic-gate 
12850Sstevel@tonic-gate 		if (pm && (scsa2usbp->scsa2usb_dev_state !=
12860Sstevel@tonic-gate 		    USB_DEV_DISCONNECTED)) {
12870Sstevel@tonic-gate 			if (pm->scsa2usb_wakeup_enabled) {
12880Sstevel@tonic-gate 				mutex_exit(&scsa2usbp->scsa2usb_mutex);
12890Sstevel@tonic-gate 				(void) pm_raise_power(dip, 0,
12904700Sfb209375 				    USB_DEV_OS_FULL_PWR);
12910Sstevel@tonic-gate 
12920Sstevel@tonic-gate 				if ((rval = usb_handle_remote_wakeup(dip,
12930Sstevel@tonic-gate 				    USB_REMOTE_WAKEUP_DISABLE)) !=
12940Sstevel@tonic-gate 				    USB_SUCCESS) {
1295978Sfrits 					USB_DPRINTF_L2(DPRINT_MASK_SCSA,
12960Sstevel@tonic-gate 					    scsa2usbp->scsa2usb_log_handle,
12970Sstevel@tonic-gate 					    "disable remote wakeup failed "
12980Sstevel@tonic-gate 					    "(%d)", rval);
12990Sstevel@tonic-gate 				}
13000Sstevel@tonic-gate 			} else {
13010Sstevel@tonic-gate 				mutex_exit(&scsa2usbp->scsa2usb_mutex);
13020Sstevel@tonic-gate 			}
13030Sstevel@tonic-gate 
13040Sstevel@tonic-gate 			(void) pm_lower_power(dip, 0, USB_DEV_OS_PWR_OFF);
13050Sstevel@tonic-gate 
13060Sstevel@tonic-gate 			mutex_enter(&scsa2usbp->scsa2usb_mutex);
13070Sstevel@tonic-gate 		}
13080Sstevel@tonic-gate 
13090Sstevel@tonic-gate 		if (pm) {
13100Sstevel@tonic-gate 			kmem_free(pm, sizeof (scsa2usb_power_t));
13110Sstevel@tonic-gate 		}
13120Sstevel@tonic-gate 
13130Sstevel@tonic-gate 		if (scsa2usbp->scsa2usb_override_str) {
13140Sstevel@tonic-gate 			kmem_free(scsa2usbp->scsa2usb_override_str,
13150Sstevel@tonic-gate 			    strlen(scsa2usbp->scsa2usb_override_str) + 1);
13160Sstevel@tonic-gate 			scsa2usbp->scsa2usb_override_str = NULL;
13170Sstevel@tonic-gate 		}
13180Sstevel@tonic-gate 
13190Sstevel@tonic-gate 		/* remove the minor nodes */
13200Sstevel@tonic-gate 		ddi_remove_minor_node(dip, NULL);
13210Sstevel@tonic-gate 
13220Sstevel@tonic-gate 		/* Cancel the registered panic callback */
13230Sstevel@tonic-gate 		scsa2usb_panic_callb_fini(scsa2usbp);
13240Sstevel@tonic-gate 
13250Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
13260Sstevel@tonic-gate 
13270Sstevel@tonic-gate 		mutex_destroy(&scsa2usbp->scsa2usb_mutex);
13280Sstevel@tonic-gate 		cv_destroy(&scsa2usbp->scsa2usb_transport_busy_cv);
13290Sstevel@tonic-gate 	}
13300Sstevel@tonic-gate 
13310Sstevel@tonic-gate 	usb_client_detach(scsa2usbp->scsa2usb_dip,
13324700Sfb209375 	    scsa2usbp->scsa2usb_dev_data);
13330Sstevel@tonic-gate 
13340Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_ugen_hdl) {
13350Sstevel@tonic-gate 		(void) usb_ugen_detach(scsa2usbp->scsa2usb_ugen_hdl,
13364700Sfb209375 		    DDI_DETACH);
13370Sstevel@tonic-gate 		usb_ugen_release_hdl(scsa2usbp->scsa2usb_ugen_hdl);
13380Sstevel@tonic-gate 	}
13390Sstevel@tonic-gate 
13400Sstevel@tonic-gate 	usb_free_log_hdl(scsa2usbp->scsa2usb_log_handle);
13410Sstevel@tonic-gate 
13420Sstevel@tonic-gate 	ddi_prop_remove_all(dip);
13430Sstevel@tonic-gate 
13440Sstevel@tonic-gate 	ddi_soft_state_free(scsa2usb_statep, ddi_get_instance(dip));
13450Sstevel@tonic-gate 
13460Sstevel@tonic-gate 	return (USB_SUCCESS);
13470Sstevel@tonic-gate }
13480Sstevel@tonic-gate 
13490Sstevel@tonic-gate 
13500Sstevel@tonic-gate /*
13510Sstevel@tonic-gate  * scsa2usb_override:
13520Sstevel@tonic-gate  *	some devices may be attached even though their subclass or
13530Sstevel@tonic-gate  *	protocol info is not according to spec.
13540Sstevel@tonic-gate  *	these can be determined by the 'subclass-protocol-override'
13550Sstevel@tonic-gate  *	property set in the conf file.
13560Sstevel@tonic-gate  */
13570Sstevel@tonic-gate static void
13580Sstevel@tonic-gate scsa2usb_override(scsa2usb_state_t *scsa2usbp)
13590Sstevel@tonic-gate {
13600Sstevel@tonic-gate 	scsa2usb_ov_t ov;
13610Sstevel@tonic-gate 	char	**override_str = NULL;
13620Sstevel@tonic-gate 	char	*override_str_cpy;
13630Sstevel@tonic-gate 	uint_t	override_str_len, override_str_cpy_len;
13640Sstevel@tonic-gate 	uint_t	i;
13650Sstevel@tonic-gate 	usb_dev_descr_t *descr = scsa2usbp->scsa2usb_dev_data->dev_descr;
13660Sstevel@tonic-gate 
13670Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
13680Sstevel@tonic-gate 
13690Sstevel@tonic-gate 	scsa2usbp->scsa2usb_subclass_override =
13700Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_protocol_override = 0;
13710Sstevel@tonic-gate 
13720Sstevel@tonic-gate 	if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, scsa2usbp->scsa2usb_dip,
13730Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "attribute-override-list",
13740Sstevel@tonic-gate 	    &override_str, &override_str_len) != DDI_PROP_SUCCESS) {
13750Sstevel@tonic-gate 
13760Sstevel@tonic-gate 		return;
13770Sstevel@tonic-gate 	}
13780Sstevel@tonic-gate 
13790Sstevel@tonic-gate 	/* parse each string in the subclass-protocol-override property */
13800Sstevel@tonic-gate 	for (i = 0; i < override_str_len; i++) {
13810Sstevel@tonic-gate 
13820Sstevel@tonic-gate 		USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
13830Sstevel@tonic-gate 		    "override_str[%d] = %s", i, override_str[i]);
13840Sstevel@tonic-gate 
13850Sstevel@tonic-gate 		/*
13860Sstevel@tonic-gate 		 * save a copy of the override string for possible
13870Sstevel@tonic-gate 		 * inclusion in soft state later
13880Sstevel@tonic-gate 		 */
13890Sstevel@tonic-gate 		override_str_cpy_len = strlen(override_str[i]) + 1;
13900Sstevel@tonic-gate 		override_str_cpy = kmem_zalloc(override_str_cpy_len, KM_SLEEP);
13910Sstevel@tonic-gate 		(void) strcpy(override_str_cpy, override_str[i]);
13920Sstevel@tonic-gate 
13930Sstevel@tonic-gate 		bzero(&ov, sizeof (scsa2usb_ov_t));
13940Sstevel@tonic-gate 
13950Sstevel@tonic-gate 		if (scsa2usb_parse_input_str(override_str[i], &ov,
13960Sstevel@tonic-gate 		    scsa2usbp) == USB_FAILURE) {
13970Sstevel@tonic-gate 			kmem_free(override_str_cpy, override_str_cpy_len);
13980Sstevel@tonic-gate 			continue;
13990Sstevel@tonic-gate 		}
14000Sstevel@tonic-gate 
14010Sstevel@tonic-gate 		/*
14020Sstevel@tonic-gate 		 * see if subclass/protocol needs to be overridden for device
14030Sstevel@tonic-gate 		 * or if device should not be power managed
14040Sstevel@tonic-gate 		 * if there'a a match, save the override string in soft state
14050Sstevel@tonic-gate 		 */
14060Sstevel@tonic-gate 		if (((descr->idVendor == (uint16_t)ov.vid) || (ov.vid == 0)) &&
14070Sstevel@tonic-gate 		    ((descr->idProduct == (uint16_t)ov.pid) || (ov.pid == 0)) &&
14080Sstevel@tonic-gate 		    ((descr->bcdDevice == (uint16_t)ov.rev) || (ov.rev == 0))) {
14090Sstevel@tonic-gate 			scsa2usbp->scsa2usb_subclass_override = ov.subclass;
14100Sstevel@tonic-gate 			scsa2usbp->scsa2usb_protocol_override = ov.protocol;
14110Sstevel@tonic-gate 
1412880Sfrits 			USB_DPRINTF_L2(DPRINT_MASK_SCSA,
14130Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
14140Sstevel@tonic-gate 			    "vid=0x%x pid=0x%x rev=0x%x subclass=0x%x "
14150Sstevel@tonic-gate 			    "protocol=0x%x "
14161415Scg149915 			    "pmoff=%d fake_removable=%d modesense=%d "
14170Sstevel@tonic-gate 			    "reduced-cmd-support=%d",
14180Sstevel@tonic-gate 			    ov.vid, ov.pid, ov.rev, ov.subclass, ov.protocol,
14191415Scg149915 			    ov.pmoff, ov.fake_removable, ov.no_modesense,
14200Sstevel@tonic-gate 			    ov.reduced_cmd_support);
14210Sstevel@tonic-gate 
14220Sstevel@tonic-gate 			if (ov.pmoff) {
14230Sstevel@tonic-gate 				scsa2usbp->scsa2usb_attrs &= ~SCSA2USB_ATTRS_PM;
14240Sstevel@tonic-gate 			}
14251415Scg149915 			if (ov.fake_removable) {
14260Sstevel@tonic-gate 				scsa2usbp->scsa2usb_attrs &=
14270Sstevel@tonic-gate 				    ~SCSA2USB_ATTRS_RMB;
14280Sstevel@tonic-gate 			}
14290Sstevel@tonic-gate 			if (ov.no_modesense) {
14300Sstevel@tonic-gate 				scsa2usbp->scsa2usb_attrs &=
14310Sstevel@tonic-gate 				    ~SCSA2USB_ATTRS_MODE_SENSE;
14320Sstevel@tonic-gate 			}
14330Sstevel@tonic-gate 			if (ov.reduced_cmd_support) {
14340Sstevel@tonic-gate 				scsa2usbp->scsa2usb_attrs &=
14350Sstevel@tonic-gate 				    ~SCSA2USB_ATTRS_REDUCED_CMD;
14360Sstevel@tonic-gate 			}
14370Sstevel@tonic-gate 			scsa2usbp->scsa2usb_override_str = override_str_cpy;
14380Sstevel@tonic-gate 			break;
14390Sstevel@tonic-gate 		} else {
14400Sstevel@tonic-gate 			kmem_free(override_str_cpy, override_str_cpy_len);
14410Sstevel@tonic-gate 		}
14420Sstevel@tonic-gate 	}
14430Sstevel@tonic-gate 
14440Sstevel@tonic-gate 	ddi_prop_free(override_str);
14450Sstevel@tonic-gate }
14460Sstevel@tonic-gate 
14470Sstevel@tonic-gate 
14480Sstevel@tonic-gate /*
14490Sstevel@tonic-gate  * scsa2usb_parse_input_str:
14500Sstevel@tonic-gate  *	parse one conf file subclass-protocol-override string
14510Sstevel@tonic-gate  *	return vendor id, product id, revision, subclass, protocol
14520Sstevel@tonic-gate  *	function return is success or failure
14530Sstevel@tonic-gate  */
14540Sstevel@tonic-gate static int
14550Sstevel@tonic-gate scsa2usb_parse_input_str(char *str, scsa2usb_ov_t *ovp,
14560Sstevel@tonic-gate     scsa2usb_state_t *scsa2usbp)
14570Sstevel@tonic-gate {
14580Sstevel@tonic-gate 	char		*input_field, *input_value;
14590Sstevel@tonic-gate 	char		*lasts;
14600Sstevel@tonic-gate 	uint_t		i;
14610Sstevel@tonic-gate 	u_longlong_t	value;
14620Sstevel@tonic-gate 
14630Sstevel@tonic-gate 	/* parse all the input pairs in the string */
14640Sstevel@tonic-gate 	for (input_field = scsa2usb_strtok_r(str, "=", &lasts);
14650Sstevel@tonic-gate 	    input_field != NULL;
14660Sstevel@tonic-gate 	    input_field = scsa2usb_strtok_r(lasts, "=", &lasts)) {
14670Sstevel@tonic-gate 
14680Sstevel@tonic-gate 		if ((input_value = scsa2usb_strtok_r(lasts, " ", &lasts)) ==
14690Sstevel@tonic-gate 		    NULL) {
14700Sstevel@tonic-gate 			scsa2usb_override_error("format", scsa2usbp);
14710Sstevel@tonic-gate 
14720Sstevel@tonic-gate 			return (USB_FAILURE);
14730Sstevel@tonic-gate 		}
14740Sstevel@tonic-gate 		/* if input value is a 'don't care', skip to the next pair */
14750Sstevel@tonic-gate 		if (strcmp(input_value, "*") == 0) {
14760Sstevel@tonic-gate 			continue;
14770Sstevel@tonic-gate 		}
14780Sstevel@tonic-gate 		if (strcasecmp(input_field, "vid") == 0) {
14790Sstevel@tonic-gate 			if (kobj_getvalue(input_value, &value) == -1) {
14800Sstevel@tonic-gate 				scsa2usb_override_error("vendor id", scsa2usbp);
14810Sstevel@tonic-gate 
14820Sstevel@tonic-gate 				return (USB_FAILURE);
14830Sstevel@tonic-gate 			}
14840Sstevel@tonic-gate 			ovp->vid = (int)value;
14850Sstevel@tonic-gate 		} else if (strcasecmp(input_field, "pid") == 0) {
14860Sstevel@tonic-gate 			if (kobj_getvalue(input_value, &value) == -1) {
14870Sstevel@tonic-gate 				scsa2usb_override_error("product id",
14880Sstevel@tonic-gate 				    scsa2usbp);
14890Sstevel@tonic-gate 
14900Sstevel@tonic-gate 				return (USB_FAILURE);
14910Sstevel@tonic-gate 			}
14920Sstevel@tonic-gate 			ovp->pid = (int)value;
14930Sstevel@tonic-gate 		} else if (strcasecmp(input_field, "rev") == 0) {
14940Sstevel@tonic-gate 			if (kobj_getvalue(input_value, &value) == -1) {
14950Sstevel@tonic-gate 				scsa2usb_override_error("revision id",
14960Sstevel@tonic-gate 				    scsa2usbp);
14970Sstevel@tonic-gate 
14980Sstevel@tonic-gate 				return (USB_FAILURE);
14990Sstevel@tonic-gate 			}
15000Sstevel@tonic-gate 			ovp->rev = (int)value;
15010Sstevel@tonic-gate 		} else if (strcasecmp(input_field, "subclass") == 0) {
15020Sstevel@tonic-gate 			for (i = 0; i < N_SCSA2USB_SUBC_OVERRIDE; i++) {
15030Sstevel@tonic-gate 				if (strcasecmp(input_value,
15040Sstevel@tonic-gate 				    scsa2usb_subclass[i].name) == 0) {
15050Sstevel@tonic-gate 					ovp->subclass =
15060Sstevel@tonic-gate 					    scsa2usb_subclass[i].value;
15070Sstevel@tonic-gate 					break;
15080Sstevel@tonic-gate 				}
15090Sstevel@tonic-gate 			}
15100Sstevel@tonic-gate 			if (ovp->subclass == 0) {
15110Sstevel@tonic-gate 				scsa2usb_override_error("subclass", scsa2usbp);
15120Sstevel@tonic-gate 
15130Sstevel@tonic-gate 				return (USB_FAILURE);
15140Sstevel@tonic-gate 			}
15150Sstevel@tonic-gate 		} else if (strcasecmp(input_field, "protocol") == 0) {
15160Sstevel@tonic-gate 			for (i = 0; i < N_SCSA2USB_PROT_OVERRIDE; i++) {
15170Sstevel@tonic-gate 				if (strcasecmp(input_value,
15180Sstevel@tonic-gate 				    scsa2usb_protocol[i].name) == 0) {
15190Sstevel@tonic-gate 					ovp->protocol =
15200Sstevel@tonic-gate 					    scsa2usb_protocol[i].value;
15210Sstevel@tonic-gate 					break;
15220Sstevel@tonic-gate 				}
15230Sstevel@tonic-gate 			}
15240Sstevel@tonic-gate 			if (ovp->protocol == 0) {
15250Sstevel@tonic-gate 				scsa2usb_override_error("protocol", scsa2usbp);
15260Sstevel@tonic-gate 
15270Sstevel@tonic-gate 				return (USB_FAILURE);
15280Sstevel@tonic-gate 			}
15290Sstevel@tonic-gate 		} else if (strcasecmp(input_field, "pm") == 0) {
15300Sstevel@tonic-gate 			if (strcasecmp(input_value, "off") == 0) {
15310Sstevel@tonic-gate 				ovp->pmoff = 1;
15320Sstevel@tonic-gate 				break;
15330Sstevel@tonic-gate 			} else {
15340Sstevel@tonic-gate 				scsa2usb_override_error("pm", scsa2usbp);
15350Sstevel@tonic-gate 
15360Sstevel@tonic-gate 				return (USB_FAILURE);
15370Sstevel@tonic-gate 			}
15380Sstevel@tonic-gate 		} else if (strcasecmp(input_field, "removable") == 0) {
15391415Scg149915 			if (strcasecmp(input_value, "true") == 0) {
15401415Scg149915 				ovp->fake_removable = 1;
15410Sstevel@tonic-gate 				break;
15420Sstevel@tonic-gate 			} else {
15430Sstevel@tonic-gate 				scsa2usb_override_error("removable", scsa2usbp);
15440Sstevel@tonic-gate 
15450Sstevel@tonic-gate 				return (USB_FAILURE);
15460Sstevel@tonic-gate 			}
15470Sstevel@tonic-gate 		} else if (strcasecmp(input_field, "modesense") == 0) {
15480Sstevel@tonic-gate 			if (strcasecmp(input_value, "false") == 0) {
15490Sstevel@tonic-gate 				ovp->no_modesense = 1;
15500Sstevel@tonic-gate 				break;
15510Sstevel@tonic-gate 			} else {
15520Sstevel@tonic-gate 				scsa2usb_override_error("modesense",
15534700Sfb209375 				    scsa2usbp);
15540Sstevel@tonic-gate 
15550Sstevel@tonic-gate 				return (USB_FAILURE);
15560Sstevel@tonic-gate 			}
15570Sstevel@tonic-gate 		} else if (strcasecmp(input_field,
15580Sstevel@tonic-gate 		    "reduced-cmd-support") == 0) {
15590Sstevel@tonic-gate 			if (strcasecmp(input_value, "true") == 0) {
15600Sstevel@tonic-gate 				ovp->reduced_cmd_support = 1;
15610Sstevel@tonic-gate 				break;
15620Sstevel@tonic-gate 			} else {
15630Sstevel@tonic-gate 				scsa2usb_override_error(
15640Sstevel@tonic-gate 				    "reduced-cmd-support", scsa2usbp);
15650Sstevel@tonic-gate 
15660Sstevel@tonic-gate 				return (USB_FAILURE);
15670Sstevel@tonic-gate 			}
15680Sstevel@tonic-gate 		} else {
1569880Sfrits 			scsa2usb_override_error(input_field, scsa2usbp);
15700Sstevel@tonic-gate 
15710Sstevel@tonic-gate 			return (USB_FAILURE);
15720Sstevel@tonic-gate 		}
15730Sstevel@tonic-gate 	}
15740Sstevel@tonic-gate 
15750Sstevel@tonic-gate 	return (USB_SUCCESS);
15760Sstevel@tonic-gate }
15770Sstevel@tonic-gate 
15780Sstevel@tonic-gate 
15790Sstevel@tonic-gate /*
15800Sstevel@tonic-gate  * scsa2usb_override_error:
15810Sstevel@tonic-gate  *	print an error message if conf file string is bad format
15820Sstevel@tonic-gate  */
15830Sstevel@tonic-gate static void
15840Sstevel@tonic-gate scsa2usb_override_error(char *input_field, scsa2usb_state_t *scsa2usbp)
15850Sstevel@tonic-gate {
15860Sstevel@tonic-gate 	USB_DPRINTF_L1(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
1587880Sfrits 	    "invalid %s in scsa2usb.conf file entry", input_field);
15880Sstevel@tonic-gate }
15890Sstevel@tonic-gate 
15900Sstevel@tonic-gate /*
15910Sstevel@tonic-gate  * scsa2usb_strtok_r:
15920Sstevel@tonic-gate  *	parse a list of tokens
15930Sstevel@tonic-gate  */
15940Sstevel@tonic-gate static char *
15950Sstevel@tonic-gate scsa2usb_strtok_r(char *p, char *sep, char **lasts)
15960Sstevel@tonic-gate {
15970Sstevel@tonic-gate 	char	*e;
15980Sstevel@tonic-gate 	char	*tok = NULL;
15990Sstevel@tonic-gate 
16000Sstevel@tonic-gate 	if (p == 0 || *p == 0) {
16010Sstevel@tonic-gate 
16020Sstevel@tonic-gate 		return (NULL);
16030Sstevel@tonic-gate 	}
16040Sstevel@tonic-gate 
16050Sstevel@tonic-gate 	e = p+strlen(p);
16060Sstevel@tonic-gate 
16070Sstevel@tonic-gate 	do {
16080Sstevel@tonic-gate 		if (strchr(sep, *p) != NULL) {
16090Sstevel@tonic-gate 			if (tok != NULL) {
16100Sstevel@tonic-gate 				*p = 0;
16110Sstevel@tonic-gate 				*lasts = p+1;
16120Sstevel@tonic-gate 
16130Sstevel@tonic-gate 				return (tok);
16140Sstevel@tonic-gate 			}
16150Sstevel@tonic-gate 		} else if (tok == NULL) {
16160Sstevel@tonic-gate 			tok = p;
16170Sstevel@tonic-gate 		}
16180Sstevel@tonic-gate 	} while (++p < e);
16190Sstevel@tonic-gate 
16200Sstevel@tonic-gate 	*lasts = NULL;
16210Sstevel@tonic-gate 
16220Sstevel@tonic-gate 	return (tok);
16230Sstevel@tonic-gate }
16240Sstevel@tonic-gate 
16250Sstevel@tonic-gate 
16260Sstevel@tonic-gate /*
16270Sstevel@tonic-gate  * scsa2usb_validate_attrs:
16280Sstevel@tonic-gate  *	many devices have BO/CB/CBI protocol support issues.
16290Sstevel@tonic-gate  *	use vendor/product info to reset the
16300Sstevel@tonic-gate  *	individual erroneous attributes
16310Sstevel@tonic-gate  *
16320Sstevel@tonic-gate  * NOTE: we look at only device at a time (at attach time)
16330Sstevel@tonic-gate  */
16340Sstevel@tonic-gate static void
16350Sstevel@tonic-gate scsa2usb_validate_attrs(scsa2usb_state_t *scsa2usbp)
16360Sstevel@tonic-gate {
16370Sstevel@tonic-gate 	int i, mask;
16380Sstevel@tonic-gate 	usb_dev_descr_t *desc = scsa2usbp->scsa2usb_dev_data->dev_descr;
16390Sstevel@tonic-gate 
16400Sstevel@tonic-gate 	if (!SCSA2USB_IS_BULK_ONLY(scsa2usbp)) {
16410Sstevel@tonic-gate 		scsa2usbp->scsa2usb_attrs &= ~SCSA2USB_ATTRS_GET_LUN;
16420Sstevel@tonic-gate 	}
16430Sstevel@tonic-gate 
16440Sstevel@tonic-gate 	/* determine if this device is on the blacklist */
16450Sstevel@tonic-gate 	for (i = 0; i < N_SCSA2USB_BLACKLIST; i++) {
16460Sstevel@tonic-gate 		if ((scsa2usb_blacklist[i].idVendor == desc->idVendor) &&
16470Sstevel@tonic-gate 		    ((scsa2usb_blacklist[i].idProduct == desc->idProduct) ||
16480Sstevel@tonic-gate 		    (scsa2usb_blacklist[i].idProduct == X))) {
16490Sstevel@tonic-gate 			scsa2usbp->scsa2usb_attrs &=
16504700Sfb209375 			    ~(scsa2usb_blacklist[i].attributes);
16510Sstevel@tonic-gate 			break;
16520Sstevel@tonic-gate 		}
16530Sstevel@tonic-gate 	}
16540Sstevel@tonic-gate 
16550Sstevel@tonic-gate 	/*
16560Sstevel@tonic-gate 	 * Mitsumi's CD-RW drives subclass isn't UFI.
16570Sstevel@tonic-gate 	 * But they support UFI command-set (this code ensures that)
16580Sstevel@tonic-gate 	 * NOTE: This is a special case, and is being called out so.
16590Sstevel@tonic-gate 	 */
16600Sstevel@tonic-gate 	if (desc->idVendor == MS_MITSUMI_VID) {
16610Sstevel@tonic-gate 		mask = scsa2usbp->scsa2usb_cmd_protocol & SCSA2USB_CMDSET_MASK;
16620Sstevel@tonic-gate 		if (mask) {
16630Sstevel@tonic-gate 			scsa2usbp->scsa2usb_cmd_protocol &= ~mask;
16640Sstevel@tonic-gate 		}
16650Sstevel@tonic-gate 		scsa2usbp->scsa2usb_cmd_protocol |= SCSA2USB_UFI_CMDSET;
16660Sstevel@tonic-gate 	}
16670Sstevel@tonic-gate 
16680Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_attrs != SCSA2USB_ALL_ATTRS) {
16690Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA,
16700Sstevel@tonic-gate 		    scsa2usbp->scsa2usb_log_handle,
16710Sstevel@tonic-gate 		    "scsa2usb attributes modified: 0x%x",
16720Sstevel@tonic-gate 		    scsa2usbp->scsa2usb_attrs);
16730Sstevel@tonic-gate 	}
16740Sstevel@tonic-gate }
16750Sstevel@tonic-gate 
16760Sstevel@tonic-gate 
16770Sstevel@tonic-gate /*
16780Sstevel@tonic-gate  * scsa2usb_create_luns:
16790Sstevel@tonic-gate  *	check the number of luns but continue if the check fails,
16800Sstevel@tonic-gate  *	create child nodes for each lun
16810Sstevel@tonic-gate  */
16820Sstevel@tonic-gate static void
16830Sstevel@tonic-gate scsa2usb_create_luns(scsa2usb_state_t *scsa2usbp)
16840Sstevel@tonic-gate {
16850Sstevel@tonic-gate 	int		lun, rval;
16860Sstevel@tonic-gate 	char		*compatible[MAX_COMPAT_NAMES];	/* compatible names */
16870Sstevel@tonic-gate 	dev_info_t	*cdip;
16880Sstevel@tonic-gate 	uchar_t		dtype;
16890Sstevel@tonic-gate 	char		*node_name;
16900Sstevel@tonic-gate 	char		*driver_name = NULL;
16910Sstevel@tonic-gate 
16920Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
16930Sstevel@tonic-gate 	    "scsa2usb_create_luns:");
16940Sstevel@tonic-gate 
16950Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
16960Sstevel@tonic-gate 
16970Sstevel@tonic-gate 	/* Set n_luns to 1 by default (for floppies and other devices) */
16980Sstevel@tonic-gate 	scsa2usbp->scsa2usb_n_luns = 1;
16990Sstevel@tonic-gate 
17000Sstevel@tonic-gate 	/*
17010Sstevel@tonic-gate 	 * Check if there are any device out there which don't
17020Sstevel@tonic-gate 	 * support the GET_MAX_LUN command. If so, don't issue
17030Sstevel@tonic-gate 	 * control request to them.
17040Sstevel@tonic-gate 	 */
17050Sstevel@tonic-gate 	if ((scsa2usbp->scsa2usb_attrs & SCSA2USB_ATTRS_GET_LUN) == 0) {
17069729SBinzi.Cao@Sun.COM 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
17070Sstevel@tonic-gate 		    "get_max_lun cmd not supported");
17080Sstevel@tonic-gate 	} else {
17090Sstevel@tonic-gate 		if (SCSA2USB_IS_BULK_ONLY(scsa2usbp)) {
17100Sstevel@tonic-gate 			scsa2usbp->scsa2usb_n_luns =
17114700Sfb209375 			    scsa2usb_bulk_only_get_max_lun(scsa2usbp);
17120Sstevel@tonic-gate 		}
17130Sstevel@tonic-gate 	}
17140Sstevel@tonic-gate 
17150Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
17160Sstevel@tonic-gate 	    "scsa2usb_create_luns: %d luns found", scsa2usbp->scsa2usb_n_luns);
17170Sstevel@tonic-gate 
17180Sstevel@tonic-gate 	/*
17190Sstevel@tonic-gate 	 * create disk child for each lun
17200Sstevel@tonic-gate 	 */
17210Sstevel@tonic-gate 	for (lun = 0; lun < scsa2usbp->scsa2usb_n_luns; lun++) {
17220Sstevel@tonic-gate 		ASSERT(scsa2usbp->scsa2usb_lun_dip[lun] == NULL);
17230Sstevel@tonic-gate 
17240Sstevel@tonic-gate 		/* do an inquiry to get the dtype of this lun */
17250Sstevel@tonic-gate 		scsa2usb_do_inquiry(scsa2usbp, 0, lun);
17260Sstevel@tonic-gate 
17270Sstevel@tonic-gate 		dtype = scsa2usbp->scsa2usb_lun_inquiry[lun].
17284700Sfb209375 		    inq_dtype & DTYPE_MASK;
17290Sstevel@tonic-gate 
17300Sstevel@tonic-gate 		USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
17310Sstevel@tonic-gate 		    "dtype[%d]=0x%x", lun, dtype);
17320Sstevel@tonic-gate 
17330Sstevel@tonic-gate 		driver_name = NULL;
17340Sstevel@tonic-gate 
17350Sstevel@tonic-gate 		switch (dtype) {
17360Sstevel@tonic-gate 		case DTYPE_DIRECT:
17370Sstevel@tonic-gate 		case DTYPE_RODIRECT:
17380Sstevel@tonic-gate 		case DTYPE_OPTICAL:
17390Sstevel@tonic-gate 			node_name = "disk";
17400Sstevel@tonic-gate 			driver_name = "sd";
17410Sstevel@tonic-gate 
17420Sstevel@tonic-gate 			break;
17430Sstevel@tonic-gate 		case DTYPE_SEQUENTIAL:
17440Sstevel@tonic-gate 			node_name = "tape";
17450Sstevel@tonic-gate 			driver_name = "st";
17460Sstevel@tonic-gate 
17470Sstevel@tonic-gate 			break;
17480Sstevel@tonic-gate 		case DTYPE_PRINTER:
17490Sstevel@tonic-gate 			node_name = "printer";
17500Sstevel@tonic-gate 
17510Sstevel@tonic-gate 			break;
17520Sstevel@tonic-gate 		case DTYPE_PROCESSOR:
17530Sstevel@tonic-gate 			node_name = "processor";
17540Sstevel@tonic-gate 
17550Sstevel@tonic-gate 			break;
17560Sstevel@tonic-gate 		case DTYPE_WORM:
17570Sstevel@tonic-gate 			node_name = "worm";
17580Sstevel@tonic-gate 
17590Sstevel@tonic-gate 			break;
17600Sstevel@tonic-gate 		case DTYPE_SCANNER:
17610Sstevel@tonic-gate 			node_name = "scanner";
17620Sstevel@tonic-gate 
17630Sstevel@tonic-gate 			break;
17640Sstevel@tonic-gate 		case DTYPE_CHANGER:
17650Sstevel@tonic-gate 			node_name = "changer";
17660Sstevel@tonic-gate 
17670Sstevel@tonic-gate 			break;
17680Sstevel@tonic-gate 		case DTYPE_COMM:
17690Sstevel@tonic-gate 			node_name = "comm";
17700Sstevel@tonic-gate 
17710Sstevel@tonic-gate 			break;
17720Sstevel@tonic-gate 		case DTYPE_ARRAY_CTRL:
17730Sstevel@tonic-gate 			node_name = "array_ctrl";
17740Sstevel@tonic-gate 
17750Sstevel@tonic-gate 			break;
17760Sstevel@tonic-gate 		case DTYPE_ESI:
17770Sstevel@tonic-gate 			node_name = "esi";
17780Sstevel@tonic-gate 			driver_name = "ses";
17790Sstevel@tonic-gate 
17800Sstevel@tonic-gate 			break;
17810Sstevel@tonic-gate 		default:
17820Sstevel@tonic-gate 			node_name = "generic";
17830Sstevel@tonic-gate 
17840Sstevel@tonic-gate 			break;
17850Sstevel@tonic-gate 		}
17860Sstevel@tonic-gate 
17870Sstevel@tonic-gate 		if (driver_name) {
17880Sstevel@tonic-gate 			compatible[0] = driver_name;
17890Sstevel@tonic-gate 		}
17900Sstevel@tonic-gate 
17910Sstevel@tonic-gate 		ndi_devi_alloc_sleep(scsa2usbp->scsa2usb_dip, node_name,
1792789Sahrens 		    (pnode_t)DEVI_SID_NODEID, &cdip);
17930Sstevel@tonic-gate 
17940Sstevel@tonic-gate 		/* attach target & lun properties */
17950Sstevel@tonic-gate 		rval = ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "target", 0);
17960Sstevel@tonic-gate 		if (rval != DDI_PROP_SUCCESS) {
17970Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_SCSA,
17980Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
17990Sstevel@tonic-gate 			    "ndi_prop_update_int target failed %d", rval);
18000Sstevel@tonic-gate 			(void) ndi_devi_free(cdip);
18010Sstevel@tonic-gate 			continue;
18020Sstevel@tonic-gate 		}
18030Sstevel@tonic-gate 
18041415Scg149915 		rval = ndi_prop_create_boolean(DDI_DEV_T_NONE, cdip,
18051415Scg149915 		    "hotpluggable");
18061415Scg149915 		if (rval != DDI_PROP_SUCCESS) {
18071415Scg149915 			USB_DPRINTF_L2(DPRINT_MASK_SCSA,
18081415Scg149915 			    scsa2usbp->scsa2usb_log_handle,
18091415Scg149915 			    "ndi_prop_create_boolean hotpluggable failed %d",
18101415Scg149915 			    rval);
18111415Scg149915 			ddi_prop_remove_all(cdip);
18121415Scg149915 			(void) ndi_devi_free(cdip);
18131415Scg149915 			continue;
18141415Scg149915 		}
18151415Scg149915 		/*
18161415Scg149915 		 * Some devices don't support LOG SENSE, so tells
18171415Scg149915 		 * sd driver not to send this command.
18181415Scg149915 		 */
18191415Scg149915 		rval = ndi_prop_update_int(DDI_DEV_T_NONE, cdip,
18201415Scg149915 		    "pm-capable", 1);
18211415Scg149915 		if (rval != DDI_PROP_SUCCESS) {
18221415Scg149915 			USB_DPRINTF_L2(DPRINT_MASK_SCSA,
18231415Scg149915 			    scsa2usbp->scsa2usb_log_handle,
18241415Scg149915 			    "ndi_prop_update_int pm-capable failed %d", rval);
18251415Scg149915 			ddi_prop_remove_all(cdip);
18261415Scg149915 			(void) ndi_devi_free(cdip);
18271415Scg149915 			continue;
18281415Scg149915 		}
18291415Scg149915 
18300Sstevel@tonic-gate 		rval = ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "lun", lun);
18310Sstevel@tonic-gate 		if (rval != DDI_PROP_SUCCESS) {
18320Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_SCSA,
18330Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
18340Sstevel@tonic-gate 			    "ndi_prop_update_int lun failed %d", rval);
18350Sstevel@tonic-gate 			ddi_prop_remove_all(cdip);
18360Sstevel@tonic-gate 			(void) ndi_devi_free(cdip);
18370Sstevel@tonic-gate 			continue;
18380Sstevel@tonic-gate 		}
18390Sstevel@tonic-gate 
18400Sstevel@tonic-gate 		if (driver_name) {
18410Sstevel@tonic-gate 			rval = ndi_prop_update_string_array(DDI_DEV_T_NONE,
18420Sstevel@tonic-gate 			    cdip, "compatible", (char **)compatible,
18430Sstevel@tonic-gate 			    MAX_COMPAT_NAMES);
18440Sstevel@tonic-gate 			if (rval != DDI_PROP_SUCCESS) {
18450Sstevel@tonic-gate 				USB_DPRINTF_L2(DPRINT_MASK_SCSA,
18460Sstevel@tonic-gate 				    scsa2usbp->scsa2usb_log_handle,
18470Sstevel@tonic-gate 				    "ndi_prop_update_string_array failed %d",
18480Sstevel@tonic-gate 				    rval);
18490Sstevel@tonic-gate 				ddi_prop_remove_all(cdip);
18500Sstevel@tonic-gate 				(void) ndi_devi_free(cdip);
18510Sstevel@tonic-gate 				continue;
18520Sstevel@tonic-gate 			}
18530Sstevel@tonic-gate 		}
18540Sstevel@tonic-gate 
18550Sstevel@tonic-gate 		/*
18560Sstevel@tonic-gate 		 * add property "usb" so we always verify that it is our child
18570Sstevel@tonic-gate 		 */
18580Sstevel@tonic-gate 		rval = ndi_prop_create_boolean(DDI_DEV_T_NONE, cdip, "usb");
18590Sstevel@tonic-gate 		if (rval != DDI_PROP_SUCCESS) {
18600Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_SCSA,
18610Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
18620Sstevel@tonic-gate 			    "ndi_prop_create_boolean failed %d", rval);
18630Sstevel@tonic-gate 			ddi_prop_remove_all(cdip);
18640Sstevel@tonic-gate 			(void) ndi_devi_free(cdip);
18650Sstevel@tonic-gate 			continue;
18660Sstevel@tonic-gate 		}
18670Sstevel@tonic-gate 
18680Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
18690Sstevel@tonic-gate 		(void) ddi_initchild(scsa2usbp->scsa2usb_dip, cdip);
18700Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
18710Sstevel@tonic-gate 
18720Sstevel@tonic-gate 		usba_set_usba_device(cdip,
18734700Sfb209375 		    usba_get_usba_device(scsa2usbp->scsa2usb_dip));
18740Sstevel@tonic-gate 	}
18750Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
18760Sstevel@tonic-gate }
18770Sstevel@tonic-gate 
18780Sstevel@tonic-gate 
18790Sstevel@tonic-gate /*
18800Sstevel@tonic-gate  * scsa2usb_is_usb:
18810Sstevel@tonic-gate  *	scsa2usb gets called for all possible sd children.
18820Sstevel@tonic-gate  *	we can only accept usb children
18830Sstevel@tonic-gate  */
18840Sstevel@tonic-gate static int
18850Sstevel@tonic-gate scsa2usb_is_usb(dev_info_t *dip)
18860Sstevel@tonic-gate {
18870Sstevel@tonic-gate 	if (dip) {
18880Sstevel@tonic-gate 		return (ddi_prop_exists(DDI_DEV_T_ANY, dip,
18890Sstevel@tonic-gate 		    DDI_PROP_DONTPASS, "usb"));
18900Sstevel@tonic-gate 	}
18910Sstevel@tonic-gate 	return (0);
18920Sstevel@tonic-gate }
18930Sstevel@tonic-gate 
18940Sstevel@tonic-gate 
18950Sstevel@tonic-gate /*
18960Sstevel@tonic-gate  * Panic Stuff
18970Sstevel@tonic-gate  * scsa2usb_panic_callb_init:
18980Sstevel@tonic-gate  *	initialize PANIC callb and free allocated resources
18990Sstevel@tonic-gate  */
19000Sstevel@tonic-gate static void
19010Sstevel@tonic-gate scsa2usb_panic_callb_init(scsa2usb_state_t *scsa2usbp)
19020Sstevel@tonic-gate {
19030Sstevel@tonic-gate 	/*
19040Sstevel@tonic-gate 	 * In case the system panics, the sync command flushes
19050Sstevel@tonic-gate 	 * dirty FS pages or buffers. This would cause a hang
19060Sstevel@tonic-gate 	 * in USB.
19070Sstevel@tonic-gate 	 * The reason for the failure is that we enter
19080Sstevel@tonic-gate 	 * polled mode (interrupts disabled) and HCD gets stuck
19090Sstevel@tonic-gate 	 * trying to execute bulk requests
19100Sstevel@tonic-gate 	 * The panic_callback registered below provides a warning
19110Sstevel@tonic-gate 	 * that a panic has occurred and from that point onwards, we
19120Sstevel@tonic-gate 	 * complete each request successfully and immediately. This
19130Sstevel@tonic-gate 	 * will fake successful syncing so at least the rest of the
19140Sstevel@tonic-gate 	 * filesystems complete syncing.
19150Sstevel@tonic-gate 	 */
19160Sstevel@tonic-gate 	scsa2usbp->scsa2usb_panic_info =
19174700Sfb209375 	    kmem_zalloc(sizeof (scsa2usb_cpr_t), KM_SLEEP);
19180Sstevel@tonic-gate 	mutex_init(&scsa2usbp->scsa2usb_panic_info->lockp,
19194700Sfb209375 	    NULL, MUTEX_DRIVER,
19204700Sfb209375 	    scsa2usbp->scsa2usb_dev_data->dev_iblock_cookie);
19210Sstevel@tonic-gate 	scsa2usbp->scsa2usb_panic_info->statep = scsa2usbp;
19220Sstevel@tonic-gate 	scsa2usbp->scsa2usb_panic_info->cpr.cc_lockp =
19234700Sfb209375 	    &scsa2usbp->scsa2usb_panic_info->lockp;
19240Sstevel@tonic-gate 	scsa2usbp->scsa2usb_panic_info->cpr.cc_id =
19254700Sfb209375 	    callb_add(scsa2usb_panic_callb,
19264700Sfb209375 	    (void *)scsa2usbp->scsa2usb_panic_info,
19274700Sfb209375 	    CB_CL_PANIC, "scsa2usb");
19280Sstevel@tonic-gate }
19290Sstevel@tonic-gate 
19300Sstevel@tonic-gate 
19310Sstevel@tonic-gate /*
19320Sstevel@tonic-gate  * scsa2usb_panic_callb_fini:
19330Sstevel@tonic-gate  *	cancel out PANIC callb and free allocated resources
19340Sstevel@tonic-gate  */
19350Sstevel@tonic-gate static void
19360Sstevel@tonic-gate scsa2usb_panic_callb_fini(scsa2usb_state_t *scsa2usbp)
19370Sstevel@tonic-gate {
19380Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_panic_info) {
19390Sstevel@tonic-gate 		SCSA2USB_CANCEL_CB(scsa2usbp->scsa2usb_panic_info->cpr.cc_id);
19400Sstevel@tonic-gate 		mutex_destroy(&scsa2usbp->scsa2usb_panic_info->lockp);
19410Sstevel@tonic-gate 		scsa2usbp->scsa2usb_panic_info->statep = NULL;
19420Sstevel@tonic-gate 		kmem_free(scsa2usbp->scsa2usb_panic_info,
19430Sstevel@tonic-gate 		    sizeof (scsa2usb_cpr_t));
19440Sstevel@tonic-gate 		scsa2usbp->scsa2usb_panic_info = NULL;
19450Sstevel@tonic-gate 	}
19460Sstevel@tonic-gate }
19470Sstevel@tonic-gate 
19480Sstevel@tonic-gate 
19490Sstevel@tonic-gate /*
19500Sstevel@tonic-gate  * scsa2usb_panic_callb:
19510Sstevel@tonic-gate  *	This routine is called when there is a system panic.
19520Sstevel@tonic-gate  */
19530Sstevel@tonic-gate /* ARGSUSED */
19540Sstevel@tonic-gate static boolean_t
19550Sstevel@tonic-gate scsa2usb_panic_callb(void *arg, int code)
19560Sstevel@tonic-gate {
19570Sstevel@tonic-gate 	scsa2usb_cpr_t *cpr_infop;
19580Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp;
19590Sstevel@tonic-gate 	uint_t		lun;
19600Sstevel@tonic-gate 
19610Sstevel@tonic-gate 	_NOTE(NO_COMPETING_THREADS_NOW);
19620Sstevel@tonic-gate 	cpr_infop = (scsa2usb_cpr_t *)arg;
19630Sstevel@tonic-gate 	scsa2usbp = (scsa2usb_state_t *)cpr_infop->statep;
19640Sstevel@tonic-gate 
19650Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
19660Sstevel@tonic-gate 	    "scsa2usb_panic_callb: code=%d", code);
19670Sstevel@tonic-gate 
19680Sstevel@tonic-gate 	/*
19690Sstevel@tonic-gate 	 * If we return error here, "sd" prints lots of error
19700Sstevel@tonic-gate 	 * messages and could retry the same pkt over and over again.
19710Sstevel@tonic-gate 	 * The sync recovery isn't "smooth" in that case. By faking
19720Sstevel@tonic-gate 	 * a success return, instead,  we force sync to complete.
19730Sstevel@tonic-gate 	 */
19740Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_cur_pkt) {
19750Sstevel@tonic-gate 		/*
19760Sstevel@tonic-gate 		 * Do not print the "no sync" warning here. it will then be
19770Sstevel@tonic-gate 		 * displayed before we actually start syncing. Also we don't
19780Sstevel@tonic-gate 		 * replace this code with a call to scsa2usb_pkt_completion().
19790Sstevel@tonic-gate 		 * NOTE: mutexes are disabled during panic.
19800Sstevel@tonic-gate 		 */
19810Sstevel@tonic-gate 		scsa2usbp->scsa2usb_cur_pkt->pkt_reason = CMD_CMPLT;
19820Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
19830Sstevel@tonic-gate 		scsa2usb_pkt_completion(scsa2usbp, scsa2usbp->scsa2usb_cur_pkt);
19840Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
19850Sstevel@tonic-gate 	}
19860Sstevel@tonic-gate 
19870Sstevel@tonic-gate 	/* get rid of waitQ */
19880Sstevel@tonic-gate 	for (lun = 0; lun < SCSA2USB_MAX_LUNS; lun++) {
19890Sstevel@tonic-gate 		scsa2usb_flush_waitQ(scsa2usbp, lun, CMD_CMPLT);
19900Sstevel@tonic-gate 	}
19910Sstevel@tonic-gate 
19922840Scarlsonj #ifndef lint
19930Sstevel@tonic-gate 	_NOTE(COMPETING_THREADS_NOW);
19942840Scarlsonj #endif
19950Sstevel@tonic-gate 
19960Sstevel@tonic-gate 	return (B_TRUE);
19970Sstevel@tonic-gate }
19980Sstevel@tonic-gate 
19990Sstevel@tonic-gate /*
20000Sstevel@tonic-gate  * scsa2usb_cpr_suspend
20010Sstevel@tonic-gate  *	determine if the device's state can be changed to SUSPENDED
20020Sstevel@tonic-gate  *	close pipes if there is no activity
20030Sstevel@tonic-gate  */
20040Sstevel@tonic-gate /* ARGSUSED */
20050Sstevel@tonic-gate static int
20060Sstevel@tonic-gate scsa2usb_cpr_suspend(dev_info_t *dip)
20070Sstevel@tonic-gate {
20080Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp;
20090Sstevel@tonic-gate 	int	prev_state;
20100Sstevel@tonic-gate 	int	rval = USB_FAILURE;
20110Sstevel@tonic-gate 
20120Sstevel@tonic-gate 	scsa2usbp = ddi_get_soft_state(scsa2usb_statep, ddi_get_instance(dip));
20130Sstevel@tonic-gate 
20140Sstevel@tonic-gate 	ASSERT(scsa2usbp != NULL);
20150Sstevel@tonic-gate 
20160Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
20170Sstevel@tonic-gate 	    "scsa2usb_cpr_suspend:");
20180Sstevel@tonic-gate 
20190Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
20200Sstevel@tonic-gate 	switch (scsa2usbp->scsa2usb_dev_state) {
20210Sstevel@tonic-gate 	case USB_DEV_ONLINE:
20220Sstevel@tonic-gate 	case USB_DEV_PWRED_DOWN:
20230Sstevel@tonic-gate 	case USB_DEV_DISCONNECTED:
20240Sstevel@tonic-gate 		prev_state = scsa2usbp->scsa2usb_dev_state;
20250Sstevel@tonic-gate 		scsa2usbp->scsa2usb_dev_state = USB_DEV_SUSPENDED;
20260Sstevel@tonic-gate 
20270Sstevel@tonic-gate 		/*
20280Sstevel@tonic-gate 		 * If the device is busy, we cannot suspend
20290Sstevel@tonic-gate 		 */
20300Sstevel@tonic-gate 		if (SCSA2USB_BUSY(scsa2usbp)) {
20310Sstevel@tonic-gate 			USB_DPRINTF_L3(DPRINT_MASK_SCSA,
20320Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
20330Sstevel@tonic-gate 			    "scsa2usb_cpr_suspend: I/O active");
20340Sstevel@tonic-gate 
20350Sstevel@tonic-gate 			/* fall back to previous state */
20360Sstevel@tonic-gate 			scsa2usbp->scsa2usb_dev_state = prev_state;
20370Sstevel@tonic-gate 		} else {
20380Sstevel@tonic-gate 			rval = USB_SUCCESS;
20390Sstevel@tonic-gate 		}
20400Sstevel@tonic-gate 
20410Sstevel@tonic-gate 		break;
20420Sstevel@tonic-gate 	case USB_DEV_SUSPENDED:
20430Sstevel@tonic-gate 	default:
20440Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
20450Sstevel@tonic-gate 		    "scsa2usb_cpr_suspend: Illegal dev state: %d",
20460Sstevel@tonic-gate 		    scsa2usbp->scsa2usb_dev_state);
20470Sstevel@tonic-gate 
20480Sstevel@tonic-gate 		break;
20490Sstevel@tonic-gate 	}
20500Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
20510Sstevel@tonic-gate 
20520Sstevel@tonic-gate 	if ((rval == USB_SUCCESS) && scsa2usbp->scsa2usb_ugen_hdl) {
20530Sstevel@tonic-gate 		rval = usb_ugen_detach(scsa2usbp->scsa2usb_ugen_hdl,
20544700Sfb209375 		    DDI_SUSPEND);
20550Sstevel@tonic-gate 	}
20560Sstevel@tonic-gate 
20570Sstevel@tonic-gate 	return (rval);
20580Sstevel@tonic-gate }
20590Sstevel@tonic-gate 
20600Sstevel@tonic-gate 
20610Sstevel@tonic-gate /*
20620Sstevel@tonic-gate  * scsa2usb_cpr_resume:
20630Sstevel@tonic-gate  *	restore device's state
20640Sstevel@tonic-gate  */
20650Sstevel@tonic-gate static void
20660Sstevel@tonic-gate scsa2usb_cpr_resume(dev_info_t *dip)
20670Sstevel@tonic-gate {
20680Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp =
20690Sstevel@tonic-gate 	    ddi_get_soft_state(scsa2usb_statep, ddi_get_instance(dip));
20700Sstevel@tonic-gate 
20710Sstevel@tonic-gate 	ASSERT(scsa2usbp != NULL);
20720Sstevel@tonic-gate 
20730Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
20746898Sfb209375 	    "scsa2usb_cpr_resume: dip = 0x%p", (void *)dip);
20750Sstevel@tonic-gate 
20760Sstevel@tonic-gate 	scsa2usb_restore_device_state(dip, scsa2usbp);
20770Sstevel@tonic-gate 
20780Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_ugen_hdl) {
20790Sstevel@tonic-gate 		(void) usb_ugen_attach(scsa2usbp->scsa2usb_ugen_hdl,
20804700Sfb209375 		    DDI_RESUME);
20810Sstevel@tonic-gate 	}
20820Sstevel@tonic-gate }
20830Sstevel@tonic-gate 
20840Sstevel@tonic-gate 
20850Sstevel@tonic-gate /*
20860Sstevel@tonic-gate  * scsa2usb_restore_device_state:
20870Sstevel@tonic-gate  *	- raise the device's power
20880Sstevel@tonic-gate  *	- reopen all the pipes
20890Sstevel@tonic-gate  */
20900Sstevel@tonic-gate static void
20910Sstevel@tonic-gate scsa2usb_restore_device_state(dev_info_t *dip, scsa2usb_state_t *scsa2usbp)
20920Sstevel@tonic-gate {
20930Sstevel@tonic-gate 	uint_t	prev_state;
20940Sstevel@tonic-gate 
20950Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
20960Sstevel@tonic-gate 	    "scsa2usb_restore_device_state:");
20970Sstevel@tonic-gate 
20980Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
20990Sstevel@tonic-gate 	prev_state = scsa2usbp->scsa2usb_dev_state;
21000Sstevel@tonic-gate 
21010Sstevel@tonic-gate 	scsa2usb_raise_power(scsa2usbp);
21020Sstevel@tonic-gate 
21030Sstevel@tonic-gate 	ASSERT((prev_state == USB_DEV_DISCONNECTED) ||
21040Sstevel@tonic-gate 	    (prev_state == USB_DEV_SUSPENDED));
21050Sstevel@tonic-gate 
21060Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
21070Sstevel@tonic-gate 
21080Sstevel@tonic-gate 	/* Check for the same device */
21090Sstevel@tonic-gate 	if (usb_check_same_device(dip, scsa2usbp->scsa2usb_log_handle,
21100Sstevel@tonic-gate 	    USB_LOG_L0, DPRINT_MASK_ALL, USB_CHK_ALL, NULL) != USB_SUCCESS) {
21110Sstevel@tonic-gate 
21120Sstevel@tonic-gate 		/* change the flags to active */
21130Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
21140Sstevel@tonic-gate 		scsa2usbp->scsa2usb_dev_state = USB_DEV_DISCONNECTED;
2115189Sfrits 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
21160Sstevel@tonic-gate 
21170Sstevel@tonic-gate 		scsa2usb_pm_idle_component(scsa2usbp);
21180Sstevel@tonic-gate 
21190Sstevel@tonic-gate 		return;
21200Sstevel@tonic-gate 	}
21210Sstevel@tonic-gate 
21220Sstevel@tonic-gate 	/*
21230Sstevel@tonic-gate 	 * if the device had remote wakeup earlier,
21240Sstevel@tonic-gate 	 * enable it again
21250Sstevel@tonic-gate 	 */
21260Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
21270Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_pm &&
21280Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_pm->scsa2usb_wakeup_enabled) {
21290Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
21300Sstevel@tonic-gate 		(void) usb_handle_remote_wakeup(scsa2usbp->scsa2usb_dip,
21310Sstevel@tonic-gate 		    USB_REMOTE_WAKEUP_ENABLE);
21320Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
21330Sstevel@tonic-gate 	}
21340Sstevel@tonic-gate 
21350Sstevel@tonic-gate 	scsa2usbp->scsa2usb_dev_state = USB_DEV_ONLINE;
21360Sstevel@tonic-gate 	scsa2usbp->scsa2usb_pkt_state = SCSA2USB_PKT_NONE;
2137189Sfrits 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
21380Sstevel@tonic-gate 
21390Sstevel@tonic-gate 	scsa2usb_pm_idle_component(scsa2usbp);
21400Sstevel@tonic-gate }
21410Sstevel@tonic-gate 
21420Sstevel@tonic-gate 
21430Sstevel@tonic-gate /*
21440Sstevel@tonic-gate  * SCSA entry points:
21450Sstevel@tonic-gate  *
21460Sstevel@tonic-gate  * scsa2usb_scsi_tgt_probe:
21470Sstevel@tonic-gate  * scsa functions are exported by means of the transport table
21480Sstevel@tonic-gate  * Issue a probe to get the inquiry data.
21490Sstevel@tonic-gate  */
21500Sstevel@tonic-gate /* ARGSUSED */
21510Sstevel@tonic-gate static int
21520Sstevel@tonic-gate scsa2usb_scsi_tgt_probe(struct scsi_device *sd, int (*waitfunc)(void))
21530Sstevel@tonic-gate {
21540Sstevel@tonic-gate 	scsi_hba_tran_t *tran;
21550Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp;
21560Sstevel@tonic-gate 	dev_info_t *dip = ddi_get_parent(sd->sd_dev);
21571415Scg149915 	int	rval;
21580Sstevel@tonic-gate 
21590Sstevel@tonic-gate 	ASSERT(dip);
21600Sstevel@tonic-gate 
21610Sstevel@tonic-gate 	tran = ddi_get_driver_private(dip);
21620Sstevel@tonic-gate 	ASSERT(tran != NULL);
21630Sstevel@tonic-gate 	scsa2usbp = (scsa2usb_state_t *)tran->tran_hba_private;
21640Sstevel@tonic-gate 	ASSERT(scsa2usbp);
21650Sstevel@tonic-gate 
21660Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
21670Sstevel@tonic-gate 	    "scsa2usb_scsi_tgt_probe:");
21680Sstevel@tonic-gate 
21690Sstevel@tonic-gate 	/* if device is disconnected (ie. pipes closed), fail immediately */
21700Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
21710Sstevel@tonic-gate 	if (!(SCSA2USB_DEVICE_ACCESS_OK(scsa2usbp))) {
21720Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
21730Sstevel@tonic-gate 
21740Sstevel@tonic-gate 		return (SCSIPROBE_FAILURE);
21750Sstevel@tonic-gate 	}
21760Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
21770Sstevel@tonic-gate 
21780Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
21796898Sfb209375 	    "scsa2usb_scsi_tgt_probe: scsi_device = 0x%p", (void *)sd);
21800Sstevel@tonic-gate 
21810Sstevel@tonic-gate 	if ((rval = scsi_hba_probe(sd, waitfunc)) == SCSIPROBE_EXISTS) {
21820Sstevel@tonic-gate 		/*
21831415Scg149915 		 * respect the removable bit on all USB storage devices
21840Sstevel@tonic-gate 		 * unless overridden by a scsa2usb.conf entry
21850Sstevel@tonic-gate 		 */
21860Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
21871415Scg149915 		if (!(scsa2usbp->scsa2usb_attrs & SCSA2USB_ATTRS_RMB)) {
21880Sstevel@tonic-gate 			_NOTE(SCHEME_PROTECTS_DATA("unshared", scsi_inquiry))
21890Sstevel@tonic-gate 			sd->sd_inq->inq_rmb = 1;
21900Sstevel@tonic-gate 		}
21910Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
21920Sstevel@tonic-gate 	}
21930Sstevel@tonic-gate 
21940Sstevel@tonic-gate 	return (rval);
21950Sstevel@tonic-gate }
21960Sstevel@tonic-gate 
21970Sstevel@tonic-gate 
21980Sstevel@tonic-gate /*
21990Sstevel@tonic-gate  * scsa2usb_scsi_tgt_init:
22000Sstevel@tonic-gate  *	check whether we created this child ourselves
22010Sstevel@tonic-gate  */
22020Sstevel@tonic-gate /* ARGSUSED */
22030Sstevel@tonic-gate static int
22040Sstevel@tonic-gate scsa2usb_scsi_tgt_init(dev_info_t *dip, dev_info_t *cdip,
22050Sstevel@tonic-gate     scsi_hba_tran_t *tran, struct scsi_device *sd)
22060Sstevel@tonic-gate {
22070Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp = (scsa2usb_state_t *)
22084700Sfb209375 	    tran->tran_hba_private;
22090Sstevel@tonic-gate 	int lun;
22100Sstevel@tonic-gate 	int t_len = sizeof (lun);
22110Sstevel@tonic-gate 
22120Sstevel@tonic-gate 	if (ddi_prop_op(DDI_DEV_T_ANY, cdip, PROP_LEN_AND_VAL_BUF,
22130Sstevel@tonic-gate 	    DDI_PROP_DONTPASS|DDI_PROP_CANSLEEP, "lun", (caddr_t)&lun,
22140Sstevel@tonic-gate 	    &t_len) != DDI_PROP_SUCCESS) {
22150Sstevel@tonic-gate 
22160Sstevel@tonic-gate 		return (DDI_FAILURE);
22170Sstevel@tonic-gate 	}
22180Sstevel@tonic-gate 
22190Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
22200Sstevel@tonic-gate 	    "scsa2usb_scsi_tgt_init: %s, lun%d", ddi_driver_name(cdip), lun);
22210Sstevel@tonic-gate 
22220Sstevel@tonic-gate 	/* is this a child we created? */
22230Sstevel@tonic-gate 	if (scsa2usb_is_usb(cdip) == 0) {
22240Sstevel@tonic-gate 
22250Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
22260Sstevel@tonic-gate 		    "scsa2usb_scsi_tgt_init: new child %s%d",
22270Sstevel@tonic-gate 		    ddi_driver_name(cdip), ddi_get_instance(cdip));
22280Sstevel@tonic-gate 
22290Sstevel@tonic-gate 		/*
22300Sstevel@tonic-gate 		 * add property "usb" so we can always verify that it
22310Sstevel@tonic-gate 		 * is our child
22320Sstevel@tonic-gate 		 */
22330Sstevel@tonic-gate 		if (ndi_prop_create_boolean(DDI_DEV_T_NONE, cdip, "usb") !=
22340Sstevel@tonic-gate 		    DDI_PROP_SUCCESS) {
22350Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_SCSA,
22360Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
22370Sstevel@tonic-gate 			    "ndi_prop_create_boolean failed");
22380Sstevel@tonic-gate 
22390Sstevel@tonic-gate 			return (DDI_FAILURE);
22400Sstevel@tonic-gate 		}
22410Sstevel@tonic-gate 
22420Sstevel@tonic-gate 		usba_set_usba_device(cdip,
22434700Sfb209375 		    usba_get_usba_device(scsa2usbp->scsa2usb_dip));
22440Sstevel@tonic-gate 
22450Sstevel@tonic-gate 		/*
22460Sstevel@tonic-gate 		 * we don't store this dip in scsa2usb_lun_dip, there
22470Sstevel@tonic-gate 		 * might be multiple dips for the same device
22480Sstevel@tonic-gate 		 */
22490Sstevel@tonic-gate 
22500Sstevel@tonic-gate 		return (DDI_SUCCESS);
22510Sstevel@tonic-gate 	}
22520Sstevel@tonic-gate 
22530Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
22540Sstevel@tonic-gate 	if ((lun >= scsa2usbp->scsa2usb_n_luns) ||
22550Sstevel@tonic-gate 	    (scsa2usbp->scsa2usb_lun_dip[lun] != NULL)) {
22560Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
22570Sstevel@tonic-gate 
22580Sstevel@tonic-gate 		return (DDI_FAILURE);
22590Sstevel@tonic-gate 	}
22600Sstevel@tonic-gate 
22610Sstevel@tonic-gate 	scsa2usbp->scsa2usb_lun_dip[lun] = cdip;
22620Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
22630Sstevel@tonic-gate 
22640Sstevel@tonic-gate 	return (DDI_SUCCESS);
22650Sstevel@tonic-gate }
22660Sstevel@tonic-gate 
22670Sstevel@tonic-gate 
22680Sstevel@tonic-gate /*
22690Sstevel@tonic-gate  * scsa2usb_scsi_tgt_free:
22700Sstevel@tonic-gate  */
22710Sstevel@tonic-gate /* ARGSUSED */
22720Sstevel@tonic-gate static void
22730Sstevel@tonic-gate scsa2usb_scsi_tgt_free(dev_info_t *hba_dip, dev_info_t *cdip,
22740Sstevel@tonic-gate 	scsi_hba_tran_t *tran, struct scsi_device *sd)
22750Sstevel@tonic-gate {
22760Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp = (scsa2usb_state_t *)
22774700Sfb209375 	    tran->tran_hba_private;
22780Sstevel@tonic-gate 	int lun;
22790Sstevel@tonic-gate 	int t_len = sizeof (lun);
22800Sstevel@tonic-gate 
22810Sstevel@tonic-gate 	/* is this our child? */
22820Sstevel@tonic-gate 	if (scsa2usb_is_usb(cdip) == 0) {
22830Sstevel@tonic-gate 
22840Sstevel@tonic-gate 		return;
22850Sstevel@tonic-gate 	}
22860Sstevel@tonic-gate 
22870Sstevel@tonic-gate 	if (ddi_prop_op(DDI_DEV_T_ANY, cdip, PROP_LEN_AND_VAL_BUF,
22880Sstevel@tonic-gate 	    DDI_PROP_DONTPASS|DDI_PROP_CANSLEEP, "lun", (caddr_t)&lun,
22890Sstevel@tonic-gate 	    &t_len) != DDI_PROP_SUCCESS) {
22900Sstevel@tonic-gate 
22910Sstevel@tonic-gate 		return;
22920Sstevel@tonic-gate 	}
22930Sstevel@tonic-gate 
22940Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
22950Sstevel@tonic-gate 	    "scsa2usb_scsi_tgt_free: %s lun%d", ddi_driver_name(cdip), lun);
22960Sstevel@tonic-gate 
22970Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
22980Sstevel@tonic-gate 	if (lun < scsa2usbp->scsa2usb_n_luns) {
22990Sstevel@tonic-gate 		if (scsa2usbp->scsa2usb_lun_dip[lun] == cdip) {
23000Sstevel@tonic-gate 			scsa2usbp->scsa2usb_lun_dip[lun] = NULL;
23010Sstevel@tonic-gate 		}
23020Sstevel@tonic-gate 	}
23030Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
23040Sstevel@tonic-gate }
23050Sstevel@tonic-gate 
23060Sstevel@tonic-gate 
23070Sstevel@tonic-gate /*
23080Sstevel@tonic-gate  * bus enumeration entry points
23090Sstevel@tonic-gate  */
23100Sstevel@tonic-gate static int
23110Sstevel@tonic-gate scsa2usb_scsi_bus_config(dev_info_t *dip, uint_t flag, ddi_bus_config_op_t op,
23120Sstevel@tonic-gate     void *arg, dev_info_t **child)
23130Sstevel@tonic-gate {
23140Sstevel@tonic-gate 	int	circ;
23150Sstevel@tonic-gate 	int	rval;
23160Sstevel@tonic-gate 
23170Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp =
23180Sstevel@tonic-gate 	    ddi_get_soft_state(scsa2usb_statep, ddi_get_instance(dip));
23190Sstevel@tonic-gate 
23200Sstevel@tonic-gate 	ASSERT(scsa2usbp != NULL);
23210Sstevel@tonic-gate 
23220Sstevel@tonic-gate 	USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
23230Sstevel@tonic-gate 	    "scsa2usb_scsi_bus_config: op=%d", op);
23240Sstevel@tonic-gate 
23250Sstevel@tonic-gate 	if (scsa2usb_scsi_bus_config_debug) {
23260Sstevel@tonic-gate 		flag |= NDI_DEVI_DEBUG;
23270Sstevel@tonic-gate 	}
23280Sstevel@tonic-gate 
23290Sstevel@tonic-gate 	ndi_devi_enter(dip, &circ);
23300Sstevel@tonic-gate 	/* create children if necessary */
23310Sstevel@tonic-gate 	if (DEVI(dip)->devi_child == NULL) {
23320Sstevel@tonic-gate 		scsa2usb_create_luns(scsa2usbp);
23330Sstevel@tonic-gate 	}
23340Sstevel@tonic-gate 
23350Sstevel@tonic-gate 	rval = ndi_busop_bus_config(dip, flag, op, arg, child, 0);
23360Sstevel@tonic-gate 
23370Sstevel@tonic-gate 	ndi_devi_exit(dip, circ);
23380Sstevel@tonic-gate 
23390Sstevel@tonic-gate 	return (rval);
23400Sstevel@tonic-gate }
23410Sstevel@tonic-gate 
23420Sstevel@tonic-gate 
23430Sstevel@tonic-gate static int
23440Sstevel@tonic-gate scsa2usb_scsi_bus_unconfig(dev_info_t *dip, uint_t flag, ddi_bus_config_op_t op,
23450Sstevel@tonic-gate     void *arg)
23460Sstevel@tonic-gate {
23470Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp =
23480Sstevel@tonic-gate 	    ddi_get_soft_state(scsa2usb_statep, ddi_get_instance(dip));
23490Sstevel@tonic-gate 
23500Sstevel@tonic-gate 	int		circular_count;
23510Sstevel@tonic-gate 	int		rval = NDI_SUCCESS;
23520Sstevel@tonic-gate 	uint_t		save_flag = flag;
23530Sstevel@tonic-gate 
23540Sstevel@tonic-gate 	ASSERT(scsa2usbp != NULL);
23550Sstevel@tonic-gate 
23560Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
23570Sstevel@tonic-gate 	    "scsa2usb_scsi_bus_unconfig: op=%d", op);
23580Sstevel@tonic-gate 
23590Sstevel@tonic-gate 	if (scsa2usb_scsi_bus_config_debug) {
23600Sstevel@tonic-gate 		flag |= NDI_DEVI_DEBUG;
23610Sstevel@tonic-gate 	}
23620Sstevel@tonic-gate 
23630Sstevel@tonic-gate 	/*
23640Sstevel@tonic-gate 	 * first offline and if offlining successful, then
23650Sstevel@tonic-gate 	 * remove children
23660Sstevel@tonic-gate 	 */
23670Sstevel@tonic-gate 	if (op == BUS_UNCONFIG_ALL) {
23680Sstevel@tonic-gate 		flag &= ~(NDI_DEVI_REMOVE | NDI_UNCONFIG);
23690Sstevel@tonic-gate 	}
23700Sstevel@tonic-gate 
23710Sstevel@tonic-gate 	ndi_devi_enter(dip, &circular_count);
23720Sstevel@tonic-gate 	rval = ndi_busop_bus_unconfig(dip, flag, op, arg);
23730Sstevel@tonic-gate 
23740Sstevel@tonic-gate 	/*
23750Sstevel@tonic-gate 	 * If unconfig is successful and not part of modunload
23760Sstevel@tonic-gate 	 * daemon, attempt to remove children.
23770Sstevel@tonic-gate 	 */
23780Sstevel@tonic-gate 	if (op == BUS_UNCONFIG_ALL && rval == NDI_SUCCESS &&
23790Sstevel@tonic-gate 	    (flag & NDI_AUTODETACH) == 0) {
23800Sstevel@tonic-gate 		flag |= NDI_DEVI_REMOVE;
23810Sstevel@tonic-gate 		rval = ndi_busop_bus_unconfig(dip, flag, op, arg);
23820Sstevel@tonic-gate 	}
23830Sstevel@tonic-gate 	ndi_devi_exit(dip, circular_count);
23840Sstevel@tonic-gate 
23850Sstevel@tonic-gate 	if ((rval != NDI_SUCCESS) && (op == BUS_UNCONFIG_ALL) &&
23860Sstevel@tonic-gate 	    (save_flag & NDI_DEVI_REMOVE)) {
23870Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
23880Sstevel@tonic-gate 		if (scsa2usbp->scsa2usb_warning_given != B_TRUE) {
23897231Slg150142 			USB_DPRINTF_L2(DPRINT_MASK_SCSA,
23900Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
23910Sstevel@tonic-gate 			    "Disconnected device was busy, "
23920Sstevel@tonic-gate 			    "please reconnect.");
23930Sstevel@tonic-gate 			scsa2usbp->scsa2usb_warning_given = B_TRUE;
23940Sstevel@tonic-gate 		}
23950Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
23960Sstevel@tonic-gate 	}
23970Sstevel@tonic-gate 
23980Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
23990Sstevel@tonic-gate 	    "scsa2usb_scsi_bus_unconfig: rval=%d", rval);
24000Sstevel@tonic-gate 
24010Sstevel@tonic-gate 	return (rval);
24020Sstevel@tonic-gate }
24030Sstevel@tonic-gate 
24040Sstevel@tonic-gate 
24050Sstevel@tonic-gate /*
24060Sstevel@tonic-gate  * scsa2usb_scsi_init_pkt:
24070Sstevel@tonic-gate  *	Set up the scsi_pkt for transport. Also initialize
24080Sstevel@tonic-gate  *	scsa2usb_cmd struct for the transport.
24090Sstevel@tonic-gate  *	NOTE: We do not do any DMA setup here as USBA framework
24100Sstevel@tonic-gate  *	does that for us.
24110Sstevel@tonic-gate  */
24120Sstevel@tonic-gate static struct scsi_pkt *
24130Sstevel@tonic-gate scsa2usb_scsi_init_pkt(struct scsi_address *ap,
24140Sstevel@tonic-gate     struct scsi_pkt *pkt, struct buf *bp, int cmdlen, int statuslen,
24150Sstevel@tonic-gate     int tgtlen, int flags, int (*callback)(), caddr_t arg)
24160Sstevel@tonic-gate {
24170Sstevel@tonic-gate 	scsa2usb_cmd_t	 *cmd;
24180Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp;
24190Sstevel@tonic-gate 	struct scsi_pkt	 *in_pkt = pkt;
24200Sstevel@tonic-gate 
24210Sstevel@tonic-gate 	ASSERT(callback == NULL_FUNC || callback == SLEEP_FUNC);
24220Sstevel@tonic-gate 
24230Sstevel@tonic-gate 	scsa2usbp = (scsa2usb_state_t *)ADDR2SCSA2USB(ap);
24240Sstevel@tonic-gate 
24250Sstevel@tonic-gate 	/* Print sync message */
24260Sstevel@tonic-gate 	if (ddi_in_panic()) {
24270Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
24280Sstevel@tonic-gate 		SCSA2USB_PRINT_SYNC_MSG(scsa2usb_sync_message, scsa2usbp);
24290Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
24300Sstevel@tonic-gate 		/* continue so caller will not hang or complain */
24310Sstevel@tonic-gate 	}
24320Sstevel@tonic-gate 
24330Sstevel@tonic-gate 	/* allocate a pkt, if none already allocated */
24340Sstevel@tonic-gate 	if (pkt == NULL) {
24350Sstevel@tonic-gate 		if (statuslen < sizeof (struct scsi_arq_status)) {
24360Sstevel@tonic-gate 			statuslen = sizeof (struct scsi_arq_status);
24370Sstevel@tonic-gate 		}
24380Sstevel@tonic-gate 
24390Sstevel@tonic-gate 		pkt = scsi_hba_pkt_alloc(scsa2usbp->scsa2usb_dip, ap, cmdlen,
24404700Sfb209375 		    statuslen, tgtlen, sizeof (scsa2usb_cmd_t),
24414700Sfb209375 		    callback, arg);
24420Sstevel@tonic-gate 		if (pkt == NULL) {
24430Sstevel@tonic-gate 
24440Sstevel@tonic-gate 			return (NULL);
24450Sstevel@tonic-gate 		}
24460Sstevel@tonic-gate 
24470Sstevel@tonic-gate 		cmd = PKT2CMD(pkt);
24480Sstevel@tonic-gate 		cmd->cmd_pkt	= pkt; /* back link to pkt */
24490Sstevel@tonic-gate 		cmd->cmd_scblen	= statuslen;
24500Sstevel@tonic-gate 		cmd->cmd_cdblen	= (uchar_t)cmdlen;
24510Sstevel@tonic-gate 
24520Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
24530Sstevel@tonic-gate 		cmd->cmd_tag	= scsa2usbp->scsa2usb_tag++;
24540Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
24550Sstevel@tonic-gate 
24560Sstevel@tonic-gate 		cmd->cmd_bp	= bp;
24575727Slh195018 		/*
24585727Slh195018 		 * The buffer size of cmd->cmd_scb is constrained
24595727Slh195018 		 * to sizeof (struct scsi_arq_status), if the scblen
24605727Slh195018 		 * is bigger than that, we use pkt->pkt_scbp directly.
24615727Slh195018 		 */
24625727Slh195018 		if (cmd->cmd_scblen == sizeof (struct scsi_arq_status)) {
24635727Slh195018 			pkt->pkt_scbp = (opaque_t)&cmd->cmd_scb;
24645727Slh195018 		}
24650Sstevel@tonic-gate 
24660Sstevel@tonic-gate 		usba_init_list(&cmd->cmd_waitQ, (usb_opaque_t)cmd,
24674700Sfb209375 		    scsa2usbp->scsa2usb_dev_data->dev_iblock_cookie);
24680Sstevel@tonic-gate 	} else {
24690Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
24700Sstevel@tonic-gate 		    "scsa2usb: pkt != NULL");
24710Sstevel@tonic-gate 
24720Sstevel@tonic-gate 		/* nothing to do */
24730Sstevel@tonic-gate 	}
24740Sstevel@tonic-gate 
24752506Ssl147100 	if (bp && (bp->b_bcount != 0)) {
24760Sstevel@tonic-gate 		if ((bp_mapin_common(bp, (callback == SLEEP_FUNC) ?
24770Sstevel@tonic-gate 		    VM_SLEEP : VM_NOSLEEP)) == NULL) {
24780Sstevel@tonic-gate 			if (pkt != in_pkt) {
24790Sstevel@tonic-gate 				scsi_hba_pkt_free(ap, pkt);
24800Sstevel@tonic-gate 			}
24810Sstevel@tonic-gate 
24820Sstevel@tonic-gate 			return (NULL);
24830Sstevel@tonic-gate 		}
24840Sstevel@tonic-gate 
24850Sstevel@tonic-gate 		USB_DPRINTF_L3(DPRINT_MASK_SCSA,
24860Sstevel@tonic-gate 		    scsa2usbp->scsa2usb_log_handle,
24870Sstevel@tonic-gate 		    "scsa2usb_scsi_init_pkt: mapped in 0x%p, addr=0x%p",
24886898Sfb209375 		    (void *)bp, (void *)bp->b_un.b_addr);
24890Sstevel@tonic-gate 	}
24900Sstevel@tonic-gate 
24910Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
24920Sstevel@tonic-gate 	    "scsa2usb_scsi_init_pkt: ap = 0x%p pkt: 0x%p\n\t"
24930Sstevel@tonic-gate 	    "bp = 0x%p cmdlen = %x stlen = 0x%x tlen = 0x%x flags = 0x%x",
24946898Sfb209375 	    (void *)ap, (void *)pkt, (void *)bp, cmdlen, statuslen,
24956898Sfb209375 	    tgtlen, flags);
24960Sstevel@tonic-gate 
24970Sstevel@tonic-gate 	return (pkt);
24980Sstevel@tonic-gate }
24990Sstevel@tonic-gate 
25000Sstevel@tonic-gate 
25010Sstevel@tonic-gate /*
25020Sstevel@tonic-gate  * scsa2usb_scsi_destroy_pkt:
25030Sstevel@tonic-gate  *	We are done with the packet. Get rid of it.
25040Sstevel@tonic-gate  */
25050Sstevel@tonic-gate static void
25060Sstevel@tonic-gate scsa2usb_scsi_destroy_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
25070Sstevel@tonic-gate {
25080Sstevel@tonic-gate 	scsa2usb_cmd_t *cmd = PKT2CMD(pkt);
25090Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp = ADDR2SCSA2USB(ap);
25100Sstevel@tonic-gate 
25110Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
25126898Sfb209375 	    "scsa2usb_scsi_destroy_pkt: pkt=0x%p", (void *)pkt);
25130Sstevel@tonic-gate 
25140Sstevel@tonic-gate 	usba_destroy_list(&cmd->cmd_waitQ);
25150Sstevel@tonic-gate 	scsi_hba_pkt_free(ap, pkt);
25160Sstevel@tonic-gate }
25170Sstevel@tonic-gate 
25180Sstevel@tonic-gate 
25190Sstevel@tonic-gate /*
25200Sstevel@tonic-gate  * scsa2usb_scsi_start:
25210Sstevel@tonic-gate  *	For each command being issued, build up the CDB
25220Sstevel@tonic-gate  *	and call scsi_transport to issue the command. This
25230Sstevel@tonic-gate  *	function is based on the assumption that USB allows
25240Sstevel@tonic-gate  *	a subset of SCSI commands. Other SCSI commands we fail.
25250Sstevel@tonic-gate  */
25260Sstevel@tonic-gate static int
25270Sstevel@tonic-gate scsa2usb_scsi_start(struct scsi_address *ap, struct scsi_pkt *pkt)
25280Sstevel@tonic-gate {
25290Sstevel@tonic-gate 	scsa2usb_cmd_t		*cmd;
25300Sstevel@tonic-gate 	scsa2usb_state_t	*scsa2usbp = ADDR2SCSA2USB(ap);
25310Sstevel@tonic-gate 	uint_t			lun = ap->a_lun;
25320Sstevel@tonic-gate 
25330Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
25340Sstevel@tonic-gate 
25350Sstevel@tonic-gate 	cmd = PKT2CMD(pkt);
25360Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
25370Sstevel@tonic-gate 	    "scsa2usb_scsi_start:\n\t"
25380Sstevel@tonic-gate 	    "bp: 0x%p ap: 0x%p pkt: 0x%p flag: 0x%x time: 0x%x\n\tcdb0: 0x%x "
25390Sstevel@tonic-gate 	    "dev_state: 0x%x pkt_state: 0x%x flags: 0x%x pipe_state: 0x%x",
25406898Sfb209375 	    (void *)cmd->cmd_bp, (void *)ap, (void *)pkt, pkt->pkt_flags,
25416898Sfb209375 	    pkt->pkt_time, pkt->pkt_cdbp[0], scsa2usbp->scsa2usb_dev_state,
25420Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_pkt_state, scsa2usbp->scsa2usb_flags,
25430Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_pipe_state);
25440Sstevel@tonic-gate 
25450Sstevel@tonic-gate 	if (pkt->pkt_time == 0) {
25460Sstevel@tonic-gate 		USB_DPRINTF_L1(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
25470Sstevel@tonic-gate 		    "pkt submitted with 0 timeout which may cause indefinite "
25480Sstevel@tonic-gate 		    "hangs");
25490Sstevel@tonic-gate 	}
25500Sstevel@tonic-gate 
25510Sstevel@tonic-gate 	/*
25520Sstevel@tonic-gate 	 * if we are in panic, we are in polled mode, so we can just
25530Sstevel@tonic-gate 	 * accept the request, drop it and return
25540Sstevel@tonic-gate 	 * if we fail this request, the rest of the file systems do not
25550Sstevel@tonic-gate 	 * get synced
25560Sstevel@tonic-gate 	 */
25570Sstevel@tonic-gate 	if (ddi_in_panic()) {
25580Sstevel@tonic-gate 		extern int do_polled_io;
25590Sstevel@tonic-gate 
25600Sstevel@tonic-gate 		ASSERT(do_polled_io);
25610Sstevel@tonic-gate 		scsa2usb_prepare_pkt(scsa2usbp, pkt);
25620Sstevel@tonic-gate 		SCSA2USB_PRINT_SYNC_MSG(scsa2usb_sync_message, scsa2usbp);
25630Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
25640Sstevel@tonic-gate 
25650Sstevel@tonic-gate 		return (TRAN_ACCEPT);
25660Sstevel@tonic-gate 	}
25670Sstevel@tonic-gate 
25680Sstevel@tonic-gate 	/* we cannot do polling, this should not happen */
25690Sstevel@tonic-gate 	if (pkt->pkt_flags & FLAG_NOINTR) {
25700Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
25710Sstevel@tonic-gate 		    "NOINTR packet: opcode = 0%x", pkt->pkt_cdbp[0]);
25720Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
25730Sstevel@tonic-gate 
25740Sstevel@tonic-gate 		return (TRAN_BADPKT);
25750Sstevel@tonic-gate 	}
25760Sstevel@tonic-gate 
25770Sstevel@tonic-gate 	/* is there a ugen open? */
25780Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_ugen_open_count) {
25790Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
25800Sstevel@tonic-gate 		    "ugen access in progress (count=%d)",
25810Sstevel@tonic-gate 		    scsa2usbp->scsa2usb_ugen_open_count);
25820Sstevel@tonic-gate 
25830Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
25840Sstevel@tonic-gate 
25850Sstevel@tonic-gate 		return (TRAN_BUSY);
25860Sstevel@tonic-gate 	}
25870Sstevel@tonic-gate 
25880Sstevel@tonic-gate 	/* prepare packet */
25890Sstevel@tonic-gate 	scsa2usb_prepare_pkt(scsa2usbp, pkt);
25900Sstevel@tonic-gate 
25910Sstevel@tonic-gate 	/* just queue up the requests in the waitQ if below max */
25920Sstevel@tonic-gate 	if (usba_list_entry_count(&scsa2usbp->scsa2usb_waitQ[lun]) >
25930Sstevel@tonic-gate 	    SCSA2USB_MAX_REQ_PER_LUN) {
25940Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA,
25950Sstevel@tonic-gate 		    scsa2usbp->scsa2usb_log_handle,
25960Sstevel@tonic-gate 		    "scsa2usb_scsi_start: limit (%d) exceeded",
25970Sstevel@tonic-gate 		    SCSA2USB_MAX_REQ_PER_LUN);
25980Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
25990Sstevel@tonic-gate 
26000Sstevel@tonic-gate 		return (TRAN_BUSY);
26010Sstevel@tonic-gate 	}
26020Sstevel@tonic-gate 
26030Sstevel@tonic-gate 	usba_add_to_list(&scsa2usbp->scsa2usb_waitQ[lun], &cmd->cmd_waitQ);
26040Sstevel@tonic-gate 
2605189Sfrits 	USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
26066898Sfb209375 	    "scsa2usb_work_thread_id=0x%p, count=%d, lun=%d",
26076898Sfb209375 	    (void *)scsa2usbp->scsa2usb_work_thread_id,
2608189Sfrits 	    usba_list_entry_count(&scsa2usbp->scsa2usb_waitQ[lun]), lun);
2609189Sfrits 
26100Sstevel@tonic-gate 	/* fire up a thread to start executing the protocol */
26110Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_work_thread_id == 0) {
26120Sstevel@tonic-gate 		if ((usb_async_req(scsa2usbp->scsa2usb_dip,
26130Sstevel@tonic-gate 		    scsa2usb_work_thread,
26140Sstevel@tonic-gate 		    (void *)scsa2usbp, USB_FLAGS_SLEEP)) != USB_SUCCESS) {
26150Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_SCSA,
26160Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
26170Sstevel@tonic-gate 			    "no work thread started");
26180Sstevel@tonic-gate 
26190Sstevel@tonic-gate 			if (usba_rm_from_list(
26200Sstevel@tonic-gate 			    &scsa2usbp->scsa2usb_waitQ[lun],
26210Sstevel@tonic-gate 			    &cmd->cmd_waitQ) == USB_SUCCESS) {
26220Sstevel@tonic-gate 				mutex_exit(&scsa2usbp->scsa2usb_mutex);
26230Sstevel@tonic-gate 
26240Sstevel@tonic-gate 				return (TRAN_BUSY);
26250Sstevel@tonic-gate 			} else {
26260Sstevel@tonic-gate 
26270Sstevel@tonic-gate 				mutex_exit(&scsa2usbp->scsa2usb_mutex);
26280Sstevel@tonic-gate 
26290Sstevel@tonic-gate 				return (TRAN_ACCEPT);
26300Sstevel@tonic-gate 			}
26310Sstevel@tonic-gate 		}
26320Sstevel@tonic-gate 		scsa2usbp->scsa2usb_work_thread_id = (kthread_t *)1;
26330Sstevel@tonic-gate 	}
2634189Sfrits 
26350Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
26360Sstevel@tonic-gate 
26370Sstevel@tonic-gate 	return (TRAN_ACCEPT);
26380Sstevel@tonic-gate }
26390Sstevel@tonic-gate 
26400Sstevel@tonic-gate 
26410Sstevel@tonic-gate /*
26420Sstevel@tonic-gate  * scsa2usb_scsi_abort:
26430Sstevel@tonic-gate  *	Issue SCSI abort command. This function is a NOP.
26440Sstevel@tonic-gate  */
26450Sstevel@tonic-gate /* ARGSUSED */
26460Sstevel@tonic-gate static int
26470Sstevel@tonic-gate scsa2usb_scsi_abort(struct scsi_address *ap, struct scsi_pkt *pkt)
26480Sstevel@tonic-gate {
26490Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp = (scsa2usb_state_t *)ADDR2SCSA2USB(ap);
26500Sstevel@tonic-gate 
26510Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
26526898Sfb209375 	    "scsa2usb_scsi_abort: pkt = %p", (void *)pkt);
26530Sstevel@tonic-gate 
26540Sstevel@tonic-gate 	/* if device is disconnected (ie. pipes closed), fail immediately */
26550Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
26560Sstevel@tonic-gate 	if (!(SCSA2USB_DEVICE_ACCESS_OK(scsa2usbp))) {
26570Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
26580Sstevel@tonic-gate 
26590Sstevel@tonic-gate 		return (0);
26600Sstevel@tonic-gate 	}
26610Sstevel@tonic-gate 
26620Sstevel@tonic-gate 	/* flush waitQ if target and lun match */
26630Sstevel@tonic-gate 	if ((ap->a_target == pkt->pkt_address.a_target) &&
26640Sstevel@tonic-gate 	    (ap->a_lun == pkt->pkt_address.a_lun)) {
26650Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
26660Sstevel@tonic-gate 		scsa2usb_flush_waitQ(scsa2usbp, ap->a_lun, CMD_ABORTED);
26670Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
26680Sstevel@tonic-gate 	}
26690Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
26700Sstevel@tonic-gate 
26710Sstevel@tonic-gate 	return (0);
26720Sstevel@tonic-gate }
26730Sstevel@tonic-gate 
26740Sstevel@tonic-gate 
26750Sstevel@tonic-gate /*
26760Sstevel@tonic-gate  * scsa2usb_scsi_reset:
26770Sstevel@tonic-gate  *	device reset may turn the device into a brick and bus reset
26780Sstevel@tonic-gate  *	is not applicable.
26790Sstevel@tonic-gate  *	just flush the waitQ
26800Sstevel@tonic-gate  *	We return success, always.
26810Sstevel@tonic-gate  */
26820Sstevel@tonic-gate /* ARGSUSED */
26830Sstevel@tonic-gate static int
26840Sstevel@tonic-gate scsa2usb_scsi_reset(struct scsi_address *ap, int level)
26850Sstevel@tonic-gate {
26860Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp = (scsa2usb_state_t *)ADDR2SCSA2USB(ap);
26870Sstevel@tonic-gate 
26880Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
26896898Sfb209375 	    "scsa2usb_scsi_reset: ap = 0x%p, level = %d", (void *)ap, level);
26900Sstevel@tonic-gate 
26910Sstevel@tonic-gate 	/* flush waitQ */
26920Sstevel@tonic-gate 	scsa2usb_flush_waitQ(scsa2usbp, ap->a_lun, CMD_RESET);
26930Sstevel@tonic-gate 
26940Sstevel@tonic-gate 	return (1);
26950Sstevel@tonic-gate }
26960Sstevel@tonic-gate 
26970Sstevel@tonic-gate 
26980Sstevel@tonic-gate /*
26990Sstevel@tonic-gate  * scsa2usb_scsi_getcap:
27000Sstevel@tonic-gate  *	Get SCSI capabilities.
27010Sstevel@tonic-gate  */
27020Sstevel@tonic-gate /* ARGSUSED */
27030Sstevel@tonic-gate static int
27040Sstevel@tonic-gate scsa2usb_scsi_getcap(struct scsi_address *ap, char *cap, int whom)
27050Sstevel@tonic-gate {
27060Sstevel@tonic-gate 	int rval = -1;
27070Sstevel@tonic-gate 	uint_t cidx;
27080Sstevel@tonic-gate 	size_t dev_bsize_cap;
27090Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp = (scsa2usb_state_t *)ADDR2SCSA2USB(ap);
27100Sstevel@tonic-gate 	ASSERT(scsa2usbp);
27110Sstevel@tonic-gate 
27120Sstevel@tonic-gate 	if (cap == NULL) {
27130Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
27140Sstevel@tonic-gate 		    "scsa2usb_scsi_getcap: invalid arg, "
27156898Sfb209375 		    "cap = 0x%p whom = %d", (void *)cap, whom);
27160Sstevel@tonic-gate 
27170Sstevel@tonic-gate 		return (rval);
27180Sstevel@tonic-gate 	}
27190Sstevel@tonic-gate 
27200Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
27210Sstevel@tonic-gate 	    "scsa2usb_scsi_getcap: cap = %s", cap);
27220Sstevel@tonic-gate 
27230Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
27240Sstevel@tonic-gate 
27250Sstevel@tonic-gate 	/* if device is disconnected (ie. pipes closed), fail immediately */
27260Sstevel@tonic-gate 	if (!(SCSA2USB_DEVICE_ACCESS_OK(scsa2usbp))) {
27270Sstevel@tonic-gate 
27280Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
27290Sstevel@tonic-gate 
27300Sstevel@tonic-gate 		return (rval);
27310Sstevel@tonic-gate 	}
27320Sstevel@tonic-gate 
27330Sstevel@tonic-gate 	cidx =	scsi_hba_lookup_capstr(cap);
27340Sstevel@tonic-gate 	switch (cidx) {
27350Sstevel@tonic-gate 	case SCSI_CAP_GEOMETRY:
27367015Sbc224572 		/* Just check and fail immediately if zero, rarely happens */
27377015Sbc224572 		if (scsa2usbp->scsa2usb_secsz[ap->a_lun] == 0) {
27387015Sbc224572 			USB_DPRINTF_L2(DPRINT_MASK_SCSA,
27397015Sbc224572 			    scsa2usbp->scsa2usb_log_handle,
27407015Sbc224572 			    "scsa2usb_scsi_getcap failed:"
27417015Sbc224572 			    "scsa2usbp->scsa2usb_secsz[ap->a_lun] == 0");
27427015Sbc224572 			mutex_exit(&scsa2usbp->scsa2usb_mutex);
27437015Sbc224572 
27447015Sbc224572 			return (rval);
27457015Sbc224572 		}
27467015Sbc224572 
27470Sstevel@tonic-gate 		dev_bsize_cap = scsa2usbp->scsa2usb_totalsec[ap->a_lun];
27480Sstevel@tonic-gate 
27490Sstevel@tonic-gate 		if (scsa2usbp->scsa2usb_secsz[ap->a_lun] > DEV_BSIZE) {
27500Sstevel@tonic-gate 			dev_bsize_cap *=
27510Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_secsz[ap->a_lun] / DEV_BSIZE;
27520Sstevel@tonic-gate 		} else if (scsa2usbp->scsa2usb_secsz[ap->a_lun] <
27530Sstevel@tonic-gate 		    DEV_BSIZE) {
27540Sstevel@tonic-gate 			dev_bsize_cap /=
27550Sstevel@tonic-gate 			    DEV_BSIZE / scsa2usbp->scsa2usb_secsz[ap->a_lun];
27560Sstevel@tonic-gate 		}
27570Sstevel@tonic-gate 
27580Sstevel@tonic-gate 		if (dev_bsize_cap < 65536 * 2 * 18) {		/* < ~1GB */
27590Sstevel@tonic-gate 			/* unlabeled floppy, 18k per cylinder */
27600Sstevel@tonic-gate 			rval = ((2 << 16) | 18);
27610Sstevel@tonic-gate 		} else if (dev_bsize_cap < 65536 * 64 * 32) {	/* < 64GB */
27620Sstevel@tonic-gate 			/* 1024k per cylinder */
27630Sstevel@tonic-gate 			rval = ((64 << 16) | 32);
27640Sstevel@tonic-gate 		} else if (dev_bsize_cap < 65536 * 255 * 63) {	/* < ~500GB */
27650Sstevel@tonic-gate 			/* ~8m per cylinder */
27660Sstevel@tonic-gate 			rval = ((255 << 16) | 63);
27670Sstevel@tonic-gate 		} else {					/* .. 8TB */
27680Sstevel@tonic-gate 			/* 64m per cylinder */
27690Sstevel@tonic-gate 			rval = ((512 << 16) | 256);
27700Sstevel@tonic-gate 		}
27710Sstevel@tonic-gate 		break;
27720Sstevel@tonic-gate 
27730Sstevel@tonic-gate 	case SCSI_CAP_DMA_MAX:
27740Sstevel@tonic-gate 		rval = scsa2usbp->scsa2usb_max_bulk_xfer_size;
27750Sstevel@tonic-gate 		break;
27760Sstevel@tonic-gate 	case SCSI_CAP_SCSI_VERSION:
27770Sstevel@tonic-gate 		rval = SCSI_VERSION_2;
27780Sstevel@tonic-gate 		break;
27790Sstevel@tonic-gate 	case SCSI_CAP_INTERCONNECT_TYPE:
27800Sstevel@tonic-gate 		rval = INTERCONNECT_USB;
27810Sstevel@tonic-gate 		break;
27820Sstevel@tonic-gate 	case SCSI_CAP_ARQ:
27830Sstevel@tonic-gate 		/* FALLTHRU */
27840Sstevel@tonic-gate 	case SCSI_CAP_UNTAGGED_QING:
27850Sstevel@tonic-gate 		rval = 1;
27860Sstevel@tonic-gate 		break;
27870Sstevel@tonic-gate 	default:
27880Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
27890Sstevel@tonic-gate 		    "scsa2usb_scsi_getcap: unsupported cap = %s", cap);
27900Sstevel@tonic-gate 		break;
27910Sstevel@tonic-gate 	}
27920Sstevel@tonic-gate 
27930Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
27940Sstevel@tonic-gate 	    "scsa2usb_scsi_getcap: cap = %s, returned = %d", cap, rval);
27950Sstevel@tonic-gate 
27960Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
27970Sstevel@tonic-gate 
27980Sstevel@tonic-gate 	return (rval);
27990Sstevel@tonic-gate }
28000Sstevel@tonic-gate 
28010Sstevel@tonic-gate 
28020Sstevel@tonic-gate /*
28030Sstevel@tonic-gate  * scsa2usb_scsi_setcap:
28040Sstevel@tonic-gate  *	Set SCSI capabilities.
28050Sstevel@tonic-gate  */
28060Sstevel@tonic-gate /* ARGSUSED */
28070Sstevel@tonic-gate static int
28080Sstevel@tonic-gate scsa2usb_scsi_setcap(struct scsi_address *ap, char *cap, int value, int whom)
28090Sstevel@tonic-gate {
28100Sstevel@tonic-gate 	int rval = -1; /* default is cap undefined */
28110Sstevel@tonic-gate 	uint_t cidx;
28120Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp = (scsa2usb_state_t *)ADDR2SCSA2USB(ap);
28130Sstevel@tonic-gate 	ASSERT(scsa2usbp);
28140Sstevel@tonic-gate 
28150Sstevel@tonic-gate 	if (cap == NULL || whom == 0) {
28160Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
28170Sstevel@tonic-gate 		    "scsa2usb_scsi_setcap: invalid arg");
28180Sstevel@tonic-gate 
28190Sstevel@tonic-gate 		return (rval);
28200Sstevel@tonic-gate 	}
28210Sstevel@tonic-gate 
28220Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
28230Sstevel@tonic-gate 	/* if device is disconnected (ie. pipes closed), fail immediately */
28240Sstevel@tonic-gate 	if (!(SCSA2USB_DEVICE_ACCESS_OK(scsa2usbp))) {
28250Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
28260Sstevel@tonic-gate 
28270Sstevel@tonic-gate 		return (rval);
28280Sstevel@tonic-gate 	}
28290Sstevel@tonic-gate 
28300Sstevel@tonic-gate 	cidx =	scsi_hba_lookup_capstr(cap);
28310Sstevel@tonic-gate 	USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
28320Sstevel@tonic-gate 	    "scsa2usb_scsi_setcap: ap = 0x%p value = 0x%x whom = 0x%x "
28336898Sfb209375 	    "cidx = 0x%x", (void *)ap, value, whom, cidx);
28340Sstevel@tonic-gate 
28350Sstevel@tonic-gate 	switch (cidx) {
28360Sstevel@tonic-gate 	case SCSI_CAP_SECTOR_SIZE:
28370Sstevel@tonic-gate 		if (value) {
28380Sstevel@tonic-gate 			scsa2usbp->scsa2usb_secsz[ap->a_lun] = value;
28390Sstevel@tonic-gate 		}
28400Sstevel@tonic-gate 		break;
28410Sstevel@tonic-gate 	case SCSI_CAP_TOTAL_SECTORS:
28420Sstevel@tonic-gate 		if (value) {
28430Sstevel@tonic-gate 			scsa2usbp->scsa2usb_totalsec[ap->a_lun] = value;
28440Sstevel@tonic-gate 		}
28450Sstevel@tonic-gate 		break;
28460Sstevel@tonic-gate 	case SCSI_CAP_ARQ:
28470Sstevel@tonic-gate 		rval = 1;
28480Sstevel@tonic-gate 		break;
28490Sstevel@tonic-gate 	case SCSI_CAP_DMA_MAX:
28500Sstevel@tonic-gate 	case SCSI_CAP_SCSI_VERSION:
28510Sstevel@tonic-gate 	case SCSI_CAP_INTERCONNECT_TYPE:
28520Sstevel@tonic-gate 	case SCSI_CAP_UNTAGGED_QING:
28530Sstevel@tonic-gate 		/* supported but not settable */
28540Sstevel@tonic-gate 		rval = 0;
28550Sstevel@tonic-gate 		break;
28560Sstevel@tonic-gate 	default:
28570Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
28580Sstevel@tonic-gate 		    "scsa2usb_scsi_setcap: unsupported cap = %s", cap);
28590Sstevel@tonic-gate 		break;
28600Sstevel@tonic-gate 	}
28610Sstevel@tonic-gate 
28620Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
28630Sstevel@tonic-gate 
28640Sstevel@tonic-gate 	return (rval);
28650Sstevel@tonic-gate }
28660Sstevel@tonic-gate 
28670Sstevel@tonic-gate 
28680Sstevel@tonic-gate /*
28690Sstevel@tonic-gate  * scsa2usb - cmd and transport stuff
28700Sstevel@tonic-gate  */
28710Sstevel@tonic-gate /*
28720Sstevel@tonic-gate  * scsa2usb_prepare_pkt:
28730Sstevel@tonic-gate  *	initialize some fields of the pkt and cmd
28740Sstevel@tonic-gate  *	(the pkt may have been resubmitted/retried)
28750Sstevel@tonic-gate  */
28760Sstevel@tonic-gate static void
28770Sstevel@tonic-gate scsa2usb_prepare_pkt(scsa2usb_state_t *scsa2usbp, struct scsi_pkt *pkt)
28780Sstevel@tonic-gate {
28790Sstevel@tonic-gate 	scsa2usb_cmd_t	*cmd = PKT2CMD(pkt);
28800Sstevel@tonic-gate 
28810Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
28820Sstevel@tonic-gate 	    "scsa2usb_prepare_pkt: pkt=0x%p cdb: 0x%x (%s)",
28836898Sfb209375 	    (void *)pkt, pkt->pkt_cdbp[0],
28840Sstevel@tonic-gate 	    scsi_cname(pkt->pkt_cdbp[0], scsa2usb_cmds));
28850Sstevel@tonic-gate 
28860Sstevel@tonic-gate 	pkt->pkt_reason = CMD_CMPLT;	/* Set reason to pkt_complete */
28870Sstevel@tonic-gate 	pkt->pkt_state = 0;		/* Reset next three fields */
28880Sstevel@tonic-gate 	pkt->pkt_statistics = 0;
28890Sstevel@tonic-gate 	pkt->pkt_resid = 0;
28900Sstevel@tonic-gate 	bzero(pkt->pkt_scbp, cmd->cmd_scblen); /* Set status to good */
28910Sstevel@tonic-gate 
28920Sstevel@tonic-gate 	if (cmd) {
28930Sstevel@tonic-gate 		cmd->cmd_timeout = pkt->pkt_time;
28940Sstevel@tonic-gate 		cmd->cmd_xfercount = 0;		/* Reset the fields */
28950Sstevel@tonic-gate 		cmd->cmd_total_xfercount = 0;
28960Sstevel@tonic-gate 		cmd->cmd_lba = 0;
28970Sstevel@tonic-gate 		cmd->cmd_done = 0;
28980Sstevel@tonic-gate 		cmd->cmd_dir = 0;
28990Sstevel@tonic-gate 		cmd->cmd_offset = 0;
29000Sstevel@tonic-gate 		cmd->cmd_actual_len = cmd->cmd_cdblen;
29010Sstevel@tonic-gate 	}
29020Sstevel@tonic-gate }
29030Sstevel@tonic-gate 
29040Sstevel@tonic-gate 
29050Sstevel@tonic-gate /*
29060Sstevel@tonic-gate  * scsa2usb_force_invalid_request
29070Sstevel@tonic-gate  */
29080Sstevel@tonic-gate static void
29090Sstevel@tonic-gate scsa2usb_force_invalid_request(scsa2usb_state_t *scsa2usbp,
29100Sstevel@tonic-gate     scsa2usb_cmd_t *cmd)
29110Sstevel@tonic-gate {
29120Sstevel@tonic-gate 	struct scsi_arq_status	*arqp;
29130Sstevel@tonic-gate 
29140Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
29156898Sfb209375 	    "scsa2usb_force_invalid_request: pkt = 0x%p", (void *)cmd->cmd_pkt);
29160Sstevel@tonic-gate 
29170Sstevel@tonic-gate 	if (cmd->cmd_scblen >= sizeof (struct scsi_arq_status)) {
29180Sstevel@tonic-gate 		arqp = (struct scsi_arq_status *)cmd->cmd_pkt->pkt_scbp;
29190Sstevel@tonic-gate 		bzero(arqp, cmd->cmd_scblen);
29200Sstevel@tonic-gate 
29210Sstevel@tonic-gate 		arqp->sts_status.sts_chk = 1;
29220Sstevel@tonic-gate 		arqp->sts_rqpkt_reason = CMD_CMPLT;
29230Sstevel@tonic-gate 		arqp->sts_rqpkt_state = STATE_XFERRED_DATA |
29240Sstevel@tonic-gate 		    STATE_GOT_BUS | STATE_GOT_STATUS;
29250Sstevel@tonic-gate 		arqp->sts_sensedata.es_valid = 1;
29260Sstevel@tonic-gate 		arqp->sts_sensedata.es_class = 7;
29270Sstevel@tonic-gate 		arqp->sts_sensedata.es_key = KEY_ILLEGAL_REQUEST;
29280Sstevel@tonic-gate 
29290Sstevel@tonic-gate 		cmd->cmd_pkt->pkt_state = STATE_ARQ_DONE |
29300Sstevel@tonic-gate 		    STATE_GOT_BUS | STATE_GOT_BUS | STATE_GOT_BUS |
29310Sstevel@tonic-gate 		    STATE_GOT_STATUS;
29320Sstevel@tonic-gate #ifdef DEBUG
29330Sstevel@tonic-gate 		{
29340Sstevel@tonic-gate 			uchar_t *p = (uchar_t *)(&arqp->sts_sensedata);
29350Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_SCSA,
29360Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
29370Sstevel@tonic-gate 			    "cdb: %x rqsense: "
29380Sstevel@tonic-gate 			    "%x %x %x %x %x %x %x %x %x %x "
29390Sstevel@tonic-gate 			    "%x %x %x %x %x %x %x %x %x %x",
29400Sstevel@tonic-gate 			    cmd->cmd_pkt->pkt_cdbp[0],
29410Sstevel@tonic-gate 			    p[0], p[1], p[2], p[3], p[4],
29420Sstevel@tonic-gate 			    p[5], p[6], p[7], p[8], p[9],
29430Sstevel@tonic-gate 			    p[10], p[11], p[12], p[13], p[14],
29440Sstevel@tonic-gate 			    p[15], p[16], p[17], p[18], p[19]);
29450Sstevel@tonic-gate 		}
29460Sstevel@tonic-gate #endif
29470Sstevel@tonic-gate 
29480Sstevel@tonic-gate 	}
29490Sstevel@tonic-gate }
29500Sstevel@tonic-gate 
29510Sstevel@tonic-gate 
29520Sstevel@tonic-gate /*
29530Sstevel@tonic-gate  * scsa2usb_cmd_transport:
29540Sstevel@tonic-gate  */
29550Sstevel@tonic-gate static int
29560Sstevel@tonic-gate scsa2usb_cmd_transport(scsa2usb_state_t *scsa2usbp, scsa2usb_cmd_t *cmd)
29570Sstevel@tonic-gate {
29580Sstevel@tonic-gate 	int rval, transport;
29590Sstevel@tonic-gate 	struct scsi_pkt *pkt;
29600Sstevel@tonic-gate 
29610Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
29620Sstevel@tonic-gate 	    "scsa2usb_cmd_transport: pkt: 0x%p, cur_pkt = 0x%p",
29636898Sfb209375 	    (void *)cmd->cmd_pkt, (void *)scsa2usbp->scsa2usb_cur_pkt);
29640Sstevel@tonic-gate 
29650Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
29660Sstevel@tonic-gate 	ASSERT(scsa2usbp->scsa2usb_cur_pkt == NULL);
29670Sstevel@tonic-gate 
29680Sstevel@tonic-gate 	pkt = scsa2usbp->scsa2usb_cur_pkt = cmd->cmd_pkt;
29690Sstevel@tonic-gate 
29700Sstevel@tonic-gate 	/* check black-listed attrs first */
29710Sstevel@tonic-gate 	if (SCSA2USB_IS_BULK_ONLY(scsa2usbp)) {
29720Sstevel@tonic-gate 		transport = scsa2usb_check_bulkonly_blacklist_attrs(scsa2usbp,
29734700Sfb209375 		    cmd, pkt->pkt_cdbp[0]);
29740Sstevel@tonic-gate 	} else if (SCSA2USB_IS_CB(scsa2usbp) || SCSA2USB_IS_CBI(scsa2usbp)) {
29750Sstevel@tonic-gate 		transport =  scsa2usb_check_ufi_blacklist_attrs(scsa2usbp,
29764700Sfb209375 		    pkt->pkt_cdbp[0], cmd);
29770Sstevel@tonic-gate 	}
29780Sstevel@tonic-gate 
297910630SGuoqing.Zhu@Sun.COM 	/* just accept the command or return error */
29800Sstevel@tonic-gate 	if (transport == SCSA2USB_JUST_ACCEPT) {
29810Sstevel@tonic-gate 		SCSA2USB_SET_PKT_DO_COMP_STATE(scsa2usbp);
29820Sstevel@tonic-gate 
29830Sstevel@tonic-gate 		return (TRAN_ACCEPT);
298410630SGuoqing.Zhu@Sun.COM 	} else if (transport == SCSA2USB_REJECT) {
298510630SGuoqing.Zhu@Sun.COM 		return (TRAN_FATAL_ERROR);
29860Sstevel@tonic-gate 	}
29870Sstevel@tonic-gate 
29880Sstevel@tonic-gate 	/* check command set next */
29890Sstevel@tonic-gate 	if (SCSA2USB_IS_SCSI_CMDSET(scsa2usbp) ||
29900Sstevel@tonic-gate 	    SCSA2USB_IS_ATAPI_CMDSET(scsa2usbp)) {
29910Sstevel@tonic-gate 		transport =
29920Sstevel@tonic-gate 		    scsa2usb_handle_scsi_cmd_sub_class(scsa2usbp, cmd, pkt);
29930Sstevel@tonic-gate 	} else if (SCSA2USB_IS_UFI_CMDSET(scsa2usbp)) {
29940Sstevel@tonic-gate 		transport =
29950Sstevel@tonic-gate 		    scsa2usb_handle_ufi_subclass_cmd(scsa2usbp, cmd, pkt);
29960Sstevel@tonic-gate 	} else {
29970Sstevel@tonic-gate 		transport = SCSA2USB_REJECT;
29980Sstevel@tonic-gate 	}
29990Sstevel@tonic-gate 
30001984Scg149915 	switch (transport) {
30011984Scg149915 	case SCSA2USB_TRANSPORT:
30020Sstevel@tonic-gate 		if (SCSA2USB_IS_BULK_ONLY(scsa2usbp)) {
30030Sstevel@tonic-gate 			rval = scsa2usb_bulk_only_transport(scsa2usbp, cmd);
30040Sstevel@tonic-gate 		} else if (SCSA2USB_IS_CB(scsa2usbp) ||
30050Sstevel@tonic-gate 		    SCSA2USB_IS_CBI(scsa2usbp)) {
30060Sstevel@tonic-gate 			rval = scsa2usb_cbi_transport(scsa2usbp, cmd);
30070Sstevel@tonic-gate 		} else {
30080Sstevel@tonic-gate 			rval = TRAN_FATAL_ERROR;
30090Sstevel@tonic-gate 		}
30101984Scg149915 		break;
30111984Scg149915 	case SCSA2USB_JUST_ACCEPT:
30121984Scg149915 		SCSA2USB_SET_PKT_DO_COMP_STATE(scsa2usbp);
30131984Scg149915 		rval = TRAN_ACCEPT;
30141984Scg149915 		break;
30151984Scg149915 	default:
30160Sstevel@tonic-gate 		rval = TRAN_FATAL_ERROR;
30170Sstevel@tonic-gate 	}
30180Sstevel@tonic-gate 
30190Sstevel@tonic-gate 	return (rval);
30200Sstevel@tonic-gate }
30210Sstevel@tonic-gate 
30220Sstevel@tonic-gate 
30230Sstevel@tonic-gate /*
30240Sstevel@tonic-gate  * scsa2usb_check_bulkonly_blacklist_attrs:
30250Sstevel@tonic-gate  *	validate "scsa2usb_blacklist_attrs" (see scsa2usb.h)
30260Sstevel@tonic-gate  *	if blacklisted attrs match accept the request
30270Sstevel@tonic-gate  *	attributes checked are:-
30280Sstevel@tonic-gate  *		SCSA2USB_ATTRS_START_STOP
30290Sstevel@tonic-gate  */
30300Sstevel@tonic-gate int
30310Sstevel@tonic-gate scsa2usb_check_bulkonly_blacklist_attrs(scsa2usb_state_t *scsa2usbp,
30320Sstevel@tonic-gate     scsa2usb_cmd_t *cmd, uchar_t opcode)
30330Sstevel@tonic-gate {
3034880Sfrits 	struct scsi_inquiry *inq =
3035880Sfrits 	    &scsa2usbp->scsa2usb_lun_inquiry[cmd->cmd_pkt->pkt_address.a_lun];
3036880Sfrits 
30370Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
30380Sstevel@tonic-gate 	    "scsa2usb_check_bulkonly_blacklist_attrs: opcode = %s",
30390Sstevel@tonic-gate 	    scsi_cname(opcode, scsa2usb_cmds));
30400Sstevel@tonic-gate 
30410Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
30420Sstevel@tonic-gate 
30430Sstevel@tonic-gate 	/*
30440Sstevel@tonic-gate 	 * decode and convert the packet
30450Sstevel@tonic-gate 	 * for most cmds, we can bcopy the cdb
30460Sstevel@tonic-gate 	 */
30470Sstevel@tonic-gate 	switch (opcode) {
30480Sstevel@tonic-gate 	case SCMD_DOORLOCK:
30490Sstevel@tonic-gate 		if (!(scsa2usbp->scsa2usb_attrs & SCSA2USB_ATTRS_DOORLOCK)) {
30500Sstevel@tonic-gate 
30510Sstevel@tonic-gate 			return (SCSA2USB_JUST_ACCEPT);
30520Sstevel@tonic-gate 
3053880Sfrits 		/*
3054880Sfrits 		 * only lock the door for CD and DVD drives
3055880Sfrits 		 */
3056880Sfrits 		} else if ((inq->inq_dtype == DTYPE_RODIRECT) ||
3057880Sfrits 		    (inq->inq_dtype == DTYPE_OPTICAL)) {
3058880Sfrits 
3059880Sfrits 			if (inq->inq_rmb) {
3060880Sfrits 
3061880Sfrits 				break;
3062880Sfrits 			}
30630Sstevel@tonic-gate 		}
30640Sstevel@tonic-gate 
30650Sstevel@tonic-gate 		return (SCSA2USB_JUST_ACCEPT);
30660Sstevel@tonic-gate 
3067*11282SSheshadri.Vasudevan@Sun.COM 	case SCMD_START_STOP:	/* SCMD_LOAD for sequential devices */
30680Sstevel@tonic-gate 		/*
30690Sstevel@tonic-gate 		 * these devices don't have mechanics that spin the
30700Sstevel@tonic-gate 		 * media up and down. So, it doesn't make much sense
30710Sstevel@tonic-gate 		 * to issue this cmd.
30720Sstevel@tonic-gate 		 *
30730Sstevel@tonic-gate 		 * Furthermore, Hagiwara devices do not handle these
30740Sstevel@tonic-gate 		 * cmds well. just accept this command as success.
30750Sstevel@tonic-gate 		 */
30760Sstevel@tonic-gate 		if (!(scsa2usbp->scsa2usb_attrs & SCSA2USB_ATTRS_START_STOP)) {
30770Sstevel@tonic-gate 
30780Sstevel@tonic-gate 			return (SCSA2USB_JUST_ACCEPT);
30790Sstevel@tonic-gate 
3080*11282SSheshadri.Vasudevan@Sun.COM 		} else if (inq->inq_dtype == DTYPE_SEQUENTIAL) {
3081*11282SSheshadri.Vasudevan@Sun.COM 			/*
3082*11282SSheshadri.Vasudevan@Sun.COM 			 * In case of USB tape device, we need to send the
3083*11282SSheshadri.Vasudevan@Sun.COM 			 * command to the device to unload the media.
3084*11282SSheshadri.Vasudevan@Sun.COM 			 */
3085*11282SSheshadri.Vasudevan@Sun.COM 			break;
3086*11282SSheshadri.Vasudevan@Sun.COM 
30870Sstevel@tonic-gate 		} else if (cmd->cmd_pkt->pkt_cdbp[4] & LOEJECT) {
30880Sstevel@tonic-gate 			/*
30890Sstevel@tonic-gate 			 * if the device is really a removable then
30900Sstevel@tonic-gate 			 * pass it on to the device, else just accept
30910Sstevel@tonic-gate 			 */
3092880Sfrits 			if (inq->inq_rmb) {
30930Sstevel@tonic-gate 
30940Sstevel@tonic-gate 				break;
30950Sstevel@tonic-gate 			}
30960Sstevel@tonic-gate 
30970Sstevel@tonic-gate 			return (SCSA2USB_JUST_ACCEPT);
30980Sstevel@tonic-gate 
30990Sstevel@tonic-gate 		} else if (!scsa2usbp->scsa2usb_rcvd_not_ready) {
31000Sstevel@tonic-gate 			/*
31010Sstevel@tonic-gate 			 * if we have not received a NOT READY condition,
31020Sstevel@tonic-gate 			 * just accept since some device choke on this too.
31030Sstevel@tonic-gate 			 * we do have to let EJECT get through though
31040Sstevel@tonic-gate 			 */
31050Sstevel@tonic-gate 			return (SCSA2USB_JUST_ACCEPT);
31060Sstevel@tonic-gate 		}
31070Sstevel@tonic-gate 
31080Sstevel@tonic-gate 		break;
31090Sstevel@tonic-gate 	case SCMD_INQUIRY:
31100Sstevel@tonic-gate 		/*
31110Sstevel@tonic-gate 		 * Some devices do not handle the inquiry cmd well
31120Sstevel@tonic-gate 		 * so build an inquiry and accept this command as
31130Sstevel@tonic-gate 		 * success.
31140Sstevel@tonic-gate 		 */
31150Sstevel@tonic-gate 		if (!(scsa2usbp->scsa2usb_attrs & SCSA2USB_ATTRS_INQUIRY)) {
31160Sstevel@tonic-gate 			uchar_t evpd = 0x01;
31178003SVitezslav.Batrla@Sun.COM 			unsigned int bufsize;
31188003SVitezslav.Batrla@Sun.COM 			int count;
31198003SVitezslav.Batrla@Sun.COM 
312010630SGuoqing.Zhu@Sun.COM 			if (cmd->cmd_pkt->pkt_cdbp[1] & evpd)
31210Sstevel@tonic-gate 				return (SCSA2USB_REJECT);
31228003SVitezslav.Batrla@Sun.COM 
31238003SVitezslav.Batrla@Sun.COM 			scsa2usb_fake_inquiry(scsa2usbp, inq);
31248003SVitezslav.Batrla@Sun.COM 
31258003SVitezslav.Batrla@Sun.COM 			/* Copy no more than requested */
31268003SVitezslav.Batrla@Sun.COM 			count = MIN(cmd->cmd_bp->b_bcount,
31278003SVitezslav.Batrla@Sun.COM 			    sizeof (struct scsi_inquiry));
31288003SVitezslav.Batrla@Sun.COM 			bufsize = cmd->cmd_pkt->pkt_cdbp[4];
31298003SVitezslav.Batrla@Sun.COM 			count = MIN(count, bufsize);
31308003SVitezslav.Batrla@Sun.COM 			bcopy(inq, cmd->cmd_bp->b_un.b_addr, count);
31318003SVitezslav.Batrla@Sun.COM 
31328003SVitezslav.Batrla@Sun.COM 			cmd->cmd_pkt->pkt_resid = bufsize - count;
31330Sstevel@tonic-gate 			cmd->cmd_pkt->pkt_state |= STATE_XFERRED_DATA;
31340Sstevel@tonic-gate 
31350Sstevel@tonic-gate 			return (SCSA2USB_JUST_ACCEPT);
313610678SGuoqing.Zhu@Sun.COM 		} else if (!(scsa2usbp->scsa2usb_attrs &
313710678SGuoqing.Zhu@Sun.COM 		    SCSA2USB_ATTRS_INQUIRY_EVPD)) {
313810678SGuoqing.Zhu@Sun.COM 			/*
313910678SGuoqing.Zhu@Sun.COM 			 * Some devices do not handle the inquiry cmd with
314010678SGuoqing.Zhu@Sun.COM 			 * evpd bit set well, e.g. some devices return the
314110678SGuoqing.Zhu@Sun.COM 			 * same page 0x83 data which will cause the generated
314210678SGuoqing.Zhu@Sun.COM 			 * devid by sd is not unique, thus return CHECK
314310678SGuoqing.Zhu@Sun.COM 			 * CONDITION directly to sd.
314410678SGuoqing.Zhu@Sun.COM 			 */
314510678SGuoqing.Zhu@Sun.COM 			uchar_t evpd = 0x01;
314610678SGuoqing.Zhu@Sun.COM 
314710678SGuoqing.Zhu@Sun.COM 			if (!(cmd->cmd_pkt->pkt_cdbp[1] & evpd))
314810678SGuoqing.Zhu@Sun.COM 				break;
314910678SGuoqing.Zhu@Sun.COM 
315010678SGuoqing.Zhu@Sun.COM 			if (cmd->cmd_bp) {
315110678SGuoqing.Zhu@Sun.COM 				cmd->cmd_pkt->pkt_resid = cmd->cmd_bp->
315210678SGuoqing.Zhu@Sun.COM 				    b_bcount;
315310678SGuoqing.Zhu@Sun.COM 			}
315410678SGuoqing.Zhu@Sun.COM 			scsa2usb_force_invalid_request(scsa2usbp, cmd);
315510678SGuoqing.Zhu@Sun.COM 
315610678SGuoqing.Zhu@Sun.COM 			return (SCSA2USB_JUST_ACCEPT);
31570Sstevel@tonic-gate 		}
31580Sstevel@tonic-gate 		break;
31590Sstevel@tonic-gate 	/*
3160880Sfrits 	 * Fake accepting the following  Opcodes
3161880Sfrits 	 * (as most drives don't support these)
31620Sstevel@tonic-gate 	 * These are needed by format command.
31630Sstevel@tonic-gate 	 */
31640Sstevel@tonic-gate 	case SCMD_RESERVE:
31650Sstevel@tonic-gate 	case SCMD_RELEASE:
31660Sstevel@tonic-gate 	case SCMD_PERSISTENT_RESERVE_IN:
31670Sstevel@tonic-gate 	case SCMD_PERSISTENT_RESERVE_OUT:
31680Sstevel@tonic-gate 
31690Sstevel@tonic-gate 		return (SCSA2USB_JUST_ACCEPT);
31700Sstevel@tonic-gate 
31710Sstevel@tonic-gate 	case SCMD_MODE_SENSE:
31720Sstevel@tonic-gate 	case SCMD_MODE_SELECT:
31730Sstevel@tonic-gate 	case SCMD_MODE_SENSE_G1:
31740Sstevel@tonic-gate 	case SCMD_MODE_SELECT_G1:
31750Sstevel@tonic-gate 		if (!(scsa2usbp->scsa2usb_attrs & SCSA2USB_ATTRS_MODE_SENSE)) {
31760Sstevel@tonic-gate 			if (cmd->cmd_bp) {
31770Sstevel@tonic-gate 				cmd->cmd_pkt->pkt_resid = cmd->cmd_bp->
31784700Sfb209375 				    b_bcount;
31790Sstevel@tonic-gate 			}
31800Sstevel@tonic-gate 			scsa2usb_force_invalid_request(scsa2usbp, cmd);
31810Sstevel@tonic-gate 
31820Sstevel@tonic-gate 			return (SCSA2USB_JUST_ACCEPT);
31830Sstevel@tonic-gate 		}
31840Sstevel@tonic-gate 
31850Sstevel@tonic-gate 		break;
31860Sstevel@tonic-gate 	default:
31870Sstevel@tonic-gate 
31880Sstevel@tonic-gate 		break;
31890Sstevel@tonic-gate 	}
31900Sstevel@tonic-gate 
31910Sstevel@tonic-gate 	return (SCSA2USB_TRANSPORT);
31920Sstevel@tonic-gate }
31930Sstevel@tonic-gate 
31940Sstevel@tonic-gate 
31950Sstevel@tonic-gate /*
31960Sstevel@tonic-gate  * scsa2usb_handle_scsi_cmd_sub_class:
31970Sstevel@tonic-gate  *	prepare a scsi cmd
31980Sstevel@tonic-gate  *	returns SCSA2USB_TRANSPORT, SCSA2USB_REJECT, SCSA2USB_JUST_ACCEPT
31990Sstevel@tonic-gate  */
32000Sstevel@tonic-gate int
32010Sstevel@tonic-gate scsa2usb_handle_scsi_cmd_sub_class(scsa2usb_state_t *scsa2usbp,
32020Sstevel@tonic-gate     scsa2usb_cmd_t *cmd, struct scsi_pkt *pkt)
32030Sstevel@tonic-gate {
320410678SGuoqing.Zhu@Sun.COM 	uchar_t evpd = 0x01;
32050Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
32060Sstevel@tonic-gate 	    "scsa2usb_handle_scsi_cmd_sub_class: cmd = 0x%p pkt = 0x%p",
32076898Sfb209375 	    (void *)cmd, (void *)pkt);
32080Sstevel@tonic-gate 
32090Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
32100Sstevel@tonic-gate 
32110Sstevel@tonic-gate 	bzero(&cmd->cmd_cdb, SCSI_CDB_SIZE);
32120Sstevel@tonic-gate 	cmd->cmd_cdb[SCSA2USB_OPCODE] = pkt->pkt_cdbp[0];   /* Set the opcode */
32130Sstevel@tonic-gate 	cmd->cmd_cdb[SCSA2USB_LUN] = pkt->pkt_cdbp[1];
32140Sstevel@tonic-gate 
32150Sstevel@tonic-gate 	/*
32160Sstevel@tonic-gate 	 * decode and convert the packet
32170Sstevel@tonic-gate 	 * for most cmds, we can bcopy the cdb
32180Sstevel@tonic-gate 	 */
32190Sstevel@tonic-gate 	switch (pkt->pkt_cdbp[0]) {
32200Sstevel@tonic-gate 	case SCMD_FORMAT:
32210Sstevel@tonic-gate 		/*
32220Sstevel@tonic-gate 		 * SCMD_FORMAT used to limit cmd->cmd_xfercount
32230Sstevel@tonic-gate 		 * to 4 bytes, but this hangs
32240Sstevel@tonic-gate 		 * formatting dvd media using cdrecord (that is,
32250Sstevel@tonic-gate 		 * a SCSI FORMAT UNIT command with a parameter list > 4 bytes)
32260Sstevel@tonic-gate 		 * (bit 4 in cdb1 is the Fmtdata bit)
32270Sstevel@tonic-gate 		 */
32280Sstevel@tonic-gate 		if ((pkt->pkt_cdbp[1] & 0x10) && cmd->cmd_bp) {
32290Sstevel@tonic-gate 			cmd->cmd_xfercount = cmd->cmd_bp->b_bcount;
32300Sstevel@tonic-gate 		} else {
32310Sstevel@tonic-gate 			cmd->cmd_xfercount = 4;
32320Sstevel@tonic-gate 		}
32330Sstevel@tonic-gate 		cmd->cmd_dir = CBW_DIR_OUT;
32340Sstevel@tonic-gate 		cmd->cmd_actual_len = CDB_GROUP0;
32350Sstevel@tonic-gate 		bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
32360Sstevel@tonic-gate 		break;
32370Sstevel@tonic-gate 
32380Sstevel@tonic-gate 	case SCMD_INQUIRY:
32390Sstevel@tonic-gate 		cmd->cmd_dir = CBW_DIR_IN;
32400Sstevel@tonic-gate 		cmd->cmd_actual_len = CDB_GROUP0;
32410Sstevel@tonic-gate 		cmd->cmd_cdb[SCSA2USB_LBA_0] = pkt->pkt_cdbp[2];
324210678SGuoqing.Zhu@Sun.COM 
324310678SGuoqing.Zhu@Sun.COM 		/*
324410678SGuoqing.Zhu@Sun.COM 		 * If vpd pages data is limited to maximum SCSA2USB_MAX_INQ_LEN,
324510678SGuoqing.Zhu@Sun.COM 		 * the page data may be truncated, which may cause some issues
324610678SGuoqing.Zhu@Sun.COM 		 * such as making the unique page 0x83 or 0x80 data from
324710678SGuoqing.Zhu@Sun.COM 		 * different devices become the same. So don't limit return
324810678SGuoqing.Zhu@Sun.COM 		 * length for vpd page inquiry cmd.
324910678SGuoqing.Zhu@Sun.COM 		 * Another, in order to maintain compatibility, the original
325010678SGuoqing.Zhu@Sun.COM 		 * length limitation for standard inquiry retains here. It
325110678SGuoqing.Zhu@Sun.COM 		 * can be removed in future if it is verified that enough
325210678SGuoqing.Zhu@Sun.COM 		 * devices can work well.
325310678SGuoqing.Zhu@Sun.COM 		 */
325410678SGuoqing.Zhu@Sun.COM 		if (pkt->pkt_cdbp[1] & evpd) {
325510678SGuoqing.Zhu@Sun.COM 			cmd->cmd_cdb[SCSA2USB_LBA_2] = cmd->cmd_xfercount =
325610678SGuoqing.Zhu@Sun.COM 			    (cmd->cmd_bp ? cmd->cmd_bp->b_bcount : 0);
325710678SGuoqing.Zhu@Sun.COM 		} else {
325810678SGuoqing.Zhu@Sun.COM 			cmd->cmd_cdb[SCSA2USB_LBA_2] = cmd->cmd_xfercount =
325910678SGuoqing.Zhu@Sun.COM 			    min(SCSA2USB_MAX_INQ_LEN,
326010678SGuoqing.Zhu@Sun.COM 			    cmd->cmd_bp ? cmd->cmd_bp->b_bcount : 0);
326110678SGuoqing.Zhu@Sun.COM 		}
32620Sstevel@tonic-gate 		break;
32630Sstevel@tonic-gate 
32640Sstevel@tonic-gate 	case SCMD_READ_CAPACITY:
32650Sstevel@tonic-gate 		cmd->cmd_dir = CBW_DIR_IN;
32660Sstevel@tonic-gate 		bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
32670Sstevel@tonic-gate 		cmd->cmd_xfercount = sizeof (scsa2usb_read_cap_t);
32680Sstevel@tonic-gate 		break;
32690Sstevel@tonic-gate 
32700Sstevel@tonic-gate 	/*
32710Sstevel@tonic-gate 	 * SCMD_READ/SCMD_WRITE are converted to G1 cmds
32720Sstevel@tonic-gate 	 * (as ATAPI devices don't recognize G0 commands)
32730Sstevel@tonic-gate 	 *
32740Sstevel@tonic-gate 	 * SCMD_READ_LONG/SCMD_WRITE_LONG are handled in
32750Sstevel@tonic-gate 	 * scsa2usb_rw_transport() along with other commands.
32760Sstevel@tonic-gate 	 *
32770Sstevel@tonic-gate 	 * USB Host Controllers cannot handle large (read/write)
32780Sstevel@tonic-gate 	 * xfers. We split the large request to chunks of
32790Sstevel@tonic-gate 	 * smaller ones to meet the HCD limitations.
32800Sstevel@tonic-gate 	 */
32810Sstevel@tonic-gate 	case SCMD_READ:
32820Sstevel@tonic-gate 	case SCMD_WRITE:
32830Sstevel@tonic-gate 	case SCMD_READ_G1:
32840Sstevel@tonic-gate 	case SCMD_WRITE_G1:
32850Sstevel@tonic-gate 	case SCMD_READ_G5:
32860Sstevel@tonic-gate 	case SCMD_WRITE_G5:
32870Sstevel@tonic-gate 	case SCMD_READ_LONG:
32880Sstevel@tonic-gate 	case SCMD_WRITE_LONG:
32890Sstevel@tonic-gate 	case SCMD_READ_CD:
32900Sstevel@tonic-gate 		switch (scsa2usbp->
32910Sstevel@tonic-gate 		    scsa2usb_lun_inquiry[pkt->pkt_address.a_lun].
32920Sstevel@tonic-gate 		    inq_dtype & DTYPE_MASK) {
32930Sstevel@tonic-gate 		case DTYPE_DIRECT:
32940Sstevel@tonic-gate 		case DTYPE_RODIRECT:
32950Sstevel@tonic-gate 		case DTYPE_OPTICAL:
32960Sstevel@tonic-gate 			return (scsa2usb_rw_transport(
32974700Sfb209375 			    scsa2usbp, pkt));
32980Sstevel@tonic-gate 		default:
32990Sstevel@tonic-gate 			bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
33000Sstevel@tonic-gate 			if (cmd->cmd_bp) {
33010Sstevel@tonic-gate 				cmd->cmd_dir =
33020Sstevel@tonic-gate 				    (cmd->cmd_bp->b_flags & B_READ) ?
33030Sstevel@tonic-gate 				    CBW_DIR_IN : CBW_DIR_OUT;
33040Sstevel@tonic-gate 				cmd->cmd_xfercount =
33050Sstevel@tonic-gate 				    cmd->cmd_bp->b_bcount;
33060Sstevel@tonic-gate 			}
33070Sstevel@tonic-gate 			break;
33080Sstevel@tonic-gate 		}
33090Sstevel@tonic-gate 		break;
33100Sstevel@tonic-gate 
33110Sstevel@tonic-gate 	case SCMD_REQUEST_SENSE:
33120Sstevel@tonic-gate 		cmd->cmd_dir = CBW_DIR_IN;
33130Sstevel@tonic-gate 		cmd->cmd_xfercount = pkt->pkt_cdbp[4];
33140Sstevel@tonic-gate 		cmd->cmd_cdb[SCSA2USB_LBA_2] = pkt->pkt_cdbp[4];
33150Sstevel@tonic-gate 		cmd->cmd_actual_len = CDB_GROUP0;
33160Sstevel@tonic-gate 		break;
33170Sstevel@tonic-gate 
33180Sstevel@tonic-gate 	case SCMD_DOORLOCK:
33190Sstevel@tonic-gate 	case SCMD_START_STOP:
33200Sstevel@tonic-gate 	case SCMD_TEST_UNIT_READY:
33210Sstevel@tonic-gate 		bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
33220Sstevel@tonic-gate 		break;
33230Sstevel@tonic-gate 
33240Sstevel@tonic-gate 	/*
33250Sstevel@tonic-gate 	 * Needed by zip protocol to reset the device
33260Sstevel@tonic-gate 	 */
33270Sstevel@tonic-gate 	case SCMD_SDIAG:
33280Sstevel@tonic-gate 	case SCMD_REZERO_UNIT:
33290Sstevel@tonic-gate 		bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
33300Sstevel@tonic-gate 		cmd->cmd_actual_len = CDB_GROUP1;
33310Sstevel@tonic-gate 		break;
33320Sstevel@tonic-gate 
33330Sstevel@tonic-gate 	case SCMD_WRITE_VERIFY:
33340Sstevel@tonic-gate 		bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
33350Sstevel@tonic-gate 		cmd->cmd_dir = CBW_DIR_OUT;
33360Sstevel@tonic-gate 		cmd->cmd_xfercount = (pkt->pkt_cdbp[7] << 8) | pkt->pkt_cdbp[8];
33370Sstevel@tonic-gate 		cmd->cmd_actual_len = CDB_GROUP1;
33380Sstevel@tonic-gate 		break;
33390Sstevel@tonic-gate 
33400Sstevel@tonic-gate 	/*
33410Sstevel@tonic-gate 	 * Next command does not have a SCSI equivalent as
33420Sstevel@tonic-gate 	 * it is vendor specific.
33430Sstevel@tonic-gate 	 * It was listed in the vendor's ATAPI Zip specs.
33440Sstevel@tonic-gate 	 */
33450Sstevel@tonic-gate 	case SCMD_READ_FORMAT_CAP:
33460Sstevel@tonic-gate 		bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
33470Sstevel@tonic-gate 		cmd->cmd_dir = CBW_DIR_IN;
33480Sstevel@tonic-gate 		cmd->cmd_xfercount = (pkt->pkt_cdbp[7] << 8) | pkt->pkt_cdbp[8];
33490Sstevel@tonic-gate 		cmd->cmd_actual_len = CDB_GROUP1;
33500Sstevel@tonic-gate 		break;
33510Sstevel@tonic-gate 	case IOMEGA_CMD_CARTRIDGE_PROTECT:
33520Sstevel@tonic-gate 		cmd->cmd_dir = CBW_DIR_OUT;
33530Sstevel@tonic-gate 		cmd->cmd_cdb[SCSA2USB_LBA_2] = pkt->pkt_cdbp[4];
33540Sstevel@tonic-gate 		cmd->cmd_cdb[SCSA2USB_LBA_2] &= ~1;	/* Make it even */
33550Sstevel@tonic-gate 		cmd->cmd_cdb[SCSA2USB_LUN] = pkt->pkt_cdbp[1];
33560Sstevel@tonic-gate 		cmd->cmd_actual_len = CDB_GROUP0;
33570Sstevel@tonic-gate 		cmd->cmd_xfercount = pkt->pkt_cdbp[4]; /* Length of password */
33580Sstevel@tonic-gate 		break;
33590Sstevel@tonic-gate 
33602057Scg149915 	/*
33612057Scg149915 	 * Do not convert SCMD_MODE_SENSE/SELECT to G1 cmds because
33622057Scg149915 	 * the mode header is different as well. USB devices don't
33632057Scg149915 	 * support 0x03 & 0x04 mode pages, which are already obsoleted
33642057Scg149915 	 * by SPC-2 specification.
33652057Scg149915 	 */
33662057Scg149915 	case SCMD_MODE_SENSE:
33672057Scg149915 	case SCMD_MODE_SELECT:
336810018SGuoqing.Zhu@Sun.COM 		if (((pkt->pkt_cdbp[2] & SD_MODE_SENSE_PAGE_MASK)
336910018SGuoqing.Zhu@Sun.COM 		    == SD_MODE_SENSE_PAGE3_CODE) ||
337010018SGuoqing.Zhu@Sun.COM 		    ((pkt->pkt_cdbp[2] & SD_MODE_SENSE_PAGE_MASK)
337110018SGuoqing.Zhu@Sun.COM 		    == SD_MODE_SENSE_PAGE4_CODE)) {
33722057Scg149915 			if (cmd->cmd_bp) {
33732057Scg149915 				cmd->cmd_pkt->pkt_resid = cmd->cmd_bp->b_bcount;
33742057Scg149915 			}
33752057Scg149915 			scsa2usb_force_invalid_request(scsa2usbp, cmd);
33762057Scg149915 			return (SCSA2USB_JUST_ACCEPT);
33772057Scg149915 		}
33782057Scg149915 		/* FALLTHROUGH */
33792057Scg149915 
33800Sstevel@tonic-gate 	default:
33810Sstevel@tonic-gate 		/*
33820Sstevel@tonic-gate 		 * an unknown command may be a uscsi cmd which we
33830Sstevel@tonic-gate 		 * should let go thru without mapping
33840Sstevel@tonic-gate 		 */
33850Sstevel@tonic-gate 		bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
33860Sstevel@tonic-gate 		if (cmd->cmd_bp) {
33870Sstevel@tonic-gate 			cmd->cmd_dir = (cmd->cmd_bp->b_flags & B_READ) ?
33884700Sfb209375 			    CBW_DIR_IN : CBW_DIR_OUT;
33890Sstevel@tonic-gate 			cmd->cmd_xfercount = cmd->cmd_bp->b_bcount;
33900Sstevel@tonic-gate 		}
33910Sstevel@tonic-gate 
33920Sstevel@tonic-gate 		break;
33930Sstevel@tonic-gate 	} /* end of switch */
33940Sstevel@tonic-gate 
33950Sstevel@tonic-gate 	USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
33960Sstevel@tonic-gate 	    "scsa2usb_handle_scsi_cmd_sub_class: opcode = 0x%x count = 0x%lx",
33970Sstevel@tonic-gate 	    pkt->pkt_cdbp[SCSA2USB_OPCODE], cmd->cmd_xfercount);
33980Sstevel@tonic-gate 
33990Sstevel@tonic-gate 	cmd->cmd_total_xfercount = cmd->cmd_xfercount;
34000Sstevel@tonic-gate 
34010Sstevel@tonic-gate 	return (SCSA2USB_TRANSPORT);
34020Sstevel@tonic-gate }
34030Sstevel@tonic-gate 
34040Sstevel@tonic-gate 
34050Sstevel@tonic-gate /*
34062506Ssl147100  * scsa2usb_do_tur is performed before READ CAPACITY command is issued.
34072506Ssl147100  * It returns media status, 0 for media ready, -1 for media not ready
34082506Ssl147100  * or other errors.
34092506Ssl147100  */
34102506Ssl147100 static int
34112506Ssl147100 scsa2usb_do_tur(scsa2usb_state_t *scsa2usbp, struct scsi_address *ap)
34122506Ssl147100 {
34132506Ssl147100 	struct scsi_pkt		*pkt;
34142506Ssl147100 	scsa2usb_cmd_t		*turcmd;
34152506Ssl147100 	int			rval = -1;
34162506Ssl147100 
34172506Ssl147100 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
34182506Ssl147100 	    "scsa2usb_do_tur:");
34192506Ssl147100 
34202506Ssl147100 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
34212506Ssl147100 
34222506Ssl147100 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
34232506Ssl147100 	if ((pkt = scsi_init_pkt(ap, NULL, NULL, CDB_GROUP0, 1,
34242506Ssl147100 	    PKT_PRIV_LEN, PKT_CONSISTENT, SLEEP_FUNC, NULL)) == NULL) {
34252506Ssl147100 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
34262506Ssl147100 		USB_DPRINTF_L2(DPRINT_MASK_SCSA,
34272506Ssl147100 		    scsa2usbp->scsa2usb_log_handle,
34282506Ssl147100 		    "scsa2usb_do_tur: init pkt failed");
34292506Ssl147100 
34302506Ssl147100 		return (rval);
34312506Ssl147100 	}
34322506Ssl147100 
34332506Ssl147100 	RQ_MAKECOM_G0(pkt, FLAG_HEAD | FLAG_NODISCON,
34342506Ssl147100 	    (char)SCMD_TEST_UNIT_READY, 0, 0);
34352506Ssl147100 
34362506Ssl147100 	pkt->pkt_comp = NULL;
34372506Ssl147100 	pkt->pkt_time = PKT_DEFAULT_TIMEOUT;
34382506Ssl147100 	turcmd = PKT2CMD(pkt);
34392506Ssl147100 
34402506Ssl147100 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
34412506Ssl147100 	scsa2usb_prepare_pkt(scsa2usbp, turcmd->cmd_pkt);
34422506Ssl147100 
34432506Ssl147100 	if (scsa2usb_cmd_transport(scsa2usbp, turcmd) != TRAN_ACCEPT) {
34442506Ssl147100 		USB_DPRINTF_L2(DPRINT_MASK_SCSA,
34452506Ssl147100 		    scsa2usbp->scsa2usb_log_handle,
34462506Ssl147100 		    "scsa2usb_do_tur: cmd transport failed, "
34472506Ssl147100 		    "pkt_reason=0x%x", turcmd->cmd_pkt->pkt_reason);
34482506Ssl147100 	} else if (*(turcmd->cmd_pkt->pkt_scbp) != STATUS_GOOD) {
34492506Ssl147100 		/*
34502506Ssl147100 		 * Theoretically, the sense data should be retrieved and
34512506Ssl147100 		 * sense key be checked when check condition happens. If
34522506Ssl147100 		 * the sense key is UNIT ATTENTION, TEST UNIT READY cmd
34532506Ssl147100 		 * needs to be sent again to clear the UNIT ATTENTION and
34542506Ssl147100 		 * another TUR to be sent to get the real media status.
34552506Ssl147100 		 * But the AMI virtual floppy device simply cannot recover
34562506Ssl147100 		 * from UNIT ATTENTION by re-sending a TUR cmd, so it
34572506Ssl147100 		 * doesn't make any difference whether to check sense key
34582506Ssl147100 		 * or not. Just ignore sense key checking here and assume
34592506Ssl147100 		 * the device is NOT READY.
34602506Ssl147100 		 */
34612506Ssl147100 		USB_DPRINTF_L2(DPRINT_MASK_SCSA,
34622506Ssl147100 		    scsa2usbp->scsa2usb_log_handle,
34632506Ssl147100 		    "scsa2usb_do_tur: media not ready");
34642506Ssl147100 	} else {
34652506Ssl147100 		rval = 0;
34662506Ssl147100 	}
34672506Ssl147100 
34682506Ssl147100 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
34692506Ssl147100 	scsi_destroy_pkt(pkt);
34702506Ssl147100 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
34712506Ssl147100 
34722506Ssl147100 	return (rval);
34732506Ssl147100 }
34742506Ssl147100 
34752506Ssl147100 
34762506Ssl147100 /*
34770Sstevel@tonic-gate  * scsa2usb_check_ufi_blacklist_attrs:
34780Sstevel@tonic-gate  *	validate "scsa2usb_blacklist_attrs" (see scsa2usb.h)
34790Sstevel@tonic-gate  *	if blacklisted attrs match accept the request
34800Sstevel@tonic-gate  *	attributes checked are:-
34810Sstevel@tonic-gate  *		SCSA2USB_ATTRS_GET_CONF
34820Sstevel@tonic-gate  *		SCSA2USB_ATTRS_GET_PERF
34830Sstevel@tonic-gate  *		SCSA2USB_ATTRS_GET_START_STOP
34840Sstevel@tonic-gate  */
34850Sstevel@tonic-gate static int
34860Sstevel@tonic-gate scsa2usb_check_ufi_blacklist_attrs(scsa2usb_state_t *scsa2usbp, uchar_t opcode,
34870Sstevel@tonic-gate     scsa2usb_cmd_t *cmd)
34880Sstevel@tonic-gate {
34890Sstevel@tonic-gate 	int	rval = SCSA2USB_TRANSPORT;
34900Sstevel@tonic-gate 
34910Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
34920Sstevel@tonic-gate 
34930Sstevel@tonic-gate 	switch (opcode) {
34940Sstevel@tonic-gate 	case SCMD_PRIN:
34950Sstevel@tonic-gate 	case SCMD_PROUT:
34960Sstevel@tonic-gate 		rval = SCSA2USB_JUST_ACCEPT;
34970Sstevel@tonic-gate 		break;
34980Sstevel@tonic-gate 	case SCMD_MODE_SENSE:
34990Sstevel@tonic-gate 	case SCMD_MODE_SELECT:
35000Sstevel@tonic-gate 		if (cmd->cmd_bp) {
35010Sstevel@tonic-gate 			cmd->cmd_pkt->pkt_resid = cmd->cmd_bp->b_bcount;
35020Sstevel@tonic-gate 		}
35030Sstevel@tonic-gate 		scsa2usb_force_invalid_request(scsa2usbp, cmd);
35040Sstevel@tonic-gate 		rval = SCSA2USB_JUST_ACCEPT;
35050Sstevel@tonic-gate 		break;
35060Sstevel@tonic-gate 	case SCMD_GET_CONFIGURATION:
35070Sstevel@tonic-gate 		if (!(scsa2usbp->scsa2usb_attrs & SCSA2USB_ATTRS_GET_CONF)) {
35080Sstevel@tonic-gate 			rval = SCSA2USB_JUST_ACCEPT;
35090Sstevel@tonic-gate 		}
35100Sstevel@tonic-gate 		break;
35110Sstevel@tonic-gate 	case SCMD_GET_PERFORMANCE:
35120Sstevel@tonic-gate 		if (!(scsa2usbp->scsa2usb_attrs & SCSA2USB_ATTRS_GET_PERF)) {
35130Sstevel@tonic-gate 			rval = SCSA2USB_JUST_ACCEPT;
35140Sstevel@tonic-gate 		}
35150Sstevel@tonic-gate 		break;
35160Sstevel@tonic-gate 	case SCMD_START_STOP:
35170Sstevel@tonic-gate 		/*
35180Sstevel@tonic-gate 		 * some CB/CBI devices don't have mechanics that spin the
35190Sstevel@tonic-gate 		 * media up and down. So, it doesn't make much sense
35200Sstevel@tonic-gate 		 * to issue this cmd to those devices.
35210Sstevel@tonic-gate 		 */
35220Sstevel@tonic-gate 		if (!(scsa2usbp->scsa2usb_attrs & SCSA2USB_ATTRS_START_STOP)) {
35230Sstevel@tonic-gate 			rval = SCSA2USB_JUST_ACCEPT;
35240Sstevel@tonic-gate 		}
35250Sstevel@tonic-gate 		break;
35262506Ssl147100 	case SCMD_READ_CAPACITY:
35272506Ssl147100 		/*
35282506Ssl147100 		 * Some devices don't support READ CAPACITY command
35292506Ssl147100 		 * when media is not ready. Need to check media status
35302506Ssl147100 		 * before issuing the cmd to such device.
35312506Ssl147100 		 */
35322506Ssl147100 		if (!(scsa2usbp->scsa2usb_attrs &
35332506Ssl147100 		    SCSA2USB_ATTRS_NO_MEDIA_CHECK)) {
35342506Ssl147100 			struct scsi_pkt *pkt = cmd->cmd_pkt;
35352506Ssl147100 
35362506Ssl147100 			ASSERT(scsa2usbp->scsa2usb_cur_pkt == pkt);
35372506Ssl147100 			scsa2usbp->scsa2usb_cur_pkt = NULL;
35382506Ssl147100 
35392506Ssl147100 			if (scsa2usb_do_tur(scsa2usbp,
35402506Ssl147100 			    &pkt->pkt_address) != 0) {
35412506Ssl147100 				/* media not ready, force cmd invalid */
35422506Ssl147100 				if (cmd->cmd_bp) {
35432506Ssl147100 					cmd->cmd_pkt->pkt_resid =
35442506Ssl147100 					    cmd->cmd_bp->b_bcount;
35452506Ssl147100 				}
35462506Ssl147100 				scsa2usb_force_invalid_request(scsa2usbp, cmd);
35472506Ssl147100 				rval = SCSA2USB_JUST_ACCEPT;
35482506Ssl147100 			}
35492506Ssl147100 
35502506Ssl147100 			scsa2usbp->scsa2usb_cur_pkt = pkt;
35512506Ssl147100 		}
35522506Ssl147100 		break;
35530Sstevel@tonic-gate 	default:
35540Sstevel@tonic-gate 		break;
35550Sstevel@tonic-gate 	}
35560Sstevel@tonic-gate 
35570Sstevel@tonic-gate 	return (rval);
35580Sstevel@tonic-gate }
35590Sstevel@tonic-gate 
35600Sstevel@tonic-gate 
35610Sstevel@tonic-gate /*
35620Sstevel@tonic-gate  * scsa2usb_handle_ufi_subclass_cmd:
35630Sstevel@tonic-gate  *	prepare a UFI cmd
35640Sstevel@tonic-gate  *	returns SCSA2USB_TRANSPORT, SCSA2USB_REJECT
35650Sstevel@tonic-gate  */
35660Sstevel@tonic-gate int
35670Sstevel@tonic-gate scsa2usb_handle_ufi_subclass_cmd(scsa2usb_state_t *scsa2usbp,
35680Sstevel@tonic-gate     scsa2usb_cmd_t *cmd, struct scsi_pkt *pkt)
35690Sstevel@tonic-gate {
35700Sstevel@tonic-gate 	uchar_t opcode =  pkt->pkt_cdbp[0];
35710Sstevel@tonic-gate 
35720Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
35730Sstevel@tonic-gate 	    "scsa2usb_handle_ufi_subclass_cmd: cmd = 0x%p pkt = 0x%p",
35746898Sfb209375 	    (void *)cmd, (void *)pkt);
35750Sstevel@tonic-gate 
35760Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
35770Sstevel@tonic-gate 
35780Sstevel@tonic-gate 	bzero(&cmd->cmd_cdb, SCSI_CDB_SIZE);
35790Sstevel@tonic-gate 	cmd->cmd_cdb[SCSA2USB_OPCODE] = opcode;   /* Set the opcode */
35800Sstevel@tonic-gate 	cmd->cmd_cdb[SCSA2USB_LUN] = pkt->pkt_cdbp[1];
35810Sstevel@tonic-gate 
35820Sstevel@tonic-gate 	/*
35830Sstevel@tonic-gate 	 * decode and convert the packet if necessary
35840Sstevel@tonic-gate 	 * for most cmds, we can bcopy the cdb
35850Sstevel@tonic-gate 	 */
35860Sstevel@tonic-gate 	switch (opcode) {
35870Sstevel@tonic-gate 	case SCMD_FORMAT:
35880Sstevel@tonic-gate 		/* if parameter list is specified */
35890Sstevel@tonic-gate 		if (pkt->pkt_cdbp[1] & 0x10) {
35900Sstevel@tonic-gate 			cmd->cmd_xfercount =
35914700Sfb209375 			    (pkt->pkt_cdbp[7] << 8) | pkt->pkt_cdbp[8];
35920Sstevel@tonic-gate 			cmd->cmd_dir = USB_EP_DIR_OUT;
35930Sstevel@tonic-gate 			cmd->cmd_actual_len = CDB_GROUP5;
35940Sstevel@tonic-gate 		}
35950Sstevel@tonic-gate 		bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
35960Sstevel@tonic-gate 		break;
35970Sstevel@tonic-gate 	case SCMD_INQUIRY:
35980Sstevel@tonic-gate 		cmd->cmd_dir = USB_EP_DIR_IN;
35990Sstevel@tonic-gate 		cmd->cmd_actual_len = CDB_GROUP0;
36000Sstevel@tonic-gate 		cmd->cmd_cdb[SCSA2USB_LBA_0] = pkt->pkt_cdbp[2];
36010Sstevel@tonic-gate 		cmd->cmd_cdb[SCSA2USB_LBA_2] = cmd->cmd_xfercount =
36020Sstevel@tonic-gate 		    min(SCSA2USB_MAX_INQ_LEN,
36030Sstevel@tonic-gate 		    cmd->cmd_bp ? cmd->cmd_bp->b_bcount : 0);
36040Sstevel@tonic-gate 		break;
36050Sstevel@tonic-gate 	case SCMD_READ_CAPACITY:
36060Sstevel@tonic-gate 		cmd->cmd_dir = USB_EP_DIR_IN;
36070Sstevel@tonic-gate 		bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
36080Sstevel@tonic-gate 		cmd->cmd_xfercount = sizeof (scsa2usb_read_cap_t);
36090Sstevel@tonic-gate 		break;
36100Sstevel@tonic-gate 	case SCMD_REQUEST_SENSE:
36110Sstevel@tonic-gate 		cmd->cmd_dir = USB_EP_DIR_IN;
36120Sstevel@tonic-gate 		cmd->cmd_xfercount = pkt->pkt_cdbp[4];
36130Sstevel@tonic-gate 		cmd->cmd_cdb[SCSA2USB_LBA_2] = pkt->pkt_cdbp[4];
36140Sstevel@tonic-gate 		cmd->cmd_actual_len = CDB_GROUP0;
36150Sstevel@tonic-gate 		break;
36160Sstevel@tonic-gate 
36170Sstevel@tonic-gate 	/*
36180Sstevel@tonic-gate 	 * do not convert SCMD_MODE_SENSE/SELECT because the
36190Sstevel@tonic-gate 	 * mode header is different as well
36200Sstevel@tonic-gate 	 */
36210Sstevel@tonic-gate 
36220Sstevel@tonic-gate 	/*
36230Sstevel@tonic-gate 	 * see usb_bulkonly.c for comments on the next set of commands
36240Sstevel@tonic-gate 	 */
36250Sstevel@tonic-gate 	case SCMD_READ:
36260Sstevel@tonic-gate 	case SCMD_WRITE:
36270Sstevel@tonic-gate 	case SCMD_READ_G1:
36280Sstevel@tonic-gate 	case SCMD_WRITE_G1:
36290Sstevel@tonic-gate 	case SCMD_READ_G5:
36300Sstevel@tonic-gate 	case SCMD_WRITE_G5:
36310Sstevel@tonic-gate 	case SCMD_READ_LONG:
36320Sstevel@tonic-gate 	case SCMD_WRITE_LONG:
36330Sstevel@tonic-gate 	case SCMD_READ_CD:
36340Sstevel@tonic-gate 
36350Sstevel@tonic-gate 		return (scsa2usb_rw_transport(scsa2usbp, pkt));
36360Sstevel@tonic-gate 
36370Sstevel@tonic-gate 	case SCMD_TEST_UNIT_READY:
36380Sstevel@tonic-gate 		/*
36390Sstevel@tonic-gate 		 * Some CB/CBI devices may not support TUR.
36400Sstevel@tonic-gate 		 */
36410Sstevel@tonic-gate 		bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
36420Sstevel@tonic-gate 		break;
36430Sstevel@tonic-gate 	case SCMD_READ_FORMAT_CAP:
36440Sstevel@tonic-gate 		bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
36450Sstevel@tonic-gate 		cmd->cmd_dir = USB_EP_DIR_IN;
36460Sstevel@tonic-gate 		cmd->cmd_actual_len = CDB_GROUP1;
36470Sstevel@tonic-gate 		cmd->cmd_xfercount = (pkt->pkt_cdbp[7] << 8) | pkt->pkt_cdbp[8];
36480Sstevel@tonic-gate 		break;
36490Sstevel@tonic-gate 	case SCMD_WRITE_VERIFY:
36500Sstevel@tonic-gate 		bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
36510Sstevel@tonic-gate 		cmd->cmd_dir = USB_EP_DIR_OUT;
36520Sstevel@tonic-gate 		cmd->cmd_actual_len = CDB_GROUP1;
36530Sstevel@tonic-gate 		cmd->cmd_xfercount = (pkt->pkt_cdbp[7] << 8) | pkt->pkt_cdbp[8];
36540Sstevel@tonic-gate 		break;
36550Sstevel@tonic-gate 	case SCMD_START_STOP:
36560Sstevel@tonic-gate 		/* A larger timeout is needed for 'flaky' CD-RW devices */
36570Sstevel@tonic-gate 		if (!(scsa2usbp->scsa2usb_attrs & SCSA2USB_ATTRS_BIG_TIMEOUT)) {
36580Sstevel@tonic-gate 			cmd->cmd_timeout = max(cmd->cmd_timeout,
36594700Sfb209375 			    20 * SCSA2USB_BULK_PIPE_TIMEOUT);
36600Sstevel@tonic-gate 		}
36610Sstevel@tonic-gate 		/* FALLTHRU */
36620Sstevel@tonic-gate 	default:
36630Sstevel@tonic-gate 		/*
36640Sstevel@tonic-gate 		 * all other commands don't need special mapping
36650Sstevel@tonic-gate 		 */
36660Sstevel@tonic-gate 		bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
36670Sstevel@tonic-gate 		if (cmd->cmd_bp) {
36680Sstevel@tonic-gate 			cmd->cmd_dir = (cmd->cmd_bp->b_flags & B_READ) ?
36694700Sfb209375 			    CBW_DIR_IN : CBW_DIR_OUT;
36700Sstevel@tonic-gate 			cmd->cmd_xfercount = cmd->cmd_bp->b_bcount;
36710Sstevel@tonic-gate 		}
36720Sstevel@tonic-gate 		break;
36730Sstevel@tonic-gate 
36740Sstevel@tonic-gate 	} /* end of switch */
36750Sstevel@tonic-gate 
36760Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
36770Sstevel@tonic-gate 	    "scsa2usb_handle_ufi_subclass_cmd: opcode = 0x%x count = 0x%lx",
36780Sstevel@tonic-gate 	    opcode, cmd->cmd_xfercount);
36790Sstevel@tonic-gate 
36800Sstevel@tonic-gate 	cmd->cmd_total_xfercount = cmd->cmd_xfercount;
36810Sstevel@tonic-gate 
36820Sstevel@tonic-gate 	return (SCSA2USB_TRANSPORT);
36830Sstevel@tonic-gate }
36840Sstevel@tonic-gate 
36850Sstevel@tonic-gate 
36860Sstevel@tonic-gate /*
36870Sstevel@tonic-gate  * scsa2usb_rw_transport:
36880Sstevel@tonic-gate  *	Handle splitting READ and WRITE requests to the
36890Sstevel@tonic-gate  *	device to a size that the host controller allows.
36900Sstevel@tonic-gate  *
36910Sstevel@tonic-gate  *	returns TRAN_* values and not USB_SUCCESS/FAILURE
36920Sstevel@tonic-gate  *
36930Sstevel@tonic-gate  * To support CD-R/CD-RW/DVD media, we need to support a
36940Sstevel@tonic-gate  * variety of block sizes for the different types of CD
36950Sstevel@tonic-gate  * data (audio, data, video, CD-XA, yellowbook, redbook etc.)
36960Sstevel@tonic-gate  *
36970Sstevel@tonic-gate  * Some of the block sizes used are:- 512, 1k, 2k, 2056, 2336
36980Sstevel@tonic-gate  * 2340, 2352, 2368, 2448, 2646, 2647 etc.
36990Sstevel@tonic-gate  *
37000Sstevel@tonic-gate  * NOTE: the driver could be entertaining a SCSI CDB that uses
37010Sstevel@tonic-gate  * any of the above listed block sizes at a given time, and a
37020Sstevel@tonic-gate  * totally different block size at any other given time for a
37030Sstevel@tonic-gate  * different CDB.
37040Sstevel@tonic-gate  *
37050Sstevel@tonic-gate  * We need to compute block size every time and figure out
37060Sstevel@tonic-gate  * matching LBA and LEN accordingly.
37070Sstevel@tonic-gate  *
37080Sstevel@tonic-gate  * Also UHCI has a limitation that it can only xfer 32k at a
37090Sstevel@tonic-gate  * given time. So, with "odd" sized blocks and a limitation of
37100Sstevel@tonic-gate  * how much we can xfer per shot, we need to compute xfer_count
37110Sstevel@tonic-gate  * as well each time.
37120Sstevel@tonic-gate  *
37130Sstevel@tonic-gate  * The same computation is also done in the function
37140Sstevel@tonic-gate  * scsa2usb_setup_next_xfer().	To save computing block_size in
37150Sstevel@tonic-gate  * this function, I am saving block_size in "cmd" now.
37160Sstevel@tonic-gate  */
37170Sstevel@tonic-gate int
37180Sstevel@tonic-gate scsa2usb_rw_transport(scsa2usb_state_t *scsa2usbp, struct scsi_pkt *pkt)
37190Sstevel@tonic-gate {
37200Sstevel@tonic-gate 	scsa2usb_cmd_t *cmd = PKT2CMD(pkt);
37210Sstevel@tonic-gate 	int lba, dir, opcode;
37220Sstevel@tonic-gate 	struct buf *bp = cmd->cmd_bp;
37230Sstevel@tonic-gate 	size_t len, xfer_count;
37240Sstevel@tonic-gate 	size_t blk_size;	/* calculate the block size to be used */
37250Sstevel@tonic-gate 	int sz;
37260Sstevel@tonic-gate 
37270Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
37280Sstevel@tonic-gate 	    "scsa2usb_rw_transport:");
37290Sstevel@tonic-gate 
37300Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
37310Sstevel@tonic-gate 
37320Sstevel@tonic-gate 	opcode = pkt->pkt_cdbp[0];
37330Sstevel@tonic-gate 	blk_size  = scsa2usbp->scsa2usb_lbasize[pkt->pkt_address.a_lun];
37340Sstevel@tonic-gate 						/* set to default */
37350Sstevel@tonic-gate 
37360Sstevel@tonic-gate 	switch (opcode) {
37370Sstevel@tonic-gate 	case SCMD_READ:
37380Sstevel@tonic-gate 		/*
37390Sstevel@tonic-gate 		 * Note that READ/WRITE(6) are not supported by the drive.
37400Sstevel@tonic-gate 		 * convert it into a 10 byte read/write.
37410Sstevel@tonic-gate 		 */
37420Sstevel@tonic-gate 		lba = SCSA2USB_LBA_6BYTE(pkt);
37430Sstevel@tonic-gate 		len = SCSA2USB_LEN_6BYTE(pkt);
37440Sstevel@tonic-gate 		opcode = SCMD_READ_G1;	/* Overwrite it w/ byte 10 cmd val */
37450Sstevel@tonic-gate 		dir = USB_EP_DIR_IN;
37460Sstevel@tonic-gate 		break;
37470Sstevel@tonic-gate 	case SCMD_WRITE:
37480Sstevel@tonic-gate 		lba = SCSA2USB_LBA_6BYTE(pkt);
37490Sstevel@tonic-gate 		len = SCSA2USB_LEN_6BYTE(pkt);
37500Sstevel@tonic-gate 		opcode = SCMD_WRITE_G1;	/* Overwrite it w/ byte 10 cmd val */
37510Sstevel@tonic-gate 		dir = USB_EP_DIR_OUT;
37520Sstevel@tonic-gate 		break;
37530Sstevel@tonic-gate 	case SCMD_READ_G1:
37540Sstevel@tonic-gate 	case SCMD_READ_LONG:
37550Sstevel@tonic-gate 		lba = SCSA2USB_LBA_10BYTE(pkt);
37560Sstevel@tonic-gate 		len = SCSA2USB_LEN_10BYTE(pkt);
37570Sstevel@tonic-gate 		dir = USB_EP_DIR_IN;
37580Sstevel@tonic-gate 		break;
37590Sstevel@tonic-gate 	case SCMD_WRITE_G1:
37600Sstevel@tonic-gate 	case SCMD_WRITE_LONG:
37610Sstevel@tonic-gate 		lba = SCSA2USB_LBA_10BYTE(pkt);
37620Sstevel@tonic-gate 		len = SCSA2USB_LEN_10BYTE(pkt);
37630Sstevel@tonic-gate 		dir = USB_EP_DIR_OUT;
37640Sstevel@tonic-gate 		if (len) {
37650Sstevel@tonic-gate 			sz = SCSA2USB_CDRW_BLKSZ(bp ? bp->b_bcount : 0, len);
37660Sstevel@tonic-gate 			if (SCSA2USB_VALID_CDRW_BLKSZ(sz)) {
37670Sstevel@tonic-gate 				blk_size = sz;	/* change it accordingly */
37680Sstevel@tonic-gate 			}
37690Sstevel@tonic-gate 		}
37700Sstevel@tonic-gate 		break;
37710Sstevel@tonic-gate 	case SCMD_READ_CD:
37720Sstevel@tonic-gate 		lba = SCSA2USB_LBA_10BYTE(pkt);
37730Sstevel@tonic-gate 		len = SCSA2USB_LEN_READ_CD(pkt);
37740Sstevel@tonic-gate 		dir = USB_EP_DIR_IN;
37750Sstevel@tonic-gate 
37760Sstevel@tonic-gate 		/* Figure out the block size */
37770Sstevel@tonic-gate 		blk_size = scsa2usb_read_cd_blk_size(pkt->pkt_cdbp[1] >> 2);
37780Sstevel@tonic-gate 		break;
37790Sstevel@tonic-gate 	case SCMD_READ_G5:
37800Sstevel@tonic-gate 		lba = SCSA2USB_LBA_12BYTE(pkt);
37810Sstevel@tonic-gate 		len = SCSA2USB_LEN_12BYTE(pkt);
37820Sstevel@tonic-gate 		dir = USB_EP_DIR_IN;
37830Sstevel@tonic-gate 		break;
37840Sstevel@tonic-gate 	case SCMD_WRITE_G5:
37850Sstevel@tonic-gate 		lba = SCSA2USB_LBA_12BYTE(pkt);
37860Sstevel@tonic-gate 		len = SCSA2USB_LEN_12BYTE(pkt);
37870Sstevel@tonic-gate 		dir = USB_EP_DIR_OUT;
37880Sstevel@tonic-gate 		break;
37890Sstevel@tonic-gate 	}
37900Sstevel@tonic-gate 
37910Sstevel@tonic-gate 	cmd->cmd_total_xfercount = xfer_count = len * blk_size;
37920Sstevel@tonic-gate 
37930Sstevel@tonic-gate 	/* reduce xfer count if necessary */
37940Sstevel@tonic-gate 	if (blk_size &&
37950Sstevel@tonic-gate 	    (xfer_count > scsa2usbp->scsa2usb_max_bulk_xfer_size)) {
37960Sstevel@tonic-gate 		/*
37970Sstevel@tonic-gate 		 * For CD-RW devices reduce the xfer count based
37980Sstevel@tonic-gate 		 * on the block size used by these devices. The
37990Sstevel@tonic-gate 		 * block size could change for READ_CD and WRITE
38000Sstevel@tonic-gate 		 * opcodes.
38010Sstevel@tonic-gate 		 *
38020Sstevel@tonic-gate 		 * Also as UHCI allows a max xfer of 32k at a time;
38030Sstevel@tonic-gate 		 * compute the xfer_count based on the new block_size.
38040Sstevel@tonic-gate 		 *
38050Sstevel@tonic-gate 		 * The len part of the cdb changes as a result of that.
38060Sstevel@tonic-gate 		 */
38070Sstevel@tonic-gate 		if (SCSA2USB_VALID_CDRW_BLKSZ(blk_size)) {
38080Sstevel@tonic-gate 			xfer_count = ((scsa2usbp->scsa2usb_max_bulk_xfer_size/
38094700Sfb209375 			    blk_size) * blk_size);
38100Sstevel@tonic-gate 			len = xfer_count/blk_size;
38110Sstevel@tonic-gate 			xfer_count = blk_size * len;
38120Sstevel@tonic-gate 		} else {
38130Sstevel@tonic-gate 			xfer_count = scsa2usbp->scsa2usb_max_bulk_xfer_size;
38140Sstevel@tonic-gate 			len = xfer_count/blk_size;
38150Sstevel@tonic-gate 		}
38160Sstevel@tonic-gate 	}
38170Sstevel@tonic-gate 
38180Sstevel@tonic-gate 	cmd->cmd_xfercount = xfer_count;
38190Sstevel@tonic-gate 	cmd->cmd_dir = (uchar_t)dir;
38207492SZhigang.Lu@Sun.COM 	cmd->cmd_blksize = (int)blk_size;
38210Sstevel@tonic-gate 
38220Sstevel@tonic-gate 	/*
38230Sstevel@tonic-gate 	 * Having figure out the 'partial' xfer len based on he
38240Sstevel@tonic-gate 	 * block size; fill it in to the cmd->cmd_cdb
38250Sstevel@tonic-gate 	 */
38260Sstevel@tonic-gate 	cmd->cmd_cdb[SCSA2USB_OPCODE] = (uchar_t)opcode;
38270Sstevel@tonic-gate 	switch (opcode) {
38280Sstevel@tonic-gate 	case SCMD_READ_CD:
38290Sstevel@tonic-gate 		bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
38300Sstevel@tonic-gate 		scsa2usb_fill_up_ReadCD_cdb_len(cmd, len, CDB_GROUP5);
38310Sstevel@tonic-gate 		break;
38320Sstevel@tonic-gate 	case SCMD_WRITE_G5:
38330Sstevel@tonic-gate 	case SCMD_READ_G5:
38340Sstevel@tonic-gate 		scsa2usb_fill_up_12byte_cdb_len(cmd, len, CDB_GROUP5);
38350Sstevel@tonic-gate 		break;
38360Sstevel@tonic-gate 	default:
38370Sstevel@tonic-gate 		scsa2usb_fill_up_cdb_len(cmd, len);
38380Sstevel@tonic-gate 		cmd->cmd_actual_len = CDB_GROUP1;
38390Sstevel@tonic-gate 		break;
38400Sstevel@tonic-gate 	}
38410Sstevel@tonic-gate 
38420Sstevel@tonic-gate 	scsa2usb_fill_up_cdb_lba(cmd, lba);
38430Sstevel@tonic-gate 
38440Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
38450Sstevel@tonic-gate 	    "bcount=0x%lx lba=0x%x len=0x%lx xfercount=0x%lx total=0x%lx",
38460Sstevel@tonic-gate 	    bp ? bp->b_bcount : 0, lba, len, cmd->cmd_xfercount,
38470Sstevel@tonic-gate 	    cmd->cmd_total_xfercount);
38480Sstevel@tonic-gate 
38490Sstevel@tonic-gate 	/* Set the timeout value as per command request */
38500Sstevel@tonic-gate 	if ((opcode == SCMD_WRITE_G1) && SCSA2USB_VALID_CDRW_BLKSZ(blk_size)) {
38510Sstevel@tonic-gate 		/*
38520Sstevel@tonic-gate 		 * We increase the time as CD-RW writes have two things
38530Sstevel@tonic-gate 		 * to do. After writing out the data to the media, a
38540Sstevel@tonic-gate 		 * TOC needs to be filled up at the beginning of the media
38550Sstevel@tonic-gate 		 * This is when the write gets "finalized".
38560Sstevel@tonic-gate 		 * Hence the actual write could take longer than the
38570Sstevel@tonic-gate 		 * value specified in cmd->cmd_timeout.
38580Sstevel@tonic-gate 		 */
38590Sstevel@tonic-gate 		cmd->cmd_timeout *= 4;
38600Sstevel@tonic-gate 
38610Sstevel@tonic-gate 		USB_DPRINTF_L4(DPRINT_MASK_SCSA,
38620Sstevel@tonic-gate 		    scsa2usbp->scsa2usb_log_handle,
38630Sstevel@tonic-gate 		    "new timeout value = 0x%x", cmd->cmd_timeout);
38640Sstevel@tonic-gate 	}
38650Sstevel@tonic-gate 
38660Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
38670Sstevel@tonic-gate 	    "lba 0x%x len 0x%lx xfercount 0x%lx total 0x%lx",
38680Sstevel@tonic-gate 	    lba, len, cmd->cmd_xfercount, cmd->cmd_total_xfercount);
38690Sstevel@tonic-gate 
38700Sstevel@tonic-gate 	return (SCSA2USB_TRANSPORT);
38710Sstevel@tonic-gate }
38720Sstevel@tonic-gate 
38730Sstevel@tonic-gate 
38740Sstevel@tonic-gate /*
38750Sstevel@tonic-gate  * scsa2usb_setup_next_xfer:
38760Sstevel@tonic-gate  *	For READs and WRITEs we split up the transfer in terms of
38770Sstevel@tonic-gate  *	HCD understood units. This function handles the split transfers.
38780Sstevel@tonic-gate  *
38790Sstevel@tonic-gate  * See comments in the previous function scsa2usb_rw_transport
38800Sstevel@tonic-gate  *
38810Sstevel@tonic-gate  * The lba computation was being done based on scsa2usb_max_bulk_xfer_size
38820Sstevel@tonic-gate  * earlier. With CD-RW devices, the xfer_count and the block_size may
38830Sstevel@tonic-gate  * no longer be a multiple of scsa2usb_max_bulk_xfer_size. So compute
38840Sstevel@tonic-gate  * xfer_count all over again. Adjust lba, based on the previous requests'
38850Sstevel@tonic-gate  * len. Find out the len and add it to cmd->cmd_lba to get the new lba
38860Sstevel@tonic-gate  */
38870Sstevel@tonic-gate void
38880Sstevel@tonic-gate scsa2usb_setup_next_xfer(scsa2usb_state_t *scsa2usbp, scsa2usb_cmd_t *cmd)
38890Sstevel@tonic-gate {
38900Sstevel@tonic-gate 	int xfer_len = min(scsa2usbp->scsa2usb_max_bulk_xfer_size,
38914700Sfb209375 	    cmd->cmd_total_xfercount);
38920Sstevel@tonic-gate 	int cdb_len;
38930Sstevel@tonic-gate 	size_t blk_size;
38940Sstevel@tonic-gate 
38950Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
38960Sstevel@tonic-gate 
38970Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
38980Sstevel@tonic-gate 	    "scsa2usb_setup_next_xfer: opcode = 0x%x lba = 0x%x "
38990Sstevel@tonic-gate 	    "total count = 0x%lx", cmd->cmd_cdb[SCSA2USB_OPCODE],
39000Sstevel@tonic-gate 	    cmd->cmd_lba, cmd->cmd_total_xfercount);
39010Sstevel@tonic-gate 
39020Sstevel@tonic-gate 	ASSERT(cmd->cmd_total_xfercount > 0);
39030Sstevel@tonic-gate 	cmd->cmd_xfercount = xfer_len;
39040Sstevel@tonic-gate 	blk_size = scsa2usbp->scsa2usb_lbasize[
39054700Sfb209375 	    cmd->cmd_pkt->pkt_address.a_lun];
39060Sstevel@tonic-gate 
39070Sstevel@tonic-gate 	/*
39080Sstevel@tonic-gate 	 * For CD-RW devices reduce the xfer count based on the
39090Sstevel@tonic-gate 	 * block_size used by these devices. See changes below
39100Sstevel@tonic-gate 	 * where xfer_count is being adjusted.
39110Sstevel@tonic-gate 	 *
39120Sstevel@tonic-gate 	 * Also adjust len/lba based on the block_size and xfer_count.
39130Sstevel@tonic-gate 	 * NOTE: Always calculate lba first, as it based on previous
39140Sstevel@tonic-gate 	 * commands' values.
39150Sstevel@tonic-gate 	 */
39160Sstevel@tonic-gate 	switch (cmd->cmd_cdb[SCSA2USB_OPCODE]) {
39170Sstevel@tonic-gate 	case SCMD_READ_CD:
39180Sstevel@tonic-gate 		/* calculate lba = current_lba + len_of_prev_cmd */
39190Sstevel@tonic-gate 		cmd->cmd_lba += (cmd->cmd_cdb[6] << 16) +
39200Sstevel@tonic-gate 		    (cmd->cmd_cdb[7] << 8) + cmd->cmd_cdb[8];
39210Sstevel@tonic-gate 		cdb_len = xfer_len/cmd->cmd_blksize;
39220Sstevel@tonic-gate 		cmd->cmd_cdb[SCSA2USB_READ_CD_LEN_2] = (uchar_t)cdb_len;
39230Sstevel@tonic-gate 		/* re-adjust xfer count */
39240Sstevel@tonic-gate 		cmd->cmd_xfercount = cdb_len * cmd->cmd_blksize;
39250Sstevel@tonic-gate 		break;
39260Sstevel@tonic-gate 	case SCMD_WRITE_G5:
39270Sstevel@tonic-gate 	case SCMD_READ_G5:
39280Sstevel@tonic-gate 		/* calculate lba = current_lba + len_of_prev_cmd */
39290Sstevel@tonic-gate 		cmd->cmd_lba += (cmd->cmd_cdb[6] << 24) +
39300Sstevel@tonic-gate 		    (cmd->cmd_cdb[7] << 16) + (cmd->cmd_cdb[8] << 8) +
39310Sstevel@tonic-gate 		    cmd->cmd_cdb[9];
39320Sstevel@tonic-gate 		if (blk_size) {
39330Sstevel@tonic-gate 			xfer_len /= blk_size;
39340Sstevel@tonic-gate 		}
39350Sstevel@tonic-gate 		scsa2usb_fill_up_12byte_cdb_len(cmd, xfer_len, CDB_GROUP5);
39360Sstevel@tonic-gate 		break;
39370Sstevel@tonic-gate 	case SCMD_WRITE_G1:
39380Sstevel@tonic-gate 	case SCMD_WRITE_LONG:
39390Sstevel@tonic-gate 		/* calculate lba = current_lba + len_of_prev_cmd */
39400Sstevel@tonic-gate 		cmd->cmd_lba += (cmd->cmd_cdb[7] << 8) + cmd->cmd_cdb[8];
39410Sstevel@tonic-gate 		if (SCSA2USB_VALID_CDRW_BLKSZ(cmd->cmd_blksize)) {
39420Sstevel@tonic-gate 			blk_size = cmd->cmd_blksize;
39430Sstevel@tonic-gate 		}
39440Sstevel@tonic-gate 		cdb_len = xfer_len/blk_size;
39450Sstevel@tonic-gate 		scsa2usb_fill_up_cdb_len(cmd, cdb_len);
39460Sstevel@tonic-gate 		/* re-adjust xfer count */
39470Sstevel@tonic-gate 		cmd->cmd_xfercount = cdb_len * blk_size;
39480Sstevel@tonic-gate 		break;
39490Sstevel@tonic-gate 	default:
39500Sstevel@tonic-gate 		if (blk_size) {
39510Sstevel@tonic-gate 			xfer_len /= blk_size;
39520Sstevel@tonic-gate 		}
39530Sstevel@tonic-gate 		scsa2usb_fill_up_cdb_len(cmd, xfer_len);
39540Sstevel@tonic-gate 		cmd->cmd_lba += scsa2usbp->scsa2usb_max_bulk_xfer_size/blk_size;
39550Sstevel@tonic-gate 	}
39560Sstevel@tonic-gate 
39570Sstevel@tonic-gate 	/* fill in the lba */
39580Sstevel@tonic-gate 	scsa2usb_fill_up_cdb_lba(cmd, cmd->cmd_lba);
39590Sstevel@tonic-gate 
39600Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
39610Sstevel@tonic-gate 	    "scsa2usb_setup_next_xfer:\n\tlba = 0x%x xfer_len = 0x%x "
39620Sstevel@tonic-gate 	    "xfercount = 0x%lx total = 0x%lx", cmd->cmd_lba, xfer_len,
39630Sstevel@tonic-gate 	    cmd->cmd_xfercount, cmd->cmd_total_xfercount);
39640Sstevel@tonic-gate }
39650Sstevel@tonic-gate 
39660Sstevel@tonic-gate 
39670Sstevel@tonic-gate /*
39680Sstevel@tonic-gate  * take one request from the lun's waitQ and transport it
39690Sstevel@tonic-gate  */
39700Sstevel@tonic-gate static void
39710Sstevel@tonic-gate scsa2usb_transport_request(scsa2usb_state_t *scsa2usbp, uint_t lun)
39720Sstevel@tonic-gate {
39730Sstevel@tonic-gate 	int			rval;
39740Sstevel@tonic-gate 	struct scsi_pkt		*pkt;
39750Sstevel@tonic-gate 	struct scsa2usb_cmd	*cmd, *arqcmd;
39760Sstevel@tonic-gate 
39770Sstevel@tonic-gate 	if ((cmd = (scsa2usb_cmd_t *)
39780Sstevel@tonic-gate 	    usba_rm_first_pvt_from_list(
39790Sstevel@tonic-gate 	    &scsa2usbp->scsa2usb_waitQ[lun])) == NULL) {
39800Sstevel@tonic-gate 
39810Sstevel@tonic-gate 		return;
39820Sstevel@tonic-gate 	}
39830Sstevel@tonic-gate 	pkt = cmd->cmd_pkt;
39840Sstevel@tonic-gate 
39850Sstevel@tonic-gate 	/*
39860Sstevel@tonic-gate 	 * if device has been disconnected, just complete it
39870Sstevel@tonic-gate 	 */
39880Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_dev_state == USB_DEV_DISCONNECTED) {
39890Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
39900Sstevel@tonic-gate 		    "device not accessible");
39910Sstevel@tonic-gate 		pkt->pkt_reason = CMD_DEV_GONE;
39920Sstevel@tonic-gate 		SCSA2USB_SET_PKT_DO_COMP_STATE(scsa2usbp);
39930Sstevel@tonic-gate 		scsa2usb_pkt_completion(scsa2usbp, pkt);
39940Sstevel@tonic-gate 
39950Sstevel@tonic-gate 		return;
39960Sstevel@tonic-gate 	}
39970Sstevel@tonic-gate 
39980Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA,
39990Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_log_handle,
40000Sstevel@tonic-gate 	    "scsa2usb_transport_request: cmd=0x%p bp=0x%p addr=0x%p",
40016898Sfb209375 	    (void *)cmd, (void *)cmd->cmd_bp,
40026898Sfb209375 	    (void *)(cmd->cmd_bp ? cmd->cmd_bp->b_un.b_addr : NULL));
40030Sstevel@tonic-gate 
40040Sstevel@tonic-gate 	rval = scsa2usb_cmd_transport(scsa2usbp, cmd);
40050Sstevel@tonic-gate 
40060Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_SCSA,
40070Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_log_handle,
40080Sstevel@tonic-gate 	    "scsa2usb_transport_request: transport rval = %d",
40090Sstevel@tonic-gate 	    rval);
40100Sstevel@tonic-gate 
40110Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_cur_pkt == NULL) {
40120Sstevel@tonic-gate 
40130Sstevel@tonic-gate 		return;
40140Sstevel@tonic-gate 	}
40150Sstevel@tonic-gate 
40160Sstevel@tonic-gate 	ASSERT(pkt == scsa2usbp->scsa2usb_cur_pkt);
40170Sstevel@tonic-gate 
40180Sstevel@tonic-gate 	if (ddi_in_panic()) {
40190Sstevel@tonic-gate 		pkt->pkt_reason = CMD_CMPLT;
40200Sstevel@tonic-gate 		scsa2usb_pkt_completion(scsa2usbp, pkt);
40210Sstevel@tonic-gate 
40220Sstevel@tonic-gate 		return;
40230Sstevel@tonic-gate 	}
40240Sstevel@tonic-gate 
40250Sstevel@tonic-gate 	/*
40260Sstevel@tonic-gate 	 * start an auto-request sense iff
40270Sstevel@tonic-gate 	 * there was a check condition, we have enough
40280Sstevel@tonic-gate 	 * space in the status block, and we have not
40290Sstevel@tonic-gate 	 * faked an auto request sense
40300Sstevel@tonic-gate 	 */
40310Sstevel@tonic-gate 	if ((*(pkt->pkt_scbp) == STATUS_CHECK) &&
40320Sstevel@tonic-gate 	    (cmd->cmd_scblen >= sizeof (struct scsi_arq_status)) &&
40330Sstevel@tonic-gate 	    ((pkt->pkt_state & STATE_ARQ_DONE) == 0) &&
40340Sstevel@tonic-gate 	    (scsa2usb_create_arq_pkt(scsa2usbp,
40350Sstevel@tonic-gate 	    &pkt->pkt_address) == USB_SUCCESS)) {
40360Sstevel@tonic-gate 		arqcmd = scsa2usbp->scsa2usb_arq_cmd;
40370Sstevel@tonic-gate 
40380Sstevel@tonic-gate 		/*
40390Sstevel@tonic-gate 		 * copy the timeout from the
40400Sstevel@tonic-gate 		 * original packet
40410Sstevel@tonic-gate 		 * for lack of a better value
40420Sstevel@tonic-gate 		 */
40430Sstevel@tonic-gate 		arqcmd->cmd_pkt->pkt_time = pkt->pkt_time;
40440Sstevel@tonic-gate 		scsa2usb_prepare_pkt(scsa2usbp,
40454700Sfb209375 		    arqcmd->cmd_pkt);
40460Sstevel@tonic-gate 
40470Sstevel@tonic-gate 		scsa2usbp->scsa2usb_cur_pkt = NULL;
40480Sstevel@tonic-gate 		if (scsa2usb_cmd_transport(
40490Sstevel@tonic-gate 		    scsa2usbp, arqcmd) == TRAN_ACCEPT) {
40500Sstevel@tonic-gate 
40510Sstevel@tonic-gate 			/* finish w/ this packet */
40520Sstevel@tonic-gate 			scsa2usb_complete_arq_pkt(
40530Sstevel@tonic-gate 			    scsa2usbp, arqcmd->cmd_pkt, cmd,
40540Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_arq_bp);
40550Sstevel@tonic-gate 
40560Sstevel@tonic-gate 			/*
40570Sstevel@tonic-gate 			 * we have valid request sense
40580Sstevel@tonic-gate 			 * data so clear the pkt_reason
40590Sstevel@tonic-gate 			 */
40600Sstevel@tonic-gate 			pkt->pkt_reason = CMD_CMPLT;
40610Sstevel@tonic-gate 		}
40620Sstevel@tonic-gate 		scsa2usbp->scsa2usb_cur_pkt = pkt;
40630Sstevel@tonic-gate 		scsa2usb_delete_arq_pkt(scsa2usbp);
40640Sstevel@tonic-gate 	}
40650Sstevel@tonic-gate 
40660Sstevel@tonic-gate 	if ((rval != TRAN_ACCEPT) &&
40670Sstevel@tonic-gate 	    (pkt->pkt_reason == CMD_CMPLT)) {
40680Sstevel@tonic-gate 		pkt->pkt_reason = CMD_TRAN_ERR;
40690Sstevel@tonic-gate 	}
40700Sstevel@tonic-gate 
40710Sstevel@tonic-gate 	SCSA2USB_SET_PKT_DO_COMP_STATE(scsa2usbp);
40720Sstevel@tonic-gate 	scsa2usb_pkt_completion(scsa2usbp, pkt);
40730Sstevel@tonic-gate 
40740Sstevel@tonic-gate 	ASSERT(scsa2usbp->scsa2usb_cur_pkt == NULL);
40750Sstevel@tonic-gate }
40760Sstevel@tonic-gate 
40770Sstevel@tonic-gate 
40780Sstevel@tonic-gate /*
40790Sstevel@tonic-gate  * scsa2usb_work_thread:
40800Sstevel@tonic-gate  *	The taskq thread that kicks off the transport (BO and CB/CBI)
40810Sstevel@tonic-gate  */
40820Sstevel@tonic-gate static void
40830Sstevel@tonic-gate scsa2usb_work_thread(void *arg)
40840Sstevel@tonic-gate {
40850Sstevel@tonic-gate 	scsa2usb_state_t	*scsa2usbp = (scsa2usb_state_t *)arg;
40860Sstevel@tonic-gate 	uint_t			lun;
40870Sstevel@tonic-gate 	uint_t			count;
40880Sstevel@tonic-gate 
4089189Sfrits 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
40900Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
40916898Sfb209375 	    "scsa2usb_work_thread start: thread_id=0x%p",
40926898Sfb209375 	    (void *)scsa2usbp->scsa2usb_work_thread_id);
4093189Sfrits 
40940Sstevel@tonic-gate 	ASSERT(scsa2usbp->scsa2usb_work_thread_id == (kthread_t *)1);
40950Sstevel@tonic-gate 	scsa2usbp->scsa2usb_work_thread_id = curthread;
40960Sstevel@tonic-gate 
40970Sstevel@tonic-gate 	/* exclude ugen accesses */
40980Sstevel@tonic-gate 	while (scsa2usbp->scsa2usb_transport_busy) {
40990Sstevel@tonic-gate 		cv_wait(&scsa2usbp->scsa2usb_transport_busy_cv,
41000Sstevel@tonic-gate 		    &scsa2usbp->scsa2usb_mutex);
41010Sstevel@tonic-gate 	}
41020Sstevel@tonic-gate 	ASSERT(scsa2usbp->scsa2usb_ugen_open_count == 0);
41030Sstevel@tonic-gate 	scsa2usbp->scsa2usb_transport_busy++;
41040Sstevel@tonic-gate 	scsa2usbp->scsa2usb_busy_thread = curthread;
41050Sstevel@tonic-gate 
41060Sstevel@tonic-gate 	scsa2usb_raise_power(scsa2usbp);
41070Sstevel@tonic-gate 
41080Sstevel@tonic-gate 	/* reopen the pipes if necessary */
41090Sstevel@tonic-gate 	(void) scsa2usb_open_usb_pipes(scsa2usbp);
41100Sstevel@tonic-gate 
41110Sstevel@tonic-gate 	for (;;) {
41120Sstevel@tonic-gate 		ASSERT(scsa2usbp->scsa2usb_ugen_open_count == 0);
41130Sstevel@tonic-gate 		for (lun = 0; lun < scsa2usbp->scsa2usb_n_luns; lun++) {
41140Sstevel@tonic-gate 			scsa2usb_transport_request(scsa2usbp, lun);
41150Sstevel@tonic-gate 		}
41160Sstevel@tonic-gate 		count = 0;
41170Sstevel@tonic-gate 		for (lun = 0; lun < SCSA2USB_MAX_LUNS; lun++) {
41180Sstevel@tonic-gate 			count += usba_list_entry_count(
41194700Sfb209375 			    &scsa2usbp->scsa2usb_waitQ[lun]);
41200Sstevel@tonic-gate 		}
41210Sstevel@tonic-gate 
41220Sstevel@tonic-gate 		if (count == 0) {
41230Sstevel@tonic-gate 
41240Sstevel@tonic-gate 			break;
41250Sstevel@tonic-gate 		}
41260Sstevel@tonic-gate 	}
41270Sstevel@tonic-gate 
41280Sstevel@tonic-gate 	scsa2usbp->scsa2usb_work_thread_id = 0;
41290Sstevel@tonic-gate 
41300Sstevel@tonic-gate 	ASSERT(scsa2usbp->scsa2usb_ugen_open_count == 0);
41310Sstevel@tonic-gate 
41320Sstevel@tonic-gate 	scsa2usbp->scsa2usb_transport_busy--;
41330Sstevel@tonic-gate 	scsa2usbp->scsa2usb_busy_thread = NULL;
41340Sstevel@tonic-gate 	cv_signal(&scsa2usbp->scsa2usb_transport_busy_cv);
41350Sstevel@tonic-gate 
41360Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
41370Sstevel@tonic-gate 	    "scsa2usb_work_thread: exit");
4138189Sfrits 
4139189Sfrits 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
4140189Sfrits 
4141189Sfrits 	scsa2usb_pm_idle_component(scsa2usbp);
41420Sstevel@tonic-gate }
41430Sstevel@tonic-gate 
41440Sstevel@tonic-gate 
41450Sstevel@tonic-gate /*
41460Sstevel@tonic-gate  * scsa2usb_flush_waitQ:
41470Sstevel@tonic-gate  *	empties the entire waitQ with errors asap.
41480Sstevel@tonic-gate  *
41490Sstevel@tonic-gate  * It is called from scsa2usb_scsi_reset and scsa2usb_panic_callb.
41500Sstevel@tonic-gate  * If the device is reset; we should empty the waitQ right away.
41510Sstevel@tonic-gate  * If the system has paniced; we should empty the waitQ right away.
41520Sstevel@tonic-gate  *
41530Sstevel@tonic-gate  * CPR suspend will only succeed if device is idle. No need to call
41540Sstevel@tonic-gate  * this function for CPR suspend case.
41550Sstevel@tonic-gate  */
41560Sstevel@tonic-gate static void
41570Sstevel@tonic-gate scsa2usb_flush_waitQ(scsa2usb_state_t *scsa2usbp, uint_t lun,
41580Sstevel@tonic-gate     uchar_t error)
41590Sstevel@tonic-gate {
41600Sstevel@tonic-gate 	struct scsi_pkt		*pkt;
41610Sstevel@tonic-gate 	struct scsa2usb_cmd	*cmd;
41620Sstevel@tonic-gate 	usba_list_entry_t	head;
41630Sstevel@tonic-gate 
41640Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
41650Sstevel@tonic-gate 
41660Sstevel@tonic-gate 	usba_move_list(&scsa2usbp->scsa2usb_waitQ[lun], &head,
41670Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_dev_data->dev_iblock_cookie);
41680Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
41690Sstevel@tonic-gate 
41700Sstevel@tonic-gate 	while ((cmd = (scsa2usb_cmd_t *)usba_rm_first_pvt_from_list(&head)) !=
41710Sstevel@tonic-gate 	    NULL) {
41720Sstevel@tonic-gate 		pkt = cmd->cmd_pkt;
41730Sstevel@tonic-gate 		pkt->pkt_reason = error;	/* set error */
41740Sstevel@tonic-gate 
41750Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
41760Sstevel@tonic-gate 		scsa2usbp->scsa2usb_pkt_state = SCSA2USB_PKT_DO_COMP;
41770Sstevel@tonic-gate 		scsa2usb_pkt_completion(scsa2usbp, pkt);
41780Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
41790Sstevel@tonic-gate 	} /* end of while */
41800Sstevel@tonic-gate }
41810Sstevel@tonic-gate 
41820Sstevel@tonic-gate 
41830Sstevel@tonic-gate /*
41840Sstevel@tonic-gate  * scsa2usb_do_inquiry is performed before INIT CHILD and we have
41850Sstevel@tonic-gate  * to fake a few things normally done by SCSA
41860Sstevel@tonic-gate  */
41870Sstevel@tonic-gate static void
41880Sstevel@tonic-gate scsa2usb_do_inquiry(scsa2usb_state_t *scsa2usbp, uint_t target, uint_t lun)
41890Sstevel@tonic-gate {
41900Sstevel@tonic-gate 	struct buf	*bp;
41910Sstevel@tonic-gate 	struct scsi_pkt *pkt;
41920Sstevel@tonic-gate 	struct scsi_address ap;
41930Sstevel@tonic-gate 	int		len = SCSA2USB_MAX_INQ_LEN;
41940Sstevel@tonic-gate 
41950Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
41960Sstevel@tonic-gate 	    "scsa2usb_do_inquiry: %d bytes", len);
41970Sstevel@tonic-gate 
41980Sstevel@tonic-gate 	/* is it inquiry-challenged? */
41990Sstevel@tonic-gate 	if (!(scsa2usbp->scsa2usb_attrs & SCSA2USB_ATTRS_INQUIRY)) {
42008003SVitezslav.Batrla@Sun.COM 		scsa2usb_fake_inquiry(scsa2usbp,
42018003SVitezslav.Batrla@Sun.COM 		    &scsa2usbp->scsa2usb_lun_inquiry[lun]);
42020Sstevel@tonic-gate 		return;
42030Sstevel@tonic-gate 	}
42040Sstevel@tonic-gate 
42050Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
42060Sstevel@tonic-gate 
42070Sstevel@tonic-gate 	bzero(&ap, sizeof (struct scsi_address));
42080Sstevel@tonic-gate 	ap.a_hba_tran = scsa2usbp->scsa2usb_tran;
42097492SZhigang.Lu@Sun.COM 	ap.a_target = (ushort_t)target;
42107492SZhigang.Lu@Sun.COM 	ap.a_lun = (uchar_t)lun;
42110Sstevel@tonic-gate 
42120Sstevel@tonic-gate 	/* limit inquiry to 36 bytes */
42130Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
42140Sstevel@tonic-gate 	if ((bp = scsi_alloc_consistent_buf(&ap, (struct buf *)NULL,
42150Sstevel@tonic-gate 	    len, B_READ, SLEEP_FUNC, NULL)) == NULL) {
42160Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
42170Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA,
42180Sstevel@tonic-gate 		    scsa2usbp->scsa2usb_log_handle,
42190Sstevel@tonic-gate 		    "scsa2usb_do_inquiry: failed");
42200Sstevel@tonic-gate 
42210Sstevel@tonic-gate 		return;
42220Sstevel@tonic-gate 	}
42230Sstevel@tonic-gate 
42240Sstevel@tonic-gate 	pkt = scsi_init_pkt(&ap, NULL, bp, CDB_GROUP0, 1,
42250Sstevel@tonic-gate 	    PKT_PRIV_LEN, PKT_CONSISTENT, SLEEP_FUNC, NULL);
42260Sstevel@tonic-gate 
42277492SZhigang.Lu@Sun.COM 	RQ_MAKECOM_G0(pkt, FLAG_NOINTR, (char)SCMD_INQUIRY, 0, (char)len);
42280Sstevel@tonic-gate 
42290Sstevel@tonic-gate 	pkt->pkt_comp = NULL;
42300Sstevel@tonic-gate 	pkt->pkt_time = 5;
42310Sstevel@tonic-gate 	bzero(bp->b_un.b_addr, len);
42320Sstevel@tonic-gate 
42330Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
42340Sstevel@tonic-gate 	    "scsa2usb_do_inquiry:INQUIRY");
42350Sstevel@tonic-gate 
42360Sstevel@tonic-gate 	(void) scsi_transport(pkt);
42370Sstevel@tonic-gate 
42380Sstevel@tonic-gate 	if (pkt->pkt_reason) {
4239978Sfrits 		USB_DPRINTF_L2(DPRINT_MASK_SCSA,
42400Sstevel@tonic-gate 		    scsa2usbp->scsa2usb_log_handle,
42410Sstevel@tonic-gate 		    "INQUIRY failed, cannot determine device type, "
42420Sstevel@tonic-gate 		    "pkt_reason=0x%x", pkt->pkt_reason);
42430Sstevel@tonic-gate 
42440Sstevel@tonic-gate 		/* not much hope for other cmds, reduce */
42450Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
42460Sstevel@tonic-gate 		scsa2usbp->scsa2usb_attrs &=
42474700Sfb209375 		    ~SCSA2USB_ATTRS_REDUCED_CMD;
42488003SVitezslav.Batrla@Sun.COM 		scsa2usb_fake_inquiry(scsa2usbp,
42498003SVitezslav.Batrla@Sun.COM 		    &scsa2usbp->scsa2usb_lun_inquiry[lun]);
42500Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
42510Sstevel@tonic-gate 	}
42520Sstevel@tonic-gate 
42530Sstevel@tonic-gate 	scsi_destroy_pkt(pkt);
42540Sstevel@tonic-gate 	scsi_free_consistent_buf(bp);
42550Sstevel@tonic-gate 
42560Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
42570Sstevel@tonic-gate }
42580Sstevel@tonic-gate 
42590Sstevel@tonic-gate 
42600Sstevel@tonic-gate /*
42610Sstevel@tonic-gate  * scsa2usb_fake_inquiry:
42620Sstevel@tonic-gate  *    build an inquiry for a given device that doesnt like inquiry
42630Sstevel@tonic-gate  *    commands.
42640Sstevel@tonic-gate  */
42658003SVitezslav.Batrla@Sun.COM static void
42668003SVitezslav.Batrla@Sun.COM scsa2usb_fake_inquiry(scsa2usb_state_t *scsa2usbp, struct scsi_inquiry *inqp)
42670Sstevel@tonic-gate {
42680Sstevel@tonic-gate 	usb_client_dev_data_t *dev_data = scsa2usbp->scsa2usb_dev_data;
42690Sstevel@tonic-gate 	int len;
42700Sstevel@tonic-gate 
42710Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
42720Sstevel@tonic-gate 	    "scsa2usb_fake_inquiry:");
42730Sstevel@tonic-gate 
42740Sstevel@tonic-gate 	bzero(inqp, sizeof (struct scsi_inquiry));
42750Sstevel@tonic-gate 	for (len = 0; len < sizeof (inqp->inq_vid); len++) {
42760Sstevel@tonic-gate 		*(inqp->inq_vid + len) = ' ';
42770Sstevel@tonic-gate 	}
42780Sstevel@tonic-gate 
42790Sstevel@tonic-gate 	for (len = 0; len < sizeof (inqp->inq_pid); len++) {
42800Sstevel@tonic-gate 		*(inqp->inq_pid + len) = ' ';
42810Sstevel@tonic-gate 	}
42820Sstevel@tonic-gate 
42830Sstevel@tonic-gate 	inqp->inq_dtype = DTYPE_DIRECT;
42840Sstevel@tonic-gate 	inqp->inq_rmb = 1;
42850Sstevel@tonic-gate 	inqp->inq_ansi = 2;
42860Sstevel@tonic-gate 	inqp->inq_rdf = RDF_SCSI2;
42870Sstevel@tonic-gate 	inqp->inq_len = sizeof (struct scsi_inquiry)-4;
42880Sstevel@tonic-gate 
42890Sstevel@tonic-gate 	/* Fill in the Vendor id/Product id strings */
42900Sstevel@tonic-gate 	if (dev_data->dev_mfg) {
42910Sstevel@tonic-gate 		if ((len = strlen(dev_data->dev_mfg)) >
42920Sstevel@tonic-gate 		    sizeof (inqp->inq_vid)) {
42930Sstevel@tonic-gate 			len = sizeof (inqp->inq_vid);
42940Sstevel@tonic-gate 		}
42950Sstevel@tonic-gate 		bcopy(dev_data->dev_mfg, inqp->inq_vid, len);
42960Sstevel@tonic-gate 	}
42970Sstevel@tonic-gate 
42980Sstevel@tonic-gate 	if (dev_data->dev_product) {
42990Sstevel@tonic-gate 		if ((len = strlen(dev_data->dev_product)) >
43000Sstevel@tonic-gate 		    sizeof (inqp->inq_pid)) {
43010Sstevel@tonic-gate 			len = sizeof (inqp->inq_pid);
43020Sstevel@tonic-gate 		}
43030Sstevel@tonic-gate 		bcopy(dev_data->dev_product, inqp->inq_pid, len);
43040Sstevel@tonic-gate 	}
43050Sstevel@tonic-gate 
43060Sstevel@tonic-gate 	/* Set the Revision to the Device */
43070Sstevel@tonic-gate 	inqp->inq_revision[0] = 0x30 +
43084700Sfb209375 	    ((dev_data->dev_descr->bcdDevice>>12) & 0xF);
43090Sstevel@tonic-gate 	inqp->inq_revision[1] = 0x30 +
43104700Sfb209375 	    ((dev_data->dev_descr->bcdDevice>>8) & 0xF);
43110Sstevel@tonic-gate 	inqp->inq_revision[2] = 0x30 +
43124700Sfb209375 	    ((dev_data->dev_descr->bcdDevice>>4) & 0xF);
43130Sstevel@tonic-gate 	inqp->inq_revision[3] = 0x30 +
43144700Sfb209375 	    ((dev_data->dev_descr->bcdDevice) & 0xF);
43150Sstevel@tonic-gate }
43160Sstevel@tonic-gate 
43170Sstevel@tonic-gate 
43180Sstevel@tonic-gate /*
43190Sstevel@tonic-gate  * scsa2usb_create_arq_pkt:
43200Sstevel@tonic-gate  *	Create and ARQ packet to get request sense data
43210Sstevel@tonic-gate  */
43220Sstevel@tonic-gate static int
43230Sstevel@tonic-gate scsa2usb_create_arq_pkt(scsa2usb_state_t *scsa2usbp, struct scsi_address *ap)
43240Sstevel@tonic-gate {
43250Sstevel@tonic-gate 	struct buf *bp;
43260Sstevel@tonic-gate 	scsa2usb_cmd_t *arq_cmd;
43270Sstevel@tonic-gate 
43280Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
43296898Sfb209375 	    "scsa2usb_create_arq_pkt: scsa2usbp: %p, ap: %p",
43306898Sfb209375 	    (void *)scsa2usbp, (void *)ap);
43310Sstevel@tonic-gate 
43320Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
43330Sstevel@tonic-gate 
43340Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
43350Sstevel@tonic-gate 	if ((bp = scsi_alloc_consistent_buf(ap, (struct buf *)NULL,
43360Sstevel@tonic-gate 	    SENSE_LENGTH, B_READ, SLEEP_FUNC, NULL)) == NULL) {
43370Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
43380Sstevel@tonic-gate 
43390Sstevel@tonic-gate 		return (USB_FAILURE);
43400Sstevel@tonic-gate 	}
43410Sstevel@tonic-gate 
43420Sstevel@tonic-gate 	arq_cmd = PKT2CMD(scsi_init_pkt(ap, NULL, bp, CDB_GROUP0, 1,
43430Sstevel@tonic-gate 	    PKT_PRIV_LEN, PKT_CONSISTENT, SLEEP_FUNC, NULL));
43440Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
43450Sstevel@tonic-gate 
43460Sstevel@tonic-gate 	RQ_MAKECOM_G0(arq_cmd->cmd_pkt,
43470Sstevel@tonic-gate 	    FLAG_SENSING | FLAG_HEAD | FLAG_NODISCON,
43480Sstevel@tonic-gate 	    (char)SCMD_REQUEST_SENSE, 0, (char)SENSE_LENGTH);
43490Sstevel@tonic-gate 
43500Sstevel@tonic-gate 	arq_cmd->cmd_pkt->pkt_ha_private = arq_cmd;
43510Sstevel@tonic-gate 	scsa2usbp->scsa2usb_arq_cmd = arq_cmd;
43520Sstevel@tonic-gate 	scsa2usbp->scsa2usb_arq_bp = bp;
43530Sstevel@tonic-gate 	arq_cmd->cmd_pkt->pkt_comp = NULL;
43540Sstevel@tonic-gate 	bzero(bp->b_un.b_addr, SENSE_LENGTH);
43550Sstevel@tonic-gate 
43560Sstevel@tonic-gate 	return (USB_SUCCESS);
43570Sstevel@tonic-gate }
43580Sstevel@tonic-gate 
43590Sstevel@tonic-gate 
43600Sstevel@tonic-gate /*
43610Sstevel@tonic-gate  * scsa2usb_delete_arq_pkt:
43620Sstevel@tonic-gate  *	Destroy the ARQ packet
43630Sstevel@tonic-gate  */
43640Sstevel@tonic-gate static void
43650Sstevel@tonic-gate scsa2usb_delete_arq_pkt(scsa2usb_state_t *scsa2usbp)
43660Sstevel@tonic-gate {
43670Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
43686898Sfb209375 	    "scsa2usb_delete_arq_pkt: cmd: 0x%p",
43696898Sfb209375 	    (void *)scsa2usbp->scsa2usb_arq_cmd);
43700Sstevel@tonic-gate 
43710Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
43720Sstevel@tonic-gate 
43730Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_arq_cmd != NULL) {
43740Sstevel@tonic-gate 		scsi_destroy_pkt(scsa2usbp->scsa2usb_arq_cmd->cmd_pkt);
43750Sstevel@tonic-gate 		scsi_free_consistent_buf(scsa2usbp->scsa2usb_arq_bp);
43760Sstevel@tonic-gate 	}
43770Sstevel@tonic-gate 	scsa2usbp->scsa2usb_arq_cmd = NULL;
43780Sstevel@tonic-gate 	scsa2usbp->scsa2usb_arq_bp = NULL;
43790Sstevel@tonic-gate }
43800Sstevel@tonic-gate 
43810Sstevel@tonic-gate 
43820Sstevel@tonic-gate /*
43830Sstevel@tonic-gate  * scsa2usb_complete_arq_pkt:
43840Sstevel@tonic-gate  *	finish processing the arq packet
43850Sstevel@tonic-gate  */
43860Sstevel@tonic-gate static void
43870Sstevel@tonic-gate scsa2usb_complete_arq_pkt(scsa2usb_state_t *scsa2usbp,
43880Sstevel@tonic-gate     struct scsi_pkt *pkt, scsa2usb_cmd_t *ssp, struct buf *bp)
43890Sstevel@tonic-gate {
43900Sstevel@tonic-gate 	scsa2usb_cmd_t		*sp = pkt->pkt_ha_private;
43910Sstevel@tonic-gate 	struct scsi_arq_status	*arqp;
43920Sstevel@tonic-gate 
43930Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
43940Sstevel@tonic-gate 
43950Sstevel@tonic-gate 	arqp = (struct scsi_arq_status *)(ssp->cmd_pkt->pkt_scbp);
43960Sstevel@tonic-gate 	arqp->sts_rqpkt_status = *((struct scsi_status *)
43974700Sfb209375 	    (sp->cmd_pkt->pkt_scbp));
43980Sstevel@tonic-gate 	arqp->sts_rqpkt_reason = CMD_CMPLT;
43990Sstevel@tonic-gate 	arqp->sts_rqpkt_state |= STATE_XFERRED_DATA;
44000Sstevel@tonic-gate 	arqp->sts_rqpkt_statistics = arqp->sts_rqpkt_resid = 0;
44010Sstevel@tonic-gate 
44020Sstevel@tonic-gate 	/* is this meaningful sense data */
44030Sstevel@tonic-gate 	if (*(bp->b_un.b_addr) != 0) {
44045727Slh195018 		bcopy(bp->b_un.b_addr, &arqp->sts_sensedata, SENSE_LENGTH);
44050Sstevel@tonic-gate 		ssp->cmd_pkt->pkt_state |= STATE_ARQ_DONE;
44060Sstevel@tonic-gate 	}
44070Sstevel@tonic-gate 
44080Sstevel@tonic-gate 	/* we will not sense start cmd until we receive a NOT READY */
44090Sstevel@tonic-gate 	if (arqp->sts_sensedata.es_key == KEY_NOT_READY) {
44100Sstevel@tonic-gate 		scsa2usbp->scsa2usb_rcvd_not_ready = B_TRUE;
44110Sstevel@tonic-gate 	}
44120Sstevel@tonic-gate }
44130Sstevel@tonic-gate 
44140Sstevel@tonic-gate 
44150Sstevel@tonic-gate /*
44160Sstevel@tonic-gate  * Miscellaneous functions for any command/transport
44170Sstevel@tonic-gate  */
44180Sstevel@tonic-gate /*
44190Sstevel@tonic-gate  * scsa2usb_open_usb_pipes:
44200Sstevel@tonic-gate  *	set up a pipe policy
44210Sstevel@tonic-gate  *	open usb bulk pipes (BO and CB/CBI)
44220Sstevel@tonic-gate  *	open usb interrupt pipe (CBI)
44230Sstevel@tonic-gate  */
44240Sstevel@tonic-gate static int
44250Sstevel@tonic-gate scsa2usb_open_usb_pipes(scsa2usb_state_t *scsa2usbp)
44260Sstevel@tonic-gate {
44270Sstevel@tonic-gate 	int			rval;
44280Sstevel@tonic-gate 	usb_pipe_policy_t	policy;	/* bulk pipe policy */
44290Sstevel@tonic-gate 	size_t			sz;
44300Sstevel@tonic-gate 
44310Sstevel@tonic-gate 	ASSERT(scsa2usbp);
44320Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
44330Sstevel@tonic-gate 
44340Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
44350Sstevel@tonic-gate 	    "scsa2usb_open_usb_pipes: dip = 0x%p flag = 0x%x",
44366898Sfb209375 	    (void *)scsa2usbp->scsa2usb_dip, scsa2usbp->scsa2usb_flags);
44370Sstevel@tonic-gate 
44380Sstevel@tonic-gate 	if (!(scsa2usbp->scsa2usb_flags & SCSA2USB_FLAGS_PIPES_OPENED)) {
44390Sstevel@tonic-gate 
44400Sstevel@tonic-gate 		/*
44410Sstevel@tonic-gate 		 * one pipe policy for all bulk pipes
44420Sstevel@tonic-gate 		 */
44430Sstevel@tonic-gate 		bzero(&policy, sizeof (usb_pipe_policy_t));
44440Sstevel@tonic-gate 		/* at least 2, for the normal and exceptional callbacks */
44450Sstevel@tonic-gate 		policy.pp_max_async_reqs = 1;
44460Sstevel@tonic-gate 
44470Sstevel@tonic-gate 		USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
44480Sstevel@tonic-gate 		    "scsa2usb_open_usb_pipes: opening bulk pipes");
44490Sstevel@tonic-gate 
44500Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
44510Sstevel@tonic-gate 
44520Sstevel@tonic-gate 		/* Open the USB bulk-in pipe */
44530Sstevel@tonic-gate 		if ((rval = usb_pipe_open(scsa2usbp->scsa2usb_dip,
44540Sstevel@tonic-gate 		    &scsa2usbp->scsa2usb_bulkin_ept, &policy, USB_FLAGS_SLEEP,
44550Sstevel@tonic-gate 		    &scsa2usbp->scsa2usb_bulkin_pipe)) != USB_SUCCESS) {
44560Sstevel@tonic-gate 			mutex_enter(&scsa2usbp->scsa2usb_mutex);
44570Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_SCSA,
44580Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
44590Sstevel@tonic-gate 			    "scsa2usb_open_usb_pipes: bulk/in pipe open "
44600Sstevel@tonic-gate 			    " failed rval = %d", rval);
44610Sstevel@tonic-gate 
44620Sstevel@tonic-gate 			return (USB_FAILURE);
44630Sstevel@tonic-gate 		}
44640Sstevel@tonic-gate 
44650Sstevel@tonic-gate 		/* Open the bulk-out pipe  using the same policy */
44660Sstevel@tonic-gate 		if ((rval = usb_pipe_open(scsa2usbp->scsa2usb_dip,
44670Sstevel@tonic-gate 		    &scsa2usbp->scsa2usb_bulkout_ept, &policy, USB_FLAGS_SLEEP,
44680Sstevel@tonic-gate 		    &scsa2usbp->scsa2usb_bulkout_pipe)) != USB_SUCCESS) {
44690Sstevel@tonic-gate 			usb_pipe_close(scsa2usbp->scsa2usb_dip,
44700Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_bulkin_pipe,
44710Sstevel@tonic-gate 			    USB_FLAGS_SLEEP, NULL, NULL);
44720Sstevel@tonic-gate 
44730Sstevel@tonic-gate 			mutex_enter(&scsa2usbp->scsa2usb_mutex);
44740Sstevel@tonic-gate 			scsa2usbp->scsa2usb_bulkin_pipe = NULL;
44750Sstevel@tonic-gate 
44760Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_SCSA,
44770Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
44780Sstevel@tonic-gate 			    "scsa2usb_open_usb_pipes: bulk/out pipe open"
44790Sstevel@tonic-gate 			    " failed rval = %d", rval);
44800Sstevel@tonic-gate 
44810Sstevel@tonic-gate 			return (USB_FAILURE);
44820Sstevel@tonic-gate 		}
44830Sstevel@tonic-gate 
44840Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
44850Sstevel@tonic-gate 
44860Sstevel@tonic-gate 		/* open interrupt pipe for CBI protocol */
44870Sstevel@tonic-gate 		if (SCSA2USB_IS_CBI(scsa2usbp)) {
44880Sstevel@tonic-gate 			mutex_exit(&scsa2usbp->scsa2usb_mutex);
44890Sstevel@tonic-gate 
44900Sstevel@tonic-gate 			if ((rval = usb_pipe_open(scsa2usbp->scsa2usb_dip,
44910Sstevel@tonic-gate 			    &scsa2usbp->scsa2usb_intr_ept, &policy,
44920Sstevel@tonic-gate 			    USB_FLAGS_SLEEP, &scsa2usbp->scsa2usb_intr_pipe)) !=
44930Sstevel@tonic-gate 			    USB_SUCCESS) {
44940Sstevel@tonic-gate 				usb_pipe_close(scsa2usbp->scsa2usb_dip,
44950Sstevel@tonic-gate 				    scsa2usbp->scsa2usb_bulkin_pipe,
44960Sstevel@tonic-gate 				    USB_FLAGS_SLEEP, NULL, NULL);
44970Sstevel@tonic-gate 
44980Sstevel@tonic-gate 				usb_pipe_close(scsa2usbp->scsa2usb_dip,
44990Sstevel@tonic-gate 				    scsa2usbp->scsa2usb_bulkout_pipe,
45000Sstevel@tonic-gate 				    USB_FLAGS_SLEEP, NULL, NULL);
45010Sstevel@tonic-gate 
45020Sstevel@tonic-gate 				mutex_enter(&scsa2usbp->scsa2usb_mutex);
45030Sstevel@tonic-gate 				scsa2usbp->scsa2usb_bulkin_pipe = NULL;
45040Sstevel@tonic-gate 				scsa2usbp->scsa2usb_bulkout_pipe = NULL;
45050Sstevel@tonic-gate 
45060Sstevel@tonic-gate 				USB_DPRINTF_L2(DPRINT_MASK_SCSA,
45070Sstevel@tonic-gate 				    scsa2usbp->scsa2usb_log_handle,
45080Sstevel@tonic-gate 				    "scsa2usb_open_usb_pipes: intr pipe open"
45090Sstevel@tonic-gate 				    " failed rval = %d", rval);
45100Sstevel@tonic-gate 
45110Sstevel@tonic-gate 				return (USB_FAILURE);
45120Sstevel@tonic-gate 			}
45130Sstevel@tonic-gate 
45140Sstevel@tonic-gate 			mutex_enter(&scsa2usbp->scsa2usb_mutex);
45150Sstevel@tonic-gate 		}
45160Sstevel@tonic-gate 
45170Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
45180Sstevel@tonic-gate 
45190Sstevel@tonic-gate 		/* get the max transfer size of the bulk pipe */
45200Sstevel@tonic-gate 		if (usb_pipe_get_max_bulk_transfer_size(scsa2usbp->scsa2usb_dip,
45210Sstevel@tonic-gate 		    &sz) == USB_SUCCESS) {
45220Sstevel@tonic-gate 			mutex_enter(&scsa2usbp->scsa2usb_mutex);
45230Sstevel@tonic-gate 			scsa2usbp->scsa2usb_max_bulk_xfer_size = sz;
45240Sstevel@tonic-gate 		} else {
45250Sstevel@tonic-gate 			mutex_enter(&scsa2usbp->scsa2usb_mutex);
45260Sstevel@tonic-gate 			scsa2usbp->scsa2usb_max_bulk_xfer_size = DEV_BSIZE;
45270Sstevel@tonic-gate 		}
45280Sstevel@tonic-gate 
45290Sstevel@tonic-gate 		/* limit the xfer size */
45300Sstevel@tonic-gate 		scsa2usbp->scsa2usb_max_bulk_xfer_size = min(
45314700Sfb209375 		    scsa2usbp->scsa2usb_max_bulk_xfer_size,
45324700Sfb209375 		    scsa2usb_max_bulk_xfer_size);
45330Sstevel@tonic-gate 
45340Sstevel@tonic-gate 		USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
45350Sstevel@tonic-gate 		    "scsa2usb_open_usb_pipes: max bulk transfer size = %lx",
45360Sstevel@tonic-gate 		    scsa2usbp->scsa2usb_max_bulk_xfer_size);
45370Sstevel@tonic-gate 
45380Sstevel@tonic-gate 		/* Set the pipes opened flag */
45390Sstevel@tonic-gate 		scsa2usbp->scsa2usb_flags |= SCSA2USB_FLAGS_PIPES_OPENED;
45400Sstevel@tonic-gate 
45410Sstevel@tonic-gate 		scsa2usbp->scsa2usb_pipe_state = SCSA2USB_PIPE_NORMAL;
45420Sstevel@tonic-gate 
45430Sstevel@tonic-gate 		/* Set the state to NONE */
45440Sstevel@tonic-gate 		scsa2usbp->scsa2usb_pkt_state = SCSA2USB_PKT_NONE;
45450Sstevel@tonic-gate 	}
45460Sstevel@tonic-gate 
45470Sstevel@tonic-gate 	return (USB_SUCCESS);
45480Sstevel@tonic-gate }
45490Sstevel@tonic-gate 
45500Sstevel@tonic-gate 
45510Sstevel@tonic-gate /*
45520Sstevel@tonic-gate  * scsa2usb_close_usb_pipes:
45530Sstevel@tonic-gate  *	close all pipes synchronously
45540Sstevel@tonic-gate  */
45550Sstevel@tonic-gate void
45560Sstevel@tonic-gate scsa2usb_close_usb_pipes(scsa2usb_state_t *scsa2usbp)
45570Sstevel@tonic-gate {
45580Sstevel@tonic-gate 	usb_flags_t flags = USB_FLAGS_SLEEP;
45590Sstevel@tonic-gate 
45600Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
45616898Sfb209375 	    "scsa2usb_close_usb_pipes: scsa2usb_state = 0x%p",
45626898Sfb209375 	    (void *)scsa2usbp);
45630Sstevel@tonic-gate 
45640Sstevel@tonic-gate 	ASSERT(scsa2usbp);
45650Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
45660Sstevel@tonic-gate 
45670Sstevel@tonic-gate 	if ((scsa2usbp->scsa2usb_flags & SCSA2USB_FLAGS_PIPES_OPENED) == 0) {
45680Sstevel@tonic-gate 
45690Sstevel@tonic-gate 		return;
45700Sstevel@tonic-gate 	}
45710Sstevel@tonic-gate 
45720Sstevel@tonic-gate 	scsa2usbp->scsa2usb_pipe_state = SCSA2USB_PIPE_CLOSING;
45730Sstevel@tonic-gate 	/* to avoid races, reset the flag first */
45740Sstevel@tonic-gate 	scsa2usbp->scsa2usb_flags &= ~SCSA2USB_FLAGS_PIPES_OPENED;
45750Sstevel@tonic-gate 
45760Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
45770Sstevel@tonic-gate 
45780Sstevel@tonic-gate 	usb_pipe_close(scsa2usbp->scsa2usb_dip,
45790Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_bulkout_pipe, flags, NULL, NULL);
45800Sstevel@tonic-gate 
45810Sstevel@tonic-gate 	usb_pipe_close(scsa2usbp->scsa2usb_dip,
45820Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_bulkin_pipe, flags, NULL, NULL);
45830Sstevel@tonic-gate 
45840Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
45850Sstevel@tonic-gate 	if (SCSA2USB_IS_CBI(scsa2usbp)) {
45860Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
45870Sstevel@tonic-gate 		usb_pipe_close(scsa2usbp->scsa2usb_dip,
45880Sstevel@tonic-gate 		    scsa2usbp->scsa2usb_intr_pipe, flags, NULL, NULL);
45890Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
45900Sstevel@tonic-gate 	}
45910Sstevel@tonic-gate 	scsa2usbp->scsa2usb_bulkout_pipe = NULL;
45920Sstevel@tonic-gate 	scsa2usbp->scsa2usb_bulkin_pipe = NULL;
45930Sstevel@tonic-gate 	scsa2usbp->scsa2usb_intr_pipe = NULL;
45940Sstevel@tonic-gate 
45950Sstevel@tonic-gate 	scsa2usbp->scsa2usb_pipe_state = SCSA2USB_PIPE_NORMAL;
45960Sstevel@tonic-gate }
45970Sstevel@tonic-gate 
45980Sstevel@tonic-gate 
45990Sstevel@tonic-gate /*
46000Sstevel@tonic-gate  * scsa2usb_fill_up_cdb_lba:
46010Sstevel@tonic-gate  *	fill up command CDBs' LBA part
46020Sstevel@tonic-gate  */
46030Sstevel@tonic-gate static void
46040Sstevel@tonic-gate scsa2usb_fill_up_cdb_lba(scsa2usb_cmd_t *cmd, int lba)
46050Sstevel@tonic-gate {
46060Sstevel@tonic-gate 	/* zero cdb1, lba bits so they won't get copied in the new cdb */
46070Sstevel@tonic-gate 	cmd->cmd_cdb[SCSA2USB_LUN] &= 0xE0;
46080Sstevel@tonic-gate 	cmd->cmd_cdb[SCSA2USB_LBA_0] = lba >> 24;
46090Sstevel@tonic-gate 	cmd->cmd_cdb[SCSA2USB_LBA_1] = lba >> 16;
46100Sstevel@tonic-gate 	cmd->cmd_cdb[SCSA2USB_LBA_2] = lba >> 8;
46110Sstevel@tonic-gate 	cmd->cmd_cdb[SCSA2USB_LBA_3] = (uchar_t)lba;
46120Sstevel@tonic-gate 	cmd->cmd_lba = lba;
46130Sstevel@tonic-gate }
46140Sstevel@tonic-gate 
46150Sstevel@tonic-gate 
46160Sstevel@tonic-gate /*
46170Sstevel@tonic-gate  * scsa2usb_fill_up_ReadCD_cdb_len:
46180Sstevel@tonic-gate  *	fill up READ_CD command CDBs' len part
46190Sstevel@tonic-gate  */
46200Sstevel@tonic-gate static void
46210Sstevel@tonic-gate scsa2usb_fill_up_ReadCD_cdb_len(scsa2usb_cmd_t *cmd, int len, int actual_len)
46220Sstevel@tonic-gate {
46230Sstevel@tonic-gate 	cmd->cmd_cdb[SCSA2USB_READ_CD_LEN_0] = len >> 16;
46240Sstevel@tonic-gate 	cmd->cmd_cdb[SCSA2USB_READ_CD_LEN_1] = len >> 8;
46250Sstevel@tonic-gate 	cmd->cmd_cdb[SCSA2USB_READ_CD_LEN_2] = (uchar_t)len;
46260Sstevel@tonic-gate 	cmd->cmd_actual_len = (uchar_t)actual_len;
46270Sstevel@tonic-gate }
46280Sstevel@tonic-gate 
46290Sstevel@tonic-gate 
46300Sstevel@tonic-gate /*
46310Sstevel@tonic-gate  * scsa2usb_fill_up_12byte_cdb_len:
46320Sstevel@tonic-gate  *	fill up generic 12-byte command CDBs' len part
46330Sstevel@tonic-gate  */
46340Sstevel@tonic-gate static void
46350Sstevel@tonic-gate scsa2usb_fill_up_12byte_cdb_len(scsa2usb_cmd_t *cmd, int len, int actual_len)
46360Sstevel@tonic-gate {
46370Sstevel@tonic-gate 	cmd->cmd_cdb[6] = len >> 24;
46380Sstevel@tonic-gate 	cmd->cmd_cdb[7] = len >> 16;
46390Sstevel@tonic-gate 	cmd->cmd_cdb[8] = len >> 8;
46400Sstevel@tonic-gate 	cmd->cmd_cdb[9] = (uchar_t)len;
46410Sstevel@tonic-gate 	cmd->cmd_actual_len = (uchar_t)actual_len;
46420Sstevel@tonic-gate }
46430Sstevel@tonic-gate 
46440Sstevel@tonic-gate 
46450Sstevel@tonic-gate /*
46460Sstevel@tonic-gate  * scsa2usb_fill_up_cdb_len:
46470Sstevel@tonic-gate  *	fill up generic 10-byte command CDBs' len part
46480Sstevel@tonic-gate  */
46490Sstevel@tonic-gate static void
46500Sstevel@tonic-gate scsa2usb_fill_up_cdb_len(scsa2usb_cmd_t *cmd, int len)
46510Sstevel@tonic-gate {
46520Sstevel@tonic-gate 	cmd->cmd_cdb[SCSA2USB_LEN_0] = len >> 8;
46530Sstevel@tonic-gate 	cmd->cmd_cdb[SCSA2USB_LEN_1] = (uchar_t)len;
46540Sstevel@tonic-gate }
46550Sstevel@tonic-gate 
46560Sstevel@tonic-gate 
46570Sstevel@tonic-gate /*
46580Sstevel@tonic-gate  * scsa2usb_read_cd_blk_size:
46590Sstevel@tonic-gate  *	For SCMD_READ_CD opcode (0xbe). Figure out the
46600Sstevel@tonic-gate  *	block size based on expected sector type field
46610Sstevel@tonic-gate  *	definition. See MMC SCSI Specs section 6.1.15
46620Sstevel@tonic-gate  *
46630Sstevel@tonic-gate  *	Based on the value of the "expected_sector_type"
46640Sstevel@tonic-gate  *	field, the block size could be different.
46650Sstevel@tonic-gate  */
46660Sstevel@tonic-gate static int
46670Sstevel@tonic-gate scsa2usb_read_cd_blk_size(uchar_t expected_sector_type)
46680Sstevel@tonic-gate {
46690Sstevel@tonic-gate 	int blk_size;
46700Sstevel@tonic-gate 
46710Sstevel@tonic-gate 	switch (expected_sector_type) {
46720Sstevel@tonic-gate 	case READ_CD_EST_CDDA:
46730Sstevel@tonic-gate 		blk_size = CDROM_BLK_2352;
46740Sstevel@tonic-gate 		break;
46750Sstevel@tonic-gate 	case READ_CD_EST_MODE2:
46760Sstevel@tonic-gate 		blk_size = CDROM_BLK_2336;
46770Sstevel@tonic-gate 		break;
46780Sstevel@tonic-gate 	case READ_CD_EST_MODE2FORM2:
46790Sstevel@tonic-gate 		blk_size = CDROM_BLK_2324;
46800Sstevel@tonic-gate 		break;
46810Sstevel@tonic-gate 	case READ_CD_EST_MODE2FORM1:
46820Sstevel@tonic-gate 	case READ_CD_EST_ALLTYPE:
46830Sstevel@tonic-gate 	case READ_CD_EST_MODE1:
46840Sstevel@tonic-gate 	default:
46850Sstevel@tonic-gate 		blk_size = CDROM_BLK_2048;
46860Sstevel@tonic-gate 	}
46870Sstevel@tonic-gate 
46880Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, NULL, "scsa2usb_read_cd_blk_size: "
46890Sstevel@tonic-gate 	    "est = 0x%x blk_size = %d", expected_sector_type, blk_size);
46900Sstevel@tonic-gate 
46910Sstevel@tonic-gate 	return (blk_size);
46920Sstevel@tonic-gate }
46930Sstevel@tonic-gate 
46940Sstevel@tonic-gate 
46950Sstevel@tonic-gate /*
46960Sstevel@tonic-gate  * scsa2usb_bp_to_mblk:
46970Sstevel@tonic-gate  *	Convert a bp to mblk_t. USBA framework understands mblk_t.
46980Sstevel@tonic-gate  */
46990Sstevel@tonic-gate static mblk_t *
47000Sstevel@tonic-gate scsa2usb_bp_to_mblk(scsa2usb_state_t *scsa2usbp)
47010Sstevel@tonic-gate {
47020Sstevel@tonic-gate 	size_t		size;
47030Sstevel@tonic-gate 	mblk_t		*mp;
47040Sstevel@tonic-gate 	struct buf	*bp;
47050Sstevel@tonic-gate 	scsa2usb_cmd_t	*cmd = PKT2CMD(scsa2usbp->scsa2usb_cur_pkt);
47060Sstevel@tonic-gate 
47070Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
47080Sstevel@tonic-gate 	    "scsa2usb_bp_to_mblk: ");
47090Sstevel@tonic-gate 
47100Sstevel@tonic-gate 	ASSERT(scsa2usbp->scsa2usb_cur_pkt);
47110Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
47120Sstevel@tonic-gate 
47130Sstevel@tonic-gate 	bp = cmd->cmd_bp;
47140Sstevel@tonic-gate 
47150Sstevel@tonic-gate 	if (bp && (bp->b_bcount > 0)) {
47160Sstevel@tonic-gate 		size = ((bp->b_bcount > cmd->cmd_xfercount) ?
47174700Sfb209375 		    cmd->cmd_xfercount : bp->b_bcount);
47180Sstevel@tonic-gate 	} else {
47190Sstevel@tonic-gate 
47200Sstevel@tonic-gate 		return (NULL);
47210Sstevel@tonic-gate 	}
47220Sstevel@tonic-gate 
47230Sstevel@tonic-gate 	mp = esballoc_wait((uchar_t *)bp->b_un.b_addr + cmd->cmd_offset,
47247062Szl227052 	    size, BPRI_LO, &frnop);
47250Sstevel@tonic-gate 
47260Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
47270Sstevel@tonic-gate 	    "scsa2usb_bp_to_mblk: "
47286898Sfb209375 	    "mp=0x%p bp=0x%p pkt=0x%p off=0x%lx sz=%lu add=0x%p",
47296898Sfb209375 	    (void *)mp, (void *)bp, (void *)scsa2usbp->scsa2usb_cur_pkt,
47306898Sfb209375 	    cmd->cmd_offset, bp->b_bcount - cmd->cmd_offset,
47316898Sfb209375 	    (void *)bp->b_un.b_addr);
47320Sstevel@tonic-gate 
47330Sstevel@tonic-gate 	mp->b_wptr += size;
47340Sstevel@tonic-gate 	cmd->cmd_offset += size;
47350Sstevel@tonic-gate 
47360Sstevel@tonic-gate 	return (mp);
47370Sstevel@tonic-gate }
47380Sstevel@tonic-gate 
47390Sstevel@tonic-gate 
47400Sstevel@tonic-gate /*
47410Sstevel@tonic-gate  * scsa2usb_handle_data_start:
47420Sstevel@tonic-gate  *	Initiate the data xfer. It could be IN/OUT direction.
47430Sstevel@tonic-gate  *
47440Sstevel@tonic-gate  *	Data IN:
47450Sstevel@tonic-gate  *		Send out the bulk-xfer request
47460Sstevel@tonic-gate  *		if rval implies STALL
47470Sstevel@tonic-gate  *			clear endpoint stall and reset bulk-in pipe
47480Sstevel@tonic-gate  *			handle data read in so far; set cmd->cmd_done
47490Sstevel@tonic-gate  *			also adjust data xfer length accordingly
47500Sstevel@tonic-gate  *		else other error
47510Sstevel@tonic-gate  *			report back to transport
47520Sstevel@tonic-gate  *			typically transport will call reset recovery
47530Sstevel@tonic-gate  *		else (no error)
47540Sstevel@tonic-gate  *			return success
47550Sstevel@tonic-gate  *
47560Sstevel@tonic-gate  *	Data OUT:
47570Sstevel@tonic-gate  *		Send out the bulk-xfer request
47580Sstevel@tonic-gate  *		if rval implies STALL
47590Sstevel@tonic-gate  *			clear endpoint stall and reset bulk-in pipe
47600Sstevel@tonic-gate  *			adjust data xfer length
47610Sstevel@tonic-gate  *		else other error
47620Sstevel@tonic-gate  *			report back to transport
47630Sstevel@tonic-gate  *			typically transport will call reset recovery
47640Sstevel@tonic-gate  *		else (no error)
47650Sstevel@tonic-gate  *			return success
47660Sstevel@tonic-gate  *
47670Sstevel@tonic-gate  *	NOTE: We call this function only if there is xfercount.
47680Sstevel@tonic-gate  */
47690Sstevel@tonic-gate int
47700Sstevel@tonic-gate scsa2usb_handle_data_start(scsa2usb_state_t *scsa2usbp,
47710Sstevel@tonic-gate     scsa2usb_cmd_t *cmd, usb_bulk_req_t *req)
47720Sstevel@tonic-gate {
47730Sstevel@tonic-gate 	int		rval = USB_SUCCESS;
47740Sstevel@tonic-gate 	uint_t		ept_addr;
47750Sstevel@tonic-gate 	usb_flags_t	flags = USB_FLAGS_SLEEP;
47760Sstevel@tonic-gate #ifdef	SCSA2USB_BULK_ONLY_TEST
47770Sstevel@tonic-gate 	usb_req_attrs_t	attrs = 0;
47780Sstevel@tonic-gate #else
47790Sstevel@tonic-gate 	usb_req_attrs_t	attrs = USB_ATTRS_SHORT_XFER_OK;
47800Sstevel@tonic-gate #endif
47810Sstevel@tonic-gate 
47820Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
47836898Sfb209375 	    "scsa2usb_handle_data_start: BEGIN cmd = %p, req = %p",
47846898Sfb209375 	    (void *)cmd, (void *)req);
47850Sstevel@tonic-gate 
47860Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
47870Sstevel@tonic-gate 
47880Sstevel@tonic-gate 	switch (cmd->cmd_dir) {
47890Sstevel@tonic-gate 	case USB_EP_DIR_IN:
47900Sstevel@tonic-gate #ifdef	SCSA2USB_BULK_ONLY_TEST
47910Sstevel@tonic-gate 		/*
47920Sstevel@tonic-gate 		 * This case occurs when the host expects to receive
47930Sstevel@tonic-gate 		 * more data than the device actually transfers. Hi > Di
47940Sstevel@tonic-gate 		 */
47950Sstevel@tonic-gate 		if (scsa2usb_test_case_5) {
47960Sstevel@tonic-gate 			usb_bulk_req_t *req2;
47970Sstevel@tonic-gate 
47980Sstevel@tonic-gate 			req->bulk_len = cmd->cmd_xfercount - 1;
47990Sstevel@tonic-gate 			req->bulk_attributes = 0;
48000Sstevel@tonic-gate 			mutex_exit(&scsa2usbp->scsa2usb_mutex);
48010Sstevel@tonic-gate 			SCSA2USB_FREE_MSG(req->bulk_data);
48020Sstevel@tonic-gate 			req->bulk_data = allocb_wait(req->bulk_len, BPRI_LO,
48030Sstevel@tonic-gate 			    STR_NOSIG, NULL);
48040Sstevel@tonic-gate 
48050Sstevel@tonic-gate 			ASSERT(req->bulk_timeout);
48060Sstevel@tonic-gate 			rval = usb_pipe_bulk_xfer(
48070Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_bulkin_pipe, req, flags);
48080Sstevel@tonic-gate 			mutex_enter(&scsa2usbp->scsa2usb_mutex);
48090Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_SCSA,
48100Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle, "rval = %x", rval);
48110Sstevel@tonic-gate 
48120Sstevel@tonic-gate 			req2 = scsa2usb_init_bulk_req(scsa2usbp,
48130Sstevel@tonic-gate 			    cmd->cmd_xfercount + 2,
48140Sstevel@tonic-gate 			    cmd->cmd_timeout, 0, flags);
48150Sstevel@tonic-gate 			req2->bulk_len = cmd->cmd_xfercount + 2;
48160Sstevel@tonic-gate 			mutex_exit(&scsa2usbp->scsa2usb_mutex);
48170Sstevel@tonic-gate 
48180Sstevel@tonic-gate 			ASSERT(req2->bulk_timeout);
48190Sstevel@tonic-gate 			rval = usb_pipe_bulk_xfer(
48200Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_bulkin_pipe, req2, flags);
48210Sstevel@tonic-gate 			mutex_enter(&scsa2usbp->scsa2usb_mutex);
48220Sstevel@tonic-gate 
48230Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_SCSA,
48240Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
48250Sstevel@tonic-gate 			    "TEST 5: Hi > Di: rval = 0x%x", rval);
48260Sstevel@tonic-gate 			scsa2usb_test_case_5 = 0;
48270Sstevel@tonic-gate 			usb_free_bulk_req(req2);
48280Sstevel@tonic-gate 
48290Sstevel@tonic-gate 			return (rval);
48300Sstevel@tonic-gate 		}
48310Sstevel@tonic-gate 
48320Sstevel@tonic-gate 		/*
48330Sstevel@tonic-gate 		 * This happens when the host expects to send data to the
48340Sstevel@tonic-gate 		 * device while the device intends to send data to the host.
48350Sstevel@tonic-gate 		 */
48360Sstevel@tonic-gate 		if (scsa2usb_test_case_8 && (cmd->cmd_cdb[0] == SCMD_READ_G1)) {
48370Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_SCSA,
48380Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
48390Sstevel@tonic-gate 			    "TEST 8: Hi <> Do: Step 2");
48400Sstevel@tonic-gate 			scsa2usb_test_mblk(scsa2usbp, B_TRUE);
48410Sstevel@tonic-gate 			scsa2usb_test_case_8 = 0;
48420Sstevel@tonic-gate 
48430Sstevel@tonic-gate 			return (rval);
48440Sstevel@tonic-gate 		}
48450Sstevel@tonic-gate #endif	/* SCSA2USB_BULK_ONLY_TEST */
48460Sstevel@tonic-gate 
48470Sstevel@tonic-gate 		ept_addr = scsa2usbp->scsa2usb_bulkin_ept.bEndpointAddress;
48480Sstevel@tonic-gate 		req->bulk_len = cmd->cmd_xfercount;
48490Sstevel@tonic-gate 		req->bulk_attributes = attrs;
48500Sstevel@tonic-gate 		SCSA2USB_FREE_MSG(req->bulk_data);
48510Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
48520Sstevel@tonic-gate 
48530Sstevel@tonic-gate 		req->bulk_data = esballoc_wait(
48544700Sfb209375 		    (uchar_t *)cmd->cmd_bp->b_un.b_addr +
48554700Sfb209375 		    cmd->cmd_offset,
48567062Szl227052 		    req->bulk_len, BPRI_LO, &frnop);
48570Sstevel@tonic-gate 
48580Sstevel@tonic-gate 		ASSERT(req->bulk_timeout);
48590Sstevel@tonic-gate 		rval = usb_pipe_bulk_xfer(scsa2usbp->scsa2usb_bulkin_pipe,
48604700Sfb209375 		    req, flags);
48610Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
48620Sstevel@tonic-gate 
48630Sstevel@tonic-gate 		break;
48640Sstevel@tonic-gate 
48650Sstevel@tonic-gate 	case USB_EP_DIR_OUT:
48660Sstevel@tonic-gate #ifdef	SCSA2USB_BULK_ONLY_TEST
48670Sstevel@tonic-gate 		/*
48680Sstevel@tonic-gate 		 * This happens when the host expects to receive data
48690Sstevel@tonic-gate 		 * from the device while the device intends to receive
48700Sstevel@tonic-gate 		 * data from the host.
48710Sstevel@tonic-gate 		 */
48720Sstevel@tonic-gate 		if (scsa2usb_test_case_10 &&
48730Sstevel@tonic-gate 		    (cmd->cmd_cdb[0] == SCMD_WRITE_G1)) {
48740Sstevel@tonic-gate 			req->bulk_len = CSW_LEN;
48750Sstevel@tonic-gate 			mutex_exit(&scsa2usbp->scsa2usb_mutex);
48760Sstevel@tonic-gate 
48770Sstevel@tonic-gate 			ASSERT(req->bulk_timeout);
48780Sstevel@tonic-gate 			rval = usb_pipe_bulk_xfer(
48790Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_bulkin_pipe, req, flags);
48800Sstevel@tonic-gate 			mutex_enter(&scsa2usbp->scsa2usb_mutex);
48810Sstevel@tonic-gate 
48820Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_SCSA,
48830Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
48840Sstevel@tonic-gate 			    "TEST 10: Ho <> Di: done rval = 0x%x",  rval);
48850Sstevel@tonic-gate 			scsa2usb_test_case_10 = 0;
48860Sstevel@tonic-gate 
48870Sstevel@tonic-gate 			return (rval);
48880Sstevel@tonic-gate 		}
48890Sstevel@tonic-gate #endif	/* SCSA2USB_BULK_ONLY_TEST */
48900Sstevel@tonic-gate 
48910Sstevel@tonic-gate 		req->bulk_data = scsa2usb_bp_to_mblk(scsa2usbp);
48920Sstevel@tonic-gate 		if (req->bulk_data == NULL) {
48930Sstevel@tonic-gate 
48940Sstevel@tonic-gate 			return (USB_FAILURE);
48950Sstevel@tonic-gate 		}
48960Sstevel@tonic-gate 
48970Sstevel@tonic-gate #ifdef	SCSA2USB_BULK_ONLY_TEST
48980Sstevel@tonic-gate 		if (scsa2usb_test_case_11) {
48990Sstevel@tonic-gate 			/*
49000Sstevel@tonic-gate 			 * Host expects to send data to the device and
49010Sstevel@tonic-gate 			 * device doesn't expect to receive any data
49020Sstevel@tonic-gate 			 */
49030Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_SCSA,
49040Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle, "TEST 11: Ho > Do");
49050Sstevel@tonic-gate 
49060Sstevel@tonic-gate 			scsa2usb_test_mblk(scsa2usbp, B_FALSE);
49070Sstevel@tonic-gate 			scsa2usb_test_case_11 = 0;
49080Sstevel@tonic-gate 		}
49090Sstevel@tonic-gate #endif	/* SCSA2USB_BULK_ONLY_TEST */
49100Sstevel@tonic-gate 
49110Sstevel@tonic-gate 		ept_addr = scsa2usbp->scsa2usb_bulkout_ept.bEndpointAddress;
49127492SZhigang.Lu@Sun.COM 		req->bulk_len = MBLKL(req->bulk_data);
49130Sstevel@tonic-gate 		req->bulk_timeout = scsa2usb_bulk_timeout(cmd->cmd_timeout);
49140Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
49150Sstevel@tonic-gate 
49160Sstevel@tonic-gate 		ASSERT(req->bulk_timeout);
49170Sstevel@tonic-gate 		rval = usb_pipe_bulk_xfer(scsa2usbp->scsa2usb_bulkout_pipe,
49184700Sfb209375 		    req, flags);
49190Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
49200Sstevel@tonic-gate 		break;
49210Sstevel@tonic-gate 	}
49220Sstevel@tonic-gate 
49230Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_SCSA,
49240Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_log_handle,
49250Sstevel@tonic-gate 	    "scsa2usb_handle_data_start: rval=%d cr=%d", rval,
49260Sstevel@tonic-gate 	    req->bulk_completion_reason);
49270Sstevel@tonic-gate 
49280Sstevel@tonic-gate 	if (rval != USB_SUCCESS) {
49290Sstevel@tonic-gate 		/* Handle Errors now */
49300Sstevel@tonic-gate 		if (req->bulk_completion_reason == USB_CR_STALL) {
49310Sstevel@tonic-gate 			if (cmd->cmd_dir == USB_EP_DIR_IN) {
49320Sstevel@tonic-gate 				(void) scsa2usb_clear_ept_stall(
49330Sstevel@tonic-gate 				    scsa2usbp, ept_addr,
49340Sstevel@tonic-gate 				    scsa2usbp-> scsa2usb_bulkin_pipe,
49350Sstevel@tonic-gate 				    "bulk-in");
49360Sstevel@tonic-gate 			} else {
49370Sstevel@tonic-gate 				(void) scsa2usb_clear_ept_stall(
49380Sstevel@tonic-gate 				    scsa2usbp, ept_addr,
49390Sstevel@tonic-gate 				    scsa2usbp-> scsa2usb_bulkout_pipe,
49400Sstevel@tonic-gate 				    "bulk-out");
49410Sstevel@tonic-gate 			}
49420Sstevel@tonic-gate 		}
49430Sstevel@tonic-gate 
49440Sstevel@tonic-gate 		/* no more data to transfer after this */
49450Sstevel@tonic-gate 		cmd->cmd_done = 1;
49460Sstevel@tonic-gate 	}
49470Sstevel@tonic-gate 
49480Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
49490Sstevel@tonic-gate 	    "scsa2usb_handle_data_start: END %s data rval = %d",
49500Sstevel@tonic-gate 	    (cmd->cmd_dir == USB_EP_DIR_IN) ? "bulk-in" : "bulk-out", rval);
49510Sstevel@tonic-gate 
49520Sstevel@tonic-gate 	return (rval);
49530Sstevel@tonic-gate }
49540Sstevel@tonic-gate 
49550Sstevel@tonic-gate 
49560Sstevel@tonic-gate /*
49570Sstevel@tonic-gate  * scsa2usb_handle_data_done:
49580Sstevel@tonic-gate  *	This function handles the completion of the data xfer.
49590Sstevel@tonic-gate  *	It also massages the inquiry data. This function may
49600Sstevel@tonic-gate  *	also be called after a stall.
49610Sstevel@tonic-gate  */
49620Sstevel@tonic-gate void
49630Sstevel@tonic-gate scsa2usb_handle_data_done(scsa2usb_state_t *scsa2usbp,
49640Sstevel@tonic-gate     scsa2usb_cmd_t *cmd, usb_bulk_req_t *req)
49650Sstevel@tonic-gate {
49660Sstevel@tonic-gate 	struct buf	*bp = cmd->cmd_bp;
49670Sstevel@tonic-gate 	struct scsi_pkt	*pkt = scsa2usbp->scsa2usb_cur_pkt;
49680Sstevel@tonic-gate 	mblk_t		*data = req->bulk_data;
49697492SZhigang.Lu@Sun.COM 	int		len = data ? MBLKL(data) : 0;
49704834Sfb209375 	uint32_t	max_lba;
49710Sstevel@tonic-gate 
49720Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
49730Sstevel@tonic-gate 
49740Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
49750Sstevel@tonic-gate 	    "scsa2usb_handle_data_done:\n\tcmd = 0x%p data = 0x%p len = 0x%x",
49766898Sfb209375 	    (void *)cmd, (void *)data, len);
49770Sstevel@tonic-gate 
49780Sstevel@tonic-gate 	cmd->cmd_resid_xfercount = cmd->cmd_xfercount - len;
49790Sstevel@tonic-gate 
49800Sstevel@tonic-gate 	if (len)  {
49810Sstevel@tonic-gate 		uchar_t	*p;
49825652Slg150142 		uchar_t dtype;
49830Sstevel@tonic-gate 		scsa2usb_read_cap_t *cap;
49845652Slg150142 		struct scsi_inquiry *inq;
49850Sstevel@tonic-gate 
49860Sstevel@tonic-gate 		switch (cmd->cmd_cdb[SCSA2USB_OPCODE]) {
49870Sstevel@tonic-gate 		case SCMD_INQUIRY:
49880Sstevel@tonic-gate 			/*
49890Sstevel@tonic-gate 			 * cache a copy of the inquiry data for our own use
49900Sstevel@tonic-gate 			 * but ensure that we have at least up to
49910Sstevel@tonic-gate 			 * inq_revision, inq_serial is not required.
49920Sstevel@tonic-gate 			 * ignore inquiry data returned for inquiry commands
49930Sstevel@tonic-gate 			 * with SCSI-3 EVPD, CmdDt bits set.
49940Sstevel@tonic-gate 			 */
49950Sstevel@tonic-gate 			if (((cmd->cmd_cdb[SCSA2USB_LUN] & 0x1f) == 0) &&
49960Sstevel@tonic-gate 			    (len >= SCSA2USB_MAX_INQ_LEN)) {
49975652Slg150142 				inq = (struct scsi_inquiry *)data->b_rptr;
49985652Slg150142 				dtype = inq->inq_dtype & DTYPE_MASK;
49995652Slg150142 				/*
50005652Slg150142 				 * scsi framework sends zero byte write(10) cmd
50015652Slg150142 				 * to (Simplified) direct-access devices with
50025652Slg150142 				 * inquiry version > 2 for reservation changes.
50035652Slg150142 				 * But some USB devices don't support zero byte
50045652Slg150142 				 * write(10) even though they have inquiry
50055652Slg150142 				 * version > 2. Considering scsa2usb driver
50065652Slg150142 				 * doesn't support reservation and all the
50075652Slg150142 				 * reservation cmds are being faked, we fake
50085652Slg150142 				 * the inquiry version to 0 to make scsi
50095652Slg150142 				 * framework send test unit ready cmd which is
50105652Slg150142 				 * supported by all the usb devices.
50115652Slg150142 				 */
50125652Slg150142 				if (((dtype == DTYPE_DIRECT) ||
50135652Slg150142 				    (dtype == DTYPE_RBC)) &&
50145652Slg150142 				    (inq->inq_ansi > 2)) {
50155652Slg150142 					inq->inq_ansi = 0;
50165652Slg150142 				}
50175652Slg150142 
50180Sstevel@tonic-gate 				bzero(&scsa2usbp->scsa2usb_lun_inquiry
50190Sstevel@tonic-gate 				    [pkt->pkt_address.a_lun],
50200Sstevel@tonic-gate 				    sizeof (struct scsi_inquiry));
50210Sstevel@tonic-gate 				bcopy(data->b_rptr,
50220Sstevel@tonic-gate 				    &scsa2usbp->scsa2usb_lun_inquiry
50230Sstevel@tonic-gate 				    [pkt->pkt_address.a_lun], len);
50240Sstevel@tonic-gate 			}
50250Sstevel@tonic-gate 
50260Sstevel@tonic-gate 			USB_DPRINTF_L3(DPRINT_MASK_SCSA,
50270Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
50280Sstevel@tonic-gate 			    "scsi inquiry type = 0x%x",
50290Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_lun_inquiry
50300Sstevel@tonic-gate 			    [pkt->pkt_address.a_lun].inq_dtype);
50310Sstevel@tonic-gate 
50320Sstevel@tonic-gate 			cmd->cmd_done = 1;
50330Sstevel@tonic-gate 			goto handle_data;
50340Sstevel@tonic-gate 
50350Sstevel@tonic-gate 		case SCMD_READ_CAPACITY:
50360Sstevel@tonic-gate 			cap = (scsa2usb_read_cap_t *)data->b_rptr;
50370Sstevel@tonic-gate 
50380Sstevel@tonic-gate 			/* Figure out the logical block size */
50390Sstevel@tonic-gate 			if ((len >= sizeof (struct scsa2usb_read_cap)) &&
50400Sstevel@tonic-gate 			    (req->bulk_completion_reason == USB_CR_OK)) {
50410Sstevel@tonic-gate 				scsa2usbp->
50420Sstevel@tonic-gate 				    scsa2usb_lbasize[pkt->pkt_address.a_lun] =
50430Sstevel@tonic-gate 				    SCSA2USB_MK_32BIT(
50444700Sfb209375 				    cap->scsa2usb_read_cap_blen3,
50454700Sfb209375 				    cap->scsa2usb_read_cap_blen2,
50464700Sfb209375 				    cap->scsa2usb_read_cap_blen1,
50474700Sfb209375 				    cap->scsa2usb_read_cap_blen0);
50480Sstevel@tonic-gate 
50494834Sfb209375 				max_lba = SCSA2USB_MK_32BIT(
50504834Sfb209375 				    cap->scsa2usb_read_cap_lba3,
50514834Sfb209375 				    cap->scsa2usb_read_cap_lba2,
50524834Sfb209375 				    cap->scsa2usb_read_cap_lba1,
50534834Sfb209375 				    cap->scsa2usb_read_cap_lba0);
50544834Sfb209375 
50554834Sfb209375 				/*
50564834Sfb209375 				 * Some devices return total logical block
50574834Sfb209375 				 * number instead of highest logical block
50584834Sfb209375 				 * address. Adjust the value by minus 1.
50594834Sfb209375 				 */
50604834Sfb209375 				if (max_lba > 0 && (scsa2usbp->scsa2usb_attrs &
50614834Sfb209375 				    SCSA2USB_ATTRS_NO_CAP_ADJUST) == 0) {
50624834Sfb209375 					max_lba -= 1;
50634834Sfb209375 					cap->scsa2usb_read_cap_lba0 =
50644834Sfb209375 					    (uchar_t)(max_lba & 0xFF);
50654834Sfb209375 					cap->scsa2usb_read_cap_lba1 =
50664834Sfb209375 					    (uchar_t)(max_lba >> 8 & 0xFF);
50674834Sfb209375 					cap->scsa2usb_read_cap_lba2 =
50684834Sfb209375 					    (uchar_t)(max_lba >> 16 & 0xFF);
50694834Sfb209375 					cap->scsa2usb_read_cap_lba3 =
50704834Sfb209375 					    (uchar_t)(max_lba >> 24 & 0xFF);
50714834Sfb209375 				}
50724834Sfb209375 
50734834Sfb209375 				USB_DPRINTF_L2(DPRINT_MASK_SCSA,
50740Sstevel@tonic-gate 				    scsa2usbp->scsa2usb_log_handle,
50756898Sfb209375 				    "bytes in each logical block=0x%lx,"
50764834Sfb209375 				    "number of total logical blocks=0x%x",
50774834Sfb209375 				    scsa2usbp->
50784834Sfb209375 				    scsa2usb_lbasize[pkt->pkt_address.a_lun],
50794834Sfb209375 				    max_lba + 1);
50800Sstevel@tonic-gate 			}
50810Sstevel@tonic-gate 			cmd->cmd_done = 1;
50820Sstevel@tonic-gate 			goto handle_data;
50830Sstevel@tonic-gate 
50840Sstevel@tonic-gate 		case SCMD_REQUEST_SENSE:
50850Sstevel@tonic-gate 			p = data->b_rptr;
50860Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_SCSA,
50870Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
50880Sstevel@tonic-gate 			    "cdb: %x rqsense: "
50890Sstevel@tonic-gate 			    "%x %x %x %x %x %x %x %x %x %x\n\t"
50900Sstevel@tonic-gate 			    "%x %x %x %x %x %x %x %x %x %x",
50910Sstevel@tonic-gate 			    cmd->cmd_cdb[0],
50920Sstevel@tonic-gate 			    p[0], p[1], p[2], p[3], p[4],
50930Sstevel@tonic-gate 			    p[5], p[6], p[7], p[8], p[9],
50940Sstevel@tonic-gate 			    p[10], p[11], p[12], p[13], p[14],
50950Sstevel@tonic-gate 			    p[15], p[16], p[17], p[18], p[19]);
50960Sstevel@tonic-gate 
50970Sstevel@tonic-gate 			scsa2usbp->scsa2usb_last_cmd.status = p[2];
50980Sstevel@tonic-gate 			cmd->cmd_done = 1;
50990Sstevel@tonic-gate 			/* FALLTHROUGH */
51000Sstevel@tonic-gate 
51015789Ssl147100 		default:
51020Sstevel@tonic-gate handle_data:
51030Sstevel@tonic-gate 			if (bp && len && (cmd->cmd_dir == USB_EP_DIR_IN)) {
51040Sstevel@tonic-gate 				/*
51050Sstevel@tonic-gate 				 * we don't have to copy the data, the
51060Sstevel@tonic-gate 				 * data pointers for the mblk_t for
51070Sstevel@tonic-gate 				 * the bulk-in xfer points to the
51080Sstevel@tonic-gate 				 * struct buf * data.
51090Sstevel@tonic-gate 				 */
51100Sstevel@tonic-gate 				cmd->cmd_offset += len;
51110Sstevel@tonic-gate 			}
51120Sstevel@tonic-gate 
51130Sstevel@tonic-gate 			USB_DPRINTF_L3(DPRINT_MASK_SCSA,
51140Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
51155789Ssl147100 			    "len = 0x%x total = 0x%lx offset = 0x%lx",
51165789Ssl147100 			    len, cmd->cmd_total_xfercount, cmd->cmd_offset);
51170Sstevel@tonic-gate 
51180Sstevel@tonic-gate 			/*
51190Sstevel@tonic-gate 			 * update total_xfercount now but it may be
51200Sstevel@tonic-gate 			 * adjusted after receiving the residue
51210Sstevel@tonic-gate 			 */
51220Sstevel@tonic-gate 			cmd->cmd_total_xfercount -= len;
51230Sstevel@tonic-gate 
51240Sstevel@tonic-gate 			if ((req->bulk_completion_reason != USB_CR_OK) ||
51250Sstevel@tonic-gate 			    (cmd->cmd_resid_xfercount != 0) ||
51260Sstevel@tonic-gate 			    (cmd->cmd_total_xfercount == 0)) {
51270Sstevel@tonic-gate 				/* set pkt_resid to total to be sure */
51280Sstevel@tonic-gate 				pkt->pkt_resid = cmd->cmd_total_xfercount;
51290Sstevel@tonic-gate 				cmd->cmd_done = 1;
51300Sstevel@tonic-gate 			}
51310Sstevel@tonic-gate 
51320Sstevel@tonic-gate 			break;
51330Sstevel@tonic-gate 		}
51340Sstevel@tonic-gate 	} else {
51350Sstevel@tonic-gate 		if (cmd->cmd_dir == USB_EP_DIR_OUT) {
51360Sstevel@tonic-gate 			if (cmd->cmd_total_xfercount == 0) {
51370Sstevel@tonic-gate 				cmd->cmd_done = 1;
51380Sstevel@tonic-gate 			}
51390Sstevel@tonic-gate 		}
51400Sstevel@tonic-gate 	}
51410Sstevel@tonic-gate }
51420Sstevel@tonic-gate 
51430Sstevel@tonic-gate 
51440Sstevel@tonic-gate /*
51450Sstevel@tonic-gate  * scsa2usb_init_bulk_req:
51460Sstevel@tonic-gate  *	Allocate (synchronously) and fill in a bulk-request
51470Sstevel@tonic-gate  */
51480Sstevel@tonic-gate usb_bulk_req_t *
51490Sstevel@tonic-gate scsa2usb_init_bulk_req(scsa2usb_state_t *scsa2usbp, size_t length,
51500Sstevel@tonic-gate     uint_t timeout, usb_req_attrs_t attrs, usb_flags_t flags)
51510Sstevel@tonic-gate {
51520Sstevel@tonic-gate 	usb_bulk_req_t	*req;
51530Sstevel@tonic-gate 
51540Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
51550Sstevel@tonic-gate 
51560Sstevel@tonic-gate 	req = usb_alloc_bulk_req(scsa2usbp->scsa2usb_dip, length,
51570Sstevel@tonic-gate 	    flags | USB_FLAGS_SLEEP);
51580Sstevel@tonic-gate 
51597492SZhigang.Lu@Sun.COM 	req->bulk_len = (uint_t)length;			/* xfer length */
51600Sstevel@tonic-gate 	req->bulk_timeout = scsa2usb_bulk_timeout(timeout); /* xfer timeout */
51610Sstevel@tonic-gate 	req->bulk_attributes = attrs;		/* xfer attrs */
51620Sstevel@tonic-gate 	req->bulk_client_private = (usb_opaque_t)scsa2usbp; /* statep */
51630Sstevel@tonic-gate 
51640Sstevel@tonic-gate 	return (req);
51650Sstevel@tonic-gate }
51660Sstevel@tonic-gate 
51670Sstevel@tonic-gate 
51680Sstevel@tonic-gate /*
51690Sstevel@tonic-gate  * scsa2usb_bulk_timeout:
51700Sstevel@tonic-gate  *	ensure that bulk requests do not have infinite timeout values
51710Sstevel@tonic-gate  */
51720Sstevel@tonic-gate int
51730Sstevel@tonic-gate scsa2usb_bulk_timeout(int timeout)
51740Sstevel@tonic-gate {
51750Sstevel@tonic-gate 	return ((timeout == 0) ? scsa2usb_long_timeout : timeout);
51760Sstevel@tonic-gate }
51770Sstevel@tonic-gate 
51780Sstevel@tonic-gate 
51790Sstevel@tonic-gate /*
51800Sstevel@tonic-gate  * scsa2usb_clear_ept_stall:
51810Sstevel@tonic-gate  *	clear endpoint stall and reset pipes
51820Sstevel@tonic-gate  */
51830Sstevel@tonic-gate int
51840Sstevel@tonic-gate scsa2usb_clear_ept_stall(scsa2usb_state_t *scsa2usbp, uint_t ept_addr,
51850Sstevel@tonic-gate     usb_pipe_handle_t ph, char *what)
51860Sstevel@tonic-gate {
51870Sstevel@tonic-gate 	int rval;
51880Sstevel@tonic-gate 	dev_info_t *dip = scsa2usbp->scsa2usb_dip;
51890Sstevel@tonic-gate 
51900Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
51910Sstevel@tonic-gate 	if (!(SCSA2USB_DEVICE_ACCESS_OK(scsa2usbp))) {
51920Sstevel@tonic-gate 
51930Sstevel@tonic-gate 		return (USB_FAILURE);
51940Sstevel@tonic-gate 	}
51950Sstevel@tonic-gate 
51960Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
51970Sstevel@tonic-gate 	rval = usb_clr_feature(dip, USB_DEV_REQ_RCPT_EP, 0, ept_addr,
51980Sstevel@tonic-gate 	    USB_FLAGS_SLEEP, NULL, NULL);
51990Sstevel@tonic-gate 
52000Sstevel@tonic-gate 	usb_pipe_reset(dip, ph, USB_FLAGS_SLEEP, NULL, NULL);
52010Sstevel@tonic-gate 
52020Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
52030Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
52040Sstevel@tonic-gate 	    "scsa2usb_clear_ept_stall: on %s: ept = 0x%x rval = %d",
52050Sstevel@tonic-gate 	    what, ept_addr, rval);
52060Sstevel@tonic-gate 
52070Sstevel@tonic-gate 	return (rval);
52080Sstevel@tonic-gate }
52090Sstevel@tonic-gate 
52100Sstevel@tonic-gate 
52110Sstevel@tonic-gate /*
52120Sstevel@tonic-gate  * scsa2usb_pkt_completion:
52130Sstevel@tonic-gate  *	Handle pkt completion.
52140Sstevel@tonic-gate  */
52150Sstevel@tonic-gate static void
52160Sstevel@tonic-gate scsa2usb_pkt_completion(scsa2usb_state_t *scsa2usbp, struct scsi_pkt *pkt)
52170Sstevel@tonic-gate {
52180Sstevel@tonic-gate 	scsa2usb_cmd_t *cmd = PKT2CMD(pkt);
52194700Sfb209375 	size_t len;
52200Sstevel@tonic-gate 
52210Sstevel@tonic-gate 	ASSERT(pkt);
52220Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
52230Sstevel@tonic-gate 
52240Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
52250Sstevel@tonic-gate 	    "scsa2usb_pkt_completion:\n\tscsa2usbp = 0x%p "
52260Sstevel@tonic-gate 	    "reason=%d, status=%d state=0x%x stats=0x%x resid=0x%lx",
52276898Sfb209375 	    (void *)scsa2usbp, pkt->pkt_reason, *(pkt->pkt_scbp),
52280Sstevel@tonic-gate 	    pkt->pkt_state, pkt->pkt_statistics, pkt->pkt_resid);
52290Sstevel@tonic-gate 
52300Sstevel@tonic-gate 	if (pkt->pkt_reason == CMD_CMPLT) {
52310Sstevel@tonic-gate 		pkt->pkt_state |= STATE_GOT_BUS | STATE_GOT_TARGET |
52324700Sfb209375 		    STATE_SENT_CMD | STATE_GOT_STATUS;
52330Sstevel@tonic-gate 		if (cmd->cmd_xfercount) {
52340Sstevel@tonic-gate 			pkt->pkt_state |= STATE_XFERRED_DATA;
52350Sstevel@tonic-gate 		}
52360Sstevel@tonic-gate 	} else {
52370Sstevel@tonic-gate 		pkt->pkt_state |= STATE_GOT_BUS | STATE_GOT_TARGET |
52384700Sfb209375 		    STATE_SENT_CMD;
52390Sstevel@tonic-gate 	}
52400Sstevel@tonic-gate 
52410Sstevel@tonic-gate 	/*
52420Sstevel@tonic-gate 	 * don't zap the current state when in panic as this will
52430Sstevel@tonic-gate 	 * make debugging harder
52440Sstevel@tonic-gate 	 */
52450Sstevel@tonic-gate 	if ((scsa2usbp->scsa2usb_cur_pkt == pkt) && !ddi_in_panic()) {
52460Sstevel@tonic-gate 		SCSA2USB_RESET_CUR_PKT(scsa2usbp);
52470Sstevel@tonic-gate 
52484700Sfb209375 		len = sizeof (scsa2usbp->scsa2usb_last_cmd.cdb);
52494700Sfb209375 		bzero(scsa2usbp->scsa2usb_last_cmd.cdb, len);
52504700Sfb209375 
52514700Sfb209375 		len = (len < cmd->cmd_cdblen) ? len : cmd->cmd_cdblen;
52524700Sfb209375 		USB_DPRINTF_L3(DPRINT_MASK_SCSA,
52534700Sfb209375 		    scsa2usbp->scsa2usb_log_handle,
52546898Sfb209375 		    "scsa2usb_pkt_completion: save last cmd, len=%ld", len);
52554700Sfb209375 
52560Sstevel@tonic-gate 		/* save the last command */
52574700Sfb209375 		bcopy(pkt->pkt_cdbp, scsa2usbp->scsa2usb_last_cmd.cdb, len);
52580Sstevel@tonic-gate 
52590Sstevel@tonic-gate 		/* reset the scsa2usb_last_cmd.status value */
52600Sstevel@tonic-gate 		if ((pkt->pkt_cdbp[0] != SCMD_REQUEST_SENSE) &&
52610Sstevel@tonic-gate 		    (pkt->pkt_cdbp[0] != SCMD_INQUIRY)) {
52620Sstevel@tonic-gate 			scsa2usbp->scsa2usb_last_cmd.status = 0;
52630Sstevel@tonic-gate 		}
52640Sstevel@tonic-gate 
52650Sstevel@tonic-gate 		/*
52660Sstevel@tonic-gate 		 * set pkt state to NONE *before* calling back as the target
52670Sstevel@tonic-gate 		 * driver will immediately submit the next packet
52680Sstevel@tonic-gate 		 */
52690Sstevel@tonic-gate 		scsa2usbp->scsa2usb_pkt_state = SCSA2USB_PKT_NONE;
52700Sstevel@tonic-gate 	}
52710Sstevel@tonic-gate 
52720Sstevel@tonic-gate 	if (pkt->pkt_comp) {
52730Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
52749106SSrivijitha.Dugganapalli@Sun.COM 		scsi_hba_pkt_comp(pkt);
52750Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
52760Sstevel@tonic-gate 
52770Sstevel@tonic-gate 	}
52780Sstevel@tonic-gate }
52790Sstevel@tonic-gate 
52800Sstevel@tonic-gate 
52810Sstevel@tonic-gate /*
52820Sstevel@tonic-gate  * Even handling functions:
52830Sstevel@tonic-gate  *
52840Sstevel@tonic-gate  * scsa2usb_reconnect_event_cb:
52850Sstevel@tonic-gate  *	event handling
52860Sstevel@tonic-gate  */
52870Sstevel@tonic-gate static int
52880Sstevel@tonic-gate scsa2usb_reconnect_event_cb(dev_info_t *dip)
52890Sstevel@tonic-gate {
52900Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp =
52910Sstevel@tonic-gate 	    ddi_get_soft_state(scsa2usb_statep, ddi_get_instance(dip));
52920Sstevel@tonic-gate 	dev_info_t	*cdip;
52930Sstevel@tonic-gate 	int		circ;
52940Sstevel@tonic-gate 	int		rval = USB_SUCCESS;
52950Sstevel@tonic-gate 
52960Sstevel@tonic-gate 	ASSERT(scsa2usbp != NULL);
52970Sstevel@tonic-gate 
52980Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
52996898Sfb209375 	    "scsa2usb_reconnect_event_cb: dip = 0x%p", (void *)dip);
53000Sstevel@tonic-gate 
53010Sstevel@tonic-gate 	scsa2usb_restore_device_state(dip, scsa2usbp);
53020Sstevel@tonic-gate 
5303880Sfrits 	USB_DPRINTF_L0(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
5304880Sfrits 	    "Reinserted device is accessible again.");
5305880Sfrits 
53060Sstevel@tonic-gate 	ndi_devi_enter(dip, &circ);
53070Sstevel@tonic-gate 	for (cdip = ddi_get_child(dip); cdip; ) {
53080Sstevel@tonic-gate 		dev_info_t *next = ddi_get_next_sibling(cdip);
53090Sstevel@tonic-gate 
53100Sstevel@tonic-gate 		mutex_enter(&DEVI(cdip)->devi_lock);
53110Sstevel@tonic-gate 		DEVI_SET_DEVICE_REINSERTED(cdip);
53120Sstevel@tonic-gate 		mutex_exit(&DEVI(cdip)->devi_lock);
53130Sstevel@tonic-gate 
53140Sstevel@tonic-gate 		cdip = next;
53150Sstevel@tonic-gate 	}
53160Sstevel@tonic-gate 	ndi_devi_exit(dip, circ);
53170Sstevel@tonic-gate 
53180Sstevel@tonic-gate 	/* stop suppressing warnings */
53190Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
53200Sstevel@tonic-gate 	scsa2usbp->scsa2usb_warning_given = B_FALSE;
53210Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
53220Sstevel@tonic-gate 
53230Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_ugen_hdl) {
53240Sstevel@tonic-gate 		rval = usb_ugen_reconnect_ev_cb(
53254700Sfb209375 		    scsa2usbp->scsa2usb_ugen_hdl);
53260Sstevel@tonic-gate 	}
53270Sstevel@tonic-gate 
53280Sstevel@tonic-gate 	return (rval);
53290Sstevel@tonic-gate }
53300Sstevel@tonic-gate 
53310Sstevel@tonic-gate 
53320Sstevel@tonic-gate /*
53330Sstevel@tonic-gate  * scsa2usb_all_waitQs_empty:
53340Sstevel@tonic-gate  *	check if all waitQs empty
53350Sstevel@tonic-gate  */
53360Sstevel@tonic-gate static int
53370Sstevel@tonic-gate scsa2usb_all_waitQs_empty(scsa2usb_state_t *scsa2usbp)
53380Sstevel@tonic-gate {
53390Sstevel@tonic-gate 	uint_t	lun;
53400Sstevel@tonic-gate 
53410Sstevel@tonic-gate 	for (lun = 0; lun < SCSA2USB_MAX_LUNS; lun++) {
53420Sstevel@tonic-gate 		if (usba_list_entry_count(
53430Sstevel@tonic-gate 		    &scsa2usbp->scsa2usb_waitQ[lun])) {
53440Sstevel@tonic-gate 
53450Sstevel@tonic-gate 			return (USB_FAILURE);
53460Sstevel@tonic-gate 		}
53470Sstevel@tonic-gate 	}
53480Sstevel@tonic-gate 
53490Sstevel@tonic-gate 	return (USB_SUCCESS);
53500Sstevel@tonic-gate }
53510Sstevel@tonic-gate 
53520Sstevel@tonic-gate 
53530Sstevel@tonic-gate /*
53540Sstevel@tonic-gate  * scsa2usb_disconnect_event_cb:
53550Sstevel@tonic-gate  *	callback for disconnect events
53560Sstevel@tonic-gate  */
53570Sstevel@tonic-gate static int
53580Sstevel@tonic-gate scsa2usb_disconnect_event_cb(dev_info_t *dip)
53590Sstevel@tonic-gate {
53600Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp =
53610Sstevel@tonic-gate 	    ddi_get_soft_state(scsa2usb_statep, ddi_get_instance(dip));
53620Sstevel@tonic-gate 	dev_info_t	*cdip;
53630Sstevel@tonic-gate 	int		circ, i;
53640Sstevel@tonic-gate 	int		rval = USB_SUCCESS;
53650Sstevel@tonic-gate 
53660Sstevel@tonic-gate 	ASSERT(scsa2usbp != NULL);
53670Sstevel@tonic-gate 
53680Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
53696898Sfb209375 	    "scsa2usb_disconnect_event_cb: dip = 0x%p", (void *)dip);
53700Sstevel@tonic-gate 
53710Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
53720Sstevel@tonic-gate 	scsa2usbp->scsa2usb_dev_state = USB_DEV_DISCONNECTED;
53730Sstevel@tonic-gate 
53740Sstevel@tonic-gate 	/*
53750Sstevel@tonic-gate 	 * wait till the work thread is done, carry on regardless
53760Sstevel@tonic-gate 	 * if not.
53770Sstevel@tonic-gate 	 */
53780Sstevel@tonic-gate 	for (i = 0; i < SCSA2USB_DRAIN_TIMEOUT; i++) {
53790Sstevel@tonic-gate 		if ((scsa2usbp->scsa2usb_work_thread_id == NULL) &&
53800Sstevel@tonic-gate 		    (scsa2usbp->scsa2usb_cur_pkt == NULL) &&
53810Sstevel@tonic-gate 		    (scsa2usb_all_waitQs_empty(scsa2usbp) ==
53820Sstevel@tonic-gate 		    USB_SUCCESS)) {
53830Sstevel@tonic-gate 
53840Sstevel@tonic-gate 			break;
53850Sstevel@tonic-gate 		}
53860Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
53870Sstevel@tonic-gate 		delay(drv_usectohz(1000000));
53880Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
53890Sstevel@tonic-gate 	}
53900Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
53910Sstevel@tonic-gate 
53920Sstevel@tonic-gate 	ndi_devi_enter(dip, &circ);
53930Sstevel@tonic-gate 	for (cdip = ddi_get_child(dip); cdip; ) {
53940Sstevel@tonic-gate 		dev_info_t *next = ddi_get_next_sibling(cdip);
53950Sstevel@tonic-gate 
53960Sstevel@tonic-gate 		mutex_enter(&DEVI(cdip)->devi_lock);
53970Sstevel@tonic-gate 		DEVI_SET_DEVICE_REMOVED(cdip);
53980Sstevel@tonic-gate 		mutex_exit(&DEVI(cdip)->devi_lock);
53990Sstevel@tonic-gate 
54000Sstevel@tonic-gate 		cdip = next;
54010Sstevel@tonic-gate 	}
54020Sstevel@tonic-gate 	ndi_devi_exit(dip, circ);
54030Sstevel@tonic-gate 
54040Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_ugen_hdl) {
54050Sstevel@tonic-gate 		rval = usb_ugen_disconnect_ev_cb(
54064700Sfb209375 		    scsa2usbp->scsa2usb_ugen_hdl);
54070Sstevel@tonic-gate 	}
54080Sstevel@tonic-gate 
54090Sstevel@tonic-gate 	return (rval);
54100Sstevel@tonic-gate }
54110Sstevel@tonic-gate 
54120Sstevel@tonic-gate 
54130Sstevel@tonic-gate /*
54140Sstevel@tonic-gate  * PM support
54150Sstevel@tonic-gate  *
54160Sstevel@tonic-gate  * scsa2usb_create_pm_components:
54170Sstevel@tonic-gate  *	create the pm components required for power management
54180Sstevel@tonic-gate  *	no mutex is need when calling USBA interfaces
54190Sstevel@tonic-gate  */
54200Sstevel@tonic-gate static void
54210Sstevel@tonic-gate scsa2usb_create_pm_components(dev_info_t *dip, scsa2usb_state_t *scsa2usbp)
54220Sstevel@tonic-gate {
54230Sstevel@tonic-gate 	scsa2usb_power_t *pm;
54240Sstevel@tonic-gate 	uint_t		pwr_states;
54250Sstevel@tonic-gate 
54260Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
54270Sstevel@tonic-gate 
54280Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_PM, scsa2usbp->scsa2usb_log_handle,
54290Sstevel@tonic-gate 	    "scsa2usb_create_pm_components: dip = 0x%p, scsa2usbp = 0x%p",
54306898Sfb209375 	    (void *)dip, (void *)scsa2usbp);
54310Sstevel@tonic-gate 
54320Sstevel@tonic-gate 	/*
54330Sstevel@tonic-gate 	 * determine if this device is on the blacklist
54340Sstevel@tonic-gate 	 * or if a conf file entry has disabled PM
54350Sstevel@tonic-gate 	 */
54360Sstevel@tonic-gate 	if ((scsa2usbp->scsa2usb_attrs & SCSA2USB_ATTRS_PM) == 0) {
54370Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_PM, scsa2usbp->scsa2usb_log_handle,
54380Sstevel@tonic-gate 		    "device cannot be power managed");
54390Sstevel@tonic-gate 
54400Sstevel@tonic-gate 		return;
54410Sstevel@tonic-gate 	}
54420Sstevel@tonic-gate 
54430Sstevel@tonic-gate 	/* Allocate the PM state structure */
54440Sstevel@tonic-gate 	pm = kmem_zalloc(sizeof (scsa2usb_power_t), KM_SLEEP);
54450Sstevel@tonic-gate 
54460Sstevel@tonic-gate 	scsa2usbp->scsa2usb_pm = pm;
54470Sstevel@tonic-gate 	pm->scsa2usb_current_power = USB_DEV_OS_FULL_PWR;
54480Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
54490Sstevel@tonic-gate 
54500Sstevel@tonic-gate 	if (usb_create_pm_components(dip, &pwr_states) ==
54510Sstevel@tonic-gate 	    USB_SUCCESS) {
54520Sstevel@tonic-gate 		if (usb_handle_remote_wakeup(dip,
54530Sstevel@tonic-gate 		    USB_REMOTE_WAKEUP_ENABLE) == USB_SUCCESS) {
54540Sstevel@tonic-gate 			pm->scsa2usb_wakeup_enabled = 1;
54550Sstevel@tonic-gate 		}
54560Sstevel@tonic-gate 
54570Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
54580Sstevel@tonic-gate 		pm->scsa2usb_pwr_states = (uint8_t)pwr_states;
5459189Sfrits 		scsa2usb_raise_power(scsa2usbp);
54600Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
54610Sstevel@tonic-gate 	}
54620Sstevel@tonic-gate 
54630Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
54640Sstevel@tonic-gate }
54650Sstevel@tonic-gate 
54660Sstevel@tonic-gate 
54670Sstevel@tonic-gate /*
54680Sstevel@tonic-gate  * scsa2usb_raise_power:
54690Sstevel@tonic-gate  *	check if the device is using full power or not
54700Sstevel@tonic-gate  */
54710Sstevel@tonic-gate static void
54720Sstevel@tonic-gate scsa2usb_raise_power(scsa2usb_state_t *scsa2usbp)
54730Sstevel@tonic-gate {
54740Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_PM, scsa2usbp->scsa2usb_log_handle,
54750Sstevel@tonic-gate 	    "scsa2usb_raise_power:");
54760Sstevel@tonic-gate 
54770Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
54780Sstevel@tonic-gate 
54790Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_pm) {
54800Sstevel@tonic-gate 		scsa2usb_pm_busy_component(scsa2usbp);
5481189Sfrits 		if (scsa2usbp->scsa2usb_pm->scsa2usb_current_power !=
5482189Sfrits 		    USB_DEV_OS_FULL_PWR) {
54830Sstevel@tonic-gate 			mutex_exit(&scsa2usbp->scsa2usb_mutex);
54840Sstevel@tonic-gate 			(void) pm_raise_power(scsa2usbp->scsa2usb_dip,
54850Sstevel@tonic-gate 			    0, USB_DEV_OS_FULL_PWR);
54860Sstevel@tonic-gate 			mutex_enter(&scsa2usbp->scsa2usb_mutex);
54870Sstevel@tonic-gate 		}
54880Sstevel@tonic-gate 	}
54890Sstevel@tonic-gate }
54900Sstevel@tonic-gate 
54910Sstevel@tonic-gate 
54920Sstevel@tonic-gate /*
54930Sstevel@tonic-gate  * functions to handle power transition for OS levels 0 -> 3
54940Sstevel@tonic-gate  */
54950Sstevel@tonic-gate static int
54960Sstevel@tonic-gate scsa2usb_pwrlvl0(scsa2usb_state_t *scsa2usbp)
54970Sstevel@tonic-gate {
54980Sstevel@tonic-gate 	int	rval;
54990Sstevel@tonic-gate 
55000Sstevel@tonic-gate 	switch (scsa2usbp->scsa2usb_dev_state) {
55010Sstevel@tonic-gate 	case USB_DEV_ONLINE:
55020Sstevel@tonic-gate 		/* Deny the powerdown request if the device is busy */
55030Sstevel@tonic-gate 		if (scsa2usbp->scsa2usb_pm->scsa2usb_pm_busy != 0) {
55040Sstevel@tonic-gate 
55050Sstevel@tonic-gate 			return (USB_FAILURE);
55060Sstevel@tonic-gate 		}
55070Sstevel@tonic-gate 
55080Sstevel@tonic-gate 		/*
55090Sstevel@tonic-gate 		 * stop polling on interrupt pipe
55100Sstevel@tonic-gate 		 */
55110Sstevel@tonic-gate 		scsa2usb_cbi_stop_intr_polling(scsa2usbp);
55120Sstevel@tonic-gate 
55130Sstevel@tonic-gate 		/* Issue USB D3 command to the device here */
55140Sstevel@tonic-gate 		rval = usb_set_device_pwrlvl3(scsa2usbp->scsa2usb_dip);
55150Sstevel@tonic-gate 		ASSERT(rval == USB_SUCCESS);
55160Sstevel@tonic-gate 
55170Sstevel@tonic-gate 		scsa2usbp->scsa2usb_dev_state = USB_DEV_PWRED_DOWN;
55180Sstevel@tonic-gate 
55190Sstevel@tonic-gate 		/* FALLTHRU */
55200Sstevel@tonic-gate 	case USB_DEV_DISCONNECTED:
55210Sstevel@tonic-gate 	case USB_DEV_SUSPENDED:
55220Sstevel@tonic-gate 	case USB_DEV_PWRED_DOWN:
55230Sstevel@tonic-gate 	default:
55240Sstevel@tonic-gate 		scsa2usbp->scsa2usb_pm->scsa2usb_current_power =
55254700Sfb209375 		    USB_DEV_OS_PWR_OFF;
55260Sstevel@tonic-gate 
55270Sstevel@tonic-gate 		return (USB_SUCCESS);
55280Sstevel@tonic-gate 	}
55290Sstevel@tonic-gate }
55300Sstevel@tonic-gate 
55310Sstevel@tonic-gate 
55320Sstevel@tonic-gate static int
55330Sstevel@tonic-gate scsa2usb_pwrlvl1(scsa2usb_state_t *scsa2usbp)
55340Sstevel@tonic-gate {
55350Sstevel@tonic-gate 	int	rval;
55360Sstevel@tonic-gate 
55370Sstevel@tonic-gate 	/* Issue USB D2 command to the device here */
55380Sstevel@tonic-gate 	rval = usb_set_device_pwrlvl2(scsa2usbp->scsa2usb_dip);
55390Sstevel@tonic-gate 	ASSERT(rval == USB_SUCCESS);
55400Sstevel@tonic-gate 
55410Sstevel@tonic-gate 	return (DDI_FAILURE);
55420Sstevel@tonic-gate }
55430Sstevel@tonic-gate 
55440Sstevel@tonic-gate 
55450Sstevel@tonic-gate static int
55460Sstevel@tonic-gate scsa2usb_pwrlvl2(scsa2usb_state_t *scsa2usbp)
55470Sstevel@tonic-gate {
55480Sstevel@tonic-gate 	int	rval;
55490Sstevel@tonic-gate 
55500Sstevel@tonic-gate 	/* Issue USB D1 command to the device here */
55510Sstevel@tonic-gate 	rval = usb_set_device_pwrlvl1(scsa2usbp->scsa2usb_dip);
55520Sstevel@tonic-gate 	ASSERT(rval == USB_SUCCESS);
55530Sstevel@tonic-gate 
55540Sstevel@tonic-gate 	return (DDI_FAILURE);
55550Sstevel@tonic-gate }
55560Sstevel@tonic-gate 
55570Sstevel@tonic-gate 
55580Sstevel@tonic-gate static int
55590Sstevel@tonic-gate scsa2usb_pwrlvl3(scsa2usb_state_t *scsa2usbp)
55600Sstevel@tonic-gate {
55610Sstevel@tonic-gate 	int	rval;
55620Sstevel@tonic-gate 
55630Sstevel@tonic-gate 	/*
55640Sstevel@tonic-gate 	 * PM framework tries to put us in full power
55650Sstevel@tonic-gate 	 * during system shutdown. If we are disconnected
55660Sstevel@tonic-gate 	 * return success anyways
55670Sstevel@tonic-gate 	 */
55680Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_dev_state != USB_DEV_DISCONNECTED) {
55690Sstevel@tonic-gate 		/* Issue USB D0 command to the device here */
55700Sstevel@tonic-gate 		rval = usb_set_device_pwrlvl0(scsa2usbp->scsa2usb_dip);
55710Sstevel@tonic-gate 		ASSERT(rval == USB_SUCCESS);
55720Sstevel@tonic-gate 
55730Sstevel@tonic-gate 		scsa2usbp->scsa2usb_dev_state = USB_DEV_ONLINE;
55740Sstevel@tonic-gate 	}
55750Sstevel@tonic-gate 	scsa2usbp->scsa2usb_pm->scsa2usb_current_power = USB_DEV_OS_FULL_PWR;
55760Sstevel@tonic-gate 
55770Sstevel@tonic-gate 	return (DDI_SUCCESS);
55780Sstevel@tonic-gate }
55790Sstevel@tonic-gate 
55800Sstevel@tonic-gate 
55810Sstevel@tonic-gate /*
55820Sstevel@tonic-gate  * scsa2usb_power:
55830Sstevel@tonic-gate  *	power entry point
55840Sstevel@tonic-gate  */
55850Sstevel@tonic-gate /* ARGSUSED */
55860Sstevel@tonic-gate static int
55870Sstevel@tonic-gate scsa2usb_power(dev_info_t *dip, int comp, int level)
55880Sstevel@tonic-gate {
55890Sstevel@tonic-gate 	scsa2usb_state_t	*scsa2usbp;
55900Sstevel@tonic-gate 	scsa2usb_power_t	*pm;
55910Sstevel@tonic-gate 	int			rval = DDI_FAILURE;
55920Sstevel@tonic-gate 
55930Sstevel@tonic-gate 	scsa2usbp = ddi_get_soft_state(scsa2usb_statep, ddi_get_instance(dip));
55940Sstevel@tonic-gate 
55950Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_PM, scsa2usbp->scsa2usb_log_handle,
55960Sstevel@tonic-gate 	    "scsa2usb_power: Begin scsa2usbp (%p): level = %d",
55976898Sfb209375 	    (void *)scsa2usbp, level);
55980Sstevel@tonic-gate 
55990Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
56000Sstevel@tonic-gate 	if (SCSA2USB_BUSY(scsa2usbp)) {
56010Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_PM, scsa2usbp->scsa2usb_log_handle,
56020Sstevel@tonic-gate 		    "scsa2usb_power: busy");
56030Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
56040Sstevel@tonic-gate 
56050Sstevel@tonic-gate 		return (rval);
56060Sstevel@tonic-gate 	}
56070Sstevel@tonic-gate 
56080Sstevel@tonic-gate 	pm = scsa2usbp->scsa2usb_pm;
56090Sstevel@tonic-gate 	if (pm == NULL) {
56100Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_PM, scsa2usbp->scsa2usb_log_handle,
56110Sstevel@tonic-gate 		    "scsa2usb_power: pm NULL");
56120Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
56130Sstevel@tonic-gate 
56140Sstevel@tonic-gate 		return (rval);
56150Sstevel@tonic-gate 	}
56160Sstevel@tonic-gate 
56170Sstevel@tonic-gate 	/* check if we are transitioning to a legal power level */
56180Sstevel@tonic-gate 	if (USB_DEV_PWRSTATE_OK(pm->scsa2usb_pwr_states, level)) {
56190Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_PM, scsa2usbp->scsa2usb_log_handle,
56200Sstevel@tonic-gate 		    "scsa2usb_power: illegal power level = %d "
56210Sstevel@tonic-gate 		    "pwr_states: %x", level, pm->scsa2usb_pwr_states);
56220Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
56230Sstevel@tonic-gate 
56240Sstevel@tonic-gate 		return (rval);
56250Sstevel@tonic-gate 	}
56260Sstevel@tonic-gate 
56270Sstevel@tonic-gate 	switch (level) {
56280Sstevel@tonic-gate 	case USB_DEV_OS_PWR_OFF :
56290Sstevel@tonic-gate 		rval = scsa2usb_pwrlvl0(scsa2usbp);
56300Sstevel@tonic-gate 		break;
56310Sstevel@tonic-gate 	case USB_DEV_OS_PWR_1 :
56320Sstevel@tonic-gate 		rval = scsa2usb_pwrlvl1(scsa2usbp);
56330Sstevel@tonic-gate 		break;
56340Sstevel@tonic-gate 	case USB_DEV_OS_PWR_2 :
56350Sstevel@tonic-gate 		rval = scsa2usb_pwrlvl2(scsa2usbp);
56360Sstevel@tonic-gate 		break;
56370Sstevel@tonic-gate 	case USB_DEV_OS_FULL_PWR :
56380Sstevel@tonic-gate 		rval = scsa2usb_pwrlvl3(scsa2usbp);
56390Sstevel@tonic-gate 		break;
56400Sstevel@tonic-gate 	}
56410Sstevel@tonic-gate 
56420Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
56430Sstevel@tonic-gate 
56440Sstevel@tonic-gate 	return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
56450Sstevel@tonic-gate }
56460Sstevel@tonic-gate 
56470Sstevel@tonic-gate 
56480Sstevel@tonic-gate static void
5649189Sfrits scsa2usb_pm_busy_component(scsa2usb_state_t *scsa2usbp)
56500Sstevel@tonic-gate {
5651189Sfrits 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
5652189Sfrits 
5653189Sfrits 	if (scsa2usbp->scsa2usb_pm) {
5654189Sfrits 		scsa2usbp->scsa2usb_pm->scsa2usb_pm_busy++;
5655189Sfrits 
5656189Sfrits 		USB_DPRINTF_L4(DPRINT_MASK_PM,
5657189Sfrits 		    scsa2usbp->scsa2usb_log_handle,
5658189Sfrits 		    "scsa2usb_pm_busy_component: %d",
5659189Sfrits 		    scsa2usbp->scsa2usb_pm->scsa2usb_pm_busy);
5660189Sfrits 
5661189Sfrits 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
5662189Sfrits 
5663189Sfrits 		if (pm_busy_component(scsa2usbp->scsa2usb_dip, 0) !=
5664189Sfrits 		    DDI_SUCCESS) {
5665189Sfrits 			mutex_enter(&scsa2usbp->scsa2usb_mutex);
5666189Sfrits 			ASSERT(scsa2usbp->scsa2usb_pm->scsa2usb_pm_busy > 0);
5667189Sfrits 			scsa2usbp->scsa2usb_pm->scsa2usb_pm_busy--;
5668189Sfrits 
5669189Sfrits 			USB_DPRINTF_L2(DPRINT_MASK_PM,
5670189Sfrits 			    scsa2usbp->scsa2usb_log_handle,
5671189Sfrits 			    "scsa2usb_pm_busy_component failed: %d",
5672189Sfrits 			    scsa2usbp->scsa2usb_pm->scsa2usb_pm_busy);
5673189Sfrits 
5674189Sfrits 			return;
5675189Sfrits 		}
5676189Sfrits 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
56770Sstevel@tonic-gate 	}
56780Sstevel@tonic-gate }
56790Sstevel@tonic-gate 
56800Sstevel@tonic-gate 
56810Sstevel@tonic-gate /*
56820Sstevel@tonic-gate  * scsa2usb_pm_idle_component:
56830Sstevel@tonic-gate  *	idles the device
56840Sstevel@tonic-gate  */
56850Sstevel@tonic-gate static void
56860Sstevel@tonic-gate scsa2usb_pm_idle_component(scsa2usb_state_t *scsa2usbp)
56870Sstevel@tonic-gate {
5688189Sfrits 	ASSERT(!mutex_owned(&scsa2usbp->scsa2usb_mutex));
5689189Sfrits 
56900Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_pm) {
56910Sstevel@tonic-gate 		if (pm_idle_component(scsa2usbp->scsa2usb_dip, 0) ==
56920Sstevel@tonic-gate 		    DDI_SUCCESS) {
56930Sstevel@tonic-gate 			mutex_enter(&scsa2usbp->scsa2usb_mutex);
56940Sstevel@tonic-gate 			ASSERT(scsa2usbp->scsa2usb_pm->scsa2usb_pm_busy > 0);
56950Sstevel@tonic-gate 			scsa2usbp->scsa2usb_pm->scsa2usb_pm_busy--;
5696189Sfrits 
5697189Sfrits 			USB_DPRINTF_L4(DPRINT_MASK_PM,
5698189Sfrits 			    scsa2usbp->scsa2usb_log_handle,
5699189Sfrits 			    "scsa2usb_pm_idle_component: %d",
5700189Sfrits 			    scsa2usbp->scsa2usb_pm->scsa2usb_pm_busy);
5701189Sfrits 
57020Sstevel@tonic-gate 			mutex_exit(&scsa2usbp->scsa2usb_mutex);
57030Sstevel@tonic-gate 		}
57040Sstevel@tonic-gate 	}
57050Sstevel@tonic-gate }
57060Sstevel@tonic-gate 
57070Sstevel@tonic-gate 
57080Sstevel@tonic-gate #ifdef	DEBUG
57090Sstevel@tonic-gate /*
57100Sstevel@tonic-gate  * scsa2usb_print_cdb:
57110Sstevel@tonic-gate  *	prints CDB
57120Sstevel@tonic-gate  */
57130Sstevel@tonic-gate void
57140Sstevel@tonic-gate scsa2usb_print_cdb(scsa2usb_state_t *scsa2usbp, scsa2usb_cmd_t *cmd)
57150Sstevel@tonic-gate {
57160Sstevel@tonic-gate 	uchar_t *c = (uchar_t *)&cmd->cmd_cdb;
57170Sstevel@tonic-gate 
57180Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
57190Sstevel@tonic-gate 	    "cmd = 0x%p opcode=%s "
57200Sstevel@tonic-gate 	    "cdb: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x",
57216898Sfb209375 	    (void *)cmd,
57226898Sfb209375 	    scsi_cname(cmd->cmd_cdb[SCSA2USB_OPCODE], scsa2usb_cmds),
57230Sstevel@tonic-gate 	    c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7], c[8],
57240Sstevel@tonic-gate 	    c[9], c[10], c[11], c[12], c[13], c[14], c[15]);
57250Sstevel@tonic-gate }
57260Sstevel@tonic-gate #endif	/* DEBUG */
57270Sstevel@tonic-gate 
57280Sstevel@tonic-gate 
57290Sstevel@tonic-gate #ifdef	SCSA2USB_BULK_ONLY_TEST
57300Sstevel@tonic-gate /*
57310Sstevel@tonic-gate  * scsa2usb_test_mblk:
57320Sstevel@tonic-gate  *	This function sends a dummy data mblk_t to simulate
57330Sstevel@tonic-gate  *	the following test cases: 5 and 11.
57340Sstevel@tonic-gate  */
57350Sstevel@tonic-gate static void
57360Sstevel@tonic-gate scsa2usb_test_mblk(scsa2usb_state_t *scsa2usbp, boolean_t large)
57370Sstevel@tonic-gate {
57380Sstevel@tonic-gate 	int			i, rval;
57390Sstevel@tonic-gate 	size_t			len;
57400Sstevel@tonic-gate 	usb_flags_t		flags = USB_FLAGS_SLEEP;
57410Sstevel@tonic-gate 	usb_bulk_req_t		*req;
57420Sstevel@tonic-gate 
57430Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
57440Sstevel@tonic-gate 
57450Sstevel@tonic-gate 	/* should we create a larger mblk? */
57460Sstevel@tonic-gate 	len = (large == B_TRUE) ? DEV_BSIZE : USB_BULK_CBWCMD_LEN;
57470Sstevel@tonic-gate 
57480Sstevel@tonic-gate 	req = scsa2usb_init_bulk_req(scsa2usbp, len,
57494700Sfb209375 	    SCSA2USB_BULK_PIPE_TIMEOUT, 0, flags);
57500Sstevel@tonic-gate 
57510Sstevel@tonic-gate 	/* fill up the data mblk */
57520Sstevel@tonic-gate 	for (i = 0; i < len; i++) {
57530Sstevel@tonic-gate 		*req->bulk_data->b_wptr++ = (uchar_t)i;
57540Sstevel@tonic-gate 	}
57550Sstevel@tonic-gate 
57560Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
57570Sstevel@tonic-gate 	ASSERT(req->bulk_timeout);
57580Sstevel@tonic-gate 	rval = usb_pipe_bulk_xfer(scsa2usbp->scsa2usb_bulkout_pipe, req, flags);
57590Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
57600Sstevel@tonic-gate 
57610Sstevel@tonic-gate 	USB_DPRINTF_L1(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
57620Sstevel@tonic-gate 	    "scsa2usb_test_mblk: Sent Data Out rval = 0x%x", rval);
57630Sstevel@tonic-gate 
57640Sstevel@tonic-gate 	usb_free_bulk_req(req);
57650Sstevel@tonic-gate }
57660Sstevel@tonic-gate #endif	/* SCSA2USB_BULK_ONLY_TEST */
5767