17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5910cba4fScg  * Common Development and Distribution License (the "License").
6910cba4fScg  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
2242cac157SVincent Wang  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
24993e3fafSRobert Mustacchi  *
25993e3fafSRobert Mustacchi  * Copyright 2016 Joyent, Inc.
2648bbca81SDaniel Hoffman  * Copyright (c) 2016 by Delphix. All rights reserved.
2710b633f4SJoshua M. Clulow  * Copyright 2019 Joshua M. Clulow <josh@sysmgr.org>
2829219719SEnyew Tan  * Copyright 2022 Tintri by DDN, Inc. All rights reserved.
29*3fe80ca4SDan Cross  * Copyright 2023 Oxide Computer Company
307c478bd9Sstevel@tonic-gate  */
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate /*
347c478bd9Sstevel@tonic-gate  * scsa2usb bridge nexus driver:
357c478bd9Sstevel@tonic-gate  *
367c478bd9Sstevel@tonic-gate  * This driver supports the following wire transports:
377c478bd9Sstevel@tonic-gate  * a. Bulk Only transport (see usb_ms_bulkonly.c)
387c478bd9Sstevel@tonic-gate  * b. CB transport (see usb_ms_cbi.c)
397c478bd9Sstevel@tonic-gate  * c. CBI transport with interrupt status completion (see usb_ms_cbi.c)
407c478bd9Sstevel@tonic-gate  *
417c478bd9Sstevel@tonic-gate  * It handles the following command sets:
427c478bd9Sstevel@tonic-gate  * a. SCSI
437c478bd9Sstevel@tonic-gate  * b. ATAPI command set (subset of SCSI command set)
447c478bd9Sstevel@tonic-gate  * c. UFI command set (
457c478bd9Sstevel@tonic-gate  *	http://www.usb.org/developers/devclass_docs/usbmass-ufi10.pdf)
467c478bd9Sstevel@tonic-gate  *
477c478bd9Sstevel@tonic-gate  * For details on USB Mass Storage Class overview:
487c478bd9Sstevel@tonic-gate  *	http://www.usb.org/developers/devclass_docs/usbmassover_11.pdf
497c478bd9Sstevel@tonic-gate  */
507c478bd9Sstevel@tonic-gate #if defined(lint) && !defined(DEBUG)
517c478bd9Sstevel@tonic-gate #define	DEBUG	1
527c478bd9Sstevel@tonic-gate #endif
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate #include <sys/usb/usba/usbai_version.h>
557c478bd9Sstevel@tonic-gate #include <sys/scsi/scsi.h>
567c478bd9Sstevel@tonic-gate #include <sys/cdio.h>
577c478bd9Sstevel@tonic-gate #include <sys/sunndi.h>
587c478bd9Sstevel@tonic-gate #include <sys/esunddi.h>
597c478bd9Sstevel@tonic-gate #include <sys/callb.h>
607c478bd9Sstevel@tonic-gate #include <sys/kobj.h>
617c478bd9Sstevel@tonic-gate #include <sys/kobj_lex.h>
627c478bd9Sstevel@tonic-gate #include <sys/strsubr.h>
63d29f5a71Szhigang lu - Sun Microsystems - Beijing China #include <sys/strsun.h>
647c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate #include <sys/usb/usba.h>
6742cac157SVincent Wang #include <sys/usb/clients/ugen/usb_ugen.h>
687c478bd9Sstevel@tonic-gate #include <sys/usb/usba/usba_ugen.h>
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate #include <sys/usb/usba/usba_private.h>
7142cac157SVincent Wang #include <sys/usb/usba/usba_ugend.h>
727c478bd9Sstevel@tonic-gate #include <sys/usb/clients/mass_storage/usb_bulkonly.h>
737c478bd9Sstevel@tonic-gate #include <sys/usb/scsa2usb/scsa2usb.h>
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate /*
767c478bd9Sstevel@tonic-gate  * Function Prototypes
777c478bd9Sstevel@tonic-gate  */
787c478bd9Sstevel@tonic-gate static int	scsa2usb_attach(dev_info_t *, ddi_attach_cmd_t);
797c478bd9Sstevel@tonic-gate static int	scsa2usb_info(dev_info_t *, ddi_info_cmd_t, void *,
807c478bd9Sstevel@tonic-gate 						void **);
817c478bd9Sstevel@tonic-gate static int	scsa2usb_detach(dev_info_t *, ddi_detach_cmd_t);
827c478bd9Sstevel@tonic-gate static int	scsa2usb_cleanup(dev_info_t *, scsa2usb_state_t *);
8347b9747fSJoshua M. Clulow static void	scsa2usb_detect_quirks(scsa2usb_state_t *);
847c478bd9Sstevel@tonic-gate static void	scsa2usb_create_luns(scsa2usb_state_t *);
857c478bd9Sstevel@tonic-gate static int	scsa2usb_is_usb(dev_info_t *);
863fbe3e28Svitezslav batrla - Sun Microsystems - Prague Czech Republic static void	scsa2usb_fake_inquiry(scsa2usb_state_t *,
873fbe3e28Svitezslav batrla - Sun Microsystems - Prague Czech Republic 		    struct scsi_inquiry *);
887c478bd9Sstevel@tonic-gate static void	scsa2usb_do_inquiry(scsa2usb_state_t *,
897c478bd9Sstevel@tonic-gate 						uint_t, uint_t);
90df4cb6e0Ssl static int	scsa2usb_do_tur(scsa2usb_state_t *, struct scsi_address *);
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate /* override property handling */
937c478bd9Sstevel@tonic-gate static void	scsa2usb_override(scsa2usb_state_t *);
947c478bd9Sstevel@tonic-gate static int	scsa2usb_parse_input_str(char *, scsa2usb_ov_t *,
957c478bd9Sstevel@tonic-gate 		    scsa2usb_state_t *);
967c478bd9Sstevel@tonic-gate static void	scsa2usb_override_error(char *, scsa2usb_state_t *);
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate /* PANIC callback handling */
1007c478bd9Sstevel@tonic-gate static void	scsa2usb_panic_callb_init(scsa2usb_state_t *);
1017c478bd9Sstevel@tonic-gate static void	scsa2usb_panic_callb_fini(scsa2usb_state_t *);
1027c478bd9Sstevel@tonic-gate static boolean_t scsa2usb_panic_callb(void *, int);
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate /* SCSA support */
1057c478bd9Sstevel@tonic-gate static int	scsa2usb_scsi_tgt_probe(struct scsi_device *, int (*)(void));
1067c478bd9Sstevel@tonic-gate static int	scsa2usb_scsi_tgt_init(dev_info_t *, dev_info_t *,
1077c478bd9Sstevel@tonic-gate 		    scsi_hba_tran_t *, struct scsi_device *);
1087c478bd9Sstevel@tonic-gate static void	scsa2usb_scsi_tgt_free(dev_info_t *, dev_info_t *,
1097c478bd9Sstevel@tonic-gate 		    scsi_hba_tran_t *, struct scsi_device *);
1107c478bd9Sstevel@tonic-gate static struct	scsi_pkt *scsa2usb_scsi_init_pkt(struct scsi_address *,
1117c478bd9Sstevel@tonic-gate 		    struct scsi_pkt *, struct buf *, int, int,
1127c478bd9Sstevel@tonic-gate 		    int, int, int (*)(), caddr_t);
1137c478bd9Sstevel@tonic-gate static void	scsa2usb_scsi_destroy_pkt(struct scsi_address *,
1147c478bd9Sstevel@tonic-gate 		    struct scsi_pkt *);
1157c478bd9Sstevel@tonic-gate static int	scsa2usb_scsi_start(struct scsi_address *, struct scsi_pkt *);
1167c478bd9Sstevel@tonic-gate static int	scsa2usb_scsi_abort(struct scsi_address *, struct scsi_pkt *);
1177c478bd9Sstevel@tonic-gate static int	scsa2usb_scsi_reset(struct scsi_address *, int);
1187c478bd9Sstevel@tonic-gate static int	scsa2usb_scsi_getcap(struct scsi_address *, char *, int);
1197c478bd9Sstevel@tonic-gate static int	scsa2usb_scsi_setcap(struct scsi_address *, char *, int, int);
1207c478bd9Sstevel@tonic-gate static int	scsa2usb_scsi_bus_config(dev_info_t *, uint_t,
1217c478bd9Sstevel@tonic-gate 		    ddi_bus_config_op_t, void *, dev_info_t **);
1227c478bd9Sstevel@tonic-gate static int	scsa2usb_scsi_bus_unconfig(dev_info_t *, uint_t,
1237c478bd9Sstevel@tonic-gate 		    ddi_bus_config_op_t, void *);
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate /* functions for command and transport support */
1267c478bd9Sstevel@tonic-gate static void	scsa2usb_prepare_pkt(scsa2usb_state_t *, struct scsi_pkt *);
1277c478bd9Sstevel@tonic-gate static int	scsa2usb_cmd_transport(scsa2usb_state_t *, scsa2usb_cmd_t *);
12847b9747fSJoshua M. Clulow static int	scsa2usb_check_bulkonly_quirks(scsa2usb_state_t *,
12947b9747fSJoshua M. Clulow 		    scsa2usb_cmd_t *);
13047b9747fSJoshua M. Clulow static int	scsa2usb_check_ufi_quirks(scsa2usb_state_t *,
1317c478bd9Sstevel@tonic-gate 		    scsa2usb_cmd_t *);
1327c478bd9Sstevel@tonic-gate static int	scsa2usb_handle_scsi_cmd_sub_class(scsa2usb_state_t *,
1337c478bd9Sstevel@tonic-gate 		    scsa2usb_cmd_t *, struct scsi_pkt *);
1347c478bd9Sstevel@tonic-gate static int	scsa2usb_handle_ufi_subclass_cmd(scsa2usb_state_t *,
1357c478bd9Sstevel@tonic-gate 		    scsa2usb_cmd_t *, struct scsi_pkt *);
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate /* waitQ handling */
1387c478bd9Sstevel@tonic-gate static void	scsa2usb_work_thread(void *);
1397c478bd9Sstevel@tonic-gate static void	scsa2usb_transport_request(scsa2usb_state_t *, uint_t);
1407c478bd9Sstevel@tonic-gate static void	scsa2usb_flush_waitQ(scsa2usb_state_t *, uint_t, uchar_t);
1417c478bd9Sstevel@tonic-gate static int	scsa2usb_all_waitQs_empty(scsa2usb_state_t *);
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate /* auto request sense handling */
1447c478bd9Sstevel@tonic-gate static int	scsa2usb_create_arq_pkt(scsa2usb_state_t *,
1457c478bd9Sstevel@tonic-gate 		    struct scsi_address *);
1467c478bd9Sstevel@tonic-gate static void	scsa2usb_delete_arq_pkt(scsa2usb_state_t *);
1477c478bd9Sstevel@tonic-gate static void	scsa2usb_complete_arq_pkt(scsa2usb_state_t *, struct scsi_pkt *,
1487c478bd9Sstevel@tonic-gate 		    scsa2usb_cmd_t *, struct buf *);
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate /* utility functions for any transport */
1517c478bd9Sstevel@tonic-gate static int	scsa2usb_open_usb_pipes(scsa2usb_state_t *);
1527c478bd9Sstevel@tonic-gate void		scsa2usb_close_usb_pipes(scsa2usb_state_t *);
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate static void	scsa2usb_fill_up_cdb_len(scsa2usb_cmd_t *, int);
15510b633f4SJoshua M. Clulow static void	scsa2usb_fill_up_cdb_lba(scsa2usb_cmd_t *, uint64_t);
15610b633f4SJoshua M. Clulow static void	scsa2usb_fill_up_g4_cdb_lba(scsa2usb_cmd_t *, uint64_t);
1577c478bd9Sstevel@tonic-gate static void	scsa2usb_fill_up_ReadCD_cdb_len(scsa2usb_cmd_t *, int, int);
1587c478bd9Sstevel@tonic-gate static void	scsa2usb_fill_up_12byte_cdb_len(scsa2usb_cmd_t *, int, int);
15910b633f4SJoshua M. Clulow static void	scsa2usb_fill_up_16byte_cdb_len(scsa2usb_cmd_t *, int, int);
1607c478bd9Sstevel@tonic-gate static int	scsa2usb_read_cd_blk_size(uchar_t);
1617c478bd9Sstevel@tonic-gate int		scsa2usb_rw_transport(scsa2usb_state_t *, struct scsi_pkt *);
1627c478bd9Sstevel@tonic-gate void		scsa2usb_setup_next_xfer(scsa2usb_state_t *, scsa2usb_cmd_t *);
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate static mblk_t	*scsa2usb_bp_to_mblk(scsa2usb_state_t *);
1657c478bd9Sstevel@tonic-gate int		scsa2usb_handle_data_start(scsa2usb_state_t *,
1667c478bd9Sstevel@tonic-gate 		    scsa2usb_cmd_t *, usb_bulk_req_t *);
1677c478bd9Sstevel@tonic-gate void		scsa2usb_handle_data_done(scsa2usb_state_t *,
1687c478bd9Sstevel@tonic-gate 		    scsa2usb_cmd_t *cmd, usb_bulk_req_t *);
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate usb_bulk_req_t *scsa2usb_init_bulk_req(scsa2usb_state_t *,
1717c478bd9Sstevel@tonic-gate 			    size_t, uint_t, usb_req_attrs_t, usb_flags_t);
1727c478bd9Sstevel@tonic-gate int		scsa2usb_bulk_timeout(int);
1737c478bd9Sstevel@tonic-gate int		scsa2usb_clear_ept_stall(scsa2usb_state_t *, uint_t,
1747c478bd9Sstevel@tonic-gate 		    usb_pipe_handle_t, char *);
1757c478bd9Sstevel@tonic-gate static void	scsa2usb_pkt_completion(scsa2usb_state_t *, struct scsi_pkt *);
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate /* event handling */
1787c478bd9Sstevel@tonic-gate static int	scsa2usb_reconnect_event_cb(dev_info_t *);
1797c478bd9Sstevel@tonic-gate static int	scsa2usb_disconnect_event_cb(dev_info_t *);
1807c478bd9Sstevel@tonic-gate static int	scsa2usb_cpr_suspend(dev_info_t *);
1817c478bd9Sstevel@tonic-gate static void	scsa2usb_cpr_resume(dev_info_t *);
1827c478bd9Sstevel@tonic-gate static void	scsa2usb_restore_device_state(dev_info_t *, scsa2usb_state_t *);
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate /* PM handling */
1857c478bd9Sstevel@tonic-gate static void	scsa2usb_create_pm_components(dev_info_t *, scsa2usb_state_t *);
1867c478bd9Sstevel@tonic-gate static void	scsa2usb_raise_power(scsa2usb_state_t *);
1877c478bd9Sstevel@tonic-gate static int	scsa2usb_pwrlvl0(scsa2usb_state_t *);
1887c478bd9Sstevel@tonic-gate static int	scsa2usb_pwrlvl1(scsa2usb_state_t *);
1897c478bd9Sstevel@tonic-gate static int	scsa2usb_pwrlvl2(scsa2usb_state_t *);
1907c478bd9Sstevel@tonic-gate static int	scsa2usb_pwrlvl3(scsa2usb_state_t *);
1917c478bd9Sstevel@tonic-gate static int	scsa2usb_power(dev_info_t *, int comp, int level);
1927c478bd9Sstevel@tonic-gate static void	scsa2usb_pm_busy_component(scsa2usb_state_t *);
1937c478bd9Sstevel@tonic-gate static void	scsa2usb_pm_idle_component(scsa2usb_state_t *);
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate /* external functions for Bulk only (BO) support */
1967c478bd9Sstevel@tonic-gate extern int	scsa2usb_bulk_only_transport(scsa2usb_state_t *,
1977c478bd9Sstevel@tonic-gate 		    scsa2usb_cmd_t *);
1987c478bd9Sstevel@tonic-gate extern int	scsa2usb_bulk_only_get_max_lun(scsa2usb_state_t *);
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate /* external functions for CB/CBI support */
2017c478bd9Sstevel@tonic-gate extern int	scsa2usb_cbi_transport(scsa2usb_state_t *, scsa2usb_cmd_t *);
2027c478bd9Sstevel@tonic-gate extern void	scsa2usb_cbi_stop_intr_polling(scsa2usb_state_t *);
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate /* cmd decoding */
2067c478bd9Sstevel@tonic-gate static char *scsa2usb_cmds[] = {
2077c478bd9Sstevel@tonic-gate 	"\000tur",
2087c478bd9Sstevel@tonic-gate 	"\001rezero",
2097c478bd9Sstevel@tonic-gate 	"\003rqsense",
2107c478bd9Sstevel@tonic-gate 	"\004format",
2117c478bd9Sstevel@tonic-gate 	"\014cartprot",
2127c478bd9Sstevel@tonic-gate 	"\022inquiry",
2137c478bd9Sstevel@tonic-gate 	"\026tranlba",
2147c478bd9Sstevel@tonic-gate 	"\030fmtverify",
2157c478bd9Sstevel@tonic-gate 	"\032modesense",
2167c478bd9Sstevel@tonic-gate 	"\033start",
2177c478bd9Sstevel@tonic-gate 	"\035snddiag",
2187c478bd9Sstevel@tonic-gate 	"\036doorlock",
2197c478bd9Sstevel@tonic-gate 	"\043formatcap",
2207c478bd9Sstevel@tonic-gate 	"\045readcap",
2217c478bd9Sstevel@tonic-gate 	"\050read10",
2227c478bd9Sstevel@tonic-gate 	"\052write10",
2237c478bd9Sstevel@tonic-gate 	"\053seek10",
2247c478bd9Sstevel@tonic-gate 	"\056writeverify",
2257c478bd9Sstevel@tonic-gate 	"\057verify",
2267c478bd9Sstevel@tonic-gate 	"\065synchcache",
2277c478bd9Sstevel@tonic-gate 	"\076readlong",
2287c478bd9Sstevel@tonic-gate 	"\077writelong",
2297c478bd9Sstevel@tonic-gate 	"\102readsubchan",
2307c478bd9Sstevel@tonic-gate 	"\103readtoc",
2317c478bd9Sstevel@tonic-gate 	"\104readhdr",
2327c478bd9Sstevel@tonic-gate 	"\105playaudio10",
2337c478bd9Sstevel@tonic-gate 	"\107playaudio_msf",
2347c478bd9Sstevel@tonic-gate 	"\110playaudio_ti",
2357c478bd9Sstevel@tonic-gate 	"\111playtrk_r10",
2367c478bd9Sstevel@tonic-gate 	"\112geteventnotify",
2377c478bd9Sstevel@tonic-gate 	"\113pause_resume",
2387c478bd9Sstevel@tonic-gate 	"\116stop/play_scan",
2397c478bd9Sstevel@tonic-gate 	"\121readdiscinfo",
2407c478bd9Sstevel@tonic-gate 	"\122readtrkinfo",
2417c478bd9Sstevel@tonic-gate 	"\123reservedtrk",
2427c478bd9Sstevel@tonic-gate 	"\124sendopcinfo",
2437c478bd9Sstevel@tonic-gate 	"\125modeselect",
2447c478bd9Sstevel@tonic-gate 	"\132modesense",
2457c478bd9Sstevel@tonic-gate 	"\133closetrksession",
2467c478bd9Sstevel@tonic-gate 	"\135sendcuesheet",
2477c478bd9Sstevel@tonic-gate 	"\136prin",
2487c478bd9Sstevel@tonic-gate 	"\137prout",
24910b633f4SJoshua M. Clulow 	"\210read16",
25010b633f4SJoshua M. Clulow 	"\212write16",
2517c478bd9Sstevel@tonic-gate 	"\241blankcd",
2527c478bd9Sstevel@tonic-gate 	"\245playaudio12",
2537c478bd9Sstevel@tonic-gate 	"\250read12",
2547c478bd9Sstevel@tonic-gate 	"\251playtrk12",
2557c478bd9Sstevel@tonic-gate 	"\252write12",
2567c478bd9Sstevel@tonic-gate 	"\254getperf",
2577c478bd9Sstevel@tonic-gate 	"\271readcdmsf",
2587c478bd9Sstevel@tonic-gate 	"\273setcdspeed",
2597c478bd9Sstevel@tonic-gate 	"\275mechanism_sts",
2607c478bd9Sstevel@tonic-gate 	"\276readcd",
2617c478bd9Sstevel@tonic-gate 	NULL
2627c478bd9Sstevel@tonic-gate };
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate /*
26647b9747fSJoshua M. Clulow  * Mass-Storage devices masquerade as "sd" disks.  These devices may not
26747b9747fSJoshua M. Clulow  * support all SCSI CDBs in their entirety due to implementation
26847b9747fSJoshua M. Clulow  * limitations.
2697c478bd9Sstevel@tonic-gate  *
27047b9747fSJoshua M. Clulow  * The following table contains a list of quirks for devices that are known to
27147b9747fSJoshua M. Clulow  * misbehave.  See the comments in scsa2usb.h for a description of each
27247b9747fSJoshua M. Clulow  * quirk attribute.
27347b9747fSJoshua M. Clulow  */
27447b9747fSJoshua M. Clulow 
27547b9747fSJoshua M. Clulow /*
27647b9747fSJoshua M. Clulow  * Either the product ID (q_pid) or the revision number (q_rev) can be a
27747b9747fSJoshua M. Clulow  * wildcard match using this constant:
2787c478bd9Sstevel@tonic-gate  */
27947b9747fSJoshua M. Clulow #define	X	UINT16_MAX
28047b9747fSJoshua M. Clulow 
28147b9747fSJoshua M. Clulow static struct quirk {
28247b9747fSJoshua M. Clulow 	uint16_t	q_vid;	/* Vendor ID */
28347b9747fSJoshua M. Clulow 	uint16_t	q_pid;	/* Product ID */
28447b9747fSJoshua M. Clulow 	uint16_t	q_rev;	/* Device revision number in BCD */
28547b9747fSJoshua M. Clulow 	uint16_t	q_attr;	/* Quirk attributes for this device */
28647b9747fSJoshua M. Clulow } scsa2usb_quirks[] = {
2877c478bd9Sstevel@tonic-gate 	/* Iomega Zip100 drive (prototype) with flaky bridge */
28847b9747fSJoshua M. Clulow 	{MS_IOMEGA_VID, MS_IOMEGA_PID1_ZIP100, X,
2897c478bd9Sstevel@tonic-gate 	    SCSA2USB_ATTRS_GET_LUN | SCSA2USB_ATTRS_PM},
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate 	/* Iomega Zip100 drive (newer model) with flaky bridge */
29247b9747fSJoshua M. Clulow 	{MS_IOMEGA_VID, MS_IOMEGA_PID2_ZIP100, X,
2937c478bd9Sstevel@tonic-gate 	    SCSA2USB_ATTRS_GET_LUN | SCSA2USB_ATTRS_PM},
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate 	/* Iomega Zip100 drive (newer model) with flaky bridge */
29647b9747fSJoshua M. Clulow 	{MS_IOMEGA_VID, MS_IOMEGA_PID3_ZIP100, X,
2977c478bd9Sstevel@tonic-gate 	    SCSA2USB_ATTRS_GET_LUN | SCSA2USB_ATTRS_PM},
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate 	/* Iomega Zip250 drive */
30047b9747fSJoshua M. Clulow 	{MS_IOMEGA_VID, MS_IOMEGA_PID_ZIP250, X, SCSA2USB_ATTRS_GET_LUN},
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate 	/* Iomega Clik! drive */
30347b9747fSJoshua M. Clulow 	{MS_IOMEGA_VID, MS_IOMEGA_PID_CLIK, X,
3047c478bd9Sstevel@tonic-gate 	    SCSA2USB_ATTRS_GET_LUN | SCSA2USB_ATTRS_START_STOP},
3057c478bd9Sstevel@tonic-gate 
3065547f1d8SBinzi Cao - Sun Microsystems - Beijing China 	/* Kingston DataTraveler Stick / PNY Attache Stick */
30747b9747fSJoshua M. Clulow 	{MS_TOSHIBA_VID, MS_TOSHIBA_PID0, X,
3085547f1d8SBinzi Cao - Sun Microsystems - Beijing China 	    SCSA2USB_ATTRS_GET_LUN},
3095547f1d8SBinzi Cao - Sun Microsystems - Beijing China 
3105547f1d8SBinzi Cao - Sun Microsystems - Beijing China 	/* PNY Floppy drive */
31147b9747fSJoshua M. Clulow 	{MS_PNY_VID, MS_PNY_PID0, X,
3125547f1d8SBinzi Cao - Sun Microsystems - Beijing China 	    SCSA2USB_ATTRS_GET_LUN},
3135547f1d8SBinzi Cao - Sun Microsystems - Beijing China 
3147c478bd9Sstevel@tonic-gate 	/* SMSC floppy Device - and its clones */
31547b9747fSJoshua M. Clulow 	{MS_SMSC_VID, X, X, SCSA2USB_ATTRS_START_STOP},
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 	/* Hagiwara SmartMedia Device */
31847b9747fSJoshua M. Clulow 	{MS_HAGIWARA_SYS_COM_VID, MS_HAGIWARA_SYSCOM_PID1, X,
3197c478bd9Sstevel@tonic-gate 	    SCSA2USB_ATTRS_GET_LUN | SCSA2USB_ATTRS_START_STOP},
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 	/* Hagiwara CompactFlash Device */
32247b9747fSJoshua M. Clulow 	{MS_HAGIWARA_SYS_COM_VID, MS_HAGIWARA_SYSCOM_PID2, X,
3237c478bd9Sstevel@tonic-gate 	    SCSA2USB_ATTRS_GET_LUN | SCSA2USB_ATTRS_START_STOP},
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 	/* Hagiwara SmartMedia/CompactFlash Combo Device */
32647b9747fSJoshua M. Clulow 	{MS_HAGIWARA_SYS_COM_VID, MS_HAGIWARA_SYSCOM_PID3, X,
3277c478bd9Sstevel@tonic-gate 	    SCSA2USB_ATTRS_START_STOP},
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate 	/* Hagiwara new SM Device */
33047b9747fSJoshua M. Clulow 	{MS_HAGIWARA_SYS_COM_VID, MS_HAGIWARA_SYSCOM_PID4, X,
3317c478bd9Sstevel@tonic-gate 	    SCSA2USB_ATTRS_GET_LUN | SCSA2USB_ATTRS_START_STOP},
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate 	/* Hagiwara new CF Device */
33447b9747fSJoshua M. Clulow 	{MS_HAGIWARA_SYS_COM_VID, MS_HAGIWARA_SYSCOM_PID5, X,
3357c478bd9Sstevel@tonic-gate 	    SCSA2USB_ATTRS_GET_LUN | SCSA2USB_ATTRS_START_STOP},
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate 	/* Mitsumi CD-RW Device(s) */
3387c478bd9Sstevel@tonic-gate 	{MS_MITSUMI_VID, X, X, SCSA2USB_ATTRS_BIG_TIMEOUT |
3397c478bd9Sstevel@tonic-gate 	    SCSA2USB_ATTRS_GET_CONF | SCSA2USB_ATTRS_GET_PERF},
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate 	/* Neodio Technologies Corporation SM/CF/MS/SD Combo Device */
34247b9747fSJoshua M. Clulow 	{MS_NEODIO_VID, MS_NEODIO_DEVICE_3050, X,
3437c478bd9Sstevel@tonic-gate 	    SCSA2USB_ATTRS_MODE_SENSE },
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate 	/* dumb flash devices */
34647b9747fSJoshua M. Clulow 	{MS_SONY_FLASH_VID, MS_SONY_FLASH_PID, X,
3477c478bd9Sstevel@tonic-gate 	    SCSA2USB_ATTRS_REDUCED_CMD},
3487c478bd9Sstevel@tonic-gate 
34947b9747fSJoshua M. Clulow 	{MS_TREK_FLASH_VID, MS_TREK_FLASH_PID, X,
3507c478bd9Sstevel@tonic-gate 	    SCSA2USB_ATTRS_REDUCED_CMD},
3517c478bd9Sstevel@tonic-gate 
35247b9747fSJoshua M. Clulow 	{MS_PENN_FLASH_VID, MS_PENN_FLASH_PID, X,
3537c478bd9Sstevel@tonic-gate 	    SCSA2USB_ATTRS_REDUCED_CMD},
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate 	/* SimpleTech UCF-100 CF Device */
35647b9747fSJoshua M. Clulow 	{MS_SIMPLETECH_VID, MS_SIMPLETECH_PID1, X,
3577c478bd9Sstevel@tonic-gate 	    SCSA2USB_ATTRS_REDUCED_CMD},
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate 	{MS_ADDONICS_CARD_READER_VID, MS_ADDONICS_CARD_READER_PID,
36047b9747fSJoshua M. Clulow 	    X, SCSA2USB_ATTRS_REDUCED_CMD},
3612115f0c6Ssl 
3622115f0c6Ssl 	/* Acomdata 80GB USB/1394 Hard Disk */
36347b9747fSJoshua M. Clulow 	{MS_ACOMDATA_VID, MS_ACOMDATA_PID1, X,
3642115f0c6Ssl 	    SCSA2USB_ATTRS_USE_CSW_RESIDUE},
3652115f0c6Ssl 
3662115f0c6Ssl 	/* OTi6828 Flash Disk */
36747b9747fSJoshua M. Clulow 	{MS_OTI_VID, MS_OTI_DEVICE_6828, X,
3682115f0c6Ssl 	    SCSA2USB_ATTRS_USE_CSW_RESIDUE},
369df4cb6e0Ssl 
370df4cb6e0Ssl 	/* AMI Virtual Floppy */
37147b9747fSJoshua M. Clulow 	{MS_AMI_VID, MS_AMI_VIRTUAL_FLOPPY, X,
372df4cb6e0Ssl 	    SCSA2USB_ATTRS_NO_MEDIA_CHECK},
37363602c90Sfb 
37463602c90Sfb 	/* ScanLogic USB Storage Device */
37547b9747fSJoshua M. Clulow 	{MS_SCANLOGIC_VID, MS_SCANLOGIC_PID1, X,
3763fbbb872Ssl 	    SCSA2USB_ATTRS_NO_CAP_ADJUST},
3773fbbb872Ssl 
3783fbbb872Ssl 	/* Super Top USB 2.0 IDE Device */
37947b9747fSJoshua M. Clulow 	{MS_SUPERTOP_VID, MS_SUPERTOP_DEVICE_6600, X,
38067318e4aSlg 	    SCSA2USB_ATTRS_USE_CSW_RESIDUE},
38167318e4aSlg 
38267318e4aSlg 	/* Aigo Miniking Device NEHFSP14 */
38347b9747fSJoshua M. Clulow 	{MS_AIGO_VID, MS_AIGO_DEVICE_6981, X,
384f0e30896Sguoqing zhu - Sun Microsystems - Beijing China 	    SCSA2USB_ATTRS_USE_CSW_RESIDUE},
385f0e30896Sguoqing zhu - Sun Microsystems - Beijing China 
386f0e30896Sguoqing zhu - Sun Microsystems - Beijing China 	/* Alcor Micro Corp 6387 flash disk */
38747b9747fSJoshua M. Clulow 	{MS_ALCOR_VID, MS_ALCOR_PID0, X,
3888f588c83Sguoqing zhu - Sun Microsystems - Beijing China 	    SCSA2USB_ATTRS_GET_LUN | SCSA2USB_ATTRS_USE_CSW_RESIDUE},
389f0e30896Sguoqing zhu - Sun Microsystems - Beijing China 
3908f588c83Sguoqing zhu - Sun Microsystems - Beijing China 	/* Western Digital External HDD */
39147b9747fSJoshua M. Clulow 	{MS_WD_VID, MS_WD_PID, X,
39247b9747fSJoshua M. Clulow 	    SCSA2USB_ATTRS_INQUIRY_EVPD},
393cefe3a5bSJoshua M. Clulow 
394cefe3a5bSJoshua M. Clulow 	/* Insyde Virtual CD-ROM */
395cefe3a5bSJoshua M. Clulow 	{MS_INSYDE_VID, MS_INSYDE_PID_CDROM, X,
396cefe3a5bSJoshua M. Clulow 	    SCSA2USB_ATTRS_MODE_SENSE},
3977c478bd9Sstevel@tonic-gate };
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate /*
4017c478bd9Sstevel@tonic-gate  * Attribute values can be overridden by values
4027c478bd9Sstevel@tonic-gate  * contained in the scsa2usb.conf file.
4037c478bd9Sstevel@tonic-gate  * These arrays define possible user input values.
4047c478bd9Sstevel@tonic-gate  */
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate struct scsa2usb_subclass_protocol_override {
4077c478bd9Sstevel@tonic-gate 	char	*name;
4087c478bd9Sstevel@tonic-gate 	int	value;
4097c478bd9Sstevel@tonic-gate };
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate static struct scsa2usb_subclass_protocol_override scsa2usb_protocol[] =  {
4127c478bd9Sstevel@tonic-gate 	{"CB", SCSA2USB_CB_PROTOCOL},
4137c478bd9Sstevel@tonic-gate 	{"CBI", SCSA2USB_CBI_PROTOCOL},
4147c478bd9Sstevel@tonic-gate 	{"BO", SCSA2USB_BULK_ONLY_PROTOCOL}
4157c478bd9Sstevel@tonic-gate };
4167c478bd9Sstevel@tonic-gate 
4177c478bd9Sstevel@tonic-gate static struct scsa2usb_subclass_protocol_override scsa2usb_subclass[] = {
4187c478bd9Sstevel@tonic-gate 	{"SCSI", SCSA2USB_SCSI_CMDSET},
4197c478bd9Sstevel@tonic-gate 	{"ATAPI", SCSA2USB_ATAPI_CMDSET},
4207c478bd9Sstevel@tonic-gate 	{"UFI", SCSA2USB_UFI_CMDSET}
4217c478bd9Sstevel@tonic-gate };
4227c478bd9Sstevel@tonic-gate 
4237c478bd9Sstevel@tonic-gate 
4247c478bd9Sstevel@tonic-gate #define	N_SCSA2USB_SUBC_OVERRIDE (sizeof (scsa2usb_subclass))/ \
4257c478bd9Sstevel@tonic-gate 			sizeof (struct scsa2usb_subclass_protocol_override)
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate #define	N_SCSA2USB_PROT_OVERRIDE (sizeof (scsa2usb_protocol))/ \
4287c478bd9Sstevel@tonic-gate 			sizeof (struct scsa2usb_subclass_protocol_override)
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate /* global variables */
4317c478bd9Sstevel@tonic-gate static void *scsa2usb_statep;				/* for soft state */
4327c478bd9Sstevel@tonic-gate static boolean_t scsa2usb_sync_message = B_TRUE;	/* for syncing */
4337c478bd9Sstevel@tonic-gate 
4347c478bd9Sstevel@tonic-gate /* for debug messages */
4354610e4a0Sfrits uint_t	scsa2usb_errmask	= (uint_t)DPRINT_MASK_ALL;
4364610e4a0Sfrits uint_t	scsa2usb_errlevel	= USB_LOG_L4;
4374610e4a0Sfrits uint_t	scsa2usb_instance_debug = (uint_t)-1;
4384610e4a0Sfrits uint_t	scsa2usb_scsi_bus_config_debug = 0;
4394610e4a0Sfrits uint_t	scsa2usb_long_timeout	= 50 * SCSA2USB_BULK_PIPE_TIMEOUT;
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate /*
4437c478bd9Sstevel@tonic-gate  * Some devices have problems with big bulk transfers,
4447c478bd9Sstevel@tonic-gate  * transfers >= 128kbytes hang the device.  This tunable allows to
4457c478bd9Sstevel@tonic-gate  * limit the maximum bulk transfers rate.
4467c478bd9Sstevel@tonic-gate  */
4474610e4a0Sfrits uint_t	scsa2usb_max_bulk_xfer_size = SCSA2USB_MAX_BULK_XFER_SIZE;
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate #ifdef	SCSA2USB_BULK_ONLY_TEST
4517c478bd9Sstevel@tonic-gate /*
4527c478bd9Sstevel@tonic-gate  * Test BO 13 cases. (See USB Mass Storage Class - Bulk Only Transport).
4537c478bd9Sstevel@tonic-gate  * We are not covering test cases 1, 6, and 12 as these are the "good"
4547c478bd9Sstevel@tonic-gate  * test cases and are tested as part of the normal drive access operations.
4557c478bd9Sstevel@tonic-gate  *
4567c478bd9Sstevel@tonic-gate  * NOTE: This is for testing only. It will be replaced by a uscsi test.
4577c478bd9Sstevel@tonic-gate  * Some are listed here while; other test cases are moved to usb_bulkonly.c
4587c478bd9Sstevel@tonic-gate  */
4597c478bd9Sstevel@tonic-gate static int scsa2usb_test_case_5 = 0;
4607c478bd9Sstevel@tonic-gate int scsa2usb_test_case_8 = 0;
4617c478bd9Sstevel@tonic-gate int scsa2usb_test_case_10 = 0;
4627c478bd9Sstevel@tonic-gate static int scsa2usb_test_case_11 = 0;
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate static void	scsa2usb_test_mblk(scsa2usb_state_t *, boolean_t);
4657c478bd9Sstevel@tonic-gate #endif	/* SCSA2USB_BULK_ONLY_TEST */
4667c478bd9Sstevel@tonic-gate 
4677c478bd9Sstevel@tonic-gate static int	scsa2usb_ugen_open(dev_t *, int, int, cred_t *);
4687c478bd9Sstevel@tonic-gate static int	scsa2usb_ugen_close(dev_t, int, int, cred_t *);
4697c478bd9Sstevel@tonic-gate static int	scsa2usb_ugen_read(dev_t, struct uio *, cred_t *);
4707c478bd9Sstevel@tonic-gate static int	scsa2usb_ugen_write(dev_t, struct uio *, cred_t *);
4717c478bd9Sstevel@tonic-gate static int	scsa2usb_ugen_poll(dev_t, short, int,  short *,
4727c478bd9Sstevel@tonic-gate 						struct pollhead **);
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate /* scsa2usb cb_ops */
4757c478bd9Sstevel@tonic-gate static struct cb_ops scsa2usb_cbops = {
4767c478bd9Sstevel@tonic-gate 	scsa2usb_ugen_open,	/* open  */
4777c478bd9Sstevel@tonic-gate 	scsa2usb_ugen_close,	/* close */
4787c478bd9Sstevel@tonic-gate 	nodev,			/* strategy */
4797c478bd9Sstevel@tonic-gate 	nodev,			/* print */
4807c478bd9Sstevel@tonic-gate 	nodev,			/* dump */
4817c478bd9Sstevel@tonic-gate 	scsa2usb_ugen_read,	/* read */
4827c478bd9Sstevel@tonic-gate 	scsa2usb_ugen_write,	/* write */
4830e7b3271Svb 	nodev,			/* ioctl */
4847c478bd9Sstevel@tonic-gate 	nodev,			/* devmap */
4857c478bd9Sstevel@tonic-gate 	nodev,			/* mmap */
4867c478bd9Sstevel@tonic-gate 	nodev,			/* segmap */
4877c478bd9Sstevel@tonic-gate 	scsa2usb_ugen_poll,	/* poll */
4887c478bd9Sstevel@tonic-gate 	ddi_prop_op,		/* prop_op */
4897c478bd9Sstevel@tonic-gate 	NULL,			/* stream */
4907c478bd9Sstevel@tonic-gate 	D_MP,			/* cb_flag */
49110b633f4SJoshua M. Clulow 	CB_REV,			/* rev */
4927c478bd9Sstevel@tonic-gate 	nodev,			/* int (*cb_aread)() */
4937c478bd9Sstevel@tonic-gate 	nodev			/* int (*cb_awrite)() */
4947c478bd9Sstevel@tonic-gate };
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate /* modloading support */
4977c478bd9Sstevel@tonic-gate static struct dev_ops scsa2usb_ops = {
4987c478bd9Sstevel@tonic-gate 	DEVO_REV,		/* devo_rev, */
4997c478bd9Sstevel@tonic-gate 	0,			/* refcnt  */
5007c478bd9Sstevel@tonic-gate 	scsa2usb_info,		/* info */
5017c478bd9Sstevel@tonic-gate 	nulldev,		/* identify */
5027c478bd9Sstevel@tonic-gate 	nulldev,		/* probe */
5037c478bd9Sstevel@tonic-gate 	scsa2usb_attach,	/* attach */
5047c478bd9Sstevel@tonic-gate 	scsa2usb_detach,	/* detach */
5057c478bd9Sstevel@tonic-gate 	nodev,			/* reset */
5067c478bd9Sstevel@tonic-gate 	&scsa2usb_cbops,	/* driver operations */
5077c478bd9Sstevel@tonic-gate 	NULL,			/* bus operations */
50819397407SSherry Moore 	scsa2usb_power,		/* power */
50919397407SSherry Moore 	ddi_quiesce_not_needed,		/* quiesce */
5107c478bd9Sstevel@tonic-gate };
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate static struct modldrv modldrv = {
5137c478bd9Sstevel@tonic-gate 	&mod_driverops,			/* Module type. This one is a driver */
514e7cc2e17Sbc 	"SCSA to USB Driver",	/* Name of the module. */
5157c478bd9Sstevel@tonic-gate 	&scsa2usb_ops,			/* driver ops */
5167c478bd9Sstevel@tonic-gate };
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
5197c478bd9Sstevel@tonic-gate 	MODREV_1, (void *)&modldrv, NULL
5207c478bd9Sstevel@tonic-gate };
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate /* event support */
5237c478bd9Sstevel@tonic-gate static usb_event_t scsa2usb_events = {
5247c478bd9Sstevel@tonic-gate 	scsa2usb_disconnect_event_cb,
5257c478bd9Sstevel@tonic-gate 	scsa2usb_reconnect_event_cb,
5267c478bd9Sstevel@tonic-gate 	NULL, NULL
5277c478bd9Sstevel@tonic-gate };
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate int
_init(void)5307c478bd9Sstevel@tonic-gate _init(void)
5317c478bd9Sstevel@tonic-gate {
5327c478bd9Sstevel@tonic-gate 	int rval;
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate 	if (((rval = ddi_soft_state_init(&scsa2usb_statep,
5357c478bd9Sstevel@tonic-gate 	    sizeof (scsa2usb_state_t), SCSA2USB_INITIAL_ALLOC)) != 0)) {
5367c478bd9Sstevel@tonic-gate 
5377c478bd9Sstevel@tonic-gate 		return (rval);
5387c478bd9Sstevel@tonic-gate 	}
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate 	if ((rval = scsi_hba_init(&modlinkage)) != 0) {
5417c478bd9Sstevel@tonic-gate 		ddi_soft_state_fini(&scsa2usb_statep);
5427c478bd9Sstevel@tonic-gate 
5437c478bd9Sstevel@tonic-gate 		return (rval);
5447c478bd9Sstevel@tonic-gate 	}
5457c478bd9Sstevel@tonic-gate 
5467c478bd9Sstevel@tonic-gate 	if ((rval = mod_install(&modlinkage)) != 0) {
5477c478bd9Sstevel@tonic-gate 		scsi_hba_fini(&modlinkage);
5487c478bd9Sstevel@tonic-gate 		ddi_soft_state_fini(&scsa2usb_statep);
5497c478bd9Sstevel@tonic-gate 
5507c478bd9Sstevel@tonic-gate 		return (rval);
5517c478bd9Sstevel@tonic-gate 	}
5527c478bd9Sstevel@tonic-gate 
5537c478bd9Sstevel@tonic-gate 	return (rval);
5547c478bd9Sstevel@tonic-gate }
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate 
5577c478bd9Sstevel@tonic-gate int
_fini(void)5587c478bd9Sstevel@tonic-gate _fini(void)
5597c478bd9Sstevel@tonic-gate {
5607c478bd9Sstevel@tonic-gate 	int	rval;
5617c478bd9Sstevel@tonic-gate 
5627c478bd9Sstevel@tonic-gate 	if ((rval = mod_remove(&modlinkage)) == 0) {
5637c478bd9Sstevel@tonic-gate 		scsi_hba_fini(&modlinkage);
5647c478bd9Sstevel@tonic-gate 		ddi_soft_state_fini(&scsa2usb_statep);
5657c478bd9Sstevel@tonic-gate 	}
5667c478bd9Sstevel@tonic-gate 
5677c478bd9Sstevel@tonic-gate 	return (rval);
5687c478bd9Sstevel@tonic-gate }
5697c478bd9Sstevel@tonic-gate 
5707c478bd9Sstevel@tonic-gate 
5717c478bd9Sstevel@tonic-gate int
_info(struct modinfo * modinfop)5727c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
5737c478bd9Sstevel@tonic-gate {
5747c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
5757c478bd9Sstevel@tonic-gate }
5767c478bd9Sstevel@tonic-gate 
5777c478bd9Sstevel@tonic-gate 
5787c478bd9Sstevel@tonic-gate /*
5797c478bd9Sstevel@tonic-gate  * scsa2usb_info :
5807c478bd9Sstevel@tonic-gate  *	Get minor number, soft state structure etc.
5817c478bd9Sstevel@tonic-gate  */
5827c478bd9Sstevel@tonic-gate /*ARGSUSED*/
5837c478bd9Sstevel@tonic-gate static int
scsa2usb_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)5847c478bd9Sstevel@tonic-gate scsa2usb_info(dev_info_t *dip, ddi_info_cmd_t infocmd,
5857c478bd9Sstevel@tonic-gate     void *arg, void **result)
5867c478bd9Sstevel@tonic-gate {
5877c478bd9Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp = NULL;
5887c478bd9Sstevel@tonic-gate 	int error = DDI_FAILURE;
5897c478bd9Sstevel@tonic-gate 	int instance = SCSA2USB_MINOR_TO_INSTANCE(getminor((dev_t)arg));
5907c478bd9Sstevel@tonic-gate 
5917c478bd9Sstevel@tonic-gate 	switch (infocmd) {
5927c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
5937c478bd9Sstevel@tonic-gate 		if (((scsa2usbp = ddi_get_soft_state(scsa2usb_statep,
5947c478bd9Sstevel@tonic-gate 		    instance)) != NULL) &&
5957c478bd9Sstevel@tonic-gate 		    scsa2usbp->scsa2usb_dip) {
5967c478bd9Sstevel@tonic-gate 			*result = scsa2usbp->scsa2usb_dip;
5977c478bd9Sstevel@tonic-gate 			error = DDI_SUCCESS;
5987c478bd9Sstevel@tonic-gate 		} else {
5997c478bd9Sstevel@tonic-gate 			*result = NULL;
6007c478bd9Sstevel@tonic-gate 		}
6017c478bd9Sstevel@tonic-gate 		break;
6027c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
6037c478bd9Sstevel@tonic-gate 		*result = (void *)(uintptr_t)instance;
6047c478bd9Sstevel@tonic-gate 		error = DDI_SUCCESS;
6057c478bd9Sstevel@tonic-gate 		break;
6067c478bd9Sstevel@tonic-gate 	default:
6077c478bd9Sstevel@tonic-gate 		break;
6087c478bd9Sstevel@tonic-gate 	}
6097c478bd9Sstevel@tonic-gate 
6107c478bd9Sstevel@tonic-gate 	return (error);
6117c478bd9Sstevel@tonic-gate }
6127c478bd9Sstevel@tonic-gate 
6137c478bd9Sstevel@tonic-gate 
6147c478bd9Sstevel@tonic-gate /*
6157c478bd9Sstevel@tonic-gate  * scsa2usb_attach:
6167c478bd9Sstevel@tonic-gate  *	Attach driver
6177c478bd9Sstevel@tonic-gate  *	Allocate a "scsi_hba_tran" - call scsi_hba_tran_alloc()
6187c478bd9Sstevel@tonic-gate  *	Invoke scsi_hba_attach_setup
6197c478bd9Sstevel@tonic-gate  *	Get the serialno of the device
6207c478bd9Sstevel@tonic-gate  *	Open bulk pipes
6217c478bd9Sstevel@tonic-gate  *	Create disk child(ren)
6227c478bd9Sstevel@tonic-gate  *	Register events
6237c478bd9Sstevel@tonic-gate  *	Create and register panic callback
6247c478bd9Sstevel@tonic-gate  *
6257c478bd9Sstevel@tonic-gate  * NOTE: Replaced CBW_DIR_OUT with USB_EP_DIR_OUT and CBW_DIR_IN with
6267c478bd9Sstevel@tonic-gate  * USB_EP_DIR_IN as they are the same #defines.
6277c478bd9Sstevel@tonic-gate  */
6287c478bd9Sstevel@tonic-gate static int
scsa2usb_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)6297c478bd9Sstevel@tonic-gate scsa2usb_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
6307c478bd9Sstevel@tonic-gate {
6317c478bd9Sstevel@tonic-gate 	int			instance = ddi_get_instance(dip);
6327c478bd9Sstevel@tonic-gate 	int			interface;
6337c478bd9Sstevel@tonic-gate 	uint_t			lun;
6347c478bd9Sstevel@tonic-gate 	boolean_t		ept_check = B_TRUE;
6357c478bd9Sstevel@tonic-gate 	scsi_hba_tran_t		*tran;		/* scsi transport */
6367c478bd9Sstevel@tonic-gate 	scsa2usb_state_t	*scsa2usbp;
6377c478bd9Sstevel@tonic-gate 	usb_log_handle_t	log_handle;
6387c478bd9Sstevel@tonic-gate 	usb_ep_data_t		*ep_data;
6397c478bd9Sstevel@tonic-gate 	usb_client_dev_data_t	*dev_data;
6407c478bd9Sstevel@tonic-gate 	usb_alt_if_data_t	*altif_data;
64110b633f4SJoshua M. Clulow 	usb_ugen_info_t		usb_ugen_info;
6427c478bd9Sstevel@tonic-gate 
6437c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, NULL,
644112116d8Sfb 	    "scsa2usb_attach: dip = 0x%p", (void *)dip);
6457c478bd9Sstevel@tonic-gate 
6467c478bd9Sstevel@tonic-gate 	switch (cmd) {
6477c478bd9Sstevel@tonic-gate 	case DDI_ATTACH:
6487c478bd9Sstevel@tonic-gate 		break;
6497c478bd9Sstevel@tonic-gate 	case DDI_RESUME:
6507c478bd9Sstevel@tonic-gate 		scsa2usb_cpr_resume(dip);
6517c478bd9Sstevel@tonic-gate 
6527c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
6537c478bd9Sstevel@tonic-gate 	default:
6547c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, NULL,
6557c478bd9Sstevel@tonic-gate 		    "scsa2usb_attach: failed");
6567c478bd9Sstevel@tonic-gate 
6577c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
6587c478bd9Sstevel@tonic-gate 	}
6597c478bd9Sstevel@tonic-gate 
6607c478bd9Sstevel@tonic-gate 	/* Allocate softc information */
6617c478bd9Sstevel@tonic-gate 	if (ddi_soft_state_zalloc(scsa2usb_statep, instance) != DDI_SUCCESS) {
6627c478bd9Sstevel@tonic-gate 		ddi_prop_remove_all(dip);
6637c478bd9Sstevel@tonic-gate 
6647c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
6657c478bd9Sstevel@tonic-gate 	}
6667c478bd9Sstevel@tonic-gate 
6677c478bd9Sstevel@tonic-gate 	/* get soft state space and initialize */
6687c478bd9Sstevel@tonic-gate 	if ((scsa2usbp = ddi_get_soft_state(scsa2usb_statep,
6697c478bd9Sstevel@tonic-gate 	    instance)) == NULL) {
6707c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, NULL,
6717c478bd9Sstevel@tonic-gate 		    "scsa2usb%d: bad soft state", instance);
6727c478bd9Sstevel@tonic-gate 		ddi_prop_remove_all(dip);
6737c478bd9Sstevel@tonic-gate 
6747c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
6757c478bd9Sstevel@tonic-gate 	}
6767c478bd9Sstevel@tonic-gate 
67710b633f4SJoshua M. Clulow 	scsa2usbp->scsa2usb_dip		= dip;
6787c478bd9Sstevel@tonic-gate 	scsa2usbp->scsa2usb_instance	= instance;
6797c478bd9Sstevel@tonic-gate 
6807c478bd9Sstevel@tonic-gate 	/* allocate a log handle for debug/error messages */
6817c478bd9Sstevel@tonic-gate 	scsa2usbp->scsa2usb_log_handle = log_handle =
6827c478bd9Sstevel@tonic-gate 	    usb_alloc_log_hdl(dip, "s2u",
683d94492edSfb 	    &scsa2usb_errlevel,
684d94492edSfb 	    &scsa2usb_errmask, &scsa2usb_instance_debug,
685d94492edSfb 	    0);
6867c478bd9Sstevel@tonic-gate 
6877c478bd9Sstevel@tonic-gate 	/* attach to USBA */
6887c478bd9Sstevel@tonic-gate 	if (usb_client_attach(dip, USBDRV_VERSION, 0) != USB_SUCCESS) {
6897c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, log_handle,
6907c478bd9Sstevel@tonic-gate 		    "usb_client_attach failed");
6917c478bd9Sstevel@tonic-gate 
6927c478bd9Sstevel@tonic-gate 		goto fail;
6937c478bd9Sstevel@tonic-gate 	}
6947c478bd9Sstevel@tonic-gate 	if (usb_get_dev_data(dip, &dev_data, USB_PARSE_LVL_IF, 0) !=
6957c478bd9Sstevel@tonic-gate 	    USB_SUCCESS) {
6967c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, log_handle,
6977c478bd9Sstevel@tonic-gate 		    "usb_get_dev_data failed");
6987c478bd9Sstevel@tonic-gate 
6997c478bd9Sstevel@tonic-gate 		goto fail;
7007c478bd9Sstevel@tonic-gate 	}
7017c478bd9Sstevel@tonic-gate 
7027c478bd9Sstevel@tonic-gate 	/* initialize the mutex with the right cookie */
7037c478bd9Sstevel@tonic-gate 	mutex_init(&scsa2usbp->scsa2usb_mutex, NULL, MUTEX_DRIVER,
704d94492edSfb 	    dev_data->dev_iblock_cookie);
7057c478bd9Sstevel@tonic-gate 	cv_init(&scsa2usbp->scsa2usb_transport_busy_cv, NULL, CV_DRIVER, NULL);
7067c478bd9Sstevel@tonic-gate 
7077c478bd9Sstevel@tonic-gate 	for (lun = 0; lun < SCSA2USB_MAX_LUNS; lun++) {
7087c478bd9Sstevel@tonic-gate 		usba_init_list(&scsa2usbp->scsa2usb_waitQ[lun], NULL,
709d94492edSfb 		    dev_data->dev_iblock_cookie);
7107c478bd9Sstevel@tonic-gate 	}
7117c478bd9Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
71210b633f4SJoshua M. Clulow 	scsa2usbp->scsa2usb_dip		= dip;
7137c478bd9Sstevel@tonic-gate 	scsa2usbp->scsa2usb_instance	= instance;
71447b9747fSJoshua M. Clulow 	/*
71547b9747fSJoshua M. Clulow 	 * Devices begin with all attributes enabled.  Attributes may be
71647b9747fSJoshua M. Clulow 	 * disabled later through detected quirks or through the configuration
71747b9747fSJoshua M. Clulow 	 * file.
71847b9747fSJoshua M. Clulow 	 */
7197c478bd9Sstevel@tonic-gate 	scsa2usbp->scsa2usb_attrs	= SCSA2USB_ALL_ATTRS;
7207c478bd9Sstevel@tonic-gate 	scsa2usbp->scsa2usb_dev_data	= dev_data;
7217c478bd9Sstevel@tonic-gate 
7227c478bd9Sstevel@tonic-gate 	/* save the default pipe handle */
7237c478bd9Sstevel@tonic-gate 	scsa2usbp->scsa2usb_default_pipe = dev_data->dev_default_ph;
7247c478bd9Sstevel@tonic-gate 
7257c478bd9Sstevel@tonic-gate 	/* basic inits are done */
7267c478bd9Sstevel@tonic-gate 	scsa2usbp->scsa2usb_flags |= SCSA2USB_FLAGS_LOCKS_INIT;
7277c478bd9Sstevel@tonic-gate 
7287c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, log_handle,
729112116d8Sfb 	    "curr_cfg=%ld, curr_if=%d",
730112116d8Sfb 	    (long)(dev_data->dev_curr_cfg - &dev_data->dev_cfg[0]),
7317c478bd9Sstevel@tonic-gate 	    dev_data->dev_curr_if);
7327c478bd9Sstevel@tonic-gate 
7337c478bd9Sstevel@tonic-gate 	interface = dev_data->dev_curr_if;
7347c478bd9Sstevel@tonic-gate 	scsa2usbp->scsa2usb_intfc_num = dev_data->dev_curr_if;
7357c478bd9Sstevel@tonic-gate 
7367c478bd9Sstevel@tonic-gate 	/* now find out relevant descriptors for alternate 0 */
7377c478bd9Sstevel@tonic-gate 	altif_data = &dev_data->dev_curr_cfg->cfg_if[interface].if_alt[0];
7387c478bd9Sstevel@tonic-gate 
7397c478bd9Sstevel@tonic-gate 	if (altif_data->altif_n_ep == 0) {
740d291d9f2Sfrits 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, log_handle,
7417c478bd9Sstevel@tonic-gate 		    "invalid alt 0 for interface %d", interface);
7427c478bd9Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
7437c478bd9Sstevel@tonic-gate 
7447c478bd9Sstevel@tonic-gate 		goto fail;
7457c478bd9Sstevel@tonic-gate 	}
7467c478bd9Sstevel@tonic-gate 
7477c478bd9Sstevel@tonic-gate 	/* All CB/CBI, BO devices should have this value set */
7487c478bd9Sstevel@tonic-gate 	if (altif_data->altif_descr.bInterfaceClass !=
7497c478bd9Sstevel@tonic-gate 	    USB_CLASS_MASS_STORAGE) {
750d291d9f2Sfrits 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, log_handle,
7517c478bd9Sstevel@tonic-gate 		    "invalid interface class (0x%x)",
7527c478bd9Sstevel@tonic-gate 		    altif_data->altif_descr.bInterfaceClass);
7537c478bd9Sstevel@tonic-gate 	}
7547c478bd9Sstevel@tonic-gate 	scsa2usbp->scsa2usb_intfc_descr = altif_data->altif_descr;
7557c478bd9Sstevel@tonic-gate 
7567c478bd9Sstevel@tonic-gate 	/* figure out the endpoints and copy the descr */
7577c478bd9Sstevel@tonic-gate 	if ((ep_data = usb_lookup_ep_data(dip, dev_data, interface, 0, 0,
7587c478bd9Sstevel@tonic-gate 	    USB_EP_ATTR_BULK, USB_EP_DIR_OUT)) != NULL) {
759993e3fafSRobert Mustacchi 		if (usb_ep_xdescr_fill(USB_EP_XDESCR_CURRENT_VERSION,
760993e3fafSRobert Mustacchi 		    dip, ep_data, &scsa2usbp->scsa2usb_bulkout_xept) !=
761993e3fafSRobert Mustacchi 		    USB_SUCCESS) {
762993e3fafSRobert Mustacchi 
763993e3fafSRobert Mustacchi 			mutex_exit(&scsa2usbp->scsa2usb_mutex);
764993e3fafSRobert Mustacchi 
765993e3fafSRobert Mustacchi 			goto fail;
766993e3fafSRobert Mustacchi 		}
7677c478bd9Sstevel@tonic-gate 	}
7687c478bd9Sstevel@tonic-gate 	if ((ep_data = usb_lookup_ep_data(dip, dev_data, interface, 0, 0,
7697c478bd9Sstevel@tonic-gate 	    USB_EP_ATTR_BULK, USB_EP_DIR_IN)) != NULL) {
770993e3fafSRobert Mustacchi 		if (usb_ep_xdescr_fill(USB_EP_XDESCR_CURRENT_VERSION,
771993e3fafSRobert Mustacchi 		    dip, ep_data, &scsa2usbp->scsa2usb_bulkin_xept) !=
772993e3fafSRobert Mustacchi 		    USB_SUCCESS) {
773993e3fafSRobert Mustacchi 
774993e3fafSRobert Mustacchi 			mutex_exit(&scsa2usbp->scsa2usb_mutex);
775993e3fafSRobert Mustacchi 
776993e3fafSRobert Mustacchi 			goto fail;
777993e3fafSRobert Mustacchi 		}
7787c478bd9Sstevel@tonic-gate 	}
7797c478bd9Sstevel@tonic-gate 	if ((ep_data = usb_lookup_ep_data(dip, dev_data, interface, 0, 0,
7807c478bd9Sstevel@tonic-gate 	    USB_EP_ATTR_INTR, USB_EP_DIR_IN)) != NULL) {
781993e3fafSRobert Mustacchi 		if (usb_ep_xdescr_fill(USB_EP_XDESCR_CURRENT_VERSION,
782993e3fafSRobert Mustacchi 		    dip, ep_data, &scsa2usbp->scsa2usb_intr_xept) !=
783993e3fafSRobert Mustacchi 		    USB_SUCCESS) {
784993e3fafSRobert Mustacchi 
785993e3fafSRobert Mustacchi 			mutex_exit(&scsa2usbp->scsa2usb_mutex);
786993e3fafSRobert Mustacchi 
787993e3fafSRobert Mustacchi 			goto fail;
788993e3fafSRobert Mustacchi 		}
7897c478bd9Sstevel@tonic-gate 	}
7907c478bd9Sstevel@tonic-gate 
7917c478bd9Sstevel@tonic-gate 	/*
7927c478bd9Sstevel@tonic-gate 	 * check here for protocol and subclass supported by this driver
7937c478bd9Sstevel@tonic-gate 	 *
7947c478bd9Sstevel@tonic-gate 	 * first check if conf file has override values
7957c478bd9Sstevel@tonic-gate 	 * Note: override values are not used if supplied values are legal
7967c478bd9Sstevel@tonic-gate 	 */
7977c478bd9Sstevel@tonic-gate 	scsa2usb_override(scsa2usbp);
7987c478bd9Sstevel@tonic-gate 
7997c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_SCSA, log_handle,
8007c478bd9Sstevel@tonic-gate 	    "protocol=0x%x override=0x%x subclass=0x%x override=0x%x",
8017c478bd9Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_intfc_descr.bInterfaceProtocol,
8027c478bd9Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_protocol_override,
8037c478bd9Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_intfc_descr.bInterfaceSubClass,
8047c478bd9Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_subclass_override);
8057c478bd9Sstevel@tonic-gate 
8067c478bd9Sstevel@tonic-gate 	switch (scsa2usbp->scsa2usb_intfc_descr.bInterfaceProtocol) {
8077c478bd9Sstevel@tonic-gate 	case USB_PROTO_MS_CBI:
8087c478bd9Sstevel@tonic-gate 		scsa2usbp->scsa2usb_cmd_protocol |= SCSA2USB_CB_PROTOCOL;
8097c478bd9Sstevel@tonic-gate 		break;
8107c478bd9Sstevel@tonic-gate 	case USB_PROTO_MS_CBI_WC:
8117c478bd9Sstevel@tonic-gate 		scsa2usbp->scsa2usb_cmd_protocol |= SCSA2USB_CBI_PROTOCOL;
8127c478bd9Sstevel@tonic-gate 		break;
8137c478bd9Sstevel@tonic-gate 	case USB_PROTO_MS_ISD_1999_SILICN:
8147c478bd9Sstevel@tonic-gate 	case USB_PROTO_MS_BULK_ONLY:
8157c478bd9Sstevel@tonic-gate 		scsa2usbp->scsa2usb_cmd_protocol |= SCSA2USB_BULK_ONLY_PROTOCOL;
8167c478bd9Sstevel@tonic-gate 		break;
8177c478bd9Sstevel@tonic-gate 	default:
8187c478bd9Sstevel@tonic-gate 		if (scsa2usbp->scsa2usb_protocol_override) {
8197c478bd9Sstevel@tonic-gate 			scsa2usbp->scsa2usb_cmd_protocol |=
8207c478bd9Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_protocol_override;
821d291d9f2Sfrits 			USB_DPRINTF_L2(DPRINT_MASK_SCSA, log_handle,
8227c478bd9Sstevel@tonic-gate 			    "overriding protocol %x",
8237c478bd9Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_intfc_descr.bInterfaceProtocol);
8247c478bd9Sstevel@tonic-gate 			break;
8257c478bd9Sstevel@tonic-gate 		}
8267c478bd9Sstevel@tonic-gate 
8277c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, log_handle,
8287c478bd9Sstevel@tonic-gate 		    "unsupported protocol = %x",
8297c478bd9Sstevel@tonic-gate 		    scsa2usbp->scsa2usb_intfc_descr.bInterfaceProtocol);
8307c478bd9Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
8317c478bd9Sstevel@tonic-gate 
8327c478bd9Sstevel@tonic-gate 		goto fail;
8337c478bd9Sstevel@tonic-gate 	}
8347c478bd9Sstevel@tonic-gate 
8357c478bd9Sstevel@tonic-gate 	switch (scsa2usbp->scsa2usb_intfc_descr.bInterfaceSubClass) {
8367c478bd9Sstevel@tonic-gate 	case USB_SUBCLS_MS_SCSI:		/* transparent SCSI */
8377c478bd9Sstevel@tonic-gate 		scsa2usbp->scsa2usb_cmd_protocol |= SCSA2USB_SCSI_CMDSET;
8387c478bd9Sstevel@tonic-gate 		break;
8397c478bd9Sstevel@tonic-gate 	case USB_SUBCLS_MS_SFF8020I:
8407c478bd9Sstevel@tonic-gate 	case USB_SUBCLS_MS_SFF8070I:
8417c478bd9Sstevel@tonic-gate 		scsa2usbp->scsa2usb_cmd_protocol |= SCSA2USB_ATAPI_CMDSET;
8427c478bd9Sstevel@tonic-gate 		break;
8437c478bd9Sstevel@tonic-gate 	case USB_SUBCLS_MS_UFI:		/* UFI */
8447c478bd9Sstevel@tonic-gate 		scsa2usbp->scsa2usb_cmd_protocol |= SCSA2USB_UFI_CMDSET;
8457c478bd9Sstevel@tonic-gate 		break;
8467c478bd9Sstevel@tonic-gate 	default:
8477c478bd9Sstevel@tonic-gate 		if (scsa2usbp->scsa2usb_subclass_override) {
8487c478bd9Sstevel@tonic-gate 			scsa2usbp->scsa2usb_cmd_protocol |=
8497c478bd9Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_subclass_override;
850d291d9f2Sfrits 			USB_DPRINTF_L2(DPRINT_MASK_SCSA, log_handle,
8517c478bd9Sstevel@tonic-gate 			    "overriding subclass %x",
8527c478bd9Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_intfc_descr.bInterfaceSubClass);
8537c478bd9Sstevel@tonic-gate 			break;
8547c478bd9Sstevel@tonic-gate 		}
8557c478bd9Sstevel@tonic-gate 
8567c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, log_handle,
8577c478bd9Sstevel@tonic-gate 		    "unsupported subclass = %x",
8587c478bd9Sstevel@tonic-gate 		    scsa2usbp->scsa2usb_intfc_descr.bInterfaceSubClass);
8597c478bd9Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
8607c478bd9Sstevel@tonic-gate 
8617c478bd9Sstevel@tonic-gate 		goto fail;
8627c478bd9Sstevel@tonic-gate 	}
8637c478bd9Sstevel@tonic-gate 
8647c478bd9Sstevel@tonic-gate 	/* check that we have the right set of endpoint descriptors */
8657c478bd9Sstevel@tonic-gate 	if (SCSA2USB_IS_BULK_ONLY(scsa2usbp) || SCSA2USB_IS_CB(scsa2usbp)) {
8667c478bd9Sstevel@tonic-gate 		if ((scsa2usbp->scsa2usb_bulkout_ept.bLength == 0) ||
8677c478bd9Sstevel@tonic-gate 		    (scsa2usbp->scsa2usb_bulkin_ept.bLength == 0)) {
8687c478bd9Sstevel@tonic-gate 			ept_check = B_FALSE;
8697c478bd9Sstevel@tonic-gate 		}
8707c478bd9Sstevel@tonic-gate 	} else if (SCSA2USB_IS_CBI(scsa2usbp)) {
8717c478bd9Sstevel@tonic-gate 		if ((scsa2usbp->scsa2usb_bulkout_ept.bLength == 0) ||
8727c478bd9Sstevel@tonic-gate 		    (scsa2usbp->scsa2usb_bulkin_ept.bLength == 0) ||
8737c478bd9Sstevel@tonic-gate 		    (scsa2usbp->scsa2usb_intr_ept.bLength == 0)) {
8747c478bd9Sstevel@tonic-gate 			ept_check = B_FALSE;
8757c478bd9Sstevel@tonic-gate 		}
8767c478bd9Sstevel@tonic-gate 	}
8777c478bd9Sstevel@tonic-gate 
8787c478bd9Sstevel@tonic-gate 	if (ept_check == B_FALSE) {
879d291d9f2Sfrits 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, log_handle,
8807c478bd9Sstevel@tonic-gate 		    "scsa2usb%d doesn't support minimum required endpoints",
8817c478bd9Sstevel@tonic-gate 		    instance);
8827c478bd9Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
8837c478bd9Sstevel@tonic-gate 
8847c478bd9Sstevel@tonic-gate 		goto fail;
8857c478bd9Sstevel@tonic-gate 	}
8867c478bd9Sstevel@tonic-gate 
88747b9747fSJoshua M. Clulow 	scsa2usb_detect_quirks(scsa2usbp);
8887c478bd9Sstevel@tonic-gate 
8897c478bd9Sstevel@tonic-gate 	/* Print the serial number from the registration data */
8907c478bd9Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_dev_data->dev_serial) {
8917c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(DPRINT_MASK_SCSA,
8927c478bd9Sstevel@tonic-gate 		    scsa2usbp->scsa2usb_log_handle, "Serial Number = %s",
8937c478bd9Sstevel@tonic-gate 		    scsa2usbp->scsa2usb_dev_data->dev_serial);
8947c478bd9Sstevel@tonic-gate 	}
8957c478bd9Sstevel@tonic-gate 
8967c478bd9Sstevel@tonic-gate 	/*
8977c478bd9Sstevel@tonic-gate 	 * Allocate a SCSA transport structure
8987c478bd9Sstevel@tonic-gate 	 */
8997c478bd9Sstevel@tonic-gate 	tran = scsi_hba_tran_alloc(dip, SCSI_HBA_CANSLEEP);
9007c478bd9Sstevel@tonic-gate 	scsa2usbp->scsa2usb_tran = tran;
9017c478bd9Sstevel@tonic-gate 
9027c478bd9Sstevel@tonic-gate 	/*
9037c478bd9Sstevel@tonic-gate 	 * initialize transport structure
9047c478bd9Sstevel@tonic-gate 	 */
9057c478bd9Sstevel@tonic-gate 	tran->tran_hba_private		= scsa2usbp;
9067c478bd9Sstevel@tonic-gate 	tran->tran_tgt_private		= NULL;
9077c478bd9Sstevel@tonic-gate 	tran->tran_tgt_init		= scsa2usb_scsi_tgt_init;
9087c478bd9Sstevel@tonic-gate 	tran->tran_tgt_probe		= scsa2usb_scsi_tgt_probe;
9097c478bd9Sstevel@tonic-gate 	tran->tran_tgt_free		= scsa2usb_scsi_tgt_free;
9107c478bd9Sstevel@tonic-gate 	tran->tran_start		= scsa2usb_scsi_start;
9117c478bd9Sstevel@tonic-gate 	tran->tran_abort		= scsa2usb_scsi_abort;
9127c478bd9Sstevel@tonic-gate 	tran->tran_reset		= scsa2usb_scsi_reset;
9137c478bd9Sstevel@tonic-gate 	tran->tran_getcap		= scsa2usb_scsi_getcap;
9147c478bd9Sstevel@tonic-gate 	tran->tran_setcap		= scsa2usb_scsi_setcap;
9157c478bd9Sstevel@tonic-gate 	tran->tran_init_pkt		= scsa2usb_scsi_init_pkt;
9167c478bd9Sstevel@tonic-gate 	tran->tran_destroy_pkt		= scsa2usb_scsi_destroy_pkt;
9177c478bd9Sstevel@tonic-gate 	tran->tran_dmafree		= NULL;
9187c478bd9Sstevel@tonic-gate 	tran->tran_sync_pkt		= NULL;
9197c478bd9Sstevel@tonic-gate 	tran->tran_reset_notify		= NULL;
9207c478bd9Sstevel@tonic-gate 	tran->tran_get_bus_addr		= NULL;
9217c478bd9Sstevel@tonic-gate 	tran->tran_get_name		= NULL;
9227c478bd9Sstevel@tonic-gate 	tran->tran_quiesce		= NULL;
9237c478bd9Sstevel@tonic-gate 	tran->tran_unquiesce		= NULL;
9247c478bd9Sstevel@tonic-gate 	tran->tran_bus_reset		= NULL;
9257c478bd9Sstevel@tonic-gate 	tran->tran_add_eventcall	= NULL;
9267c478bd9Sstevel@tonic-gate 	tran->tran_get_eventcookie	= NULL;
9277c478bd9Sstevel@tonic-gate 	tran->tran_post_event		= NULL;
9287c478bd9Sstevel@tonic-gate 	tran->tran_remove_eventcall	= NULL;
9297c478bd9Sstevel@tonic-gate 	tran->tran_bus_config		= scsa2usb_scsi_bus_config;
9307c478bd9Sstevel@tonic-gate 	tran->tran_bus_unconfig		= scsa2usb_scsi_bus_unconfig;
9317c478bd9Sstevel@tonic-gate 
9327c478bd9Sstevel@tonic-gate 	/*
9337c478bd9Sstevel@tonic-gate 	 * register with SCSA as an HBA
9347c478bd9Sstevel@tonic-gate 	 * Note that the dma attributes are from parent nexus
9357c478bd9Sstevel@tonic-gate 	 */
9367c478bd9Sstevel@tonic-gate 	if (scsi_hba_attach_setup(dip, usba_get_hc_dma_attr(dip), tran, 0)) {
9377c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, log_handle,
9387c478bd9Sstevel@tonic-gate 		    "scsi_hba_attach_setup failed");
9397c478bd9Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
9407c478bd9Sstevel@tonic-gate 
9417c478bd9Sstevel@tonic-gate 		goto fail;
9427c478bd9Sstevel@tonic-gate 	}
9437c478bd9Sstevel@tonic-gate 
9447c478bd9Sstevel@tonic-gate 	scsa2usbp->scsa2usb_flags |= SCSA2USB_FLAGS_HBA_ATTACH_SETUP;
9457c478bd9Sstevel@tonic-gate 
9467c478bd9Sstevel@tonic-gate 	/* create minor node */
9477c478bd9Sstevel@tonic-gate 	if (ddi_create_minor_node(dip, "scsa2usb", S_IFCHR,
9487c478bd9Sstevel@tonic-gate 	    instance << SCSA2USB_MINOR_INSTANCE_SHIFT,
9497c478bd9Sstevel@tonic-gate 	    DDI_NT_SCSI_NEXUS, 0) != DDI_SUCCESS) {
9507c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
9517c478bd9Sstevel@tonic-gate 		    "scsi_attach: ddi_create_minor_node failed");
9527c478bd9Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
9537c478bd9Sstevel@tonic-gate 
9547c478bd9Sstevel@tonic-gate 		goto fail;
9557c478bd9Sstevel@tonic-gate 	}
9567c478bd9Sstevel@tonic-gate 
9577c478bd9Sstevel@tonic-gate 	/* open pipes and set scsa2usb_flags */
9587c478bd9Sstevel@tonic-gate 	if (scsa2usb_open_usb_pipes(scsa2usbp) == USB_FAILURE) {
9597c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, log_handle,
9607c478bd9Sstevel@tonic-gate 		    "error opening pipes");
9617c478bd9Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
9627c478bd9Sstevel@tonic-gate 
9637c478bd9Sstevel@tonic-gate 		goto fail;
9647c478bd9Sstevel@tonic-gate 	}
9657c478bd9Sstevel@tonic-gate 
9667c478bd9Sstevel@tonic-gate 	/* set default block size. updated after read cap cmd */
9677c478bd9Sstevel@tonic-gate 	for (lun = 0; lun < SCSA2USB_MAX_LUNS; lun++) {
9687c478bd9Sstevel@tonic-gate 		scsa2usbp->scsa2usb_lbasize[lun] = DEV_BSIZE;
9697c478bd9Sstevel@tonic-gate 	}
9707c478bd9Sstevel@tonic-gate 
9717c478bd9Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
9727c478bd9Sstevel@tonic-gate 
9737c478bd9Sstevel@tonic-gate 	/* initialize PANIC callback */
9747c478bd9Sstevel@tonic-gate 	scsa2usb_panic_callb_init(scsa2usbp);
9757c478bd9Sstevel@tonic-gate 
9767c478bd9Sstevel@tonic-gate 	/* finally we are all done 'initializing' the device */
9777c478bd9Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
9787c478bd9Sstevel@tonic-gate 	scsa2usbp->scsa2usb_dev_state = USB_DEV_ONLINE;
9797c478bd9Sstevel@tonic-gate 
9807c478bd9Sstevel@tonic-gate 	/* enable PM, mutex needs to be held across this */
9817c478bd9Sstevel@tonic-gate 	scsa2usb_create_pm_components(dip, scsa2usbp);
9827c478bd9Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
9837c478bd9Sstevel@tonic-gate 
9847c478bd9Sstevel@tonic-gate 	/* register for connect/disconnect events */
9857c478bd9Sstevel@tonic-gate 	if (usb_register_event_cbs(scsa2usbp->scsa2usb_dip, &scsa2usb_events,
9867c478bd9Sstevel@tonic-gate 	    0) != USB_SUCCESS) {
9877c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, log_handle,
9887c478bd9Sstevel@tonic-gate 		    "error cb registering");
9897c478bd9Sstevel@tonic-gate 		goto fail;
9907c478bd9Sstevel@tonic-gate 	}
9917c478bd9Sstevel@tonic-gate 
9927c478bd9Sstevel@tonic-gate 	/* free the dev_data tree, we no longer need it */
9937c478bd9Sstevel@tonic-gate 	usb_free_descr_tree(dip, dev_data);
9947c478bd9Sstevel@tonic-gate 
9957c478bd9Sstevel@tonic-gate 	scsa2usb_pm_idle_component(scsa2usbp);
9967c478bd9Sstevel@tonic-gate 
9977c478bd9Sstevel@tonic-gate 	/* log the conf file override string if there is one */
9987c478bd9Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_override_str) {
999d291d9f2Sfrits 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
10007c478bd9Sstevel@tonic-gate 		    "scsa2usb.conf override: %s",
10017c478bd9Sstevel@tonic-gate 		    scsa2usbp->scsa2usb_override_str);
10027c478bd9Sstevel@tonic-gate 	}
10037c478bd9Sstevel@tonic-gate 
10047c478bd9Sstevel@tonic-gate 	if (usb_owns_device(dip)) {
10057c478bd9Sstevel@tonic-gate 		/* get a ugen handle */
10067c478bd9Sstevel@tonic-gate 		bzero(&usb_ugen_info, sizeof (usb_ugen_info));
10077c478bd9Sstevel@tonic-gate 		usb_ugen_info.usb_ugen_flags = 0;
10087c478bd9Sstevel@tonic-gate 		usb_ugen_info.usb_ugen_minor_node_ugen_bits_mask =
1009d94492edSfb 		    (dev_t)SCSA2USB_MINOR_UGEN_BITS_MASK;
10107c478bd9Sstevel@tonic-gate 		usb_ugen_info.usb_ugen_minor_node_instance_mask =
1011d94492edSfb 		    (dev_t)~SCSA2USB_MINOR_UGEN_BITS_MASK;
10127c478bd9Sstevel@tonic-gate 		scsa2usbp->scsa2usb_ugen_hdl =
1013d94492edSfb 		    usb_ugen_get_hdl(dip, &usb_ugen_info);
10147c478bd9Sstevel@tonic-gate 
10157c478bd9Sstevel@tonic-gate 		if (usb_ugen_attach(scsa2usbp->scsa2usb_ugen_hdl, cmd) !=
10167c478bd9Sstevel@tonic-gate 		    USB_SUCCESS) {
10177c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_SCSA,
10187c478bd9Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
10197c478bd9Sstevel@tonic-gate 			    "usb_ugen_attach failed");
10207c478bd9Sstevel@tonic-gate 
10217c478bd9Sstevel@tonic-gate 			usb_ugen_release_hdl(scsa2usbp->scsa2usb_ugen_hdl);
10227c478bd9Sstevel@tonic-gate 			scsa2usbp->scsa2usb_ugen_hdl = NULL;
10237c478bd9Sstevel@tonic-gate 		}
10247c478bd9Sstevel@tonic-gate 	}
10257c478bd9Sstevel@tonic-gate 
10267c478bd9Sstevel@tonic-gate 	/* report device */
10277c478bd9Sstevel@tonic-gate 	ddi_report_dev(dip);
10287c478bd9Sstevel@tonic-gate 
10297c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
10307c478bd9Sstevel@tonic-gate 
10317c478bd9Sstevel@tonic-gate fail:
10327c478bd9Sstevel@tonic-gate 	if (scsa2usbp) {
10337c478bd9Sstevel@tonic-gate 		(void) scsa2usb_cleanup(dip, scsa2usbp);
10347c478bd9Sstevel@tonic-gate 	}
10357c478bd9Sstevel@tonic-gate 
10367c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
10377c478bd9Sstevel@tonic-gate }
10387c478bd9Sstevel@tonic-gate 
10397c478bd9Sstevel@tonic-gate 
10407c478bd9Sstevel@tonic-gate /*
10417c478bd9Sstevel@tonic-gate  * scsa2usb_detach:
10427c478bd9Sstevel@tonic-gate  *	detach or suspend driver instance
10437c478bd9Sstevel@tonic-gate  */
10447c478bd9Sstevel@tonic-gate static int
scsa2usb_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)10457c478bd9Sstevel@tonic-gate scsa2usb_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
10467c478bd9Sstevel@tonic-gate {
10477c478bd9Sstevel@tonic-gate 	scsi_hba_tran_t	*tran;
10487c478bd9Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp;
10497c478bd9Sstevel@tonic-gate 	int rval;
10507c478bd9Sstevel@tonic-gate 
10517c478bd9Sstevel@tonic-gate 	tran = ddi_get_driver_private(dip);
10527c478bd9Sstevel@tonic-gate 	ASSERT(tran != NULL);
10537c478bd9Sstevel@tonic-gate 
10547c478bd9Sstevel@tonic-gate 	scsa2usbp = (scsa2usb_state_t *)tran->tran_hba_private;
10557c478bd9Sstevel@tonic-gate 	ASSERT(scsa2usbp);
10567c478bd9Sstevel@tonic-gate 
10577c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
1058112116d8Sfb 	    "scsa2usb_detach: dip = 0x%p, cmd = %d", (void *)dip, cmd);
10597c478bd9Sstevel@tonic-gate 
10607c478bd9Sstevel@tonic-gate 	switch (cmd) {
10617c478bd9Sstevel@tonic-gate 	case DDI_DETACH:
10627c478bd9Sstevel@tonic-gate 
10637c478bd9Sstevel@tonic-gate 		if (scsa2usb_cleanup(dip, scsa2usbp) != USB_SUCCESS) {
10647c478bd9Sstevel@tonic-gate 
10657c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
10667c478bd9Sstevel@tonic-gate 		}
10677c478bd9Sstevel@tonic-gate 
10687c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
10697c478bd9Sstevel@tonic-gate 	case DDI_SUSPEND:
10707c478bd9Sstevel@tonic-gate 		rval = scsa2usb_cpr_suspend(dip);
10717c478bd9Sstevel@tonic-gate 
10727c478bd9Sstevel@tonic-gate 		return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
10737c478bd9Sstevel@tonic-gate 	default:
10747c478bd9Sstevel@tonic-gate 
10757c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
10767c478bd9Sstevel@tonic-gate 	}
10777c478bd9Sstevel@tonic-gate }
10787c478bd9Sstevel@tonic-gate 
10797c478bd9Sstevel@tonic-gate /*
10807c478bd9Sstevel@tonic-gate  * ugen support
10817c478bd9Sstevel@tonic-gate  */
10827c478bd9Sstevel@tonic-gate /*
10837c478bd9Sstevel@tonic-gate  * scsa2usb_ugen_open()
10847c478bd9Sstevel@tonic-gate  * (all ugen opens and pipe opens are by definition exclusive so it is OK
10857c478bd9Sstevel@tonic-gate  * to count opens)
10867c478bd9Sstevel@tonic-gate  */
10877c478bd9Sstevel@tonic-gate static int
scsa2usb_ugen_open(dev_t * devp,int flag,int sflag,cred_t * cr)10887c478bd9Sstevel@tonic-gate scsa2usb_ugen_open(dev_t *devp, int flag, int sflag, cred_t *cr)
10897c478bd9Sstevel@tonic-gate {
10907c478bd9Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp;
10917c478bd9Sstevel@tonic-gate 	int		rval;
10927c478bd9Sstevel@tonic-gate 
10937c478bd9Sstevel@tonic-gate 	if ((scsa2usbp = ddi_get_soft_state(scsa2usb_statep,
10947c478bd9Sstevel@tonic-gate 	    SCSA2USB_MINOR_TO_INSTANCE(getminor(*devp)))) == NULL) {
10957c478bd9Sstevel@tonic-gate 		/* deferred detach */
10967c478bd9Sstevel@tonic-gate 
10977c478bd9Sstevel@tonic-gate 		return (ENXIO);
10987c478bd9Sstevel@tonic-gate 	}
10997c478bd9Sstevel@tonic-gate 
11007c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
11017c478bd9Sstevel@tonic-gate 	    "scsa2usb_ugen_open: dev_t=0x%lx", *devp);
11027c478bd9Sstevel@tonic-gate 
11037c478bd9Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
11047c478bd9Sstevel@tonic-gate 
11057c478bd9Sstevel@tonic-gate 	/* if this is the first ugen open, check on transport busy */
110642cac157SVincent Wang 	if (scsa2usbp->scsa2usb_busy_proc != curproc) {
11077c478bd9Sstevel@tonic-gate 		while (scsa2usbp->scsa2usb_transport_busy ||
11087c478bd9Sstevel@tonic-gate 		    (scsa2usb_all_waitQs_empty(scsa2usbp) !=
11097c478bd9Sstevel@tonic-gate 		    USB_SUCCESS)) {
11107c478bd9Sstevel@tonic-gate 			rval = cv_wait_sig(
1111d94492edSfb 			    &scsa2usbp->scsa2usb_transport_busy_cv,
1112d94492edSfb 			    &scsa2usbp->scsa2usb_mutex);
11137c478bd9Sstevel@tonic-gate 			if (rval == 0) {
11147c478bd9Sstevel@tonic-gate 				mutex_exit(&scsa2usbp->scsa2usb_mutex);
11157c478bd9Sstevel@tonic-gate 
11167c478bd9Sstevel@tonic-gate 				return (EINTR);
11177c478bd9Sstevel@tonic-gate 			}
11187c478bd9Sstevel@tonic-gate 		}
11197c478bd9Sstevel@tonic-gate 		scsa2usbp->scsa2usb_transport_busy++;
112042cac157SVincent Wang 		scsa2usbp->scsa2usb_busy_proc = curproc;
11217c478bd9Sstevel@tonic-gate 	}
112242cac157SVincent Wang 
11237c478bd9Sstevel@tonic-gate 	scsa2usbp->scsa2usb_ugen_open_count++;
11247c478bd9Sstevel@tonic-gate 
11257c478bd9Sstevel@tonic-gate 	scsa2usb_raise_power(scsa2usbp);
11267c478bd9Sstevel@tonic-gate 
11277c478bd9Sstevel@tonic-gate 	scsa2usb_close_usb_pipes(scsa2usbp);
11287c478bd9Sstevel@tonic-gate 
11297c478bd9Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
11307c478bd9Sstevel@tonic-gate 
11317c478bd9Sstevel@tonic-gate 	rval = usb_ugen_open(scsa2usbp->scsa2usb_ugen_hdl, devp, flag,
1132d94492edSfb 	    sflag, cr);
113342cac157SVincent Wang 	if (!rval) {
113442cac157SVincent Wang 		/*
113542cac157SVincent Wang 		 * if usb_ugen_open() succeeded, we'll change the minor number
113642cac157SVincent Wang 		 * so that we can keep track of every open()/close() issued by
113742cac157SVincent Wang 		 * the userland processes. We need to pick a minor number that
113842cac157SVincent Wang 		 * is not used by the ugen framework
113942cac157SVincent Wang 		 */
114042cac157SVincent Wang 
114142cac157SVincent Wang 		usb_ugen_hdl_impl_t	*usb_ugen_hdl_impl;
114242cac157SVincent Wang 		ugen_state_t		*ugenp;
114342cac157SVincent Wang 		int			ugen_minor, clone;
114442cac157SVincent Wang 
114542cac157SVincent Wang 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
114642cac157SVincent Wang 
114742cac157SVincent Wang 		usb_ugen_hdl_impl =
114842cac157SVincent Wang 		    (usb_ugen_hdl_impl_t *)scsa2usbp->scsa2usb_ugen_hdl;
114942cac157SVincent Wang 		ugenp =  usb_ugen_hdl_impl->hdl_ugenp;
115042cac157SVincent Wang 
115142cac157SVincent Wang 		/* 'clone' is bigger than any ugen minor in use */
115242cac157SVincent Wang 		for (clone = ugenp->ug_minor_node_table_index + 1;
115342cac157SVincent Wang 		    clone < SCSA2USB_MAX_CLONE; clone++) {
115442cac157SVincent Wang 			if (!scsa2usbp->scsa2usb_clones[clone])
115542cac157SVincent Wang 				break;
115642cac157SVincent Wang 		}
115742cac157SVincent Wang 
115842cac157SVincent Wang 		if (clone >= SCSA2USB_MAX_CLONE) {
115942cac157SVincent Wang 			cmn_err(CE_WARN, "scsa2usb_ugen_open: too many clones");
116042cac157SVincent Wang 			rval = EBUSY;
116142cac157SVincent Wang 			mutex_exit(&scsa2usbp->scsa2usb_mutex);
116242cac157SVincent Wang 			goto open_done;
116342cac157SVincent Wang 		}
116442cac157SVincent Wang 
116542cac157SVincent Wang 		ugen_minor = getminor(*devp) & SCSA2USB_MINOR_UGEN_BITS_MASK;
116642cac157SVincent Wang 		*devp = makedevice(getmajor(*devp),
116742cac157SVincent Wang 		    (scsa2usbp->scsa2usb_instance
116842cac157SVincent Wang 		    << SCSA2USB_MINOR_INSTANCE_SHIFT)
116942cac157SVincent Wang 		    + clone);
117042cac157SVincent Wang 
117142cac157SVincent Wang 		/* save the ugen minor */
117242cac157SVincent Wang 		scsa2usbp->scsa2usb_clones[clone] = (uint8_t)ugen_minor;
117342cac157SVincent Wang 		USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
117442cac157SVincent Wang 		    "scsa2usb_ugen_open: new dev=%lx, old minor=%x",
117542cac157SVincent Wang 		    *devp, ugen_minor);
117642cac157SVincent Wang 
117742cac157SVincent Wang 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
117842cac157SVincent Wang 	}
117942cac157SVincent Wang 
118042cac157SVincent Wang open_done:
11817c478bd9Sstevel@tonic-gate 
11827c478bd9Sstevel@tonic-gate 	if (rval) {
11837c478bd9Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
11847c478bd9Sstevel@tonic-gate 
11857c478bd9Sstevel@tonic-gate 		/* reopen the pipes */
11867c478bd9Sstevel@tonic-gate 		if (--scsa2usbp->scsa2usb_ugen_open_count == 0) {
11877c478bd9Sstevel@tonic-gate 			scsa2usbp->scsa2usb_transport_busy--;
118842cac157SVincent Wang 			scsa2usbp->scsa2usb_busy_proc = NULL;
11897c478bd9Sstevel@tonic-gate 			cv_signal(&scsa2usbp->scsa2usb_transport_busy_cv);
11907c478bd9Sstevel@tonic-gate 		}
11917c478bd9Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
1192496d8c83Sfrits 
1193496d8c83Sfrits 		scsa2usb_pm_idle_component(scsa2usbp);
11947c478bd9Sstevel@tonic-gate 	}
11957c478bd9Sstevel@tonic-gate 
11967c478bd9Sstevel@tonic-gate 	return (rval);
11977c478bd9Sstevel@tonic-gate }
11987c478bd9Sstevel@tonic-gate 
11997c478bd9Sstevel@tonic-gate 
12007c478bd9Sstevel@tonic-gate /*
12017c478bd9Sstevel@tonic-gate  * scsa2usb_ugen_close()
12027c478bd9Sstevel@tonic-gate  */
12037c478bd9Sstevel@tonic-gate static int
scsa2usb_ugen_close(dev_t dev,int flag,int otype,cred_t * cr)12047c478bd9Sstevel@tonic-gate scsa2usb_ugen_close(dev_t dev, int flag, int otype, cred_t *cr)
12057c478bd9Sstevel@tonic-gate {
12067c478bd9Sstevel@tonic-gate 	int rval;
120742cac157SVincent Wang 	int	ugen_minor, clone;
12087c478bd9Sstevel@tonic-gate 
12097c478bd9Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp = ddi_get_soft_state(scsa2usb_statep,
1210d94492edSfb 	    SCSA2USB_MINOR_TO_INSTANCE(getminor(dev)));
12117c478bd9Sstevel@tonic-gate 
12127c478bd9Sstevel@tonic-gate 	if (scsa2usbp == NULL) {
12137c478bd9Sstevel@tonic-gate 
12147c478bd9Sstevel@tonic-gate 		return (ENXIO);
12157c478bd9Sstevel@tonic-gate 	}
12167c478bd9Sstevel@tonic-gate 
12177c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
12187c478bd9Sstevel@tonic-gate 	    "scsa2usb_ugen_close: dev_t=0x%lx", dev);
12197c478bd9Sstevel@tonic-gate 
122042cac157SVincent Wang 	clone = getminor(dev) & SCSA2USB_MINOR_UGEN_BITS_MASK;
122142cac157SVincent Wang 	ugen_minor = scsa2usbp->scsa2usb_clones[clone];
122242cac157SVincent Wang 	dev = makedevice(getmajor(dev),
122342cac157SVincent Wang 	    (scsa2usbp->scsa2usb_instance << SCSA2USB_MINOR_INSTANCE_SHIFT)
122442cac157SVincent Wang 	    + ugen_minor);
122542cac157SVincent Wang 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
122642cac157SVincent Wang 	    "scsa2usb_ugen_close: old dev=%lx", dev);
12277c478bd9Sstevel@tonic-gate 	rval = usb_ugen_close(scsa2usbp->scsa2usb_ugen_hdl, dev, flag,
1228d94492edSfb 	    otype, cr);
12297c478bd9Sstevel@tonic-gate 
12307c478bd9Sstevel@tonic-gate 	if (rval == 0) {
12317c478bd9Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
12327c478bd9Sstevel@tonic-gate 
123342cac157SVincent Wang 		scsa2usbp->scsa2usb_clones[clone] = 0;
12347c478bd9Sstevel@tonic-gate 		/* reopen the pipes */
12357c478bd9Sstevel@tonic-gate 		if (--scsa2usbp->scsa2usb_ugen_open_count == 0) {
12367c478bd9Sstevel@tonic-gate 			scsa2usbp->scsa2usb_transport_busy--;
123742cac157SVincent Wang 			scsa2usbp->scsa2usb_busy_proc = NULL;
12387c478bd9Sstevel@tonic-gate 			cv_signal(&scsa2usbp->scsa2usb_transport_busy_cv);
12397c478bd9Sstevel@tonic-gate 		}
12407c478bd9Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
1241496d8c83Sfrits 
1242496d8c83Sfrits 		scsa2usb_pm_idle_component(scsa2usbp);
12437c478bd9Sstevel@tonic-gate 	}
12447c478bd9Sstevel@tonic-gate 
12457c478bd9Sstevel@tonic-gate 	return (rval);
12467c478bd9Sstevel@tonic-gate }
12477c478bd9Sstevel@tonic-gate 
12487c478bd9Sstevel@tonic-gate 
12497c478bd9Sstevel@tonic-gate /*
12507c478bd9Sstevel@tonic-gate  * scsa2usb_ugen_read/write()
12517c478bd9Sstevel@tonic-gate  */
12527c478bd9Sstevel@tonic-gate /*ARGSUSED*/
12537c478bd9Sstevel@tonic-gate static int
scsa2usb_ugen_read(dev_t dev,struct uio * uiop,cred_t * credp)12547c478bd9Sstevel@tonic-gate scsa2usb_ugen_read(dev_t dev, struct uio *uiop, cred_t *credp)
12557c478bd9Sstevel@tonic-gate {
125642cac157SVincent Wang 	int clone, ugen_minor;
12577c478bd9Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp = ddi_get_soft_state(scsa2usb_statep,
1258d94492edSfb 	    SCSA2USB_MINOR_TO_INSTANCE(getminor(dev)));
12597c478bd9Sstevel@tonic-gate 
12607c478bd9Sstevel@tonic-gate 	if (scsa2usbp == NULL) {
12617c478bd9Sstevel@tonic-gate 
12627c478bd9Sstevel@tonic-gate 		return (ENXIO);
12637c478bd9Sstevel@tonic-gate 	}
12647c478bd9Sstevel@tonic-gate 
12657c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
12667c478bd9Sstevel@tonic-gate 	    "scsa2usb_ugen_read: dev_t=0x%lx", dev);
12677c478bd9Sstevel@tonic-gate 
126842cac157SVincent Wang 	clone = getminor(dev) & SCSA2USB_MINOR_UGEN_BITS_MASK;
126942cac157SVincent Wang 	ugen_minor = scsa2usbp->scsa2usb_clones[clone];
127042cac157SVincent Wang 	dev = makedevice(getmajor(dev),
127142cac157SVincent Wang 	    (scsa2usbp->scsa2usb_instance << SCSA2USB_MINOR_INSTANCE_SHIFT)
127242cac157SVincent Wang 	    + ugen_minor);
12737c478bd9Sstevel@tonic-gate 
12747c478bd9Sstevel@tonic-gate 	return (usb_ugen_read(scsa2usbp->scsa2usb_ugen_hdl, dev,
1275d94492edSfb 	    uiop, credp));
12767c478bd9Sstevel@tonic-gate }
12777c478bd9Sstevel@tonic-gate 
12787c478bd9Sstevel@tonic-gate 
12797c478bd9Sstevel@tonic-gate /*ARGSUSED*/
12807c478bd9Sstevel@tonic-gate static int
scsa2usb_ugen_write(dev_t dev,struct uio * uiop,cred_t * credp)12817c478bd9Sstevel@tonic-gate scsa2usb_ugen_write(dev_t dev, struct uio *uiop, cred_t *credp)
12827c478bd9Sstevel@tonic-gate {
128342cac157SVincent Wang 	int clone, ugen_minor;
12847c478bd9Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp = ddi_get_soft_state(scsa2usb_statep,
1285d94492edSfb 	    SCSA2USB_MINOR_TO_INSTANCE(getminor(dev)));
12867c478bd9Sstevel@tonic-gate 
12877c478bd9Sstevel@tonic-gate 	if (scsa2usbp == NULL) {
12887c478bd9Sstevel@tonic-gate 
12897c478bd9Sstevel@tonic-gate 		return (ENXIO);
12907c478bd9Sstevel@tonic-gate 	}
12917c478bd9Sstevel@tonic-gate 
12927c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
12937c478bd9Sstevel@tonic-gate 	    "scsa2usb_ugen_write: dev_t=0x%lx", dev);
12947c478bd9Sstevel@tonic-gate 
129542cac157SVincent Wang 	clone = getminor(dev) & SCSA2USB_MINOR_UGEN_BITS_MASK;
129642cac157SVincent Wang 	ugen_minor = scsa2usbp->scsa2usb_clones[clone];
129742cac157SVincent Wang 	dev = makedevice(getmajor(dev),
129842cac157SVincent Wang 	    (scsa2usbp->scsa2usb_instance << SCSA2USB_MINOR_INSTANCE_SHIFT)
129942cac157SVincent Wang 	    + ugen_minor);
130042cac157SVincent Wang 
13017c478bd9Sstevel@tonic-gate 	return (usb_ugen_write(scsa2usbp->scsa2usb_ugen_hdl,
1302d94492edSfb 	    dev, uiop, credp));
13037c478bd9Sstevel@tonic-gate }
13047c478bd9Sstevel@tonic-gate 
13057c478bd9Sstevel@tonic-gate 
13067c478bd9Sstevel@tonic-gate /*
13077c478bd9Sstevel@tonic-gate  * scsa2usb_ugen_poll
13087c478bd9Sstevel@tonic-gate  */
13097c478bd9Sstevel@tonic-gate static int
scsa2usb_ugen_poll(dev_t dev,short events,int anyyet,short * reventsp,struct pollhead ** phpp)13107c478bd9Sstevel@tonic-gate scsa2usb_ugen_poll(dev_t dev, short events,
13117c478bd9Sstevel@tonic-gate     int anyyet,  short *reventsp, struct pollhead **phpp)
13127c478bd9Sstevel@tonic-gate {
131342cac157SVincent Wang 	int clone, ugen_minor;
13147c478bd9Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp = ddi_get_soft_state(scsa2usb_statep,
1315d94492edSfb 	    SCSA2USB_MINOR_TO_INSTANCE(getminor(dev)));
13167c478bd9Sstevel@tonic-gate 
13177c478bd9Sstevel@tonic-gate 	if (scsa2usbp == NULL) {
13187c478bd9Sstevel@tonic-gate 
13197c478bd9Sstevel@tonic-gate 		return (ENXIO);
13207c478bd9Sstevel@tonic-gate 	}
13217c478bd9Sstevel@tonic-gate 
13227c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
13237c478bd9Sstevel@tonic-gate 	    "scsa2usb_ugen_poll: dev_t=0x%lx", dev);
13247c478bd9Sstevel@tonic-gate 
132542cac157SVincent Wang 	clone = getminor(dev) & SCSA2USB_MINOR_UGEN_BITS_MASK;
132642cac157SVincent Wang 	ugen_minor = scsa2usbp->scsa2usb_clones[clone];
132742cac157SVincent Wang 	dev = makedevice(getmajor(dev),
132842cac157SVincent Wang 	    (scsa2usbp->scsa2usb_instance << SCSA2USB_MINOR_INSTANCE_SHIFT)
132942cac157SVincent Wang 	    + ugen_minor);
133042cac157SVincent Wang 
13317c478bd9Sstevel@tonic-gate 	return (usb_ugen_poll(scsa2usbp->scsa2usb_ugen_hdl, dev, events,
1332d94492edSfb 	    anyyet, reventsp, phpp));
13337c478bd9Sstevel@tonic-gate }
13347c478bd9Sstevel@tonic-gate 
13357c478bd9Sstevel@tonic-gate 
13367c478bd9Sstevel@tonic-gate /*
13377c478bd9Sstevel@tonic-gate  * scsa2usb_cleanup:
13387c478bd9Sstevel@tonic-gate  *	cleanup whatever attach has setup
13397c478bd9Sstevel@tonic-gate  */
13407c478bd9Sstevel@tonic-gate static int
scsa2usb_cleanup(dev_info_t * dip,scsa2usb_state_t * scsa2usbp)13417c478bd9Sstevel@tonic-gate scsa2usb_cleanup(dev_info_t *dip, scsa2usb_state_t *scsa2usbp)
13427c478bd9Sstevel@tonic-gate {
13437c478bd9Sstevel@tonic-gate 	int		rval, i;
13447c478bd9Sstevel@tonic-gate 	scsa2usb_power_t *pm;
13457c478bd9Sstevel@tonic-gate 	uint_t		lun;
13467c478bd9Sstevel@tonic-gate 
13477c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
13487c478bd9Sstevel@tonic-gate 	    "scsa2usb_cleanup:");
13497c478bd9Sstevel@tonic-gate 
13507c478bd9Sstevel@tonic-gate 	/* wait till the work thread is done */
13517c478bd9Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
13527c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCSA2USB_DRAIN_TIMEOUT; i++) {
13537c478bd9Sstevel@tonic-gate 		if (scsa2usbp->scsa2usb_work_thread_id == NULL) {
13547c478bd9Sstevel@tonic-gate 
13557c478bd9Sstevel@tonic-gate 			break;
13567c478bd9Sstevel@tonic-gate 		}
13577c478bd9Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
13587c478bd9Sstevel@tonic-gate 		delay(drv_usectohz(1000000));
13597c478bd9Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
13607c478bd9Sstevel@tonic-gate 	}
13617c478bd9Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
13627c478bd9Sstevel@tonic-gate 
13637c478bd9Sstevel@tonic-gate 	if (i >= SCSA2USB_DRAIN_TIMEOUT) {
13647c478bd9Sstevel@tonic-gate 
13657c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
13667c478bd9Sstevel@tonic-gate 	}
13677c478bd9Sstevel@tonic-gate 
13687c478bd9Sstevel@tonic-gate 	/*
13697c478bd9Sstevel@tonic-gate 	 * Disable the event callbacks first, after this point, event
13707c478bd9Sstevel@tonic-gate 	 * callbacks will never get called. Note we shouldn't hold
13717c478bd9Sstevel@tonic-gate 	 * mutex while unregistering events because there may be a
13727c478bd9Sstevel@tonic-gate 	 * competing event callback thread. Event callbacks are done
13737c478bd9Sstevel@tonic-gate 	 * with ndi mutex held and this can cause a potential deadlock.
13747c478bd9Sstevel@tonic-gate 	 */
13757c478bd9Sstevel@tonic-gate 	usb_unregister_event_cbs(scsa2usbp->scsa2usb_dip, &scsa2usb_events);
13767c478bd9Sstevel@tonic-gate 
13777c478bd9Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_flags & SCSA2USB_FLAGS_LOCKS_INIT) {
13787c478bd9Sstevel@tonic-gate 		/*
13797c478bd9Sstevel@tonic-gate 		 * if a waitQ exists, get rid of it before destroying it
13807c478bd9Sstevel@tonic-gate 		 */
13817c478bd9Sstevel@tonic-gate 		for (lun = 0; lun < SCSA2USB_MAX_LUNS; lun++) {
13827c478bd9Sstevel@tonic-gate 			scsa2usb_flush_waitQ(scsa2usbp, lun, CMD_TRAN_ERR);
13837c478bd9Sstevel@tonic-gate 			usba_destroy_list(&scsa2usbp->scsa2usb_waitQ[lun]);
13847c478bd9Sstevel@tonic-gate 		}
13857c478bd9Sstevel@tonic-gate 
13867c478bd9Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
13877c478bd9Sstevel@tonic-gate 		if (scsa2usbp->scsa2usb_flags &
13887c478bd9Sstevel@tonic-gate 		    SCSA2USB_FLAGS_HBA_ATTACH_SETUP) {
13897c478bd9Sstevel@tonic-gate 			(void) scsi_hba_detach(dip);
13907c478bd9Sstevel@tonic-gate 			scsi_hba_tran_free(scsa2usbp->scsa2usb_tran);
13917c478bd9Sstevel@tonic-gate 		}
13927c478bd9Sstevel@tonic-gate 
13937c478bd9Sstevel@tonic-gate 		if (scsa2usbp->scsa2usb_flags &
13947c478bd9Sstevel@tonic-gate 		    SCSA2USB_FLAGS_PIPES_OPENED) {
13957c478bd9Sstevel@tonic-gate 			scsa2usb_close_usb_pipes(scsa2usbp);
13967c478bd9Sstevel@tonic-gate 		}
13977c478bd9Sstevel@tonic-gate 
13987c478bd9Sstevel@tonic-gate 		/* Lower the power */
13997c478bd9Sstevel@tonic-gate 		pm = scsa2usbp->scsa2usb_pm;
14007c478bd9Sstevel@tonic-gate 
14017c478bd9Sstevel@tonic-gate 		if (pm && (scsa2usbp->scsa2usb_dev_state !=
14027c478bd9Sstevel@tonic-gate 		    USB_DEV_DISCONNECTED)) {
14037c478bd9Sstevel@tonic-gate 			if (pm->scsa2usb_wakeup_enabled) {
14047c478bd9Sstevel@tonic-gate 				mutex_exit(&scsa2usbp->scsa2usb_mutex);
14057c478bd9Sstevel@tonic-gate 				(void) pm_raise_power(dip, 0,
1406d94492edSfb 				    USB_DEV_OS_FULL_PWR);
14077c478bd9Sstevel@tonic-gate 
14087c478bd9Sstevel@tonic-gate 				if ((rval = usb_handle_remote_wakeup(dip,
14097c478bd9Sstevel@tonic-gate 				    USB_REMOTE_WAKEUP_DISABLE)) !=
14107c478bd9Sstevel@tonic-gate 				    USB_SUCCESS) {
1411d291d9f2Sfrits 					USB_DPRINTF_L2(DPRINT_MASK_SCSA,
14127c478bd9Sstevel@tonic-gate 					    scsa2usbp->scsa2usb_log_handle,
14137c478bd9Sstevel@tonic-gate 					    "disable remote wakeup failed "
14147c478bd9Sstevel@tonic-gate 					    "(%d)", rval);
14157c478bd9Sstevel@tonic-gate 				}
14167c478bd9Sstevel@tonic-gate 			} else {
14177c478bd9Sstevel@tonic-gate 				mutex_exit(&scsa2usbp->scsa2usb_mutex);
14187c478bd9Sstevel@tonic-gate 			}
14197c478bd9Sstevel@tonic-gate 
14207c478bd9Sstevel@tonic-gate 			(void) pm_lower_power(dip, 0, USB_DEV_OS_PWR_OFF);
14217c478bd9Sstevel@tonic-gate 
14227c478bd9Sstevel@tonic-gate 			mutex_enter(&scsa2usbp->scsa2usb_mutex);
14237c478bd9Sstevel@tonic-gate 		}
14247c478bd9Sstevel@tonic-gate 
14257c478bd9Sstevel@tonic-gate 		if (pm) {
14267c478bd9Sstevel@tonic-gate 			kmem_free(pm, sizeof (scsa2usb_power_t));
14277c478bd9Sstevel@tonic-gate 		}
14287c478bd9Sstevel@tonic-gate 
14297c478bd9Sstevel@tonic-gate 		if (scsa2usbp->scsa2usb_override_str) {
14307c478bd9Sstevel@tonic-gate 			kmem_free(scsa2usbp->scsa2usb_override_str,
14317c478bd9Sstevel@tonic-gate 			    strlen(scsa2usbp->scsa2usb_override_str) + 1);
14327c478bd9Sstevel@tonic-gate 			scsa2usbp->scsa2usb_override_str = NULL;
14337c478bd9Sstevel@tonic-gate 		}
14347c478bd9Sstevel@tonic-gate 
14357c478bd9Sstevel@tonic-gate 		/* remove the minor nodes */
14367c478bd9Sstevel@tonic-gate 		ddi_remove_minor_node(dip, NULL);
14377c478bd9Sstevel@tonic-gate 
14387c478bd9Sstevel@tonic-gate 		/* Cancel the registered panic callback */
14397c478bd9Sstevel@tonic-gate 		scsa2usb_panic_callb_fini(scsa2usbp);
14407c478bd9Sstevel@tonic-gate 
14417c478bd9Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
14427c478bd9Sstevel@tonic-gate 
14437c478bd9Sstevel@tonic-gate 		mutex_destroy(&scsa2usbp->scsa2usb_mutex);
14447c478bd9Sstevel@tonic-gate 		cv_destroy(&scsa2usbp->scsa2usb_transport_busy_cv);
14457c478bd9Sstevel@tonic-gate 	}
14467c478bd9Sstevel@tonic-gate 
14477c478bd9Sstevel@tonic-gate 	usb_client_detach(scsa2usbp->scsa2usb_dip,
1448d94492edSfb 	    scsa2usbp->scsa2usb_dev_data);
14497c478bd9Sstevel@tonic-gate 
14507c478bd9Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_ugen_hdl) {
14517c478bd9Sstevel@tonic-gate 		(void) usb_ugen_detach(scsa2usbp->scsa2usb_ugen_hdl,
1452d94492edSfb 		    DDI_DETACH);
14537c478bd9Sstevel@tonic-gate 		usb_ugen_release_hdl(scsa2usbp->scsa2usb_ugen_hdl);
14547c478bd9Sstevel@tonic-gate 	}
14557c478bd9Sstevel@tonic-gate 
14567c478bd9Sstevel@tonic-gate 	usb_free_log_hdl(scsa2usbp->scsa2usb_log_handle);
14577c478bd9Sstevel@tonic-gate 
14587c478bd9Sstevel@tonic-gate 	ddi_prop_remove_all(dip);
14597c478bd9Sstevel@tonic-gate 
14607c478bd9Sstevel@tonic-gate 	ddi_soft_state_free(scsa2usb_statep, ddi_get_instance(dip));
14617c478bd9Sstevel@tonic-gate 
14627c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
14637c478bd9Sstevel@tonic-gate }
14647c478bd9Sstevel@tonic-gate 
14657c478bd9Sstevel@tonic-gate 
14667c478bd9Sstevel@tonic-gate /*
14677c478bd9Sstevel@tonic-gate  * scsa2usb_override:
14687c478bd9Sstevel@tonic-gate  *	some devices may be attached even though their subclass or
14697c478bd9Sstevel@tonic-gate  *	protocol info is not according to spec.
14707c478bd9Sstevel@tonic-gate  *	these can be determined by the 'subclass-protocol-override'
14717c478bd9Sstevel@tonic-gate  *	property set in the conf file.
14727c478bd9Sstevel@tonic-gate  */
14737c478bd9Sstevel@tonic-gate static void
scsa2usb_override(scsa2usb_state_t * scsa2usbp)14747c478bd9Sstevel@tonic-gate scsa2usb_override(scsa2usb_state_t *scsa2usbp)
14757c478bd9Sstevel@tonic-gate {
14767c478bd9Sstevel@tonic-gate 	scsa2usb_ov_t ov;
14777c478bd9Sstevel@tonic-gate 	char	**override_str = NULL;
14787c478bd9Sstevel@tonic-gate 	char	*override_str_cpy;
14797c478bd9Sstevel@tonic-gate 	uint_t	override_str_len, override_str_cpy_len;
14807c478bd9Sstevel@tonic-gate 	uint_t	i;
14817c478bd9Sstevel@tonic-gate 	usb_dev_descr_t *descr = scsa2usbp->scsa2usb_dev_data->dev_descr;
14827c478bd9Sstevel@tonic-gate 
14837c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
14847c478bd9Sstevel@tonic-gate 
14857c478bd9Sstevel@tonic-gate 	scsa2usbp->scsa2usb_subclass_override =
14867c478bd9Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_protocol_override = 0;
14877c478bd9Sstevel@tonic-gate 
14887c478bd9Sstevel@tonic-gate 	if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, scsa2usbp->scsa2usb_dip,
14897c478bd9Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "attribute-override-list",
14907c478bd9Sstevel@tonic-gate 	    &override_str, &override_str_len) != DDI_PROP_SUCCESS) {
14917c478bd9Sstevel@tonic-gate 
14927c478bd9Sstevel@tonic-gate 		return;
14937c478bd9Sstevel@tonic-gate 	}
14947c478bd9Sstevel@tonic-gate 
14957c478bd9Sstevel@tonic-gate 	/* parse each string in the subclass-protocol-override property */
14967c478bd9Sstevel@tonic-gate 	for (i = 0; i < override_str_len; i++) {
14977c478bd9Sstevel@tonic-gate 
14987c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
14997c478bd9Sstevel@tonic-gate 		    "override_str[%d] = %s", i, override_str[i]);
15007c478bd9Sstevel@tonic-gate 
15017c478bd9Sstevel@tonic-gate 		/*
15027c478bd9Sstevel@tonic-gate 		 * save a copy of the override string for possible
15037c478bd9Sstevel@tonic-gate 		 * inclusion in soft state later
15047c478bd9Sstevel@tonic-gate 		 */
15057c478bd9Sstevel@tonic-gate 		override_str_cpy_len = strlen(override_str[i]) + 1;
15067c478bd9Sstevel@tonic-gate 		override_str_cpy = kmem_zalloc(override_str_cpy_len, KM_SLEEP);
15077c478bd9Sstevel@tonic-gate 		(void) strcpy(override_str_cpy, override_str[i]);
15087c478bd9Sstevel@tonic-gate 
15097c478bd9Sstevel@tonic-gate 		bzero(&ov, sizeof (scsa2usb_ov_t));
15107c478bd9Sstevel@tonic-gate 
15117c478bd9Sstevel@tonic-gate 		if (scsa2usb_parse_input_str(override_str[i], &ov,
15127c478bd9Sstevel@tonic-gate 		    scsa2usbp) == USB_FAILURE) {
15137c478bd9Sstevel@tonic-gate 			kmem_free(override_str_cpy, override_str_cpy_len);
15147c478bd9Sstevel@tonic-gate 			continue;
15157c478bd9Sstevel@tonic-gate 		}
15167c478bd9Sstevel@tonic-gate 
15177c478bd9Sstevel@tonic-gate 		/*
15187c478bd9Sstevel@tonic-gate 		 * see if subclass/protocol needs to be overridden for device
15197c478bd9Sstevel@tonic-gate 		 * or if device should not be power managed
15207c478bd9Sstevel@tonic-gate 		 * if there'a a match, save the override string in soft state
15217c478bd9Sstevel@tonic-gate 		 */
15227c478bd9Sstevel@tonic-gate 		if (((descr->idVendor == (uint16_t)ov.vid) || (ov.vid == 0)) &&
15237c478bd9Sstevel@tonic-gate 		    ((descr->idProduct == (uint16_t)ov.pid) || (ov.pid == 0)) &&
15247c478bd9Sstevel@tonic-gate 		    ((descr->bcdDevice == (uint16_t)ov.rev) || (ov.rev == 0))) {
15257c478bd9Sstevel@tonic-gate 			scsa2usbp->scsa2usb_subclass_override = ov.subclass;
15267c478bd9Sstevel@tonic-gate 			scsa2usbp->scsa2usb_protocol_override = ov.protocol;
15277c478bd9Sstevel@tonic-gate 
15284610e4a0Sfrits 			USB_DPRINTF_L2(DPRINT_MASK_SCSA,
15297c478bd9Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
15307c478bd9Sstevel@tonic-gate 			    "vid=0x%x pid=0x%x rev=0x%x subclass=0x%x "
15317c478bd9Sstevel@tonic-gate 			    "protocol=0x%x "
15320167b58cScg 			    "pmoff=%d fake_removable=%d modesense=%d "
15337c478bd9Sstevel@tonic-gate 			    "reduced-cmd-support=%d",
15347c478bd9Sstevel@tonic-gate 			    ov.vid, ov.pid, ov.rev, ov.subclass, ov.protocol,
15350167b58cScg 			    ov.pmoff, ov.fake_removable, ov.no_modesense,
15367c478bd9Sstevel@tonic-gate 			    ov.reduced_cmd_support);
15377c478bd9Sstevel@tonic-gate 
15387c478bd9Sstevel@tonic-gate 			if (ov.pmoff) {
15397c478bd9Sstevel@tonic-gate 				scsa2usbp->scsa2usb_attrs &= ~SCSA2USB_ATTRS_PM;
15407c478bd9Sstevel@tonic-gate 			}
15410167b58cScg 			if (ov.fake_removable) {
15427c478bd9Sstevel@tonic-gate 				scsa2usbp->scsa2usb_attrs &=
15437c478bd9Sstevel@tonic-gate 				    ~SCSA2USB_ATTRS_RMB;
15447c478bd9Sstevel@tonic-gate 			}
15457c478bd9Sstevel@tonic-gate 			if (ov.no_modesense) {
15467c478bd9Sstevel@tonic-gate 				scsa2usbp->scsa2usb_attrs &=
15477c478bd9Sstevel@tonic-gate 				    ~SCSA2USB_ATTRS_MODE_SENSE;
15487c478bd9Sstevel@tonic-gate 			}
15497c478bd9Sstevel@tonic-gate 			if (ov.reduced_cmd_support) {
15507c478bd9Sstevel@tonic-gate 				scsa2usbp->scsa2usb_attrs &=
15517c478bd9Sstevel@tonic-gate 				    ~SCSA2USB_ATTRS_REDUCED_CMD;
15527c478bd9Sstevel@tonic-gate 			}
15537c478bd9Sstevel@tonic-gate 			scsa2usbp->scsa2usb_override_str = override_str_cpy;
15547c478bd9Sstevel@tonic-gate 			break;
15557c478bd9Sstevel@tonic-gate 		} else {
15567c478bd9Sstevel@tonic-gate 			kmem_free(override_str_cpy, override_str_cpy_len);
15577c478bd9Sstevel@tonic-gate 		}
15587c478bd9Sstevel@tonic-gate 	}
15597c478bd9Sstevel@tonic-gate 
15607c478bd9Sstevel@tonic-gate 	ddi_prop_free(override_str);
15617c478bd9Sstevel@tonic-gate }
15627c478bd9Sstevel@tonic-gate 
15637c478bd9Sstevel@tonic-gate 
15647c478bd9Sstevel@tonic-gate /*
15657c478bd9Sstevel@tonic-gate  * scsa2usb_parse_input_str:
15667c478bd9Sstevel@tonic-gate  *	parse one conf file subclass-protocol-override string
15677c478bd9Sstevel@tonic-gate  *	return vendor id, product id, revision, subclass, protocol
15687c478bd9Sstevel@tonic-gate  *	function return is success or failure
15697c478bd9Sstevel@tonic-gate  */
15707c478bd9Sstevel@tonic-gate static int
scsa2usb_parse_input_str(char * str,scsa2usb_ov_t * ovp,scsa2usb_state_t * scsa2usbp)15717c478bd9Sstevel@tonic-gate scsa2usb_parse_input_str(char *str, scsa2usb_ov_t *ovp,
15727c478bd9Sstevel@tonic-gate     scsa2usb_state_t *scsa2usbp)
15737c478bd9Sstevel@tonic-gate {
15747c478bd9Sstevel@tonic-gate 	char		*input_field, *input_value;
15757c478bd9Sstevel@tonic-gate 	char		*lasts;
15767c478bd9Sstevel@tonic-gate 	uint_t		i;
15777c478bd9Sstevel@tonic-gate 	u_longlong_t	value;
15787c478bd9Sstevel@tonic-gate 
15797c478bd9Sstevel@tonic-gate 	/* parse all the input pairs in the string */
158029219719SEnyew Tan 	for (input_field = strtok_r(str, "=", &lasts);
15817c478bd9Sstevel@tonic-gate 	    input_field != NULL;
158229219719SEnyew Tan 	    input_field = strtok_r(lasts, "=", &lasts)) {
15837c478bd9Sstevel@tonic-gate 
158429219719SEnyew Tan 		if ((input_value = strtok_r(lasts, " ", &lasts)) ==
15857c478bd9Sstevel@tonic-gate 		    NULL) {
15867c478bd9Sstevel@tonic-gate 			scsa2usb_override_error("format", scsa2usbp);
15877c478bd9Sstevel@tonic-gate 
15887c478bd9Sstevel@tonic-gate 			return (USB_FAILURE);
15897c478bd9Sstevel@tonic-gate 		}
15907c478bd9Sstevel@tonic-gate 		/* if input value is a 'don't care', skip to the next pair */
15917c478bd9Sstevel@tonic-gate 		if (strcmp(input_value, "*") == 0) {
15927c478bd9Sstevel@tonic-gate 			continue;
15937c478bd9Sstevel@tonic-gate 		}
15947c478bd9Sstevel@tonic-gate 		if (strcasecmp(input_field, "vid") == 0) {
15957c478bd9Sstevel@tonic-gate 			if (kobj_getvalue(input_value, &value) == -1) {
15967c478bd9Sstevel@tonic-gate 				scsa2usb_override_error("vendor id", scsa2usbp);
15977c478bd9Sstevel@tonic-gate 
15987c478bd9Sstevel@tonic-gate 				return (USB_FAILURE);
15997c478bd9Sstevel@tonic-gate 			}
16007c478bd9Sstevel@tonic-gate 			ovp->vid = (int)value;
16017c478bd9Sstevel@tonic-gate 		} else if (strcasecmp(input_field, "pid") == 0) {
16027c478bd9Sstevel@tonic-gate 			if (kobj_getvalue(input_value, &value) == -1) {
16037c478bd9Sstevel@tonic-gate 				scsa2usb_override_error("product id",
16047c478bd9Sstevel@tonic-gate 				    scsa2usbp);
16057c478bd9Sstevel@tonic-gate 
16067c478bd9Sstevel@tonic-gate 				return (USB_FAILURE);
16077c478bd9Sstevel@tonic-gate 			}
16087c478bd9Sstevel@tonic-gate 			ovp->pid = (int)value;
16097c478bd9Sstevel@tonic-gate 		} else if (strcasecmp(input_field, "rev") == 0) {
16107c478bd9Sstevel@tonic-gate 			if (kobj_getvalue(input_value, &value) == -1) {
16117c478bd9Sstevel@tonic-gate 				scsa2usb_override_error("revision id",
16127c478bd9Sstevel@tonic-gate 				    scsa2usbp);
16137c478bd9Sstevel@tonic-gate 
16147c478bd9Sstevel@tonic-gate 				return (USB_FAILURE);
16157c478bd9Sstevel@tonic-gate 			}
16167c478bd9Sstevel@tonic-gate 			ovp->rev = (int)value;
16177c478bd9Sstevel@tonic-gate 		} else if (strcasecmp(input_field, "subclass") == 0) {
16187c478bd9Sstevel@tonic-gate 			for (i = 0; i < N_SCSA2USB_SUBC_OVERRIDE; i++) {
16197c478bd9Sstevel@tonic-gate 				if (strcasecmp(input_value,
16207c478bd9Sstevel@tonic-gate 				    scsa2usb_subclass[i].name) == 0) {
16217c478bd9Sstevel@tonic-gate 					ovp->subclass =
16227c478bd9Sstevel@tonic-gate 					    scsa2usb_subclass[i].value;
16237c478bd9Sstevel@tonic-gate 					break;
16247c478bd9Sstevel@tonic-gate 				}
16257c478bd9Sstevel@tonic-gate 			}
16267c478bd9Sstevel@tonic-gate 			if (ovp->subclass == 0) {
16277c478bd9Sstevel@tonic-gate 				scsa2usb_override_error("subclass", scsa2usbp);
16287c478bd9Sstevel@tonic-gate 
16297c478bd9Sstevel@tonic-gate 				return (USB_FAILURE);
16307c478bd9Sstevel@tonic-gate 			}
16317c478bd9Sstevel@tonic-gate 		} else if (strcasecmp(input_field, "protocol") == 0) {
16327c478bd9Sstevel@tonic-gate 			for (i = 0; i < N_SCSA2USB_PROT_OVERRIDE; i++) {
16337c478bd9Sstevel@tonic-gate 				if (strcasecmp(input_value,
16347c478bd9Sstevel@tonic-gate 				    scsa2usb_protocol[i].name) == 0) {
16357c478bd9Sstevel@tonic-gate 					ovp->protocol =
16367c478bd9Sstevel@tonic-gate 					    scsa2usb_protocol[i].value;
16377c478bd9Sstevel@tonic-gate 					break;
16387c478bd9Sstevel@tonic-gate 				}
16397c478bd9Sstevel@tonic-gate 			}
16407c478bd9Sstevel@tonic-gate 			if (ovp->protocol == 0) {
16417c478bd9Sstevel@tonic-gate 				scsa2usb_override_error("protocol", scsa2usbp);
16427c478bd9Sstevel@tonic-gate 
16437c478bd9Sstevel@tonic-gate 				return (USB_FAILURE);
16447c478bd9Sstevel@tonic-gate 			}
16457c478bd9Sstevel@tonic-gate 		} else if (strcasecmp(input_field, "pm") == 0) {
16467c478bd9Sstevel@tonic-gate 			if (strcasecmp(input_value, "off") == 0) {
16477c478bd9Sstevel@tonic-gate 				ovp->pmoff = 1;
16487c478bd9Sstevel@tonic-gate 				break;
16497c478bd9Sstevel@tonic-gate 			} else {
16507c478bd9Sstevel@tonic-gate 				scsa2usb_override_error("pm", scsa2usbp);
16517c478bd9Sstevel@tonic-gate 
16527c478bd9Sstevel@tonic-gate 				return (USB_FAILURE);
16537c478bd9Sstevel@tonic-gate 			}
16547c478bd9Sstevel@tonic-gate 		} else if (strcasecmp(input_field, "removable") == 0) {
16550167b58cScg 			if (strcasecmp(input_value, "true") == 0) {
16560167b58cScg 				ovp->fake_removable = 1;
16577c478bd9Sstevel@tonic-gate 				break;
16587c478bd9Sstevel@tonic-gate 			} else {
16597c478bd9Sstevel@tonic-gate 				scsa2usb_override_error("removable", scsa2usbp);
16607c478bd9Sstevel@tonic-gate 
16617c478bd9Sstevel@tonic-gate 				return (USB_FAILURE);
16627c478bd9Sstevel@tonic-gate 			}
16637c478bd9Sstevel@tonic-gate 		} else if (strcasecmp(input_field, "modesense") == 0) {
16647c478bd9Sstevel@tonic-gate 			if (strcasecmp(input_value, "false") == 0) {
16657c478bd9Sstevel@tonic-gate 				ovp->no_modesense = 1;
16667c478bd9Sstevel@tonic-gate 				break;
16677c478bd9Sstevel@tonic-gate 			} else {
16687c478bd9Sstevel@tonic-gate 				scsa2usb_override_error("modesense",
1669d94492edSfb 				    scsa2usbp);
16707c478bd9Sstevel@tonic-gate 
16717c478bd9Sstevel@tonic-gate 				return (USB_FAILURE);
16727c478bd9Sstevel@tonic-gate 			}
16737c478bd9Sstevel@tonic-gate 		} else if (strcasecmp(input_field,
16747c478bd9Sstevel@tonic-gate 		    "reduced-cmd-support") == 0) {
16757c478bd9Sstevel@tonic-gate 			if (strcasecmp(input_value, "true") == 0) {
16767c478bd9Sstevel@tonic-gate 				ovp->reduced_cmd_support = 1;
16777c478bd9Sstevel@tonic-gate 				break;
16787c478bd9Sstevel@tonic-gate 			} else {
16797c478bd9Sstevel@tonic-gate 				scsa2usb_override_error(
16807c478bd9Sstevel@tonic-gate 				    "reduced-cmd-support", scsa2usbp);
16817c478bd9Sstevel@tonic-gate 
16827c478bd9Sstevel@tonic-gate 				return (USB_FAILURE);
16837c478bd9Sstevel@tonic-gate 			}
16847c478bd9Sstevel@tonic-gate 		} else {
16854610e4a0Sfrits 			scsa2usb_override_error(input_field, scsa2usbp);
16867c478bd9Sstevel@tonic-gate 
16877c478bd9Sstevel@tonic-gate 			return (USB_FAILURE);
16887c478bd9Sstevel@tonic-gate 		}
16897c478bd9Sstevel@tonic-gate 	}
16907c478bd9Sstevel@tonic-gate 
16917c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
16927c478bd9Sstevel@tonic-gate }
16937c478bd9Sstevel@tonic-gate 
16947c478bd9Sstevel@tonic-gate 
16957c478bd9Sstevel@tonic-gate /*
16967c478bd9Sstevel@tonic-gate  * scsa2usb_override_error:
16977c478bd9Sstevel@tonic-gate  *	print an error message if conf file string is bad format
16987c478bd9Sstevel@tonic-gate  */
16997c478bd9Sstevel@tonic-gate static void
scsa2usb_override_error(char * input_field,scsa2usb_state_t * scsa2usbp)17007c478bd9Sstevel@tonic-gate scsa2usb_override_error(char *input_field, scsa2usb_state_t *scsa2usbp)
17017c478bd9Sstevel@tonic-gate {
17027c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L1(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
17034610e4a0Sfrits 	    "invalid %s in scsa2usb.conf file entry", input_field);
17047c478bd9Sstevel@tonic-gate }
17057c478bd9Sstevel@tonic-gate 
17067c478bd9Sstevel@tonic-gate 
17077c478bd9Sstevel@tonic-gate /*
170847b9747fSJoshua M. Clulow  * Some devices are not complete or compatible implementations of the USB mass
170947b9747fSJoshua M. Clulow  * storage protocols, and need special handling.  This routine checks various
171047b9747fSJoshua M. Clulow  * aspects of the device against internal lists of quirky hardware.
17117c478bd9Sstevel@tonic-gate  */
17127c478bd9Sstevel@tonic-gate static void
scsa2usb_detect_quirks(scsa2usb_state_t * scsa2usbp)171347b9747fSJoshua M. Clulow scsa2usb_detect_quirks(scsa2usb_state_t *scsa2usbp)
17147c478bd9Sstevel@tonic-gate {
171547b9747fSJoshua M. Clulow 	int mask;
17167c478bd9Sstevel@tonic-gate 	usb_dev_descr_t *desc = scsa2usbp->scsa2usb_dev_data->dev_descr;
17177c478bd9Sstevel@tonic-gate 
17187c478bd9Sstevel@tonic-gate 	if (!SCSA2USB_IS_BULK_ONLY(scsa2usbp)) {
17197c478bd9Sstevel@tonic-gate 		scsa2usbp->scsa2usb_attrs &= ~SCSA2USB_ATTRS_GET_LUN;
17207c478bd9Sstevel@tonic-gate 	}
17217c478bd9Sstevel@tonic-gate 
172247b9747fSJoshua M. Clulow 	/*
172347b9747fSJoshua M. Clulow 	 * Determine if this device is on the quirks list:
172447b9747fSJoshua M. Clulow 	 */
172547b9747fSJoshua M. Clulow 	for (uint_t i = 0; i < ARRAY_SIZE(scsa2usb_quirks); i++) {
172647b9747fSJoshua M. Clulow 		struct quirk *q = &scsa2usb_quirks[i];
172747b9747fSJoshua M. Clulow 
172847b9747fSJoshua M. Clulow 		if (q->q_vid == desc->idVendor &&
172947b9747fSJoshua M. Clulow 		    (q->q_pid == desc->idProduct || q->q_pid == X) &&
173047b9747fSJoshua M. Clulow 		    (q->q_rev == desc->bcdDevice || q->q_rev == X)) {
173147b9747fSJoshua M. Clulow 			/*
173247b9747fSJoshua M. Clulow 			 * Remove any attribute bits specified in the quirks
173347b9747fSJoshua M. Clulow 			 * table:
173447b9747fSJoshua M. Clulow 			 */
173547b9747fSJoshua M. Clulow 			scsa2usbp->scsa2usb_attrs &= ~(q->q_attr);
17367c478bd9Sstevel@tonic-gate 			break;
17377c478bd9Sstevel@tonic-gate 		}
17387c478bd9Sstevel@tonic-gate 	}
17397c478bd9Sstevel@tonic-gate 
17407c478bd9Sstevel@tonic-gate 	/*
17417c478bd9Sstevel@tonic-gate 	 * Mitsumi's CD-RW drives subclass isn't UFI.
17427c478bd9Sstevel@tonic-gate 	 * But they support UFI command-set (this code ensures that)
17437c478bd9Sstevel@tonic-gate 	 * NOTE: This is a special case, and is being called out so.
17447c478bd9Sstevel@tonic-gate 	 */
17457c478bd9Sstevel@tonic-gate 	if (desc->idVendor == MS_MITSUMI_VID) {
17467c478bd9Sstevel@tonic-gate 		mask = scsa2usbp->scsa2usb_cmd_protocol & SCSA2USB_CMDSET_MASK;
17477c478bd9Sstevel@tonic-gate 		if (mask) {
17487c478bd9Sstevel@tonic-gate 			scsa2usbp->scsa2usb_cmd_protocol &= ~mask;
17497c478bd9Sstevel@tonic-gate 		}
17507c478bd9Sstevel@tonic-gate 		scsa2usbp->scsa2usb_cmd_protocol |= SCSA2USB_UFI_CMDSET;
17517c478bd9Sstevel@tonic-gate 	}
17527c478bd9Sstevel@tonic-gate 
17537c478bd9Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_attrs != SCSA2USB_ALL_ATTRS) {
17547c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA,
17557c478bd9Sstevel@tonic-gate 		    scsa2usbp->scsa2usb_log_handle,
17567c478bd9Sstevel@tonic-gate 		    "scsa2usb attributes modified: 0x%x",
17577c478bd9Sstevel@tonic-gate 		    scsa2usbp->scsa2usb_attrs);
17587c478bd9Sstevel@tonic-gate 	}
17597c478bd9Sstevel@tonic-gate }
17607c478bd9Sstevel@tonic-gate 
17617c478bd9Sstevel@tonic-gate 
17627c478bd9Sstevel@tonic-gate /*
17637c478bd9Sstevel@tonic-gate  * scsa2usb_create_luns:
17647c478bd9Sstevel@tonic-gate  *	check the number of luns but continue if the check fails,
17657c478bd9Sstevel@tonic-gate  *	create child nodes for each lun
17667c478bd9Sstevel@tonic-gate  */
17677c478bd9Sstevel@tonic-gate static void
scsa2usb_create_luns(scsa2usb_state_t * scsa2usbp)17687c478bd9Sstevel@tonic-gate scsa2usb_create_luns(scsa2usb_state_t *scsa2usbp)
17697c478bd9Sstevel@tonic-gate {
17707c478bd9Sstevel@tonic-gate 	int		lun, rval;
17717c478bd9Sstevel@tonic-gate 	char		*compatible[MAX_COMPAT_NAMES];	/* compatible names */
17727c478bd9Sstevel@tonic-gate 	dev_info_t	*cdip;
17737c478bd9Sstevel@tonic-gate 	uchar_t		dtype;
17747c478bd9Sstevel@tonic-gate 	char		*node_name;
17757c478bd9Sstevel@tonic-gate 	char		*driver_name = NULL;
17767c478bd9Sstevel@tonic-gate 
17777c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
17787c478bd9Sstevel@tonic-gate 	    "scsa2usb_create_luns:");
17797c478bd9Sstevel@tonic-gate 
17807c478bd9Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
17817c478bd9Sstevel@tonic-gate 
17827c478bd9Sstevel@tonic-gate 	/* Set n_luns to 1 by default (for floppies and other devices) */
17837c478bd9Sstevel@tonic-gate 	scsa2usbp->scsa2usb_n_luns = 1;
17847c478bd9Sstevel@tonic-gate 
17857c478bd9Sstevel@tonic-gate 	/*
17867c478bd9Sstevel@tonic-gate 	 * Check if there are any device out there which don't
17877c478bd9Sstevel@tonic-gate 	 * support the GET_MAX_LUN command. If so, don't issue
17887c478bd9Sstevel@tonic-gate 	 * control request to them.
17897c478bd9Sstevel@tonic-gate 	 */
17907c478bd9Sstevel@tonic-gate 	if ((scsa2usbp->scsa2usb_attrs & SCSA2USB_ATTRS_GET_LUN) == 0) {
17915547f1d8SBinzi Cao - Sun Microsystems - Beijing China 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
17927c478bd9Sstevel@tonic-gate 		    "get_max_lun cmd not supported");
17937c478bd9Sstevel@tonic-gate 	} else {
17947c478bd9Sstevel@tonic-gate 		if (SCSA2USB_IS_BULK_ONLY(scsa2usbp)) {
17957c478bd9Sstevel@tonic-gate 			scsa2usbp->scsa2usb_n_luns =
1796d94492edSfb 			    scsa2usb_bulk_only_get_max_lun(scsa2usbp);
17977c478bd9Sstevel@tonic-gate 		}
17987c478bd9Sstevel@tonic-gate 	}
17997c478bd9Sstevel@tonic-gate 
18007c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
18017c478bd9Sstevel@tonic-gate 	    "scsa2usb_create_luns: %d luns found", scsa2usbp->scsa2usb_n_luns);
18027c478bd9Sstevel@tonic-gate 
18037c478bd9Sstevel@tonic-gate 	/*
18047c478bd9Sstevel@tonic-gate 	 * create disk child for each lun
18057c478bd9Sstevel@tonic-gate 	 */
18067c478bd9Sstevel@tonic-gate 	for (lun = 0; lun < scsa2usbp->scsa2usb_n_luns; lun++) {
18077c478bd9Sstevel@tonic-gate 		ASSERT(scsa2usbp->scsa2usb_lun_dip[lun] == NULL);
18087c478bd9Sstevel@tonic-gate 
18097c478bd9Sstevel@tonic-gate 		/* do an inquiry to get the dtype of this lun */
18107c478bd9Sstevel@tonic-gate 		scsa2usb_do_inquiry(scsa2usbp, 0, lun);
18117c478bd9Sstevel@tonic-gate 
18127c478bd9Sstevel@tonic-gate 		dtype = scsa2usbp->scsa2usb_lun_inquiry[lun].
1813d94492edSfb 		    inq_dtype & DTYPE_MASK;
18147c478bd9Sstevel@tonic-gate 
18157c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
18167c478bd9Sstevel@tonic-gate 		    "dtype[%d]=0x%x", lun, dtype);
18177c478bd9Sstevel@tonic-gate 
18187c478bd9Sstevel@tonic-gate 		driver_name = NULL;
18197c478bd9Sstevel@tonic-gate 
18207c478bd9Sstevel@tonic-gate 		switch (dtype) {
18217c478bd9Sstevel@tonic-gate 		case DTYPE_DIRECT:
18227c478bd9Sstevel@tonic-gate 		case DTYPE_RODIRECT:
18237c478bd9Sstevel@tonic-gate 		case DTYPE_OPTICAL:
18247c478bd9Sstevel@tonic-gate 			node_name = "disk";
18257c478bd9Sstevel@tonic-gate 			driver_name = "sd";
18267c478bd9Sstevel@tonic-gate 
18277c478bd9Sstevel@tonic-gate 			break;
18287c478bd9Sstevel@tonic-gate 		case DTYPE_SEQUENTIAL:
18297c478bd9Sstevel@tonic-gate 			node_name = "tape";
18307c478bd9Sstevel@tonic-gate 			driver_name = "st";
18317c478bd9Sstevel@tonic-gate 
18327c478bd9Sstevel@tonic-gate 			break;
18337c478bd9Sstevel@tonic-gate 		case DTYPE_PRINTER:
18347c478bd9Sstevel@tonic-gate 			node_name = "printer";
18357c478bd9Sstevel@tonic-gate 
18367c478bd9Sstevel@tonic-gate 			break;
18377c478bd9Sstevel@tonic-gate 		case DTYPE_PROCESSOR:
18387c478bd9Sstevel@tonic-gate 			node_name = "processor";
18397c478bd9Sstevel@tonic-gate 
18407c478bd9Sstevel@tonic-gate 			break;
18417c478bd9Sstevel@tonic-gate 		case DTYPE_WORM:
18427c478bd9Sstevel@tonic-gate 			node_name = "worm";
18437c478bd9Sstevel@tonic-gate 
18447c478bd9Sstevel@tonic-gate 			break;
18457c478bd9Sstevel@tonic-gate 		case DTYPE_SCANNER:
18467c478bd9Sstevel@tonic-gate 			node_name = "scanner";
18477c478bd9Sstevel@tonic-gate 
18487c478bd9Sstevel@tonic-gate 			break;
18497c478bd9Sstevel@tonic-gate 		case DTYPE_CHANGER:
18507c478bd9Sstevel@tonic-gate 			node_name = "changer";
18517c478bd9Sstevel@tonic-gate 
18527c478bd9Sstevel@tonic-gate 			break;
18537c478bd9Sstevel@tonic-gate 		case DTYPE_COMM:
18547c478bd9Sstevel@tonic-gate 			node_name = "comm";
18557c478bd9Sstevel@tonic-gate 
18567c478bd9Sstevel@tonic-gate 			break;
18577c478bd9Sstevel@tonic-gate 		case DTYPE_ARRAY_CTRL:
18587c478bd9Sstevel@tonic-gate 			node_name = "array_ctrl";
18597c478bd9Sstevel@tonic-gate 
18607c478bd9Sstevel@tonic-gate 			break;
18617c478bd9Sstevel@tonic-gate 		case DTYPE_ESI:
18627c478bd9Sstevel@tonic-gate 			node_name = "esi";
18637c478bd9Sstevel@tonic-gate 			driver_name = "ses";
18647c478bd9Sstevel@tonic-gate 
18657c478bd9Sstevel@tonic-gate 			break;
18667c478bd9Sstevel@tonic-gate 		default:
18677c478bd9Sstevel@tonic-gate 			node_name = "generic";
18687c478bd9Sstevel@tonic-gate 
18697c478bd9Sstevel@tonic-gate 			break;
18707c478bd9Sstevel@tonic-gate 		}
18717c478bd9Sstevel@tonic-gate 
18727c478bd9Sstevel@tonic-gate 		if (driver_name) {
18737c478bd9Sstevel@tonic-gate 			compatible[0] = driver_name;
18747c478bd9Sstevel@tonic-gate 		}
18757c478bd9Sstevel@tonic-gate 
18767c478bd9Sstevel@tonic-gate 		ndi_devi_alloc_sleep(scsa2usbp->scsa2usb_dip, node_name,
1877fa9e4066Sahrens 		    (pnode_t)DEVI_SID_NODEID, &cdip);
18787c478bd9Sstevel@tonic-gate 
18797c478bd9Sstevel@tonic-gate 		/* attach target & lun properties */
18807c478bd9Sstevel@tonic-gate 		rval = ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "target", 0);
18817c478bd9Sstevel@tonic-gate 		if (rval != DDI_PROP_SUCCESS) {
18827c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_SCSA,
18837c478bd9Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
18847c478bd9Sstevel@tonic-gate 			    "ndi_prop_update_int target failed %d", rval);
18857c478bd9Sstevel@tonic-gate 			(void) ndi_devi_free(cdip);
18867c478bd9Sstevel@tonic-gate 			continue;
18877c478bd9Sstevel@tonic-gate 		}
18887c478bd9Sstevel@tonic-gate 
18890167b58cScg 		rval = ndi_prop_create_boolean(DDI_DEV_T_NONE, cdip,
18900167b58cScg 		    "hotpluggable");
18910167b58cScg 		if (rval != DDI_PROP_SUCCESS) {
18920167b58cScg 			USB_DPRINTF_L2(DPRINT_MASK_SCSA,
18930167b58cScg 			    scsa2usbp->scsa2usb_log_handle,
18940167b58cScg 			    "ndi_prop_create_boolean hotpluggable failed %d",
18950167b58cScg 			    rval);
18960167b58cScg 			ddi_prop_remove_all(cdip);
18970167b58cScg 			(void) ndi_devi_free(cdip);
18980167b58cScg 			continue;
18990167b58cScg 		}
19000167b58cScg 		/*
19010167b58cScg 		 * Some devices don't support LOG SENSE, so tells
19020167b58cScg 		 * sd driver not to send this command.
19030167b58cScg 		 */
19040167b58cScg 		rval = ndi_prop_update_int(DDI_DEV_T_NONE, cdip,
19050167b58cScg 		    "pm-capable", 1);
19060167b58cScg 		if (rval != DDI_PROP_SUCCESS) {
19070167b58cScg 			USB_DPRINTF_L2(DPRINT_MASK_SCSA,
19080167b58cScg 			    scsa2usbp->scsa2usb_log_handle,
19090167b58cScg 			    "ndi_prop_update_int pm-capable failed %d", rval);
19100167b58cScg 			ddi_prop_remove_all(cdip);
19110167b58cScg 			(void) ndi_devi_free(cdip);
19120167b58cScg 			continue;
19130167b58cScg 		}
19140167b58cScg 
19157c478bd9Sstevel@tonic-gate 		rval = ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "lun", lun);
19167c478bd9Sstevel@tonic-gate 		if (rval != DDI_PROP_SUCCESS) {
19177c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_SCSA,
19187c478bd9Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
19197c478bd9Sstevel@tonic-gate 			    "ndi_prop_update_int lun failed %d", rval);
19207c478bd9Sstevel@tonic-gate 			ddi_prop_remove_all(cdip);
19217c478bd9Sstevel@tonic-gate 			(void) ndi_devi_free(cdip);
19227c478bd9Sstevel@tonic-gate 			continue;
19237c478bd9Sstevel@tonic-gate 		}
19247c478bd9Sstevel@tonic-gate 
19257c478bd9Sstevel@tonic-gate 		if (driver_name) {
19267c478bd9Sstevel@tonic-gate 			rval = ndi_prop_update_string_array(DDI_DEV_T_NONE,
19277c478bd9Sstevel@tonic-gate 			    cdip, "compatible", (char **)compatible,
19287c478bd9Sstevel@tonic-gate 			    MAX_COMPAT_NAMES);
19297c478bd9Sstevel@tonic-gate 			if (rval != DDI_PROP_SUCCESS) {
19307c478bd9Sstevel@tonic-gate 				USB_DPRINTF_L2(DPRINT_MASK_SCSA,
19317c478bd9Sstevel@tonic-gate 				    scsa2usbp->scsa2usb_log_handle,
19327c478bd9Sstevel@tonic-gate 				    "ndi_prop_update_string_array failed %d",
19337c478bd9Sstevel@tonic-gate 				    rval);
19347c478bd9Sstevel@tonic-gate 				ddi_prop_remove_all(cdip);
19357c478bd9Sstevel@tonic-gate 				(void) ndi_devi_free(cdip);
19367c478bd9Sstevel@tonic-gate 				continue;
19377c478bd9Sstevel@tonic-gate 			}
19387c478bd9Sstevel@tonic-gate 		}
19397c478bd9Sstevel@tonic-gate 
19407c478bd9Sstevel@tonic-gate 		/*
19417c478bd9Sstevel@tonic-gate 		 * add property "usb" so we always verify that it is our child
19427c478bd9Sstevel@tonic-gate 		 */
19437c478bd9Sstevel@tonic-gate 		rval = ndi_prop_create_boolean(DDI_DEV_T_NONE, cdip, "usb");
19447c478bd9Sstevel@tonic-gate 		if (rval != DDI_PROP_SUCCESS) {
19457c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_SCSA,
19467c478bd9Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
19477c478bd9Sstevel@tonic-gate 			    "ndi_prop_create_boolean failed %d", rval);
19487c478bd9Sstevel@tonic-gate 			ddi_prop_remove_all(cdip);
19497c478bd9Sstevel@tonic-gate 			(void) ndi_devi_free(cdip);
19507c478bd9Sstevel@tonic-gate 			continue;
19517c478bd9Sstevel@tonic-gate 		}
19527c478bd9Sstevel@tonic-gate 
19537c478bd9Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
19547c478bd9Sstevel@tonic-gate 		(void) ddi_initchild(scsa2usbp->scsa2usb_dip, cdip);
19557c478bd9Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
19567c478bd9Sstevel@tonic-gate 
19577c478bd9Sstevel@tonic-gate 		usba_set_usba_device(cdip,
1958d94492edSfb 		    usba_get_usba_device(scsa2usbp->scsa2usb_dip));
19597c478bd9Sstevel@tonic-gate 	}
19607c478bd9Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
19617c478bd9Sstevel@tonic-gate }
19627c478bd9Sstevel@tonic-gate 
19637c478bd9Sstevel@tonic-gate 
19647c478bd9Sstevel@tonic-gate /*
19657c478bd9Sstevel@tonic-gate  * scsa2usb_is_usb:
19667c478bd9Sstevel@tonic-gate  *	scsa2usb gets called for all possible sd children.
19677c478bd9Sstevel@tonic-gate  *	we can only accept usb children
19687c478bd9Sstevel@tonic-gate  */
19697c478bd9Sstevel@tonic-gate static int
scsa2usb_is_usb(dev_info_t * dip)19707c478bd9Sstevel@tonic-gate scsa2usb_is_usb(dev_info_t *dip)
19717c478bd9Sstevel@tonic-gate {
19727c478bd9Sstevel@tonic-gate 	if (dip) {
19737c478bd9Sstevel@tonic-gate 		return (ddi_prop_exists(DDI_DEV_T_ANY, dip,
19747c478bd9Sstevel@tonic-gate 		    DDI_PROP_DONTPASS, "usb"));
19757c478bd9Sstevel@tonic-gate 	}
19767c478bd9Sstevel@tonic-gate 	return (0);
19777c478bd9Sstevel@tonic-gate }
19787c478bd9Sstevel@tonic-gate 
19797c478bd9Sstevel@tonic-gate 
19807c478bd9Sstevel@tonic-gate /*
19817c478bd9Sstevel@tonic-gate  * Panic Stuff
19827c478bd9Sstevel@tonic-gate  * scsa2usb_panic_callb_init:
19837c478bd9Sstevel@tonic-gate  *	initialize PANIC callb and free allocated resources
19847c478bd9Sstevel@tonic-gate  */
19857c478bd9Sstevel@tonic-gate static void
scsa2usb_panic_callb_init(scsa2usb_state_t * scsa2usbp)19867c478bd9Sstevel@tonic-gate scsa2usb_panic_callb_init(scsa2usb_state_t *scsa2usbp)
19877c478bd9Sstevel@tonic-gate {
19887c478bd9Sstevel@tonic-gate 	/*
19897c478bd9Sstevel@tonic-gate 	 * In case the system panics, the sync command flushes
19907c478bd9Sstevel@tonic-gate 	 * dirty FS pages or buffers. This would cause a hang
19917c478bd9Sstevel@tonic-gate 	 * in USB.
19927c478bd9Sstevel@tonic-gate 	 * The reason for the failure is that we enter
19937c478bd9Sstevel@tonic-gate 	 * polled mode (interrupts disabled) and HCD gets stuck
19947c478bd9Sstevel@tonic-gate 	 * trying to execute bulk requests
19957c478bd9Sstevel@tonic-gate 	 * The panic_callback registered below provides a warning
19967c478bd9Sstevel@tonic-gate 	 * that a panic has occurred and from that point onwards, we
19977c478bd9Sstevel@tonic-gate 	 * complete each request successfully and immediately. This
19987c478bd9Sstevel@tonic-gate 	 * will fake successful syncing so at least the rest of the
19997c478bd9Sstevel@tonic-gate 	 * filesystems complete syncing.
20007c478bd9Sstevel@tonic-gate 	 */
20017c478bd9Sstevel@tonic-gate 	scsa2usbp->scsa2usb_panic_info =
2002d94492edSfb 	    kmem_zalloc(sizeof (scsa2usb_cpr_t), KM_SLEEP);
20037c478bd9Sstevel@tonic-gate 	mutex_init(&scsa2usbp->scsa2usb_panic_info->lockp,
2004d94492edSfb 	    NULL, MUTEX_DRIVER,
2005d94492edSfb 	    scsa2usbp->scsa2usb_dev_data->dev_iblock_cookie);
20067c478bd9Sstevel@tonic-gate 	scsa2usbp->scsa2usb_panic_info->statep = scsa2usbp;
20077c478bd9Sstevel@tonic-gate 	scsa2usbp->scsa2usb_panic_info->cpr.cc_lockp =
2008d94492edSfb 	    &scsa2usbp->scsa2usb_panic_info->lockp;
20097c478bd9Sstevel@tonic-gate 	scsa2usbp->scsa2usb_panic_info->cpr.cc_id =
2010d94492edSfb 	    callb_add(scsa2usb_panic_callb,
2011d94492edSfb 	    (void *)scsa2usbp->scsa2usb_panic_info,
2012d94492edSfb 	    CB_CL_PANIC, "scsa2usb");
20137c478bd9Sstevel@tonic-gate }
20147c478bd9Sstevel@tonic-gate 
20157c478bd9Sstevel@tonic-gate 
20167c478bd9Sstevel@tonic-gate /*
20177c478bd9Sstevel@tonic-gate  * scsa2usb_panic_callb_fini:
20187c478bd9Sstevel@tonic-gate  *	cancel out PANIC callb and free allocated resources
20197c478bd9Sstevel@tonic-gate  */
20207c478bd9Sstevel@tonic-gate static void
scsa2usb_panic_callb_fini(scsa2usb_state_t * scsa2usbp)20217c478bd9Sstevel@tonic-gate scsa2usb_panic_callb_fini(scsa2usb_state_t *scsa2usbp)
20227c478bd9Sstevel@tonic-gate {
20237c478bd9Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_panic_info) {
20247c478bd9Sstevel@tonic-gate 		SCSA2USB_CANCEL_CB(scsa2usbp->scsa2usb_panic_info->cpr.cc_id);
20257c478bd9Sstevel@tonic-gate 		mutex_destroy(&scsa2usbp->scsa2usb_panic_info->lockp);
20267c478bd9Sstevel@tonic-gate 		scsa2usbp->scsa2usb_panic_info->statep = NULL;
20277c478bd9Sstevel@tonic-gate 		kmem_free(scsa2usbp->scsa2usb_panic_info,
20287c478bd9Sstevel@tonic-gate 		    sizeof (scsa2usb_cpr_t));
20297c478bd9Sstevel@tonic-gate 		scsa2usbp->scsa2usb_panic_info = NULL;
20307c478bd9Sstevel@tonic-gate 	}
20317c478bd9Sstevel@tonic-gate }
20327c478bd9Sstevel@tonic-gate 
20337c478bd9Sstevel@tonic-gate 
20347c478bd9Sstevel@tonic-gate /*
20357c478bd9Sstevel@tonic-gate  * scsa2usb_panic_callb:
20367c478bd9Sstevel@tonic-gate  *	This routine is called when there is a system panic.
20377c478bd9Sstevel@tonic-gate  */
20387c478bd9Sstevel@tonic-gate /* ARGSUSED */
20397c478bd9Sstevel@tonic-gate static boolean_t
scsa2usb_panic_callb(void * arg,int code)20407c478bd9Sstevel@tonic-gate scsa2usb_panic_callb(void *arg, int code)
20417c478bd9Sstevel@tonic-gate {
20427c478bd9Sstevel@tonic-gate 	scsa2usb_cpr_t *cpr_infop;
20437c478bd9Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp;
20447c478bd9Sstevel@tonic-gate 	uint_t		lun;
20457c478bd9Sstevel@tonic-gate 
20467c478bd9Sstevel@tonic-gate 	_NOTE(NO_COMPETING_THREADS_NOW);
20477c478bd9Sstevel@tonic-gate 	cpr_infop = (scsa2usb_cpr_t *)arg;
20487c478bd9Sstevel@tonic-gate 	scsa2usbp = (scsa2usb_state_t *)cpr_infop->statep;
20497c478bd9Sstevel@tonic-gate 
20507c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
20517c478bd9Sstevel@tonic-gate 	    "scsa2usb_panic_callb: code=%d", code);
20527c478bd9Sstevel@tonic-gate 
20537c478bd9Sstevel@tonic-gate 	/*
20547c478bd9Sstevel@tonic-gate 	 * If we return error here, "sd" prints lots of error
20557c478bd9Sstevel@tonic-gate 	 * messages and could retry the same pkt over and over again.
20567c478bd9Sstevel@tonic-gate 	 * The sync recovery isn't "smooth" in that case. By faking
20577c478bd9Sstevel@tonic-gate 	 * a success return, instead,  we force sync to complete.
20587c478bd9Sstevel@tonic-gate 	 */
20597c478bd9Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_cur_pkt) {
20607c478bd9Sstevel@tonic-gate 		/*
20617c478bd9Sstevel@tonic-gate 		 * Do not print the "no sync" warning here. it will then be
20627c478bd9Sstevel@tonic-gate 		 * displayed before we actually start syncing. Also we don't
20637c478bd9Sstevel@tonic-gate 		 * replace this code with a call to scsa2usb_pkt_completion().
20647c478bd9Sstevel@tonic-gate 		 * NOTE: mutexes are disabled during panic.
20657c478bd9Sstevel@tonic-gate 		 */
20667c478bd9Sstevel@tonic-gate 		scsa2usbp->scsa2usb_cur_pkt->pkt_reason = CMD_CMPLT;
20677c478bd9Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
20687c478bd9Sstevel@tonic-gate 		scsa2usb_pkt_completion(scsa2usbp, scsa2usbp->scsa2usb_cur_pkt);
20697c478bd9Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
20707c478bd9Sstevel@tonic-gate 	}
20717c478bd9Sstevel@tonic-gate 
20727c478bd9Sstevel@tonic-gate 	/* get rid of waitQ */
20737c478bd9Sstevel@tonic-gate 	for (lun = 0; lun < SCSA2USB_MAX_LUNS; lun++) {
20747c478bd9Sstevel@tonic-gate 		scsa2usb_flush_waitQ(scsa2usbp, lun, CMD_CMPLT);
20757c478bd9Sstevel@tonic-gate 	}
20767c478bd9Sstevel@tonic-gate 
2077055d7c80Scarlsonj #ifndef lint
20787c478bd9Sstevel@tonic-gate 	_NOTE(COMPETING_THREADS_NOW);
2079055d7c80Scarlsonj #endif
20807c478bd9Sstevel@tonic-gate 
20817c478bd9Sstevel@tonic-gate 	return (B_TRUE);
20827c478bd9Sstevel@tonic-gate }
20837c478bd9Sstevel@tonic-gate 
20847c478bd9Sstevel@tonic-gate /*
20857c478bd9Sstevel@tonic-gate  * scsa2usb_cpr_suspend
20867c478bd9Sstevel@tonic-gate  *	determine if the device's state can be changed to SUSPENDED
20877c478bd9Sstevel@tonic-gate  *	close pipes if there is no activity
20887c478bd9Sstevel@tonic-gate  */
20897c478bd9Sstevel@tonic-gate /* ARGSUSED */
20907c478bd9Sstevel@tonic-gate static int
scsa2usb_cpr_suspend(dev_info_t * dip)20917c478bd9Sstevel@tonic-gate scsa2usb_cpr_suspend(dev_info_t *dip)
20927c478bd9Sstevel@tonic-gate {
20937c478bd9Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp;
20947c478bd9Sstevel@tonic-gate 	int	prev_state;
20957c478bd9Sstevel@tonic-gate 	int	rval = USB_FAILURE;
20967c478bd9Sstevel@tonic-gate 
20977c478bd9Sstevel@tonic-gate 	scsa2usbp = ddi_get_soft_state(scsa2usb_statep, ddi_get_instance(dip));
20987c478bd9Sstevel@tonic-gate 
20997c478bd9Sstevel@tonic-gate 	ASSERT(scsa2usbp != NULL);
21007c478bd9Sstevel@tonic-gate 
21017c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
21027c478bd9Sstevel@tonic-gate 	    "scsa2usb_cpr_suspend:");
21037c478bd9Sstevel@tonic-gate 
21047c478bd9Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
21057c478bd9Sstevel@tonic-gate 	switch (scsa2usbp->scsa2usb_dev_state) {
21067c478bd9Sstevel@tonic-gate 	case USB_DEV_ONLINE:
21077c478bd9Sstevel@tonic-gate 	case USB_DEV_PWRED_DOWN:
21087c478bd9Sstevel@tonic-gate 	case USB_DEV_DISCONNECTED:
21097c478bd9Sstevel@tonic-gate 		prev_state = scsa2usbp->scsa2usb_dev_state;
21107c478bd9Sstevel@tonic-gate 		scsa2usbp->scsa2usb_dev_state = USB_DEV_SUSPENDED;
21117c478bd9Sstevel@tonic-gate 
21127c478bd9Sstevel@tonic-gate 		/*
21137c478bd9Sstevel@tonic-gate 		 * If the device is busy, we cannot suspend
21147c478bd9Sstevel@tonic-gate 		 */
21157c478bd9Sstevel@tonic-gate 		if (SCSA2USB_BUSY(scsa2usbp)) {
21167c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L3(DPRINT_MASK_SCSA,
21177c478bd9Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
21187c478bd9Sstevel@tonic-gate 			    "scsa2usb_cpr_suspend: I/O active");
21197c478bd9Sstevel@tonic-gate 
21207c478bd9Sstevel@tonic-gate 			/* fall back to previous state */
21217c478bd9Sstevel@tonic-gate 			scsa2usbp->scsa2usb_dev_state = prev_state;
21227c478bd9Sstevel@tonic-gate 		} else {
21237c478bd9Sstevel@tonic-gate 			rval = USB_SUCCESS;
21247c478bd9Sstevel@tonic-gate 		}
21257c478bd9Sstevel@tonic-gate 
21267c478bd9Sstevel@tonic-gate 		break;
21277c478bd9Sstevel@tonic-gate 	case USB_DEV_SUSPENDED:
21287c478bd9Sstevel@tonic-gate 	default:
21297c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
21307c478bd9Sstevel@tonic-gate 		    "scsa2usb_cpr_suspend: Illegal dev state: %d",
21317c478bd9Sstevel@tonic-gate 		    scsa2usbp->scsa2usb_dev_state);
21327c478bd9Sstevel@tonic-gate 
21337c478bd9Sstevel@tonic-gate 		break;
21347c478bd9Sstevel@tonic-gate 	}
21357c478bd9Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
21367c478bd9Sstevel@tonic-gate 
21377c478bd9Sstevel@tonic-gate 	if ((rval == USB_SUCCESS) && scsa2usbp->scsa2usb_ugen_hdl) {
21387c478bd9Sstevel@tonic-gate 		rval = usb_ugen_detach(scsa2usbp->scsa2usb_ugen_hdl,
2139d94492edSfb 		    DDI_SUSPEND);
21407c478bd9Sstevel@tonic-gate 	}
21417c478bd9Sstevel@tonic-gate 
21427c478bd9Sstevel@tonic-gate 	return (rval);
21437c478bd9Sstevel@tonic-gate }
21447c478bd9Sstevel@tonic-gate 
21457c478bd9Sstevel@tonic-gate 
21467c478bd9Sstevel@tonic-gate /*
21477c478bd9Sstevel@tonic-gate  * scsa2usb_cpr_resume:
21487c478bd9Sstevel@tonic-gate  *	restore device's state
21497c478bd9Sstevel@tonic-gate  */
21507c478bd9Sstevel@tonic-gate static void
scsa2usb_cpr_resume(dev_info_t * dip)21517c478bd9Sstevel@tonic-gate scsa2usb_cpr_resume(dev_info_t *dip)
21527c478bd9Sstevel@tonic-gate {
21537c478bd9Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp =
21547c478bd9Sstevel@tonic-gate 	    ddi_get_soft_state(scsa2usb_statep, ddi_get_instance(dip));
21557c478bd9Sstevel@tonic-gate 
21567c478bd9Sstevel@tonic-gate 	ASSERT(scsa2usbp != NULL);
21577c478bd9Sstevel@tonic-gate 
21587c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
2159112116d8Sfb 	    "scsa2usb_cpr_resume: dip = 0x%p", (void *)dip);
21607c478bd9Sstevel@tonic-gate 
21617c478bd9Sstevel@tonic-gate 	scsa2usb_restore_device_state(dip, scsa2usbp);
21627c478bd9Sstevel@tonic-gate 
21637c478bd9Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_ugen_hdl) {
21647c478bd9Sstevel@tonic-gate 		(void) usb_ugen_attach(scsa2usbp->scsa2usb_ugen_hdl,
2165d94492edSfb 		    DDI_RESUME);
21667c478bd9Sstevel@tonic-gate 	}
21677c478bd9Sstevel@tonic-gate }
21687c478bd9Sstevel@tonic-gate 
21697c478bd9Sstevel@tonic-gate 
21707c478bd9Sstevel@tonic-gate /*
21717c478bd9Sstevel@tonic-gate  * scsa2usb_restore_device_state:
21727c478bd9Sstevel@tonic-gate  *	- raise the device's power
21737c478bd9Sstevel@tonic-gate  *	- reopen all the pipes
21747c478bd9Sstevel@tonic-gate  */
21757c478bd9Sstevel@tonic-gate static void
scsa2usb_restore_device_state(dev_info_t * dip,scsa2usb_state_t * scsa2usbp)21767c478bd9Sstevel@tonic-gate scsa2usb_restore_device_state(dev_info_t *dip, scsa2usb_state_t *scsa2usbp)
21777c478bd9Sstevel@tonic-gate {
21787c478bd9Sstevel@tonic-gate 	uint_t	prev_state;
21797c478bd9Sstevel@tonic-gate 
21807c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
21817c478bd9Sstevel@tonic-gate 	    "scsa2usb_restore_device_state:");
21827c478bd9Sstevel@tonic-gate 
21837c478bd9Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
21847c478bd9Sstevel@tonic-gate 	prev_state = scsa2usbp->scsa2usb_dev_state;
21857c478bd9Sstevel@tonic-gate 
21867c478bd9Sstevel@tonic-gate 	scsa2usb_raise_power(scsa2usbp);
21877c478bd9Sstevel@tonic-gate 
21887c478bd9Sstevel@tonic-gate 	ASSERT((prev_state == USB_DEV_DISCONNECTED) ||
21897c478bd9Sstevel@tonic-gate 	    (prev_state == USB_DEV_SUSPENDED));
21907c478bd9Sstevel@tonic-gate 
21917c478bd9Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
21927c478bd9Sstevel@tonic-gate 
21937c478bd9Sstevel@tonic-gate 	/* Check for the same device */
21947c478bd9Sstevel@tonic-gate 	if (usb_check_same_device(dip, scsa2usbp->scsa2usb_log_handle,
21957c478bd9Sstevel@tonic-gate 	    USB_LOG_L0, DPRINT_MASK_ALL, USB_CHK_ALL, NULL) != USB_SUCCESS) {
21967c478bd9Sstevel@tonic-gate 
21977c478bd9Sstevel@tonic-gate 		/* change the flags to active */
21987c478bd9Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
21997c478bd9Sstevel@tonic-gate 		scsa2usbp->scsa2usb_dev_state = USB_DEV_DISCONNECTED;
2200496d8c83Sfrits 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
22017c478bd9Sstevel@tonic-gate 
22027c478bd9Sstevel@tonic-gate 		scsa2usb_pm_idle_component(scsa2usbp);
22037c478bd9Sstevel@tonic-gate 
22047c478bd9Sstevel@tonic-gate 		return;
22057c478bd9Sstevel@tonic-gate 	}
22067c478bd9Sstevel@tonic-gate 
22077c478bd9Sstevel@tonic-gate 	/*
22087c478bd9Sstevel@tonic-gate 	 * if the device had remote wakeup earlier,
22097c478bd9Sstevel@tonic-gate 	 * enable it again
22107c478bd9Sstevel@tonic-gate 	 */
22117c478bd9Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
22127c478bd9Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_pm &&
22137c478bd9Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_pm->scsa2usb_wakeup_enabled) {
22147c478bd9Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
22157c478bd9Sstevel@tonic-gate 		(void) usb_handle_remote_wakeup(scsa2usbp->scsa2usb_dip,
22167c478bd9Sstevel@tonic-gate 		    USB_REMOTE_WAKEUP_ENABLE);
22177c478bd9Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
22187c478bd9Sstevel@tonic-gate 	}
22197c478bd9Sstevel@tonic-gate 
22207c478bd9Sstevel@tonic-gate 	scsa2usbp->scsa2usb_dev_state = USB_DEV_ONLINE;
22217c478bd9Sstevel@tonic-gate 	scsa2usbp->scsa2usb_pkt_state = SCSA2USB_PKT_NONE;
2222496d8c83Sfrits 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
22237c478bd9Sstevel@tonic-gate 
22247c478bd9Sstevel@tonic-gate 	scsa2usb_pm_idle_component(scsa2usbp);
22257c478bd9Sstevel@tonic-gate }
22267c478bd9Sstevel@tonic-gate 
22277c478bd9Sstevel@tonic-gate 
22287c478bd9Sstevel@tonic-gate /*
22297c478bd9Sstevel@tonic-gate  * SCSA entry points:
22307c478bd9Sstevel@tonic-gate  *
22317c478bd9Sstevel@tonic-gate  * scsa2usb_scsi_tgt_probe:
22327c478bd9Sstevel@tonic-gate  * scsa functions are exported by means of the transport table
22337c478bd9Sstevel@tonic-gate  * Issue a probe to get the inquiry data.
22347c478bd9Sstevel@tonic-gate  */
22357c478bd9Sstevel@tonic-gate /* ARGSUSED */
22367c478bd9Sstevel@tonic-gate static int
scsa2usb_scsi_tgt_probe(struct scsi_device * sd,int (* waitfunc)(void))22377c478bd9Sstevel@tonic-gate scsa2usb_scsi_tgt_probe(struct scsi_device *sd, int (*waitfunc)(void))
22387c478bd9Sstevel@tonic-gate {
22397c478bd9Sstevel@tonic-gate 	scsi_hba_tran_t *tran;
22407c478bd9Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp;
22417c478bd9Sstevel@tonic-gate 	dev_info_t *dip = ddi_get_parent(sd->sd_dev);
22420167b58cScg 	int	rval;
22437c478bd9Sstevel@tonic-gate 
22447c478bd9Sstevel@tonic-gate 	ASSERT(dip);
22457c478bd9Sstevel@tonic-gate 
22467c478bd9Sstevel@tonic-gate 	tran = ddi_get_driver_private(dip);
22477c478bd9Sstevel@tonic-gate 	ASSERT(tran != NULL);
22487c478bd9Sstevel@tonic-gate 	scsa2usbp = (scsa2usb_state_t *)tran->tran_hba_private;
22497c478bd9Sstevel@tonic-gate 	ASSERT(scsa2usbp);
22507c478bd9Sstevel@tonic-gate 
22517c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
22527c478bd9Sstevel@tonic-gate 	    "scsa2usb_scsi_tgt_probe:");
22537c478bd9Sstevel@tonic-gate 
22547c478bd9Sstevel@tonic-gate 	/* if device is disconnected (ie. pipes closed), fail immediately */
22557c478bd9Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
22567c478bd9Sstevel@tonic-gate 	if (!(SCSA2USB_DEVICE_ACCESS_OK(scsa2usbp))) {
22577c478bd9Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
22587c478bd9Sstevel@tonic-gate 
22597c478bd9Sstevel@tonic-gate 		return (SCSIPROBE_FAILURE);
22607c478bd9Sstevel@tonic-gate 	}
22617c478bd9Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
22627c478bd9Sstevel@tonic-gate 
22637c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
2264112116d8Sfb 	    "scsa2usb_scsi_tgt_probe: scsi_device = 0x%p", (void *)sd);
22657c478bd9Sstevel@tonic-gate 
22667c478bd9Sstevel@tonic-gate 	if ((rval = scsi_hba_probe(sd, waitfunc)) == SCSIPROBE_EXISTS) {
22677c478bd9Sstevel@tonic-gate 		/*
22680167b58cScg 		 * respect the removable bit on all USB storage devices
22697c478bd9Sstevel@tonic-gate 		 * unless overridden by a scsa2usb.conf entry
22707c478bd9Sstevel@tonic-gate 		 */
22717c478bd9Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
22720167b58cScg 		if (!(scsa2usbp->scsa2usb_attrs & SCSA2USB_ATTRS_RMB)) {
22737c478bd9Sstevel@tonic-gate 			_NOTE(SCHEME_PROTECTS_DATA("unshared", scsi_inquiry))
22747c478bd9Sstevel@tonic-gate 			sd->sd_inq->inq_rmb = 1;
22757c478bd9Sstevel@tonic-gate 		}
22767c478bd9Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
22777c478bd9Sstevel@tonic-gate 	}
22787c478bd9Sstevel@tonic-gate 
22797c478bd9Sstevel@tonic-gate 	return (rval);
22807c478bd9Sstevel@tonic-gate }
22817c478bd9Sstevel@tonic-gate 
22827c478bd9Sstevel@tonic-gate 
22837c478bd9Sstevel@tonic-gate /*
22847c478bd9Sstevel@tonic-gate  * scsa2usb_scsi_tgt_init:
22857c478bd9Sstevel@tonic-gate  *	check whether we created this child ourselves
22867c478bd9Sstevel@tonic-gate  */
22877c478bd9Sstevel@tonic-gate /* ARGSUSED */
22887c478bd9Sstevel@tonic-gate static int
scsa2usb_scsi_tgt_init(dev_info_t * dip,dev_info_t * cdip,scsi_hba_tran_t * tran,struct scsi_device * sd)22897c478bd9Sstevel@tonic-gate scsa2usb_scsi_tgt_init(dev_info_t *dip, dev_info_t *cdip,
22907c478bd9Sstevel@tonic-gate     scsi_hba_tran_t *tran, struct scsi_device *sd)
22917c478bd9Sstevel@tonic-gate {
22927c478bd9Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp = (scsa2usb_state_t *)
2293d94492edSfb 	    tran->tran_hba_private;
22947c478bd9Sstevel@tonic-gate 	int lun;
22957c478bd9Sstevel@tonic-gate 	int t_len = sizeof (lun);
22967c478bd9Sstevel@tonic-gate 
22977c478bd9Sstevel@tonic-gate 	if (ddi_prop_op(DDI_DEV_T_ANY, cdip, PROP_LEN_AND_VAL_BUF,
22987c478bd9Sstevel@tonic-gate 	    DDI_PROP_DONTPASS|DDI_PROP_CANSLEEP, "lun", (caddr_t)&lun,
22997c478bd9Sstevel@tonic-gate 	    &t_len) != DDI_PROP_SUCCESS) {
23007c478bd9Sstevel@tonic-gate 
23017c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
23027c478bd9Sstevel@tonic-gate 	}
23037c478bd9Sstevel@tonic-gate 
23047c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
23057c478bd9Sstevel@tonic-gate 	    "scsa2usb_scsi_tgt_init: %s, lun%d", ddi_driver_name(cdip), lun);
23067c478bd9Sstevel@tonic-gate 
23077c478bd9Sstevel@tonic-gate 	/* is this a child we created? */
23087c478bd9Sstevel@tonic-gate 	if (scsa2usb_is_usb(cdip) == 0) {
23097c478bd9Sstevel@tonic-gate 
23107c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
23117c478bd9Sstevel@tonic-gate 		    "scsa2usb_scsi_tgt_init: new child %s%d",
23127c478bd9Sstevel@tonic-gate 		    ddi_driver_name(cdip), ddi_get_instance(cdip));
23137c478bd9Sstevel@tonic-gate 
23147c478bd9Sstevel@tonic-gate 		/*
23157c478bd9Sstevel@tonic-gate 		 * add property "usb" so we can always verify that it
23167c478bd9Sstevel@tonic-gate 		 * is our child
23177c478bd9Sstevel@tonic-gate 		 */
23187c478bd9Sstevel@tonic-gate 		if (ndi_prop_create_boolean(DDI_DEV_T_NONE, cdip, "usb") !=
23197c478bd9Sstevel@tonic-gate 		    DDI_PROP_SUCCESS) {
23207c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_SCSA,
23217c478bd9Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
23227c478bd9Sstevel@tonic-gate 			    "ndi_prop_create_boolean failed");
23237c478bd9Sstevel@tonic-gate 
23247c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
23257c478bd9Sstevel@tonic-gate 		}
23267c478bd9Sstevel@tonic-gate 
23277c478bd9Sstevel@tonic-gate 		usba_set_usba_device(cdip,
2328d94492edSfb 		    usba_get_usba_device(scsa2usbp->scsa2usb_dip));
23297c478bd9Sstevel@tonic-gate 
23307c478bd9Sstevel@tonic-gate 		/*
23317c478bd9Sstevel@tonic-gate 		 * we don't store this dip in scsa2usb_lun_dip, there
23327c478bd9Sstevel@tonic-gate 		 * might be multiple dips for the same device
23337c478bd9Sstevel@tonic-gate 		 */
23347c478bd9Sstevel@tonic-gate 
23357c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
23367c478bd9Sstevel@tonic-gate 	}
23377c478bd9Sstevel@tonic-gate 
23387c478bd9Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
23397c478bd9Sstevel@tonic-gate 	if ((lun >= scsa2usbp->scsa2usb_n_luns) ||
23407c478bd9Sstevel@tonic-gate 	    (scsa2usbp->scsa2usb_lun_dip[lun] != NULL)) {
23417c478bd9Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
23427c478bd9Sstevel@tonic-gate 
23437c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
23447c478bd9Sstevel@tonic-gate 	}
23457c478bd9Sstevel@tonic-gate 
23467c478bd9Sstevel@tonic-gate 	scsa2usbp->scsa2usb_lun_dip[lun] = cdip;
23477c478bd9Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
23487c478bd9Sstevel@tonic-gate 
23497c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
23507c478bd9Sstevel@tonic-gate }
23517c478bd9Sstevel@tonic-gate 
23527c478bd9Sstevel@tonic-gate 
23537c478bd9Sstevel@tonic-gate /*
23547c478bd9Sstevel@tonic-gate  * scsa2usb_scsi_tgt_free:
23557c478bd9Sstevel@tonic-gate  */
23567c478bd9Sstevel@tonic-gate /* ARGSUSED */
23577c478bd9Sstevel@tonic-gate static void
scsa2usb_scsi_tgt_free(dev_info_t * hba_dip,dev_info_t * cdip,scsi_hba_tran_t * tran,struct scsi_device * sd)23587c478bd9Sstevel@tonic-gate scsa2usb_scsi_tgt_free(dev_info_t *hba_dip, dev_info_t *cdip,
2359993e3fafSRobert Mustacchi     scsi_hba_tran_t *tran, struct scsi_device *sd)
23607c478bd9Sstevel@tonic-gate {
23617c478bd9Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp = (scsa2usb_state_t *)
2362d94492edSfb 	    tran->tran_hba_private;
23637c478bd9Sstevel@tonic-gate 	int lun;
23647c478bd9Sstevel@tonic-gate 	int t_len = sizeof (lun);
23657c478bd9Sstevel@tonic-gate 
23667c478bd9Sstevel@tonic-gate 	/* is this our child? */
23677c478bd9Sstevel@tonic-gate 	if (scsa2usb_is_usb(cdip) == 0) {
23687c478bd9Sstevel@tonic-gate 
23697c478bd9Sstevel@tonic-gate 		return;
23707c478bd9Sstevel@tonic-gate 	}
23717c478bd9Sstevel@tonic-gate 
23727c478bd9Sstevel@tonic-gate 	if (ddi_prop_op(DDI_DEV_T_ANY, cdip, PROP_LEN_AND_VAL_BUF,
23737c478bd9Sstevel@tonic-gate 	    DDI_PROP_DONTPASS|DDI_PROP_CANSLEEP, "lun", (caddr_t)&lun,
23747c478bd9Sstevel@tonic-gate 	    &t_len) != DDI_PROP_SUCCESS) {
23757c478bd9Sstevel@tonic-gate 
23767c478bd9Sstevel@tonic-gate 		return;
23777c478bd9Sstevel@tonic-gate 	}
23787c478bd9Sstevel@tonic-gate 
23797c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
23807c478bd9Sstevel@tonic-gate 	    "scsa2usb_scsi_tgt_free: %s lun%d", ddi_driver_name(cdip), lun);
23817c478bd9Sstevel@tonic-gate 
23827c478bd9Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
23837c478bd9Sstevel@tonic-gate 	if (lun < scsa2usbp->scsa2usb_n_luns) {
23847c478bd9Sstevel@tonic-gate 		if (scsa2usbp->scsa2usb_lun_dip[lun] == cdip) {
23857c478bd9Sstevel@tonic-gate 			scsa2usbp->scsa2usb_lun_dip[lun] = NULL;
23867c478bd9Sstevel@tonic-gate 		}
23877c478bd9Sstevel@tonic-gate 	}
23887c478bd9Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
23897c478bd9Sstevel@tonic-gate }
23907c478bd9Sstevel@tonic-gate 
23917c478bd9Sstevel@tonic-gate 
23927c478bd9Sstevel@tonic-gate /*
23937c478bd9Sstevel@tonic-gate  * bus enumeration entry points
23947c478bd9Sstevel@tonic-gate  */
23957c478bd9Sstevel@tonic-gate static int
scsa2usb_scsi_bus_config(dev_info_t * dip,uint_t flag,ddi_bus_config_op_t op,void * arg,dev_info_t ** child)23967c478bd9Sstevel@tonic-gate scsa2usb_scsi_bus_config(dev_info_t *dip, uint_t flag, ddi_bus_config_op_t op,
23977c478bd9Sstevel@tonic-gate     void *arg, dev_info_t **child)
23987c478bd9Sstevel@tonic-gate {
23997c478bd9Sstevel@tonic-gate 	int	rval;
24007c478bd9Sstevel@tonic-gate 
24017c478bd9Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp =
24027c478bd9Sstevel@tonic-gate 	    ddi_get_soft_state(scsa2usb_statep, ddi_get_instance(dip));
24037c478bd9Sstevel@tonic-gate 
24047c478bd9Sstevel@tonic-gate 	ASSERT(scsa2usbp != NULL);
24057c478bd9Sstevel@tonic-gate 
24067c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
24077c478bd9Sstevel@tonic-gate 	    "scsa2usb_scsi_bus_config: op=%d", op);
24087c478bd9Sstevel@tonic-gate 
24097c478bd9Sstevel@tonic-gate 	if (scsa2usb_scsi_bus_config_debug) {
24107c478bd9Sstevel@tonic-gate 		flag |= NDI_DEVI_DEBUG;
24117c478bd9Sstevel@tonic-gate 	}
24127c478bd9Sstevel@tonic-gate 
2413*3fe80ca4SDan Cross 	ndi_devi_enter(dip);
24147c478bd9Sstevel@tonic-gate 	/* create children if necessary */
24157c478bd9Sstevel@tonic-gate 	if (DEVI(dip)->devi_child == NULL) {
24167c478bd9Sstevel@tonic-gate 		scsa2usb_create_luns(scsa2usbp);
24177c478bd9Sstevel@tonic-gate 	}
24187c478bd9Sstevel@tonic-gate 
24197c478bd9Sstevel@tonic-gate 	rval = ndi_busop_bus_config(dip, flag, op, arg, child, 0);
24207c478bd9Sstevel@tonic-gate 
2421*3fe80ca4SDan Cross 	ndi_devi_exit(dip);
24227c478bd9Sstevel@tonic-gate 
24237c478bd9Sstevel@tonic-gate 	return (rval);
24247c478bd9Sstevel@tonic-gate }
24257c478bd9Sstevel@tonic-gate 
24267c478bd9Sstevel@tonic-gate 
24277c478bd9Sstevel@tonic-gate static int
scsa2usb_scsi_bus_unconfig(dev_info_t * dip,uint_t flag,ddi_bus_config_op_t op,void * arg)24287c478bd9Sstevel@tonic-gate scsa2usb_scsi_bus_unconfig(dev_info_t *dip, uint_t flag, ddi_bus_config_op_t op,
24297c478bd9Sstevel@tonic-gate     void *arg)
24307c478bd9Sstevel@tonic-gate {
24317c478bd9Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp =
24327c478bd9Sstevel@tonic-gate 	    ddi_get_soft_state(scsa2usb_statep, ddi_get_instance(dip));
24337c478bd9Sstevel@tonic-gate 
24347c478bd9Sstevel@tonic-gate 	int		rval = NDI_SUCCESS;
24357c478bd9Sstevel@tonic-gate 	uint_t		save_flag = flag;
24367c478bd9Sstevel@tonic-gate 
24377c478bd9Sstevel@tonic-gate 	ASSERT(scsa2usbp != NULL);
24387c478bd9Sstevel@tonic-gate 
24397c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
24407c478bd9Sstevel@tonic-gate 	    "scsa2usb_scsi_bus_unconfig: op=%d", op);
24417c478bd9Sstevel@tonic-gate 
24427c478bd9Sstevel@tonic-gate 	if (scsa2usb_scsi_bus_config_debug) {
24437c478bd9Sstevel@tonic-gate 		flag |= NDI_DEVI_DEBUG;
24447c478bd9Sstevel@tonic-gate 	}
24457c478bd9Sstevel@tonic-gate 
24467c478bd9Sstevel@tonic-gate 	/*
24477c478bd9Sstevel@tonic-gate 	 * first offline and if offlining successful, then
24487c478bd9Sstevel@tonic-gate 	 * remove children
24497c478bd9Sstevel@tonic-gate 	 */
24507c478bd9Sstevel@tonic-gate 	if (op == BUS_UNCONFIG_ALL) {
24517c478bd9Sstevel@tonic-gate 		flag &= ~(NDI_DEVI_REMOVE | NDI_UNCONFIG);
24527c478bd9Sstevel@tonic-gate 	}
24537c478bd9Sstevel@tonic-gate 
2454*3fe80ca4SDan Cross 	ndi_devi_enter(dip);
24557c478bd9Sstevel@tonic-gate 	rval = ndi_busop_bus_unconfig(dip, flag, op, arg);
24567c478bd9Sstevel@tonic-gate 
24577c478bd9Sstevel@tonic-gate 	/*
24587c478bd9Sstevel@tonic-gate 	 * If unconfig is successful and not part of modunload
24597c478bd9Sstevel@tonic-gate 	 * daemon, attempt to remove children.
24607c478bd9Sstevel@tonic-gate 	 */
24617c478bd9Sstevel@tonic-gate 	if (op == BUS_UNCONFIG_ALL && rval == NDI_SUCCESS &&
24627c478bd9Sstevel@tonic-gate 	    (flag & NDI_AUTODETACH) == 0) {
24637c478bd9Sstevel@tonic-gate 		flag |= NDI_DEVI_REMOVE;
24647c478bd9Sstevel@tonic-gate 		rval = ndi_busop_bus_unconfig(dip, flag, op, arg);
24657c478bd9Sstevel@tonic-gate 	}
2466*3fe80ca4SDan Cross 	ndi_devi_exit(dip);
24677c478bd9Sstevel@tonic-gate 
24687c478bd9Sstevel@tonic-gate 	if ((rval != NDI_SUCCESS) && (op == BUS_UNCONFIG_ALL) &&
24697c478bd9Sstevel@tonic-gate 	    (save_flag & NDI_DEVI_REMOVE)) {
24707c478bd9Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
24717c478bd9Sstevel@tonic-gate 		if (scsa2usbp->scsa2usb_warning_given != B_TRUE) {
247267318e4aSlg 			USB_DPRINTF_L2(DPRINT_MASK_SCSA,
24737c478bd9Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
24747c478bd9Sstevel@tonic-gate 			    "Disconnected device was busy, "
24757c478bd9Sstevel@tonic-gate 			    "please reconnect.");
24767c478bd9Sstevel@tonic-gate 			scsa2usbp->scsa2usb_warning_given = B_TRUE;
24777c478bd9Sstevel@tonic-gate 		}
24787c478bd9Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
24797c478bd9Sstevel@tonic-gate 	}
24807c478bd9Sstevel@tonic-gate 
24817c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
24827c478bd9Sstevel@tonic-gate 	    "scsa2usb_scsi_bus_unconfig: rval=%d", rval);
24837c478bd9Sstevel@tonic-gate 
24847c478bd9Sstevel@tonic-gate 	return (rval);
24857c478bd9Sstevel@tonic-gate }
24867c478bd9Sstevel@tonic-gate 
24877c478bd9Sstevel@tonic-gate 
24887c478bd9Sstevel@tonic-gate /*
24897c478bd9Sstevel@tonic-gate  * scsa2usb_scsi_init_pkt:
24907c478bd9Sstevel@tonic-gate  *	Set up the scsi_pkt for transport. Also initialize
24917c478bd9Sstevel@tonic-gate  *	scsa2usb_cmd struct for the transport.
24927c478bd9Sstevel@tonic-gate  *	NOTE: We do not do any DMA setup here as USBA framework
24937c478bd9Sstevel@tonic-gate  *	does that for us.
24947c478bd9Sstevel@tonic-gate  */
24957c478bd9Sstevel@tonic-gate static struct scsi_pkt *
scsa2usb_scsi_init_pkt(struct scsi_address * ap,struct scsi_pkt * pkt,struct buf * bp,int cmdlen,int statuslen,int tgtlen,int flags,int (* callback)(),caddr_t arg)24967c478bd9Sstevel@tonic-gate scsa2usb_scsi_init_pkt(struct scsi_address *ap,
24977c478bd9Sstevel@tonic-gate     struct scsi_pkt *pkt, struct buf *bp, int cmdlen, int statuslen,
24987c478bd9Sstevel@tonic-gate     int tgtlen, int flags, int (*callback)(), caddr_t arg)
24997c478bd9Sstevel@tonic-gate {
25007c478bd9Sstevel@tonic-gate 	scsa2usb_cmd_t	 *cmd;
25017c478bd9Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp;
25027c478bd9Sstevel@tonic-gate 	struct scsi_pkt	 *in_pkt = pkt;
25037c478bd9Sstevel@tonic-gate 
25047c478bd9Sstevel@tonic-gate 	ASSERT(callback == NULL_FUNC || callback == SLEEP_FUNC);
25057c478bd9Sstevel@tonic-gate 
25067c478bd9Sstevel@tonic-gate 	scsa2usbp = (scsa2usb_state_t *)ADDR2SCSA2USB(ap);
25077c478bd9Sstevel@tonic-gate 
25087c478bd9Sstevel@tonic-gate 	/* Print sync message */
25097c478bd9Sstevel@tonic-gate 	if (ddi_in_panic()) {
25107c478bd9Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
25117c478bd9Sstevel@tonic-gate 		SCSA2USB_PRINT_SYNC_MSG(scsa2usb_sync_message, scsa2usbp);
25127c478bd9Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
25137c478bd9Sstevel@tonic-gate 		/* continue so caller will not hang or complain */
25147c478bd9Sstevel@tonic-gate 	}
25157c478bd9Sstevel@tonic-gate 
25167c478bd9Sstevel@tonic-gate 	/* allocate a pkt, if none already allocated */
25177c478bd9Sstevel@tonic-gate 	if (pkt == NULL) {
25187c478bd9Sstevel@tonic-gate 		if (statuslen < sizeof (struct scsi_arq_status)) {
25197c478bd9Sstevel@tonic-gate 			statuslen = sizeof (struct scsi_arq_status);
25207c478bd9Sstevel@tonic-gate 		}
25217c478bd9Sstevel@tonic-gate 
25227c478bd9Sstevel@tonic-gate 		pkt = scsi_hba_pkt_alloc(scsa2usbp->scsa2usb_dip, ap, cmdlen,
2523d94492edSfb 		    statuslen, tgtlen, sizeof (scsa2usb_cmd_t),
2524d94492edSfb 		    callback, arg);
25257c478bd9Sstevel@tonic-gate 		if (pkt == NULL) {
25267c478bd9Sstevel@tonic-gate 
25277c478bd9Sstevel@tonic-gate 			return (NULL);
25287c478bd9Sstevel@tonic-gate 		}
25297c478bd9Sstevel@tonic-gate 
25307c478bd9Sstevel@tonic-gate 		cmd = PKT2CMD(pkt);
25317c478bd9Sstevel@tonic-gate 		cmd->cmd_pkt	= pkt; /* back link to pkt */
25327c478bd9Sstevel@tonic-gate 		cmd->cmd_scblen	= statuslen;
25337c478bd9Sstevel@tonic-gate 		cmd->cmd_cdblen	= (uchar_t)cmdlen;
25347c478bd9Sstevel@tonic-gate 
25357c478bd9Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
25367c478bd9Sstevel@tonic-gate 		cmd->cmd_tag	= scsa2usbp->scsa2usb_tag++;
25377c478bd9Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
25387c478bd9Sstevel@tonic-gate 
25397c478bd9Sstevel@tonic-gate 		cmd->cmd_bp	= bp;
2540fae6130aSlh 		/*
2541fae6130aSlh 		 * The buffer size of cmd->cmd_scb is constrained
2542fae6130aSlh 		 * to sizeof (struct scsi_arq_status), if the scblen
2543fae6130aSlh 		 * is bigger than that, we use pkt->pkt_scbp directly.
2544fae6130aSlh 		 */
2545fae6130aSlh 		if (cmd->cmd_scblen == sizeof (struct scsi_arq_status)) {
2546fae6130aSlh 			pkt->pkt_scbp = (opaque_t)&cmd->cmd_scb;
2547fae6130aSlh 		}
25487c478bd9Sstevel@tonic-gate 
25497c478bd9Sstevel@tonic-gate 		usba_init_list(&cmd->cmd_waitQ, (usb_opaque_t)cmd,
2550d94492edSfb 		    scsa2usbp->scsa2usb_dev_data->dev_iblock_cookie);
25517c478bd9Sstevel@tonic-gate 	} else {
25527c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
25537c478bd9Sstevel@tonic-gate 		    "scsa2usb: pkt != NULL");
25547c478bd9Sstevel@tonic-gate 
25557c478bd9Sstevel@tonic-gate 		/* nothing to do */
25567c478bd9Sstevel@tonic-gate 	}
25577c478bd9Sstevel@tonic-gate 
2558df4cb6e0Ssl 	if (bp && (bp->b_bcount != 0)) {
25597c478bd9Sstevel@tonic-gate 		if ((bp_mapin_common(bp, (callback == SLEEP_FUNC) ?
25607c478bd9Sstevel@tonic-gate 		    VM_SLEEP : VM_NOSLEEP)) == NULL) {
25617c478bd9Sstevel@tonic-gate 			if (pkt != in_pkt) {
25627c478bd9Sstevel@tonic-gate 				scsi_hba_pkt_free(ap, pkt);
25637c478bd9Sstevel@tonic-gate 			}
25647c478bd9Sstevel@tonic-gate 
25657c478bd9Sstevel@tonic-gate 			return (NULL);
25667c478bd9Sstevel@tonic-gate 		}
25677c478bd9Sstevel@tonic-gate 
25687c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(DPRINT_MASK_SCSA,
25697c478bd9Sstevel@tonic-gate 		    scsa2usbp->scsa2usb_log_handle,
25707c478bd9Sstevel@tonic-gate 		    "scsa2usb_scsi_init_pkt: mapped in 0x%p, addr=0x%p",
2571112116d8Sfb 		    (void *)bp, (void *)bp->b_un.b_addr);
25727c478bd9Sstevel@tonic-gate 	}
25737c478bd9Sstevel@tonic-gate 
25747c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
25757c478bd9Sstevel@tonic-gate 	    "scsa2usb_scsi_init_pkt: ap = 0x%p pkt: 0x%p\n\t"
25767c478bd9Sstevel@tonic-gate 	    "bp = 0x%p cmdlen = %x stlen = 0x%x tlen = 0x%x flags = 0x%x",
2577112116d8Sfb 	    (void *)ap, (void *)pkt, (void *)bp, cmdlen, statuslen,
2578112116d8Sfb 	    tgtlen, flags);
25797c478bd9Sstevel@tonic-gate 
25807c478bd9Sstevel@tonic-gate 	return (pkt);
25817c478bd9Sstevel@tonic-gate }
25827c478bd9Sstevel@tonic-gate 
25837c478bd9Sstevel@tonic-gate 
25847c478bd9Sstevel@tonic-gate /*
25857c478bd9Sstevel@tonic-gate  * scsa2usb_scsi_destroy_pkt:
25867c478bd9Sstevel@tonic-gate  *	We are done with the packet. Get rid of it.
25877c478bd9Sstevel@tonic-gate  */
25887c478bd9Sstevel@tonic-gate static void
scsa2usb_scsi_destroy_pkt(struct scsi_address * ap,struct scsi_pkt * pkt)25897c478bd9Sstevel@tonic-gate scsa2usb_scsi_destroy_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
25907c478bd9Sstevel@tonic-gate {
25917c478bd9Sstevel@tonic-gate 	scsa2usb_cmd_t *cmd = PKT2CMD(pkt);
25927c478bd9Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp = ADDR2SCSA2USB(ap);
25937c478bd9Sstevel@tonic-gate 
25947c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
2595112116d8Sfb 	    "scsa2usb_scsi_destroy_pkt: pkt=0x%p", (void *)pkt);
25967c478bd9Sstevel@tonic-gate 
25977c478bd9Sstevel@tonic-gate 	usba_destroy_list(&cmd->cmd_waitQ);
25987c478bd9Sstevel@tonic-gate 	scsi_hba_pkt_free(ap, pkt);
25997c478bd9Sstevel@tonic-gate }
26007c478bd9Sstevel@tonic-gate 
26017c478bd9Sstevel@tonic-gate 
26027c478bd9Sstevel@tonic-gate /*
26037c478bd9Sstevel@tonic-gate  * scsa2usb_scsi_start:
26047c478bd9Sstevel@tonic-gate  *	For each command being issued, build up the CDB
26057c478bd9Sstevel@tonic-gate  *	and call scsi_transport to issue the command. This
26067c478bd9Sstevel@tonic-gate  *	function is based on the assumption that USB allows
26077c478bd9Sstevel@tonic-gate  *	a subset of SCSI commands. Other SCSI commands we fail.
26087c478bd9Sstevel@tonic-gate  */
26097c478bd9Sstevel@tonic-gate static int
scsa2usb_scsi_start(struct scsi_address * ap,struct scsi_pkt * pkt)26107c478bd9Sstevel@tonic-gate scsa2usb_scsi_start(struct scsi_address *ap, struct scsi_pkt *pkt)
26117c478bd9Sstevel@tonic-gate {
26127c478bd9Sstevel@tonic-gate 	scsa2usb_cmd_t		*cmd;
26137c478bd9Sstevel@tonic-gate 	scsa2usb_state_t	*scsa2usbp = ADDR2SCSA2USB(ap);
26147c478bd9Sstevel@tonic-gate 	uint_t			lun = ap->a_lun;
26157c478bd9Sstevel@tonic-gate 
26167c478bd9Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
26177c478bd9Sstevel@tonic-gate 
26187c478bd9Sstevel@tonic-gate 	cmd = PKT2CMD(pkt);
26197c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
26207c478bd9Sstevel@tonic-gate 	    "scsa2usb_scsi_start:\n\t"
26217c478bd9Sstevel@tonic-gate 	    "bp: 0x%p ap: 0x%p pkt: 0x%p flag: 0x%x time: 0x%x\n\tcdb0: 0x%x "
26227c478bd9Sstevel@tonic-gate 	    "dev_state: 0x%x pkt_state: 0x%x flags: 0x%x pipe_state: 0x%x",
2623112116d8Sfb 	    (void *)cmd->cmd_bp, (void *)ap, (void *)pkt, pkt->pkt_flags,
2624112116d8Sfb 	    pkt->pkt_time, pkt->pkt_cdbp[0], scsa2usbp->scsa2usb_dev_state,
26257c478bd9Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_pkt_state, scsa2usbp->scsa2usb_flags,
26267c478bd9Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_pipe_state);
26277c478bd9Sstevel@tonic-gate 
26287c478bd9Sstevel@tonic-gate 	if (pkt->pkt_time == 0) {
26297c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L1(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
26307c478bd9Sstevel@tonic-gate 		    "pkt submitted with 0 timeout which may cause indefinite "
26317c478bd9Sstevel@tonic-gate 		    "hangs");
26327c478bd9Sstevel@tonic-gate 	}
26337c478bd9Sstevel@tonic-gate 
26347c478bd9Sstevel@tonic-gate 	/*
26357c478bd9Sstevel@tonic-gate 	 * if we are in panic, we are in polled mode, so we can just
26367c478bd9Sstevel@tonic-gate 	 * accept the request, drop it and return
26377c478bd9Sstevel@tonic-gate 	 * if we fail this request, the rest of the file systems do not
26387c478bd9Sstevel@tonic-gate 	 * get synced
26397c478bd9Sstevel@tonic-gate 	 */
26407c478bd9Sstevel@tonic-gate 	if (ddi_in_panic()) {
26417c478bd9Sstevel@tonic-gate 		extern int do_polled_io;
26427c478bd9Sstevel@tonic-gate 
26437c478bd9Sstevel@tonic-gate 		ASSERT(do_polled_io);
26447c478bd9Sstevel@tonic-gate 		scsa2usb_prepare_pkt(scsa2usbp, pkt);
26457c478bd9Sstevel@tonic-gate 		SCSA2USB_PRINT_SYNC_MSG(scsa2usb_sync_message, scsa2usbp);
26467c478bd9Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
26477c478bd9Sstevel@tonic-gate 
26487c478bd9Sstevel@tonic-gate 		return (TRAN_ACCEPT);
26497c478bd9Sstevel@tonic-gate 	}
26507c478bd9Sstevel@tonic-gate 
26517c478bd9Sstevel@tonic-gate 	/* we cannot do polling, this should not happen */
26527c478bd9Sstevel@tonic-gate 	if (pkt->pkt_flags & FLAG_NOINTR) {
26537c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
26547c478bd9Sstevel@tonic-gate 		    "NOINTR packet: opcode = 0%x", pkt->pkt_cdbp[0]);
26557c478bd9Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
26567c478bd9Sstevel@tonic-gate 
26577c478bd9Sstevel@tonic-gate 		return (TRAN_BADPKT);
26587c478bd9Sstevel@tonic-gate 	}
26597c478bd9Sstevel@tonic-gate 
26607c478bd9Sstevel@tonic-gate 	/* prepare packet */
26617c478bd9Sstevel@tonic-gate 	scsa2usb_prepare_pkt(scsa2usbp, pkt);
26627c478bd9Sstevel@tonic-gate 
26637c478bd9Sstevel@tonic-gate 	/* just queue up the requests in the waitQ if below max */
26647c478bd9Sstevel@tonic-gate 	if (usba_list_entry_count(&scsa2usbp->scsa2usb_waitQ[lun]) >
26657c478bd9Sstevel@tonic-gate 	    SCSA2USB_MAX_REQ_PER_LUN) {
26667c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA,
26677c478bd9Sstevel@tonic-gate 		    scsa2usbp->scsa2usb_log_handle,
26687c478bd9Sstevel@tonic-gate 		    "scsa2usb_scsi_start: limit (%d) exceeded",
26697c478bd9Sstevel@tonic-gate 		    SCSA2USB_MAX_REQ_PER_LUN);
26707c478bd9Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
26717c478bd9Sstevel@tonic-gate 
26727c478bd9Sstevel@tonic-gate 		return (TRAN_BUSY);
26737c478bd9Sstevel@tonic-gate 	}
26747c478bd9Sstevel@tonic-gate 
26757c478bd9Sstevel@tonic-gate 	usba_add_to_list(&scsa2usbp->scsa2usb_waitQ[lun], &cmd->cmd_waitQ);
26767c478bd9Sstevel@tonic-gate 
2677496d8c83Sfrits 	USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
2678112116d8Sfb 	    "scsa2usb_work_thread_id=0x%p, count=%d, lun=%d",
2679112116d8Sfb 	    (void *)scsa2usbp->scsa2usb_work_thread_id,
2680496d8c83Sfrits 	    usba_list_entry_count(&scsa2usbp->scsa2usb_waitQ[lun]), lun);
2681496d8c83Sfrits 
26827c478bd9Sstevel@tonic-gate 	/* fire up a thread to start executing the protocol */
26837c478bd9Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_work_thread_id == 0) {
26847c478bd9Sstevel@tonic-gate 		if ((usb_async_req(scsa2usbp->scsa2usb_dip,
26857c478bd9Sstevel@tonic-gate 		    scsa2usb_work_thread,
26867c478bd9Sstevel@tonic-gate 		    (void *)scsa2usbp, USB_FLAGS_SLEEP)) != USB_SUCCESS) {
26877c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_SCSA,
26887c478bd9Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
26897c478bd9Sstevel@tonic-gate 			    "no work thread started");
26907c478bd9Sstevel@tonic-gate 
26917c478bd9Sstevel@tonic-gate 			if (usba_rm_from_list(
26927c478bd9Sstevel@tonic-gate 			    &scsa2usbp->scsa2usb_waitQ[lun],
26937c478bd9Sstevel@tonic-gate 			    &cmd->cmd_waitQ) == USB_SUCCESS) {
26947c478bd9Sstevel@tonic-gate 				mutex_exit(&scsa2usbp->scsa2usb_mutex);
26957c478bd9Sstevel@tonic-gate 
26967c478bd9Sstevel@tonic-gate 				return (TRAN_BUSY);
26977c478bd9Sstevel@tonic-gate 			} else {
26987c478bd9Sstevel@tonic-gate 
26997c478bd9Sstevel@tonic-gate 				mutex_exit(&scsa2usbp->scsa2usb_mutex);
27007c478bd9Sstevel@tonic-gate 
27017c478bd9Sstevel@tonic-gate 				return (TRAN_ACCEPT);
27027c478bd9Sstevel@tonic-gate 			}
27037c478bd9Sstevel@tonic-gate 		}
27047c478bd9Sstevel@tonic-gate 		scsa2usbp->scsa2usb_work_thread_id = (kthread_t *)1;
27057c478bd9Sstevel@tonic-gate 	}
2706496d8c83Sfrits 
27077c478bd9Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
27087c478bd9Sstevel@tonic-gate 
27097c478bd9Sstevel@tonic-gate 	return (TRAN_ACCEPT);
27107c478bd9Sstevel@tonic-gate }
27117c478bd9Sstevel@tonic-gate 
27127c478bd9Sstevel@tonic-gate 
27137c478bd9Sstevel@tonic-gate /*
27147c478bd9Sstevel@tonic-gate  * scsa2usb_scsi_abort:
27157c478bd9Sstevel@tonic-gate  *	Issue SCSI abort command. This function is a NOP.
27167c478bd9Sstevel@tonic-gate  */
27177c478bd9Sstevel@tonic-gate /* ARGSUSED */
27187c478bd9Sstevel@tonic-gate static int
scsa2usb_scsi_abort(struct scsi_address * ap,struct scsi_pkt * pkt)27197c478bd9Sstevel@tonic-gate scsa2usb_scsi_abort(struct scsi_address *ap, struct scsi_pkt *pkt)
27207c478bd9Sstevel@tonic-gate {
27217c478bd9Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp = (scsa2usb_state_t *)ADDR2SCSA2USB(ap);
27227c478bd9Sstevel@tonic-gate 
27237c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
2724112116d8Sfb 	    "scsa2usb_scsi_abort: pkt = %p", (void *)pkt);
27257c478bd9Sstevel@tonic-gate 
27267c478bd9Sstevel@tonic-gate 	/* if device is disconnected (ie. pipes closed), fail immediately */
27277c478bd9Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
27287c478bd9Sstevel@tonic-gate 	if (!(SCSA2USB_DEVICE_ACCESS_OK(scsa2usbp))) {
27297c478bd9Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
27307c478bd9Sstevel@tonic-gate 
27317c478bd9Sstevel@tonic-gate 		return (0);
27327c478bd9Sstevel@tonic-gate 	}
27337c478bd9Sstevel@tonic-gate 
27347c478bd9Sstevel@tonic-gate 	/* flush waitQ if target and lun match */
27357c478bd9Sstevel@tonic-gate 	if ((ap->a_target == pkt->pkt_address.a_target) &&
27367c478bd9Sstevel@tonic-gate 	    (ap->a_lun == pkt->pkt_address.a_lun)) {
27377c478bd9Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
27387c478bd9Sstevel@tonic-gate 		scsa2usb_flush_waitQ(scsa2usbp, ap->a_lun, CMD_ABORTED);
27397c478bd9Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
27407c478bd9Sstevel@tonic-gate 	}
27417c478bd9Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
27427c478bd9Sstevel@tonic-gate 
27437c478bd9Sstevel@tonic-gate 	return (0);
27447c478bd9Sstevel@tonic-gate }
27457c478bd9Sstevel@tonic-gate 
27467c478bd9Sstevel@tonic-gate 
27477c478bd9Sstevel@tonic-gate /*
27487c478bd9Sstevel@tonic-gate  * scsa2usb_scsi_reset:
27497c478bd9Sstevel@tonic-gate  *	device reset may turn the device into a brick and bus reset
27507c478bd9Sstevel@tonic-gate  *	is not applicable.
27517c478bd9Sstevel@tonic-gate  *	just flush the waitQ
27527c478bd9Sstevel@tonic-gate  *	We return success, always.
27537c478bd9Sstevel@tonic-gate  */
27547c478bd9Sstevel@tonic-gate /* ARGSUSED */
27557c478bd9Sstevel@tonic-gate static int
scsa2usb_scsi_reset(struct scsi_address * ap,int level)27567c478bd9Sstevel@tonic-gate scsa2usb_scsi_reset(struct scsi_address *ap, int level)
27577c478bd9Sstevel@tonic-gate {
27587c478bd9Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp = (scsa2usb_state_t *)ADDR2SCSA2USB(ap);
27597c478bd9Sstevel@tonic-gate 
27607c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
2761112116d8Sfb 	    "scsa2usb_scsi_reset: ap = 0x%p, level = %d", (void *)ap, level);
27627c478bd9Sstevel@tonic-gate 
27637c478bd9Sstevel@tonic-gate 	/* flush waitQ */
27647c478bd9Sstevel@tonic-gate 	scsa2usb_flush_waitQ(scsa2usbp, ap->a_lun, CMD_RESET);
27657c478bd9Sstevel@tonic-gate 
27667c478bd9Sstevel@tonic-gate 	return (1);
27677c478bd9Sstevel@tonic-gate }
27687c478bd9Sstevel@tonic-gate 
27697c478bd9Sstevel@tonic-gate 
27707c478bd9Sstevel@tonic-gate /*
27717c478bd9Sstevel@tonic-gate  * scsa2usb_scsi_getcap:
27727c478bd9Sstevel@tonic-gate  *	Get SCSI capabilities.
27737c478bd9Sstevel@tonic-gate  */
27747c478bd9Sstevel@tonic-gate /* ARGSUSED */
27757c478bd9Sstevel@tonic-gate static int
scsa2usb_scsi_getcap(struct scsi_address * ap,char * cap,int whom)27767c478bd9Sstevel@tonic-gate scsa2usb_scsi_getcap(struct scsi_address *ap, char *cap, int whom)
27777c478bd9Sstevel@tonic-gate {
27787c478bd9Sstevel@tonic-gate 	int rval = -1;
27797c478bd9Sstevel@tonic-gate 	uint_t cidx;
27807c478bd9Sstevel@tonic-gate 	size_t dev_bsize_cap;
27817c478bd9Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp = (scsa2usb_state_t *)ADDR2SCSA2USB(ap);
27827c478bd9Sstevel@tonic-gate 	ASSERT(scsa2usbp);
27837c478bd9Sstevel@tonic-gate 
27847c478bd9Sstevel@tonic-gate 	if (cap == NULL) {
27857c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
27867c478bd9Sstevel@tonic-gate 		    "scsa2usb_scsi_getcap: invalid arg, "
2787112116d8Sfb 		    "cap = 0x%p whom = %d", (void *)cap, whom);
27887c478bd9Sstevel@tonic-gate 
27897c478bd9Sstevel@tonic-gate 		return (rval);
27907c478bd9Sstevel@tonic-gate 	}
27917c478bd9Sstevel@tonic-gate 
27927c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
27937c478bd9Sstevel@tonic-gate 	    "scsa2usb_scsi_getcap: cap = %s", cap);
27947c478bd9Sstevel@tonic-gate 
27957c478bd9Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
27967c478bd9Sstevel@tonic-gate 
27977c478bd9Sstevel@tonic-gate 	/* if device is disconnected (ie. pipes closed), fail immediately */
27987c478bd9Sstevel@tonic-gate 	if (!(SCSA2USB_DEVICE_ACCESS_OK(scsa2usbp))) {
27997c478bd9Sstevel@tonic-gate 
28007c478bd9Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
28017c478bd9Sstevel@tonic-gate 
28027c478bd9Sstevel@tonic-gate 		return (rval);
28037c478bd9Sstevel@tonic-gate 	}
28047c478bd9Sstevel@tonic-gate 
28057c478bd9Sstevel@tonic-gate 	cidx =	scsi_hba_lookup_capstr(cap);
28067c478bd9Sstevel@tonic-gate 	switch (cidx) {
28077c478bd9Sstevel@tonic-gate 	case SCSI_CAP_GEOMETRY:
2808e7cc2e17Sbc 		/* Just check and fail immediately if zero, rarely happens */
2809e7cc2e17Sbc 		if (scsa2usbp->scsa2usb_secsz[ap->a_lun] == 0) {
2810e7cc2e17Sbc 			USB_DPRINTF_L2(DPRINT_MASK_SCSA,
2811e7cc2e17Sbc 			    scsa2usbp->scsa2usb_log_handle,
2812e7cc2e17Sbc 			    "scsa2usb_scsi_getcap failed:"
2813e7cc2e17Sbc 			    "scsa2usbp->scsa2usb_secsz[ap->a_lun] == 0");
2814e7cc2e17Sbc 			mutex_exit(&scsa2usbp->scsa2usb_mutex);
2815e7cc2e17Sbc 
2816e7cc2e17Sbc 			return (rval);
2817e7cc2e17Sbc 		}
2818e7cc2e17Sbc 
28197c478bd9Sstevel@tonic-gate 		dev_bsize_cap = scsa2usbp->scsa2usb_totalsec[ap->a_lun];
28207c478bd9Sstevel@tonic-gate 
28217c478bd9Sstevel@tonic-gate 		if (scsa2usbp->scsa2usb_secsz[ap->a_lun] > DEV_BSIZE) {
28227c478bd9Sstevel@tonic-gate 			dev_bsize_cap *=
28237c478bd9Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_secsz[ap->a_lun] / DEV_BSIZE;
28247c478bd9Sstevel@tonic-gate 		} else if (scsa2usbp->scsa2usb_secsz[ap->a_lun] <
28257c478bd9Sstevel@tonic-gate 		    DEV_BSIZE) {
28267c478bd9Sstevel@tonic-gate 			dev_bsize_cap /=
28277c478bd9Sstevel@tonic-gate 			    DEV_BSIZE / scsa2usbp->scsa2usb_secsz[ap->a_lun];
28287c478bd9Sstevel@tonic-gate 		}
28297c478bd9Sstevel@tonic-gate 
28307c478bd9Sstevel@tonic-gate 		if (dev_bsize_cap < 65536 * 2 * 18) {		/* < ~1GB */
28317c478bd9Sstevel@tonic-gate 			/* unlabeled floppy, 18k per cylinder */
28327c478bd9Sstevel@tonic-gate 			rval = ((2 << 16) | 18);
28337c478bd9Sstevel@tonic-gate 		} else if (dev_bsize_cap < 65536 * 64 * 32) {	/* < 64GB */
28347c478bd9Sstevel@tonic-gate 			/* 1024k per cylinder */
28357c478bd9Sstevel@tonic-gate 			rval = ((64 << 16) | 32);
28367c478bd9Sstevel@tonic-gate 		} else if (dev_bsize_cap < 65536 * 255 * 63) {	/* < ~500GB */
28377c478bd9Sstevel@tonic-gate 			/* ~8m per cylinder */
28387c478bd9Sstevel@tonic-gate 			rval = ((255 << 16) | 63);
28397c478bd9Sstevel@tonic-gate 		} else {					/* .. 8TB */
28407c478bd9Sstevel@tonic-gate 			/* 64m per cylinder */
28417c478bd9Sstevel@tonic-gate 			rval = ((512 << 16) | 256);
28427c478bd9Sstevel@tonic-gate 		}
28437c478bd9Sstevel@tonic-gate 		break;
28447c478bd9Sstevel@tonic-gate 
28457c478bd9Sstevel@tonic-gate 	case SCSI_CAP_DMA_MAX:
28467c478bd9Sstevel@tonic-gate 		rval = scsa2usbp->scsa2usb_max_bulk_xfer_size;
28477c478bd9Sstevel@tonic-gate 		break;
28487c478bd9Sstevel@tonic-gate 	case SCSI_CAP_SCSI_VERSION:
28497c478bd9Sstevel@tonic-gate 		rval = SCSI_VERSION_2;
28507c478bd9Sstevel@tonic-gate 		break;
28517c478bd9Sstevel@tonic-gate 	case SCSI_CAP_INTERCONNECT_TYPE:
28527c478bd9Sstevel@tonic-gate 		rval = INTERCONNECT_USB;
28537c478bd9Sstevel@tonic-gate 		break;
28547c478bd9Sstevel@tonic-gate 	case SCSI_CAP_ARQ:
28557c478bd9Sstevel@tonic-gate 		/* FALLTHRU */
28567c478bd9Sstevel@tonic-gate 	case SCSI_CAP_UNTAGGED_QING:
28577c478bd9Sstevel@tonic-gate 		rval = 1;
28587c478bd9Sstevel@tonic-gate 		break;
28597c478bd9Sstevel@tonic-gate 	default:
28607c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
28617c478bd9Sstevel@tonic-gate 		    "scsa2usb_scsi_getcap: unsupported cap = %s", cap);
28627c478bd9Sstevel@tonic-gate 		break;
28637c478bd9Sstevel@tonic-gate 	}
28647c478bd9Sstevel@tonic-gate 
28657c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
28667c478bd9Sstevel@tonic-gate 	    "scsa2usb_scsi_getcap: cap = %s, returned = %d", cap, rval);
28677c478bd9Sstevel@tonic-gate 
28687c478bd9Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
28697c478bd9Sstevel@tonic-gate 
28707c478bd9Sstevel@tonic-gate 	return (rval);
28717c478bd9Sstevel@tonic-gate }
28727c478bd9Sstevel@tonic-gate 
28737c478bd9Sstevel@tonic-gate 
28747c478bd9Sstevel@tonic-gate /*
28757c478bd9Sstevel@tonic-gate  * scsa2usb_scsi_setcap:
28767c478bd9Sstevel@tonic-gate  *	Set SCSI capabilities.
28777c478bd9Sstevel@tonic-gate  */
28787c478bd9Sstevel@tonic-gate /* ARGSUSED */
28797c478bd9Sstevel@tonic-gate static int
scsa2usb_scsi_setcap(struct scsi_address * ap,char * cap,int value,int whom)28807c478bd9Sstevel@tonic-gate scsa2usb_scsi_setcap(struct scsi_address *ap, char *cap, int value, int whom)
28817c478bd9Sstevel@tonic-gate {
28827c478bd9Sstevel@tonic-gate 	int rval = -1; /* default is cap undefined */
28837c478bd9Sstevel@tonic-gate 	uint_t cidx;
28847c478bd9Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp = (scsa2usb_state_t *)ADDR2SCSA2USB(ap);
28857c478bd9Sstevel@tonic-gate 	ASSERT(scsa2usbp);
28867c478bd9Sstevel@tonic-gate 
28877c478bd9Sstevel@tonic-gate 	if (cap == NULL || whom == 0) {
28887c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
28897c478bd9Sstevel@tonic-gate 		    "scsa2usb_scsi_setcap: invalid arg");
28907c478bd9Sstevel@tonic-gate 
28917c478bd9Sstevel@tonic-gate 		return (rval);
28927c478bd9Sstevel@tonic-gate 	}
28937c478bd9Sstevel@tonic-gate 
28947c478bd9Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
28957c478bd9Sstevel@tonic-gate 	/* if device is disconnected (ie. pipes closed), fail immediately */
28967c478bd9Sstevel@tonic-gate 	if (!(SCSA2USB_DEVICE_ACCESS_OK(scsa2usbp))) {
28977c478bd9Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
28987c478bd9Sstevel@tonic-gate 
28997c478bd9Sstevel@tonic-gate 		return (rval);
29007c478bd9Sstevel@tonic-gate 	}
29017c478bd9Sstevel@tonic-gate 
29027c478bd9Sstevel@tonic-gate 	cidx =	scsi_hba_lookup_capstr(cap);
29037c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
29047c478bd9Sstevel@tonic-gate 	    "scsa2usb_scsi_setcap: ap = 0x%p value = 0x%x whom = 0x%x "
2905112116d8Sfb 	    "cidx = 0x%x", (void *)ap, value, whom, cidx);
29067c478bd9Sstevel@tonic-gate 
29077c478bd9Sstevel@tonic-gate 	switch (cidx) {
29087c478bd9Sstevel@tonic-gate 	case SCSI_CAP_SECTOR_SIZE:
29097c478bd9Sstevel@tonic-gate 		if (value) {
29107c478bd9Sstevel@tonic-gate 			scsa2usbp->scsa2usb_secsz[ap->a_lun] = value;
29117c478bd9Sstevel@tonic-gate 		}
29127c478bd9Sstevel@tonic-gate 		break;
29137c478bd9Sstevel@tonic-gate 	case SCSI_CAP_TOTAL_SECTORS:
29147c478bd9Sstevel@tonic-gate 		if (value) {
29157c478bd9Sstevel@tonic-gate 			scsa2usbp->scsa2usb_totalsec[ap->a_lun] = value;
29167c478bd9Sstevel@tonic-gate 		}
29177c478bd9Sstevel@tonic-gate 		break;
29187c478bd9Sstevel@tonic-gate 	case SCSI_CAP_ARQ:
29197c478bd9Sstevel@tonic-gate 		rval = 1;
29207c478bd9Sstevel@tonic-gate 		break;
29217c478bd9Sstevel@tonic-gate 	case SCSI_CAP_DMA_MAX:
29227c478bd9Sstevel@tonic-gate 	case SCSI_CAP_SCSI_VERSION:
29237c478bd9Sstevel@tonic-gate 	case SCSI_CAP_INTERCONNECT_TYPE:
29247c478bd9Sstevel@tonic-gate 	case SCSI_CAP_UNTAGGED_QING:
29257c478bd9Sstevel@tonic-gate 		/* supported but not settable */
29267c478bd9Sstevel@tonic-gate 		rval = 0;
29277c478bd9Sstevel@tonic-gate 		break;
29287c478bd9Sstevel@tonic-gate 	default:
29297c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
29307c478bd9Sstevel@tonic-gate 		    "scsa2usb_scsi_setcap: unsupported cap = %s", cap);
29317c478bd9Sstevel@tonic-gate 		break;
29327c478bd9Sstevel@tonic-gate 	}
29337c478bd9Sstevel@tonic-gate 
29347c478bd9Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
29357c478bd9Sstevel@tonic-gate 
29367c478bd9Sstevel@tonic-gate 	return (rval);
29377c478bd9Sstevel@tonic-gate }
29387c478bd9Sstevel@tonic-gate 
29397c478bd9Sstevel@tonic-gate 
29407c478bd9Sstevel@tonic-gate /*
29417c478bd9Sstevel@tonic-gate  * scsa2usb - cmd and transport stuff
29427c478bd9Sstevel@tonic-gate  */
29437c478bd9Sstevel@tonic-gate /*
29447c478bd9Sstevel@tonic-gate  * scsa2usb_prepare_pkt:
29457c478bd9Sstevel@tonic-gate  *	initialize some fields of the pkt and cmd
29467c478bd9Sstevel@tonic-gate  *	(the pkt may have been resubmitted/retried)
29477c478bd9Sstevel@tonic-gate  */
29487c478bd9Sstevel@tonic-gate static void
scsa2usb_prepare_pkt(scsa2usb_state_t * scsa2usbp,struct scsi_pkt * pkt)29497c478bd9Sstevel@tonic-gate scsa2usb_prepare_pkt(scsa2usb_state_t *scsa2usbp, struct scsi_pkt *pkt)
29507c478bd9Sstevel@tonic-gate {
29517c478bd9Sstevel@tonic-gate 	scsa2usb_cmd_t	*cmd = PKT2CMD(pkt);
29527c478bd9Sstevel@tonic-gate 
29537c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
29547c478bd9Sstevel@tonic-gate 	    "scsa2usb_prepare_pkt: pkt=0x%p cdb: 0x%x (%s)",
2955112116d8Sfb 	    (void *)pkt, pkt->pkt_cdbp[0],
29567c478bd9Sstevel@tonic-gate 	    scsi_cname(pkt->pkt_cdbp[0], scsa2usb_cmds));
29577c478bd9Sstevel@tonic-gate 
29587c478bd9Sstevel@tonic-gate 	pkt->pkt_reason = CMD_CMPLT;	/* Set reason to pkt_complete */
29597c478bd9Sstevel@tonic-gate 	pkt->pkt_state = 0;		/* Reset next three fields */
29607c478bd9Sstevel@tonic-gate 	pkt->pkt_statistics = 0;
29617c478bd9Sstevel@tonic-gate 	pkt->pkt_resid = 0;
29627c478bd9Sstevel@tonic-gate 	bzero(pkt->pkt_scbp, cmd->cmd_scblen); /* Set status to good */
29637c478bd9Sstevel@tonic-gate 
29647c478bd9Sstevel@tonic-gate 	if (cmd) {
29657c478bd9Sstevel@tonic-gate 		cmd->cmd_timeout = pkt->pkt_time;
29667c478bd9Sstevel@tonic-gate 		cmd->cmd_xfercount = 0;		/* Reset the fields */
29677c478bd9Sstevel@tonic-gate 		cmd->cmd_total_xfercount = 0;
29687c478bd9Sstevel@tonic-gate 		cmd->cmd_lba = 0;
29697c478bd9Sstevel@tonic-gate 		cmd->cmd_done = 0;
29707c478bd9Sstevel@tonic-gate 		cmd->cmd_dir = 0;
29717c478bd9Sstevel@tonic-gate 		cmd->cmd_offset = 0;
29727c478bd9Sstevel@tonic-gate 		cmd->cmd_actual_len = cmd->cmd_cdblen;
29737c478bd9Sstevel@tonic-gate 	}
29747c478bd9Sstevel@tonic-gate }
29757c478bd9Sstevel@tonic-gate 
29767c478bd9Sstevel@tonic-gate 
29777c478bd9Sstevel@tonic-gate /*
29787c478bd9Sstevel@tonic-gate  * scsa2usb_force_invalid_request
29797c478bd9Sstevel@tonic-gate  */
29807c478bd9Sstevel@tonic-gate static void
scsa2usb_force_invalid_request(scsa2usb_state_t * scsa2usbp,scsa2usb_cmd_t * cmd)29817c478bd9Sstevel@tonic-gate scsa2usb_force_invalid_request(scsa2usb_state_t *scsa2usbp,
29827c478bd9Sstevel@tonic-gate     scsa2usb_cmd_t *cmd)
29837c478bd9Sstevel@tonic-gate {
29847c478bd9Sstevel@tonic-gate 	struct scsi_arq_status	*arqp;
29857c478bd9Sstevel@tonic-gate 
29867c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
2987112116d8Sfb 	    "scsa2usb_force_invalid_request: pkt = 0x%p", (void *)cmd->cmd_pkt);
29887c478bd9Sstevel@tonic-gate 
29897c478bd9Sstevel@tonic-gate 	if (cmd->cmd_scblen >= sizeof (struct scsi_arq_status)) {
29907c478bd9Sstevel@tonic-gate 		arqp = (struct scsi_arq_status *)cmd->cmd_pkt->pkt_scbp;
29917c478bd9Sstevel@tonic-gate 		bzero(arqp, cmd->cmd_scblen);
29927c478bd9Sstevel@tonic-gate 
29937c478bd9Sstevel@tonic-gate 		arqp->sts_status.sts_chk = 1;
29947c478bd9Sstevel@tonic-gate 		arqp->sts_rqpkt_reason = CMD_CMPLT;
29957c478bd9Sstevel@tonic-gate 		arqp->sts_rqpkt_state = STATE_XFERRED_DATA |
29967c478bd9Sstevel@tonic-gate 		    STATE_GOT_BUS | STATE_GOT_STATUS;
29977c478bd9Sstevel@tonic-gate 		arqp->sts_sensedata.es_valid = 1;
29987c478bd9Sstevel@tonic-gate 		arqp->sts_sensedata.es_class = 7;
29997c478bd9Sstevel@tonic-gate 		arqp->sts_sensedata.es_key = KEY_ILLEGAL_REQUEST;
30007c478bd9Sstevel@tonic-gate 
30017c478bd9Sstevel@tonic-gate 		cmd->cmd_pkt->pkt_state = STATE_ARQ_DONE |
30027c478bd9Sstevel@tonic-gate 		    STATE_GOT_BUS | STATE_GOT_BUS | STATE_GOT_BUS |
30037c478bd9Sstevel@tonic-gate 		    STATE_GOT_STATUS;
30047c478bd9Sstevel@tonic-gate #ifdef DEBUG
30057c478bd9Sstevel@tonic-gate 		{
30067c478bd9Sstevel@tonic-gate 			uchar_t *p = (uchar_t *)(&arqp->sts_sensedata);
30077c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_SCSA,
30087c478bd9Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
30097c478bd9Sstevel@tonic-gate 			    "cdb: %x rqsense: "
30107c478bd9Sstevel@tonic-gate 			    "%x %x %x %x %x %x %x %x %x %x "
30117c478bd9Sstevel@tonic-gate 			    "%x %x %x %x %x %x %x %x %x %x",
30127c478bd9Sstevel@tonic-gate 			    cmd->cmd_pkt->pkt_cdbp[0],
30137c478bd9Sstevel@tonic-gate 			    p[0], p[1], p[2], p[3], p[4],
30147c478bd9Sstevel@tonic-gate 			    p[5], p[6], p[7], p[8], p[9],
30157c478bd9Sstevel@tonic-gate 			    p[10], p[11], p[12], p[13], p[14],
30167c478bd9Sstevel@tonic-gate 			    p[15], p[16], p[17], p[18], p[19]);
30177c478bd9Sstevel@tonic-gate 		}
30187c478bd9Sstevel@tonic-gate #endif
30197c478bd9Sstevel@tonic-gate 
30207c478bd9Sstevel@tonic-gate 	}
30217c478bd9Sstevel@tonic-gate }
30227c478bd9Sstevel@tonic-gate 
30237c478bd9Sstevel@tonic-gate 
30247c478bd9Sstevel@tonic-gate static int
scsa2usb_cmd_transport(scsa2usb_state_t * scsa2usbp,scsa2usb_cmd_t * cmd)30257c478bd9Sstevel@tonic-gate scsa2usb_cmd_transport(scsa2usb_state_t *scsa2usbp, scsa2usb_cmd_t *cmd)
30267c478bd9Sstevel@tonic-gate {
30277c478bd9Sstevel@tonic-gate 	int rval, transport;
30287c478bd9Sstevel@tonic-gate 	struct scsi_pkt *pkt;
30297c478bd9Sstevel@tonic-gate 
30307c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
30317c478bd9Sstevel@tonic-gate 	    "scsa2usb_cmd_transport: pkt: 0x%p, cur_pkt = 0x%p",
3032112116d8Sfb 	    (void *)cmd->cmd_pkt, (void *)scsa2usbp->scsa2usb_cur_pkt);
30337c478bd9Sstevel@tonic-gate 
30347c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
30357c478bd9Sstevel@tonic-gate 	ASSERT(scsa2usbp->scsa2usb_cur_pkt == NULL);
30367c478bd9Sstevel@tonic-gate 
30377c478bd9Sstevel@tonic-gate 	pkt = scsa2usbp->scsa2usb_cur_pkt = cmd->cmd_pkt;
30387c478bd9Sstevel@tonic-gate 
303947b9747fSJoshua M. Clulow 	/*
304047b9747fSJoshua M. Clulow 	 * Check per-device quirks first:
304147b9747fSJoshua M. Clulow 	 */
30427c478bd9Sstevel@tonic-gate 	if (SCSA2USB_IS_BULK_ONLY(scsa2usbp)) {
304347b9747fSJoshua M. Clulow 		transport = scsa2usb_check_bulkonly_quirks(scsa2usbp, cmd);
30447c478bd9Sstevel@tonic-gate 	} else if (SCSA2USB_IS_CB(scsa2usbp) || SCSA2USB_IS_CBI(scsa2usbp)) {
304547b9747fSJoshua M. Clulow 		transport = scsa2usb_check_ufi_quirks(scsa2usbp, cmd);
304647b9747fSJoshua M. Clulow 	} else {
304747b9747fSJoshua M. Clulow 		return (TRAN_FATAL_ERROR);
30487c478bd9Sstevel@tonic-gate 	}
30497c478bd9Sstevel@tonic-gate 
3050b248f0fdSguoqing zhu - Sun Microsystems - Beijing China 	/* just accept the command or return error */
30517c478bd9Sstevel@tonic-gate 	if (transport == SCSA2USB_JUST_ACCEPT) {
30527c478bd9Sstevel@tonic-gate 		SCSA2USB_SET_PKT_DO_COMP_STATE(scsa2usbp);
30537c478bd9Sstevel@tonic-gate 
30547c478bd9Sstevel@tonic-gate 		return (TRAN_ACCEPT);
3055b248f0fdSguoqing zhu - Sun Microsystems - Beijing China 	} else if (transport == SCSA2USB_REJECT) {
3056b248f0fdSguoqing zhu - Sun Microsystems - Beijing China 		return (TRAN_FATAL_ERROR);
30577c478bd9Sstevel@tonic-gate 	}
30587c478bd9Sstevel@tonic-gate 
30597c478bd9Sstevel@tonic-gate 	/* check command set next */
30607c478bd9Sstevel@tonic-gate 	if (SCSA2USB_IS_SCSI_CMDSET(scsa2usbp) ||
30617c478bd9Sstevel@tonic-gate 	    SCSA2USB_IS_ATAPI_CMDSET(scsa2usbp)) {
30627c478bd9Sstevel@tonic-gate 		transport =
30637c478bd9Sstevel@tonic-gate 		    scsa2usb_handle_scsi_cmd_sub_class(scsa2usbp, cmd, pkt);
30647c478bd9Sstevel@tonic-gate 	} else if (SCSA2USB_IS_UFI_CMDSET(scsa2usbp)) {
30657c478bd9Sstevel@tonic-gate 		transport =
30667c478bd9Sstevel@tonic-gate 		    scsa2usb_handle_ufi_subclass_cmd(scsa2usbp, cmd, pkt);
30677c478bd9Sstevel@tonic-gate 	} else {
30687c478bd9Sstevel@tonic-gate 		transport = SCSA2USB_REJECT;
30697c478bd9Sstevel@tonic-gate 	}
30707c478bd9Sstevel@tonic-gate 
3071910cba4fScg 	switch (transport) {
3072910cba4fScg 	case SCSA2USB_TRANSPORT:
30737c478bd9Sstevel@tonic-gate 		if (SCSA2USB_IS_BULK_ONLY(scsa2usbp)) {
30747c478bd9Sstevel@tonic-gate 			rval = scsa2usb_bulk_only_transport(scsa2usbp, cmd);
30757c478bd9Sstevel@tonic-gate 		} else if (SCSA2USB_IS_CB(scsa2usbp) ||
30767c478bd9Sstevel@tonic-gate 		    SCSA2USB_IS_CBI(scsa2usbp)) {
30777c478bd9Sstevel@tonic-gate 			rval = scsa2usb_cbi_transport(scsa2usbp, cmd);
30787c478bd9Sstevel@tonic-gate 		} else {
30797c478bd9Sstevel@tonic-gate 			rval = TRAN_FATAL_ERROR;
30807c478bd9Sstevel@tonic-gate 		}
3081910cba4fScg 		break;
3082910cba4fScg 	case SCSA2USB_JUST_ACCEPT:
3083910cba4fScg 		SCSA2USB_SET_PKT_DO_COMP_STATE(scsa2usbp);
3084910cba4fScg 		rval = TRAN_ACCEPT;
3085910cba4fScg 		break;
3086910cba4fScg 	default:
30877c478bd9Sstevel@tonic-gate 		rval = TRAN_FATAL_ERROR;
30887c478bd9Sstevel@tonic-gate 	}
30897c478bd9Sstevel@tonic-gate 
30907c478bd9Sstevel@tonic-gate 	return (rval);
30917c478bd9Sstevel@tonic-gate }
30927c478bd9Sstevel@tonic-gate 
30937c478bd9Sstevel@tonic-gate 
30947c478bd9Sstevel@tonic-gate /*
309547b9747fSJoshua M. Clulow  * Check this Bulk Only command against the quirks for this particular device.
309647b9747fSJoshua M. Clulow  * Returns a transport disposition.
30977c478bd9Sstevel@tonic-gate  */
30987c478bd9Sstevel@tonic-gate int
scsa2usb_check_bulkonly_quirks(scsa2usb_state_t * scsa2usbp,scsa2usb_cmd_t * cmd)309947b9747fSJoshua M. Clulow scsa2usb_check_bulkonly_quirks(scsa2usb_state_t *scsa2usbp, scsa2usb_cmd_t *cmd)
31007c478bd9Sstevel@tonic-gate {
31014610e4a0Sfrits 	struct scsi_inquiry *inq =
31024610e4a0Sfrits 	    &scsa2usbp->scsa2usb_lun_inquiry[cmd->cmd_pkt->pkt_address.a_lun];
31034610e4a0Sfrits 
31047c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
31057c478bd9Sstevel@tonic-gate 
31067c478bd9Sstevel@tonic-gate 	/*
31077c478bd9Sstevel@tonic-gate 	 * decode and convert the packet
31087c478bd9Sstevel@tonic-gate 	 * for most cmds, we can bcopy the cdb
31097c478bd9Sstevel@tonic-gate 	 */
311047b9747fSJoshua M. Clulow 	switch (cmd->cmd_pkt->pkt_cdbp[0]) {
31117c478bd9Sstevel@tonic-gate 	case SCMD_DOORLOCK:
31127c478bd9Sstevel@tonic-gate 		if (!(scsa2usbp->scsa2usb_attrs & SCSA2USB_ATTRS_DOORLOCK)) {
31137c478bd9Sstevel@tonic-gate 
31147c478bd9Sstevel@tonic-gate 			return (SCSA2USB_JUST_ACCEPT);
31157c478bd9Sstevel@tonic-gate 
31164610e4a0Sfrits 		/*
31174610e4a0Sfrits 		 * only lock the door for CD and DVD drives
31184610e4a0Sfrits 		 */
31194610e4a0Sfrits 		} else if ((inq->inq_dtype == DTYPE_RODIRECT) ||
31204610e4a0Sfrits 		    (inq->inq_dtype == DTYPE_OPTICAL)) {
31217c478bd9Sstevel@tonic-gate 
31224610e4a0Sfrits 			if (inq->inq_rmb) {
31234610e4a0Sfrits 
31244610e4a0Sfrits 				break;
31254610e4a0Sfrits 			}
31267c478bd9Sstevel@tonic-gate 		}
31277c478bd9Sstevel@tonic-gate 
31287c478bd9Sstevel@tonic-gate 		return (SCSA2USB_JUST_ACCEPT);
31297c478bd9Sstevel@tonic-gate 
31309038fe48SSheshadri Vasudevan 	case SCMD_START_STOP:	/* SCMD_LOAD for sequential devices */
31317c478bd9Sstevel@tonic-gate 		/*
31327c478bd9Sstevel@tonic-gate 		 * these devices don't have mechanics that spin the
31337c478bd9Sstevel@tonic-gate 		 * media up and down. So, it doesn't make much sense
31347c478bd9Sstevel@tonic-gate 		 * to issue this cmd.
31357c478bd9Sstevel@tonic-gate 		 *
31367c478bd9Sstevel@tonic-gate 		 * Furthermore, Hagiwara devices do not handle these
31377c478bd9Sstevel@tonic-gate 		 * cmds well. just accept this command as success.
31387c478bd9Sstevel@tonic-gate 		 */
31397c478bd9Sstevel@tonic-gate 		if (!(scsa2usbp->scsa2usb_attrs & SCSA2USB_ATTRS_START_STOP)) {
31407c478bd9Sstevel@tonic-gate 
31417c478bd9Sstevel@tonic-gate 			return (SCSA2USB_JUST_ACCEPT);
31427c478bd9Sstevel@tonic-gate 
31439038fe48SSheshadri Vasudevan 		} else if (inq->inq_dtype == DTYPE_SEQUENTIAL) {
31449038fe48SSheshadri Vasudevan 			/*
31459038fe48SSheshadri Vasudevan 			 * In case of USB tape device, we need to send the
31469038fe48SSheshadri Vasudevan 			 * command to the device to unload the media.
31479038fe48SSheshadri Vasudevan 			 */
31489038fe48SSheshadri Vasudevan 			break;
31499038fe48SSheshadri Vasudevan 
31507c478bd9Sstevel@tonic-gate 		} else if (cmd->cmd_pkt->pkt_cdbp[4] & LOEJECT) {
31517c478bd9Sstevel@tonic-gate 			/*
31527c478bd9Sstevel@tonic-gate 			 * if the device is really a removable then
31537c478bd9Sstevel@tonic-gate 			 * pass it on to the device, else just accept
31547c478bd9Sstevel@tonic-gate 			 */
31554610e4a0Sfrits 			if (inq->inq_rmb) {
31567c478bd9Sstevel@tonic-gate 
31577c478bd9Sstevel@tonic-gate 				break;
31587c478bd9Sstevel@tonic-gate 			}
31597c478bd9Sstevel@tonic-gate 
31607c478bd9Sstevel@tonic-gate 			return (SCSA2USB_JUST_ACCEPT);
31617c478bd9Sstevel@tonic-gate 
31627c478bd9Sstevel@tonic-gate 		} else if (!scsa2usbp->scsa2usb_rcvd_not_ready) {
31637c478bd9Sstevel@tonic-gate 			/*
31647c478bd9Sstevel@tonic-gate 			 * if we have not received a NOT READY condition,
31657c478bd9Sstevel@tonic-gate 			 * just accept since some device choke on this too.
31667c478bd9Sstevel@tonic-gate 			 * we do have to let EJECT get through though
31677c478bd9Sstevel@tonic-gate 			 */
31687c478bd9Sstevel@tonic-gate 			return (SCSA2USB_JUST_ACCEPT);
31697c478bd9Sstevel@tonic-gate 		}
31707c478bd9Sstevel@tonic-gate 
31717c478bd9Sstevel@tonic-gate 		break;
31727c478bd9Sstevel@tonic-gate 	case SCMD_INQUIRY:
31737c478bd9Sstevel@tonic-gate 		/*
31747c478bd9Sstevel@tonic-gate 		 * Some devices do not handle the inquiry cmd well
31757c478bd9Sstevel@tonic-gate 		 * so build an inquiry and accept this command as
31767c478bd9Sstevel@tonic-gate 		 * success.
31777c478bd9Sstevel@tonic-gate 		 */
31787c478bd9Sstevel@tonic-gate 		if (!(scsa2usbp->scsa2usb_attrs & SCSA2USB_ATTRS_INQUIRY)) {
31797c478bd9Sstevel@tonic-gate 			uchar_t evpd = 0x01;
31803fbe3e28Svitezslav batrla - Sun Microsystems - Prague Czech Republic 			unsigned int bufsize;
31813fbe3e28Svitezslav batrla - Sun Microsystems - Prague Czech Republic 			int count;
31827c478bd9Sstevel@tonic-gate 
3183b248f0fdSguoqing zhu - Sun Microsystems - Beijing China 			if (cmd->cmd_pkt->pkt_cdbp[1] & evpd)
31847c478bd9Sstevel@tonic-gate 				return (SCSA2USB_REJECT);
31853fbe3e28Svitezslav batrla - Sun Microsystems - Prague Czech Republic 
31863fbe3e28Svitezslav batrla - Sun Microsystems - Prague Czech Republic 			scsa2usb_fake_inquiry(scsa2usbp, inq);
31873fbe3e28Svitezslav batrla - Sun Microsystems - Prague Czech Republic 
31883fbe3e28Svitezslav batrla - Sun Microsystems - Prague Czech Republic 			/* Copy no more than requested */
31893fbe3e28Svitezslav batrla - Sun Microsystems - Prague Czech Republic 			count = MIN(cmd->cmd_bp->b_bcount,
31903fbe3e28Svitezslav batrla - Sun Microsystems - Prague Czech Republic 			    sizeof (struct scsi_inquiry));
31913fbe3e28Svitezslav batrla - Sun Microsystems - Prague Czech Republic 			bufsize = cmd->cmd_pkt->pkt_cdbp[4];
31923fbe3e28Svitezslav batrla - Sun Microsystems - Prague Czech Republic 			count = MIN(count, bufsize);
31933fbe3e28Svitezslav batrla - Sun Microsystems - Prague Czech Republic 			bcopy(inq, cmd->cmd_bp->b_un.b_addr, count);
31943fbe3e28Svitezslav batrla - Sun Microsystems - Prague Czech Republic 
31953fbe3e28Svitezslav batrla - Sun Microsystems - Prague Czech Republic 			cmd->cmd_pkt->pkt_resid = bufsize - count;
31967c478bd9Sstevel@tonic-gate 			cmd->cmd_pkt->pkt_state |= STATE_XFERRED_DATA;
31977c478bd9Sstevel@tonic-gate 
31988f588c83Sguoqing zhu - Sun Microsystems - Beijing China 			return (SCSA2USB_JUST_ACCEPT);
31998f588c83Sguoqing zhu - Sun Microsystems - Beijing China 		} else if (!(scsa2usbp->scsa2usb_attrs &
32008f588c83Sguoqing zhu - Sun Microsystems - Beijing China 		    SCSA2USB_ATTRS_INQUIRY_EVPD)) {
32018f588c83Sguoqing zhu - Sun Microsystems - Beijing China 			/*
32028f588c83Sguoqing zhu - Sun Microsystems - Beijing China 			 * Some devices do not handle the inquiry cmd with
32038f588c83Sguoqing zhu - Sun Microsystems - Beijing China 			 * evpd bit set well, e.g. some devices return the
32048f588c83Sguoqing zhu - Sun Microsystems - Beijing China 			 * same page 0x83 data which will cause the generated
32058f588c83Sguoqing zhu - Sun Microsystems - Beijing China 			 * devid by sd is not unique, thus return CHECK
32068f588c83Sguoqing zhu - Sun Microsystems - Beijing China 			 * CONDITION directly to sd.
32078f588c83Sguoqing zhu - Sun Microsystems - Beijing China 			 */
32088f588c83Sguoqing zhu - Sun Microsystems - Beijing China 			uchar_t evpd = 0x01;
32098f588c83Sguoqing zhu - Sun Microsystems - Beijing China 
32108f588c83Sguoqing zhu - Sun Microsystems - Beijing China 			if (!(cmd->cmd_pkt->pkt_cdbp[1] & evpd))
32118f588c83Sguoqing zhu - Sun Microsystems - Beijing China 				break;
32128f588c83Sguoqing zhu - Sun Microsystems - Beijing China 
32138f588c83Sguoqing zhu - Sun Microsystems - Beijing China 			if (cmd->cmd_bp) {
32148f588c83Sguoqing zhu - Sun Microsystems - Beijing China 				cmd->cmd_pkt->pkt_resid = cmd->cmd_bp->
32158f588c83Sguoqing zhu - Sun Microsystems - Beijing China 				    b_bcount;
32168f588c83Sguoqing zhu - Sun Microsystems - Beijing China 			}
32178f588c83Sguoqing zhu - Sun Microsystems - Beijing China 			scsa2usb_force_invalid_request(scsa2usbp, cmd);
32188f588c83Sguoqing zhu - Sun Microsystems - Beijing China 
32197c478bd9Sstevel@tonic-gate 			return (SCSA2USB_JUST_ACCEPT);
32207c478bd9Sstevel@tonic-gate 		}
32217c478bd9Sstevel@tonic-gate 		break;
32227c478bd9Sstevel@tonic-gate 	/*
32234610e4a0Sfrits 	 * Fake accepting the following  Opcodes
32244610e4a0Sfrits 	 * (as most drives don't support these)
32257c478bd9Sstevel@tonic-gate 	 * These are needed by format command.
32267c478bd9Sstevel@tonic-gate 	 */
32277c478bd9Sstevel@tonic-gate 	case SCMD_RESERVE:
32287c478bd9Sstevel@tonic-gate 	case SCMD_RELEASE:
32297c478bd9Sstevel@tonic-gate 	case SCMD_PERSISTENT_RESERVE_IN:
32307c478bd9Sstevel@tonic-gate 	case SCMD_PERSISTENT_RESERVE_OUT:
32317c478bd9Sstevel@tonic-gate 
32327c478bd9Sstevel@tonic-gate 		return (SCSA2USB_JUST_ACCEPT);
32337c478bd9Sstevel@tonic-gate 
32347c478bd9Sstevel@tonic-gate 	case SCMD_MODE_SENSE:
32357c478bd9Sstevel@tonic-gate 	case SCMD_MODE_SELECT:
32367c478bd9Sstevel@tonic-gate 	case SCMD_MODE_SENSE_G1:
32377c478bd9Sstevel@tonic-gate 	case SCMD_MODE_SELECT_G1:
32387c478bd9Sstevel@tonic-gate 		if (!(scsa2usbp->scsa2usb_attrs & SCSA2USB_ATTRS_MODE_SENSE)) {
32397c478bd9Sstevel@tonic-gate 			if (cmd->cmd_bp) {
32407c478bd9Sstevel@tonic-gate 				cmd->cmd_pkt->pkt_resid = cmd->cmd_bp->
3241d94492edSfb 				    b_bcount;
32427c478bd9Sstevel@tonic-gate 			}
32437c478bd9Sstevel@tonic-gate 			scsa2usb_force_invalid_request(scsa2usbp, cmd);
32447c478bd9Sstevel@tonic-gate 
32457c478bd9Sstevel@tonic-gate 			return (SCSA2USB_JUST_ACCEPT);
32467c478bd9Sstevel@tonic-gate 		}
32477c478bd9Sstevel@tonic-gate 
32487c478bd9Sstevel@tonic-gate 		break;
32497c478bd9Sstevel@tonic-gate 	default:
32507c478bd9Sstevel@tonic-gate 
32517c478bd9Sstevel@tonic-gate 		break;
32527c478bd9Sstevel@tonic-gate 	}
32537c478bd9Sstevel@tonic-gate 
32547c478bd9Sstevel@tonic-gate 	return (SCSA2USB_TRANSPORT);
32557c478bd9Sstevel@tonic-gate }
32567c478bd9Sstevel@tonic-gate 
32577c478bd9Sstevel@tonic-gate 
32587c478bd9Sstevel@tonic-gate /*
32597c478bd9Sstevel@tonic-gate  * scsa2usb_handle_scsi_cmd_sub_class:
32607c478bd9Sstevel@tonic-gate  *	prepare a scsi cmd
32617c478bd9Sstevel@tonic-gate  *	returns SCSA2USB_TRANSPORT, SCSA2USB_REJECT, SCSA2USB_JUST_ACCEPT
32627c478bd9Sstevel@tonic-gate  */
32637c478bd9Sstevel@tonic-gate int
scsa2usb_handle_scsi_cmd_sub_class(scsa2usb_state_t * scsa2usbp,scsa2usb_cmd_t * cmd,struct scsi_pkt * pkt)32647c478bd9Sstevel@tonic-gate scsa2usb_handle_scsi_cmd_sub_class(scsa2usb_state_t *scsa2usbp,
32657c478bd9Sstevel@tonic-gate     scsa2usb_cmd_t *cmd, struct scsi_pkt *pkt)
32667c478bd9Sstevel@tonic-gate {
32678f588c83Sguoqing zhu - Sun Microsystems - Beijing China 	uchar_t evpd = 0x01;
32687c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
32697c478bd9Sstevel@tonic-gate 	    "scsa2usb_handle_scsi_cmd_sub_class: cmd = 0x%p pkt = 0x%p",
3270112116d8Sfb 	    (void *)cmd, (void *)pkt);
32717c478bd9Sstevel@tonic-gate 
32727c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
32737c478bd9Sstevel@tonic-gate 
32747c478bd9Sstevel@tonic-gate 	bzero(&cmd->cmd_cdb, SCSI_CDB_SIZE);
32757c478bd9Sstevel@tonic-gate 	cmd->cmd_cdb[SCSA2USB_OPCODE] = pkt->pkt_cdbp[0];   /* Set the opcode */
32767c478bd9Sstevel@tonic-gate 	cmd->cmd_cdb[SCSA2USB_LUN] = pkt->pkt_cdbp[1];
32777c478bd9Sstevel@tonic-gate 
32787c478bd9Sstevel@tonic-gate 	/*
32797c478bd9Sstevel@tonic-gate 	 * decode and convert the packet
32807c478bd9Sstevel@tonic-gate 	 * for most cmds, we can bcopy the cdb
32817c478bd9Sstevel@tonic-gate 	 */
32827c478bd9Sstevel@tonic-gate 	switch (pkt->pkt_cdbp[0]) {
32837c478bd9Sstevel@tonic-gate 	case SCMD_FORMAT:
32847c478bd9Sstevel@tonic-gate 		/*
32857c478bd9Sstevel@tonic-gate 		 * SCMD_FORMAT used to limit cmd->cmd_xfercount
32867c478bd9Sstevel@tonic-gate 		 * to 4 bytes, but this hangs
32877c478bd9Sstevel@tonic-gate 		 * formatting dvd media using cdrecord (that is,
32887c478bd9Sstevel@tonic-gate 		 * a SCSI FORMAT UNIT command with a parameter list > 4 bytes)
32897c478bd9Sstevel@tonic-gate 		 * (bit 4 in cdb1 is the Fmtdata bit)
32907c478bd9Sstevel@tonic-gate 		 */
32917c478bd9Sstevel@tonic-gate 		if ((pkt->pkt_cdbp[1] & 0x10) && cmd->cmd_bp) {
32927c478bd9Sstevel@tonic-gate 			cmd->cmd_xfercount = cmd->cmd_bp->b_bcount;
32937c478bd9Sstevel@tonic-gate 		} else {
32947c478bd9Sstevel@tonic-gate 			cmd->cmd_xfercount = 4;
32957c478bd9Sstevel@tonic-gate 		}
32967c478bd9Sstevel@tonic-gate 		cmd->cmd_dir = CBW_DIR_OUT;
32977c478bd9Sstevel@tonic-gate 		cmd->cmd_actual_len = CDB_GROUP0;
32987c478bd9Sstevel@tonic-gate 		bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
32997c478bd9Sstevel@tonic-gate 		break;
33007c478bd9Sstevel@tonic-gate 
33017c478bd9Sstevel@tonic-gate 	case SCMD_INQUIRY:
33027c478bd9Sstevel@tonic-gate 		cmd->cmd_dir = CBW_DIR_IN;
33037c478bd9Sstevel@tonic-gate 		cmd->cmd_actual_len = CDB_GROUP0;
33047c478bd9Sstevel@tonic-gate 		cmd->cmd_cdb[SCSA2USB_LBA_0] = pkt->pkt_cdbp[2];
33058f588c83Sguoqing zhu - Sun Microsystems - Beijing China 
33068f588c83Sguoqing zhu - Sun Microsystems - Beijing China 		/*
33078f588c83Sguoqing zhu - Sun Microsystems - Beijing China 		 * If vpd pages data is limited to maximum SCSA2USB_MAX_INQ_LEN,
33088f588c83Sguoqing zhu - Sun Microsystems - Beijing China 		 * the page data may be truncated, which may cause some issues
33098f588c83Sguoqing zhu - Sun Microsystems - Beijing China 		 * such as making the unique page 0x83 or 0x80 data from
33108f588c83Sguoqing zhu - Sun Microsystems - Beijing China 		 * different devices become the same. So don't limit return
33118f588c83Sguoqing zhu - Sun Microsystems - Beijing China 		 * length for vpd page inquiry cmd.
33128f588c83Sguoqing zhu - Sun Microsystems - Beijing China 		 * Another, in order to maintain compatibility, the original
33138f588c83Sguoqing zhu - Sun Microsystems - Beijing China 		 * length limitation for standard inquiry retains here. It
33148f588c83Sguoqing zhu - Sun Microsystems - Beijing China 		 * can be removed in future if it is verified that enough
33158f588c83Sguoqing zhu - Sun Microsystems - Beijing China 		 * devices can work well.
33168f588c83Sguoqing zhu - Sun Microsystems - Beijing China 		 */
33178f588c83Sguoqing zhu - Sun Microsystems - Beijing China 		if (pkt->pkt_cdbp[1] & evpd) {
33188f588c83Sguoqing zhu - Sun Microsystems - Beijing China 			cmd->cmd_cdb[SCSA2USB_LBA_2] = cmd->cmd_xfercount =
33198f588c83Sguoqing zhu - Sun Microsystems - Beijing China 			    (cmd->cmd_bp ? cmd->cmd_bp->b_bcount : 0);
33208f588c83Sguoqing zhu - Sun Microsystems - Beijing China 		} else {
33218f588c83Sguoqing zhu - Sun Microsystems - Beijing China 			cmd->cmd_cdb[SCSA2USB_LBA_2] = cmd->cmd_xfercount =
33228f588c83Sguoqing zhu - Sun Microsystems - Beijing China 			    min(SCSA2USB_MAX_INQ_LEN,
33238f588c83Sguoqing zhu - Sun Microsystems - Beijing China 			    cmd->cmd_bp ? cmd->cmd_bp->b_bcount : 0);
33248f588c83Sguoqing zhu - Sun Microsystems - Beijing China 		}
33257c478bd9Sstevel@tonic-gate 		break;
33267c478bd9Sstevel@tonic-gate 
33277c478bd9Sstevel@tonic-gate 	case SCMD_READ_CAPACITY:
33287c478bd9Sstevel@tonic-gate 		cmd->cmd_dir = CBW_DIR_IN;
33297c478bd9Sstevel@tonic-gate 		bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
33307c478bd9Sstevel@tonic-gate 		cmd->cmd_xfercount = sizeof (scsa2usb_read_cap_t);
33317c478bd9Sstevel@tonic-gate 		break;
33327c478bd9Sstevel@tonic-gate 
33337c478bd9Sstevel@tonic-gate 	/*
33347c478bd9Sstevel@tonic-gate 	 * SCMD_READ/SCMD_WRITE are converted to G1 cmds
33357c478bd9Sstevel@tonic-gate 	 * (as ATAPI devices don't recognize G0 commands)
33367c478bd9Sstevel@tonic-gate 	 *
33377c478bd9Sstevel@tonic-gate 	 * SCMD_READ_LONG/SCMD_WRITE_LONG are handled in
33387c478bd9Sstevel@tonic-gate 	 * scsa2usb_rw_transport() along with other commands.
33397c478bd9Sstevel@tonic-gate 	 *
33407c478bd9Sstevel@tonic-gate 	 * USB Host Controllers cannot handle large (read/write)
33417c478bd9Sstevel@tonic-gate 	 * xfers. We split the large request to chunks of
33427c478bd9Sstevel@tonic-gate 	 * smaller ones to meet the HCD limitations.
33437c478bd9Sstevel@tonic-gate 	 */
33447c478bd9Sstevel@tonic-gate 	case SCMD_READ:
33457c478bd9Sstevel@tonic-gate 	case SCMD_WRITE:
33467c478bd9Sstevel@tonic-gate 	case SCMD_READ_G1:
33477c478bd9Sstevel@tonic-gate 	case SCMD_WRITE_G1:
334810b633f4SJoshua M. Clulow 	case SCMD_READ_G4:
334910b633f4SJoshua M. Clulow 	case SCMD_WRITE_G4:
33507c478bd9Sstevel@tonic-gate 	case SCMD_READ_G5:
33517c478bd9Sstevel@tonic-gate 	case SCMD_WRITE_G5:
33527c478bd9Sstevel@tonic-gate 	case SCMD_READ_LONG:
33537c478bd9Sstevel@tonic-gate 	case SCMD_WRITE_LONG:
33547c478bd9Sstevel@tonic-gate 	case SCMD_READ_CD:
33557c478bd9Sstevel@tonic-gate 		switch (scsa2usbp->
33567c478bd9Sstevel@tonic-gate 		    scsa2usb_lun_inquiry[pkt->pkt_address.a_lun].
33577c478bd9Sstevel@tonic-gate 		    inq_dtype & DTYPE_MASK) {
33587c478bd9Sstevel@tonic-gate 		case DTYPE_DIRECT:
33597c478bd9Sstevel@tonic-gate 		case DTYPE_RODIRECT:
33607c478bd9Sstevel@tonic-gate 		case DTYPE_OPTICAL:
33617c478bd9Sstevel@tonic-gate 			return (scsa2usb_rw_transport(
3362d94492edSfb 			    scsa2usbp, pkt));
33637c478bd9Sstevel@tonic-gate 		default:
33647c478bd9Sstevel@tonic-gate 			bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
33657c478bd9Sstevel@tonic-gate 			if (cmd->cmd_bp) {
33667c478bd9Sstevel@tonic-gate 				cmd->cmd_dir =
33677c478bd9Sstevel@tonic-gate 				    (cmd->cmd_bp->b_flags & B_READ) ?
33687c478bd9Sstevel@tonic-gate 				    CBW_DIR_IN : CBW_DIR_OUT;
33697c478bd9Sstevel@tonic-gate 				cmd->cmd_xfercount =
33707c478bd9Sstevel@tonic-gate 				    cmd->cmd_bp->b_bcount;
33717c478bd9Sstevel@tonic-gate 			}
33727c478bd9Sstevel@tonic-gate 			break;
33737c478bd9Sstevel@tonic-gate 		}
33747c478bd9Sstevel@tonic-gate 		break;
33757c478bd9Sstevel@tonic-gate 
33767c478bd9Sstevel@tonic-gate 	case SCMD_REQUEST_SENSE:
33777c478bd9Sstevel@tonic-gate 		cmd->cmd_dir = CBW_DIR_IN;
33787c478bd9Sstevel@tonic-gate 		cmd->cmd_xfercount = pkt->pkt_cdbp[4];
33797c478bd9Sstevel@tonic-gate 		cmd->cmd_cdb[SCSA2USB_LBA_2] = pkt->pkt_cdbp[4];
33807c478bd9Sstevel@tonic-gate 		cmd->cmd_actual_len = CDB_GROUP0;
33817c478bd9Sstevel@tonic-gate 		break;
33827c478bd9Sstevel@tonic-gate 
33837c478bd9Sstevel@tonic-gate 	case SCMD_DOORLOCK:
33847c478bd9Sstevel@tonic-gate 	case SCMD_START_STOP:
33857c478bd9Sstevel@tonic-gate 	case SCMD_TEST_UNIT_READY:
33867c478bd9Sstevel@tonic-gate 		bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
33877c478bd9Sstevel@tonic-gate 		break;
33887c478bd9Sstevel@tonic-gate 
33897c478bd9Sstevel@tonic-gate 	/*
33907c478bd9Sstevel@tonic-gate 	 * Needed by zip protocol to reset the device
33917c478bd9Sstevel@tonic-gate 	 */
33927c478bd9Sstevel@tonic-gate 	case SCMD_SDIAG:
33937c478bd9Sstevel@tonic-gate 	case SCMD_REZERO_UNIT:
33947c478bd9Sstevel@tonic-gate 		bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
33957c478bd9Sstevel@tonic-gate 		cmd->cmd_actual_len = CDB_GROUP1;
33967c478bd9Sstevel@tonic-gate 		break;
33977c478bd9Sstevel@tonic-gate 
33987c478bd9Sstevel@tonic-gate 	case SCMD_WRITE_VERIFY:
33997c478bd9Sstevel@tonic-gate 		bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
34007c478bd9Sstevel@tonic-gate 		cmd->cmd_dir = CBW_DIR_OUT;
34017c478bd9Sstevel@tonic-gate 		cmd->cmd_xfercount = (pkt->pkt_cdbp[7] << 8) | pkt->pkt_cdbp[8];
34027c478bd9Sstevel@tonic-gate 		cmd->cmd_actual_len = CDB_GROUP1;
34037c478bd9Sstevel@tonic-gate 		break;
34047c478bd9Sstevel@tonic-gate 
34057c478bd9Sstevel@tonic-gate 	/*
34067c478bd9Sstevel@tonic-gate 	 * Next command does not have a SCSI equivalent as
34077c478bd9Sstevel@tonic-gate 	 * it is vendor specific.
34087c478bd9Sstevel@tonic-gate 	 * It was listed in the vendor's ATAPI Zip specs.
34097c478bd9Sstevel@tonic-gate 	 */
34107c478bd9Sstevel@tonic-gate 	case SCMD_READ_FORMAT_CAP:
34117c478bd9Sstevel@tonic-gate 		bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
34127c478bd9Sstevel@tonic-gate 		cmd->cmd_dir = CBW_DIR_IN;
34137c478bd9Sstevel@tonic-gate 		cmd->cmd_xfercount = (pkt->pkt_cdbp[7] << 8) | pkt->pkt_cdbp[8];
34147c478bd9Sstevel@tonic-gate 		cmd->cmd_actual_len = CDB_GROUP1;
34157c478bd9Sstevel@tonic-gate 		break;
34167c478bd9Sstevel@tonic-gate 	case IOMEGA_CMD_CARTRIDGE_PROTECT:
34177c478bd9Sstevel@tonic-gate 		cmd->cmd_dir = CBW_DIR_OUT;
34187c478bd9Sstevel@tonic-gate 		cmd->cmd_cdb[SCSA2USB_LBA_2] = pkt->pkt_cdbp[4];
34197c478bd9Sstevel@tonic-gate 		cmd->cmd_cdb[SCSA2USB_LBA_2] &= ~1;	/* Make it even */
34207c478bd9Sstevel@tonic-gate 		cmd->cmd_cdb[SCSA2USB_LUN] = pkt->pkt_cdbp[1];
34217c478bd9Sstevel@tonic-gate 		cmd->cmd_actual_len = CDB_GROUP0;
34227c478bd9Sstevel@tonic-gate 		cmd->cmd_xfercount = pkt->pkt_cdbp[4]; /* Length of password */
34237c478bd9Sstevel@tonic-gate 		break;
34247c478bd9Sstevel@tonic-gate 
342514d649faScg 	/*
342614d649faScg 	 * Do not convert SCMD_MODE_SENSE/SELECT to G1 cmds because
342714d649faScg 	 * the mode header is different as well. USB devices don't
342814d649faScg 	 * support 0x03 & 0x04 mode pages, which are already obsoleted
342914d649faScg 	 * by SPC-2 specification.
343014d649faScg 	 */
343114d649faScg 	case SCMD_MODE_SENSE:
343214d649faScg 	case SCMD_MODE_SELECT:
343342e43e98Sguoqing zhu - Sun Microsystems - Beijing China 		if (((pkt->pkt_cdbp[2] & SD_MODE_SENSE_PAGE_MASK)
343442e43e98Sguoqing zhu - Sun Microsystems - Beijing China 		    == SD_MODE_SENSE_PAGE3_CODE) ||
343542e43e98Sguoqing zhu - Sun Microsystems - Beijing China 		    ((pkt->pkt_cdbp[2] & SD_MODE_SENSE_PAGE_MASK)
343642e43e98Sguoqing zhu - Sun Microsystems - Beijing China 		    == SD_MODE_SENSE_PAGE4_CODE)) {
343714d649faScg 			if (cmd->cmd_bp) {
343814d649faScg 				cmd->cmd_pkt->pkt_resid = cmd->cmd_bp->b_bcount;
343914d649faScg 			}
344014d649faScg 			scsa2usb_force_invalid_request(scsa2usbp, cmd);
344114d649faScg 			return (SCSA2USB_JUST_ACCEPT);
344214d649faScg 		}
344314d649faScg 		/* FALLTHROUGH */
344414d649faScg 
34457c478bd9Sstevel@tonic-gate 	default:
34467c478bd9Sstevel@tonic-gate 		/*
34477c478bd9Sstevel@tonic-gate 		 * an unknown command may be a uscsi cmd which we
34487c478bd9Sstevel@tonic-gate 		 * should let go thru without mapping
34497c478bd9Sstevel@tonic-gate 		 */
34507c478bd9Sstevel@tonic-gate 		bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
34517c478bd9Sstevel@tonic-gate 		if (cmd->cmd_bp) {
34527c478bd9Sstevel@tonic-gate 			cmd->cmd_dir = (cmd->cmd_bp->b_flags & B_READ) ?
3453d94492edSfb 			    CBW_DIR_IN : CBW_DIR_OUT;
34547c478bd9Sstevel@tonic-gate 			cmd->cmd_xfercount = cmd->cmd_bp->b_bcount;
34557c478bd9Sstevel@tonic-gate 		}
34567c478bd9Sstevel@tonic-gate 
34577c478bd9Sstevel@tonic-gate 		break;
34587c478bd9Sstevel@tonic-gate 	} /* end of switch */
34597c478bd9Sstevel@tonic-gate 
34607c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
34617c478bd9Sstevel@tonic-gate 	    "scsa2usb_handle_scsi_cmd_sub_class: opcode = 0x%x count = 0x%lx",
34627c478bd9Sstevel@tonic-gate 	    pkt->pkt_cdbp[SCSA2USB_OPCODE], cmd->cmd_xfercount);
34637c478bd9Sstevel@tonic-gate 
34647c478bd9Sstevel@tonic-gate 	cmd->cmd_total_xfercount = cmd->cmd_xfercount;
34657c478bd9Sstevel@tonic-gate 
34667c478bd9Sstevel@tonic-gate 	return (SCSA2USB_TRANSPORT);
34677c478bd9Sstevel@tonic-gate }
34687c478bd9Sstevel@tonic-gate 
34697c478bd9Sstevel@tonic-gate 
3470df4cb6e0Ssl /*
3471df4cb6e0Ssl  * scsa2usb_do_tur is performed before READ CAPACITY command is issued.
3472df4cb6e0Ssl  * It returns media status, 0 for media ready, -1 for media not ready
3473df4cb6e0Ssl  * or other errors.
3474df4cb6e0Ssl  */
3475df4cb6e0Ssl static int
scsa2usb_do_tur(scsa2usb_state_t * scsa2usbp,struct scsi_address * ap)3476df4cb6e0Ssl scsa2usb_do_tur(scsa2usb_state_t *scsa2usbp, struct scsi_address *ap)
3477df4cb6e0Ssl {
3478df4cb6e0Ssl 	struct scsi_pkt		*pkt;
3479df4cb6e0Ssl 	scsa2usb_cmd_t		*turcmd;
3480df4cb6e0Ssl 	int			rval = -1;
3481df4cb6e0Ssl 
3482df4cb6e0Ssl 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
3483df4cb6e0Ssl 	    "scsa2usb_do_tur:");
3484df4cb6e0Ssl 
3485df4cb6e0Ssl 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
3486df4cb6e0Ssl 
3487df4cb6e0Ssl 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
3488df4cb6e0Ssl 	if ((pkt = scsi_init_pkt(ap, NULL, NULL, CDB_GROUP0, 1,
3489df4cb6e0Ssl 	    PKT_PRIV_LEN, PKT_CONSISTENT, SLEEP_FUNC, NULL)) == NULL) {
3490df4cb6e0Ssl 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
3491df4cb6e0Ssl 		USB_DPRINTF_L2(DPRINT_MASK_SCSA,
3492df4cb6e0Ssl 		    scsa2usbp->scsa2usb_log_handle,
3493df4cb6e0Ssl 		    "scsa2usb_do_tur: init pkt failed");
3494df4cb6e0Ssl 
3495df4cb6e0Ssl 		return (rval);
3496df4cb6e0Ssl 	}
3497df4cb6e0Ssl 
3498df4cb6e0Ssl 	RQ_MAKECOM_G0(pkt, FLAG_HEAD | FLAG_NODISCON,
3499df4cb6e0Ssl 	    (char)SCMD_TEST_UNIT_READY, 0, 0);
3500df4cb6e0Ssl 
3501df4cb6e0Ssl 	pkt->pkt_comp = NULL;
3502df4cb6e0Ssl 	pkt->pkt_time = PKT_DEFAULT_TIMEOUT;
3503df4cb6e0Ssl 	turcmd = PKT2CMD(pkt);
3504df4cb6e0Ssl 
3505df4cb6e0Ssl 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
3506df4cb6e0Ssl 	scsa2usb_prepare_pkt(scsa2usbp, turcmd->cmd_pkt);
3507df4cb6e0Ssl 
3508df4cb6e0Ssl 	if (scsa2usb_cmd_transport(scsa2usbp, turcmd) != TRAN_ACCEPT) {
3509df4cb6e0Ssl 		USB_DPRINTF_L2(DPRINT_MASK_SCSA,
3510df4cb6e0Ssl 		    scsa2usbp->scsa2usb_log_handle,
3511df4cb6e0Ssl 		    "scsa2usb_do_tur: cmd transport failed, "
3512df4cb6e0Ssl 		    "pkt_reason=0x%x", turcmd->cmd_pkt->pkt_reason);
3513df4cb6e0Ssl 	} else if (*(turcmd->cmd_pkt->pkt_scbp) != STATUS_GOOD) {
3514df4cb6e0Ssl 		/*
3515df4cb6e0Ssl 		 * Theoretically, the sense data should be retrieved and
3516df4cb6e0Ssl 		 * sense key be checked when check condition happens. If
3517df4cb6e0Ssl 		 * the sense key is UNIT ATTENTION, TEST UNIT READY cmd
3518df4cb6e0Ssl 		 * needs to be sent again to clear the UNIT ATTENTION and
3519df4cb6e0Ssl 		 * another TUR to be sent to get the real media status.
3520df4cb6e0Ssl 		 * But the AMI virtual floppy device simply cannot recover
3521df4cb6e0Ssl 		 * from UNIT ATTENTION by re-sending a TUR cmd, so it
3522df4cb6e0Ssl 		 * doesn't make any difference whether to check sense key
3523df4cb6e0Ssl 		 * or not. Just ignore sense key checking here and assume
3524df4cb6e0Ssl 		 * the device is NOT READY.
3525df4cb6e0Ssl 		 */
3526df4cb6e0Ssl 		USB_DPRINTF_L2(DPRINT_MASK_SCSA,
3527df4cb6e0Ssl 		    scsa2usbp->scsa2usb_log_handle,
3528df4cb6e0Ssl 		    "scsa2usb_do_tur: media not ready");
3529df4cb6e0Ssl 	} else {
3530df4cb6e0Ssl 		rval = 0;
3531df4cb6e0Ssl 	}
3532df4cb6e0Ssl 
3533df4cb6e0Ssl 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
3534df4cb6e0Ssl 	scsi_destroy_pkt(pkt);
3535df4cb6e0Ssl 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
3536df4cb6e0Ssl 
3537df4cb6e0Ssl 	return (rval);
3538df4cb6e0Ssl }
3539df4cb6e0Ssl 
3540df4cb6e0Ssl 
35417c478bd9Sstevel@tonic-gate /*
354247b9747fSJoshua M. Clulow  * Check this UFI command against the quirks for this particular device.
354347b9747fSJoshua M. Clulow  * Returns a transport disposition.
35447c478bd9Sstevel@tonic-gate  */
35457c478bd9Sstevel@tonic-gate static int
scsa2usb_check_ufi_quirks(scsa2usb_state_t * scsa2usbp,scsa2usb_cmd_t * cmd)354647b9747fSJoshua M. Clulow scsa2usb_check_ufi_quirks(scsa2usb_state_t *scsa2usbp, scsa2usb_cmd_t *cmd)
35477c478bd9Sstevel@tonic-gate {
354847b9747fSJoshua M. Clulow 	int rval = SCSA2USB_TRANSPORT;
35497c478bd9Sstevel@tonic-gate 
35507c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
35517c478bd9Sstevel@tonic-gate 
355247b9747fSJoshua M. Clulow 	switch (cmd->cmd_pkt->pkt_cdbp[0]) {
35537c478bd9Sstevel@tonic-gate 	case SCMD_PRIN:
35547c478bd9Sstevel@tonic-gate 	case SCMD_PROUT:
35557c478bd9Sstevel@tonic-gate 		rval = SCSA2USB_JUST_ACCEPT;
35567c478bd9Sstevel@tonic-gate 		break;
35577c478bd9Sstevel@tonic-gate 	case SCMD_MODE_SENSE:
35587c478bd9Sstevel@tonic-gate 	case SCMD_MODE_SELECT:
35597c478bd9Sstevel@tonic-gate 		if (cmd->cmd_bp) {
35607c478bd9Sstevel@tonic-gate 			cmd->cmd_pkt->pkt_resid = cmd->cmd_bp->b_bcount;
35617c478bd9Sstevel@tonic-gate 		}
35627c478bd9Sstevel@tonic-gate 		scsa2usb_force_invalid_request(scsa2usbp, cmd);
35637c478bd9Sstevel@tonic-gate 		rval = SCSA2USB_JUST_ACCEPT;
35647c478bd9Sstevel@tonic-gate 		break;
35657c478bd9Sstevel@tonic-gate 	case SCMD_GET_CONFIGURATION:
35667c478bd9Sstevel@tonic-gate 		if (!(scsa2usbp->scsa2usb_attrs & SCSA2USB_ATTRS_GET_CONF)) {
35677c478bd9Sstevel@tonic-gate 			rval = SCSA2USB_JUST_ACCEPT;
35687c478bd9Sstevel@tonic-gate 		}
35697c478bd9Sstevel@tonic-gate 		break;
35707c478bd9Sstevel@tonic-gate 	case SCMD_GET_PERFORMANCE:
35717c478bd9Sstevel@tonic-gate 		if (!(scsa2usbp->scsa2usb_attrs & SCSA2USB_ATTRS_GET_PERF)) {
35727c478bd9Sstevel@tonic-gate 			rval = SCSA2USB_JUST_ACCEPT;
35737c478bd9Sstevel@tonic-gate 		}
35747c478bd9Sstevel@tonic-gate 		break;
35757c478bd9Sstevel@tonic-gate 	case SCMD_START_STOP:
35767c478bd9Sstevel@tonic-gate 		/*
35777c478bd9Sstevel@tonic-gate 		 * some CB/CBI devices don't have mechanics that spin the
35787c478bd9Sstevel@tonic-gate 		 * media up and down. So, it doesn't make much sense
35797c478bd9Sstevel@tonic-gate 		 * to issue this cmd to those devices.
35807c478bd9Sstevel@tonic-gate 		 */
35817c478bd9Sstevel@tonic-gate 		if (!(scsa2usbp->scsa2usb_attrs & SCSA2USB_ATTRS_START_STOP)) {
35827c478bd9Sstevel@tonic-gate 			rval = SCSA2USB_JUST_ACCEPT;
35837c478bd9Sstevel@tonic-gate 		}
35847c478bd9Sstevel@tonic-gate 		break;
3585df4cb6e0Ssl 	case SCMD_READ_CAPACITY:
3586df4cb6e0Ssl 		/*
3587df4cb6e0Ssl 		 * Some devices don't support READ CAPACITY command
3588df4cb6e0Ssl 		 * when media is not ready. Need to check media status
3589df4cb6e0Ssl 		 * before issuing the cmd to such device.
3590df4cb6e0Ssl 		 */
3591df4cb6e0Ssl 		if (!(scsa2usbp->scsa2usb_attrs &
3592df4cb6e0Ssl 		    SCSA2USB_ATTRS_NO_MEDIA_CHECK)) {
3593df4cb6e0Ssl 			struct scsi_pkt *pkt = cmd->cmd_pkt;
3594df4cb6e0Ssl 
3595df4cb6e0Ssl 			ASSERT(scsa2usbp->scsa2usb_cur_pkt == pkt);
3596df4cb6e0Ssl 			scsa2usbp->scsa2usb_cur_pkt = NULL;
3597df4cb6e0Ssl 
3598df4cb6e0Ssl 			if (scsa2usb_do_tur(scsa2usbp,
3599df4cb6e0Ssl 			    &pkt->pkt_address) != 0) {
3600df4cb6e0Ssl 				/* media not ready, force cmd invalid */
3601df4cb6e0Ssl 				if (cmd->cmd_bp) {
3602df4cb6e0Ssl 					cmd->cmd_pkt->pkt_resid =
3603df4cb6e0Ssl 					    cmd->cmd_bp->b_bcount;
3604df4cb6e0Ssl 				}
3605df4cb6e0Ssl 				scsa2usb_force_invalid_request(scsa2usbp, cmd);
3606df4cb6e0Ssl 				rval = SCSA2USB_JUST_ACCEPT;
3607df4cb6e0Ssl 			}
3608df4cb6e0Ssl 
3609df4cb6e0Ssl 			scsa2usbp->scsa2usb_cur_pkt = pkt;
3610df4cb6e0Ssl 		}
3611df4cb6e0Ssl 		break;
36127c478bd9Sstevel@tonic-gate 	default:
36137c478bd9Sstevel@tonic-gate 		break;
36147c478bd9Sstevel@tonic-gate 	}
36157c478bd9Sstevel@tonic-gate 
36167c478bd9Sstevel@tonic-gate 	return (rval);
36177c478bd9Sstevel@tonic-gate }
36187c478bd9Sstevel@tonic-gate 
36197c478bd9Sstevel@tonic-gate 
36207c478bd9Sstevel@tonic-gate /*
36217c478bd9Sstevel@tonic-gate  * scsa2usb_handle_ufi_subclass_cmd:
36227c478bd9Sstevel@tonic-gate  *	prepare a UFI cmd
36237c478bd9Sstevel@tonic-gate  *	returns SCSA2USB_TRANSPORT, SCSA2USB_REJECT
36247c478bd9Sstevel@tonic-gate  */
36257c478bd9Sstevel@tonic-gate int
scsa2usb_handle_ufi_subclass_cmd(scsa2usb_state_t * scsa2usbp,scsa2usb_cmd_t * cmd,struct scsi_pkt * pkt)36267c478bd9Sstevel@tonic-gate scsa2usb_handle_ufi_subclass_cmd(scsa2usb_state_t *scsa2usbp,
36277c478bd9Sstevel@tonic-gate     scsa2usb_cmd_t *cmd, struct scsi_pkt *pkt)
36287c478bd9Sstevel@tonic-gate {
362947b9747fSJoshua M. Clulow 	uchar_t opcode = pkt->pkt_cdbp[0];
36307c478bd9Sstevel@tonic-gate 
36317c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
36327c478bd9Sstevel@tonic-gate 	    "scsa2usb_handle_ufi_subclass_cmd: cmd = 0x%p pkt = 0x%p",
3633112116d8Sfb 	    (void *)cmd, (void *)pkt);
36347c478bd9Sstevel@tonic-gate 
36357c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
36367c478bd9Sstevel@tonic-gate 
36377c478bd9Sstevel@tonic-gate 	bzero(&cmd->cmd_cdb, SCSI_CDB_SIZE);
36387c478bd9Sstevel@tonic-gate 	cmd->cmd_cdb[SCSA2USB_OPCODE] = opcode;   /* Set the opcode */
36397c478bd9Sstevel@tonic-gate 	cmd->cmd_cdb[SCSA2USB_LUN] = pkt->pkt_cdbp[1];
36407c478bd9Sstevel@tonic-gate 
36417c478bd9Sstevel@tonic-gate 	/*
36427c478bd9Sstevel@tonic-gate 	 * decode and convert the packet if necessary
36437c478bd9Sstevel@tonic-gate 	 * for most cmds, we can bcopy the cdb
36447c478bd9Sstevel@tonic-gate 	 */
36457c478bd9Sstevel@tonic-gate 	switch (opcode) {
36467c478bd9Sstevel@tonic-gate 	case SCMD_FORMAT:
36477c478bd9Sstevel@tonic-gate 		/* if parameter list is specified */
36487c478bd9Sstevel@tonic-gate 		if (pkt->pkt_cdbp[1] & 0x10) {
36497c478bd9Sstevel@tonic-gate 			cmd->cmd_xfercount =
3650d94492edSfb 			    (pkt->pkt_cdbp[7] << 8) | pkt->pkt_cdbp[8];
36517c478bd9Sstevel@tonic-gate 			cmd->cmd_dir = USB_EP_DIR_OUT;
36527c478bd9Sstevel@tonic-gate 			cmd->cmd_actual_len = CDB_GROUP5;
36537c478bd9Sstevel@tonic-gate 		}
36547c478bd9Sstevel@tonic-gate 		bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
36557c478bd9Sstevel@tonic-gate 		break;
36567c478bd9Sstevel@tonic-gate 	case SCMD_INQUIRY:
36577c478bd9Sstevel@tonic-gate 		cmd->cmd_dir = USB_EP_DIR_IN;
36587c478bd9Sstevel@tonic-gate 		cmd->cmd_actual_len = CDB_GROUP0;
36597c478bd9Sstevel@tonic-gate 		cmd->cmd_cdb[SCSA2USB_LBA_0] = pkt->pkt_cdbp[2];
36607c478bd9Sstevel@tonic-gate 		cmd->cmd_cdb[SCSA2USB_LBA_2] = cmd->cmd_xfercount =
36617c478bd9Sstevel@tonic-gate 		    min(SCSA2USB_MAX_INQ_LEN,
36627c478bd9Sstevel@tonic-gate 		    cmd->cmd_bp ? cmd->cmd_bp->b_bcount : 0);
36637c478bd9Sstevel@tonic-gate 		break;
36647c478bd9Sstevel@tonic-gate 	case SCMD_READ_CAPACITY:
36657c478bd9Sstevel@tonic-gate 		cmd->cmd_dir = USB_EP_DIR_IN;
36667c478bd9Sstevel@tonic-gate 		bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
36677c478bd9Sstevel@tonic-gate 		cmd->cmd_xfercount = sizeof (scsa2usb_read_cap_t);
36687c478bd9Sstevel@tonic-gate 		break;
36697c478bd9Sstevel@tonic-gate 	case SCMD_REQUEST_SENSE:
36707c478bd9Sstevel@tonic-gate 		cmd->cmd_dir = USB_EP_DIR_IN;
36717c478bd9Sstevel@tonic-gate 		cmd->cmd_xfercount = pkt->pkt_cdbp[4];
36727c478bd9Sstevel@tonic-gate 		cmd->cmd_cdb[SCSA2USB_LBA_2] = pkt->pkt_cdbp[4];
36737c478bd9Sstevel@tonic-gate 		cmd->cmd_actual_len = CDB_GROUP0;
36747c478bd9Sstevel@tonic-gate 		break;
36757c478bd9Sstevel@tonic-gate 
36767c478bd9Sstevel@tonic-gate 	/*
36777c478bd9Sstevel@tonic-gate 	 * do not convert SCMD_MODE_SENSE/SELECT because the
36787c478bd9Sstevel@tonic-gate 	 * mode header is different as well
36797c478bd9Sstevel@tonic-gate 	 */
36807c478bd9Sstevel@tonic-gate 
36817c478bd9Sstevel@tonic-gate 	/*
36827c478bd9Sstevel@tonic-gate 	 * see usb_bulkonly.c for comments on the next set of commands
36837c478bd9Sstevel@tonic-gate 	 */
36847c478bd9Sstevel@tonic-gate 	case SCMD_READ:
36857c478bd9Sstevel@tonic-gate 	case SCMD_WRITE:
36867c478bd9Sstevel@tonic-gate 	case SCMD_READ_G1:
36877c478bd9Sstevel@tonic-gate 	case SCMD_WRITE_G1:
368810b633f4SJoshua M. Clulow 	case SCMD_READ_G4:
368910b633f4SJoshua M. Clulow 	case SCMD_WRITE_G4:
36907c478bd9Sstevel@tonic-gate 	case SCMD_READ_G5:
36917c478bd9Sstevel@tonic-gate 	case SCMD_WRITE_G5:
36927c478bd9Sstevel@tonic-gate 	case SCMD_READ_LONG:
36937c478bd9Sstevel@tonic-gate 	case SCMD_WRITE_LONG:
36947c478bd9Sstevel@tonic-gate 	case SCMD_READ_CD:
36957c478bd9Sstevel@tonic-gate 		return (scsa2usb_rw_transport(scsa2usbp, pkt));
36967c478bd9Sstevel@tonic-gate 
36977c478bd9Sstevel@tonic-gate 	case SCMD_TEST_UNIT_READY:
36987c478bd9Sstevel@tonic-gate 		/*
36997c478bd9Sstevel@tonic-gate 		 * Some CB/CBI devices may not support TUR.
37007c478bd9Sstevel@tonic-gate 		 */
37017c478bd9Sstevel@tonic-gate 		bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
37027c478bd9Sstevel@tonic-gate 		break;
37037c478bd9Sstevel@tonic-gate 	case SCMD_READ_FORMAT_CAP:
37047c478bd9Sstevel@tonic-gate 		bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
37057c478bd9Sstevel@tonic-gate 		cmd->cmd_dir = USB_EP_DIR_IN;
37067c478bd9Sstevel@tonic-gate 		cmd->cmd_actual_len = CDB_GROUP1;
37077c478bd9Sstevel@tonic-gate 		cmd->cmd_xfercount = (pkt->pkt_cdbp[7] << 8) | pkt->pkt_cdbp[8];
37087c478bd9Sstevel@tonic-gate 		break;
37097c478bd9Sstevel@tonic-gate 	case SCMD_WRITE_VERIFY:
37107c478bd9Sstevel@tonic-gate 		bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
37117c478bd9Sstevel@tonic-gate 		cmd->cmd_dir = USB_EP_DIR_OUT;
37127c478bd9Sstevel@tonic-gate 		cmd->cmd_actual_len = CDB_GROUP1;
37137c478bd9Sstevel@tonic-gate 		cmd->cmd_xfercount = (pkt->pkt_cdbp[7] << 8) | pkt->pkt_cdbp[8];
37147c478bd9Sstevel@tonic-gate 		break;
37157c478bd9Sstevel@tonic-gate 	case SCMD_START_STOP:
37167c478bd9Sstevel@tonic-gate 		/* A larger timeout is needed for 'flaky' CD-RW devices */
37177c478bd9Sstevel@tonic-gate 		if (!(scsa2usbp->scsa2usb_attrs & SCSA2USB_ATTRS_BIG_TIMEOUT)) {
37187c478bd9Sstevel@tonic-gate 			cmd->cmd_timeout = max(cmd->cmd_timeout,
3719d94492edSfb 			    20 * SCSA2USB_BULK_PIPE_TIMEOUT);
37207c478bd9Sstevel@tonic-gate 		}
37217c478bd9Sstevel@tonic-gate 		/* FALLTHRU */
37227c478bd9Sstevel@tonic-gate 	default:
37237c478bd9Sstevel@tonic-gate 		/*
37247c478bd9Sstevel@tonic-gate 		 * all other commands don't need special mapping
37257c478bd9Sstevel@tonic-gate 		 */
37267c478bd9Sstevel@tonic-gate 		bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
37277c478bd9Sstevel@tonic-gate 		if (cmd->cmd_bp) {
37287c478bd9Sstevel@tonic-gate 			cmd->cmd_dir = (cmd->cmd_bp->b_flags & B_READ) ?
3729d94492edSfb 			    CBW_DIR_IN : CBW_DIR_OUT;
37307c478bd9Sstevel@tonic-gate 			cmd->cmd_xfercount = cmd->cmd_bp->b_bcount;
37317c478bd9Sstevel@tonic-gate 		}
37327c478bd9Sstevel@tonic-gate 		break;
37337c478bd9Sstevel@tonic-gate 
37347c478bd9Sstevel@tonic-gate 	} /* end of switch */
37357c478bd9Sstevel@tonic-gate 
37367c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
37377c478bd9Sstevel@tonic-gate 	    "scsa2usb_handle_ufi_subclass_cmd: opcode = 0x%x count = 0x%lx",
37387c478bd9Sstevel@tonic-gate 	    opcode, cmd->cmd_xfercount);
37397c478bd9Sstevel@tonic-gate 
37407c478bd9Sstevel@tonic-gate 	cmd->cmd_total_xfercount = cmd->cmd_xfercount;
37417c478bd9Sstevel@tonic-gate 
37427c478bd9Sstevel@tonic-gate 	return (SCSA2USB_TRANSPORT);
37437c478bd9Sstevel@tonic-gate }
37447c478bd9Sstevel@tonic-gate 
37457c478bd9Sstevel@tonic-gate 
37467c478bd9Sstevel@tonic-gate /*
37477c478bd9Sstevel@tonic-gate  * scsa2usb_rw_transport:
37487c478bd9Sstevel@tonic-gate  *	Handle splitting READ and WRITE requests to the
37497c478bd9Sstevel@tonic-gate  *	device to a size that the host controller allows.
37507c478bd9Sstevel@tonic-gate  *
37517c478bd9Sstevel@tonic-gate  *	returns TRAN_* values and not USB_SUCCESS/FAILURE
37527c478bd9Sstevel@tonic-gate  *
37537c478bd9Sstevel@tonic-gate  * To support CD-R/CD-RW/DVD media, we need to support a
37547c478bd9Sstevel@tonic-gate  * variety of block sizes for the different types of CD
37557c478bd9Sstevel@tonic-gate  * data (audio, data, video, CD-XA, yellowbook, redbook etc.)
37567c478bd9Sstevel@tonic-gate  *
37577c478bd9Sstevel@tonic-gate  * Some of the block sizes used are:- 512, 1k, 2k, 2056, 2336
37587c478bd9Sstevel@tonic-gate  * 2340, 2352, 2368, 2448, 2646, 2647 etc.
37597c478bd9Sstevel@tonic-gate  *
37607c478bd9Sstevel@tonic-gate  * NOTE: the driver could be entertaining a SCSI CDB that uses
37617c478bd9Sstevel@tonic-gate  * any of the above listed block sizes at a given time, and a
37627c478bd9Sstevel@tonic-gate  * totally different block size at any other given time for a
37637c478bd9Sstevel@tonic-gate  * different CDB.
37647c478bd9Sstevel@tonic-gate  *
37657c478bd9Sstevel@tonic-gate  * We need to compute block size every time and figure out
37667c478bd9Sstevel@tonic-gate  * matching LBA and LEN accordingly.
37677c478bd9Sstevel@tonic-gate  *
37687c478bd9Sstevel@tonic-gate  * Also UHCI has a limitation that it can only xfer 32k at a
37697c478bd9Sstevel@tonic-gate  * given time. So, with "odd" sized blocks and a limitation of
37707c478bd9Sstevel@tonic-gate  * how much we can xfer per shot, we need to compute xfer_count
37717c478bd9Sstevel@tonic-gate  * as well each time.
37727c478bd9Sstevel@tonic-gate  *
37737c478bd9Sstevel@tonic-gate  * The same computation is also done in the function
37747c478bd9Sstevel@tonic-gate  * scsa2usb_setup_next_xfer().	To save computing block_size in
37757c478bd9Sstevel@tonic-gate  * this function, I am saving block_size in "cmd" now.
37767c478bd9Sstevel@tonic-gate  */
37777c478bd9Sstevel@tonic-gate int
scsa2usb_rw_transport(scsa2usb_state_t * scsa2usbp,struct scsi_pkt * pkt)37787c478bd9Sstevel@tonic-gate scsa2usb_rw_transport(scsa2usb_state_t *scsa2usbp, struct scsi_pkt *pkt)
37797c478bd9Sstevel@tonic-gate {
37807c478bd9Sstevel@tonic-gate 	scsa2usb_cmd_t *cmd = PKT2CMD(pkt);
378110b633f4SJoshua M. Clulow 	int dir, opcode;
378210b633f4SJoshua M. Clulow 	uint64_t lba;
37837c478bd9Sstevel@tonic-gate 	struct buf *bp = cmd->cmd_bp;
37847c478bd9Sstevel@tonic-gate 	size_t len, xfer_count;
37857c478bd9Sstevel@tonic-gate 	size_t blk_size;	/* calculate the block size to be used */
37867c478bd9Sstevel@tonic-gate 	int sz;
37877c478bd9Sstevel@tonic-gate 
37887c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
37897c478bd9Sstevel@tonic-gate 	    "scsa2usb_rw_transport:");
37907c478bd9Sstevel@tonic-gate 
37917c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
37927c478bd9Sstevel@tonic-gate 
37937c478bd9Sstevel@tonic-gate 	opcode = pkt->pkt_cdbp[0];
379410b633f4SJoshua M. Clulow 	blk_size = scsa2usbp->scsa2usb_lbasize[pkt->pkt_address.a_lun];
37957c478bd9Sstevel@tonic-gate 						/* set to default */
37967c478bd9Sstevel@tonic-gate 
37977c478bd9Sstevel@tonic-gate 	switch (opcode) {
37987c478bd9Sstevel@tonic-gate 	case SCMD_READ:
37997c478bd9Sstevel@tonic-gate 		/*
38007c478bd9Sstevel@tonic-gate 		 * Note that READ/WRITE(6) are not supported by the drive.
38017c478bd9Sstevel@tonic-gate 		 * convert it into a 10 byte read/write.
38027c478bd9Sstevel@tonic-gate 		 */
38037c478bd9Sstevel@tonic-gate 		lba = SCSA2USB_LBA_6BYTE(pkt);
38047c478bd9Sstevel@tonic-gate 		len = SCSA2USB_LEN_6BYTE(pkt);
38057c478bd9Sstevel@tonic-gate 		opcode = SCMD_READ_G1;	/* Overwrite it w/ byte 10 cmd val */
38067c478bd9Sstevel@tonic-gate 		dir = USB_EP_DIR_IN;
38077c478bd9Sstevel@tonic-gate 		break;
38087c478bd9Sstevel@tonic-gate 	case SCMD_WRITE:
38097c478bd9Sstevel@tonic-gate 		lba = SCSA2USB_LBA_6BYTE(pkt);
38107c478bd9Sstevel@tonic-gate 		len = SCSA2USB_LEN_6BYTE(pkt);
38117c478bd9Sstevel@tonic-gate 		opcode = SCMD_WRITE_G1;	/* Overwrite it w/ byte 10 cmd val */
38127c478bd9Sstevel@tonic-gate 		dir = USB_EP_DIR_OUT;
38137c478bd9Sstevel@tonic-gate 		break;
38147c478bd9Sstevel@tonic-gate 	case SCMD_READ_G1:
38157c478bd9Sstevel@tonic-gate 	case SCMD_READ_LONG:
38167c478bd9Sstevel@tonic-gate 		lba = SCSA2USB_LBA_10BYTE(pkt);
38177c478bd9Sstevel@tonic-gate 		len = SCSA2USB_LEN_10BYTE(pkt);
38187c478bd9Sstevel@tonic-gate 		dir = USB_EP_DIR_IN;
38197c478bd9Sstevel@tonic-gate 		break;
38207c478bd9Sstevel@tonic-gate 	case SCMD_WRITE_G1:
38217c478bd9Sstevel@tonic-gate 	case SCMD_WRITE_LONG:
38227c478bd9Sstevel@tonic-gate 		lba = SCSA2USB_LBA_10BYTE(pkt);
38237c478bd9Sstevel@tonic-gate 		len = SCSA2USB_LEN_10BYTE(pkt);
38247c478bd9Sstevel@tonic-gate 		dir = USB_EP_DIR_OUT;
382510b633f4SJoshua M. Clulow 		if (len > 0) {
382610b633f4SJoshua M. Clulow 			sz = SCSA2USB_CDRW_BLKSZ(bp != NULL ?
382710b633f4SJoshua M. Clulow 			    bp->b_bcount : 0, len);
38287c478bd9Sstevel@tonic-gate 			if (SCSA2USB_VALID_CDRW_BLKSZ(sz)) {
38297c478bd9Sstevel@tonic-gate 				blk_size = sz;	/* change it accordingly */
38307c478bd9Sstevel@tonic-gate 			}
38317c478bd9Sstevel@tonic-gate 		}
38327c478bd9Sstevel@tonic-gate 		break;
38337c478bd9Sstevel@tonic-gate 	case SCMD_READ_CD:
38347c478bd9Sstevel@tonic-gate 		lba = SCSA2USB_LBA_10BYTE(pkt);
38357c478bd9Sstevel@tonic-gate 		len = SCSA2USB_LEN_READ_CD(pkt);
38367c478bd9Sstevel@tonic-gate 		dir = USB_EP_DIR_IN;
38377c478bd9Sstevel@tonic-gate 
38387c478bd9Sstevel@tonic-gate 		/* Figure out the block size */
38397c478bd9Sstevel@tonic-gate 		blk_size = scsa2usb_read_cd_blk_size(pkt->pkt_cdbp[1] >> 2);
38407c478bd9Sstevel@tonic-gate 		break;
384110b633f4SJoshua M. Clulow 	case SCMD_READ_G4:
384210b633f4SJoshua M. Clulow 		lba = SCSA2USB_LBA_16BYTE(pkt);
384310b633f4SJoshua M. Clulow 		len = SCSA2USB_LEN_16BYTE(pkt);
384410b633f4SJoshua M. Clulow 		dir = USB_EP_DIR_IN;
384510b633f4SJoshua M. Clulow 		break;
384610b633f4SJoshua M. Clulow 	case SCMD_WRITE_G4:
384710b633f4SJoshua M. Clulow 		lba = SCSA2USB_LBA_16BYTE(pkt);
384810b633f4SJoshua M. Clulow 		len = SCSA2USB_LEN_16BYTE(pkt);
384910b633f4SJoshua M. Clulow 		dir = USB_EP_DIR_OUT;
385010b633f4SJoshua M. Clulow 		break;
38517c478bd9Sstevel@tonic-gate 	case SCMD_READ_G5:
38527c478bd9Sstevel@tonic-gate 		lba = SCSA2USB_LBA_12BYTE(pkt);
38537c478bd9Sstevel@tonic-gate 		len = SCSA2USB_LEN_12BYTE(pkt);
38547c478bd9Sstevel@tonic-gate 		dir = USB_EP_DIR_IN;
38557c478bd9Sstevel@tonic-gate 		break;
38567c478bd9Sstevel@tonic-gate 	case SCMD_WRITE_G5:
38577c478bd9Sstevel@tonic-gate 		lba = SCSA2USB_LBA_12BYTE(pkt);
38587c478bd9Sstevel@tonic-gate 		len = SCSA2USB_LEN_12BYTE(pkt);
38597c478bd9Sstevel@tonic-gate 		dir = USB_EP_DIR_OUT;
38607c478bd9Sstevel@tonic-gate 		break;
38617c478bd9Sstevel@tonic-gate 	}
38627c478bd9Sstevel@tonic-gate 
38637c478bd9Sstevel@tonic-gate 	cmd->cmd_total_xfercount = xfer_count = len * blk_size;
38647c478bd9Sstevel@tonic-gate 
38657c478bd9Sstevel@tonic-gate 	/* reduce xfer count if necessary */
386610b633f4SJoshua M. Clulow 	if (blk_size != 0 &&
386710b633f4SJoshua M. Clulow 	    xfer_count > scsa2usbp->scsa2usb_max_bulk_xfer_size) {
38687c478bd9Sstevel@tonic-gate 		/*
38697c478bd9Sstevel@tonic-gate 		 * For CD-RW devices reduce the xfer count based
38707c478bd9Sstevel@tonic-gate 		 * on the block size used by these devices. The
38717c478bd9Sstevel@tonic-gate 		 * block size could change for READ_CD and WRITE
38727c478bd9Sstevel@tonic-gate 		 * opcodes.
38737c478bd9Sstevel@tonic-gate 		 *
38747c478bd9Sstevel@tonic-gate 		 * Also as UHCI allows a max xfer of 32k at a time;
38757c478bd9Sstevel@tonic-gate 		 * compute the xfer_count based on the new block_size.
38767c478bd9Sstevel@tonic-gate 		 *
38777c478bd9Sstevel@tonic-gate 		 * The len part of the cdb changes as a result of that.
38787c478bd9Sstevel@tonic-gate 		 */
38797c478bd9Sstevel@tonic-gate 		if (SCSA2USB_VALID_CDRW_BLKSZ(blk_size)) {
388010b633f4SJoshua M. Clulow 			xfer_count = (scsa2usbp->scsa2usb_max_bulk_xfer_size /
388110b633f4SJoshua M. Clulow 			    blk_size) * blk_size;
388210b633f4SJoshua M. Clulow 			len = xfer_count / blk_size;
38837c478bd9Sstevel@tonic-gate 			xfer_count = blk_size * len;
38847c478bd9Sstevel@tonic-gate 		} else {
38857c478bd9Sstevel@tonic-gate 			xfer_count = scsa2usbp->scsa2usb_max_bulk_xfer_size;
388610b633f4SJoshua M. Clulow 			len = xfer_count / blk_size;
38877c478bd9Sstevel@tonic-gate 		}
38887c478bd9Sstevel@tonic-gate 	}
38897c478bd9Sstevel@tonic-gate 
38907c478bd9Sstevel@tonic-gate 	cmd->cmd_xfercount = xfer_count;
38917c478bd9Sstevel@tonic-gate 	cmd->cmd_dir = (uchar_t)dir;
3892d29f5a71Szhigang lu - Sun Microsystems - Beijing China 	cmd->cmd_blksize = (int)blk_size;
38937c478bd9Sstevel@tonic-gate 
38947c478bd9Sstevel@tonic-gate 	/*
389548bbca81SDaniel Hoffman 	 * Having figured out the 'partial' xfer len based on the
38967c478bd9Sstevel@tonic-gate 	 * block size; fill it in to the cmd->cmd_cdb
38977c478bd9Sstevel@tonic-gate 	 */
38987c478bd9Sstevel@tonic-gate 	cmd->cmd_cdb[SCSA2USB_OPCODE] = (uchar_t)opcode;
38997c478bd9Sstevel@tonic-gate 	switch (opcode) {
39007c478bd9Sstevel@tonic-gate 	case SCMD_READ_CD:
39017c478bd9Sstevel@tonic-gate 		bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
39027c478bd9Sstevel@tonic-gate 		scsa2usb_fill_up_ReadCD_cdb_len(cmd, len, CDB_GROUP5);
390310b633f4SJoshua M. Clulow 		scsa2usb_fill_up_cdb_lba(cmd, lba);
390410b633f4SJoshua M. Clulow 		break;
390510b633f4SJoshua M. Clulow 	case SCMD_WRITE_G4:
390610b633f4SJoshua M. Clulow 	case SCMD_READ_G4:
390710b633f4SJoshua M. Clulow 		scsa2usb_fill_up_16byte_cdb_len(cmd, len, CDB_GROUP4);
390810b633f4SJoshua M. Clulow 		scsa2usb_fill_up_g4_cdb_lba(cmd, lba);
39097c478bd9Sstevel@tonic-gate 		break;
39107c478bd9Sstevel@tonic-gate 	case SCMD_WRITE_G5:
39117c478bd9Sstevel@tonic-gate 	case SCMD_READ_G5:
39127c478bd9Sstevel@tonic-gate 		scsa2usb_fill_up_12byte_cdb_len(cmd, len, CDB_GROUP5);
391310b633f4SJoshua M. Clulow 		scsa2usb_fill_up_cdb_lba(cmd, lba);
39147c478bd9Sstevel@tonic-gate 		break;
39157c478bd9Sstevel@tonic-gate 	default:
39167c478bd9Sstevel@tonic-gate 		scsa2usb_fill_up_cdb_len(cmd, len);
39177c478bd9Sstevel@tonic-gate 		cmd->cmd_actual_len = CDB_GROUP1;
391810b633f4SJoshua M. Clulow 		scsa2usb_fill_up_cdb_lba(cmd, lba);
39197c478bd9Sstevel@tonic-gate 		break;
39207c478bd9Sstevel@tonic-gate 	}
39217c478bd9Sstevel@tonic-gate 
39227c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
39237c478bd9Sstevel@tonic-gate 	    "bcount=0x%lx lba=0x%x len=0x%lx xfercount=0x%lx total=0x%lx",
39247c478bd9Sstevel@tonic-gate 	    bp ? bp->b_bcount : 0, lba, len, cmd->cmd_xfercount,
39257c478bd9Sstevel@tonic-gate 	    cmd->cmd_total_xfercount);
39267c478bd9Sstevel@tonic-gate 
39277c478bd9Sstevel@tonic-gate 	/* Set the timeout value as per command request */
39287c478bd9Sstevel@tonic-gate 	if ((opcode == SCMD_WRITE_G1) && SCSA2USB_VALID_CDRW_BLKSZ(blk_size)) {
39297c478bd9Sstevel@tonic-gate 		/*
39307c478bd9Sstevel@tonic-gate 		 * We increase the time as CD-RW writes have two things
39317c478bd9Sstevel@tonic-gate 		 * to do. After writing out the data to the media, a
39327c478bd9Sstevel@tonic-gate 		 * TOC needs to be filled up at the beginning of the media
39337c478bd9Sstevel@tonic-gate 		 * This is when the write gets "finalized".
39347c478bd9Sstevel@tonic-gate 		 * Hence the actual write could take longer than the
39357c478bd9Sstevel@tonic-gate 		 * value specified in cmd->cmd_timeout.
39367c478bd9Sstevel@tonic-gate 		 */
39377c478bd9Sstevel@tonic-gate 		cmd->cmd_timeout *= 4;
39387c478bd9Sstevel@tonic-gate 
39397c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(DPRINT_MASK_SCSA,
39407c478bd9Sstevel@tonic-gate 		    scsa2usbp->scsa2usb_log_handle,
39417c478bd9Sstevel@tonic-gate 		    "new timeout value = 0x%x", cmd->cmd_timeout);
39427c478bd9Sstevel@tonic-gate 	}
39437c478bd9Sstevel@tonic-gate 
39447c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
39457c478bd9Sstevel@tonic-gate 	    "lba 0x%x len 0x%lx xfercount 0x%lx total 0x%lx",
39467c478bd9Sstevel@tonic-gate 	    lba, len, cmd->cmd_xfercount, cmd->cmd_total_xfercount);
39477c478bd9Sstevel@tonic-gate 
39487c478bd9Sstevel@tonic-gate 	return (SCSA2USB_TRANSPORT);
39497c478bd9Sstevel@tonic-gate }
39507c478bd9Sstevel@tonic-gate 
39517c478bd9Sstevel@tonic-gate 
39527c478bd9Sstevel@tonic-gate /*
39537c478bd9Sstevel@tonic-gate  * scsa2usb_setup_next_xfer:
39547c478bd9Sstevel@tonic-gate  *	For READs and WRITEs we split up the transfer in terms of
39557c478bd9Sstevel@tonic-gate  *	HCD understood units. This function handles the split transfers.
39567c478bd9Sstevel@tonic-gate  *
39577c478bd9Sstevel@tonic-gate  * See comments in the previous function scsa2usb_rw_transport
39587c478bd9Sstevel@tonic-gate  *
39597c478bd9Sstevel@tonic-gate  * The lba computation was being done based on scsa2usb_max_bulk_xfer_size
39607c478bd9Sstevel@tonic-gate  * earlier. With CD-RW devices, the xfer_count and the block_size may
39617c478bd9Sstevel@tonic-gate  * no longer be a multiple of scsa2usb_max_bulk_xfer_size. So compute
39627c478bd9Sstevel@tonic-gate  * xfer_count all over again. Adjust lba, based on the previous requests'
39637c478bd9Sstevel@tonic-gate  * len. Find out the len and add it to cmd->cmd_lba to get the new lba
39647c478bd9Sstevel@tonic-gate  */
39657c478bd9Sstevel@tonic-gate void
scsa2usb_setup_next_xfer(scsa2usb_state_t * scsa2usbp,scsa2usb_cmd_t * cmd)39667c478bd9Sstevel@tonic-gate scsa2usb_setup_next_xfer(scsa2usb_state_t *scsa2usbp, scsa2usb_cmd_t *cmd)
39677c478bd9Sstevel@tonic-gate {
39687c478bd9Sstevel@tonic-gate 	int xfer_len = min(scsa2usbp->scsa2usb_max_bulk_xfer_size,
3969d94492edSfb 	    cmd->cmd_total_xfercount);
39707c478bd9Sstevel@tonic-gate 	int cdb_len;
39717c478bd9Sstevel@tonic-gate 	size_t blk_size;
39727c478bd9Sstevel@tonic-gate 
39737c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
39747c478bd9Sstevel@tonic-gate 
39757c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
39767c478bd9Sstevel@tonic-gate 	    "scsa2usb_setup_next_xfer: opcode = 0x%x lba = 0x%x "
39777c478bd9Sstevel@tonic-gate 	    "total count = 0x%lx", cmd->cmd_cdb[SCSA2USB_OPCODE],
39787c478bd9Sstevel@tonic-gate 	    cmd->cmd_lba, cmd->cmd_total_xfercount);
39797c478bd9Sstevel@tonic-gate 
39807c478bd9Sstevel@tonic-gate 	ASSERT(cmd->cmd_total_xfercount > 0);
39817c478bd9Sstevel@tonic-gate 	cmd->cmd_xfercount = xfer_len;
39827c478bd9Sstevel@tonic-gate 	blk_size = scsa2usbp->scsa2usb_lbasize[
3983d94492edSfb 	    cmd->cmd_pkt->pkt_address.a_lun];
39847c478bd9Sstevel@tonic-gate 
39857c478bd9Sstevel@tonic-gate 	/*
39867c478bd9Sstevel@tonic-gate 	 * For CD-RW devices reduce the xfer count based on the
39877c478bd9Sstevel@tonic-gate 	 * block_size used by these devices. See changes below
39887c478bd9Sstevel@tonic-gate 	 * where xfer_count is being adjusted.
39897c478bd9Sstevel@tonic-gate 	 *
39907c478bd9Sstevel@tonic-gate 	 * Also adjust len/lba based on the block_size and xfer_count.
39917c478bd9Sstevel@tonic-gate 	 * NOTE: Always calculate lba first, as it based on previous
39927c478bd9Sstevel@tonic-gate 	 * commands' values.
39937c478bd9Sstevel@tonic-gate 	 */
39947c478bd9Sstevel@tonic-gate 	switch (cmd->cmd_cdb[SCSA2USB_OPCODE]) {
39957c478bd9Sstevel@tonic-gate 	case SCMD_READ_CD:
39967c478bd9Sstevel@tonic-gate 		/* calculate lba = current_lba + len_of_prev_cmd */
39977c478bd9Sstevel@tonic-gate 		cmd->cmd_lba += (cmd->cmd_cdb[6] << 16) +
39987c478bd9Sstevel@tonic-gate 		    (cmd->cmd_cdb[7] << 8) + cmd->cmd_cdb[8];
399910b633f4SJoshua M. Clulow 		cdb_len = xfer_len / cmd->cmd_blksize;
40007c478bd9Sstevel@tonic-gate 		cmd->cmd_cdb[SCSA2USB_READ_CD_LEN_2] = (uchar_t)cdb_len;
40017c478bd9Sstevel@tonic-gate 		/* re-adjust xfer count */
40027c478bd9Sstevel@tonic-gate 		cmd->cmd_xfercount = cdb_len * cmd->cmd_blksize;
400310b633f4SJoshua M. Clulow 		scsa2usb_fill_up_cdb_lba(cmd, cmd->cmd_lba);
400410b633f4SJoshua M. Clulow 		break;
400510b633f4SJoshua M. Clulow 	case SCMD_WRITE_G4:
400610b633f4SJoshua M. Clulow 	case SCMD_READ_G4:
400710b633f4SJoshua M. Clulow 		/* calculate lba = current_lba + len_of_prev_cmd */
400810b633f4SJoshua M. Clulow 		cmd->cmd_lba += (cmd->cmd_cdb[10] << 24) +
400910b633f4SJoshua M. Clulow 		    (cmd->cmd_cdb[11] << 16) + (cmd->cmd_cdb[12] << 8) +
401010b633f4SJoshua M. Clulow 		    cmd->cmd_cdb[13];
401110b633f4SJoshua M. Clulow 		if (blk_size != 0) {
401210b633f4SJoshua M. Clulow 			xfer_len /= blk_size;
401310b633f4SJoshua M. Clulow 		}
401410b633f4SJoshua M. Clulow 		scsa2usb_fill_up_16byte_cdb_len(cmd, xfer_len, CDB_GROUP5);
401510b633f4SJoshua M. Clulow 		scsa2usb_fill_up_g4_cdb_lba(cmd, cmd->cmd_lba);
40167c478bd9Sstevel@tonic-gate 		break;
40177c478bd9Sstevel@tonic-gate 	case SCMD_WRITE_G5:
40187c478bd9Sstevel@tonic-gate 	case SCMD_READ_G5:
40197c478bd9Sstevel@tonic-gate 		/* calculate lba = current_lba + len_of_prev_cmd */
40207c478bd9Sstevel@tonic-gate 		cmd->cmd_lba += (cmd->cmd_cdb[6] << 24) +
40217c478bd9Sstevel@tonic-gate 		    (cmd->cmd_cdb[7] << 16) + (cmd->cmd_cdb[8] << 8) +
40227c478bd9Sstevel@tonic-gate 		    cmd->cmd_cdb[9];
402310b633f4SJoshua M. Clulow 		if (blk_size != 0) {
40247c478bd9Sstevel@tonic-gate 			xfer_len /= blk_size;
40257c478bd9Sstevel@tonic-gate 		}
40267c478bd9Sstevel@tonic-gate 		scsa2usb_fill_up_12byte_cdb_len(cmd, xfer_len, CDB_GROUP5);
402710b633f4SJoshua M. Clulow 		scsa2usb_fill_up_cdb_lba(cmd, cmd->cmd_lba);
40287c478bd9Sstevel@tonic-gate 		break;
40297c478bd9Sstevel@tonic-gate 	case SCMD_WRITE_G1:
40307c478bd9Sstevel@tonic-gate 	case SCMD_WRITE_LONG:
40317c478bd9Sstevel@tonic-gate 		/* calculate lba = current_lba + len_of_prev_cmd */
40327c478bd9Sstevel@tonic-gate 		cmd->cmd_lba += (cmd->cmd_cdb[7] << 8) + cmd->cmd_cdb[8];
40337c478bd9Sstevel@tonic-gate 		if (SCSA2USB_VALID_CDRW_BLKSZ(cmd->cmd_blksize)) {
40347c478bd9Sstevel@tonic-gate 			blk_size = cmd->cmd_blksize;
40357c478bd9Sstevel@tonic-gate 		}
403610b633f4SJoshua M. Clulow 		cdb_len = xfer_len / blk_size;
40377c478bd9Sstevel@tonic-gate 		scsa2usb_fill_up_cdb_len(cmd, cdb_len);
40387c478bd9Sstevel@tonic-gate 		/* re-adjust xfer count */
40397c478bd9Sstevel@tonic-gate 		cmd->cmd_xfercount = cdb_len * blk_size;
404010b633f4SJoshua M. Clulow 		scsa2usb_fill_up_cdb_lba(cmd, cmd->cmd_lba);
40417c478bd9Sstevel@tonic-gate 		break;
40427c478bd9Sstevel@tonic-gate 	default:
404310b633f4SJoshua M. Clulow 		if (blk_size != 0) {
40447c478bd9Sstevel@tonic-gate 			xfer_len /= blk_size;
40457c478bd9Sstevel@tonic-gate 		}
40467c478bd9Sstevel@tonic-gate 		scsa2usb_fill_up_cdb_len(cmd, xfer_len);
404710b633f4SJoshua M. Clulow 		cmd->cmd_lba += scsa2usbp->scsa2usb_max_bulk_xfer_size /
404810b633f4SJoshua M. Clulow 		    blk_size;
404910b633f4SJoshua M. Clulow 		scsa2usb_fill_up_cdb_lba(cmd, cmd->cmd_lba);
405010b633f4SJoshua M. Clulow 		break;
40517c478bd9Sstevel@tonic-gate 	}
40527c478bd9Sstevel@tonic-gate 
40537c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
40547c478bd9Sstevel@tonic-gate 	    "scsa2usb_setup_next_xfer:\n\tlba = 0x%x xfer_len = 0x%x "
40557c478bd9Sstevel@tonic-gate 	    "xfercount = 0x%lx total = 0x%lx", cmd->cmd_lba, xfer_len,
40567c478bd9Sstevel@tonic-gate 	    cmd->cmd_xfercount, cmd->cmd_total_xfercount);
40577c478bd9Sstevel@tonic-gate }
40587c478bd9Sstevel@tonic-gate 
40597c478bd9Sstevel@tonic-gate 
40607c478bd9Sstevel@tonic-gate /*
40617c478bd9Sstevel@tonic-gate  * take one request from the lun's waitQ and transport it
40627c478bd9Sstevel@tonic-gate  */
40637c478bd9Sstevel@tonic-gate static void
scsa2usb_transport_request(scsa2usb_state_t * scsa2usbp,uint_t lun)40647c478bd9Sstevel@tonic-gate scsa2usb_transport_request(scsa2usb_state_t *scsa2usbp, uint_t lun)
40657c478bd9Sstevel@tonic-gate {
40667c478bd9Sstevel@tonic-gate 	int			rval;
40677c478bd9Sstevel@tonic-gate 	struct scsi_pkt		*pkt;
40687c478bd9Sstevel@tonic-gate 	struct scsa2usb_cmd	*cmd, *arqcmd;
40697c478bd9Sstevel@tonic-gate 
40707c478bd9Sstevel@tonic-gate 	if ((cmd = (scsa2usb_cmd_t *)
40717c478bd9Sstevel@tonic-gate 	    usba_rm_first_pvt_from_list(
40727c478bd9Sstevel@tonic-gate 	    &scsa2usbp->scsa2usb_waitQ[lun])) == NULL) {
40737c478bd9Sstevel@tonic-gate 
40747c478bd9Sstevel@tonic-gate 		return;
40757c478bd9Sstevel@tonic-gate 	}
40767c478bd9Sstevel@tonic-gate 	pkt = cmd->cmd_pkt;
40777c478bd9Sstevel@tonic-gate 
40787c478bd9Sstevel@tonic-gate 	/*
40797c478bd9Sstevel@tonic-gate 	 * if device has been disconnected, just complete it
40807c478bd9Sstevel@tonic-gate 	 */
40817c478bd9Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_dev_state == USB_DEV_DISCONNECTED) {
40827c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
40837c478bd9Sstevel@tonic-gate 		    "device not accessible");
40847c478bd9Sstevel@tonic-gate 		pkt->pkt_reason = CMD_DEV_GONE;
40857c478bd9Sstevel@tonic-gate 		SCSA2USB_SET_PKT_DO_COMP_STATE(scsa2usbp);
40867c478bd9Sstevel@tonic-gate 		scsa2usb_pkt_completion(scsa2usbp, pkt);
40877c478bd9Sstevel@tonic-gate 
40887c478bd9Sstevel@tonic-gate 		return;
40897c478bd9Sstevel@tonic-gate 	}
40907c478bd9Sstevel@tonic-gate 
40917c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA,
40927c478bd9Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_log_handle,
40937c478bd9Sstevel@tonic-gate 	    "scsa2usb_transport_request: cmd=0x%p bp=0x%p addr=0x%p",
4094112116d8Sfb 	    (void *)cmd, (void *)cmd->cmd_bp,
4095112116d8Sfb 	    (void *)(cmd->cmd_bp ? cmd->cmd_bp->b_un.b_addr : NULL));
40967c478bd9Sstevel@tonic-gate 
40977c478bd9Sstevel@tonic-gate 	rval = scsa2usb_cmd_transport(scsa2usbp, cmd);
40987c478bd9Sstevel@tonic-gate 
40997c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_SCSA,
41007c478bd9Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_log_handle,
41017c478bd9Sstevel@tonic-gate 	    "scsa2usb_transport_request: transport rval = %d",
41027c478bd9Sstevel@tonic-gate 	    rval);
41037c478bd9Sstevel@tonic-gate 
41047c478bd9Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_cur_pkt == NULL) {
41057c478bd9Sstevel@tonic-gate 
41067c478bd9Sstevel@tonic-gate 		return;
41077c478bd9Sstevel@tonic-gate 	}
41087c478bd9Sstevel@tonic-gate 
41097c478bd9Sstevel@tonic-gate 	ASSERT(pkt == scsa2usbp->scsa2usb_cur_pkt);
41107c478bd9Sstevel@tonic-gate 
41117c478bd9Sstevel@tonic-gate 	if (ddi_in_panic()) {
41127c478bd9Sstevel@tonic-gate 		pkt->pkt_reason = CMD_CMPLT;
41137c478bd9Sstevel@tonic-gate 		scsa2usb_pkt_completion(scsa2usbp, pkt);
41147c478bd9Sstevel@tonic-gate 
41157c478bd9Sstevel@tonic-gate 		return;
41167c478bd9Sstevel@tonic-gate 	}
41177c478bd9Sstevel@tonic-gate 
41187c478bd9Sstevel@tonic-gate 	/*
41197c478bd9Sstevel@tonic-gate 	 * start an auto-request sense iff
41207c478bd9Sstevel@tonic-gate 	 * there was a check condition, we have enough
41217c478bd9Sstevel@tonic-gate 	 * space in the status block, and we have not
41227c478bd9Sstevel@tonic-gate 	 * faked an auto request sense
41237c478bd9Sstevel@tonic-gate 	 */
41247c478bd9Sstevel@tonic-gate 	if ((*(pkt->pkt_scbp) == STATUS_CHECK) &&
41257c478bd9Sstevel@tonic-gate 	    (cmd->cmd_scblen >= sizeof (struct scsi_arq_status)) &&
41267c478bd9Sstevel@tonic-gate 	    ((pkt->pkt_state & STATE_ARQ_DONE) == 0) &&
41277c478bd9Sstevel@tonic-gate 	    (scsa2usb_create_arq_pkt(scsa2usbp,
41287c478bd9Sstevel@tonic-gate 	    &pkt->pkt_address) == USB_SUCCESS)) {
41297c478bd9Sstevel@tonic-gate 		arqcmd = scsa2usbp->scsa2usb_arq_cmd;
41307c478bd9Sstevel@tonic-gate 
41317c478bd9Sstevel@tonic-gate 		/*
41327c478bd9Sstevel@tonic-gate 		 * copy the timeout from the
41337c478bd9Sstevel@tonic-gate 		 * original packet
41347c478bd9Sstevel@tonic-gate 		 * for lack of a better value
41357c478bd9Sstevel@tonic-gate 		 */
41367c478bd9Sstevel@tonic-gate 		arqcmd->cmd_pkt->pkt_time = pkt->pkt_time;
41377c478bd9Sstevel@tonic-gate 		scsa2usb_prepare_pkt(scsa2usbp,
4138d94492edSfb 		    arqcmd->cmd_pkt);
41397c478bd9Sstevel@tonic-gate 
41407c478bd9Sstevel@tonic-gate 		scsa2usbp->scsa2usb_cur_pkt = NULL;
41417c478bd9Sstevel@tonic-gate 		if (scsa2usb_cmd_transport(
41427c478bd9Sstevel@tonic-gate 		    scsa2usbp, arqcmd) == TRAN_ACCEPT) {
41437c478bd9Sstevel@tonic-gate 
41447c478bd9Sstevel@tonic-gate 			/* finish w/ this packet */
41457c478bd9Sstevel@tonic-gate 			scsa2usb_complete_arq_pkt(
41467c478bd9Sstevel@tonic-gate 			    scsa2usbp, arqcmd->cmd_pkt, cmd,
41477c478bd9Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_arq_bp);
41487c478bd9Sstevel@tonic-gate 
41497c478bd9Sstevel@tonic-gate 			/*
41507c478bd9Sstevel@tonic-gate 			 * we have valid request sense
41517c478bd9Sstevel@tonic-gate 			 * data so clear the pkt_reason
41527c478bd9Sstevel@tonic-gate 			 */
41537c478bd9Sstevel@tonic-gate 			pkt->pkt_reason = CMD_CMPLT;
41547c478bd9Sstevel@tonic-gate 		}
41557c478bd9Sstevel@tonic-gate 		scsa2usbp->scsa2usb_cur_pkt = pkt;
41567c478bd9Sstevel@tonic-gate 		scsa2usb_delete_arq_pkt(scsa2usbp);
41577c478bd9Sstevel@tonic-gate 	}
41587c478bd9Sstevel@tonic-gate 
41597c478bd9Sstevel@tonic-gate 	if ((rval != TRAN_ACCEPT) &&
41607c478bd9Sstevel@tonic-gate 	    (pkt->pkt_reason == CMD_CMPLT)) {
41617c478bd9Sstevel@tonic-gate 		pkt->pkt_reason = CMD_TRAN_ERR;
41627c478bd9Sstevel@tonic-gate 	}
41637c478bd9Sstevel@tonic-gate 
41647c478bd9Sstevel@tonic-gate 	SCSA2USB_SET_PKT_DO_COMP_STATE(scsa2usbp);
41657c478bd9Sstevel@tonic-gate 	scsa2usb_pkt_completion(scsa2usbp, pkt);
41667c478bd9Sstevel@tonic-gate 
41677c478bd9Sstevel@tonic-gate 	ASSERT(scsa2usbp->scsa2usb_cur_pkt == NULL);
41687c478bd9Sstevel@tonic-gate }
41697c478bd9Sstevel@tonic-gate 
41707c478bd9Sstevel@tonic-gate 
41717c478bd9Sstevel@tonic-gate /*
41727c478bd9Sstevel@tonic-gate  * scsa2usb_work_thread:
41737c478bd9Sstevel@tonic-gate  *	The taskq thread that kicks off the transport (BO and CB/CBI)
41747c478bd9Sstevel@tonic-gate  */
41757c478bd9Sstevel@tonic-gate static void
scsa2usb_work_thread(void * arg)41767c478bd9Sstevel@tonic-gate scsa2usb_work_thread(void *arg)
41777c478bd9Sstevel@tonic-gate {
41787c478bd9Sstevel@tonic-gate 	scsa2usb_state_t	*scsa2usbp = (scsa2usb_state_t *)arg;
41797c478bd9Sstevel@tonic-gate 	uint_t			lun;
41807c478bd9Sstevel@tonic-gate 	uint_t			count;
41817c478bd9Sstevel@tonic-gate 
4182496d8c83Sfrits 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
41837c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
4184112116d8Sfb 	    "scsa2usb_work_thread start: thread_id=0x%p",
4185112116d8Sfb 	    (void *)scsa2usbp->scsa2usb_work_thread_id);
41867c478bd9Sstevel@tonic-gate 
41877c478bd9Sstevel@tonic-gate 	ASSERT(scsa2usbp->scsa2usb_work_thread_id == (kthread_t *)1);
41887c478bd9Sstevel@tonic-gate 	scsa2usbp->scsa2usb_work_thread_id = curthread;
41897c478bd9Sstevel@tonic-gate 
41907c478bd9Sstevel@tonic-gate 	/* exclude ugen accesses */
41917c478bd9Sstevel@tonic-gate 	while (scsa2usbp->scsa2usb_transport_busy) {
41927c478bd9Sstevel@tonic-gate 		cv_wait(&scsa2usbp->scsa2usb_transport_busy_cv,
41937c478bd9Sstevel@tonic-gate 		    &scsa2usbp->scsa2usb_mutex);
41947c478bd9Sstevel@tonic-gate 	}
41957c478bd9Sstevel@tonic-gate 	ASSERT(scsa2usbp->scsa2usb_ugen_open_count == 0);
41967c478bd9Sstevel@tonic-gate 	scsa2usbp->scsa2usb_transport_busy++;
419742cac157SVincent Wang 	scsa2usbp->scsa2usb_busy_proc = curproc;
41987c478bd9Sstevel@tonic-gate 
41997c478bd9Sstevel@tonic-gate 	scsa2usb_raise_power(scsa2usbp);
42007c478bd9Sstevel@tonic-gate 
42017c478bd9Sstevel@tonic-gate 	/* reopen the pipes if necessary */
42027c478bd9Sstevel@tonic-gate 	(void) scsa2usb_open_usb_pipes(scsa2usbp);
42037c478bd9Sstevel@tonic-gate 
42047c478bd9Sstevel@tonic-gate 	for (;;) {
42057c478bd9Sstevel@tonic-gate 		ASSERT(scsa2usbp->scsa2usb_ugen_open_count == 0);
42067c478bd9Sstevel@tonic-gate 		for (lun = 0; lun < scsa2usbp->scsa2usb_n_luns; lun++) {
42077c478bd9Sstevel@tonic-gate 			scsa2usb_transport_request(scsa2usbp, lun);
42087c478bd9Sstevel@tonic-gate 		}
42097c478bd9Sstevel@tonic-gate 		count = 0;
42107c478bd9Sstevel@tonic-gate 		for (lun = 0; lun < SCSA2USB_MAX_LUNS; lun++) {
42117c478bd9Sstevel@tonic-gate 			count += usba_list_entry_count(
4212d94492edSfb 			    &scsa2usbp->scsa2usb_waitQ[lun]);
42137c478bd9Sstevel@tonic-gate 		}
42147c478bd9Sstevel@tonic-gate 
42157c478bd9Sstevel@tonic-gate 		if (count == 0) {
42167c478bd9Sstevel@tonic-gate 
42177c478bd9Sstevel@tonic-gate 			break;
42187c478bd9Sstevel@tonic-gate 		}
42197c478bd9Sstevel@tonic-gate 	}
42207c478bd9Sstevel@tonic-gate 
42217c478bd9Sstevel@tonic-gate 	scsa2usbp->scsa2usb_work_thread_id = 0;
42227c478bd9Sstevel@tonic-gate 
42237c478bd9Sstevel@tonic-gate 	ASSERT(scsa2usbp->scsa2usb_ugen_open_count == 0);
42247c478bd9Sstevel@tonic-gate 
42257c478bd9Sstevel@tonic-gate 	scsa2usbp->scsa2usb_transport_busy--;
422642cac157SVincent Wang 	scsa2usbp->scsa2usb_busy_proc = NULL;
42277c478bd9Sstevel@tonic-gate 	cv_signal(&scsa2usbp->scsa2usb_transport_busy_cv);
42287c478bd9Sstevel@tonic-gate 
42297c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
42307c478bd9Sstevel@tonic-gate 	    "scsa2usb_work_thread: exit");
4231496d8c83Sfrits 
4232496d8c83Sfrits 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
4233496d8c83Sfrits 
4234496d8c83Sfrits 	scsa2usb_pm_idle_component(scsa2usbp);
42357c478bd9Sstevel@tonic-gate }
42367c478bd9Sstevel@tonic-gate 
42377c478bd9Sstevel@tonic-gate 
42387c478bd9Sstevel@tonic-gate /*
42397c478bd9Sstevel@tonic-gate  * scsa2usb_flush_waitQ:
42407c478bd9Sstevel@tonic-gate  *	empties the entire waitQ with errors asap.
42417c478bd9Sstevel@tonic-gate  *
42427c478bd9Sstevel@tonic-gate  * It is called from scsa2usb_scsi_reset and scsa2usb_panic_callb.
42437c478bd9Sstevel@tonic-gate  * If the device is reset; we should empty the waitQ right away.
42447c478bd9Sstevel@tonic-gate  * If the system has paniced; we should empty the waitQ right away.
42457c478bd9Sstevel@tonic-gate  *
42467c478bd9Sstevel@tonic-gate  * CPR suspend will only succeed if device is idle. No need to call
42477c478bd9Sstevel@tonic-gate  * this function for CPR suspend case.
42487c478bd9Sstevel@tonic-gate  */
42497c478bd9Sstevel@tonic-gate static void
scsa2usb_flush_waitQ(scsa2usb_state_t * scsa2usbp,uint_t lun,uchar_t error)42507c478bd9Sstevel@tonic-gate scsa2usb_flush_waitQ(scsa2usb_state_t *scsa2usbp, uint_t lun,
42517c478bd9Sstevel@tonic-gate     uchar_t error)
42527c478bd9Sstevel@tonic-gate {
42537c478bd9Sstevel@tonic-gate 	struct scsi_pkt		*pkt;
42547c478bd9Sstevel@tonic-gate 	struct scsa2usb_cmd	*cmd;
42557c478bd9Sstevel@tonic-gate 	usba_list_entry_t	head;
42567c478bd9Sstevel@tonic-gate 
42577c478bd9Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
42587c478bd9Sstevel@tonic-gate 
42597c478bd9Sstevel@tonic-gate 	usba_move_list(&scsa2usbp->scsa2usb_waitQ[lun], &head,
42607c478bd9Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_dev_data->dev_iblock_cookie);
42617c478bd9Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
42627c478bd9Sstevel@tonic-gate 
42637c478bd9Sstevel@tonic-gate 	while ((cmd = (scsa2usb_cmd_t *)usba_rm_first_pvt_from_list(&head)) !=
42647c478bd9Sstevel@tonic-gate 	    NULL) {
42657c478bd9Sstevel@tonic-gate 		pkt = cmd->cmd_pkt;
42667c478bd9Sstevel@tonic-gate 		pkt->pkt_reason = error;	/* set error */
42677c478bd9Sstevel@tonic-gate 
42687c478bd9Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
42697c478bd9Sstevel@tonic-gate 		scsa2usbp->scsa2usb_pkt_state = SCSA2USB_PKT_DO_COMP;
42707c478bd9Sstevel@tonic-gate 		scsa2usb_pkt_completion(scsa2usbp, pkt);
42717c478bd9Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
42727c478bd9Sstevel@tonic-gate 	} /* end of while */
42737c478bd9Sstevel@tonic-gate }
42747c478bd9Sstevel@tonic-gate 
42757c478bd9Sstevel@tonic-gate 
42767c478bd9Sstevel@tonic-gate /*
42777c478bd9Sstevel@tonic-gate  * scsa2usb_do_inquiry is performed before INIT CHILD and we have
42787c478bd9Sstevel@tonic-gate  * to fake a few things normally done by SCSA
42797c478bd9Sstevel@tonic-gate  */
42807c478bd9Sstevel@tonic-gate static void
scsa2usb_do_inquiry(scsa2usb_state_t * scsa2usbp,uint_t target,uint_t lun)42817c478bd9Sstevel@tonic-gate scsa2usb_do_inquiry(scsa2usb_state_t *scsa2usbp, uint_t target, uint_t lun)
42827c478bd9Sstevel@tonic-gate {
42837c478bd9Sstevel@tonic-gate 	struct buf	*bp;
42847c478bd9Sstevel@tonic-gate 	struct scsi_pkt *pkt;
42857c478bd9Sstevel@tonic-gate 	struct scsi_address ap;
42867c478bd9Sstevel@tonic-gate 	int		len = SCSA2USB_MAX_INQ_LEN;
42877c478bd9Sstevel@tonic-gate 
42887c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
42897c478bd9Sstevel@tonic-gate 	    "scsa2usb_do_inquiry: %d bytes", len);
42907c478bd9Sstevel@tonic-gate 
42917c478bd9Sstevel@tonic-gate 	/* is it inquiry-challenged? */
42927c478bd9Sstevel@tonic-gate 	if (!(scsa2usbp->scsa2usb_attrs & SCSA2USB_ATTRS_INQUIRY)) {
42933fbe3e28Svitezslav batrla - Sun Microsystems - Prague Czech Republic 		scsa2usb_fake_inquiry(scsa2usbp,
42943fbe3e28Svitezslav batrla - Sun Microsystems - Prague Czech Republic 		    &scsa2usbp->scsa2usb_lun_inquiry[lun]);
42957c478bd9Sstevel@tonic-gate 		return;
42967c478bd9Sstevel@tonic-gate 	}
42977c478bd9Sstevel@tonic-gate 
42987c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
42997c478bd9Sstevel@tonic-gate 
43007c478bd9Sstevel@tonic-gate 	bzero(&ap, sizeof (struct scsi_address));
43017c478bd9Sstevel@tonic-gate 	ap.a_hba_tran = scsa2usbp->scsa2usb_tran;
4302d29f5a71Szhigang lu - Sun Microsystems - Beijing China 	ap.a_target = (ushort_t)target;
4303d29f5a71Szhigang lu - Sun Microsystems - Beijing China 	ap.a_lun = (uchar_t)lun;
43047c478bd9Sstevel@tonic-gate 
43057c478bd9Sstevel@tonic-gate 	/* limit inquiry to 36 bytes */
43067c478bd9Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
43077c478bd9Sstevel@tonic-gate 	if ((bp = scsi_alloc_consistent_buf(&ap, (struct buf *)NULL,
43087c478bd9Sstevel@tonic-gate 	    len, B_READ, SLEEP_FUNC, NULL)) == NULL) {
43097c478bd9Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
43107c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_SCSA,
43117c478bd9Sstevel@tonic-gate 		    scsa2usbp->scsa2usb_log_handle,
43127c478bd9Sstevel@tonic-gate 		    "scsa2usb_do_inquiry: failed");
43137c478bd9Sstevel@tonic-gate 
43147c478bd9Sstevel@tonic-gate 		return;
43157c478bd9Sstevel@tonic-gate 	}
43167c478bd9Sstevel@tonic-gate 
43177c478bd9Sstevel@tonic-gate 	pkt = scsi_init_pkt(&ap, NULL, bp, CDB_GROUP0, 1,
43187c478bd9Sstevel@tonic-gate 	    PKT_PRIV_LEN, PKT_CONSISTENT, SLEEP_FUNC, NULL);
43197c478bd9Sstevel@tonic-gate 
4320d29f5a71Szhigang lu - Sun Microsystems - Beijing China 	RQ_MAKECOM_G0(pkt, FLAG_NOINTR, (char)SCMD_INQUIRY, 0, (char)len);
43217c478bd9Sstevel@tonic-gate 
43227c478bd9Sstevel@tonic-gate 	pkt->pkt_comp = NULL;
43237c478bd9Sstevel@tonic-gate 	pkt->pkt_time = 5;
43247c478bd9Sstevel@tonic-gate 	bzero(bp->b_un.b_addr, len);
43257c478bd9Sstevel@tonic-gate 
43267c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
43277c478bd9Sstevel@tonic-gate 	    "scsa2usb_do_inquiry:INQUIRY");
43287c478bd9Sstevel@tonic-gate 
43297c478bd9Sstevel@tonic-gate 	(void) scsi_transport(pkt);
43307c478bd9Sstevel@tonic-gate 
43317c478bd9Sstevel@tonic-gate 	if (pkt->pkt_reason) {
4332d291d9f2Sfrits 		USB_DPRINTF_L2(DPRINT_MASK_SCSA,
43337c478bd9Sstevel@tonic-gate 		    scsa2usbp->scsa2usb_log_handle,
43347c478bd9Sstevel@tonic-gate 		    "INQUIRY failed, cannot determine device type, "
43357c478bd9Sstevel@tonic-gate 		    "pkt_reason=0x%x", pkt->pkt_reason);
43367c478bd9Sstevel@tonic-gate 
43377c478bd9Sstevel@tonic-gate 		/* not much hope for other cmds, reduce */
43387c478bd9Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
43397c478bd9Sstevel@tonic-gate 		scsa2usbp->scsa2usb_attrs &=
4340d94492edSfb 		    ~SCSA2USB_ATTRS_REDUCED_CMD;
43413fbe3e28Svitezslav batrla - Sun Microsystems - Prague Czech Republic 		scsa2usb_fake_inquiry(scsa2usbp,
43423fbe3e28Svitezslav batrla - Sun Microsystems - Prague Czech Republic 		    &scsa2usbp->scsa2usb_lun_inquiry[lun]);
43437c478bd9Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
43447c478bd9Sstevel@tonic-gate 	}
43457c478bd9Sstevel@tonic-gate 
43467c478bd9Sstevel@tonic-gate 	scsi_destroy_pkt(pkt);
43477c478bd9Sstevel@tonic-gate 	scsi_free_consistent_buf(bp);
43487c478bd9Sstevel@tonic-gate 
43497c478bd9Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
43507c478bd9Sstevel@tonic-gate }
43517c478bd9Sstevel@tonic-gate 
43527c478bd9Sstevel@tonic-gate 
43537c478bd9Sstevel@tonic-gate /*
43547c478bd9Sstevel@tonic-gate  * scsa2usb_fake_inquiry:
43557c478bd9Sstevel@tonic-gate  *    build an inquiry for a given device that doesnt like inquiry
43567c478bd9Sstevel@tonic-gate  *    commands.
43577c478bd9Sstevel@tonic-gate  */
43583fbe3e28Svitezslav batrla - Sun Microsystems - Prague Czech Republic static void
scsa2usb_fake_inquiry(scsa2usb_state_t * scsa2usbp,struct scsi_inquiry * inqp)43593fbe3e28Svitezslav batrla - Sun Microsystems - Prague Czech Republic scsa2usb_fake_inquiry(scsa2usb_state_t *scsa2usbp, struct scsi_inquiry *inqp)
43607c478bd9Sstevel@tonic-gate {
43617c478bd9Sstevel@tonic-gate 	usb_client_dev_data_t *dev_data = scsa2usbp->scsa2usb_dev_data;
43627c478bd9Sstevel@tonic-gate 	int len;
43637c478bd9Sstevel@tonic-gate 
43647c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
43657c478bd9Sstevel@tonic-gate 	    "scsa2usb_fake_inquiry:");
43667c478bd9Sstevel@tonic-gate 
43677c478bd9Sstevel@tonic-gate 	bzero(inqp, sizeof (struct scsi_inquiry));
43687c478bd9Sstevel@tonic-gate 	for (len = 0; len < sizeof (inqp->inq_vid); len++) {
43697c478bd9Sstevel@tonic-gate 		*(inqp->inq_vid + len) = ' ';
43707c478bd9Sstevel@tonic-gate 	}
43717c478bd9Sstevel@tonic-gate 
43727c478bd9Sstevel@tonic-gate 	for (len = 0; len < sizeof (inqp->inq_pid); len++) {
43737c478bd9Sstevel@tonic-gate 		*(inqp->inq_pid + len) = ' ';
43747c478bd9Sstevel@tonic-gate 	}
43757c478bd9Sstevel@tonic-gate 
43767c478bd9Sstevel@tonic-gate 	inqp->inq_dtype = DTYPE_DIRECT;
43777c478bd9Sstevel@tonic-gate 	inqp->inq_rmb = 1;
43787c478bd9Sstevel@tonic-gate 	inqp->inq_ansi = 2;
43797c478bd9Sstevel@tonic-gate 	inqp->inq_rdf = RDF_SCSI2;
43807c478bd9Sstevel@tonic-gate 	inqp->inq_len = sizeof (struct scsi_inquiry)-4;
43817c478bd9Sstevel@tonic-gate 
43827c478bd9Sstevel@tonic-gate 	/* Fill in the Vendor id/Product id strings */
43837c478bd9Sstevel@tonic-gate 	if (dev_data->dev_mfg) {
43847c478bd9Sstevel@tonic-gate 		if ((len = strlen(dev_data->dev_mfg)) >
43857c478bd9Sstevel@tonic-gate 		    sizeof (inqp->inq_vid)) {
43867c478bd9Sstevel@tonic-gate 			len = sizeof (inqp->inq_vid);
43877c478bd9Sstevel@tonic-gate 		}
43887c478bd9Sstevel@tonic-gate 		bcopy(dev_data->dev_mfg, inqp->inq_vid, len);
43897c478bd9Sstevel@tonic-gate 	}
43907c478bd9Sstevel@tonic-gate 
43917c478bd9Sstevel@tonic-gate 	if (dev_data->dev_product) {
43927c478bd9Sstevel@tonic-gate 		if ((len = strlen(dev_data->dev_product)) >
43937c478bd9Sstevel@tonic-gate 		    sizeof (inqp->inq_pid)) {
43947c478bd9Sstevel@tonic-gate 			len = sizeof (inqp->inq_pid);
43957c478bd9Sstevel@tonic-gate 		}
43967c478bd9Sstevel@tonic-gate 		bcopy(dev_data->dev_product, inqp->inq_pid, len);
43977c478bd9Sstevel@tonic-gate 	}
43987c478bd9Sstevel@tonic-gate 
43997c478bd9Sstevel@tonic-gate 	/* Set the Revision to the Device */
44007c478bd9Sstevel@tonic-gate 	inqp->inq_revision[0] = 0x30 +
4401d94492edSfb 	    ((dev_data->dev_descr->bcdDevice>>12) & 0xF);
44027c478bd9Sstevel@tonic-gate 	inqp->inq_revision[1] = 0x30 +
4403d94492edSfb 	    ((dev_data->dev_descr->bcdDevice>>8) & 0xF);
44047c478bd9Sstevel@tonic-gate 	inqp->inq_revision[2] = 0x30 +
4405d94492edSfb 	    ((dev_data->dev_descr->bcdDevice>>4) & 0xF);
44067c478bd9Sstevel@tonic-gate 	inqp->inq_revision[3] = 0x30 +
4407d94492edSfb 	    ((dev_data->dev_descr->bcdDevice) & 0xF);
44087c478bd9Sstevel@tonic-gate }
44097c478bd9Sstevel@tonic-gate 
44107c478bd9Sstevel@tonic-gate 
44117c478bd9Sstevel@tonic-gate /*
44127c478bd9Sstevel@tonic-gate  * scsa2usb_create_arq_pkt:
44137c478bd9Sstevel@tonic-gate  *	Create and ARQ packet to get request sense data
44147c478bd9Sstevel@tonic-gate  */
44157c478bd9Sstevel@tonic-gate static int
scsa2usb_create_arq_pkt(scsa2usb_state_t * scsa2usbp,struct scsi_address * ap)44167c478bd9Sstevel@tonic-gate scsa2usb_create_arq_pkt(scsa2usb_state_t *scsa2usbp, struct scsi_address *ap)
44177c478bd9Sstevel@tonic-gate {
44187c478bd9Sstevel@tonic-gate 	struct buf *bp;
44197c478bd9Sstevel@tonic-gate 	scsa2usb_cmd_t *arq_cmd;
44207c478bd9Sstevel@tonic-gate 
44217c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
4422112116d8Sfb 	    "scsa2usb_create_arq_pkt: scsa2usbp: %p, ap: %p",
4423112116d8Sfb 	    (void *)scsa2usbp, (void *)ap);
44247c478bd9Sstevel@tonic-gate 
44257c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
44267c478bd9Sstevel@tonic-gate 
44277c478bd9Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
44287c478bd9Sstevel@tonic-gate 	if ((bp = scsi_alloc_consistent_buf(ap, (struct buf *)NULL,
44297c478bd9Sstevel@tonic-gate 	    SENSE_LENGTH, B_READ, SLEEP_FUNC, NULL)) == NULL) {
44307c478bd9Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
44317c478bd9Sstevel@tonic-gate 
44327c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
44337c478bd9Sstevel@tonic-gate 	}
44347c478bd9Sstevel@tonic-gate 
44357c478bd9Sstevel@tonic-gate 	arq_cmd = PKT2CMD(scsi_init_pkt(ap, NULL, bp, CDB_GROUP0, 1,
44367c478bd9Sstevel@tonic-gate 	    PKT_PRIV_LEN, PKT_CONSISTENT, SLEEP_FUNC, NULL));
44377c478bd9Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
44387c478bd9Sstevel@tonic-gate 
44397c478bd9Sstevel@tonic-gate 	RQ_MAKECOM_G0(arq_cmd->cmd_pkt,
44407c478bd9Sstevel@tonic-gate 	    FLAG_SENSING | FLAG_HEAD | FLAG_NODISCON,
44417c478bd9Sstevel@tonic-gate 	    (char)SCMD_REQUEST_SENSE, 0, (char)SENSE_LENGTH);
44427c478bd9Sstevel@tonic-gate 
44437c478bd9Sstevel@tonic-gate 	arq_cmd->cmd_pkt->pkt_ha_private = arq_cmd;
44447c478bd9Sstevel@tonic-gate 	scsa2usbp->scsa2usb_arq_cmd = arq_cmd;
44457c478bd9Sstevel@tonic-gate 	scsa2usbp->scsa2usb_arq_bp = bp;
44467c478bd9Sstevel@tonic-gate 	arq_cmd->cmd_pkt->pkt_comp = NULL;
44477c478bd9Sstevel@tonic-gate 	bzero(bp->b_un.b_addr, SENSE_LENGTH);
44487c478bd9Sstevel@tonic-gate 
44497c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
44507c478bd9Sstevel@tonic-gate }
44517c478bd9Sstevel@tonic-gate 
44527c478bd9Sstevel@tonic-gate 
44537c478bd9Sstevel@tonic-gate /*
44547c478bd9Sstevel@tonic-gate  * scsa2usb_delete_arq_pkt:
44557c478bd9Sstevel@tonic-gate  *	Destroy the ARQ packet
44567c478bd9Sstevel@tonic-gate  */
44577c478bd9Sstevel@tonic-gate static void
scsa2usb_delete_arq_pkt(scsa2usb_state_t * scsa2usbp)44587c478bd9Sstevel@tonic-gate scsa2usb_delete_arq_pkt(scsa2usb_state_t *scsa2usbp)
44597c478bd9Sstevel@tonic-gate {
44607c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
4461112116d8Sfb 	    "scsa2usb_delete_arq_pkt: cmd: 0x%p",
4462112116d8Sfb 	    (void *)scsa2usbp->scsa2usb_arq_cmd);
44637c478bd9Sstevel@tonic-gate 
44647c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
44657c478bd9Sstevel@tonic-gate 
44667c478bd9Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_arq_cmd != NULL) {
44677c478bd9Sstevel@tonic-gate 		scsi_destroy_pkt(scsa2usbp->scsa2usb_arq_cmd->cmd_pkt);
44687c478bd9Sstevel@tonic-gate 		scsi_free_consistent_buf(scsa2usbp->scsa2usb_arq_bp);
44697c478bd9Sstevel@tonic-gate 	}
44707c478bd9Sstevel@tonic-gate 	scsa2usbp->scsa2usb_arq_cmd = NULL;
44717c478bd9Sstevel@tonic-gate 	scsa2usbp->scsa2usb_arq_bp = NULL;
44727c478bd9Sstevel@tonic-gate }
44737c478bd9Sstevel@tonic-gate 
44747c478bd9Sstevel@tonic-gate 
44757c478bd9Sstevel@tonic-gate /*
44767c478bd9Sstevel@tonic-gate  * scsa2usb_complete_arq_pkt:
44777c478bd9Sstevel@tonic-gate  *	finish processing the arq packet
44787c478bd9Sstevel@tonic-gate  */
44797c478bd9Sstevel@tonic-gate static void
scsa2usb_complete_arq_pkt(scsa2usb_state_t * scsa2usbp,struct scsi_pkt * pkt,scsa2usb_cmd_t * ssp,struct buf * bp)44807c478bd9Sstevel@tonic-gate scsa2usb_complete_arq_pkt(scsa2usb_state_t *scsa2usbp,
44817c478bd9Sstevel@tonic-gate     struct scsi_pkt *pkt, scsa2usb_cmd_t *ssp, struct buf *bp)
44827c478bd9Sstevel@tonic-gate {
44837c478bd9Sstevel@tonic-gate 	scsa2usb_cmd_t		*sp = pkt->pkt_ha_private;
44847c478bd9Sstevel@tonic-gate 	struct scsi_arq_status	*arqp;
44857c478bd9Sstevel@tonic-gate 
44867c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
44877c478bd9Sstevel@tonic-gate 
44887c478bd9Sstevel@tonic-gate 	arqp = (struct scsi_arq_status *)(ssp->cmd_pkt->pkt_scbp);
44897c478bd9Sstevel@tonic-gate 	arqp->sts_rqpkt_status = *((struct scsi_status *)
4490d94492edSfb 	    (sp->cmd_pkt->pkt_scbp));
44917c478bd9Sstevel@tonic-gate 	arqp->sts_rqpkt_reason = CMD_CMPLT;
44927c478bd9Sstevel@tonic-gate 	arqp->sts_rqpkt_state |= STATE_XFERRED_DATA;
44937c478bd9Sstevel@tonic-gate 	arqp->sts_rqpkt_statistics = arqp->sts_rqpkt_resid = 0;
44947c478bd9Sstevel@tonic-gate 
44957c478bd9Sstevel@tonic-gate 	/* is this meaningful sense data */
44967c478bd9Sstevel@tonic-gate 	if (*(bp->b_un.b_addr) != 0) {
4497fae6130aSlh 		bcopy(bp->b_un.b_addr, &arqp->sts_sensedata, SENSE_LENGTH);
44987c478bd9Sstevel@tonic-gate 		ssp->cmd_pkt->pkt_state |= STATE_ARQ_DONE;
44997c478bd9Sstevel@tonic-gate 	}
45007c478bd9Sstevel@tonic-gate 
45017c478bd9Sstevel@tonic-gate 	/* we will not sense start cmd until we receive a NOT READY */
45027c478bd9Sstevel@tonic-gate 	if (arqp->sts_sensedata.es_key == KEY_NOT_READY) {
45037c478bd9Sstevel@tonic-gate 		scsa2usbp->scsa2usb_rcvd_not_ready = B_TRUE;
45047c478bd9Sstevel@tonic-gate 	}
45057c478bd9Sstevel@tonic-gate }
45067c478bd9Sstevel@tonic-gate 
45077c478bd9Sstevel@tonic-gate 
45087c478bd9Sstevel@tonic-gate /*
45097c478bd9Sstevel@tonic-gate  * Miscellaneous functions for any command/transport
45107c478bd9Sstevel@tonic-gate  */
45117c478bd9Sstevel@tonic-gate /*
45127c478bd9Sstevel@tonic-gate  * scsa2usb_open_usb_pipes:
45137c478bd9Sstevel@tonic-gate  *	set up a pipe policy
45147c478bd9Sstevel@tonic-gate  *	open usb bulk pipes (BO and CB/CBI)
45157c478bd9Sstevel@tonic-gate  *	open usb interrupt pipe (CBI)
45167c478bd9Sstevel@tonic-gate  */
45177c478bd9Sstevel@tonic-gate static int
scsa2usb_open_usb_pipes(scsa2usb_state_t * scsa2usbp)45187c478bd9Sstevel@tonic-gate scsa2usb_open_usb_pipes(scsa2usb_state_t *scsa2usbp)
45197c478bd9Sstevel@tonic-gate {
45207c478bd9Sstevel@tonic-gate 	int			rval;
45217c478bd9Sstevel@tonic-gate 	usb_pipe_policy_t	policy;	/* bulk pipe policy */
45227c478bd9Sstevel@tonic-gate 	size_t			sz;
45237c478bd9Sstevel@tonic-gate 
45247c478bd9Sstevel@tonic-gate 	ASSERT(scsa2usbp);
45257c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
45267c478bd9Sstevel@tonic-gate 
45277c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
45287c478bd9Sstevel@tonic-gate 	    "scsa2usb_open_usb_pipes: dip = 0x%p flag = 0x%x",
4529112116d8Sfb 	    (void *)scsa2usbp->scsa2usb_dip, scsa2usbp->scsa2usb_flags);
45307c478bd9Sstevel@tonic-gate 
45317c478bd9Sstevel@tonic-gate 	if (!(scsa2usbp->scsa2usb_flags & SCSA2USB_FLAGS_PIPES_OPENED)) {
45327c478bd9Sstevel@tonic-gate 
45337c478bd9Sstevel@tonic-gate 		/*
45347c478bd9Sstevel@tonic-gate 		 * one pipe policy for all bulk pipes
45357c478bd9Sstevel@tonic-gate 		 */
45367c478bd9Sstevel@tonic-gate 		bzero(&policy, sizeof (usb_pipe_policy_t));
45377c478bd9Sstevel@tonic-gate 		/* at least 2, for the normal and exceptional callbacks */
45387c478bd9Sstevel@tonic-gate 		policy.pp_max_async_reqs = 1;
45397c478bd9Sstevel@tonic-gate 
45407c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
45417c478bd9Sstevel@tonic-gate 		    "scsa2usb_open_usb_pipes: opening bulk pipes");
45427c478bd9Sstevel@tonic-gate 
45437c478bd9Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
45447c478bd9Sstevel@tonic-gate 
45457c478bd9Sstevel@tonic-gate 		/* Open the USB bulk-in pipe */
4546993e3fafSRobert Mustacchi 		if ((rval = usb_pipe_xopen(scsa2usbp->scsa2usb_dip,
4547993e3fafSRobert Mustacchi 		    &scsa2usbp->scsa2usb_bulkin_xept, &policy, USB_FLAGS_SLEEP,
45487c478bd9Sstevel@tonic-gate 		    &scsa2usbp->scsa2usb_bulkin_pipe)) != USB_SUCCESS) {
45497c478bd9Sstevel@tonic-gate 			mutex_enter(&scsa2usbp->scsa2usb_mutex);
45507c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_SCSA,
45517c478bd9Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
45527c478bd9Sstevel@tonic-gate 			    "scsa2usb_open_usb_pipes: bulk/in pipe open "
45537c478bd9Sstevel@tonic-gate 			    " failed rval = %d", rval);
45547c478bd9Sstevel@tonic-gate 
45557c478bd9Sstevel@tonic-gate 			return (USB_FAILURE);
45567c478bd9Sstevel@tonic-gate 		}
45577c478bd9Sstevel@tonic-gate 
45587c478bd9Sstevel@tonic-gate 		/* Open the bulk-out pipe  using the same policy */
4559993e3fafSRobert Mustacchi 		if ((rval = usb_pipe_xopen(scsa2usbp->scsa2usb_dip,
4560993e3fafSRobert Mustacchi 		    &scsa2usbp->scsa2usb_bulkout_xept, &policy, USB_FLAGS_SLEEP,
45617c478bd9Sstevel@tonic-gate 		    &scsa2usbp->scsa2usb_bulkout_pipe)) != USB_SUCCESS) {
45627c478bd9Sstevel@tonic-gate 			usb_pipe_close(scsa2usbp->scsa2usb_dip,
45637c478bd9Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_bulkin_pipe,
45647c478bd9Sstevel@tonic-gate 			    USB_FLAGS_SLEEP, NULL, NULL);
45657c478bd9Sstevel@tonic-gate 
45667c478bd9Sstevel@tonic-gate 			mutex_enter(&scsa2usbp->scsa2usb_mutex);
45677c478bd9Sstevel@tonic-gate 			scsa2usbp->scsa2usb_bulkin_pipe = NULL;
45687c478bd9Sstevel@tonic-gate 
45697c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_SCSA,
45707c478bd9Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
45717c478bd9Sstevel@tonic-gate 			    "scsa2usb_open_usb_pipes: bulk/out pipe open"
45727c478bd9Sstevel@tonic-gate 			    " failed rval = %d", rval);
45737c478bd9Sstevel@tonic-gate 
45747c478bd9Sstevel@tonic-gate 			return (USB_FAILURE);
45757c478bd9Sstevel@tonic-gate 		}
45767c478bd9Sstevel@tonic-gate 
45777c478bd9Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
45787c478bd9Sstevel@tonic-gate 
45797c478bd9Sstevel@tonic-gate 		/* open interrupt pipe for CBI protocol */
45807c478bd9Sstevel@tonic-gate 		if (SCSA2USB_IS_CBI(scsa2usbp)) {
45817c478bd9Sstevel@tonic-gate 			mutex_exit(&scsa2usbp->scsa2usb_mutex);
45827c478bd9Sstevel@tonic-gate 
4583993e3fafSRobert Mustacchi 			if ((rval = usb_pipe_xopen(scsa2usbp->scsa2usb_dip,
4584993e3fafSRobert Mustacchi 			    &scsa2usbp->scsa2usb_intr_xept, &policy,
45857c478bd9Sstevel@tonic-gate 			    USB_FLAGS_SLEEP, &scsa2usbp->scsa2usb_intr_pipe)) !=
45867c478bd9Sstevel@tonic-gate 			    USB_SUCCESS) {
45877c478bd9Sstevel@tonic-gate 				usb_pipe_close(scsa2usbp->scsa2usb_dip,
45887c478bd9Sstevel@tonic-gate 				    scsa2usbp->scsa2usb_bulkin_pipe,
45897c478bd9Sstevel@tonic-gate 				    USB_FLAGS_SLEEP, NULL, NULL);
45907c478bd9Sstevel@tonic-gate 
45917c478bd9Sstevel@tonic-gate 				usb_pipe_close(scsa2usbp->scsa2usb_dip,
45927c478bd9Sstevel@tonic-gate 				    scsa2usbp->scsa2usb_bulkout_pipe,
45937c478bd9Sstevel@tonic-gate 				    USB_FLAGS_SLEEP, NULL, NULL);
45947c478bd9Sstevel@tonic-gate 
45957c478bd9Sstevel@tonic-gate 				mutex_enter(&scsa2usbp->scsa2usb_mutex);
45967c478bd9Sstevel@tonic-gate 				scsa2usbp->scsa2usb_bulkin_pipe = NULL;
45977c478bd9Sstevel@tonic-gate 				scsa2usbp->scsa2usb_bulkout_pipe = NULL;
45987c478bd9Sstevel@tonic-gate 
45997c478bd9Sstevel@tonic-gate 				USB_DPRINTF_L2(DPRINT_MASK_SCSA,
46007c478bd9Sstevel@tonic-gate 				    scsa2usbp->scsa2usb_log_handle,
46017c478bd9Sstevel@tonic-gate 				    "scsa2usb_open_usb_pipes: intr pipe open"
46027c478bd9Sstevel@tonic-gate 				    " failed rval = %d", rval);
46037c478bd9Sstevel@tonic-gate 
46047c478bd9Sstevel@tonic-gate 				return (USB_FAILURE);
46057c478bd9Sstevel@tonic-gate 			}
46067c478bd9Sstevel@tonic-gate 
46077c478bd9Sstevel@tonic-gate 			mutex_enter(&scsa2usbp->scsa2usb_mutex);
46087c478bd9Sstevel@tonic-gate 		}
46097c478bd9Sstevel@tonic-gate 
46107c478bd9Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
46117c478bd9Sstevel@tonic-gate 
46127c478bd9Sstevel@tonic-gate 		/* get the max transfer size of the bulk pipe */
46137c478bd9Sstevel@tonic-gate 		if (usb_pipe_get_max_bulk_transfer_size(scsa2usbp->scsa2usb_dip,
46147c478bd9Sstevel@tonic-gate 		    &sz) == USB_SUCCESS) {
46157c478bd9Sstevel@tonic-gate 			mutex_enter(&scsa2usbp->scsa2usb_mutex);
46167c478bd9Sstevel@tonic-gate 			scsa2usbp->scsa2usb_max_bulk_xfer_size = sz;
46177c478bd9Sstevel@tonic-gate 		} else {
46187c478bd9Sstevel@tonic-gate 			mutex_enter(&scsa2usbp->scsa2usb_mutex);
46197c478bd9Sstevel@tonic-gate 			scsa2usbp->scsa2usb_max_bulk_xfer_size = DEV_BSIZE;
46207c478bd9Sstevel@tonic-gate 		}
46217c478bd9Sstevel@tonic-gate 
46227c478bd9Sstevel@tonic-gate 		/* limit the xfer size */
46237c478bd9Sstevel@tonic-gate 		scsa2usbp->scsa2usb_max_bulk_xfer_size = min(
4624d94492edSfb 		    scsa2usbp->scsa2usb_max_bulk_xfer_size,
4625d94492edSfb 		    scsa2usb_max_bulk_xfer_size);
46267c478bd9Sstevel@tonic-gate 
46277c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
46287c478bd9Sstevel@tonic-gate 		    "scsa2usb_open_usb_pipes: max bulk transfer size = %lx",
46297c478bd9Sstevel@tonic-gate 		    scsa2usbp->scsa2usb_max_bulk_xfer_size);
46307c478bd9Sstevel@tonic-gate 
46317c478bd9Sstevel@tonic-gate 		/* Set the pipes opened flag */
46327c478bd9Sstevel@tonic-gate 		scsa2usbp->scsa2usb_flags |= SCSA2USB_FLAGS_PIPES_OPENED;
46337c478bd9Sstevel@tonic-gate 
46347c478bd9Sstevel@tonic-gate 		scsa2usbp->scsa2usb_pipe_state = SCSA2USB_PIPE_NORMAL;
46357c478bd9Sstevel@tonic-gate 
46367c478bd9Sstevel@tonic-gate 		/* Set the state to NONE */
46377c478bd9Sstevel@tonic-gate 		scsa2usbp->scsa2usb_pkt_state = SCSA2USB_PKT_NONE;
46387c478bd9Sstevel@tonic-gate 	}
46397c478bd9Sstevel@tonic-gate 
46407c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
46417c478bd9Sstevel@tonic-gate }
46427c478bd9Sstevel@tonic-gate 
46437c478bd9Sstevel@tonic-gate 
46447c478bd9Sstevel@tonic-gate /*
46457c478bd9Sstevel@tonic-gate  * scsa2usb_close_usb_pipes:
46467c478bd9Sstevel@tonic-gate  *	close all pipes synchronously
46477c478bd9Sstevel@tonic-gate  */
46487c478bd9Sstevel@tonic-gate void
scsa2usb_close_usb_pipes(scsa2usb_state_t * scsa2usbp)46497c478bd9Sstevel@tonic-gate scsa2usb_close_usb_pipes(scsa2usb_state_t *scsa2usbp)
46507c478bd9Sstevel@tonic-gate {
46517c478bd9Sstevel@tonic-gate 	usb_flags_t flags = USB_FLAGS_SLEEP;
46527c478bd9Sstevel@tonic-gate 
46537c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
4654112116d8Sfb 	    "scsa2usb_close_usb_pipes: scsa2usb_state = 0x%p",
4655112116d8Sfb 	    (void *)scsa2usbp);
46567c478bd9Sstevel@tonic-gate 
46577c478bd9Sstevel@tonic-gate 	ASSERT(scsa2usbp);
46587c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
46597c478bd9Sstevel@tonic-gate 
46607c478bd9Sstevel@tonic-gate 	if ((scsa2usbp->scsa2usb_flags & SCSA2USB_FLAGS_PIPES_OPENED) == 0) {
46617c478bd9Sstevel@tonic-gate 
46627c478bd9Sstevel@tonic-gate 		return;
46637c478bd9Sstevel@tonic-gate 	}
46647c478bd9Sstevel@tonic-gate 
46657c478bd9Sstevel@tonic-gate 	scsa2usbp->scsa2usb_pipe_state = SCSA2USB_PIPE_CLOSING;
46667c478bd9Sstevel@tonic-gate 	/* to avoid races, reset the flag first */
46677c478bd9Sstevel@tonic-gate 	scsa2usbp->scsa2usb_flags &= ~SCSA2USB_FLAGS_PIPES_OPENED;
46687c478bd9Sstevel@tonic-gate 
46697c478bd9Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
46707c478bd9Sstevel@tonic-gate 
46717c478bd9Sstevel@tonic-gate 	usb_pipe_close(scsa2usbp->scsa2usb_dip,
46727c478bd9Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_bulkout_pipe, flags, NULL, NULL);
46737c478bd9Sstevel@tonic-gate 
46747c478bd9Sstevel@tonic-gate 	usb_pipe_close(scsa2usbp->scsa2usb_dip,
46757c478bd9Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_bulkin_pipe, flags, NULL, NULL);
46767c478bd9Sstevel@tonic-gate 
46777c478bd9Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
46787c478bd9Sstevel@tonic-gate 	if (SCSA2USB_IS_CBI(scsa2usbp)) {
46797c478bd9Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
46807c478bd9Sstevel@tonic-gate 		usb_pipe_close(scsa2usbp->scsa2usb_dip,
46817c478bd9Sstevel@tonic-gate 		    scsa2usbp->scsa2usb_intr_pipe, flags, NULL, NULL);
46827c478bd9Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
46837c478bd9Sstevel@tonic-gate 	}
46847c478bd9Sstevel@tonic-gate 	scsa2usbp->scsa2usb_bulkout_pipe = NULL;
46857c478bd9Sstevel@tonic-gate 	scsa2usbp->scsa2usb_bulkin_pipe = NULL;
46867c478bd9Sstevel@tonic-gate 	scsa2usbp->scsa2usb_intr_pipe = NULL;
46877c478bd9Sstevel@tonic-gate 
46887c478bd9Sstevel@tonic-gate 	scsa2usbp->scsa2usb_pipe_state = SCSA2USB_PIPE_NORMAL;
46897c478bd9Sstevel@tonic-gate }
46907c478bd9Sstevel@tonic-gate 
46917c478bd9Sstevel@tonic-gate 
46927c478bd9Sstevel@tonic-gate /*
46937c478bd9Sstevel@tonic-gate  * scsa2usb_fill_up_cdb_lba:
46947c478bd9Sstevel@tonic-gate  *	fill up command CDBs' LBA part
46957c478bd9Sstevel@tonic-gate  */
46967c478bd9Sstevel@tonic-gate static void
scsa2usb_fill_up_cdb_lba(scsa2usb_cmd_t * cmd,uint64_t lba)469710b633f4SJoshua M. Clulow scsa2usb_fill_up_cdb_lba(scsa2usb_cmd_t *cmd, uint64_t lba)
46987c478bd9Sstevel@tonic-gate {
46997c478bd9Sstevel@tonic-gate 	/* zero cdb1, lba bits so they won't get copied in the new cdb */
47007c478bd9Sstevel@tonic-gate 	cmd->cmd_cdb[SCSA2USB_LUN] &= 0xE0;
47017c478bd9Sstevel@tonic-gate 	cmd->cmd_cdb[SCSA2USB_LBA_0] = lba >> 24;
47027c478bd9Sstevel@tonic-gate 	cmd->cmd_cdb[SCSA2USB_LBA_1] = lba >> 16;
47037c478bd9Sstevel@tonic-gate 	cmd->cmd_cdb[SCSA2USB_LBA_2] = lba >> 8;
47047c478bd9Sstevel@tonic-gate 	cmd->cmd_cdb[SCSA2USB_LBA_3] = (uchar_t)lba;
47057c478bd9Sstevel@tonic-gate 	cmd->cmd_lba = lba;
47067c478bd9Sstevel@tonic-gate }
47077c478bd9Sstevel@tonic-gate 
47087c478bd9Sstevel@tonic-gate 
470910b633f4SJoshua M. Clulow /*
471010b633f4SJoshua M. Clulow  * scsa2usb_fill_up_g4_cdb_lba:
471110b633f4SJoshua M. Clulow  *	fill in the CDB for a Group 4 command (16-byte CDB)
471210b633f4SJoshua M. Clulow  */
471310b633f4SJoshua M. Clulow static void
scsa2usb_fill_up_g4_cdb_lba(scsa2usb_cmd_t * cmd,uint64_t lba)471410b633f4SJoshua M. Clulow scsa2usb_fill_up_g4_cdb_lba(scsa2usb_cmd_t *cmd, uint64_t lba)
471510b633f4SJoshua M. Clulow {
471610b633f4SJoshua M. Clulow 	/* zero cdb1, lba bits so they won't get copied in the new cdb */
471710b633f4SJoshua M. Clulow 	cmd->cmd_cdb[SCSA2USB_LUN] &= 0xE0;
471810b633f4SJoshua M. Clulow 	cmd->cmd_cdb[2] = lba >> 56;
471910b633f4SJoshua M. Clulow 	cmd->cmd_cdb[3] = lba >> 48;
472010b633f4SJoshua M. Clulow 	cmd->cmd_cdb[4] = lba >> 40;
472110b633f4SJoshua M. Clulow 	cmd->cmd_cdb[5] = lba >> 32;
472210b633f4SJoshua M. Clulow 	cmd->cmd_cdb[6] = lba >> 24;
472310b633f4SJoshua M. Clulow 	cmd->cmd_cdb[7] = lba >> 16;
472410b633f4SJoshua M. Clulow 	cmd->cmd_cdb[8] = lba >> 8;
472510b633f4SJoshua M. Clulow 	cmd->cmd_cdb[9] = lba;
472610b633f4SJoshua M. Clulow 	cmd->cmd_lba = lba;
472710b633f4SJoshua M. Clulow }
472810b633f4SJoshua M. Clulow 
472910b633f4SJoshua M. Clulow 
47307c478bd9Sstevel@tonic-gate /*
47317c478bd9Sstevel@tonic-gate  * scsa2usb_fill_up_ReadCD_cdb_len:
47327c478bd9Sstevel@tonic-gate  *	fill up READ_CD command CDBs' len part
47337c478bd9Sstevel@tonic-gate  */
47347c478bd9Sstevel@tonic-gate static void
scsa2usb_fill_up_ReadCD_cdb_len(scsa2usb_cmd_t * cmd,int len,int actual_len)47357c478bd9Sstevel@tonic-gate scsa2usb_fill_up_ReadCD_cdb_len(scsa2usb_cmd_t *cmd, int len, int actual_len)
47367c478bd9Sstevel@tonic-gate {
47377c478bd9Sstevel@tonic-gate 	cmd->cmd_cdb[SCSA2USB_READ_CD_LEN_0] = len >> 16;
47387c478bd9Sstevel@tonic-gate 	cmd->cmd_cdb[SCSA2USB_READ_CD_LEN_1] = len >> 8;
47397c478bd9Sstevel@tonic-gate 	cmd->cmd_cdb[SCSA2USB_READ_CD_LEN_2] = (uchar_t)len;
47407c478bd9Sstevel@tonic-gate 	cmd->cmd_actual_len = (uchar_t)actual_len;
47417c478bd9Sstevel@tonic-gate }
47427c478bd9Sstevel@tonic-gate 
47437c478bd9Sstevel@tonic-gate 
474410b633f4SJoshua M. Clulow /*
474510b633f4SJoshua M. Clulow  * scsa2usb_fill_up_16byte_cdb_len:
474610b633f4SJoshua M. Clulow  *	populate CDB length field for SCMD_WRITE_G4 and SCMD_READ_G4
474710b633f4SJoshua M. Clulow  */
474810b633f4SJoshua M. Clulow static void
scsa2usb_fill_up_16byte_cdb_len(scsa2usb_cmd_t * cmd,int len,int actual_len)474910b633f4SJoshua M. Clulow scsa2usb_fill_up_16byte_cdb_len(scsa2usb_cmd_t *cmd, int len, int actual_len)
475010b633f4SJoshua M. Clulow {
475110b633f4SJoshua M. Clulow 	cmd->cmd_cdb[10] = len >> 24;
475210b633f4SJoshua M. Clulow 	cmd->cmd_cdb[11] = len >> 16;
475310b633f4SJoshua M. Clulow 	cmd->cmd_cdb[12] = len >> 8;
475410b633f4SJoshua M. Clulow 	cmd->cmd_cdb[13] = len;
475510b633f4SJoshua M. Clulow 	cmd->cmd_actual_len = actual_len;
475610b633f4SJoshua M. Clulow }
475710b633f4SJoshua M. Clulow 
475810b633f4SJoshua M. Clulow 
47597c478bd9Sstevel@tonic-gate /*
47607c478bd9Sstevel@tonic-gate  * scsa2usb_fill_up_12byte_cdb_len:
47617c478bd9Sstevel@tonic-gate  *	fill up generic 12-byte command CDBs' len part
47627c478bd9Sstevel@tonic-gate  */
47637c478bd9Sstevel@tonic-gate static void
scsa2usb_fill_up_12byte_cdb_len(scsa2usb_cmd_t * cmd,int len,int actual_len)47647c478bd9Sstevel@tonic-gate scsa2usb_fill_up_12byte_cdb_len(scsa2usb_cmd_t *cmd, int len, int actual_len)
47657c478bd9Sstevel@tonic-gate {
47667c478bd9Sstevel@tonic-gate 	cmd->cmd_cdb[6] = len >> 24;
47677c478bd9Sstevel@tonic-gate 	cmd->cmd_cdb[7] = len >> 16;
47687c478bd9Sstevel@tonic-gate 	cmd->cmd_cdb[8] = len >> 8;
47697c478bd9Sstevel@tonic-gate 	cmd->cmd_cdb[9] = (uchar_t)len;
47707c478bd9Sstevel@tonic-gate 	cmd->cmd_actual_len = (uchar_t)actual_len;
47717c478bd9Sstevel@tonic-gate }
47727c478bd9Sstevel@tonic-gate 
47737c478bd9Sstevel@tonic-gate 
47747c478bd9Sstevel@tonic-gate /*
47757c478bd9Sstevel@tonic-gate  * scsa2usb_fill_up_cdb_len:
47767c478bd9Sstevel@tonic-gate  *	fill up generic 10-byte command CDBs' len part
47777c478bd9Sstevel@tonic-gate  */
47787c478bd9Sstevel@tonic-gate static void
scsa2usb_fill_up_cdb_len(scsa2usb_cmd_t * cmd,int len)47797c478bd9Sstevel@tonic-gate scsa2usb_fill_up_cdb_len(scsa2usb_cmd_t *cmd, int len)
47807c478bd9Sstevel@tonic-gate {
47817c478bd9Sstevel@tonic-gate 	cmd->cmd_cdb[SCSA2USB_LEN_0] = len >> 8;
47827c478bd9Sstevel@tonic-gate 	cmd->cmd_cdb[SCSA2USB_LEN_1] = (uchar_t)len;
47837c478bd9Sstevel@tonic-gate }
47847c478bd9Sstevel@tonic-gate 
47857c478bd9Sstevel@tonic-gate 
47867c478bd9Sstevel@tonic-gate /*
47877c478bd9Sstevel@tonic-gate  * scsa2usb_read_cd_blk_size:
47887c478bd9Sstevel@tonic-gate  *	For SCMD_READ_CD opcode (0xbe). Figure out the
47897c478bd9Sstevel@tonic-gate  *	block size based on expected sector type field
47907c478bd9Sstevel@tonic-gate  *	definition. See MMC SCSI Specs section 6.1.15
47917c478bd9Sstevel@tonic-gate  *
47927c478bd9Sstevel@tonic-gate  *	Based on the value of the "expected_sector_type"
47937c478bd9Sstevel@tonic-gate  *	field, the block size could be different.
47947c478bd9Sstevel@tonic-gate  */
47957c478bd9Sstevel@tonic-gate static int
scsa2usb_read_cd_blk_size(uchar_t expected_sector_type)47967c478bd9Sstevel@tonic-gate scsa2usb_read_cd_blk_size(uchar_t expected_sector_type)
47977c478bd9Sstevel@tonic-gate {
47987c478bd9Sstevel@tonic-gate 	int blk_size;
47997c478bd9Sstevel@tonic-gate 
48007c478bd9Sstevel@tonic-gate 	switch (expected_sector_type) {
48017c478bd9Sstevel@tonic-gate 	case READ_CD_EST_CDDA:
48027c478bd9Sstevel@tonic-gate 		blk_size = CDROM_BLK_2352;
48037c478bd9Sstevel@tonic-gate 		break;
48047c478bd9Sstevel@tonic-gate 	case READ_CD_EST_MODE2:
48057c478bd9Sstevel@tonic-gate 		blk_size = CDROM_BLK_2336;
48067c478bd9Sstevel@tonic-gate 		break;
48077c478bd9Sstevel@tonic-gate 	case READ_CD_EST_MODE2FORM2:
48087c478bd9Sstevel@tonic-gate 		blk_size = CDROM_BLK_2324;
48097c478bd9Sstevel@tonic-gate 		break;
48107c478bd9Sstevel@tonic-gate 	case READ_CD_EST_MODE2FORM1:
48117c478bd9Sstevel@tonic-gate 	case READ_CD_EST_ALLTYPE:
48127c478bd9Sstevel@tonic-gate 	case READ_CD_EST_MODE1:
48137c478bd9Sstevel@tonic-gate 	default:
48147c478bd9Sstevel@tonic-gate 		blk_size = CDROM_BLK_2048;
48157c478bd9Sstevel@tonic-gate 	}
48167c478bd9Sstevel@tonic-gate 
48177c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, NULL, "scsa2usb_read_cd_blk_size: "
48187c478bd9Sstevel@tonic-gate 	    "est = 0x%x blk_size = %d", expected_sector_type, blk_size);
48197c478bd9Sstevel@tonic-gate 
48207c478bd9Sstevel@tonic-gate 	return (blk_size);
48217c478bd9Sstevel@tonic-gate }
48227c478bd9Sstevel@tonic-gate 
48237c478bd9Sstevel@tonic-gate 
48247c478bd9Sstevel@tonic-gate /*
48257c478bd9Sstevel@tonic-gate  * scsa2usb_bp_to_mblk:
48267c478bd9Sstevel@tonic-gate  *	Convert a bp to mblk_t. USBA framework understands mblk_t.
48277c478bd9Sstevel@tonic-gate  */
48287c478bd9Sstevel@tonic-gate static mblk_t *
scsa2usb_bp_to_mblk(scsa2usb_state_t * scsa2usbp)48297c478bd9Sstevel@tonic-gate scsa2usb_bp_to_mblk(scsa2usb_state_t *scsa2usbp)
48307c478bd9Sstevel@tonic-gate {
48317c478bd9Sstevel@tonic-gate 	size_t		size;
48327c478bd9Sstevel@tonic-gate 	mblk_t		*mp;
48337c478bd9Sstevel@tonic-gate 	struct buf	*bp;
48347c478bd9Sstevel@tonic-gate 	scsa2usb_cmd_t	*cmd = PKT2CMD(scsa2usbp->scsa2usb_cur_pkt);
48357c478bd9Sstevel@tonic-gate 
48367c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
48377c478bd9Sstevel@tonic-gate 	    "scsa2usb_bp_to_mblk: ");
48387c478bd9Sstevel@tonic-gate 
48397c478bd9Sstevel@tonic-gate 	ASSERT(scsa2usbp->scsa2usb_cur_pkt);
48407c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
48417c478bd9Sstevel@tonic-gate 
48427c478bd9Sstevel@tonic-gate 	bp = cmd->cmd_bp;
48437c478bd9Sstevel@tonic-gate 
48447c478bd9Sstevel@tonic-gate 	if (bp && (bp->b_bcount > 0)) {
48457c478bd9Sstevel@tonic-gate 		size = ((bp->b_bcount > cmd->cmd_xfercount) ?
4846d94492edSfb 		    cmd->cmd_xfercount : bp->b_bcount);
48477c478bd9Sstevel@tonic-gate 	} else {
48487c478bd9Sstevel@tonic-gate 
48497c478bd9Sstevel@tonic-gate 		return (NULL);
48507c478bd9Sstevel@tonic-gate 	}
48517c478bd9Sstevel@tonic-gate 
48527c478bd9Sstevel@tonic-gate 	mp = esballoc_wait((uchar_t *)bp->b_un.b_addr + cmd->cmd_offset,
48535bb8b905Szl 	    size, BPRI_LO, &frnop);
48547c478bd9Sstevel@tonic-gate 
48557c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
48567c478bd9Sstevel@tonic-gate 	    "scsa2usb_bp_to_mblk: "
4857112116d8Sfb 	    "mp=0x%p bp=0x%p pkt=0x%p off=0x%lx sz=%lu add=0x%p",
4858112116d8Sfb 	    (void *)mp, (void *)bp, (void *)scsa2usbp->scsa2usb_cur_pkt,
4859112116d8Sfb 	    cmd->cmd_offset, bp->b_bcount - cmd->cmd_offset,
4860112116d8Sfb 	    (void *)bp->b_un.b_addr);
48617c478bd9Sstevel@tonic-gate 
48627c478bd9Sstevel@tonic-gate 	mp->b_wptr += size;
48637c478bd9Sstevel@tonic-gate 	cmd->cmd_offset += size;
48647c478bd9Sstevel@tonic-gate 
48657c478bd9Sstevel@tonic-gate 	return (mp);
48667c478bd9Sstevel@tonic-gate }
48677c478bd9Sstevel@tonic-gate 
48687c478bd9Sstevel@tonic-gate 
48697c478bd9Sstevel@tonic-gate /*
48707c478bd9Sstevel@tonic-gate  * scsa2usb_handle_data_start:
48717c478bd9Sstevel@tonic-gate  *	Initiate the data xfer. It could be IN/OUT direction.
48727c478bd9Sstevel@tonic-gate  *
48737c478bd9Sstevel@tonic-gate  *	Data IN:
48747c478bd9Sstevel@tonic-gate  *		Send out the bulk-xfer request
48757c478bd9Sstevel@tonic-gate  *		if rval implies STALL
48767c478bd9Sstevel@tonic-gate  *			clear endpoint stall and reset bulk-in pipe
48777c478bd9Sstevel@tonic-gate  *			handle data read in so far; set cmd->cmd_done
48787c478bd9Sstevel@tonic-gate  *			also adjust data xfer length accordingly
48797c478bd9Sstevel@tonic-gate  *		else other error
48807c478bd9Sstevel@tonic-gate  *			report back to transport
48817c478bd9Sstevel@tonic-gate  *			typically transport will call reset recovery
48827c478bd9Sstevel@tonic-gate  *		else (no error)
48837c478bd9Sstevel@tonic-gate  *			return success
48847c478bd9Sstevel@tonic-gate  *
48857c478bd9Sstevel@tonic-gate  *	Data OUT:
48867c478bd9Sstevel@tonic-gate  *		Send out the bulk-xfer request
48877c478bd9Sstevel@tonic-gate  *		if rval implies STALL
48887c478bd9Sstevel@tonic-gate  *			clear endpoint stall and reset bulk-in pipe
48897c478bd9Sstevel@tonic-gate  *			adjust data xfer length
48907c478bd9Sstevel@tonic-gate  *		else other error
48917c478bd9Sstevel@tonic-gate  *			report back to transport
48927c478bd9Sstevel@tonic-gate  *			typically transport will call reset recovery
48937c478bd9Sstevel@tonic-gate  *		else (no error)
48947c478bd9Sstevel@tonic-gate  *			return success
48957c478bd9Sstevel@tonic-gate  *
48967c478bd9Sstevel@tonic-gate  *	NOTE: We call this function only if there is xfercount.
48977c478bd9Sstevel@tonic-gate  */
48987c478bd9Sstevel@tonic-gate int
scsa2usb_handle_data_start(scsa2usb_state_t * scsa2usbp,scsa2usb_cmd_t * cmd,usb_bulk_req_t * req)48997c478bd9Sstevel@tonic-gate scsa2usb_handle_data_start(scsa2usb_state_t *scsa2usbp,
49007c478bd9Sstevel@tonic-gate     scsa2usb_cmd_t *cmd, usb_bulk_req_t *req)
49017c478bd9Sstevel@tonic-gate {
49027c478bd9Sstevel@tonic-gate 	int		rval = USB_SUCCESS;
49037c478bd9Sstevel@tonic-gate 	uint_t		ept_addr;
49047c478bd9Sstevel@tonic-gate 	usb_flags_t	flags = USB_FLAGS_SLEEP;
49057c478bd9Sstevel@tonic-gate #ifdef	SCSA2USB_BULK_ONLY_TEST
49067c478bd9Sstevel@tonic-gate 	usb_req_attrs_t	attrs = 0;
49077c478bd9Sstevel@tonic-gate #else
49087c478bd9Sstevel@tonic-gate 	usb_req_attrs_t	attrs = USB_ATTRS_SHORT_XFER_OK;
49097c478bd9Sstevel@tonic-gate #endif
49107c478bd9Sstevel@tonic-gate 
49117c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
4912112116d8Sfb 	    "scsa2usb_handle_data_start: BEGIN cmd = %p, req = %p",
4913112116d8Sfb 	    (void *)cmd, (void *)req);
49147c478bd9Sstevel@tonic-gate 
49157c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
49167c478bd9Sstevel@tonic-gate 
49177c478bd9Sstevel@tonic-gate 	switch (cmd->cmd_dir) {
49187c478bd9Sstevel@tonic-gate 	case USB_EP_DIR_IN:
49197c478bd9Sstevel@tonic-gate #ifdef	SCSA2USB_BULK_ONLY_TEST
49207c478bd9Sstevel@tonic-gate 		/*
49217c478bd9Sstevel@tonic-gate 		 * This case occurs when the host expects to receive
49227c478bd9Sstevel@tonic-gate 		 * more data than the device actually transfers. Hi > Di
49237c478bd9Sstevel@tonic-gate 		 */
49247c478bd9Sstevel@tonic-gate 		if (scsa2usb_test_case_5) {
49257c478bd9Sstevel@tonic-gate 			usb_bulk_req_t *req2;
49267c478bd9Sstevel@tonic-gate 
49277c478bd9Sstevel@tonic-gate 			req->bulk_len = cmd->cmd_xfercount - 1;
49287c478bd9Sstevel@tonic-gate 			req->bulk_attributes = 0;
49297c478bd9Sstevel@tonic-gate 			mutex_exit(&scsa2usbp->scsa2usb_mutex);
49307c478bd9Sstevel@tonic-gate 			SCSA2USB_FREE_MSG(req->bulk_data);
49317c478bd9Sstevel@tonic-gate 			req->bulk_data = allocb_wait(req->bulk_len, BPRI_LO,
49327c478bd9Sstevel@tonic-gate 			    STR_NOSIG, NULL);
49337c478bd9Sstevel@tonic-gate 
49347c478bd9Sstevel@tonic-gate 			ASSERT(req->bulk_timeout);
49357c478bd9Sstevel@tonic-gate 			rval = usb_pipe_bulk_xfer(
49367c478bd9Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_bulkin_pipe, req, flags);
49377c478bd9Sstevel@tonic-gate 			mutex_enter(&scsa2usbp->scsa2usb_mutex);
49387c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_SCSA,
49397c478bd9Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle, "rval = %x", rval);
49407c478bd9Sstevel@tonic-gate 
49417c478bd9Sstevel@tonic-gate 			req2 = scsa2usb_init_bulk_req(scsa2usbp,
49427c478bd9Sstevel@tonic-gate 			    cmd->cmd_xfercount + 2,
49437c478bd9Sstevel@tonic-gate 			    cmd->cmd_timeout, 0, flags);
49447c478bd9Sstevel@tonic-gate 			req2->bulk_len = cmd->cmd_xfercount + 2;
49457c478bd9Sstevel@tonic-gate 			mutex_exit(&scsa2usbp->scsa2usb_mutex);
49467c478bd9Sstevel@tonic-gate 
49477c478bd9Sstevel@tonic-gate 			ASSERT(req2->bulk_timeout);
49487c478bd9Sstevel@tonic-gate 			rval = usb_pipe_bulk_xfer(
49497c478bd9Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_bulkin_pipe, req2, flags);
49507c478bd9Sstevel@tonic-gate 			mutex_enter(&scsa2usbp->scsa2usb_mutex);
49517c478bd9Sstevel@tonic-gate 
49527c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_SCSA,
49537c478bd9Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
49547c478bd9Sstevel@tonic-gate 			    "TEST 5: Hi > Di: rval = 0x%x", rval);
49557c478bd9Sstevel@tonic-gate 			scsa2usb_test_case_5 = 0;
49567c478bd9Sstevel@tonic-gate 			usb_free_bulk_req(req2);
49577c478bd9Sstevel@tonic-gate 
49587c478bd9Sstevel@tonic-gate 			return (rval);
49597c478bd9Sstevel@tonic-gate 		}
49607c478bd9Sstevel@tonic-gate 
49617c478bd9Sstevel@tonic-gate 		/*
49627c478bd9Sstevel@tonic-gate 		 * This happens when the host expects to send data to the
49637c478bd9Sstevel@tonic-gate 		 * device while the device intends to send data to the host.
49647c478bd9Sstevel@tonic-gate 		 */
49657c478bd9Sstevel@tonic-gate 		if (scsa2usb_test_case_8 && (cmd->cmd_cdb[0] == SCMD_READ_G1)) {
49667c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_SCSA,
49677c478bd9Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
49687c478bd9Sstevel@tonic-gate 			    "TEST 8: Hi <> Do: Step 2");
49697c478bd9Sstevel@tonic-gate 			scsa2usb_test_mblk(scsa2usbp, B_TRUE);
49707c478bd9Sstevel@tonic-gate 			scsa2usb_test_case_8 = 0;
49717c478bd9Sstevel@tonic-gate 
49727c478bd9Sstevel@tonic-gate 			return (rval);
49737c478bd9Sstevel@tonic-gate 		}
49747c478bd9Sstevel@tonic-gate #endif	/* SCSA2USB_BULK_ONLY_TEST */
49757c478bd9Sstevel@tonic-gate 
49767c478bd9Sstevel@tonic-gate 		ept_addr = scsa2usbp->scsa2usb_bulkin_ept.bEndpointAddress;
49777c478bd9Sstevel@tonic-gate 		req->bulk_len = cmd->cmd_xfercount;
49787c478bd9Sstevel@tonic-gate 		req->bulk_attributes = attrs;
49797c478bd9Sstevel@tonic-gate 		SCSA2USB_FREE_MSG(req->bulk_data);
49807c478bd9Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
49817c478bd9Sstevel@tonic-gate 
49827c478bd9Sstevel@tonic-gate 		req->bulk_data = esballoc_wait(
4983d94492edSfb 		    (uchar_t *)cmd->cmd_bp->b_un.b_addr +
4984d94492edSfb 		    cmd->cmd_offset,
49855bb8b905Szl 		    req->bulk_len, BPRI_LO, &frnop);
49867c478bd9Sstevel@tonic-gate 
49877c478bd9Sstevel@tonic-gate 		ASSERT(req->bulk_timeout);
49887c478bd9Sstevel@tonic-gate 		rval = usb_pipe_bulk_xfer(scsa2usbp->scsa2usb_bulkin_pipe,
4989d94492edSfb 		    req, flags);
49907c478bd9Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
49917c478bd9Sstevel@tonic-gate 
49927c478bd9Sstevel@tonic-gate 		break;
49937c478bd9Sstevel@tonic-gate 
49947c478bd9Sstevel@tonic-gate 	case USB_EP_DIR_OUT:
49957c478bd9Sstevel@tonic-gate #ifdef	SCSA2USB_BULK_ONLY_TEST
49967c478bd9Sstevel@tonic-gate 		/*
49977c478bd9Sstevel@tonic-gate 		 * This happens when the host expects to receive data
49987c478bd9Sstevel@tonic-gate 		 * from the device while the device intends to receive
49997c478bd9Sstevel@tonic-gate 		 * data from the host.
50007c478bd9Sstevel@tonic-gate 		 */
50017c478bd9Sstevel@tonic-gate 		if (scsa2usb_test_case_10 &&
50027c478bd9Sstevel@tonic-gate 		    (cmd->cmd_cdb[0] == SCMD_WRITE_G1)) {
50037c478bd9Sstevel@tonic-gate 			req->bulk_len = CSW_LEN;
50047c478bd9Sstevel@tonic-gate 			mutex_exit(&scsa2usbp->scsa2usb_mutex);
50057c478bd9Sstevel@tonic-gate 
50067c478bd9Sstevel@tonic-gate 			ASSERT(req->bulk_timeout);
50077c478bd9Sstevel@tonic-gate 			rval = usb_pipe_bulk_xfer(
50087c478bd9Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_bulkin_pipe, req, flags);
50097c478bd9Sstevel@tonic-gate 			mutex_enter(&scsa2usbp->scsa2usb_mutex);
50107c478bd9Sstevel@tonic-gate 
50117c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_SCSA,
50127c478bd9Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
50137c478bd9Sstevel@tonic-gate 			    "TEST 10: Ho <> Di: done rval = 0x%x",  rval);
50147c478bd9Sstevel@tonic-gate 			scsa2usb_test_case_10 = 0;
50157c478bd9Sstevel@tonic-gate 
50167c478bd9Sstevel@tonic-gate 			return (rval);
50177c478bd9Sstevel@tonic-gate 		}
50187c478bd9Sstevel@tonic-gate #endif	/* SCSA2USB_BULK_ONLY_TEST */
50197c478bd9Sstevel@tonic-gate 
50207c478bd9Sstevel@tonic-gate 		req->bulk_data = scsa2usb_bp_to_mblk(scsa2usbp);
50217c478bd9Sstevel@tonic-gate 		if (req->bulk_data == NULL) {
50227c478bd9Sstevel@tonic-gate 
50237c478bd9Sstevel@tonic-gate 			return (USB_FAILURE);
50247c478bd9Sstevel@tonic-gate 		}
50257c478bd9Sstevel@tonic-gate 
50267c478bd9Sstevel@tonic-gate #ifdef	SCSA2USB_BULK_ONLY_TEST
50277c478bd9Sstevel@tonic-gate 		if (scsa2usb_test_case_11) {
50287c478bd9Sstevel@tonic-gate 			/*
50297c478bd9Sstevel@tonic-gate 			 * Host expects to send data to the device and
50307c478bd9Sstevel@tonic-gate 			 * device doesn't expect to receive any data
50317c478bd9Sstevel@tonic-gate 			 */
50327c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_SCSA,
50337c478bd9Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle, "TEST 11: Ho > Do");
50347c478bd9Sstevel@tonic-gate 
50357c478bd9Sstevel@tonic-gate 			scsa2usb_test_mblk(scsa2usbp, B_FALSE);
50367c478bd9Sstevel@tonic-gate 			scsa2usb_test_case_11 = 0;
50377c478bd9Sstevel@tonic-gate 		}
50387c478bd9Sstevel@tonic-gate #endif	/* SCSA2USB_BULK_ONLY_TEST */
50397c478bd9Sstevel@tonic-gate 
50407c478bd9Sstevel@tonic-gate 		ept_addr = scsa2usbp->scsa2usb_bulkout_ept.bEndpointAddress;
5041d29f5a71Szhigang lu - Sun Microsystems - Beijing China 		req->bulk_len = MBLKL(req->bulk_data);
50427c478bd9Sstevel@tonic-gate 		req->bulk_timeout = scsa2usb_bulk_timeout(cmd->cmd_timeout);
50437c478bd9Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
50447c478bd9Sstevel@tonic-gate 
50457c478bd9Sstevel@tonic-gate 		ASSERT(req->bulk_timeout);
50467c478bd9Sstevel@tonic-gate 		rval = usb_pipe_bulk_xfer(scsa2usbp->scsa2usb_bulkout_pipe,
5047d94492edSfb 		    req, flags);
50487c478bd9Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
50497c478bd9Sstevel@tonic-gate 		break;
50507c478bd9Sstevel@tonic-gate 	}
50517c478bd9Sstevel@tonic-gate 
50527c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_SCSA,
50537c478bd9Sstevel@tonic-gate 	    scsa2usbp->scsa2usb_log_handle,
50547c478bd9Sstevel@tonic-gate 	    "scsa2usb_handle_data_start: rval=%d cr=%d", rval,
50557c478bd9Sstevel@tonic-gate 	    req->bulk_completion_reason);
50567c478bd9Sstevel@tonic-gate 
50577c478bd9Sstevel@tonic-gate 	if (rval != USB_SUCCESS) {
50587c478bd9Sstevel@tonic-gate 		/* Handle Errors now */
50597c478bd9Sstevel@tonic-gate 		if (req->bulk_completion_reason == USB_CR_STALL) {
50607c478bd9Sstevel@tonic-gate 			if (cmd->cmd_dir == USB_EP_DIR_IN) {
50617c478bd9Sstevel@tonic-gate 				(void) scsa2usb_clear_ept_stall(
50627c478bd9Sstevel@tonic-gate 				    scsa2usbp, ept_addr,
50637c478bd9Sstevel@tonic-gate 				    scsa2usbp-> scsa2usb_bulkin_pipe,
50647c478bd9Sstevel@tonic-gate 				    "bulk-in");
50657c478bd9Sstevel@tonic-gate 			} else {
50667c478bd9Sstevel@tonic-gate 				(void) scsa2usb_clear_ept_stall(
50677c478bd9Sstevel@tonic-gate 				    scsa2usbp, ept_addr,
50687c478bd9Sstevel@tonic-gate 				    scsa2usbp-> scsa2usb_bulkout_pipe,
50697c478bd9Sstevel@tonic-gate 				    "bulk-out");
50707c478bd9Sstevel@tonic-gate 			}
50717c478bd9Sstevel@tonic-gate 		}
50727c478bd9Sstevel@tonic-gate 
50737c478bd9Sstevel@tonic-gate 		/* no more data to transfer after this */
50747c478bd9Sstevel@tonic-gate 		cmd->cmd_done = 1;
50757c478bd9Sstevel@tonic-gate 	}
50767c478bd9Sstevel@tonic-gate 
50777c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
50787c478bd9Sstevel@tonic-gate 	    "scsa2usb_handle_data_start: END %s data rval = %d",
50797c478bd9Sstevel@tonic-gate 	    (cmd->cmd_dir == USB_EP_DIR_IN) ? "bulk-in" : "bulk-out", rval);
50807c478bd9Sstevel@tonic-gate 
50817c478bd9Sstevel@tonic-gate 	return (rval);
50827c478bd9Sstevel@tonic-gate }
50837c478bd9Sstevel@tonic-gate 
50847c478bd9Sstevel@tonic-gate 
50857c478bd9Sstevel@tonic-gate /*
50867c478bd9Sstevel@tonic-gate  * scsa2usb_handle_data_done:
50877c478bd9Sstevel@tonic-gate  *	This function handles the completion of the data xfer.
50887c478bd9Sstevel@tonic-gate  *	It also massages the inquiry data. This function may
50897c478bd9Sstevel@tonic-gate  *	also be called after a stall.
50907c478bd9Sstevel@tonic-gate  */
50917c478bd9Sstevel@tonic-gate void
scsa2usb_handle_data_done(scsa2usb_state_t * scsa2usbp,scsa2usb_cmd_t * cmd,usb_bulk_req_t * req)50927c478bd9Sstevel@tonic-gate scsa2usb_handle_data_done(scsa2usb_state_t *scsa2usbp,
50937c478bd9Sstevel@tonic-gate     scsa2usb_cmd_t *cmd, usb_bulk_req_t *req)
50947c478bd9Sstevel@tonic-gate {
50957c478bd9Sstevel@tonic-gate 	struct buf	*bp = cmd->cmd_bp;
50967c478bd9Sstevel@tonic-gate 	struct scsi_pkt	*pkt = scsa2usbp->scsa2usb_cur_pkt;
50977c478bd9Sstevel@tonic-gate 	mblk_t		*data = req->bulk_data;
5098d29f5a71Szhigang lu - Sun Microsystems - Beijing China 	int		len = data ? MBLKL(data) : 0;
509963602c90Sfb 	uint32_t	max_lba;
51007c478bd9Sstevel@tonic-gate 
51017c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
51027c478bd9Sstevel@tonic-gate 
51037c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
51047c478bd9Sstevel@tonic-gate 	    "scsa2usb_handle_data_done:\n\tcmd = 0x%p data = 0x%p len = 0x%x",
5105112116d8Sfb 	    (void *)cmd, (void *)data, len);
51067c478bd9Sstevel@tonic-gate 
51077c478bd9Sstevel@tonic-gate 	cmd->cmd_resid_xfercount = cmd->cmd_xfercount - len;
51087c478bd9Sstevel@tonic-gate 
51097c478bd9Sstevel@tonic-gate 	if (len)  {
51107c478bd9Sstevel@tonic-gate 		uchar_t	*p;
511172d9a10cSlg 		uchar_t dtype;
51127c478bd9Sstevel@tonic-gate 		scsa2usb_read_cap_t *cap;
511372d9a10cSlg 		struct scsi_inquiry *inq;
51147c478bd9Sstevel@tonic-gate 
51157c478bd9Sstevel@tonic-gate 		switch (cmd->cmd_cdb[SCSA2USB_OPCODE]) {
51167c478bd9Sstevel@tonic-gate 		case SCMD_INQUIRY:
51177c478bd9Sstevel@tonic-gate 			/*
51187c478bd9Sstevel@tonic-gate 			 * cache a copy of the inquiry data for our own use
51197c478bd9Sstevel@tonic-gate 			 * but ensure that we have at least up to
51207c478bd9Sstevel@tonic-gate 			 * inq_revision, inq_serial is not required.
51217c478bd9Sstevel@tonic-gate 			 * ignore inquiry data returned for inquiry commands
51227c478bd9Sstevel@tonic-gate 			 * with SCSI-3 EVPD, CmdDt bits set.
51237c478bd9Sstevel@tonic-gate 			 */
51247c478bd9Sstevel@tonic-gate 			if (((cmd->cmd_cdb[SCSA2USB_LUN] & 0x1f) == 0) &&
51257c478bd9Sstevel@tonic-gate 			    (len >= SCSA2USB_MAX_INQ_LEN)) {
512672d9a10cSlg 				inq = (struct scsi_inquiry *)data->b_rptr;
512772d9a10cSlg 				dtype = inq->inq_dtype & DTYPE_MASK;
512872d9a10cSlg 				/*
512972d9a10cSlg 				 * scsi framework sends zero byte write(10) cmd
513072d9a10cSlg 				 * to (Simplified) direct-access devices with
513172d9a10cSlg 				 * inquiry version > 2 for reservation changes.
513272d9a10cSlg 				 * But some USB devices don't support zero byte
513372d9a10cSlg 				 * write(10) even though they have inquiry
513472d9a10cSlg 				 * version > 2. Considering scsa2usb driver
513572d9a10cSlg 				 * doesn't support reservation and all the
513672d9a10cSlg 				 * reservation cmds are being faked, we fake
513772d9a10cSlg 				 * the inquiry version to 0 to make scsi
513872d9a10cSlg 				 * framework send test unit ready cmd which is
513972d9a10cSlg 				 * supported by all the usb devices.
514072d9a10cSlg 				 */
514172d9a10cSlg 				if (((dtype == DTYPE_DIRECT) ||
514272d9a10cSlg 				    (dtype == DTYPE_RBC)) &&
514372d9a10cSlg 				    (inq->inq_ansi > 2)) {
514472d9a10cSlg 					inq->inq_ansi = 0;
514572d9a10cSlg 				}
514672d9a10cSlg 
51477c478bd9Sstevel@tonic-gate 				bzero(&scsa2usbp->scsa2usb_lun_inquiry
51487c478bd9Sstevel@tonic-gate 				    [pkt->pkt_address.a_lun],
51497c478bd9Sstevel@tonic-gate 				    sizeof (struct scsi_inquiry));
51507c478bd9Sstevel@tonic-gate 				bcopy(data->b_rptr,
51517c478bd9Sstevel@tonic-gate 				    &scsa2usbp->scsa2usb_lun_inquiry
51527c478bd9Sstevel@tonic-gate 				    [pkt->pkt_address.a_lun], len);
51537c478bd9Sstevel@tonic-gate 			}
51547c478bd9Sstevel@tonic-gate 
51557c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L3(DPRINT_MASK_SCSA,
51567c478bd9Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
51577c478bd9Sstevel@tonic-gate 			    "scsi inquiry type = 0x%x",
51587c478bd9Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_lun_inquiry
51597c478bd9Sstevel@tonic-gate 			    [pkt->pkt_address.a_lun].inq_dtype);
51607c478bd9Sstevel@tonic-gate 
51617c478bd9Sstevel@tonic-gate 			cmd->cmd_done = 1;
51627c478bd9Sstevel@tonic-gate 			goto handle_data;
51637c478bd9Sstevel@tonic-gate 
51647c478bd9Sstevel@tonic-gate 		case SCMD_READ_CAPACITY:
51657c478bd9Sstevel@tonic-gate 			cap = (scsa2usb_read_cap_t *)data->b_rptr;
51667c478bd9Sstevel@tonic-gate 
51677c478bd9Sstevel@tonic-gate 			/* Figure out the logical block size */
51687c478bd9Sstevel@tonic-gate 			if ((len >= sizeof (struct scsa2usb_read_cap)) &&
51697c478bd9Sstevel@tonic-gate 			    (req->bulk_completion_reason == USB_CR_OK)) {
51707c478bd9Sstevel@tonic-gate 				scsa2usbp->
51717c478bd9Sstevel@tonic-gate 				    scsa2usb_lbasize[pkt->pkt_address.a_lun] =
51727c478bd9Sstevel@tonic-gate 				    SCSA2USB_MK_32BIT(
5173d94492edSfb 				    cap->scsa2usb_read_cap_blen3,
5174d94492edSfb 				    cap->scsa2usb_read_cap_blen2,
5175d94492edSfb 				    cap->scsa2usb_read_cap_blen1,
5176d94492edSfb 				    cap->scsa2usb_read_cap_blen0);
51777c478bd9Sstevel@tonic-gate 
517863602c90Sfb 				max_lba = SCSA2USB_MK_32BIT(
517963602c90Sfb 				    cap->scsa2usb_read_cap_lba3,
518063602c90Sfb 				    cap->scsa2usb_read_cap_lba2,
518163602c90Sfb 				    cap->scsa2usb_read_cap_lba1,
518263602c90Sfb 				    cap->scsa2usb_read_cap_lba0);
518363602c90Sfb 
518463602c90Sfb 				/*
518563602c90Sfb 				 * Some devices return total logical block
518663602c90Sfb 				 * number instead of highest logical block
518763602c90Sfb 				 * address. Adjust the value by minus 1.
518863602c90Sfb 				 */
518963602c90Sfb 				if (max_lba > 0 && (scsa2usbp->scsa2usb_attrs &
519063602c90Sfb 				    SCSA2USB_ATTRS_NO_CAP_ADJUST) == 0) {
519163602c90Sfb 					max_lba -= 1;
519263602c90Sfb 					cap->scsa2usb_read_cap_lba0 =
519363602c90Sfb 					    (uchar_t)(max_lba & 0xFF);
519463602c90Sfb 					cap->scsa2usb_read_cap_lba1 =
519563602c90Sfb 					    (uchar_t)(max_lba >> 8 & 0xFF);
519663602c90Sfb 					cap->scsa2usb_read_cap_lba2 =
519763602c90Sfb 					    (uchar_t)(max_lba >> 16 & 0xFF);
519863602c90Sfb 					cap->scsa2usb_read_cap_lba3 =
519963602c90Sfb 					    (uchar_t)(max_lba >> 24 & 0xFF);
520063602c90Sfb 				}
520163602c90Sfb 
520263602c90Sfb 				USB_DPRINTF_L2(DPRINT_MASK_SCSA,
52037c478bd9Sstevel@tonic-gate 				    scsa2usbp->scsa2usb_log_handle,
5204112116d8Sfb 				    "bytes in each logical block=0x%lx,"
520563602c90Sfb 				    "number of total logical blocks=0x%x",
520663602c90Sfb 				    scsa2usbp->
520763602c90Sfb 				    scsa2usb_lbasize[pkt->pkt_address.a_lun],
520863602c90Sfb 				    max_lba + 1);
52097c478bd9Sstevel@tonic-gate 			}
52107c478bd9Sstevel@tonic-gate 			cmd->cmd_done = 1;
52117c478bd9Sstevel@tonic-gate 			goto handle_data;
52127c478bd9Sstevel@tonic-gate 
52137c478bd9Sstevel@tonic-gate 		case SCMD_REQUEST_SENSE:
52147c478bd9Sstevel@tonic-gate 			p = data->b_rptr;
52157c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_SCSA,
52167c478bd9Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
52177c478bd9Sstevel@tonic-gate 			    "cdb: %x rqsense: "
52187c478bd9Sstevel@tonic-gate 			    "%x %x %x %x %x %x %x %x %x %x\n\t"
52197c478bd9Sstevel@tonic-gate 			    "%x %x %x %x %x %x %x %x %x %x",
52207c478bd9Sstevel@tonic-gate 			    cmd->cmd_cdb[0],
52217c478bd9Sstevel@tonic-gate 			    p[0], p[1], p[2], p[3], p[4],
52227c478bd9Sstevel@tonic-gate 			    p[5], p[6], p[7], p[8], p[9],
52237c478bd9Sstevel@tonic-gate 			    p[10], p[11], p[12], p[13], p[14],
52247c478bd9Sstevel@tonic-gate 			    p[15], p[16], p[17], p[18], p[19]);
52257c478bd9Sstevel@tonic-gate 
52267c478bd9Sstevel@tonic-gate 			scsa2usbp->scsa2usb_last_cmd.status = p[2];
52277c478bd9Sstevel@tonic-gate 			cmd->cmd_done = 1;
52287c478bd9Sstevel@tonic-gate 			/* FALLTHROUGH */
52297c478bd9Sstevel@tonic-gate 
52303fbbb872Ssl 		default:
52317c478bd9Sstevel@tonic-gate handle_data:
52327c478bd9Sstevel@tonic-gate 			if (bp && len && (cmd->cmd_dir == USB_EP_DIR_IN)) {
52337c478bd9Sstevel@tonic-gate 				/*
52347c478bd9Sstevel@tonic-gate 				 * we don't have to copy the data, the
52357c478bd9Sstevel@tonic-gate 				 * data pointers for the mblk_t for
52367c478bd9Sstevel@tonic-gate 				 * the bulk-in xfer points to the
52377c478bd9Sstevel@tonic-gate 				 * struct buf * data.
52387c478bd9Sstevel@tonic-gate 				 */
52397c478bd9Sstevel@tonic-gate 				cmd->cmd_offset += len;
52407c478bd9Sstevel@tonic-gate 			}
52417c478bd9Sstevel@tonic-gate 
52427c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L3(DPRINT_MASK_SCSA,
52437c478bd9Sstevel@tonic-gate 			    scsa2usbp->scsa2usb_log_handle,
52443fbbb872Ssl 			    "len = 0x%x total = 0x%lx offset = 0x%lx",
52453fbbb872Ssl 			    len, cmd->cmd_total_xfercount, cmd->cmd_offset);
52467c478bd9Sstevel@tonic-gate 
52477c478bd9Sstevel@tonic-gate 			/*
52487c478bd9Sstevel@tonic-gate 			 * update total_xfercount now but it may be
52497c478bd9Sstevel@tonic-gate 			 * adjusted after receiving the residue
52507c478bd9Sstevel@tonic-gate 			 */
52517c478bd9Sstevel@tonic-gate 			cmd->cmd_total_xfercount -= len;
52527c478bd9Sstevel@tonic-gate 
52537c478bd9Sstevel@tonic-gate 			if ((req->bulk_completion_reason != USB_CR_OK) ||
52547c478bd9Sstevel@tonic-gate 			    (cmd->cmd_resid_xfercount != 0) ||
52557c478bd9Sstevel@tonic-gate 			    (cmd->cmd_total_xfercount == 0)) {
52567c478bd9Sstevel@tonic-gate 				/* set pkt_resid to total to be sure */
52577c478bd9Sstevel@tonic-gate 				pkt->pkt_resid = cmd->cmd_total_xfercount;
52587c478bd9Sstevel@tonic-gate 				cmd->cmd_done = 1;
52597c478bd9Sstevel@tonic-gate 			}
52607c478bd9Sstevel@tonic-gate 
52617c478bd9Sstevel@tonic-gate 			break;
52627c478bd9Sstevel@tonic-gate 		}
52637c478bd9Sstevel@tonic-gate 	} else {
52647c478bd9Sstevel@tonic-gate 		if (cmd->cmd_dir == USB_EP_DIR_OUT) {
52657c478bd9Sstevel@tonic-gate 			if (cmd->cmd_total_xfercount == 0) {
52667c478bd9Sstevel@tonic-gate 				cmd->cmd_done = 1;
52677c478bd9Sstevel@tonic-gate 			}
52687c478bd9Sstevel@tonic-gate 		}
52697c478bd9Sstevel@tonic-gate 	}
52707c478bd9Sstevel@tonic-gate }
52717c478bd9Sstevel@tonic-gate 
52727c478bd9Sstevel@tonic-gate 
52737c478bd9Sstevel@tonic-gate /*
52747c478bd9Sstevel@tonic-gate  * scsa2usb_init_bulk_req:
52757c478bd9Sstevel@tonic-gate  *	Allocate (synchronously) and fill in a bulk-request
52767c478bd9Sstevel@tonic-gate  */
52777c478bd9Sstevel@tonic-gate usb_bulk_req_t *
scsa2usb_init_bulk_req(scsa2usb_state_t * scsa2usbp,size_t length,uint_t timeout,usb_req_attrs_t attrs,usb_flags_t flags)52787c478bd9Sstevel@tonic-gate scsa2usb_init_bulk_req(scsa2usb_state_t *scsa2usbp, size_t length,
52797c478bd9Sstevel@tonic-gate     uint_t timeout, usb_req_attrs_t attrs, usb_flags_t flags)
52807c478bd9Sstevel@tonic-gate {
52817c478bd9Sstevel@tonic-gate 	usb_bulk_req_t	*req;
52827c478bd9Sstevel@tonic-gate 
52837c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
52847c478bd9Sstevel@tonic-gate 
52857c478bd9Sstevel@tonic-gate 	req = usb_alloc_bulk_req(scsa2usbp->scsa2usb_dip, length,
52867c478bd9Sstevel@tonic-gate 	    flags | USB_FLAGS_SLEEP);
52877c478bd9Sstevel@tonic-gate 
5288d29f5a71Szhigang lu - Sun Microsystems - Beijing China 	req->bulk_len = (uint_t)length;			/* xfer length */
52897c478bd9Sstevel@tonic-gate 	req->bulk_timeout = scsa2usb_bulk_timeout(timeout); /* xfer timeout */
52907c478bd9Sstevel@tonic-gate 	req->bulk_attributes = attrs;		/* xfer attrs */
52917c478bd9Sstevel@tonic-gate 	req->bulk_client_private = (usb_opaque_t)scsa2usbp; /* statep */
52927c478bd9Sstevel@tonic-gate 
52937c478bd9Sstevel@tonic-gate 	return (req);
52947c478bd9Sstevel@tonic-gate }
52957c478bd9Sstevel@tonic-gate 
52967c478bd9Sstevel@tonic-gate 
52977c478bd9Sstevel@tonic-gate /*
52987c478bd9Sstevel@tonic-gate  * scsa2usb_bulk_timeout:
52997c478bd9Sstevel@tonic-gate  *	ensure that bulk requests do not have infinite timeout values
53007c478bd9Sstevel@tonic-gate  */
53017c478bd9Sstevel@tonic-gate int
scsa2usb_bulk_timeout(int timeout)53027c478bd9Sstevel@tonic-gate scsa2usb_bulk_timeout(int timeout)
53037c478bd9Sstevel@tonic-gate {
53047c478bd9Sstevel@tonic-gate 	return ((timeout == 0) ? scsa2usb_long_timeout : timeout);
53057c478bd9Sstevel@tonic-gate }
53067c478bd9Sstevel@tonic-gate 
53077c478bd9Sstevel@tonic-gate 
53087c478bd9Sstevel@tonic-gate /*
53097c478bd9Sstevel@tonic-gate  * scsa2usb_clear_ept_stall:
53107c478bd9Sstevel@tonic-gate  *	clear endpoint stall and reset pipes
53117c478bd9Sstevel@tonic-gate  */
53127c478bd9Sstevel@tonic-gate int
scsa2usb_clear_ept_stall(scsa2usb_state_t * scsa2usbp,uint_t ept_addr,usb_pipe_handle_t ph,char * what)53137c478bd9Sstevel@tonic-gate scsa2usb_clear_ept_stall(scsa2usb_state_t *scsa2usbp, uint_t ept_addr,
53147c478bd9Sstevel@tonic-gate     usb_pipe_handle_t ph, char *what)
53157c478bd9Sstevel@tonic-gate {
53167c478bd9Sstevel@tonic-gate 	int rval;
53177c478bd9Sstevel@tonic-gate 	dev_info_t *dip = scsa2usbp->scsa2usb_dip;
53187c478bd9Sstevel@tonic-gate 
53197c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
53207c478bd9Sstevel@tonic-gate 	if (!(SCSA2USB_DEVICE_ACCESS_OK(scsa2usbp))) {
53217c478bd9Sstevel@tonic-gate 
53227c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
53237c478bd9Sstevel@tonic-gate 	}
53247c478bd9Sstevel@tonic-gate 
53257c478bd9Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
53267c478bd9Sstevel@tonic-gate 	rval = usb_clr_feature(dip, USB_DEV_REQ_RCPT_EP, 0, ept_addr,
53277c478bd9Sstevel@tonic-gate 	    USB_FLAGS_SLEEP, NULL, NULL);
53287c478bd9Sstevel@tonic-gate 
53297c478bd9Sstevel@tonic-gate 	usb_pipe_reset(dip, ph, USB_FLAGS_SLEEP, NULL, NULL);
53307c478bd9Sstevel@tonic-gate 
53317c478bd9Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
53327c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
53337c478bd9Sstevel@tonic-gate 	    "scsa2usb_clear_ept_stall: on %s: ept = 0x%x rval = %d",
53347c478bd9Sstevel@tonic-gate 	    what, ept_addr, rval);
53357c478bd9Sstevel@tonic-gate 
53367c478bd9Sstevel@tonic-gate 	return (rval);
53377c478bd9Sstevel@tonic-gate }
53387c478bd9Sstevel@tonic-gate 
53397c478bd9Sstevel@tonic-gate 
53407c478bd9Sstevel@tonic-gate /*
53417c478bd9Sstevel@tonic-gate  * scsa2usb_pkt_completion:
53427c478bd9Sstevel@tonic-gate  *	Handle pkt completion.
53437c478bd9Sstevel@tonic-gate  */
53447c478bd9Sstevel@tonic-gate static void
scsa2usb_pkt_completion(scsa2usb_state_t * scsa2usbp,struct scsi_pkt * pkt)53457c478bd9Sstevel@tonic-gate scsa2usb_pkt_completion(scsa2usb_state_t *scsa2usbp, struct scsi_pkt *pkt)
53467c478bd9Sstevel@tonic-gate {
53477c478bd9Sstevel@tonic-gate 	scsa2usb_cmd_t *cmd = PKT2CMD(pkt);
5348d94492edSfb 	size_t len;
53497c478bd9Sstevel@tonic-gate 
53507c478bd9Sstevel@tonic-gate 	ASSERT(pkt);
53517c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
53527c478bd9Sstevel@tonic-gate 
53537c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
53547c478bd9Sstevel@tonic-gate 	    "scsa2usb_pkt_completion:\n\tscsa2usbp = 0x%p "
53557c478bd9Sstevel@tonic-gate 	    "reason=%d, status=%d state=0x%x stats=0x%x resid=0x%lx",
5356112116d8Sfb 	    (void *)scsa2usbp, pkt->pkt_reason, *(pkt->pkt_scbp),
53577c478bd9Sstevel@tonic-gate 	    pkt->pkt_state, pkt->pkt_statistics, pkt->pkt_resid);
53587c478bd9Sstevel@tonic-gate 
53597c478bd9Sstevel@tonic-gate 	if (pkt->pkt_reason == CMD_CMPLT) {
53607c478bd9Sstevel@tonic-gate 		pkt->pkt_state |= STATE_GOT_BUS | STATE_GOT_TARGET |
5361d94492edSfb 		    STATE_SENT_CMD | STATE_GOT_STATUS;
53627c478bd9Sstevel@tonic-gate 		if (cmd->cmd_xfercount) {
53637c478bd9Sstevel@tonic-gate 			pkt->pkt_state |= STATE_XFERRED_DATA;
53647c478bd9Sstevel@tonic-gate 		}
53657c478bd9Sstevel@tonic-gate 	} else {
53667c478bd9Sstevel@tonic-gate 		pkt->pkt_state |= STATE_GOT_BUS | STATE_GOT_TARGET |
5367d94492edSfb 		    STATE_SENT_CMD;
53687c478bd9Sstevel@tonic-gate 	}
53697c478bd9Sstevel@tonic-gate 
53707c478bd9Sstevel@tonic-gate 	/*
53717c478bd9Sstevel@tonic-gate 	 * don't zap the current state when in panic as this will
53727c478bd9Sstevel@tonic-gate 	 * make debugging harder
53737c478bd9Sstevel@tonic-gate 	 */
53747c478bd9Sstevel@tonic-gate 	if ((scsa2usbp->scsa2usb_cur_pkt == pkt) && !ddi_in_panic()) {
53757c478bd9Sstevel@tonic-gate 		SCSA2USB_RESET_CUR_PKT(scsa2usbp);
53767c478bd9Sstevel@tonic-gate 
5377d94492edSfb 		len = sizeof (scsa2usbp->scsa2usb_last_cmd.cdb);
5378d94492edSfb 		bzero(scsa2usbp->scsa2usb_last_cmd.cdb, len);
5379d94492edSfb 
5380d94492edSfb 		len = (len < cmd->cmd_cdblen) ? len : cmd->cmd_cdblen;
5381d94492edSfb 		USB_DPRINTF_L3(DPRINT_MASK_SCSA,
5382d94492edSfb 		    scsa2usbp->scsa2usb_log_handle,
5383112116d8Sfb 		    "scsa2usb_pkt_completion: save last cmd, len=%ld", len);
5384d94492edSfb 
53857c478bd9Sstevel@tonic-gate 		/* save the last command */
5386d94492edSfb 		bcopy(pkt->pkt_cdbp, scsa2usbp->scsa2usb_last_cmd.cdb, len);
53877c478bd9Sstevel@tonic-gate 
53887c478bd9Sstevel@tonic-gate 		/* reset the scsa2usb_last_cmd.status value */
53897c478bd9Sstevel@tonic-gate 		if ((pkt->pkt_cdbp[0] != SCMD_REQUEST_SENSE) &&
53907c478bd9Sstevel@tonic-gate 		    (pkt->pkt_cdbp[0] != SCMD_INQUIRY)) {
53917c478bd9Sstevel@tonic-gate 			scsa2usbp->scsa2usb_last_cmd.status = 0;
53927c478bd9Sstevel@tonic-gate 		}
53937c478bd9Sstevel@tonic-gate 
53947c478bd9Sstevel@tonic-gate 		/*
53957c478bd9Sstevel@tonic-gate 		 * set pkt state to NONE *before* calling back as the target
53967c478bd9Sstevel@tonic-gate 		 * driver will immediately submit the next packet
53977c478bd9Sstevel@tonic-gate 		 */
53987c478bd9Sstevel@tonic-gate 		scsa2usbp->scsa2usb_pkt_state = SCSA2USB_PKT_NONE;
53997c478bd9Sstevel@tonic-gate 	}
54007c478bd9Sstevel@tonic-gate 
54017c478bd9Sstevel@tonic-gate 	if (pkt->pkt_comp) {
54027c478bd9Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
54039c57abc8Ssrivijitha dugganapalli 		scsi_hba_pkt_comp(pkt);
54047c478bd9Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
54057c478bd9Sstevel@tonic-gate 
54067c478bd9Sstevel@tonic-gate 	}
54077c478bd9Sstevel@tonic-gate }
54087c478bd9Sstevel@tonic-gate 
54097c478bd9Sstevel@tonic-gate 
54107c478bd9Sstevel@tonic-gate /*
54117c478bd9Sstevel@tonic-gate  * Even handling functions:
54127c478bd9Sstevel@tonic-gate  *
54137c478bd9Sstevel@tonic-gate  * scsa2usb_reconnect_event_cb:
54147c478bd9Sstevel@tonic-gate  *	event handling
54157c478bd9Sstevel@tonic-gate  */
54167c478bd9Sstevel@tonic-gate static int
scsa2usb_reconnect_event_cb(dev_info_t * dip)54177c478bd9Sstevel@tonic-gate scsa2usb_reconnect_event_cb(dev_info_t *dip)
54187c478bd9Sstevel@tonic-gate {
54197c478bd9Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp =
54207c478bd9Sstevel@tonic-gate 	    ddi_get_soft_state(scsa2usb_statep, ddi_get_instance(dip));
54217c478bd9Sstevel@tonic-gate 	dev_info_t	*cdip;
54227c478bd9Sstevel@tonic-gate 	int		rval = USB_SUCCESS;
54237c478bd9Sstevel@tonic-gate 
54247c478bd9Sstevel@tonic-gate 	ASSERT(scsa2usbp != NULL);
54257c478bd9Sstevel@tonic-gate 
54267c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
5427112116d8Sfb 	    "scsa2usb_reconnect_event_cb: dip = 0x%p", (void *)dip);
54287c478bd9Sstevel@tonic-gate 
54297c478bd9Sstevel@tonic-gate 	scsa2usb_restore_device_state(dip, scsa2usbp);
54307c478bd9Sstevel@tonic-gate 
54314610e4a0Sfrits 	USB_DPRINTF_L0(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
54324610e4a0Sfrits 	    "Reinserted device is accessible again.");
54334610e4a0Sfrits 
5434*3fe80ca4SDan Cross 	ndi_devi_enter(dip);
54357c478bd9Sstevel@tonic-gate 	for (cdip = ddi_get_child(dip); cdip; ) {
54367c478bd9Sstevel@tonic-gate 		dev_info_t *next = ddi_get_next_sibling(cdip);
54377c478bd9Sstevel@tonic-gate 
54387c478bd9Sstevel@tonic-gate 		mutex_enter(&DEVI(cdip)->devi_lock);
54397c478bd9Sstevel@tonic-gate 		DEVI_SET_DEVICE_REINSERTED(cdip);
54407c478bd9Sstevel@tonic-gate 		mutex_exit(&DEVI(cdip)->devi_lock);
54417c478bd9Sstevel@tonic-gate 
54427c478bd9Sstevel@tonic-gate 		cdip = next;
54437c478bd9Sstevel@tonic-gate 	}
5444*3fe80ca4SDan Cross 	ndi_devi_exit(dip);
54457c478bd9Sstevel@tonic-gate 
54467c478bd9Sstevel@tonic-gate 	/* stop suppressing warnings */
54477c478bd9Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
54487c478bd9Sstevel@tonic-gate 	scsa2usbp->scsa2usb_warning_given = B_FALSE;
54497c478bd9Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
54507c478bd9Sstevel@tonic-gate 
54517c478bd9Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_ugen_hdl) {
54527c478bd9Sstevel@tonic-gate 		rval = usb_ugen_reconnect_ev_cb(
5453d94492edSfb 		    scsa2usbp->scsa2usb_ugen_hdl);
54547c478bd9Sstevel@tonic-gate 	}
54557c478bd9Sstevel@tonic-gate 
54567c478bd9Sstevel@tonic-gate 	return (rval);
54577c478bd9Sstevel@tonic-gate }
54587c478bd9Sstevel@tonic-gate 
54597c478bd9Sstevel@tonic-gate 
54607c478bd9Sstevel@tonic-gate /*
54617c478bd9Sstevel@tonic-gate  * scsa2usb_all_waitQs_empty:
54627c478bd9Sstevel@tonic-gate  *	check if all waitQs empty
54637c478bd9Sstevel@tonic-gate  */
54647c478bd9Sstevel@tonic-gate static int
scsa2usb_all_waitQs_empty(scsa2usb_state_t * scsa2usbp)54657c478bd9Sstevel@tonic-gate scsa2usb_all_waitQs_empty(scsa2usb_state_t *scsa2usbp)
54667c478bd9Sstevel@tonic-gate {
54677c478bd9Sstevel@tonic-gate 	uint_t	lun;
54687c478bd9Sstevel@tonic-gate 
54697c478bd9Sstevel@tonic-gate 	for (lun = 0; lun < SCSA2USB_MAX_LUNS; lun++) {
54707c478bd9Sstevel@tonic-gate 		if (usba_list_entry_count(
54717c478bd9Sstevel@tonic-gate 		    &scsa2usbp->scsa2usb_waitQ[lun])) {
54727c478bd9Sstevel@tonic-gate 
54737c478bd9Sstevel@tonic-gate 			return (USB_FAILURE);
54747c478bd9Sstevel@tonic-gate 		}
54757c478bd9Sstevel@tonic-gate 	}
54767c478bd9Sstevel@tonic-gate 
54777c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
54787c478bd9Sstevel@tonic-gate }
54797c478bd9Sstevel@tonic-gate 
54807c478bd9Sstevel@tonic-gate 
54817c478bd9Sstevel@tonic-gate /*
54827c478bd9Sstevel@tonic-gate  * scsa2usb_disconnect_event_cb:
54837c478bd9Sstevel@tonic-gate  *	callback for disconnect events
54847c478bd9Sstevel@tonic-gate  */
54857c478bd9Sstevel@tonic-gate static int
scsa2usb_disconnect_event_cb(dev_info_t * dip)54867c478bd9Sstevel@tonic-gate scsa2usb_disconnect_event_cb(dev_info_t *dip)
54877c478bd9Sstevel@tonic-gate {
54887c478bd9Sstevel@tonic-gate 	scsa2usb_state_t *scsa2usbp =
54897c478bd9Sstevel@tonic-gate 	    ddi_get_soft_state(scsa2usb_statep, ddi_get_instance(dip));
54907c478bd9Sstevel@tonic-gate 	dev_info_t	*cdip;
5491*3fe80ca4SDan Cross 	int		i;
54927c478bd9Sstevel@tonic-gate 	int		rval = USB_SUCCESS;
54937c478bd9Sstevel@tonic-gate 
54947c478bd9Sstevel@tonic-gate 	ASSERT(scsa2usbp != NULL);
54957c478bd9Sstevel@tonic-gate 
54967c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
5497112116d8Sfb 	    "scsa2usb_disconnect_event_cb: dip = 0x%p", (void *)dip);
54987c478bd9Sstevel@tonic-gate 
54997c478bd9Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
55007c478bd9Sstevel@tonic-gate 	scsa2usbp->scsa2usb_dev_state = USB_DEV_DISCONNECTED;
55017c478bd9Sstevel@tonic-gate 
55027c478bd9Sstevel@tonic-gate 	/*
55037c478bd9Sstevel@tonic-gate 	 * wait till the work thread is done, carry on regardless
55047c478bd9Sstevel@tonic-gate 	 * if not.
55057c478bd9Sstevel@tonic-gate 	 */
55067c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCSA2USB_DRAIN_TIMEOUT; i++) {
55077c478bd9Sstevel@tonic-gate 		if ((scsa2usbp->scsa2usb_work_thread_id == NULL) &&
55087c478bd9Sstevel@tonic-gate 		    (scsa2usbp->scsa2usb_cur_pkt == NULL) &&
55097c478bd9Sstevel@tonic-gate 		    (scsa2usb_all_waitQs_empty(scsa2usbp) ==
55107c478bd9Sstevel@tonic-gate 		    USB_SUCCESS)) {
55117c478bd9Sstevel@tonic-gate 
55127c478bd9Sstevel@tonic-gate 			break;
55137c478bd9Sstevel@tonic-gate 		}
55147c478bd9Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
55157c478bd9Sstevel@tonic-gate 		delay(drv_usectohz(1000000));
55167c478bd9Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
55177c478bd9Sstevel@tonic-gate 	}
55187c478bd9Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
55197c478bd9Sstevel@tonic-gate 
5520*3fe80ca4SDan Cross 	ndi_devi_enter(dip);
55217c478bd9Sstevel@tonic-gate 	for (cdip = ddi_get_child(dip); cdip; ) {
55227c478bd9Sstevel@tonic-gate 		dev_info_t *next = ddi_get_next_sibling(cdip);
55237c478bd9Sstevel@tonic-gate 
55247c478bd9Sstevel@tonic-gate 		mutex_enter(&DEVI(cdip)->devi_lock);
55257c478bd9Sstevel@tonic-gate 		DEVI_SET_DEVICE_REMOVED(cdip);
55267c478bd9Sstevel@tonic-gate 		mutex_exit(&DEVI(cdip)->devi_lock);
55277c478bd9Sstevel@tonic-gate 
55287c478bd9Sstevel@tonic-gate 		cdip = next;
55297c478bd9Sstevel@tonic-gate 	}
5530*3fe80ca4SDan Cross 	ndi_devi_exit(dip);
55317c478bd9Sstevel@tonic-gate 
55327c478bd9Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_ugen_hdl) {
55337c478bd9Sstevel@tonic-gate 		rval = usb_ugen_disconnect_ev_cb(
5534d94492edSfb 		    scsa2usbp->scsa2usb_ugen_hdl);
55357c478bd9Sstevel@tonic-gate 	}
55367c478bd9Sstevel@tonic-gate 
55377c478bd9Sstevel@tonic-gate 	return (rval);
55387c478bd9Sstevel@tonic-gate }
55397c478bd9Sstevel@tonic-gate 
55407c478bd9Sstevel@tonic-gate 
55417c478bd9Sstevel@tonic-gate /*
55427c478bd9Sstevel@tonic-gate  * PM support
55437c478bd9Sstevel@tonic-gate  *
55447c478bd9Sstevel@tonic-gate  * scsa2usb_create_pm_components:
55457c478bd9Sstevel@tonic-gate  *	create the pm components required for power management
55467c478bd9Sstevel@tonic-gate  *	no mutex is need when calling USBA interfaces
55477c478bd9Sstevel@tonic-gate  */
55487c478bd9Sstevel@tonic-gate static void
scsa2usb_create_pm_components(dev_info_t * dip,scsa2usb_state_t * scsa2usbp)55497c478bd9Sstevel@tonic-gate scsa2usb_create_pm_components(dev_info_t *dip, scsa2usb_state_t *scsa2usbp)
55507c478bd9Sstevel@tonic-gate {
55517c478bd9Sstevel@tonic-gate 	scsa2usb_power_t *pm;
55527c478bd9Sstevel@tonic-gate 	uint_t		pwr_states;
55537c478bd9Sstevel@tonic-gate 
55547c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
55557c478bd9Sstevel@tonic-gate 
55567c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_PM, scsa2usbp->scsa2usb_log_handle,
55577c478bd9Sstevel@tonic-gate 	    "scsa2usb_create_pm_components: dip = 0x%p, scsa2usbp = 0x%p",
5558112116d8Sfb 	    (void *)dip, (void *)scsa2usbp);
55597c478bd9Sstevel@tonic-gate 
55607c478bd9Sstevel@tonic-gate 	/*
556147b9747fSJoshua M. Clulow 	 * Check if power management is disabled by a per-device quirk:
55627c478bd9Sstevel@tonic-gate 	 */
55637c478bd9Sstevel@tonic-gate 	if ((scsa2usbp->scsa2usb_attrs & SCSA2USB_ATTRS_PM) == 0) {
55647c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_PM, scsa2usbp->scsa2usb_log_handle,
55657c478bd9Sstevel@tonic-gate 		    "device cannot be power managed");
55667c478bd9Sstevel@tonic-gate 		return;
55677c478bd9Sstevel@tonic-gate 	}
55687c478bd9Sstevel@tonic-gate 
55697c478bd9Sstevel@tonic-gate 	/* Allocate the PM state structure */
55707c478bd9Sstevel@tonic-gate 	pm = kmem_zalloc(sizeof (scsa2usb_power_t), KM_SLEEP);
55717c478bd9Sstevel@tonic-gate 
55727c478bd9Sstevel@tonic-gate 	scsa2usbp->scsa2usb_pm = pm;
55737c478bd9Sstevel@tonic-gate 	pm->scsa2usb_current_power = USB_DEV_OS_FULL_PWR;
55747c478bd9Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
55757c478bd9Sstevel@tonic-gate 
55767c478bd9Sstevel@tonic-gate 	if (usb_create_pm_components(dip, &pwr_states) ==
55777c478bd9Sstevel@tonic-gate 	    USB_SUCCESS) {
55787c478bd9Sstevel@tonic-gate 		if (usb_handle_remote_wakeup(dip,
55797c478bd9Sstevel@tonic-gate 		    USB_REMOTE_WAKEUP_ENABLE) == USB_SUCCESS) {
55807c478bd9Sstevel@tonic-gate 			pm->scsa2usb_wakeup_enabled = 1;
55817c478bd9Sstevel@tonic-gate 		}
55827c478bd9Sstevel@tonic-gate 
55837c478bd9Sstevel@tonic-gate 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
55847c478bd9Sstevel@tonic-gate 		pm->scsa2usb_pwr_states = (uint8_t)pwr_states;
5585496d8c83Sfrits 		scsa2usb_raise_power(scsa2usbp);
55867c478bd9Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
55877c478bd9Sstevel@tonic-gate 	}
55887c478bd9Sstevel@tonic-gate 
55897c478bd9Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
55907c478bd9Sstevel@tonic-gate }
55917c478bd9Sstevel@tonic-gate 
55927c478bd9Sstevel@tonic-gate 
55937c478bd9Sstevel@tonic-gate /*
55947c478bd9Sstevel@tonic-gate  * scsa2usb_raise_power:
55957c478bd9Sstevel@tonic-gate  *	check if the device is using full power or not
55967c478bd9Sstevel@tonic-gate  */
55977c478bd9Sstevel@tonic-gate static void
scsa2usb_raise_power(scsa2usb_state_t * scsa2usbp)55987c478bd9Sstevel@tonic-gate scsa2usb_raise_power(scsa2usb_state_t *scsa2usbp)
55997c478bd9Sstevel@tonic-gate {
56007c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_PM, scsa2usbp->scsa2usb_log_handle,
56017c478bd9Sstevel@tonic-gate 	    "scsa2usb_raise_power:");
56027c478bd9Sstevel@tonic-gate 
56037c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
56047c478bd9Sstevel@tonic-gate 
56057c478bd9Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_pm) {
56067c478bd9Sstevel@tonic-gate 		scsa2usb_pm_busy_component(scsa2usbp);
5607496d8c83Sfrits 		if (scsa2usbp->scsa2usb_pm->scsa2usb_current_power !=
5608496d8c83Sfrits 		    USB_DEV_OS_FULL_PWR) {
56097c478bd9Sstevel@tonic-gate 			mutex_exit(&scsa2usbp->scsa2usb_mutex);
56107c478bd9Sstevel@tonic-gate 			(void) pm_raise_power(scsa2usbp->scsa2usb_dip,
56117c478bd9Sstevel@tonic-gate 			    0, USB_DEV_OS_FULL_PWR);
56127c478bd9Sstevel@tonic-gate 			mutex_enter(&scsa2usbp->scsa2usb_mutex);
56137c478bd9Sstevel@tonic-gate 		}
56147c478bd9Sstevel@tonic-gate 	}
56157c478bd9Sstevel@tonic-gate }
56167c478bd9Sstevel@tonic-gate 
56177c478bd9Sstevel@tonic-gate 
56187c478bd9Sstevel@tonic-gate /*
56197c478bd9Sstevel@tonic-gate  * functions to handle power transition for OS levels 0 -> 3
56207c478bd9Sstevel@tonic-gate  */
56217c478bd9Sstevel@tonic-gate static int
scsa2usb_pwrlvl0(scsa2usb_state_t * scsa2usbp)56227c478bd9Sstevel@tonic-gate scsa2usb_pwrlvl0(scsa2usb_state_t *scsa2usbp)
56237c478bd9Sstevel@tonic-gate {
56247c478bd9Sstevel@tonic-gate 	int	rval;
56257c478bd9Sstevel@tonic-gate 
56267c478bd9Sstevel@tonic-gate 	switch (scsa2usbp->scsa2usb_dev_state) {
56277c478bd9Sstevel@tonic-gate 	case USB_DEV_ONLINE:
56287c478bd9Sstevel@tonic-gate 		/* Deny the powerdown request if the device is busy */
56297c478bd9Sstevel@tonic-gate 		if (scsa2usbp->scsa2usb_pm->scsa2usb_pm_busy != 0) {
56307c478bd9Sstevel@tonic-gate 
56317c478bd9Sstevel@tonic-gate 			return (USB_FAILURE);
56327c478bd9Sstevel@tonic-gate 		}
56337c478bd9Sstevel@tonic-gate 
56347c478bd9Sstevel@tonic-gate 		/*
56357c478bd9Sstevel@tonic-gate 		 * stop polling on interrupt pipe
56367c478bd9Sstevel@tonic-gate 		 */
56377c478bd9Sstevel@tonic-gate 		scsa2usb_cbi_stop_intr_polling(scsa2usbp);
56387c478bd9Sstevel@tonic-gate 
56397c478bd9Sstevel@tonic-gate 		/* Issue USB D3 command to the device here */
56407c478bd9Sstevel@tonic-gate 		rval = usb_set_device_pwrlvl3(scsa2usbp->scsa2usb_dip);
56417c478bd9Sstevel@tonic-gate 		ASSERT(rval == USB_SUCCESS);
56427c478bd9Sstevel@tonic-gate 
56437c478bd9Sstevel@tonic-gate 		scsa2usbp->scsa2usb_dev_state = USB_DEV_PWRED_DOWN;
56447c478bd9Sstevel@tonic-gate 
56457c478bd9Sstevel@tonic-gate 		/* FALLTHRU */
56467c478bd9Sstevel@tonic-gate 	case USB_DEV_DISCONNECTED:
56477c478bd9Sstevel@tonic-gate 	case USB_DEV_SUSPENDED:
56487c478bd9Sstevel@tonic-gate 	case USB_DEV_PWRED_DOWN:
56497c478bd9Sstevel@tonic-gate 	default:
56507c478bd9Sstevel@tonic-gate 		scsa2usbp->scsa2usb_pm->scsa2usb_current_power =
5651d94492edSfb 		    USB_DEV_OS_PWR_OFF;
56527c478bd9Sstevel@tonic-gate 
56537c478bd9Sstevel@tonic-gate 		return (USB_SUCCESS);
56547c478bd9Sstevel@tonic-gate 	}
56557c478bd9Sstevel@tonic-gate }
56567c478bd9Sstevel@tonic-gate 
56577c478bd9Sstevel@tonic-gate 
56587c478bd9Sstevel@tonic-gate static int
scsa2usb_pwrlvl1(scsa2usb_state_t * scsa2usbp)56597c478bd9Sstevel@tonic-gate scsa2usb_pwrlvl1(scsa2usb_state_t *scsa2usbp)
56607c478bd9Sstevel@tonic-gate {
56617c478bd9Sstevel@tonic-gate 	int	rval;
56627c478bd9Sstevel@tonic-gate 
56637c478bd9Sstevel@tonic-gate 	/* Issue USB D2 command to the device here */
56647c478bd9Sstevel@tonic-gate 	rval = usb_set_device_pwrlvl2(scsa2usbp->scsa2usb_dip);
56657c478bd9Sstevel@tonic-gate 	ASSERT(rval == USB_SUCCESS);
56667c478bd9Sstevel@tonic-gate 
56677c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
56687c478bd9Sstevel@tonic-gate }
56697c478bd9Sstevel@tonic-gate 
56707c478bd9Sstevel@tonic-gate 
56717c478bd9Sstevel@tonic-gate static int
scsa2usb_pwrlvl2(scsa2usb_state_t * scsa2usbp)56727c478bd9Sstevel@tonic-gate scsa2usb_pwrlvl2(scsa2usb_state_t *scsa2usbp)
56737c478bd9Sstevel@tonic-gate {
56747c478bd9Sstevel@tonic-gate 	int	rval;
56757c478bd9Sstevel@tonic-gate 
56767c478bd9Sstevel@tonic-gate 	/* Issue USB D1 command to the device here */
56777c478bd9Sstevel@tonic-gate 	rval = usb_set_device_pwrlvl1(scsa2usbp->scsa2usb_dip);
56787c478bd9Sstevel@tonic-gate 	ASSERT(rval == USB_SUCCESS);
56797c478bd9Sstevel@tonic-gate 
56807c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
56817c478bd9Sstevel@tonic-gate }
56827c478bd9Sstevel@tonic-gate 
56837c478bd9Sstevel@tonic-gate 
56847c478bd9Sstevel@tonic-gate static int
scsa2usb_pwrlvl3(scsa2usb_state_t * scsa2usbp)56857c478bd9Sstevel@tonic-gate scsa2usb_pwrlvl3(scsa2usb_state_t *scsa2usbp)
56867c478bd9Sstevel@tonic-gate {
56877c478bd9Sstevel@tonic-gate 	int	rval;
56887c478bd9Sstevel@tonic-gate 
56897c478bd9Sstevel@tonic-gate 	/*
56907c478bd9Sstevel@tonic-gate 	 * PM framework tries to put us in full power
56917c478bd9Sstevel@tonic-gate 	 * during system shutdown. If we are disconnected
56927c478bd9Sstevel@tonic-gate 	 * return success anyways
56937c478bd9Sstevel@tonic-gate 	 */
56947c478bd9Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_dev_state != USB_DEV_DISCONNECTED) {
56957c478bd9Sstevel@tonic-gate 		/* Issue USB D0 command to the device here */
56967c478bd9Sstevel@tonic-gate 		rval = usb_set_device_pwrlvl0(scsa2usbp->scsa2usb_dip);
56977c478bd9Sstevel@tonic-gate 		ASSERT(rval == USB_SUCCESS);
56987c478bd9Sstevel@tonic-gate 
56997c478bd9Sstevel@tonic-gate 		scsa2usbp->scsa2usb_dev_state = USB_DEV_ONLINE;
57007c478bd9Sstevel@tonic-gate 	}
57017c478bd9Sstevel@tonic-gate 	scsa2usbp->scsa2usb_pm->scsa2usb_current_power = USB_DEV_OS_FULL_PWR;
57027c478bd9Sstevel@tonic-gate 
57037c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
57047c478bd9Sstevel@tonic-gate }
57057c478bd9Sstevel@tonic-gate 
57067c478bd9Sstevel@tonic-gate 
57077c478bd9Sstevel@tonic-gate /*
57087c478bd9Sstevel@tonic-gate  * scsa2usb_power:
57097c478bd9Sstevel@tonic-gate  *	power entry point
57107c478bd9Sstevel@tonic-gate  */
57117c478bd9Sstevel@tonic-gate /* ARGSUSED */
57127c478bd9Sstevel@tonic-gate static int
scsa2usb_power(dev_info_t * dip,int comp,int level)57137c478bd9Sstevel@tonic-gate scsa2usb_power(dev_info_t *dip, int comp, int level)
57147c478bd9Sstevel@tonic-gate {
57157c478bd9Sstevel@tonic-gate 	scsa2usb_state_t	*scsa2usbp;
57167c478bd9Sstevel@tonic-gate 	scsa2usb_power_t	*pm;
57177c478bd9Sstevel@tonic-gate 	int			rval = DDI_FAILURE;
57187c478bd9Sstevel@tonic-gate 
57197c478bd9Sstevel@tonic-gate 	scsa2usbp = ddi_get_soft_state(scsa2usb_statep, ddi_get_instance(dip));
57207c478bd9Sstevel@tonic-gate 
57217c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_PM, scsa2usbp->scsa2usb_log_handle,
57227c478bd9Sstevel@tonic-gate 	    "scsa2usb_power: Begin scsa2usbp (%p): level = %d",
5723112116d8Sfb 	    (void *)scsa2usbp, level);
57247c478bd9Sstevel@tonic-gate 
57257c478bd9Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
57267c478bd9Sstevel@tonic-gate 	if (SCSA2USB_BUSY(scsa2usbp)) {
57277c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_PM, scsa2usbp->scsa2usb_log_handle,
57287c478bd9Sstevel@tonic-gate 		    "scsa2usb_power: busy");
57297c478bd9Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
57307c478bd9Sstevel@tonic-gate 
57317c478bd9Sstevel@tonic-gate 		return (rval);
57327c478bd9Sstevel@tonic-gate 	}
57337c478bd9Sstevel@tonic-gate 
57347c478bd9Sstevel@tonic-gate 	pm = scsa2usbp->scsa2usb_pm;
57357c478bd9Sstevel@tonic-gate 	if (pm == NULL) {
57367c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_PM, scsa2usbp->scsa2usb_log_handle,
57377c478bd9Sstevel@tonic-gate 		    "scsa2usb_power: pm NULL");
57387c478bd9Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
57397c478bd9Sstevel@tonic-gate 
57407c478bd9Sstevel@tonic-gate 		return (rval);
57417c478bd9Sstevel@tonic-gate 	}
57427c478bd9Sstevel@tonic-gate 
57437c478bd9Sstevel@tonic-gate 	/* check if we are transitioning to a legal power level */
57447c478bd9Sstevel@tonic-gate 	if (USB_DEV_PWRSTATE_OK(pm->scsa2usb_pwr_states, level)) {
57457c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_PM, scsa2usbp->scsa2usb_log_handle,
57467c478bd9Sstevel@tonic-gate 		    "scsa2usb_power: illegal power level = %d "
57477c478bd9Sstevel@tonic-gate 		    "pwr_states: %x", level, pm->scsa2usb_pwr_states);
57487c478bd9Sstevel@tonic-gate 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
57497c478bd9Sstevel@tonic-gate 
57507c478bd9Sstevel@tonic-gate 		return (rval);
57517c478bd9Sstevel@tonic-gate 	}
57527c478bd9Sstevel@tonic-gate 
57537c478bd9Sstevel@tonic-gate 	switch (level) {
57547c478bd9Sstevel@tonic-gate 	case USB_DEV_OS_PWR_OFF :
57557c478bd9Sstevel@tonic-gate 		rval = scsa2usb_pwrlvl0(scsa2usbp);
57567c478bd9Sstevel@tonic-gate 		break;
57577c478bd9Sstevel@tonic-gate 	case USB_DEV_OS_PWR_1 :
57587c478bd9Sstevel@tonic-gate 		rval = scsa2usb_pwrlvl1(scsa2usbp);
57597c478bd9Sstevel@tonic-gate 		break;
57607c478bd9Sstevel@tonic-gate 	case USB_DEV_OS_PWR_2 :
57617c478bd9Sstevel@tonic-gate 		rval = scsa2usb_pwrlvl2(scsa2usbp);
57627c478bd9Sstevel@tonic-gate 		break;
57637c478bd9Sstevel@tonic-gate 	case USB_DEV_OS_FULL_PWR :
57647c478bd9Sstevel@tonic-gate 		rval = scsa2usb_pwrlvl3(scsa2usbp);
57657c478bd9Sstevel@tonic-gate 		break;
57667c478bd9Sstevel@tonic-gate 	}
57677c478bd9Sstevel@tonic-gate 
57687c478bd9Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
57697c478bd9Sstevel@tonic-gate 
57707c478bd9Sstevel@tonic-gate 	return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
57717c478bd9Sstevel@tonic-gate }
57727c478bd9Sstevel@tonic-gate 
57737c478bd9Sstevel@tonic-gate 
57747c478bd9Sstevel@tonic-gate static void
scsa2usb_pm_busy_component(scsa2usb_state_t * scsa2usbp)5775496d8c83Sfrits scsa2usb_pm_busy_component(scsa2usb_state_t *scsa2usbp)
57767c478bd9Sstevel@tonic-gate {
5777496d8c83Sfrits 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
57787c478bd9Sstevel@tonic-gate 
5779496d8c83Sfrits 	if (scsa2usbp->scsa2usb_pm) {
5780496d8c83Sfrits 		scsa2usbp->scsa2usb_pm->scsa2usb_pm_busy++;
57817c478bd9Sstevel@tonic-gate 
5782496d8c83Sfrits 		USB_DPRINTF_L4(DPRINT_MASK_PM,
5783496d8c83Sfrits 		    scsa2usbp->scsa2usb_log_handle,
5784496d8c83Sfrits 		    "scsa2usb_pm_busy_component: %d",
5785496d8c83Sfrits 		    scsa2usbp->scsa2usb_pm->scsa2usb_pm_busy);
5786496d8c83Sfrits 
5787496d8c83Sfrits 		mutex_exit(&scsa2usbp->scsa2usb_mutex);
5788496d8c83Sfrits 
5789496d8c83Sfrits 		if (pm_busy_component(scsa2usbp->scsa2usb_dip, 0) !=
5790496d8c83Sfrits 		    DDI_SUCCESS) {
5791496d8c83Sfrits 			mutex_enter(&scsa2usbp->scsa2usb_mutex);
5792496d8c83Sfrits 			ASSERT(scsa2usbp->scsa2usb_pm->scsa2usb_pm_busy > 0);
5793496d8c83Sfrits 			scsa2usbp->scsa2usb_pm->scsa2usb_pm_busy--;
57947c478bd9Sstevel@tonic-gate 
5795496d8c83Sfrits 			USB_DPRINTF_L2(DPRINT_MASK_PM,
5796496d8c83Sfrits 			    scsa2usbp->scsa2usb_log_handle,
5797496d8c83Sfrits 			    "scsa2usb_pm_busy_component failed: %d",
5798496d8c83Sfrits 			    scsa2usbp->scsa2usb_pm->scsa2usb_pm_busy);
57997c478bd9Sstevel@tonic-gate 
5800496d8c83Sfrits 			return;
5801496d8c83Sfrits 		}
5802496d8c83Sfrits 		mutex_enter(&scsa2usbp->scsa2usb_mutex);
5803496d8c83Sfrits 	}
58047c478bd9Sstevel@tonic-gate }
58057c478bd9Sstevel@tonic-gate 
58067c478bd9Sstevel@tonic-gate 
58077c478bd9Sstevel@tonic-gate /*
58087c478bd9Sstevel@tonic-gate  * scsa2usb_pm_idle_component:
58097c478bd9Sstevel@tonic-gate  *	idles the device
58107c478bd9Sstevel@tonic-gate  */
58117c478bd9Sstevel@tonic-gate static void
scsa2usb_pm_idle_component(scsa2usb_state_t * scsa2usbp)58127c478bd9Sstevel@tonic-gate scsa2usb_pm_idle_component(scsa2usb_state_t *scsa2usbp)
58137c478bd9Sstevel@tonic-gate {
5814496d8c83Sfrits 	ASSERT(!mutex_owned(&scsa2usbp->scsa2usb_mutex));
5815496d8c83Sfrits 
58167c478bd9Sstevel@tonic-gate 	if (scsa2usbp->scsa2usb_pm) {
58177c478bd9Sstevel@tonic-gate 		if (pm_idle_component(scsa2usbp->scsa2usb_dip, 0) ==
58187c478bd9Sstevel@tonic-gate 		    DDI_SUCCESS) {
58197c478bd9Sstevel@tonic-gate 			mutex_enter(&scsa2usbp->scsa2usb_mutex);
58207c478bd9Sstevel@tonic-gate 			ASSERT(scsa2usbp->scsa2usb_pm->scsa2usb_pm_busy > 0);
58217c478bd9Sstevel@tonic-gate 			scsa2usbp->scsa2usb_pm->scsa2usb_pm_busy--;
5822496d8c83Sfrits 
5823496d8c83Sfrits 			USB_DPRINTF_L4(DPRINT_MASK_PM,
5824496d8c83Sfrits 			    scsa2usbp->scsa2usb_log_handle,
5825496d8c83Sfrits 			    "scsa2usb_pm_idle_component: %d",
5826496d8c83Sfrits 			    scsa2usbp->scsa2usb_pm->scsa2usb_pm_busy);
5827496d8c83Sfrits 
58287c478bd9Sstevel@tonic-gate 			mutex_exit(&scsa2usbp->scsa2usb_mutex);
58297c478bd9Sstevel@tonic-gate 		}
58307c478bd9Sstevel@tonic-gate 	}
58317c478bd9Sstevel@tonic-gate }
58327c478bd9Sstevel@tonic-gate 
58337c478bd9Sstevel@tonic-gate 
58347c478bd9Sstevel@tonic-gate #ifdef	DEBUG
58357c478bd9Sstevel@tonic-gate /*
58367c478bd9Sstevel@tonic-gate  * scsa2usb_print_cdb:
58377c478bd9Sstevel@tonic-gate  *	prints CDB
58387c478bd9Sstevel@tonic-gate  */
58397c478bd9Sstevel@tonic-gate void
scsa2usb_print_cdb(scsa2usb_state_t * scsa2usbp,scsa2usb_cmd_t * cmd)58407c478bd9Sstevel@tonic-gate scsa2usb_print_cdb(scsa2usb_state_t *scsa2usbp, scsa2usb_cmd_t *cmd)
58417c478bd9Sstevel@tonic-gate {
58427c478bd9Sstevel@tonic-gate 	uchar_t *c = (uchar_t *)&cmd->cmd_cdb;
58437c478bd9Sstevel@tonic-gate 
58447c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
58457c478bd9Sstevel@tonic-gate 	    "cmd = 0x%p opcode=%s "
58467c478bd9Sstevel@tonic-gate 	    "cdb: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x",
5847112116d8Sfb 	    (void *)cmd,
5848112116d8Sfb 	    scsi_cname(cmd->cmd_cdb[SCSA2USB_OPCODE], scsa2usb_cmds),
58497c478bd9Sstevel@tonic-gate 	    c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7], c[8],
58507c478bd9Sstevel@tonic-gate 	    c[9], c[10], c[11], c[12], c[13], c[14], c[15]);
58517c478bd9Sstevel@tonic-gate }
58527c478bd9Sstevel@tonic-gate #endif	/* DEBUG */
58537c478bd9Sstevel@tonic-gate 
58547c478bd9Sstevel@tonic-gate 
58557c478bd9Sstevel@tonic-gate #ifdef	SCSA2USB_BULK_ONLY_TEST
58567c478bd9Sstevel@tonic-gate /*
58577c478bd9Sstevel@tonic-gate  * scsa2usb_test_mblk:
58587c478bd9Sstevel@tonic-gate  *	This function sends a dummy data mblk_t to simulate
58597c478bd9Sstevel@tonic-gate  *	the following test cases: 5 and 11.
58607c478bd9Sstevel@tonic-gate  */
58617c478bd9Sstevel@tonic-gate static void
scsa2usb_test_mblk(scsa2usb_state_t * scsa2usbp,boolean_t large)58627c478bd9Sstevel@tonic-gate scsa2usb_test_mblk(scsa2usb_state_t *scsa2usbp, boolean_t large)
58637c478bd9Sstevel@tonic-gate {
58647c478bd9Sstevel@tonic-gate 	int			i, rval;
58657c478bd9Sstevel@tonic-gate 	size_t			len;
58667c478bd9Sstevel@tonic-gate 	usb_flags_t		flags = USB_FLAGS_SLEEP;
58677c478bd9Sstevel@tonic-gate 	usb_bulk_req_t		*req;
58687c478bd9Sstevel@tonic-gate 
58697c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
58707c478bd9Sstevel@tonic-gate 
58717c478bd9Sstevel@tonic-gate 	/* should we create a larger mblk? */
58727c478bd9Sstevel@tonic-gate 	len = (large == B_TRUE) ? DEV_BSIZE : USB_BULK_CBWCMD_LEN;
58737c478bd9Sstevel@tonic-gate 
58747c478bd9Sstevel@tonic-gate 	req = scsa2usb_init_bulk_req(scsa2usbp, len,
5875d94492edSfb 	    SCSA2USB_BULK_PIPE_TIMEOUT, 0, flags);
58767c478bd9Sstevel@tonic-gate 
58777c478bd9Sstevel@tonic-gate 	/* fill up the data mblk */
58787c478bd9Sstevel@tonic-gate 	for (i = 0; i < len; i++) {
58797c478bd9Sstevel@tonic-gate 		*req->bulk_data->b_wptr++ = (uchar_t)i;
58807c478bd9Sstevel@tonic-gate 	}
58817c478bd9Sstevel@tonic-gate 
58827c478bd9Sstevel@tonic-gate 	mutex_exit(&scsa2usbp->scsa2usb_mutex);
58837c478bd9Sstevel@tonic-gate 	ASSERT(req->bulk_timeout);
58847c478bd9Sstevel@tonic-gate 	rval = usb_pipe_bulk_xfer(scsa2usbp->scsa2usb_bulkout_pipe, req, flags);
58857c478bd9Sstevel@tonic-gate 	mutex_enter(&scsa2usbp->scsa2usb_mutex);
58867c478bd9Sstevel@tonic-gate 
58877c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L1(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
58887c478bd9Sstevel@tonic-gate 	    "scsa2usb_test_mblk: Sent Data Out rval = 0x%x", rval);
58897c478bd9Sstevel@tonic-gate 
58907c478bd9Sstevel@tonic-gate 	usb_free_bulk_req(req);
58917c478bd9Sstevel@tonic-gate }
58927c478bd9Sstevel@tonic-gate #endif	/* SCSA2USB_BULK_ONLY_TEST */
5893