10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
51984Scg149915 * Common Development and Distribution License (the "License").
61984Scg149915 * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*11427SVincent.Wang@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate
270Sstevel@tonic-gate /*
280Sstevel@tonic-gate * scsa2usb bridge nexus driver:
290Sstevel@tonic-gate *
300Sstevel@tonic-gate * This driver supports the following wire transports:
310Sstevel@tonic-gate * a. Bulk Only transport (see usb_ms_bulkonly.c)
320Sstevel@tonic-gate * b. CB transport (see usb_ms_cbi.c)
330Sstevel@tonic-gate * c. CBI transport with interrupt status completion (see usb_ms_cbi.c)
340Sstevel@tonic-gate *
350Sstevel@tonic-gate * It handles the following command sets:
360Sstevel@tonic-gate * a. SCSI
370Sstevel@tonic-gate * b. ATAPI command set (subset of SCSI command set)
380Sstevel@tonic-gate * c. UFI command set (
390Sstevel@tonic-gate * http://www.usb.org/developers/devclass_docs/usbmass-ufi10.pdf)
400Sstevel@tonic-gate *
410Sstevel@tonic-gate * For details on USB Mass Storage Class overview:
420Sstevel@tonic-gate * http://www.usb.org/developers/devclass_docs/usbmassover_11.pdf
430Sstevel@tonic-gate */
440Sstevel@tonic-gate #if defined(lint) && !defined(DEBUG)
450Sstevel@tonic-gate #define DEBUG 1
460Sstevel@tonic-gate #endif
470Sstevel@tonic-gate
480Sstevel@tonic-gate #include <sys/usb/usba/usbai_version.h>
490Sstevel@tonic-gate #include <sys/scsi/scsi.h>
500Sstevel@tonic-gate #include <sys/cdio.h>
510Sstevel@tonic-gate #include <sys/sunndi.h>
520Sstevel@tonic-gate #include <sys/esunddi.h>
530Sstevel@tonic-gate #include <sys/callb.h>
540Sstevel@tonic-gate #include <sys/kobj.h>
550Sstevel@tonic-gate #include <sys/kobj_lex.h>
560Sstevel@tonic-gate #include <sys/strsubr.h>
577492SZhigang.Lu@Sun.COM #include <sys/strsun.h>
580Sstevel@tonic-gate #include <sys/sysmacros.h>
590Sstevel@tonic-gate
600Sstevel@tonic-gate #include <sys/usb/usba.h>
61*11427SVincent.Wang@Sun.COM #include <sys/usb/clients/ugen/usb_ugen.h>
620Sstevel@tonic-gate #include <sys/usb/usba/usba_ugen.h>
630Sstevel@tonic-gate
640Sstevel@tonic-gate #include <sys/usb/usba/usba_private.h>
65*11427SVincent.Wang@Sun.COM #include <sys/usb/usba/usba_ugend.h>
660Sstevel@tonic-gate #include <sys/usb/clients/mass_storage/usb_bulkonly.h>
670Sstevel@tonic-gate #include <sys/usb/scsa2usb/scsa2usb.h>
680Sstevel@tonic-gate
690Sstevel@tonic-gate /*
700Sstevel@tonic-gate * Function Prototypes
710Sstevel@tonic-gate */
720Sstevel@tonic-gate static int scsa2usb_attach(dev_info_t *, ddi_attach_cmd_t);
730Sstevel@tonic-gate static int scsa2usb_info(dev_info_t *, ddi_info_cmd_t, void *,
740Sstevel@tonic-gate void **);
750Sstevel@tonic-gate static int scsa2usb_detach(dev_info_t *, ddi_detach_cmd_t);
760Sstevel@tonic-gate static int scsa2usb_cleanup(dev_info_t *, scsa2usb_state_t *);
770Sstevel@tonic-gate static void scsa2usb_validate_attrs(scsa2usb_state_t *);
780Sstevel@tonic-gate static void scsa2usb_create_luns(scsa2usb_state_t *);
790Sstevel@tonic-gate static int scsa2usb_is_usb(dev_info_t *);
808003SVitezslav.Batrla@Sun.COM static void scsa2usb_fake_inquiry(scsa2usb_state_t *,
818003SVitezslav.Batrla@Sun.COM struct scsi_inquiry *);
820Sstevel@tonic-gate static void scsa2usb_do_inquiry(scsa2usb_state_t *,
830Sstevel@tonic-gate uint_t, uint_t);
842506Ssl147100 static int scsa2usb_do_tur(scsa2usb_state_t *, struct scsi_address *);
850Sstevel@tonic-gate
860Sstevel@tonic-gate /* override property handling */
870Sstevel@tonic-gate static void scsa2usb_override(scsa2usb_state_t *);
880Sstevel@tonic-gate static int scsa2usb_parse_input_str(char *, scsa2usb_ov_t *,
890Sstevel@tonic-gate scsa2usb_state_t *);
900Sstevel@tonic-gate static void scsa2usb_override_error(char *, scsa2usb_state_t *);
910Sstevel@tonic-gate static char *scsa2usb_strtok_r(char *, char *, char **);
920Sstevel@tonic-gate
930Sstevel@tonic-gate
940Sstevel@tonic-gate /* PANIC callback handling */
950Sstevel@tonic-gate static void scsa2usb_panic_callb_init(scsa2usb_state_t *);
960Sstevel@tonic-gate static void scsa2usb_panic_callb_fini(scsa2usb_state_t *);
970Sstevel@tonic-gate static boolean_t scsa2usb_panic_callb(void *, int);
980Sstevel@tonic-gate
990Sstevel@tonic-gate /* SCSA support */
1000Sstevel@tonic-gate static int scsa2usb_scsi_tgt_probe(struct scsi_device *, int (*)(void));
1010Sstevel@tonic-gate static int scsa2usb_scsi_tgt_init(dev_info_t *, dev_info_t *,
1020Sstevel@tonic-gate scsi_hba_tran_t *, struct scsi_device *);
1030Sstevel@tonic-gate static void scsa2usb_scsi_tgt_free(dev_info_t *, dev_info_t *,
1040Sstevel@tonic-gate scsi_hba_tran_t *, struct scsi_device *);
1050Sstevel@tonic-gate static struct scsi_pkt *scsa2usb_scsi_init_pkt(struct scsi_address *,
1060Sstevel@tonic-gate struct scsi_pkt *, struct buf *, int, int,
1070Sstevel@tonic-gate int, int, int (*)(), caddr_t);
1080Sstevel@tonic-gate static void scsa2usb_scsi_destroy_pkt(struct scsi_address *,
1090Sstevel@tonic-gate struct scsi_pkt *);
1100Sstevel@tonic-gate static int scsa2usb_scsi_start(struct scsi_address *, struct scsi_pkt *);
1110Sstevel@tonic-gate static int scsa2usb_scsi_abort(struct scsi_address *, struct scsi_pkt *);
1120Sstevel@tonic-gate static int scsa2usb_scsi_reset(struct scsi_address *, int);
1130Sstevel@tonic-gate static int scsa2usb_scsi_getcap(struct scsi_address *, char *, int);
1140Sstevel@tonic-gate static int scsa2usb_scsi_setcap(struct scsi_address *, char *, int, int);
1150Sstevel@tonic-gate static int scsa2usb_scsi_bus_config(dev_info_t *, uint_t,
1160Sstevel@tonic-gate ddi_bus_config_op_t, void *, dev_info_t **);
1170Sstevel@tonic-gate static int scsa2usb_scsi_bus_unconfig(dev_info_t *, uint_t,
1180Sstevel@tonic-gate ddi_bus_config_op_t, void *);
1190Sstevel@tonic-gate
1200Sstevel@tonic-gate /* functions for command and transport support */
1210Sstevel@tonic-gate static void scsa2usb_prepare_pkt(scsa2usb_state_t *, struct scsi_pkt *);
1220Sstevel@tonic-gate static int scsa2usb_cmd_transport(scsa2usb_state_t *, scsa2usb_cmd_t *);
1230Sstevel@tonic-gate static int scsa2usb_check_bulkonly_blacklist_attrs(scsa2usb_state_t *,
1240Sstevel@tonic-gate scsa2usb_cmd_t *, uchar_t);
1250Sstevel@tonic-gate static int scsa2usb_check_ufi_blacklist_attrs(scsa2usb_state_t *, uchar_t,
1260Sstevel@tonic-gate scsa2usb_cmd_t *);
1270Sstevel@tonic-gate static int scsa2usb_handle_scsi_cmd_sub_class(scsa2usb_state_t *,
1280Sstevel@tonic-gate scsa2usb_cmd_t *, struct scsi_pkt *);
1290Sstevel@tonic-gate static int scsa2usb_handle_ufi_subclass_cmd(scsa2usb_state_t *,
1300Sstevel@tonic-gate scsa2usb_cmd_t *, struct scsi_pkt *);
1310Sstevel@tonic-gate
1320Sstevel@tonic-gate /* waitQ handling */
1330Sstevel@tonic-gate static void scsa2usb_work_thread(void *);
1340Sstevel@tonic-gate static void scsa2usb_transport_request(scsa2usb_state_t *, uint_t);
1350Sstevel@tonic-gate static void scsa2usb_flush_waitQ(scsa2usb_state_t *, uint_t, uchar_t);
1360Sstevel@tonic-gate static int scsa2usb_all_waitQs_empty(scsa2usb_state_t *);
1370Sstevel@tonic-gate
1380Sstevel@tonic-gate /* auto request sense handling */
1390Sstevel@tonic-gate static int scsa2usb_create_arq_pkt(scsa2usb_state_t *,
1400Sstevel@tonic-gate struct scsi_address *);
1410Sstevel@tonic-gate static void scsa2usb_delete_arq_pkt(scsa2usb_state_t *);
1420Sstevel@tonic-gate static void scsa2usb_complete_arq_pkt(scsa2usb_state_t *, struct scsi_pkt *,
1430Sstevel@tonic-gate scsa2usb_cmd_t *, struct buf *);
1440Sstevel@tonic-gate
1450Sstevel@tonic-gate /* utility functions for any transport */
1460Sstevel@tonic-gate static int scsa2usb_open_usb_pipes(scsa2usb_state_t *);
1470Sstevel@tonic-gate void scsa2usb_close_usb_pipes(scsa2usb_state_t *);
1480Sstevel@tonic-gate
1490Sstevel@tonic-gate static void scsa2usb_fill_up_cdb_len(scsa2usb_cmd_t *, int);
1500Sstevel@tonic-gate static void scsa2usb_fill_up_cdb_lba(scsa2usb_cmd_t *, int);
1510Sstevel@tonic-gate static void scsa2usb_fill_up_ReadCD_cdb_len(scsa2usb_cmd_t *, int, int);
1520Sstevel@tonic-gate static void scsa2usb_fill_up_12byte_cdb_len(scsa2usb_cmd_t *, int, int);
1530Sstevel@tonic-gate static int scsa2usb_read_cd_blk_size(uchar_t);
1540Sstevel@tonic-gate int scsa2usb_rw_transport(scsa2usb_state_t *, struct scsi_pkt *);
1550Sstevel@tonic-gate void scsa2usb_setup_next_xfer(scsa2usb_state_t *, scsa2usb_cmd_t *);
1560Sstevel@tonic-gate
1570Sstevel@tonic-gate static mblk_t *scsa2usb_bp_to_mblk(scsa2usb_state_t *);
1580Sstevel@tonic-gate int scsa2usb_handle_data_start(scsa2usb_state_t *,
1590Sstevel@tonic-gate scsa2usb_cmd_t *, usb_bulk_req_t *);
1600Sstevel@tonic-gate void scsa2usb_handle_data_done(scsa2usb_state_t *,
1610Sstevel@tonic-gate scsa2usb_cmd_t *cmd, usb_bulk_req_t *);
1620Sstevel@tonic-gate
1630Sstevel@tonic-gate usb_bulk_req_t *scsa2usb_init_bulk_req(scsa2usb_state_t *,
1640Sstevel@tonic-gate size_t, uint_t, usb_req_attrs_t, usb_flags_t);
1650Sstevel@tonic-gate int scsa2usb_bulk_timeout(int);
1660Sstevel@tonic-gate int scsa2usb_clear_ept_stall(scsa2usb_state_t *, uint_t,
1670Sstevel@tonic-gate usb_pipe_handle_t, char *);
1680Sstevel@tonic-gate static void scsa2usb_pkt_completion(scsa2usb_state_t *, struct scsi_pkt *);
1690Sstevel@tonic-gate
1700Sstevel@tonic-gate /* event handling */
1710Sstevel@tonic-gate static int scsa2usb_reconnect_event_cb(dev_info_t *);
1720Sstevel@tonic-gate static int scsa2usb_disconnect_event_cb(dev_info_t *);
1730Sstevel@tonic-gate static int scsa2usb_cpr_suspend(dev_info_t *);
1740Sstevel@tonic-gate static void scsa2usb_cpr_resume(dev_info_t *);
1750Sstevel@tonic-gate static void scsa2usb_restore_device_state(dev_info_t *, scsa2usb_state_t *);
1760Sstevel@tonic-gate
1770Sstevel@tonic-gate /* PM handling */
1780Sstevel@tonic-gate static void scsa2usb_create_pm_components(dev_info_t *, scsa2usb_state_t *);
1790Sstevel@tonic-gate static void scsa2usb_raise_power(scsa2usb_state_t *);
1800Sstevel@tonic-gate static int scsa2usb_pwrlvl0(scsa2usb_state_t *);
1810Sstevel@tonic-gate static int scsa2usb_pwrlvl1(scsa2usb_state_t *);
1820Sstevel@tonic-gate static int scsa2usb_pwrlvl2(scsa2usb_state_t *);
1830Sstevel@tonic-gate static int scsa2usb_pwrlvl3(scsa2usb_state_t *);
1840Sstevel@tonic-gate static int scsa2usb_power(dev_info_t *, int comp, int level);
1850Sstevel@tonic-gate static void scsa2usb_pm_busy_component(scsa2usb_state_t *);
1860Sstevel@tonic-gate static void scsa2usb_pm_idle_component(scsa2usb_state_t *);
1870Sstevel@tonic-gate
1880Sstevel@tonic-gate /* external functions for Bulk only (BO) support */
1890Sstevel@tonic-gate extern int scsa2usb_bulk_only_transport(scsa2usb_state_t *,
1900Sstevel@tonic-gate scsa2usb_cmd_t *);
1910Sstevel@tonic-gate extern int scsa2usb_bulk_only_get_max_lun(scsa2usb_state_t *);
1920Sstevel@tonic-gate
1930Sstevel@tonic-gate /* external functions for CB/CBI support */
1940Sstevel@tonic-gate extern int scsa2usb_cbi_transport(scsa2usb_state_t *, scsa2usb_cmd_t *);
1950Sstevel@tonic-gate extern void scsa2usb_cbi_stop_intr_polling(scsa2usb_state_t *);
1960Sstevel@tonic-gate
1970Sstevel@tonic-gate
1980Sstevel@tonic-gate /* cmd decoding */
1990Sstevel@tonic-gate static char *scsa2usb_cmds[] = {
2000Sstevel@tonic-gate "\000tur",
2010Sstevel@tonic-gate "\001rezero",
2020Sstevel@tonic-gate "\003rqsense",
2030Sstevel@tonic-gate "\004format",
2040Sstevel@tonic-gate "\014cartprot",
2050Sstevel@tonic-gate "\022inquiry",
2060Sstevel@tonic-gate "\026tranlba",
2070Sstevel@tonic-gate "\030fmtverify",
2080Sstevel@tonic-gate "\032modesense",
2090Sstevel@tonic-gate "\033start",
2100Sstevel@tonic-gate "\035snddiag",
2110Sstevel@tonic-gate "\036doorlock",
2120Sstevel@tonic-gate "\043formatcap",
2130Sstevel@tonic-gate "\045readcap",
2140Sstevel@tonic-gate "\050read10",
2150Sstevel@tonic-gate "\052write10",
2160Sstevel@tonic-gate "\053seek10",
2170Sstevel@tonic-gate "\056writeverify",
2180Sstevel@tonic-gate "\057verify",
2190Sstevel@tonic-gate "\065synchcache",
2200Sstevel@tonic-gate "\076readlong",
2210Sstevel@tonic-gate "\077writelong",
2220Sstevel@tonic-gate "\102readsubchan",
2230Sstevel@tonic-gate "\103readtoc",
2240Sstevel@tonic-gate "\104readhdr",
2250Sstevel@tonic-gate "\105playaudio10",
2260Sstevel@tonic-gate "\107playaudio_msf",
2270Sstevel@tonic-gate "\110playaudio_ti",
2280Sstevel@tonic-gate "\111playtrk_r10",
2290Sstevel@tonic-gate "\112geteventnotify",
2300Sstevel@tonic-gate "\113pause_resume",
2310Sstevel@tonic-gate "\116stop/play_scan",
2320Sstevel@tonic-gate "\121readdiscinfo",
2330Sstevel@tonic-gate "\122readtrkinfo",
2340Sstevel@tonic-gate "\123reservedtrk",
2350Sstevel@tonic-gate "\124sendopcinfo",
2360Sstevel@tonic-gate "\125modeselect",
2370Sstevel@tonic-gate "\132modesense",
2380Sstevel@tonic-gate "\133closetrksession",
2390Sstevel@tonic-gate "\135sendcuesheet",
2400Sstevel@tonic-gate "\136prin",
2410Sstevel@tonic-gate "\137prout",
2420Sstevel@tonic-gate "\241blankcd",
2430Sstevel@tonic-gate "\245playaudio12",
2440Sstevel@tonic-gate "\250read12",
2450Sstevel@tonic-gate "\251playtrk12",
2460Sstevel@tonic-gate "\252write12",
2470Sstevel@tonic-gate "\254getperf",
2480Sstevel@tonic-gate "\271readcdmsf",
2490Sstevel@tonic-gate "\273setcdspeed",
2500Sstevel@tonic-gate "\275mechanism_sts",
2510Sstevel@tonic-gate "\276readcd",
2520Sstevel@tonic-gate NULL
2530Sstevel@tonic-gate };
2540Sstevel@tonic-gate
2550Sstevel@tonic-gate
2560Sstevel@tonic-gate /*
2570Sstevel@tonic-gate * Mass-Storage devices masquerade as "sd" disks.
2580Sstevel@tonic-gate *
2590Sstevel@tonic-gate * These devices may not support all SCSI CDBs in their
2600Sstevel@tonic-gate * entirety due to their hardware implementation limitations.
2610Sstevel@tonic-gate *
2620Sstevel@tonic-gate * As such, following is a list of some of the black-listed
2630Sstevel@tonic-gate * devices w/ the attributes that they do not support.
2640Sstevel@tonic-gate * (See scsa2usb.h for description on each attribute)
2650Sstevel@tonic-gate */
2660Sstevel@tonic-gate #define X ((uint16_t)(-1))
2670Sstevel@tonic-gate
2680Sstevel@tonic-gate static struct blacklist {
2690Sstevel@tonic-gate uint16_t idVendor; /* vendor ID */
2700Sstevel@tonic-gate uint16_t idProduct; /* product ID */
2710Sstevel@tonic-gate uint16_t bcdDevice; /* device release number in bcd */
2720Sstevel@tonic-gate uint16_t attributes; /* attributes to blacklist */
2730Sstevel@tonic-gate } scsa2usb_blacklist[] = {
2740Sstevel@tonic-gate /* Iomega Zip100 drive (prototype) with flaky bridge */
2750Sstevel@tonic-gate {MS_IOMEGA_VID, MS_IOMEGA_PID1_ZIP100, 0,
2760Sstevel@tonic-gate SCSA2USB_ATTRS_GET_LUN | SCSA2USB_ATTRS_PM},
2770Sstevel@tonic-gate
2780Sstevel@tonic-gate /* Iomega Zip100 drive (newer model) with flaky bridge */
2790Sstevel@tonic-gate {MS_IOMEGA_VID, MS_IOMEGA_PID2_ZIP100, 0,
2800Sstevel@tonic-gate SCSA2USB_ATTRS_GET_LUN | SCSA2USB_ATTRS_PM},
2810Sstevel@tonic-gate
2820Sstevel@tonic-gate /* Iomega Zip100 drive (newer model) with flaky bridge */
2830Sstevel@tonic-gate {MS_IOMEGA_VID, MS_IOMEGA_PID3_ZIP100, 0,
2840Sstevel@tonic-gate SCSA2USB_ATTRS_GET_LUN | SCSA2USB_ATTRS_PM},
2850Sstevel@tonic-gate
2860Sstevel@tonic-gate /* Iomega Zip250 drive */
2870Sstevel@tonic-gate {MS_IOMEGA_VID, MS_IOMEGA_PID_ZIP250, 0, SCSA2USB_ATTRS_GET_LUN},
2880Sstevel@tonic-gate
2890Sstevel@tonic-gate /* Iomega Clik! drive */
2900Sstevel@tonic-gate {MS_IOMEGA_VID, MS_IOMEGA_PID_CLIK, 0,
2910Sstevel@tonic-gate SCSA2USB_ATTRS_GET_LUN | SCSA2USB_ATTRS_START_STOP},
2920Sstevel@tonic-gate
2939729SBinzi.Cao@Sun.COM /* Kingston DataTraveler Stick / PNY Attache Stick */
2949729SBinzi.Cao@Sun.COM {MS_TOSHIBA_VID, MS_TOSHIBA_PID0, 0,
2959729SBinzi.Cao@Sun.COM SCSA2USB_ATTRS_GET_LUN},
2969729SBinzi.Cao@Sun.COM
2979729SBinzi.Cao@Sun.COM /* PNY Floppy drive */
2989729SBinzi.Cao@Sun.COM {MS_PNY_VID, MS_PNY_PID0, 0,
2999729SBinzi.Cao@Sun.COM SCSA2USB_ATTRS_GET_LUN},
3009729SBinzi.Cao@Sun.COM
3010Sstevel@tonic-gate /* SMSC floppy Device - and its clones */
3020Sstevel@tonic-gate {MS_SMSC_VID, X, 0, SCSA2USB_ATTRS_START_STOP},
3030Sstevel@tonic-gate
3040Sstevel@tonic-gate /* Hagiwara SmartMedia Device */
3050Sstevel@tonic-gate {MS_HAGIWARA_SYS_COM_VID, MS_HAGIWARA_SYSCOM_PID1, 0,
3060Sstevel@tonic-gate SCSA2USB_ATTRS_GET_LUN | SCSA2USB_ATTRS_START_STOP},
3070Sstevel@tonic-gate
3080Sstevel@tonic-gate /* Hagiwara CompactFlash Device */
3090Sstevel@tonic-gate {MS_HAGIWARA_SYS_COM_VID, MS_HAGIWARA_SYSCOM_PID2, 0,
3100Sstevel@tonic-gate SCSA2USB_ATTRS_GET_LUN | SCSA2USB_ATTRS_START_STOP},
3110Sstevel@tonic-gate
3120Sstevel@tonic-gate /* Hagiwara SmartMedia/CompactFlash Combo Device */
3130Sstevel@tonic-gate {MS_HAGIWARA_SYS_COM_VID, MS_HAGIWARA_SYSCOM_PID3, 0,
3140Sstevel@tonic-gate SCSA2USB_ATTRS_START_STOP},
3150Sstevel@tonic-gate
3160Sstevel@tonic-gate /* Hagiwara new SM Device */
3170Sstevel@tonic-gate {MS_HAGIWARA_SYS_COM_VID, MS_HAGIWARA_SYSCOM_PID4, 0,
3180Sstevel@tonic-gate SCSA2USB_ATTRS_GET_LUN | SCSA2USB_ATTRS_START_STOP},
3190Sstevel@tonic-gate
3200Sstevel@tonic-gate /* Hagiwara new CF Device */
3210Sstevel@tonic-gate {MS_HAGIWARA_SYS_COM_VID, MS_HAGIWARA_SYSCOM_PID5, 0,
3220Sstevel@tonic-gate SCSA2USB_ATTRS_GET_LUN | SCSA2USB_ATTRS_START_STOP},
3230Sstevel@tonic-gate
3240Sstevel@tonic-gate /* Mitsumi CD-RW Device(s) */
3250Sstevel@tonic-gate {MS_MITSUMI_VID, X, X, SCSA2USB_ATTRS_BIG_TIMEOUT |
3260Sstevel@tonic-gate SCSA2USB_ATTRS_GET_CONF | SCSA2USB_ATTRS_GET_PERF},
3270Sstevel@tonic-gate
3280Sstevel@tonic-gate /* Neodio Technologies Corporation SM/CF/MS/SD Combo Device */
3290Sstevel@tonic-gate {MS_NEODIO_VID, MS_NEODIO_DEVICE_3050, 0,
3300Sstevel@tonic-gate SCSA2USB_ATTRS_MODE_SENSE },
3310Sstevel@tonic-gate
3320Sstevel@tonic-gate /* dumb flash devices */
3330Sstevel@tonic-gate {MS_SONY_FLASH_VID, MS_SONY_FLASH_PID, 0,
3340Sstevel@tonic-gate SCSA2USB_ATTRS_REDUCED_CMD},
3350Sstevel@tonic-gate
3360Sstevel@tonic-gate {MS_TREK_FLASH_VID, MS_TREK_FLASH_PID, 0,
3370Sstevel@tonic-gate SCSA2USB_ATTRS_REDUCED_CMD},
3380Sstevel@tonic-gate
3390Sstevel@tonic-gate {MS_PENN_FLASH_VID, MS_PENN_FLASH_PID, 0,
3400Sstevel@tonic-gate SCSA2USB_ATTRS_REDUCED_CMD},
3410Sstevel@tonic-gate
3420Sstevel@tonic-gate /* SimpleTech UCF-100 CF Device */
3430Sstevel@tonic-gate {MS_SIMPLETECH_VID, MS_SIMPLETECH_PID1, 0,
3440Sstevel@tonic-gate SCSA2USB_ATTRS_REDUCED_CMD},
3450Sstevel@tonic-gate
3460Sstevel@tonic-gate {MS_ADDONICS_CARD_READER_VID, MS_ADDONICS_CARD_READER_PID,
3470Sstevel@tonic-gate 0, SCSA2USB_ATTRS_REDUCED_CMD},
3481101Ssl147100
3491101Ssl147100 /* Acomdata 80GB USB/1394 Hard Disk */
3501101Ssl147100 {MS_ACOMDATA_VID, MS_ACOMDATA_PID1, 0,
3511101Ssl147100 SCSA2USB_ATTRS_USE_CSW_RESIDUE},
3521101Ssl147100
3531101Ssl147100 /* OTi6828 Flash Disk */
3541101Ssl147100 {MS_OTI_VID, MS_OTI_DEVICE_6828, 0,
3551101Ssl147100 SCSA2USB_ATTRS_USE_CSW_RESIDUE},
3562506Ssl147100
3572506Ssl147100 /* AMI Virtual Floppy */
3582506Ssl147100 {MS_AMI_VID, MS_AMI_VIRTUAL_FLOPPY, 0,
3592506Ssl147100 SCSA2USB_ATTRS_NO_MEDIA_CHECK},
3604834Sfb209375
3614834Sfb209375 /* ScanLogic USB Storage Device */
3624834Sfb209375 {MS_SCANLOGIC_VID, MS_SCANLOGIC_PID1, 0,
3635789Ssl147100 SCSA2USB_ATTRS_NO_CAP_ADJUST},
3645789Ssl147100
3655789Ssl147100 /* Super Top USB 2.0 IDE Device */
3665789Ssl147100 {MS_SUPERTOP_VID, MS_SUPERTOP_DEVICE_6600, 0,
3677231Slg150142 SCSA2USB_ATTRS_USE_CSW_RESIDUE},
3687231Slg150142
3697231Slg150142 /* Aigo Miniking Device NEHFSP14 */
3707231Slg150142 {MS_AIGO_VID, MS_AIGO_DEVICE_6981, 0,
3718075SGuoqing.Zhu@Sun.COM SCSA2USB_ATTRS_USE_CSW_RESIDUE},
3728075SGuoqing.Zhu@Sun.COM
3738075SGuoqing.Zhu@Sun.COM /* Alcor Micro Corp 6387 flash disk */
3748075SGuoqing.Zhu@Sun.COM {MS_ALCOR_VID, MS_ALCOR_PID0, 0,
37510678SGuoqing.Zhu@Sun.COM SCSA2USB_ATTRS_GET_LUN | SCSA2USB_ATTRS_USE_CSW_RESIDUE},
37610678SGuoqing.Zhu@Sun.COM
37710678SGuoqing.Zhu@Sun.COM /* Western Digital External HDD */
37810678SGuoqing.Zhu@Sun.COM {MS_WD_VID, MS_WD_PID, 0,
37910678SGuoqing.Zhu@Sun.COM SCSA2USB_ATTRS_INQUIRY_EVPD}
3800Sstevel@tonic-gate };
3810Sstevel@tonic-gate
3820Sstevel@tonic-gate
3830Sstevel@tonic-gate #define N_SCSA2USB_BLACKLIST (sizeof (scsa2usb_blacklist))/ \
3840Sstevel@tonic-gate sizeof (struct blacklist)
3850Sstevel@tonic-gate
3860Sstevel@tonic-gate /*
3870Sstevel@tonic-gate * Attribute values can be overridden by values
3880Sstevel@tonic-gate * contained in the scsa2usb.conf file.
3890Sstevel@tonic-gate * These arrays define possible user input values.
3900Sstevel@tonic-gate */
3910Sstevel@tonic-gate
3920Sstevel@tonic-gate struct scsa2usb_subclass_protocol_override {
3930Sstevel@tonic-gate char *name;
3940Sstevel@tonic-gate int value;
3950Sstevel@tonic-gate };
3960Sstevel@tonic-gate
3970Sstevel@tonic-gate static struct scsa2usb_subclass_protocol_override scsa2usb_protocol[] = {
3980Sstevel@tonic-gate {"CB", SCSA2USB_CB_PROTOCOL},
3990Sstevel@tonic-gate {"CBI", SCSA2USB_CBI_PROTOCOL},
4000Sstevel@tonic-gate {"BO", SCSA2USB_BULK_ONLY_PROTOCOL}
4010Sstevel@tonic-gate };
4020Sstevel@tonic-gate
4030Sstevel@tonic-gate static struct scsa2usb_subclass_protocol_override scsa2usb_subclass[] = {
4040Sstevel@tonic-gate {"SCSI", SCSA2USB_SCSI_CMDSET},
4050Sstevel@tonic-gate {"ATAPI", SCSA2USB_ATAPI_CMDSET},
4060Sstevel@tonic-gate {"UFI", SCSA2USB_UFI_CMDSET}
4070Sstevel@tonic-gate };
4080Sstevel@tonic-gate
4090Sstevel@tonic-gate
4100Sstevel@tonic-gate #define N_SCSA2USB_SUBC_OVERRIDE (sizeof (scsa2usb_subclass))/ \
4110Sstevel@tonic-gate sizeof (struct scsa2usb_subclass_protocol_override)
4120Sstevel@tonic-gate
4130Sstevel@tonic-gate #define N_SCSA2USB_PROT_OVERRIDE (sizeof (scsa2usb_protocol))/ \
4140Sstevel@tonic-gate sizeof (struct scsa2usb_subclass_protocol_override)
4150Sstevel@tonic-gate
4160Sstevel@tonic-gate /* global variables */
4170Sstevel@tonic-gate static void *scsa2usb_statep; /* for soft state */
4180Sstevel@tonic-gate static boolean_t scsa2usb_sync_message = B_TRUE; /* for syncing */
4190Sstevel@tonic-gate
4200Sstevel@tonic-gate /* for debug messages */
421880Sfrits uint_t scsa2usb_errmask = (uint_t)DPRINT_MASK_ALL;
422880Sfrits uint_t scsa2usb_errlevel = USB_LOG_L4;
423880Sfrits uint_t scsa2usb_instance_debug = (uint_t)-1;
424880Sfrits uint_t scsa2usb_scsi_bus_config_debug = 0;
425880Sfrits uint_t scsa2usb_long_timeout = 50 * SCSA2USB_BULK_PIPE_TIMEOUT;
4260Sstevel@tonic-gate
4270Sstevel@tonic-gate
4280Sstevel@tonic-gate /*
4290Sstevel@tonic-gate * Some devices have problems with big bulk transfers,
4300Sstevel@tonic-gate * transfers >= 128kbytes hang the device. This tunable allows to
4310Sstevel@tonic-gate * limit the maximum bulk transfers rate.
4320Sstevel@tonic-gate */
433880Sfrits uint_t scsa2usb_max_bulk_xfer_size = SCSA2USB_MAX_BULK_XFER_SIZE;
4340Sstevel@tonic-gate
4350Sstevel@tonic-gate
4360Sstevel@tonic-gate #ifdef SCSA2USB_BULK_ONLY_TEST
4370Sstevel@tonic-gate /*
4380Sstevel@tonic-gate * Test BO 13 cases. (See USB Mass Storage Class - Bulk Only Transport).
4390Sstevel@tonic-gate * We are not covering test cases 1, 6, and 12 as these are the "good"
4400Sstevel@tonic-gate * test cases and are tested as part of the normal drive access operations.
4410Sstevel@tonic-gate *
4420Sstevel@tonic-gate * NOTE: This is for testing only. It will be replaced by a uscsi test.
4430Sstevel@tonic-gate * Some are listed here while; other test cases are moved to usb_bulkonly.c
4440Sstevel@tonic-gate */
4450Sstevel@tonic-gate static int scsa2usb_test_case_5 = 0;
4460Sstevel@tonic-gate int scsa2usb_test_case_8 = 0;
4470Sstevel@tonic-gate int scsa2usb_test_case_10 = 0;
4480Sstevel@tonic-gate static int scsa2usb_test_case_11 = 0;
4490Sstevel@tonic-gate
4500Sstevel@tonic-gate static void scsa2usb_test_mblk(scsa2usb_state_t *, boolean_t);
4510Sstevel@tonic-gate #endif /* SCSA2USB_BULK_ONLY_TEST */
4520Sstevel@tonic-gate
4530Sstevel@tonic-gate static int scsa2usb_ugen_open(dev_t *, int, int, cred_t *);
4540Sstevel@tonic-gate static int scsa2usb_ugen_close(dev_t, int, int, cred_t *);
4550Sstevel@tonic-gate static int scsa2usb_ugen_read(dev_t, struct uio *, cred_t *);
4560Sstevel@tonic-gate static int scsa2usb_ugen_write(dev_t, struct uio *, cred_t *);
4570Sstevel@tonic-gate static int scsa2usb_ugen_poll(dev_t, short, int, short *,
4580Sstevel@tonic-gate struct pollhead **);
4590Sstevel@tonic-gate
4600Sstevel@tonic-gate /* scsa2usb cb_ops */
4610Sstevel@tonic-gate static struct cb_ops scsa2usb_cbops = {
4620Sstevel@tonic-gate scsa2usb_ugen_open, /* open */
4630Sstevel@tonic-gate scsa2usb_ugen_close, /* close */
4640Sstevel@tonic-gate nodev, /* strategy */
4650Sstevel@tonic-gate nodev, /* print */
4660Sstevel@tonic-gate nodev, /* dump */
4670Sstevel@tonic-gate scsa2usb_ugen_read, /* read */
4680Sstevel@tonic-gate scsa2usb_ugen_write, /* write */
4696910Svb160487 nodev, /* ioctl */
4700Sstevel@tonic-gate nodev, /* devmap */
4710Sstevel@tonic-gate nodev, /* mmap */
4720Sstevel@tonic-gate nodev, /* segmap */
4730Sstevel@tonic-gate scsa2usb_ugen_poll, /* poll */
4740Sstevel@tonic-gate ddi_prop_op, /* prop_op */
4750Sstevel@tonic-gate NULL, /* stream */
4760Sstevel@tonic-gate D_MP, /* cb_flag */
4770Sstevel@tonic-gate CB_REV, /* rev */
4780Sstevel@tonic-gate nodev, /* int (*cb_aread)() */
4790Sstevel@tonic-gate nodev /* int (*cb_awrite)() */
4800Sstevel@tonic-gate };
4810Sstevel@tonic-gate
4820Sstevel@tonic-gate /* modloading support */
4830Sstevel@tonic-gate static struct dev_ops scsa2usb_ops = {
4840Sstevel@tonic-gate DEVO_REV, /* devo_rev, */
4850Sstevel@tonic-gate 0, /* refcnt */
4860Sstevel@tonic-gate scsa2usb_info, /* info */
4870Sstevel@tonic-gate nulldev, /* identify */
4880Sstevel@tonic-gate nulldev, /* probe */
4890Sstevel@tonic-gate scsa2usb_attach, /* attach */
4900Sstevel@tonic-gate scsa2usb_detach, /* detach */
4910Sstevel@tonic-gate nodev, /* reset */
4920Sstevel@tonic-gate &scsa2usb_cbops, /* driver operations */
4930Sstevel@tonic-gate NULL, /* bus operations */
4947656SSherry.Moore@Sun.COM scsa2usb_power, /* power */
4957656SSherry.Moore@Sun.COM ddi_quiesce_not_needed, /* quiesce */
4960Sstevel@tonic-gate };
4970Sstevel@tonic-gate
4980Sstevel@tonic-gate static struct modldrv modldrv = {
4990Sstevel@tonic-gate &mod_driverops, /* Module type. This one is a driver */
5007015Sbc224572 "SCSA to USB Driver", /* Name of the module. */
5010Sstevel@tonic-gate &scsa2usb_ops, /* driver ops */
5020Sstevel@tonic-gate };
5030Sstevel@tonic-gate
5040Sstevel@tonic-gate static struct modlinkage modlinkage = {
5050Sstevel@tonic-gate MODREV_1, (void *)&modldrv, NULL
5060Sstevel@tonic-gate };
5070Sstevel@tonic-gate
5080Sstevel@tonic-gate /* event support */
5090Sstevel@tonic-gate static usb_event_t scsa2usb_events = {
5100Sstevel@tonic-gate scsa2usb_disconnect_event_cb,
5110Sstevel@tonic-gate scsa2usb_reconnect_event_cb,
5120Sstevel@tonic-gate NULL, NULL
5130Sstevel@tonic-gate };
5140Sstevel@tonic-gate
5150Sstevel@tonic-gate int
_init(void)5160Sstevel@tonic-gate _init(void)
5170Sstevel@tonic-gate {
5180Sstevel@tonic-gate int rval;
5190Sstevel@tonic-gate
5200Sstevel@tonic-gate if (((rval = ddi_soft_state_init(&scsa2usb_statep,
5210Sstevel@tonic-gate sizeof (scsa2usb_state_t), SCSA2USB_INITIAL_ALLOC)) != 0)) {
5220Sstevel@tonic-gate
5230Sstevel@tonic-gate return (rval);
5240Sstevel@tonic-gate }
5250Sstevel@tonic-gate
5260Sstevel@tonic-gate if ((rval = scsi_hba_init(&modlinkage)) != 0) {
5270Sstevel@tonic-gate ddi_soft_state_fini(&scsa2usb_statep);
5280Sstevel@tonic-gate
5290Sstevel@tonic-gate return (rval);
5300Sstevel@tonic-gate }
5310Sstevel@tonic-gate
5320Sstevel@tonic-gate if ((rval = mod_install(&modlinkage)) != 0) {
5330Sstevel@tonic-gate scsi_hba_fini(&modlinkage);
5340Sstevel@tonic-gate ddi_soft_state_fini(&scsa2usb_statep);
5350Sstevel@tonic-gate
5360Sstevel@tonic-gate return (rval);
5370Sstevel@tonic-gate }
5380Sstevel@tonic-gate
5390Sstevel@tonic-gate return (rval);
5400Sstevel@tonic-gate }
5410Sstevel@tonic-gate
5420Sstevel@tonic-gate
5430Sstevel@tonic-gate int
_fini(void)5440Sstevel@tonic-gate _fini(void)
5450Sstevel@tonic-gate {
5460Sstevel@tonic-gate int rval;
5470Sstevel@tonic-gate
5480Sstevel@tonic-gate if ((rval = mod_remove(&modlinkage)) == 0) {
5490Sstevel@tonic-gate scsi_hba_fini(&modlinkage);
5500Sstevel@tonic-gate ddi_soft_state_fini(&scsa2usb_statep);
5510Sstevel@tonic-gate }
5520Sstevel@tonic-gate
5530Sstevel@tonic-gate return (rval);
5540Sstevel@tonic-gate }
5550Sstevel@tonic-gate
5560Sstevel@tonic-gate
5570Sstevel@tonic-gate int
_info(struct modinfo * modinfop)5580Sstevel@tonic-gate _info(struct modinfo *modinfop)
5590Sstevel@tonic-gate {
5600Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop));
5610Sstevel@tonic-gate }
5620Sstevel@tonic-gate
5630Sstevel@tonic-gate
5640Sstevel@tonic-gate /*
5650Sstevel@tonic-gate * scsa2usb_info :
5660Sstevel@tonic-gate * Get minor number, soft state structure etc.
5670Sstevel@tonic-gate */
5680Sstevel@tonic-gate /*ARGSUSED*/
5690Sstevel@tonic-gate static int
scsa2usb_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)5700Sstevel@tonic-gate scsa2usb_info(dev_info_t *dip, ddi_info_cmd_t infocmd,
5710Sstevel@tonic-gate void *arg, void **result)
5720Sstevel@tonic-gate {
5730Sstevel@tonic-gate scsa2usb_state_t *scsa2usbp = NULL;
5740Sstevel@tonic-gate int error = DDI_FAILURE;
5750Sstevel@tonic-gate int instance = SCSA2USB_MINOR_TO_INSTANCE(getminor((dev_t)arg));
5760Sstevel@tonic-gate
5770Sstevel@tonic-gate switch (infocmd) {
5780Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO:
5790Sstevel@tonic-gate if (((scsa2usbp = ddi_get_soft_state(scsa2usb_statep,
5800Sstevel@tonic-gate instance)) != NULL) &&
5810Sstevel@tonic-gate scsa2usbp->scsa2usb_dip) {
5820Sstevel@tonic-gate *result = scsa2usbp->scsa2usb_dip;
5830Sstevel@tonic-gate error = DDI_SUCCESS;
5840Sstevel@tonic-gate } else {
5850Sstevel@tonic-gate *result = NULL;
5860Sstevel@tonic-gate }
5870Sstevel@tonic-gate break;
5880Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE:
5890Sstevel@tonic-gate *result = (void *)(uintptr_t)instance;
5900Sstevel@tonic-gate error = DDI_SUCCESS;
5910Sstevel@tonic-gate break;
5920Sstevel@tonic-gate default:
5930Sstevel@tonic-gate break;
5940Sstevel@tonic-gate }
5950Sstevel@tonic-gate
5960Sstevel@tonic-gate return (error);
5970Sstevel@tonic-gate }
5980Sstevel@tonic-gate
5990Sstevel@tonic-gate
6000Sstevel@tonic-gate /*
6010Sstevel@tonic-gate * scsa2usb_attach:
6020Sstevel@tonic-gate * Attach driver
6030Sstevel@tonic-gate * Allocate a "scsi_hba_tran" - call scsi_hba_tran_alloc()
6040Sstevel@tonic-gate * Invoke scsi_hba_attach_setup
6050Sstevel@tonic-gate * Get the serialno of the device
6060Sstevel@tonic-gate * Open bulk pipes
6070Sstevel@tonic-gate * Create disk child(ren)
6080Sstevel@tonic-gate * Register events
6090Sstevel@tonic-gate * Create and register panic callback
6100Sstevel@tonic-gate *
6110Sstevel@tonic-gate * NOTE: Replaced CBW_DIR_OUT with USB_EP_DIR_OUT and CBW_DIR_IN with
6120Sstevel@tonic-gate * USB_EP_DIR_IN as they are the same #defines.
6130Sstevel@tonic-gate */
6140Sstevel@tonic-gate static int
scsa2usb_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)6150Sstevel@tonic-gate scsa2usb_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
6160Sstevel@tonic-gate {
6170Sstevel@tonic-gate int instance = ddi_get_instance(dip);
6180Sstevel@tonic-gate int interface;
6190Sstevel@tonic-gate uint_t lun;
6200Sstevel@tonic-gate boolean_t ept_check = B_TRUE;
6210Sstevel@tonic-gate scsi_hba_tran_t *tran; /* scsi transport */
6220Sstevel@tonic-gate scsa2usb_state_t *scsa2usbp;
6230Sstevel@tonic-gate usb_log_handle_t log_handle;
6240Sstevel@tonic-gate usb_ep_data_t *ep_data;
6250Sstevel@tonic-gate usb_client_dev_data_t *dev_data;
6260Sstevel@tonic-gate usb_alt_if_data_t *altif_data;
6270Sstevel@tonic-gate usb_ugen_info_t usb_ugen_info;
6280Sstevel@tonic-gate
6290Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, NULL,
6306898Sfb209375 "scsa2usb_attach: dip = 0x%p", (void *)dip);
6310Sstevel@tonic-gate
6320Sstevel@tonic-gate switch (cmd) {
6330Sstevel@tonic-gate case DDI_ATTACH:
6340Sstevel@tonic-gate break;
6350Sstevel@tonic-gate case DDI_RESUME:
6360Sstevel@tonic-gate scsa2usb_cpr_resume(dip);
6370Sstevel@tonic-gate
6380Sstevel@tonic-gate return (DDI_SUCCESS);
6390Sstevel@tonic-gate default:
6400Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_SCSA, NULL,
6410Sstevel@tonic-gate "scsa2usb_attach: failed");
6420Sstevel@tonic-gate
6430Sstevel@tonic-gate return (DDI_FAILURE);
6440Sstevel@tonic-gate }
6450Sstevel@tonic-gate
6460Sstevel@tonic-gate /* Allocate softc information */
6470Sstevel@tonic-gate if (ddi_soft_state_zalloc(scsa2usb_statep, instance) != DDI_SUCCESS) {
6480Sstevel@tonic-gate ddi_prop_remove_all(dip);
6490Sstevel@tonic-gate
6500Sstevel@tonic-gate return (DDI_FAILURE);
6510Sstevel@tonic-gate }
6520Sstevel@tonic-gate
6530Sstevel@tonic-gate /* get soft state space and initialize */
6540Sstevel@tonic-gate if ((scsa2usbp = ddi_get_soft_state(scsa2usb_statep,
6550Sstevel@tonic-gate instance)) == NULL) {
6560Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_SCSA, NULL,
6570Sstevel@tonic-gate "scsa2usb%d: bad soft state", instance);
6580Sstevel@tonic-gate ddi_prop_remove_all(dip);
6590Sstevel@tonic-gate
6600Sstevel@tonic-gate return (DDI_FAILURE);
6610Sstevel@tonic-gate }
6620Sstevel@tonic-gate
6630Sstevel@tonic-gate scsa2usbp->scsa2usb_dip = dip;
6640Sstevel@tonic-gate scsa2usbp->scsa2usb_instance = instance;
6650Sstevel@tonic-gate
6660Sstevel@tonic-gate /* allocate a log handle for debug/error messages */
6670Sstevel@tonic-gate scsa2usbp->scsa2usb_log_handle = log_handle =
6680Sstevel@tonic-gate usb_alloc_log_hdl(dip, "s2u",
6694700Sfb209375 &scsa2usb_errlevel,
6704700Sfb209375 &scsa2usb_errmask, &scsa2usb_instance_debug,
6714700Sfb209375 0);
6720Sstevel@tonic-gate
6730Sstevel@tonic-gate /* attach to USBA */
6740Sstevel@tonic-gate if (usb_client_attach(dip, USBDRV_VERSION, 0) != USB_SUCCESS) {
6750Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_SCSA, log_handle,
6760Sstevel@tonic-gate "usb_client_attach failed");
6770Sstevel@tonic-gate
6780Sstevel@tonic-gate goto fail;
6790Sstevel@tonic-gate }
6800Sstevel@tonic-gate if (usb_get_dev_data(dip, &dev_data, USB_PARSE_LVL_IF, 0) !=
6810Sstevel@tonic-gate USB_SUCCESS) {
6820Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_SCSA, log_handle,
6830Sstevel@tonic-gate "usb_get_dev_data failed");
6840Sstevel@tonic-gate
6850Sstevel@tonic-gate goto fail;
6860Sstevel@tonic-gate }
6870Sstevel@tonic-gate
6880Sstevel@tonic-gate /* initialize the mutex with the right cookie */
6890Sstevel@tonic-gate mutex_init(&scsa2usbp->scsa2usb_mutex, NULL, MUTEX_DRIVER,
6904700Sfb209375 dev_data->dev_iblock_cookie);
6910Sstevel@tonic-gate cv_init(&scsa2usbp->scsa2usb_transport_busy_cv, NULL, CV_DRIVER, NULL);
6920Sstevel@tonic-gate
6930Sstevel@tonic-gate for (lun = 0; lun < SCSA2USB_MAX_LUNS; lun++) {
6940Sstevel@tonic-gate usba_init_list(&scsa2usbp->scsa2usb_waitQ[lun], NULL,
6954700Sfb209375 dev_data->dev_iblock_cookie);
6960Sstevel@tonic-gate }
6970Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
6980Sstevel@tonic-gate scsa2usbp->scsa2usb_dip = dip;
6990Sstevel@tonic-gate scsa2usbp->scsa2usb_instance = instance;
7000Sstevel@tonic-gate scsa2usbp->scsa2usb_attrs = SCSA2USB_ALL_ATTRS;
7010Sstevel@tonic-gate scsa2usbp->scsa2usb_dev_data = dev_data;
7020Sstevel@tonic-gate
7030Sstevel@tonic-gate
7040Sstevel@tonic-gate /* save the default pipe handle */
7050Sstevel@tonic-gate scsa2usbp->scsa2usb_default_pipe = dev_data->dev_default_ph;
7060Sstevel@tonic-gate
7070Sstevel@tonic-gate /* basic inits are done */
7080Sstevel@tonic-gate scsa2usbp->scsa2usb_flags |= SCSA2USB_FLAGS_LOCKS_INIT;
7090Sstevel@tonic-gate
7100Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, log_handle,
7116898Sfb209375 "curr_cfg=%ld, curr_if=%d",
7126898Sfb209375 (long)(dev_data->dev_curr_cfg - &dev_data->dev_cfg[0]),
7130Sstevel@tonic-gate dev_data->dev_curr_if);
7140Sstevel@tonic-gate
7150Sstevel@tonic-gate interface = dev_data->dev_curr_if;
7160Sstevel@tonic-gate scsa2usbp->scsa2usb_intfc_num = dev_data->dev_curr_if;
7170Sstevel@tonic-gate
7180Sstevel@tonic-gate /* now find out relevant descriptors for alternate 0 */
7190Sstevel@tonic-gate altif_data = &dev_data->dev_curr_cfg->cfg_if[interface].if_alt[0];
7200Sstevel@tonic-gate
7210Sstevel@tonic-gate if (altif_data->altif_n_ep == 0) {
722978Sfrits USB_DPRINTF_L2(DPRINT_MASK_SCSA, log_handle,
7230Sstevel@tonic-gate "invalid alt 0 for interface %d", interface);
7240Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
7250Sstevel@tonic-gate
7260Sstevel@tonic-gate goto fail;
7270Sstevel@tonic-gate }
7280Sstevel@tonic-gate
7290Sstevel@tonic-gate /* All CB/CBI, BO devices should have this value set */
7300Sstevel@tonic-gate if (altif_data->altif_descr.bInterfaceClass !=
7310Sstevel@tonic-gate USB_CLASS_MASS_STORAGE) {
732978Sfrits USB_DPRINTF_L2(DPRINT_MASK_SCSA, log_handle,
7330Sstevel@tonic-gate "invalid interface class (0x%x)",
7340Sstevel@tonic-gate altif_data->altif_descr.bInterfaceClass);
7350Sstevel@tonic-gate }
7360Sstevel@tonic-gate scsa2usbp->scsa2usb_intfc_descr = altif_data->altif_descr;
7370Sstevel@tonic-gate
7380Sstevel@tonic-gate /* figure out the endpoints and copy the descr */
7390Sstevel@tonic-gate if ((ep_data = usb_lookup_ep_data(dip, dev_data, interface, 0, 0,
7400Sstevel@tonic-gate USB_EP_ATTR_BULK, USB_EP_DIR_OUT)) != NULL) {
7410Sstevel@tonic-gate scsa2usbp->scsa2usb_bulkout_ept = ep_data->ep_descr;
7420Sstevel@tonic-gate }
7430Sstevel@tonic-gate if ((ep_data = usb_lookup_ep_data(dip, dev_data, interface, 0, 0,
7440Sstevel@tonic-gate USB_EP_ATTR_BULK, USB_EP_DIR_IN)) != NULL) {
7450Sstevel@tonic-gate scsa2usbp->scsa2usb_bulkin_ept = ep_data->ep_descr;
7460Sstevel@tonic-gate }
7470Sstevel@tonic-gate if ((ep_data = usb_lookup_ep_data(dip, dev_data, interface, 0, 0,
7480Sstevel@tonic-gate USB_EP_ATTR_INTR, USB_EP_DIR_IN)) != NULL) {
7490Sstevel@tonic-gate scsa2usbp->scsa2usb_intr_ept = ep_data->ep_descr;
7500Sstevel@tonic-gate }
7510Sstevel@tonic-gate
7520Sstevel@tonic-gate /*
7530Sstevel@tonic-gate * check here for protocol and subclass supported by this driver
7540Sstevel@tonic-gate *
7550Sstevel@tonic-gate * first check if conf file has override values
7560Sstevel@tonic-gate * Note: override values are not used if supplied values are legal
7570Sstevel@tonic-gate */
7580Sstevel@tonic-gate scsa2usb_override(scsa2usbp);
7590Sstevel@tonic-gate
7600Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_SCSA, log_handle,
7610Sstevel@tonic-gate "protocol=0x%x override=0x%x subclass=0x%x override=0x%x",
7620Sstevel@tonic-gate scsa2usbp->scsa2usb_intfc_descr.bInterfaceProtocol,
7630Sstevel@tonic-gate scsa2usbp->scsa2usb_protocol_override,
7640Sstevel@tonic-gate scsa2usbp->scsa2usb_intfc_descr.bInterfaceSubClass,
7650Sstevel@tonic-gate scsa2usbp->scsa2usb_subclass_override);
7660Sstevel@tonic-gate
7670Sstevel@tonic-gate switch (scsa2usbp->scsa2usb_intfc_descr.bInterfaceProtocol) {
7680Sstevel@tonic-gate case USB_PROTO_MS_CBI:
7690Sstevel@tonic-gate scsa2usbp->scsa2usb_cmd_protocol |= SCSA2USB_CB_PROTOCOL;
7700Sstevel@tonic-gate break;
7710Sstevel@tonic-gate case USB_PROTO_MS_CBI_WC:
7720Sstevel@tonic-gate scsa2usbp->scsa2usb_cmd_protocol |= SCSA2USB_CBI_PROTOCOL;
7730Sstevel@tonic-gate break;
7740Sstevel@tonic-gate case USB_PROTO_MS_ISD_1999_SILICN:
7750Sstevel@tonic-gate case USB_PROTO_MS_BULK_ONLY:
7760Sstevel@tonic-gate scsa2usbp->scsa2usb_cmd_protocol |= SCSA2USB_BULK_ONLY_PROTOCOL;
7770Sstevel@tonic-gate break;
7780Sstevel@tonic-gate default:
7790Sstevel@tonic-gate if (scsa2usbp->scsa2usb_protocol_override) {
7800Sstevel@tonic-gate scsa2usbp->scsa2usb_cmd_protocol |=
7810Sstevel@tonic-gate scsa2usbp->scsa2usb_protocol_override;
782978Sfrits USB_DPRINTF_L2(DPRINT_MASK_SCSA, log_handle,
7830Sstevel@tonic-gate "overriding protocol %x",
7840Sstevel@tonic-gate scsa2usbp->scsa2usb_intfc_descr.bInterfaceProtocol);
7850Sstevel@tonic-gate break;
7860Sstevel@tonic-gate }
7870Sstevel@tonic-gate
7880Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_SCSA, log_handle,
7890Sstevel@tonic-gate "unsupported protocol = %x",
7900Sstevel@tonic-gate scsa2usbp->scsa2usb_intfc_descr.bInterfaceProtocol);
7910Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
7920Sstevel@tonic-gate
7930Sstevel@tonic-gate goto fail;
7940Sstevel@tonic-gate }
7950Sstevel@tonic-gate
7960Sstevel@tonic-gate switch (scsa2usbp->scsa2usb_intfc_descr.bInterfaceSubClass) {
7970Sstevel@tonic-gate case USB_SUBCLS_MS_SCSI: /* transparent SCSI */
7980Sstevel@tonic-gate scsa2usbp->scsa2usb_cmd_protocol |= SCSA2USB_SCSI_CMDSET;
7990Sstevel@tonic-gate break;
8000Sstevel@tonic-gate case USB_SUBCLS_MS_SFF8020I:
8010Sstevel@tonic-gate case USB_SUBCLS_MS_SFF8070I:
8020Sstevel@tonic-gate scsa2usbp->scsa2usb_cmd_protocol |= SCSA2USB_ATAPI_CMDSET;
8030Sstevel@tonic-gate break;
8040Sstevel@tonic-gate case USB_SUBCLS_MS_UFI: /* UFI */
8050Sstevel@tonic-gate scsa2usbp->scsa2usb_cmd_protocol |= SCSA2USB_UFI_CMDSET;
8060Sstevel@tonic-gate break;
8070Sstevel@tonic-gate default:
8080Sstevel@tonic-gate if (scsa2usbp->scsa2usb_subclass_override) {
8090Sstevel@tonic-gate scsa2usbp->scsa2usb_cmd_protocol |=
8100Sstevel@tonic-gate scsa2usbp->scsa2usb_subclass_override;
811978Sfrits USB_DPRINTF_L2(DPRINT_MASK_SCSA, log_handle,
8120Sstevel@tonic-gate "overriding subclass %x",
8130Sstevel@tonic-gate scsa2usbp->scsa2usb_intfc_descr.bInterfaceSubClass);
8140Sstevel@tonic-gate break;
8150Sstevel@tonic-gate }
8160Sstevel@tonic-gate
8170Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_SCSA, log_handle,
8180Sstevel@tonic-gate "unsupported subclass = %x",
8190Sstevel@tonic-gate scsa2usbp->scsa2usb_intfc_descr.bInterfaceSubClass);
8200Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
8210Sstevel@tonic-gate
8220Sstevel@tonic-gate goto fail;
8230Sstevel@tonic-gate }
8240Sstevel@tonic-gate
8250Sstevel@tonic-gate /* check that we have the right set of endpoint descriptors */
8260Sstevel@tonic-gate if (SCSA2USB_IS_BULK_ONLY(scsa2usbp) || SCSA2USB_IS_CB(scsa2usbp)) {
8270Sstevel@tonic-gate if ((scsa2usbp->scsa2usb_bulkout_ept.bLength == 0) ||
8280Sstevel@tonic-gate (scsa2usbp->scsa2usb_bulkin_ept.bLength == 0)) {
8290Sstevel@tonic-gate ept_check = B_FALSE;
8300Sstevel@tonic-gate }
8310Sstevel@tonic-gate } else if (SCSA2USB_IS_CBI(scsa2usbp)) {
8320Sstevel@tonic-gate if ((scsa2usbp->scsa2usb_bulkout_ept.bLength == 0) ||
8330Sstevel@tonic-gate (scsa2usbp->scsa2usb_bulkin_ept.bLength == 0) ||
8340Sstevel@tonic-gate (scsa2usbp->scsa2usb_intr_ept.bLength == 0)) {
8350Sstevel@tonic-gate ept_check = B_FALSE;
8360Sstevel@tonic-gate }
8370Sstevel@tonic-gate }
8380Sstevel@tonic-gate
8390Sstevel@tonic-gate if (ept_check == B_FALSE) {
840978Sfrits USB_DPRINTF_L2(DPRINT_MASK_SCSA, log_handle,
8410Sstevel@tonic-gate "scsa2usb%d doesn't support minimum required endpoints",
8420Sstevel@tonic-gate instance);
8430Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
8440Sstevel@tonic-gate
8450Sstevel@tonic-gate goto fail;
8460Sstevel@tonic-gate }
8470Sstevel@tonic-gate
8480Sstevel@tonic-gate /*
8490Sstevel@tonic-gate * Validate the black-listed attributes
8500Sstevel@tonic-gate */
8510Sstevel@tonic-gate scsa2usb_validate_attrs(scsa2usbp);
8520Sstevel@tonic-gate
8530Sstevel@tonic-gate /* Print the serial number from the registration data */
8540Sstevel@tonic-gate if (scsa2usbp->scsa2usb_dev_data->dev_serial) {
8550Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA,
8560Sstevel@tonic-gate scsa2usbp->scsa2usb_log_handle, "Serial Number = %s",
8570Sstevel@tonic-gate scsa2usbp->scsa2usb_dev_data->dev_serial);
8580Sstevel@tonic-gate }
8590Sstevel@tonic-gate
8600Sstevel@tonic-gate /*
8610Sstevel@tonic-gate * Allocate a SCSA transport structure
8620Sstevel@tonic-gate */
8630Sstevel@tonic-gate tran = scsi_hba_tran_alloc(dip, SCSI_HBA_CANSLEEP);
8640Sstevel@tonic-gate scsa2usbp->scsa2usb_tran = tran;
8650Sstevel@tonic-gate
8660Sstevel@tonic-gate /*
8670Sstevel@tonic-gate * initialize transport structure
8680Sstevel@tonic-gate */
8690Sstevel@tonic-gate tran->tran_hba_private = scsa2usbp;
8700Sstevel@tonic-gate tran->tran_tgt_private = NULL;
8710Sstevel@tonic-gate tran->tran_tgt_init = scsa2usb_scsi_tgt_init;
8720Sstevel@tonic-gate tran->tran_tgt_probe = scsa2usb_scsi_tgt_probe;
8730Sstevel@tonic-gate tran->tran_tgt_free = scsa2usb_scsi_tgt_free;
8740Sstevel@tonic-gate tran->tran_start = scsa2usb_scsi_start;
8750Sstevel@tonic-gate tran->tran_abort = scsa2usb_scsi_abort;
8760Sstevel@tonic-gate tran->tran_reset = scsa2usb_scsi_reset;
8770Sstevel@tonic-gate tran->tran_getcap = scsa2usb_scsi_getcap;
8780Sstevel@tonic-gate tran->tran_setcap = scsa2usb_scsi_setcap;
8790Sstevel@tonic-gate tran->tran_init_pkt = scsa2usb_scsi_init_pkt;
8800Sstevel@tonic-gate tran->tran_destroy_pkt = scsa2usb_scsi_destroy_pkt;
8810Sstevel@tonic-gate tran->tran_dmafree = NULL;
8820Sstevel@tonic-gate tran->tran_sync_pkt = NULL;
8830Sstevel@tonic-gate tran->tran_reset_notify = NULL;
8840Sstevel@tonic-gate tran->tran_get_bus_addr = NULL;
8850Sstevel@tonic-gate tran->tran_get_name = NULL;
8860Sstevel@tonic-gate tran->tran_quiesce = NULL;
8870Sstevel@tonic-gate tran->tran_unquiesce = NULL;
8880Sstevel@tonic-gate tran->tran_bus_reset = NULL;
8890Sstevel@tonic-gate tran->tran_add_eventcall = NULL;
8900Sstevel@tonic-gate tran->tran_get_eventcookie = NULL;
8910Sstevel@tonic-gate tran->tran_post_event = NULL;
8920Sstevel@tonic-gate tran->tran_remove_eventcall = NULL;
8930Sstevel@tonic-gate tran->tran_bus_config = scsa2usb_scsi_bus_config;
8940Sstevel@tonic-gate tran->tran_bus_unconfig = scsa2usb_scsi_bus_unconfig;
8950Sstevel@tonic-gate
8960Sstevel@tonic-gate /*
8970Sstevel@tonic-gate * register with SCSA as an HBA
8980Sstevel@tonic-gate * Note that the dma attributes are from parent nexus
8990Sstevel@tonic-gate */
9000Sstevel@tonic-gate if (scsi_hba_attach_setup(dip, usba_get_hc_dma_attr(dip), tran, 0)) {
9010Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_SCSA, log_handle,
9020Sstevel@tonic-gate "scsi_hba_attach_setup failed");
9030Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
9040Sstevel@tonic-gate
9050Sstevel@tonic-gate goto fail;
9060Sstevel@tonic-gate }
9070Sstevel@tonic-gate
9080Sstevel@tonic-gate scsa2usbp->scsa2usb_flags |= SCSA2USB_FLAGS_HBA_ATTACH_SETUP;
9090Sstevel@tonic-gate
9100Sstevel@tonic-gate /* create minor node */
9110Sstevel@tonic-gate if (ddi_create_minor_node(dip, "scsa2usb", S_IFCHR,
9120Sstevel@tonic-gate instance << SCSA2USB_MINOR_INSTANCE_SHIFT,
9130Sstevel@tonic-gate DDI_NT_SCSI_NEXUS, 0) != DDI_SUCCESS) {
9140Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
9150Sstevel@tonic-gate "scsi_attach: ddi_create_minor_node failed");
9160Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
9170Sstevel@tonic-gate
9180Sstevel@tonic-gate goto fail;
9190Sstevel@tonic-gate }
9200Sstevel@tonic-gate
9210Sstevel@tonic-gate /* open pipes and set scsa2usb_flags */
9220Sstevel@tonic-gate if (scsa2usb_open_usb_pipes(scsa2usbp) == USB_FAILURE) {
9230Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_SCSA, log_handle,
9240Sstevel@tonic-gate "error opening pipes");
9250Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
9260Sstevel@tonic-gate
9270Sstevel@tonic-gate goto fail;
9280Sstevel@tonic-gate }
9290Sstevel@tonic-gate
9300Sstevel@tonic-gate /* set default block size. updated after read cap cmd */
9310Sstevel@tonic-gate for (lun = 0; lun < SCSA2USB_MAX_LUNS; lun++) {
9320Sstevel@tonic-gate scsa2usbp->scsa2usb_lbasize[lun] = DEV_BSIZE;
9330Sstevel@tonic-gate }
9340Sstevel@tonic-gate
9350Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
9360Sstevel@tonic-gate
9370Sstevel@tonic-gate /* initialize PANIC callback */
9380Sstevel@tonic-gate scsa2usb_panic_callb_init(scsa2usbp);
9390Sstevel@tonic-gate
9400Sstevel@tonic-gate /* finally we are all done 'initializing' the device */
9410Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
9420Sstevel@tonic-gate scsa2usbp->scsa2usb_dev_state = USB_DEV_ONLINE;
9430Sstevel@tonic-gate
9440Sstevel@tonic-gate /* enable PM, mutex needs to be held across this */
9450Sstevel@tonic-gate scsa2usb_create_pm_components(dip, scsa2usbp);
9460Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
9470Sstevel@tonic-gate
9480Sstevel@tonic-gate /* register for connect/disconnect events */
9490Sstevel@tonic-gate if (usb_register_event_cbs(scsa2usbp->scsa2usb_dip, &scsa2usb_events,
9500Sstevel@tonic-gate 0) != USB_SUCCESS) {
9510Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_SCSA, log_handle,
9520Sstevel@tonic-gate "error cb registering");
9530Sstevel@tonic-gate goto fail;
9540Sstevel@tonic-gate }
9550Sstevel@tonic-gate
9560Sstevel@tonic-gate /* free the dev_data tree, we no longer need it */
9570Sstevel@tonic-gate usb_free_descr_tree(dip, dev_data);
9580Sstevel@tonic-gate
9590Sstevel@tonic-gate scsa2usb_pm_idle_component(scsa2usbp);
9600Sstevel@tonic-gate
9610Sstevel@tonic-gate /* log the conf file override string if there is one */
9620Sstevel@tonic-gate if (scsa2usbp->scsa2usb_override_str) {
963978Sfrits USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
9640Sstevel@tonic-gate "scsa2usb.conf override: %s",
9650Sstevel@tonic-gate scsa2usbp->scsa2usb_override_str);
9660Sstevel@tonic-gate }
9670Sstevel@tonic-gate
9680Sstevel@tonic-gate if (usb_owns_device(dip)) {
9690Sstevel@tonic-gate /* get a ugen handle */
9700Sstevel@tonic-gate bzero(&usb_ugen_info, sizeof (usb_ugen_info));
9710Sstevel@tonic-gate usb_ugen_info.usb_ugen_flags = 0;
9720Sstevel@tonic-gate usb_ugen_info.usb_ugen_minor_node_ugen_bits_mask =
9734700Sfb209375 (dev_t)SCSA2USB_MINOR_UGEN_BITS_MASK;
9740Sstevel@tonic-gate usb_ugen_info.usb_ugen_minor_node_instance_mask =
9754700Sfb209375 (dev_t)~SCSA2USB_MINOR_UGEN_BITS_MASK;
9760Sstevel@tonic-gate scsa2usbp->scsa2usb_ugen_hdl =
9774700Sfb209375 usb_ugen_get_hdl(dip, &usb_ugen_info);
9780Sstevel@tonic-gate
9790Sstevel@tonic-gate if (usb_ugen_attach(scsa2usbp->scsa2usb_ugen_hdl, cmd) !=
9800Sstevel@tonic-gate USB_SUCCESS) {
9810Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_SCSA,
9820Sstevel@tonic-gate scsa2usbp->scsa2usb_log_handle,
9830Sstevel@tonic-gate "usb_ugen_attach failed");
9840Sstevel@tonic-gate
9850Sstevel@tonic-gate usb_ugen_release_hdl(scsa2usbp->scsa2usb_ugen_hdl);
9860Sstevel@tonic-gate scsa2usbp->scsa2usb_ugen_hdl = NULL;
9870Sstevel@tonic-gate }
9880Sstevel@tonic-gate }
9890Sstevel@tonic-gate
9900Sstevel@tonic-gate /* report device */
9910Sstevel@tonic-gate ddi_report_dev(dip);
9920Sstevel@tonic-gate
9930Sstevel@tonic-gate return (DDI_SUCCESS);
9940Sstevel@tonic-gate
9950Sstevel@tonic-gate fail:
9960Sstevel@tonic-gate if (scsa2usbp) {
9970Sstevel@tonic-gate (void) scsa2usb_cleanup(dip, scsa2usbp);
9980Sstevel@tonic-gate }
9990Sstevel@tonic-gate
10000Sstevel@tonic-gate return (DDI_FAILURE);
10010Sstevel@tonic-gate }
10020Sstevel@tonic-gate
10030Sstevel@tonic-gate
10040Sstevel@tonic-gate /*
10050Sstevel@tonic-gate * scsa2usb_detach:
10060Sstevel@tonic-gate * detach or suspend driver instance
10070Sstevel@tonic-gate */
10080Sstevel@tonic-gate static int
scsa2usb_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)10090Sstevel@tonic-gate scsa2usb_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
10100Sstevel@tonic-gate {
10110Sstevel@tonic-gate scsi_hba_tran_t *tran;
10120Sstevel@tonic-gate scsa2usb_state_t *scsa2usbp;
10130Sstevel@tonic-gate int rval;
10140Sstevel@tonic-gate
10150Sstevel@tonic-gate tran = ddi_get_driver_private(dip);
10160Sstevel@tonic-gate ASSERT(tran != NULL);
10170Sstevel@tonic-gate
10180Sstevel@tonic-gate scsa2usbp = (scsa2usb_state_t *)tran->tran_hba_private;
10190Sstevel@tonic-gate ASSERT(scsa2usbp);
10200Sstevel@tonic-gate
10210Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
10226898Sfb209375 "scsa2usb_detach: dip = 0x%p, cmd = %d", (void *)dip, cmd);
10230Sstevel@tonic-gate
10240Sstevel@tonic-gate switch (cmd) {
10250Sstevel@tonic-gate case DDI_DETACH:
10260Sstevel@tonic-gate
10270Sstevel@tonic-gate if (scsa2usb_cleanup(dip, scsa2usbp) != USB_SUCCESS) {
10280Sstevel@tonic-gate
10290Sstevel@tonic-gate return (DDI_FAILURE);
10300Sstevel@tonic-gate }
10310Sstevel@tonic-gate
10320Sstevel@tonic-gate return (DDI_SUCCESS);
10330Sstevel@tonic-gate case DDI_SUSPEND:
10340Sstevel@tonic-gate rval = scsa2usb_cpr_suspend(dip);
10350Sstevel@tonic-gate
10360Sstevel@tonic-gate return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
10370Sstevel@tonic-gate default:
10380Sstevel@tonic-gate
10390Sstevel@tonic-gate return (DDI_FAILURE);
10400Sstevel@tonic-gate }
10410Sstevel@tonic-gate }
10420Sstevel@tonic-gate
10430Sstevel@tonic-gate /*
10440Sstevel@tonic-gate * ugen support
10450Sstevel@tonic-gate */
10460Sstevel@tonic-gate /*
10470Sstevel@tonic-gate * scsa2usb_ugen_open()
10480Sstevel@tonic-gate * (all ugen opens and pipe opens are by definition exclusive so it is OK
10490Sstevel@tonic-gate * to count opens)
10500Sstevel@tonic-gate */
10510Sstevel@tonic-gate static int
scsa2usb_ugen_open(dev_t * devp,int flag,int sflag,cred_t * cr)10520Sstevel@tonic-gate scsa2usb_ugen_open(dev_t *devp, int flag, int sflag, cred_t *cr)
10530Sstevel@tonic-gate {
10540Sstevel@tonic-gate scsa2usb_state_t *scsa2usbp;
10550Sstevel@tonic-gate int rval;
10560Sstevel@tonic-gate
10570Sstevel@tonic-gate if ((scsa2usbp = ddi_get_soft_state(scsa2usb_statep,
10580Sstevel@tonic-gate SCSA2USB_MINOR_TO_INSTANCE(getminor(*devp)))) == NULL) {
10590Sstevel@tonic-gate /* deferred detach */
10600Sstevel@tonic-gate
10610Sstevel@tonic-gate return (ENXIO);
10620Sstevel@tonic-gate }
10630Sstevel@tonic-gate
10640Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
10650Sstevel@tonic-gate "scsa2usb_ugen_open: dev_t=0x%lx", *devp);
10660Sstevel@tonic-gate
10670Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
10680Sstevel@tonic-gate
10690Sstevel@tonic-gate /* if this is the first ugen open, check on transport busy */
1070*11427SVincent.Wang@Sun.COM if (scsa2usbp->scsa2usb_busy_proc != curproc) {
10710Sstevel@tonic-gate while (scsa2usbp->scsa2usb_transport_busy ||
10720Sstevel@tonic-gate (scsa2usb_all_waitQs_empty(scsa2usbp) !=
10730Sstevel@tonic-gate USB_SUCCESS)) {
10740Sstevel@tonic-gate rval = cv_wait_sig(
10754700Sfb209375 &scsa2usbp->scsa2usb_transport_busy_cv,
10764700Sfb209375 &scsa2usbp->scsa2usb_mutex);
10770Sstevel@tonic-gate if (rval == 0) {
10780Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
10790Sstevel@tonic-gate
10800Sstevel@tonic-gate return (EINTR);
10810Sstevel@tonic-gate }
10820Sstevel@tonic-gate }
10830Sstevel@tonic-gate scsa2usbp->scsa2usb_transport_busy++;
1084*11427SVincent.Wang@Sun.COM scsa2usbp->scsa2usb_busy_proc = curproc;
10850Sstevel@tonic-gate }
1086*11427SVincent.Wang@Sun.COM
10870Sstevel@tonic-gate scsa2usbp->scsa2usb_ugen_open_count++;
10880Sstevel@tonic-gate
10890Sstevel@tonic-gate scsa2usb_raise_power(scsa2usbp);
10900Sstevel@tonic-gate
10910Sstevel@tonic-gate scsa2usb_close_usb_pipes(scsa2usbp);
10920Sstevel@tonic-gate
10930Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
10940Sstevel@tonic-gate
10950Sstevel@tonic-gate rval = usb_ugen_open(scsa2usbp->scsa2usb_ugen_hdl, devp, flag,
10964700Sfb209375 sflag, cr);
1097*11427SVincent.Wang@Sun.COM if (!rval) {
1098*11427SVincent.Wang@Sun.COM /*
1099*11427SVincent.Wang@Sun.COM * if usb_ugen_open() succeeded, we'll change the minor number
1100*11427SVincent.Wang@Sun.COM * so that we can keep track of every open()/close() issued by
1101*11427SVincent.Wang@Sun.COM * the userland processes. We need to pick a minor number that
1102*11427SVincent.Wang@Sun.COM * is not used by the ugen framework
1103*11427SVincent.Wang@Sun.COM */
1104*11427SVincent.Wang@Sun.COM
1105*11427SVincent.Wang@Sun.COM usb_ugen_hdl_impl_t *usb_ugen_hdl_impl;
1106*11427SVincent.Wang@Sun.COM ugen_state_t *ugenp;
1107*11427SVincent.Wang@Sun.COM int ugen_minor, clone;
1108*11427SVincent.Wang@Sun.COM
1109*11427SVincent.Wang@Sun.COM mutex_enter(&scsa2usbp->scsa2usb_mutex);
1110*11427SVincent.Wang@Sun.COM
1111*11427SVincent.Wang@Sun.COM usb_ugen_hdl_impl =
1112*11427SVincent.Wang@Sun.COM (usb_ugen_hdl_impl_t *)scsa2usbp->scsa2usb_ugen_hdl;
1113*11427SVincent.Wang@Sun.COM ugenp = usb_ugen_hdl_impl->hdl_ugenp;
1114*11427SVincent.Wang@Sun.COM
1115*11427SVincent.Wang@Sun.COM /* 'clone' is bigger than any ugen minor in use */
1116*11427SVincent.Wang@Sun.COM for (clone = ugenp->ug_minor_node_table_index + 1;
1117*11427SVincent.Wang@Sun.COM clone < SCSA2USB_MAX_CLONE; clone++) {
1118*11427SVincent.Wang@Sun.COM if (!scsa2usbp->scsa2usb_clones[clone])
1119*11427SVincent.Wang@Sun.COM break;
1120*11427SVincent.Wang@Sun.COM }
1121*11427SVincent.Wang@Sun.COM
1122*11427SVincent.Wang@Sun.COM if (clone >= SCSA2USB_MAX_CLONE) {
1123*11427SVincent.Wang@Sun.COM cmn_err(CE_WARN, "scsa2usb_ugen_open: too many clones");
1124*11427SVincent.Wang@Sun.COM rval = EBUSY;
1125*11427SVincent.Wang@Sun.COM mutex_exit(&scsa2usbp->scsa2usb_mutex);
1126*11427SVincent.Wang@Sun.COM goto open_done;
1127*11427SVincent.Wang@Sun.COM }
1128*11427SVincent.Wang@Sun.COM
1129*11427SVincent.Wang@Sun.COM ugen_minor = getminor(*devp) & SCSA2USB_MINOR_UGEN_BITS_MASK;
1130*11427SVincent.Wang@Sun.COM *devp = makedevice(getmajor(*devp),
1131*11427SVincent.Wang@Sun.COM (scsa2usbp->scsa2usb_instance
1132*11427SVincent.Wang@Sun.COM << SCSA2USB_MINOR_INSTANCE_SHIFT)
1133*11427SVincent.Wang@Sun.COM + clone);
1134*11427SVincent.Wang@Sun.COM
1135*11427SVincent.Wang@Sun.COM /* save the ugen minor */
1136*11427SVincent.Wang@Sun.COM scsa2usbp->scsa2usb_clones[clone] = (uint8_t)ugen_minor;
1137*11427SVincent.Wang@Sun.COM USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
1138*11427SVincent.Wang@Sun.COM "scsa2usb_ugen_open: new dev=%lx, old minor=%x",
1139*11427SVincent.Wang@Sun.COM *devp, ugen_minor);
1140*11427SVincent.Wang@Sun.COM
1141*11427SVincent.Wang@Sun.COM mutex_exit(&scsa2usbp->scsa2usb_mutex);
1142*11427SVincent.Wang@Sun.COM }
1143*11427SVincent.Wang@Sun.COM
1144*11427SVincent.Wang@Sun.COM open_done:
11450Sstevel@tonic-gate
11460Sstevel@tonic-gate if (rval) {
11470Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
11480Sstevel@tonic-gate
11490Sstevel@tonic-gate /* reopen the pipes */
11500Sstevel@tonic-gate if (--scsa2usbp->scsa2usb_ugen_open_count == 0) {
11510Sstevel@tonic-gate scsa2usbp->scsa2usb_transport_busy--;
1152*11427SVincent.Wang@Sun.COM scsa2usbp->scsa2usb_busy_proc = NULL;
11530Sstevel@tonic-gate cv_signal(&scsa2usbp->scsa2usb_transport_busy_cv);
11540Sstevel@tonic-gate }
1155189Sfrits mutex_exit(&scsa2usbp->scsa2usb_mutex);
1156189Sfrits
11570Sstevel@tonic-gate scsa2usb_pm_idle_component(scsa2usbp);
11580Sstevel@tonic-gate }
11590Sstevel@tonic-gate
11600Sstevel@tonic-gate return (rval);
11610Sstevel@tonic-gate }
11620Sstevel@tonic-gate
11630Sstevel@tonic-gate
11640Sstevel@tonic-gate /*
11650Sstevel@tonic-gate * scsa2usb_ugen_close()
11660Sstevel@tonic-gate */
11670Sstevel@tonic-gate static int
scsa2usb_ugen_close(dev_t dev,int flag,int otype,cred_t * cr)11680Sstevel@tonic-gate scsa2usb_ugen_close(dev_t dev, int flag, int otype, cred_t *cr)
11690Sstevel@tonic-gate {
11700Sstevel@tonic-gate int rval;
1171*11427SVincent.Wang@Sun.COM int ugen_minor, clone;
11720Sstevel@tonic-gate
11730Sstevel@tonic-gate scsa2usb_state_t *scsa2usbp = ddi_get_soft_state(scsa2usb_statep,
11744700Sfb209375 SCSA2USB_MINOR_TO_INSTANCE(getminor(dev)));
11750Sstevel@tonic-gate
11760Sstevel@tonic-gate if (scsa2usbp == NULL) {
11770Sstevel@tonic-gate
11780Sstevel@tonic-gate return (ENXIO);
11790Sstevel@tonic-gate }
11800Sstevel@tonic-gate
11810Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
11820Sstevel@tonic-gate "scsa2usb_ugen_close: dev_t=0x%lx", dev);
11830Sstevel@tonic-gate
1184*11427SVincent.Wang@Sun.COM clone = getminor(dev) & SCSA2USB_MINOR_UGEN_BITS_MASK;
1185*11427SVincent.Wang@Sun.COM ugen_minor = scsa2usbp->scsa2usb_clones[clone];
1186*11427SVincent.Wang@Sun.COM dev = makedevice(getmajor(dev),
1187*11427SVincent.Wang@Sun.COM (scsa2usbp->scsa2usb_instance << SCSA2USB_MINOR_INSTANCE_SHIFT)
1188*11427SVincent.Wang@Sun.COM + ugen_minor);
1189*11427SVincent.Wang@Sun.COM USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
1190*11427SVincent.Wang@Sun.COM "scsa2usb_ugen_close: old dev=%lx", dev);
11910Sstevel@tonic-gate rval = usb_ugen_close(scsa2usbp->scsa2usb_ugen_hdl, dev, flag,
11924700Sfb209375 otype, cr);
11930Sstevel@tonic-gate
11940Sstevel@tonic-gate if (rval == 0) {
11950Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
11960Sstevel@tonic-gate
1197*11427SVincent.Wang@Sun.COM scsa2usbp->scsa2usb_clones[clone] = 0;
11980Sstevel@tonic-gate /* reopen the pipes */
11990Sstevel@tonic-gate if (--scsa2usbp->scsa2usb_ugen_open_count == 0) {
12000Sstevel@tonic-gate scsa2usbp->scsa2usb_transport_busy--;
1201*11427SVincent.Wang@Sun.COM scsa2usbp->scsa2usb_busy_proc = NULL;
12020Sstevel@tonic-gate cv_signal(&scsa2usbp->scsa2usb_transport_busy_cv);
12030Sstevel@tonic-gate }
1204189Sfrits mutex_exit(&scsa2usbp->scsa2usb_mutex);
1205189Sfrits
12060Sstevel@tonic-gate scsa2usb_pm_idle_component(scsa2usbp);
12070Sstevel@tonic-gate }
12080Sstevel@tonic-gate
12090Sstevel@tonic-gate return (rval);
12100Sstevel@tonic-gate }
12110Sstevel@tonic-gate
12120Sstevel@tonic-gate
12130Sstevel@tonic-gate /*
12140Sstevel@tonic-gate * scsa2usb_ugen_read/write()
12150Sstevel@tonic-gate */
12160Sstevel@tonic-gate /*ARGSUSED*/
12170Sstevel@tonic-gate static int
scsa2usb_ugen_read(dev_t dev,struct uio * uiop,cred_t * credp)12180Sstevel@tonic-gate scsa2usb_ugen_read(dev_t dev, struct uio *uiop, cred_t *credp)
12190Sstevel@tonic-gate {
1220*11427SVincent.Wang@Sun.COM int clone, ugen_minor;
12210Sstevel@tonic-gate scsa2usb_state_t *scsa2usbp = ddi_get_soft_state(scsa2usb_statep,
12224700Sfb209375 SCSA2USB_MINOR_TO_INSTANCE(getminor(dev)));
12230Sstevel@tonic-gate
12240Sstevel@tonic-gate if (scsa2usbp == NULL) {
12250Sstevel@tonic-gate
12260Sstevel@tonic-gate return (ENXIO);
12270Sstevel@tonic-gate }
12280Sstevel@tonic-gate
12290Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
12300Sstevel@tonic-gate "scsa2usb_ugen_read: dev_t=0x%lx", dev);
12310Sstevel@tonic-gate
1232*11427SVincent.Wang@Sun.COM clone = getminor(dev) & SCSA2USB_MINOR_UGEN_BITS_MASK;
1233*11427SVincent.Wang@Sun.COM ugen_minor = scsa2usbp->scsa2usb_clones[clone];
1234*11427SVincent.Wang@Sun.COM dev = makedevice(getmajor(dev),
1235*11427SVincent.Wang@Sun.COM (scsa2usbp->scsa2usb_instance << SCSA2USB_MINOR_INSTANCE_SHIFT)
1236*11427SVincent.Wang@Sun.COM + ugen_minor);
12370Sstevel@tonic-gate
12380Sstevel@tonic-gate return (usb_ugen_read(scsa2usbp->scsa2usb_ugen_hdl, dev,
12394700Sfb209375 uiop, credp));
12400Sstevel@tonic-gate }
12410Sstevel@tonic-gate
12420Sstevel@tonic-gate
12430Sstevel@tonic-gate /*ARGSUSED*/
12440Sstevel@tonic-gate static int
scsa2usb_ugen_write(dev_t dev,struct uio * uiop,cred_t * credp)12450Sstevel@tonic-gate scsa2usb_ugen_write(dev_t dev, struct uio *uiop, cred_t *credp)
12460Sstevel@tonic-gate {
1247*11427SVincent.Wang@Sun.COM int clone, ugen_minor;
12480Sstevel@tonic-gate scsa2usb_state_t *scsa2usbp = ddi_get_soft_state(scsa2usb_statep,
12494700Sfb209375 SCSA2USB_MINOR_TO_INSTANCE(getminor(dev)));
12500Sstevel@tonic-gate
12510Sstevel@tonic-gate if (scsa2usbp == NULL) {
12520Sstevel@tonic-gate
12530Sstevel@tonic-gate return (ENXIO);
12540Sstevel@tonic-gate }
12550Sstevel@tonic-gate
12560Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
12570Sstevel@tonic-gate "scsa2usb_ugen_write: dev_t=0x%lx", dev);
12580Sstevel@tonic-gate
1259*11427SVincent.Wang@Sun.COM clone = getminor(dev) & SCSA2USB_MINOR_UGEN_BITS_MASK;
1260*11427SVincent.Wang@Sun.COM ugen_minor = scsa2usbp->scsa2usb_clones[clone];
1261*11427SVincent.Wang@Sun.COM dev = makedevice(getmajor(dev),
1262*11427SVincent.Wang@Sun.COM (scsa2usbp->scsa2usb_instance << SCSA2USB_MINOR_INSTANCE_SHIFT)
1263*11427SVincent.Wang@Sun.COM + ugen_minor);
1264*11427SVincent.Wang@Sun.COM
12650Sstevel@tonic-gate return (usb_ugen_write(scsa2usbp->scsa2usb_ugen_hdl,
12664700Sfb209375 dev, uiop, credp));
12670Sstevel@tonic-gate }
12680Sstevel@tonic-gate
12690Sstevel@tonic-gate
12700Sstevel@tonic-gate /*
12710Sstevel@tonic-gate * scsa2usb_ugen_poll
12720Sstevel@tonic-gate */
12730Sstevel@tonic-gate static int
scsa2usb_ugen_poll(dev_t dev,short events,int anyyet,short * reventsp,struct pollhead ** phpp)12740Sstevel@tonic-gate scsa2usb_ugen_poll(dev_t dev, short events,
12750Sstevel@tonic-gate int anyyet, short *reventsp, struct pollhead **phpp)
12760Sstevel@tonic-gate {
1277*11427SVincent.Wang@Sun.COM int clone, ugen_minor;
12780Sstevel@tonic-gate scsa2usb_state_t *scsa2usbp = ddi_get_soft_state(scsa2usb_statep,
12794700Sfb209375 SCSA2USB_MINOR_TO_INSTANCE(getminor(dev)));
12800Sstevel@tonic-gate
12810Sstevel@tonic-gate if (scsa2usbp == NULL) {
12820Sstevel@tonic-gate
12830Sstevel@tonic-gate return (ENXIO);
12840Sstevel@tonic-gate }
12850Sstevel@tonic-gate
12860Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
12870Sstevel@tonic-gate "scsa2usb_ugen_poll: dev_t=0x%lx", dev);
12880Sstevel@tonic-gate
1289*11427SVincent.Wang@Sun.COM clone = getminor(dev) & SCSA2USB_MINOR_UGEN_BITS_MASK;
1290*11427SVincent.Wang@Sun.COM ugen_minor = scsa2usbp->scsa2usb_clones[clone];
1291*11427SVincent.Wang@Sun.COM dev = makedevice(getmajor(dev),
1292*11427SVincent.Wang@Sun.COM (scsa2usbp->scsa2usb_instance << SCSA2USB_MINOR_INSTANCE_SHIFT)
1293*11427SVincent.Wang@Sun.COM + ugen_minor);
1294*11427SVincent.Wang@Sun.COM
12950Sstevel@tonic-gate return (usb_ugen_poll(scsa2usbp->scsa2usb_ugen_hdl, dev, events,
12964700Sfb209375 anyyet, reventsp, phpp));
12970Sstevel@tonic-gate }
12980Sstevel@tonic-gate
12990Sstevel@tonic-gate
13000Sstevel@tonic-gate /*
13010Sstevel@tonic-gate * scsa2usb_cleanup:
13020Sstevel@tonic-gate * cleanup whatever attach has setup
13030Sstevel@tonic-gate */
13040Sstevel@tonic-gate static int
scsa2usb_cleanup(dev_info_t * dip,scsa2usb_state_t * scsa2usbp)13050Sstevel@tonic-gate scsa2usb_cleanup(dev_info_t *dip, scsa2usb_state_t *scsa2usbp)
13060Sstevel@tonic-gate {
13070Sstevel@tonic-gate int rval, i;
13080Sstevel@tonic-gate scsa2usb_power_t *pm;
13090Sstevel@tonic-gate uint_t lun;
13100Sstevel@tonic-gate
13110Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
13120Sstevel@tonic-gate "scsa2usb_cleanup:");
13130Sstevel@tonic-gate
13140Sstevel@tonic-gate /* wait till the work thread is done */
13150Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
13160Sstevel@tonic-gate for (i = 0; i < SCSA2USB_DRAIN_TIMEOUT; i++) {
13170Sstevel@tonic-gate if (scsa2usbp->scsa2usb_work_thread_id == NULL) {
13180Sstevel@tonic-gate
13190Sstevel@tonic-gate break;
13200Sstevel@tonic-gate }
13210Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
13220Sstevel@tonic-gate delay(drv_usectohz(1000000));
13230Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
13240Sstevel@tonic-gate }
13250Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
13260Sstevel@tonic-gate
13270Sstevel@tonic-gate if (i >= SCSA2USB_DRAIN_TIMEOUT) {
13280Sstevel@tonic-gate
13290Sstevel@tonic-gate return (USB_FAILURE);
13300Sstevel@tonic-gate }
13310Sstevel@tonic-gate
13320Sstevel@tonic-gate /*
13330Sstevel@tonic-gate * Disable the event callbacks first, after this point, event
13340Sstevel@tonic-gate * callbacks will never get called. Note we shouldn't hold
13350Sstevel@tonic-gate * mutex while unregistering events because there may be a
13360Sstevel@tonic-gate * competing event callback thread. Event callbacks are done
13370Sstevel@tonic-gate * with ndi mutex held and this can cause a potential deadlock.
13380Sstevel@tonic-gate */
13390Sstevel@tonic-gate usb_unregister_event_cbs(scsa2usbp->scsa2usb_dip, &scsa2usb_events);
13400Sstevel@tonic-gate
13410Sstevel@tonic-gate if (scsa2usbp->scsa2usb_flags & SCSA2USB_FLAGS_LOCKS_INIT) {
13420Sstevel@tonic-gate /*
13430Sstevel@tonic-gate * if a waitQ exists, get rid of it before destroying it
13440Sstevel@tonic-gate */
13450Sstevel@tonic-gate for (lun = 0; lun < SCSA2USB_MAX_LUNS; lun++) {
13460Sstevel@tonic-gate scsa2usb_flush_waitQ(scsa2usbp, lun, CMD_TRAN_ERR);
13470Sstevel@tonic-gate usba_destroy_list(&scsa2usbp->scsa2usb_waitQ[lun]);
13480Sstevel@tonic-gate }
13490Sstevel@tonic-gate
13500Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
13510Sstevel@tonic-gate if (scsa2usbp->scsa2usb_flags &
13520Sstevel@tonic-gate SCSA2USB_FLAGS_HBA_ATTACH_SETUP) {
13530Sstevel@tonic-gate (void) scsi_hba_detach(dip);
13540Sstevel@tonic-gate scsi_hba_tran_free(scsa2usbp->scsa2usb_tran);
13550Sstevel@tonic-gate }
13560Sstevel@tonic-gate
13570Sstevel@tonic-gate if (scsa2usbp->scsa2usb_flags &
13580Sstevel@tonic-gate SCSA2USB_FLAGS_PIPES_OPENED) {
13590Sstevel@tonic-gate scsa2usb_close_usb_pipes(scsa2usbp);
13600Sstevel@tonic-gate }
13610Sstevel@tonic-gate
13620Sstevel@tonic-gate /* Lower the power */
13630Sstevel@tonic-gate pm = scsa2usbp->scsa2usb_pm;
13640Sstevel@tonic-gate
13650Sstevel@tonic-gate if (pm && (scsa2usbp->scsa2usb_dev_state !=
13660Sstevel@tonic-gate USB_DEV_DISCONNECTED)) {
13670Sstevel@tonic-gate if (pm->scsa2usb_wakeup_enabled) {
13680Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
13690Sstevel@tonic-gate (void) pm_raise_power(dip, 0,
13704700Sfb209375 USB_DEV_OS_FULL_PWR);
13710Sstevel@tonic-gate
13720Sstevel@tonic-gate if ((rval = usb_handle_remote_wakeup(dip,
13730Sstevel@tonic-gate USB_REMOTE_WAKEUP_DISABLE)) !=
13740Sstevel@tonic-gate USB_SUCCESS) {
1375978Sfrits USB_DPRINTF_L2(DPRINT_MASK_SCSA,
13760Sstevel@tonic-gate scsa2usbp->scsa2usb_log_handle,
13770Sstevel@tonic-gate "disable remote wakeup failed "
13780Sstevel@tonic-gate "(%d)", rval);
13790Sstevel@tonic-gate }
13800Sstevel@tonic-gate } else {
13810Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
13820Sstevel@tonic-gate }
13830Sstevel@tonic-gate
13840Sstevel@tonic-gate (void) pm_lower_power(dip, 0, USB_DEV_OS_PWR_OFF);
13850Sstevel@tonic-gate
13860Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
13870Sstevel@tonic-gate }
13880Sstevel@tonic-gate
13890Sstevel@tonic-gate if (pm) {
13900Sstevel@tonic-gate kmem_free(pm, sizeof (scsa2usb_power_t));
13910Sstevel@tonic-gate }
13920Sstevel@tonic-gate
13930Sstevel@tonic-gate if (scsa2usbp->scsa2usb_override_str) {
13940Sstevel@tonic-gate kmem_free(scsa2usbp->scsa2usb_override_str,
13950Sstevel@tonic-gate strlen(scsa2usbp->scsa2usb_override_str) + 1);
13960Sstevel@tonic-gate scsa2usbp->scsa2usb_override_str = NULL;
13970Sstevel@tonic-gate }
13980Sstevel@tonic-gate
13990Sstevel@tonic-gate /* remove the minor nodes */
14000Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL);
14010Sstevel@tonic-gate
14020Sstevel@tonic-gate /* Cancel the registered panic callback */
14030Sstevel@tonic-gate scsa2usb_panic_callb_fini(scsa2usbp);
14040Sstevel@tonic-gate
14050Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
14060Sstevel@tonic-gate
14070Sstevel@tonic-gate mutex_destroy(&scsa2usbp->scsa2usb_mutex);
14080Sstevel@tonic-gate cv_destroy(&scsa2usbp->scsa2usb_transport_busy_cv);
14090Sstevel@tonic-gate }
14100Sstevel@tonic-gate
14110Sstevel@tonic-gate usb_client_detach(scsa2usbp->scsa2usb_dip,
14124700Sfb209375 scsa2usbp->scsa2usb_dev_data);
14130Sstevel@tonic-gate
14140Sstevel@tonic-gate if (scsa2usbp->scsa2usb_ugen_hdl) {
14150Sstevel@tonic-gate (void) usb_ugen_detach(scsa2usbp->scsa2usb_ugen_hdl,
14164700Sfb209375 DDI_DETACH);
14170Sstevel@tonic-gate usb_ugen_release_hdl(scsa2usbp->scsa2usb_ugen_hdl);
14180Sstevel@tonic-gate }
14190Sstevel@tonic-gate
14200Sstevel@tonic-gate usb_free_log_hdl(scsa2usbp->scsa2usb_log_handle);
14210Sstevel@tonic-gate
14220Sstevel@tonic-gate ddi_prop_remove_all(dip);
14230Sstevel@tonic-gate
14240Sstevel@tonic-gate ddi_soft_state_free(scsa2usb_statep, ddi_get_instance(dip));
14250Sstevel@tonic-gate
14260Sstevel@tonic-gate return (USB_SUCCESS);
14270Sstevel@tonic-gate }
14280Sstevel@tonic-gate
14290Sstevel@tonic-gate
14300Sstevel@tonic-gate /*
14310Sstevel@tonic-gate * scsa2usb_override:
14320Sstevel@tonic-gate * some devices may be attached even though their subclass or
14330Sstevel@tonic-gate * protocol info is not according to spec.
14340Sstevel@tonic-gate * these can be determined by the 'subclass-protocol-override'
14350Sstevel@tonic-gate * property set in the conf file.
14360Sstevel@tonic-gate */
14370Sstevel@tonic-gate static void
scsa2usb_override(scsa2usb_state_t * scsa2usbp)14380Sstevel@tonic-gate scsa2usb_override(scsa2usb_state_t *scsa2usbp)
14390Sstevel@tonic-gate {
14400Sstevel@tonic-gate scsa2usb_ov_t ov;
14410Sstevel@tonic-gate char **override_str = NULL;
14420Sstevel@tonic-gate char *override_str_cpy;
14430Sstevel@tonic-gate uint_t override_str_len, override_str_cpy_len;
14440Sstevel@tonic-gate uint_t i;
14450Sstevel@tonic-gate usb_dev_descr_t *descr = scsa2usbp->scsa2usb_dev_data->dev_descr;
14460Sstevel@tonic-gate
14470Sstevel@tonic-gate ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
14480Sstevel@tonic-gate
14490Sstevel@tonic-gate scsa2usbp->scsa2usb_subclass_override =
14500Sstevel@tonic-gate scsa2usbp->scsa2usb_protocol_override = 0;
14510Sstevel@tonic-gate
14520Sstevel@tonic-gate if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, scsa2usbp->scsa2usb_dip,
14530Sstevel@tonic-gate DDI_PROP_DONTPASS, "attribute-override-list",
14540Sstevel@tonic-gate &override_str, &override_str_len) != DDI_PROP_SUCCESS) {
14550Sstevel@tonic-gate
14560Sstevel@tonic-gate return;
14570Sstevel@tonic-gate }
14580Sstevel@tonic-gate
14590Sstevel@tonic-gate /* parse each string in the subclass-protocol-override property */
14600Sstevel@tonic-gate for (i = 0; i < override_str_len; i++) {
14610Sstevel@tonic-gate
14620Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
14630Sstevel@tonic-gate "override_str[%d] = %s", i, override_str[i]);
14640Sstevel@tonic-gate
14650Sstevel@tonic-gate /*
14660Sstevel@tonic-gate * save a copy of the override string for possible
14670Sstevel@tonic-gate * inclusion in soft state later
14680Sstevel@tonic-gate */
14690Sstevel@tonic-gate override_str_cpy_len = strlen(override_str[i]) + 1;
14700Sstevel@tonic-gate override_str_cpy = kmem_zalloc(override_str_cpy_len, KM_SLEEP);
14710Sstevel@tonic-gate (void) strcpy(override_str_cpy, override_str[i]);
14720Sstevel@tonic-gate
14730Sstevel@tonic-gate bzero(&ov, sizeof (scsa2usb_ov_t));
14740Sstevel@tonic-gate
14750Sstevel@tonic-gate if (scsa2usb_parse_input_str(override_str[i], &ov,
14760Sstevel@tonic-gate scsa2usbp) == USB_FAILURE) {
14770Sstevel@tonic-gate kmem_free(override_str_cpy, override_str_cpy_len);
14780Sstevel@tonic-gate continue;
14790Sstevel@tonic-gate }
14800Sstevel@tonic-gate
14810Sstevel@tonic-gate /*
14820Sstevel@tonic-gate * see if subclass/protocol needs to be overridden for device
14830Sstevel@tonic-gate * or if device should not be power managed
14840Sstevel@tonic-gate * if there'a a match, save the override string in soft state
14850Sstevel@tonic-gate */
14860Sstevel@tonic-gate if (((descr->idVendor == (uint16_t)ov.vid) || (ov.vid == 0)) &&
14870Sstevel@tonic-gate ((descr->idProduct == (uint16_t)ov.pid) || (ov.pid == 0)) &&
14880Sstevel@tonic-gate ((descr->bcdDevice == (uint16_t)ov.rev) || (ov.rev == 0))) {
14890Sstevel@tonic-gate scsa2usbp->scsa2usb_subclass_override = ov.subclass;
14900Sstevel@tonic-gate scsa2usbp->scsa2usb_protocol_override = ov.protocol;
14910Sstevel@tonic-gate
1492880Sfrits USB_DPRINTF_L2(DPRINT_MASK_SCSA,
14930Sstevel@tonic-gate scsa2usbp->scsa2usb_log_handle,
14940Sstevel@tonic-gate "vid=0x%x pid=0x%x rev=0x%x subclass=0x%x "
14950Sstevel@tonic-gate "protocol=0x%x "
14961415Scg149915 "pmoff=%d fake_removable=%d modesense=%d "
14970Sstevel@tonic-gate "reduced-cmd-support=%d",
14980Sstevel@tonic-gate ov.vid, ov.pid, ov.rev, ov.subclass, ov.protocol,
14991415Scg149915 ov.pmoff, ov.fake_removable, ov.no_modesense,
15000Sstevel@tonic-gate ov.reduced_cmd_support);
15010Sstevel@tonic-gate
15020Sstevel@tonic-gate if (ov.pmoff) {
15030Sstevel@tonic-gate scsa2usbp->scsa2usb_attrs &= ~SCSA2USB_ATTRS_PM;
15040Sstevel@tonic-gate }
15051415Scg149915 if (ov.fake_removable) {
15060Sstevel@tonic-gate scsa2usbp->scsa2usb_attrs &=
15070Sstevel@tonic-gate ~SCSA2USB_ATTRS_RMB;
15080Sstevel@tonic-gate }
15090Sstevel@tonic-gate if (ov.no_modesense) {
15100Sstevel@tonic-gate scsa2usbp->scsa2usb_attrs &=
15110Sstevel@tonic-gate ~SCSA2USB_ATTRS_MODE_SENSE;
15120Sstevel@tonic-gate }
15130Sstevel@tonic-gate if (ov.reduced_cmd_support) {
15140Sstevel@tonic-gate scsa2usbp->scsa2usb_attrs &=
15150Sstevel@tonic-gate ~SCSA2USB_ATTRS_REDUCED_CMD;
15160Sstevel@tonic-gate }
15170Sstevel@tonic-gate scsa2usbp->scsa2usb_override_str = override_str_cpy;
15180Sstevel@tonic-gate break;
15190Sstevel@tonic-gate } else {
15200Sstevel@tonic-gate kmem_free(override_str_cpy, override_str_cpy_len);
15210Sstevel@tonic-gate }
15220Sstevel@tonic-gate }
15230Sstevel@tonic-gate
15240Sstevel@tonic-gate ddi_prop_free(override_str);
15250Sstevel@tonic-gate }
15260Sstevel@tonic-gate
15270Sstevel@tonic-gate
15280Sstevel@tonic-gate /*
15290Sstevel@tonic-gate * scsa2usb_parse_input_str:
15300Sstevel@tonic-gate * parse one conf file subclass-protocol-override string
15310Sstevel@tonic-gate * return vendor id, product id, revision, subclass, protocol
15320Sstevel@tonic-gate * function return is success or failure
15330Sstevel@tonic-gate */
15340Sstevel@tonic-gate static int
scsa2usb_parse_input_str(char * str,scsa2usb_ov_t * ovp,scsa2usb_state_t * scsa2usbp)15350Sstevel@tonic-gate scsa2usb_parse_input_str(char *str, scsa2usb_ov_t *ovp,
15360Sstevel@tonic-gate scsa2usb_state_t *scsa2usbp)
15370Sstevel@tonic-gate {
15380Sstevel@tonic-gate char *input_field, *input_value;
15390Sstevel@tonic-gate char *lasts;
15400Sstevel@tonic-gate uint_t i;
15410Sstevel@tonic-gate u_longlong_t value;
15420Sstevel@tonic-gate
15430Sstevel@tonic-gate /* parse all the input pairs in the string */
15440Sstevel@tonic-gate for (input_field = scsa2usb_strtok_r(str, "=", &lasts);
15450Sstevel@tonic-gate input_field != NULL;
15460Sstevel@tonic-gate input_field = scsa2usb_strtok_r(lasts, "=", &lasts)) {
15470Sstevel@tonic-gate
15480Sstevel@tonic-gate if ((input_value = scsa2usb_strtok_r(lasts, " ", &lasts)) ==
15490Sstevel@tonic-gate NULL) {
15500Sstevel@tonic-gate scsa2usb_override_error("format", scsa2usbp);
15510Sstevel@tonic-gate
15520Sstevel@tonic-gate return (USB_FAILURE);
15530Sstevel@tonic-gate }
15540Sstevel@tonic-gate /* if input value is a 'don't care', skip to the next pair */
15550Sstevel@tonic-gate if (strcmp(input_value, "*") == 0) {
15560Sstevel@tonic-gate continue;
15570Sstevel@tonic-gate }
15580Sstevel@tonic-gate if (strcasecmp(input_field, "vid") == 0) {
15590Sstevel@tonic-gate if (kobj_getvalue(input_value, &value) == -1) {
15600Sstevel@tonic-gate scsa2usb_override_error("vendor id", scsa2usbp);
15610Sstevel@tonic-gate
15620Sstevel@tonic-gate return (USB_FAILURE);
15630Sstevel@tonic-gate }
15640Sstevel@tonic-gate ovp->vid = (int)value;
15650Sstevel@tonic-gate } else if (strcasecmp(input_field, "pid") == 0) {
15660Sstevel@tonic-gate if (kobj_getvalue(input_value, &value) == -1) {
15670Sstevel@tonic-gate scsa2usb_override_error("product id",
15680Sstevel@tonic-gate scsa2usbp);
15690Sstevel@tonic-gate
15700Sstevel@tonic-gate return (USB_FAILURE);
15710Sstevel@tonic-gate }
15720Sstevel@tonic-gate ovp->pid = (int)value;
15730Sstevel@tonic-gate } else if (strcasecmp(input_field, "rev") == 0) {
15740Sstevel@tonic-gate if (kobj_getvalue(input_value, &value) == -1) {
15750Sstevel@tonic-gate scsa2usb_override_error("revision id",
15760Sstevel@tonic-gate scsa2usbp);
15770Sstevel@tonic-gate
15780Sstevel@tonic-gate return (USB_FAILURE);
15790Sstevel@tonic-gate }
15800Sstevel@tonic-gate ovp->rev = (int)value;
15810Sstevel@tonic-gate } else if (strcasecmp(input_field, "subclass") == 0) {
15820Sstevel@tonic-gate for (i = 0; i < N_SCSA2USB_SUBC_OVERRIDE; i++) {
15830Sstevel@tonic-gate if (strcasecmp(input_value,
15840Sstevel@tonic-gate scsa2usb_subclass[i].name) == 0) {
15850Sstevel@tonic-gate ovp->subclass =
15860Sstevel@tonic-gate scsa2usb_subclass[i].value;
15870Sstevel@tonic-gate break;
15880Sstevel@tonic-gate }
15890Sstevel@tonic-gate }
15900Sstevel@tonic-gate if (ovp->subclass == 0) {
15910Sstevel@tonic-gate scsa2usb_override_error("subclass", scsa2usbp);
15920Sstevel@tonic-gate
15930Sstevel@tonic-gate return (USB_FAILURE);
15940Sstevel@tonic-gate }
15950Sstevel@tonic-gate } else if (strcasecmp(input_field, "protocol") == 0) {
15960Sstevel@tonic-gate for (i = 0; i < N_SCSA2USB_PROT_OVERRIDE; i++) {
15970Sstevel@tonic-gate if (strcasecmp(input_value,
15980Sstevel@tonic-gate scsa2usb_protocol[i].name) == 0) {
15990Sstevel@tonic-gate ovp->protocol =
16000Sstevel@tonic-gate scsa2usb_protocol[i].value;
16010Sstevel@tonic-gate break;
16020Sstevel@tonic-gate }
16030Sstevel@tonic-gate }
16040Sstevel@tonic-gate if (ovp->protocol == 0) {
16050Sstevel@tonic-gate scsa2usb_override_error("protocol", scsa2usbp);
16060Sstevel@tonic-gate
16070Sstevel@tonic-gate return (USB_FAILURE);
16080Sstevel@tonic-gate }
16090Sstevel@tonic-gate } else if (strcasecmp(input_field, "pm") == 0) {
16100Sstevel@tonic-gate if (strcasecmp(input_value, "off") == 0) {
16110Sstevel@tonic-gate ovp->pmoff = 1;
16120Sstevel@tonic-gate break;
16130Sstevel@tonic-gate } else {
16140Sstevel@tonic-gate scsa2usb_override_error("pm", scsa2usbp);
16150Sstevel@tonic-gate
16160Sstevel@tonic-gate return (USB_FAILURE);
16170Sstevel@tonic-gate }
16180Sstevel@tonic-gate } else if (strcasecmp(input_field, "removable") == 0) {
16191415Scg149915 if (strcasecmp(input_value, "true") == 0) {
16201415Scg149915 ovp->fake_removable = 1;
16210Sstevel@tonic-gate break;
16220Sstevel@tonic-gate } else {
16230Sstevel@tonic-gate scsa2usb_override_error("removable", scsa2usbp);
16240Sstevel@tonic-gate
16250Sstevel@tonic-gate return (USB_FAILURE);
16260Sstevel@tonic-gate }
16270Sstevel@tonic-gate } else if (strcasecmp(input_field, "modesense") == 0) {
16280Sstevel@tonic-gate if (strcasecmp(input_value, "false") == 0) {
16290Sstevel@tonic-gate ovp->no_modesense = 1;
16300Sstevel@tonic-gate break;
16310Sstevel@tonic-gate } else {
16320Sstevel@tonic-gate scsa2usb_override_error("modesense",
16334700Sfb209375 scsa2usbp);
16340Sstevel@tonic-gate
16350Sstevel@tonic-gate return (USB_FAILURE);
16360Sstevel@tonic-gate }
16370Sstevel@tonic-gate } else if (strcasecmp(input_field,
16380Sstevel@tonic-gate "reduced-cmd-support") == 0) {
16390Sstevel@tonic-gate if (strcasecmp(input_value, "true") == 0) {
16400Sstevel@tonic-gate ovp->reduced_cmd_support = 1;
16410Sstevel@tonic-gate break;
16420Sstevel@tonic-gate } else {
16430Sstevel@tonic-gate scsa2usb_override_error(
16440Sstevel@tonic-gate "reduced-cmd-support", scsa2usbp);
16450Sstevel@tonic-gate
16460Sstevel@tonic-gate return (USB_FAILURE);
16470Sstevel@tonic-gate }
16480Sstevel@tonic-gate } else {
1649880Sfrits scsa2usb_override_error(input_field, scsa2usbp);
16500Sstevel@tonic-gate
16510Sstevel@tonic-gate return (USB_FAILURE);
16520Sstevel@tonic-gate }
16530Sstevel@tonic-gate }
16540Sstevel@tonic-gate
16550Sstevel@tonic-gate return (USB_SUCCESS);
16560Sstevel@tonic-gate }
16570Sstevel@tonic-gate
16580Sstevel@tonic-gate
16590Sstevel@tonic-gate /*
16600Sstevel@tonic-gate * scsa2usb_override_error:
16610Sstevel@tonic-gate * print an error message if conf file string is bad format
16620Sstevel@tonic-gate */
16630Sstevel@tonic-gate static void
scsa2usb_override_error(char * input_field,scsa2usb_state_t * scsa2usbp)16640Sstevel@tonic-gate scsa2usb_override_error(char *input_field, scsa2usb_state_t *scsa2usbp)
16650Sstevel@tonic-gate {
16660Sstevel@tonic-gate USB_DPRINTF_L1(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
1667880Sfrits "invalid %s in scsa2usb.conf file entry", input_field);
16680Sstevel@tonic-gate }
16690Sstevel@tonic-gate
16700Sstevel@tonic-gate /*
16710Sstevel@tonic-gate * scsa2usb_strtok_r:
16720Sstevel@tonic-gate * parse a list of tokens
16730Sstevel@tonic-gate */
16740Sstevel@tonic-gate static char *
scsa2usb_strtok_r(char * p,char * sep,char ** lasts)16750Sstevel@tonic-gate scsa2usb_strtok_r(char *p, char *sep, char **lasts)
16760Sstevel@tonic-gate {
16770Sstevel@tonic-gate char *e;
16780Sstevel@tonic-gate char *tok = NULL;
16790Sstevel@tonic-gate
16800Sstevel@tonic-gate if (p == 0 || *p == 0) {
16810Sstevel@tonic-gate
16820Sstevel@tonic-gate return (NULL);
16830Sstevel@tonic-gate }
16840Sstevel@tonic-gate
16850Sstevel@tonic-gate e = p+strlen(p);
16860Sstevel@tonic-gate
16870Sstevel@tonic-gate do {
16880Sstevel@tonic-gate if (strchr(sep, *p) != NULL) {
16890Sstevel@tonic-gate if (tok != NULL) {
16900Sstevel@tonic-gate *p = 0;
16910Sstevel@tonic-gate *lasts = p+1;
16920Sstevel@tonic-gate
16930Sstevel@tonic-gate return (tok);
16940Sstevel@tonic-gate }
16950Sstevel@tonic-gate } else if (tok == NULL) {
16960Sstevel@tonic-gate tok = p;
16970Sstevel@tonic-gate }
16980Sstevel@tonic-gate } while (++p < e);
16990Sstevel@tonic-gate
17000Sstevel@tonic-gate *lasts = NULL;
17010Sstevel@tonic-gate
17020Sstevel@tonic-gate return (tok);
17030Sstevel@tonic-gate }
17040Sstevel@tonic-gate
17050Sstevel@tonic-gate
17060Sstevel@tonic-gate /*
17070Sstevel@tonic-gate * scsa2usb_validate_attrs:
17080Sstevel@tonic-gate * many devices have BO/CB/CBI protocol support issues.
17090Sstevel@tonic-gate * use vendor/product info to reset the
17100Sstevel@tonic-gate * individual erroneous attributes
17110Sstevel@tonic-gate *
17120Sstevel@tonic-gate * NOTE: we look at only device at a time (at attach time)
17130Sstevel@tonic-gate */
17140Sstevel@tonic-gate static void
scsa2usb_validate_attrs(scsa2usb_state_t * scsa2usbp)17150Sstevel@tonic-gate scsa2usb_validate_attrs(scsa2usb_state_t *scsa2usbp)
17160Sstevel@tonic-gate {
17170Sstevel@tonic-gate int i, mask;
17180Sstevel@tonic-gate usb_dev_descr_t *desc = scsa2usbp->scsa2usb_dev_data->dev_descr;
17190Sstevel@tonic-gate
17200Sstevel@tonic-gate if (!SCSA2USB_IS_BULK_ONLY(scsa2usbp)) {
17210Sstevel@tonic-gate scsa2usbp->scsa2usb_attrs &= ~SCSA2USB_ATTRS_GET_LUN;
17220Sstevel@tonic-gate }
17230Sstevel@tonic-gate
17240Sstevel@tonic-gate /* determine if this device is on the blacklist */
17250Sstevel@tonic-gate for (i = 0; i < N_SCSA2USB_BLACKLIST; i++) {
17260Sstevel@tonic-gate if ((scsa2usb_blacklist[i].idVendor == desc->idVendor) &&
17270Sstevel@tonic-gate ((scsa2usb_blacklist[i].idProduct == desc->idProduct) ||
17280Sstevel@tonic-gate (scsa2usb_blacklist[i].idProduct == X))) {
17290Sstevel@tonic-gate scsa2usbp->scsa2usb_attrs &=
17304700Sfb209375 ~(scsa2usb_blacklist[i].attributes);
17310Sstevel@tonic-gate break;
17320Sstevel@tonic-gate }
17330Sstevel@tonic-gate }
17340Sstevel@tonic-gate
17350Sstevel@tonic-gate /*
17360Sstevel@tonic-gate * Mitsumi's CD-RW drives subclass isn't UFI.
17370Sstevel@tonic-gate * But they support UFI command-set (this code ensures that)
17380Sstevel@tonic-gate * NOTE: This is a special case, and is being called out so.
17390Sstevel@tonic-gate */
17400Sstevel@tonic-gate if (desc->idVendor == MS_MITSUMI_VID) {
17410Sstevel@tonic-gate mask = scsa2usbp->scsa2usb_cmd_protocol & SCSA2USB_CMDSET_MASK;
17420Sstevel@tonic-gate if (mask) {
17430Sstevel@tonic-gate scsa2usbp->scsa2usb_cmd_protocol &= ~mask;
17440Sstevel@tonic-gate }
17450Sstevel@tonic-gate scsa2usbp->scsa2usb_cmd_protocol |= SCSA2USB_UFI_CMDSET;
17460Sstevel@tonic-gate }
17470Sstevel@tonic-gate
17480Sstevel@tonic-gate if (scsa2usbp->scsa2usb_attrs != SCSA2USB_ALL_ATTRS) {
17490Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_SCSA,
17500Sstevel@tonic-gate scsa2usbp->scsa2usb_log_handle,
17510Sstevel@tonic-gate "scsa2usb attributes modified: 0x%x",
17520Sstevel@tonic-gate scsa2usbp->scsa2usb_attrs);
17530Sstevel@tonic-gate }
17540Sstevel@tonic-gate }
17550Sstevel@tonic-gate
17560Sstevel@tonic-gate
17570Sstevel@tonic-gate /*
17580Sstevel@tonic-gate * scsa2usb_create_luns:
17590Sstevel@tonic-gate * check the number of luns but continue if the check fails,
17600Sstevel@tonic-gate * create child nodes for each lun
17610Sstevel@tonic-gate */
17620Sstevel@tonic-gate static void
scsa2usb_create_luns(scsa2usb_state_t * scsa2usbp)17630Sstevel@tonic-gate scsa2usb_create_luns(scsa2usb_state_t *scsa2usbp)
17640Sstevel@tonic-gate {
17650Sstevel@tonic-gate int lun, rval;
17660Sstevel@tonic-gate char *compatible[MAX_COMPAT_NAMES]; /* compatible names */
17670Sstevel@tonic-gate dev_info_t *cdip;
17680Sstevel@tonic-gate uchar_t dtype;
17690Sstevel@tonic-gate char *node_name;
17700Sstevel@tonic-gate char *driver_name = NULL;
17710Sstevel@tonic-gate
17720Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
17730Sstevel@tonic-gate "scsa2usb_create_luns:");
17740Sstevel@tonic-gate
17750Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
17760Sstevel@tonic-gate
17770Sstevel@tonic-gate /* Set n_luns to 1 by default (for floppies and other devices) */
17780Sstevel@tonic-gate scsa2usbp->scsa2usb_n_luns = 1;
17790Sstevel@tonic-gate
17800Sstevel@tonic-gate /*
17810Sstevel@tonic-gate * Check if there are any device out there which don't
17820Sstevel@tonic-gate * support the GET_MAX_LUN command. If so, don't issue
17830Sstevel@tonic-gate * control request to them.
17840Sstevel@tonic-gate */
17850Sstevel@tonic-gate if ((scsa2usbp->scsa2usb_attrs & SCSA2USB_ATTRS_GET_LUN) == 0) {
17869729SBinzi.Cao@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
17870Sstevel@tonic-gate "get_max_lun cmd not supported");
17880Sstevel@tonic-gate } else {
17890Sstevel@tonic-gate if (SCSA2USB_IS_BULK_ONLY(scsa2usbp)) {
17900Sstevel@tonic-gate scsa2usbp->scsa2usb_n_luns =
17914700Sfb209375 scsa2usb_bulk_only_get_max_lun(scsa2usbp);
17920Sstevel@tonic-gate }
17930Sstevel@tonic-gate }
17940Sstevel@tonic-gate
17950Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
17960Sstevel@tonic-gate "scsa2usb_create_luns: %d luns found", scsa2usbp->scsa2usb_n_luns);
17970Sstevel@tonic-gate
17980Sstevel@tonic-gate /*
17990Sstevel@tonic-gate * create disk child for each lun
18000Sstevel@tonic-gate */
18010Sstevel@tonic-gate for (lun = 0; lun < scsa2usbp->scsa2usb_n_luns; lun++) {
18020Sstevel@tonic-gate ASSERT(scsa2usbp->scsa2usb_lun_dip[lun] == NULL);
18030Sstevel@tonic-gate
18040Sstevel@tonic-gate /* do an inquiry to get the dtype of this lun */
18050Sstevel@tonic-gate scsa2usb_do_inquiry(scsa2usbp, 0, lun);
18060Sstevel@tonic-gate
18070Sstevel@tonic-gate dtype = scsa2usbp->scsa2usb_lun_inquiry[lun].
18084700Sfb209375 inq_dtype & DTYPE_MASK;
18090Sstevel@tonic-gate
18100Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
18110Sstevel@tonic-gate "dtype[%d]=0x%x", lun, dtype);
18120Sstevel@tonic-gate
18130Sstevel@tonic-gate driver_name = NULL;
18140Sstevel@tonic-gate
18150Sstevel@tonic-gate switch (dtype) {
18160Sstevel@tonic-gate case DTYPE_DIRECT:
18170Sstevel@tonic-gate case DTYPE_RODIRECT:
18180Sstevel@tonic-gate case DTYPE_OPTICAL:
18190Sstevel@tonic-gate node_name = "disk";
18200Sstevel@tonic-gate driver_name = "sd";
18210Sstevel@tonic-gate
18220Sstevel@tonic-gate break;
18230Sstevel@tonic-gate case DTYPE_SEQUENTIAL:
18240Sstevel@tonic-gate node_name = "tape";
18250Sstevel@tonic-gate driver_name = "st";
18260Sstevel@tonic-gate
18270Sstevel@tonic-gate break;
18280Sstevel@tonic-gate case DTYPE_PRINTER:
18290Sstevel@tonic-gate node_name = "printer";
18300Sstevel@tonic-gate
18310Sstevel@tonic-gate break;
18320Sstevel@tonic-gate case DTYPE_PROCESSOR:
18330Sstevel@tonic-gate node_name = "processor";
18340Sstevel@tonic-gate
18350Sstevel@tonic-gate break;
18360Sstevel@tonic-gate case DTYPE_WORM:
18370Sstevel@tonic-gate node_name = "worm";
18380Sstevel@tonic-gate
18390Sstevel@tonic-gate break;
18400Sstevel@tonic-gate case DTYPE_SCANNER:
18410Sstevel@tonic-gate node_name = "scanner";
18420Sstevel@tonic-gate
18430Sstevel@tonic-gate break;
18440Sstevel@tonic-gate case DTYPE_CHANGER:
18450Sstevel@tonic-gate node_name = "changer";
18460Sstevel@tonic-gate
18470Sstevel@tonic-gate break;
18480Sstevel@tonic-gate case DTYPE_COMM:
18490Sstevel@tonic-gate node_name = "comm";
18500Sstevel@tonic-gate
18510Sstevel@tonic-gate break;
18520Sstevel@tonic-gate case DTYPE_ARRAY_CTRL:
18530Sstevel@tonic-gate node_name = "array_ctrl";
18540Sstevel@tonic-gate
18550Sstevel@tonic-gate break;
18560Sstevel@tonic-gate case DTYPE_ESI:
18570Sstevel@tonic-gate node_name = "esi";
18580Sstevel@tonic-gate driver_name = "ses";
18590Sstevel@tonic-gate
18600Sstevel@tonic-gate break;
18610Sstevel@tonic-gate default:
18620Sstevel@tonic-gate node_name = "generic";
18630Sstevel@tonic-gate
18640Sstevel@tonic-gate break;
18650Sstevel@tonic-gate }
18660Sstevel@tonic-gate
18670Sstevel@tonic-gate if (driver_name) {
18680Sstevel@tonic-gate compatible[0] = driver_name;
18690Sstevel@tonic-gate }
18700Sstevel@tonic-gate
18710Sstevel@tonic-gate ndi_devi_alloc_sleep(scsa2usbp->scsa2usb_dip, node_name,
1872789Sahrens (pnode_t)DEVI_SID_NODEID, &cdip);
18730Sstevel@tonic-gate
18740Sstevel@tonic-gate /* attach target & lun properties */
18750Sstevel@tonic-gate rval = ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "target", 0);
18760Sstevel@tonic-gate if (rval != DDI_PROP_SUCCESS) {
18770Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_SCSA,
18780Sstevel@tonic-gate scsa2usbp->scsa2usb_log_handle,
18790Sstevel@tonic-gate "ndi_prop_update_int target failed %d", rval);
18800Sstevel@tonic-gate (void) ndi_devi_free(cdip);
18810Sstevel@tonic-gate continue;
18820Sstevel@tonic-gate }
18830Sstevel@tonic-gate
18841415Scg149915 rval = ndi_prop_create_boolean(DDI_DEV_T_NONE, cdip,
18851415Scg149915 "hotpluggable");
18861415Scg149915 if (rval != DDI_PROP_SUCCESS) {
18871415Scg149915 USB_DPRINTF_L2(DPRINT_MASK_SCSA,
18881415Scg149915 scsa2usbp->scsa2usb_log_handle,
18891415Scg149915 "ndi_prop_create_boolean hotpluggable failed %d",
18901415Scg149915 rval);
18911415Scg149915 ddi_prop_remove_all(cdip);
18921415Scg149915 (void) ndi_devi_free(cdip);
18931415Scg149915 continue;
18941415Scg149915 }
18951415Scg149915 /*
18961415Scg149915 * Some devices don't support LOG SENSE, so tells
18971415Scg149915 * sd driver not to send this command.
18981415Scg149915 */
18991415Scg149915 rval = ndi_prop_update_int(DDI_DEV_T_NONE, cdip,
19001415Scg149915 "pm-capable", 1);
19011415Scg149915 if (rval != DDI_PROP_SUCCESS) {
19021415Scg149915 USB_DPRINTF_L2(DPRINT_MASK_SCSA,
19031415Scg149915 scsa2usbp->scsa2usb_log_handle,
19041415Scg149915 "ndi_prop_update_int pm-capable failed %d", rval);
19051415Scg149915 ddi_prop_remove_all(cdip);
19061415Scg149915 (void) ndi_devi_free(cdip);
19071415Scg149915 continue;
19081415Scg149915 }
19091415Scg149915
19100Sstevel@tonic-gate rval = ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "lun", lun);
19110Sstevel@tonic-gate if (rval != DDI_PROP_SUCCESS) {
19120Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_SCSA,
19130Sstevel@tonic-gate scsa2usbp->scsa2usb_log_handle,
19140Sstevel@tonic-gate "ndi_prop_update_int lun failed %d", rval);
19150Sstevel@tonic-gate ddi_prop_remove_all(cdip);
19160Sstevel@tonic-gate (void) ndi_devi_free(cdip);
19170Sstevel@tonic-gate continue;
19180Sstevel@tonic-gate }
19190Sstevel@tonic-gate
19200Sstevel@tonic-gate if (driver_name) {
19210Sstevel@tonic-gate rval = ndi_prop_update_string_array(DDI_DEV_T_NONE,
19220Sstevel@tonic-gate cdip, "compatible", (char **)compatible,
19230Sstevel@tonic-gate MAX_COMPAT_NAMES);
19240Sstevel@tonic-gate if (rval != DDI_PROP_SUCCESS) {
19250Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_SCSA,
19260Sstevel@tonic-gate scsa2usbp->scsa2usb_log_handle,
19270Sstevel@tonic-gate "ndi_prop_update_string_array failed %d",
19280Sstevel@tonic-gate rval);
19290Sstevel@tonic-gate ddi_prop_remove_all(cdip);
19300Sstevel@tonic-gate (void) ndi_devi_free(cdip);
19310Sstevel@tonic-gate continue;
19320Sstevel@tonic-gate }
19330Sstevel@tonic-gate }
19340Sstevel@tonic-gate
19350Sstevel@tonic-gate /*
19360Sstevel@tonic-gate * add property "usb" so we always verify that it is our child
19370Sstevel@tonic-gate */
19380Sstevel@tonic-gate rval = ndi_prop_create_boolean(DDI_DEV_T_NONE, cdip, "usb");
19390Sstevel@tonic-gate if (rval != DDI_PROP_SUCCESS) {
19400Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_SCSA,
19410Sstevel@tonic-gate scsa2usbp->scsa2usb_log_handle,
19420Sstevel@tonic-gate "ndi_prop_create_boolean failed %d", rval);
19430Sstevel@tonic-gate ddi_prop_remove_all(cdip);
19440Sstevel@tonic-gate (void) ndi_devi_free(cdip);
19450Sstevel@tonic-gate continue;
19460Sstevel@tonic-gate }
19470Sstevel@tonic-gate
19480Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
19490Sstevel@tonic-gate (void) ddi_initchild(scsa2usbp->scsa2usb_dip, cdip);
19500Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
19510Sstevel@tonic-gate
19520Sstevel@tonic-gate usba_set_usba_device(cdip,
19534700Sfb209375 usba_get_usba_device(scsa2usbp->scsa2usb_dip));
19540Sstevel@tonic-gate }
19550Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
19560Sstevel@tonic-gate }
19570Sstevel@tonic-gate
19580Sstevel@tonic-gate
19590Sstevel@tonic-gate /*
19600Sstevel@tonic-gate * scsa2usb_is_usb:
19610Sstevel@tonic-gate * scsa2usb gets called for all possible sd children.
19620Sstevel@tonic-gate * we can only accept usb children
19630Sstevel@tonic-gate */
19640Sstevel@tonic-gate static int
scsa2usb_is_usb(dev_info_t * dip)19650Sstevel@tonic-gate scsa2usb_is_usb(dev_info_t *dip)
19660Sstevel@tonic-gate {
19670Sstevel@tonic-gate if (dip) {
19680Sstevel@tonic-gate return (ddi_prop_exists(DDI_DEV_T_ANY, dip,
19690Sstevel@tonic-gate DDI_PROP_DONTPASS, "usb"));
19700Sstevel@tonic-gate }
19710Sstevel@tonic-gate return (0);
19720Sstevel@tonic-gate }
19730Sstevel@tonic-gate
19740Sstevel@tonic-gate
19750Sstevel@tonic-gate /*
19760Sstevel@tonic-gate * Panic Stuff
19770Sstevel@tonic-gate * scsa2usb_panic_callb_init:
19780Sstevel@tonic-gate * initialize PANIC callb and free allocated resources
19790Sstevel@tonic-gate */
19800Sstevel@tonic-gate static void
scsa2usb_panic_callb_init(scsa2usb_state_t * scsa2usbp)19810Sstevel@tonic-gate scsa2usb_panic_callb_init(scsa2usb_state_t *scsa2usbp)
19820Sstevel@tonic-gate {
19830Sstevel@tonic-gate /*
19840Sstevel@tonic-gate * In case the system panics, the sync command flushes
19850Sstevel@tonic-gate * dirty FS pages or buffers. This would cause a hang
19860Sstevel@tonic-gate * in USB.
19870Sstevel@tonic-gate * The reason for the failure is that we enter
19880Sstevel@tonic-gate * polled mode (interrupts disabled) and HCD gets stuck
19890Sstevel@tonic-gate * trying to execute bulk requests
19900Sstevel@tonic-gate * The panic_callback registered below provides a warning
19910Sstevel@tonic-gate * that a panic has occurred and from that point onwards, we
19920Sstevel@tonic-gate * complete each request successfully and immediately. This
19930Sstevel@tonic-gate * will fake successful syncing so at least the rest of the
19940Sstevel@tonic-gate * filesystems complete syncing.
19950Sstevel@tonic-gate */
19960Sstevel@tonic-gate scsa2usbp->scsa2usb_panic_info =
19974700Sfb209375 kmem_zalloc(sizeof (scsa2usb_cpr_t), KM_SLEEP);
19980Sstevel@tonic-gate mutex_init(&scsa2usbp->scsa2usb_panic_info->lockp,
19994700Sfb209375 NULL, MUTEX_DRIVER,
20004700Sfb209375 scsa2usbp->scsa2usb_dev_data->dev_iblock_cookie);
20010Sstevel@tonic-gate scsa2usbp->scsa2usb_panic_info->statep = scsa2usbp;
20020Sstevel@tonic-gate scsa2usbp->scsa2usb_panic_info->cpr.cc_lockp =
20034700Sfb209375 &scsa2usbp->scsa2usb_panic_info->lockp;
20040Sstevel@tonic-gate scsa2usbp->scsa2usb_panic_info->cpr.cc_id =
20054700Sfb209375 callb_add(scsa2usb_panic_callb,
20064700Sfb209375 (void *)scsa2usbp->scsa2usb_panic_info,
20074700Sfb209375 CB_CL_PANIC, "scsa2usb");
20080Sstevel@tonic-gate }
20090Sstevel@tonic-gate
20100Sstevel@tonic-gate
20110Sstevel@tonic-gate /*
20120Sstevel@tonic-gate * scsa2usb_panic_callb_fini:
20130Sstevel@tonic-gate * cancel out PANIC callb and free allocated resources
20140Sstevel@tonic-gate */
20150Sstevel@tonic-gate static void
scsa2usb_panic_callb_fini(scsa2usb_state_t * scsa2usbp)20160Sstevel@tonic-gate scsa2usb_panic_callb_fini(scsa2usb_state_t *scsa2usbp)
20170Sstevel@tonic-gate {
20180Sstevel@tonic-gate if (scsa2usbp->scsa2usb_panic_info) {
20190Sstevel@tonic-gate SCSA2USB_CANCEL_CB(scsa2usbp->scsa2usb_panic_info->cpr.cc_id);
20200Sstevel@tonic-gate mutex_destroy(&scsa2usbp->scsa2usb_panic_info->lockp);
20210Sstevel@tonic-gate scsa2usbp->scsa2usb_panic_info->statep = NULL;
20220Sstevel@tonic-gate kmem_free(scsa2usbp->scsa2usb_panic_info,
20230Sstevel@tonic-gate sizeof (scsa2usb_cpr_t));
20240Sstevel@tonic-gate scsa2usbp->scsa2usb_panic_info = NULL;
20250Sstevel@tonic-gate }
20260Sstevel@tonic-gate }
20270Sstevel@tonic-gate
20280Sstevel@tonic-gate
20290Sstevel@tonic-gate /*
20300Sstevel@tonic-gate * scsa2usb_panic_callb:
20310Sstevel@tonic-gate * This routine is called when there is a system panic.
20320Sstevel@tonic-gate */
20330Sstevel@tonic-gate /* ARGSUSED */
20340Sstevel@tonic-gate static boolean_t
scsa2usb_panic_callb(void * arg,int code)20350Sstevel@tonic-gate scsa2usb_panic_callb(void *arg, int code)
20360Sstevel@tonic-gate {
20370Sstevel@tonic-gate scsa2usb_cpr_t *cpr_infop;
20380Sstevel@tonic-gate scsa2usb_state_t *scsa2usbp;
20390Sstevel@tonic-gate uint_t lun;
20400Sstevel@tonic-gate
20410Sstevel@tonic-gate _NOTE(NO_COMPETING_THREADS_NOW);
20420Sstevel@tonic-gate cpr_infop = (scsa2usb_cpr_t *)arg;
20430Sstevel@tonic-gate scsa2usbp = (scsa2usb_state_t *)cpr_infop->statep;
20440Sstevel@tonic-gate
20450Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
20460Sstevel@tonic-gate "scsa2usb_panic_callb: code=%d", code);
20470Sstevel@tonic-gate
20480Sstevel@tonic-gate /*
20490Sstevel@tonic-gate * If we return error here, "sd" prints lots of error
20500Sstevel@tonic-gate * messages and could retry the same pkt over and over again.
20510Sstevel@tonic-gate * The sync recovery isn't "smooth" in that case. By faking
20520Sstevel@tonic-gate * a success return, instead, we force sync to complete.
20530Sstevel@tonic-gate */
20540Sstevel@tonic-gate if (scsa2usbp->scsa2usb_cur_pkt) {
20550Sstevel@tonic-gate /*
20560Sstevel@tonic-gate * Do not print the "no sync" warning here. it will then be
20570Sstevel@tonic-gate * displayed before we actually start syncing. Also we don't
20580Sstevel@tonic-gate * replace this code with a call to scsa2usb_pkt_completion().
20590Sstevel@tonic-gate * NOTE: mutexes are disabled during panic.
20600Sstevel@tonic-gate */
20610Sstevel@tonic-gate scsa2usbp->scsa2usb_cur_pkt->pkt_reason = CMD_CMPLT;
20620Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
20630Sstevel@tonic-gate scsa2usb_pkt_completion(scsa2usbp, scsa2usbp->scsa2usb_cur_pkt);
20640Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
20650Sstevel@tonic-gate }
20660Sstevel@tonic-gate
20670Sstevel@tonic-gate /* get rid of waitQ */
20680Sstevel@tonic-gate for (lun = 0; lun < SCSA2USB_MAX_LUNS; lun++) {
20690Sstevel@tonic-gate scsa2usb_flush_waitQ(scsa2usbp, lun, CMD_CMPLT);
20700Sstevel@tonic-gate }
20710Sstevel@tonic-gate
20722840Scarlsonj #ifndef lint
20730Sstevel@tonic-gate _NOTE(COMPETING_THREADS_NOW);
20742840Scarlsonj #endif
20750Sstevel@tonic-gate
20760Sstevel@tonic-gate return (B_TRUE);
20770Sstevel@tonic-gate }
20780Sstevel@tonic-gate
20790Sstevel@tonic-gate /*
20800Sstevel@tonic-gate * scsa2usb_cpr_suspend
20810Sstevel@tonic-gate * determine if the device's state can be changed to SUSPENDED
20820Sstevel@tonic-gate * close pipes if there is no activity
20830Sstevel@tonic-gate */
20840Sstevel@tonic-gate /* ARGSUSED */
20850Sstevel@tonic-gate static int
scsa2usb_cpr_suspend(dev_info_t * dip)20860Sstevel@tonic-gate scsa2usb_cpr_suspend(dev_info_t *dip)
20870Sstevel@tonic-gate {
20880Sstevel@tonic-gate scsa2usb_state_t *scsa2usbp;
20890Sstevel@tonic-gate int prev_state;
20900Sstevel@tonic-gate int rval = USB_FAILURE;
20910Sstevel@tonic-gate
20920Sstevel@tonic-gate scsa2usbp = ddi_get_soft_state(scsa2usb_statep, ddi_get_instance(dip));
20930Sstevel@tonic-gate
20940Sstevel@tonic-gate ASSERT(scsa2usbp != NULL);
20950Sstevel@tonic-gate
20960Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
20970Sstevel@tonic-gate "scsa2usb_cpr_suspend:");
20980Sstevel@tonic-gate
20990Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
21000Sstevel@tonic-gate switch (scsa2usbp->scsa2usb_dev_state) {
21010Sstevel@tonic-gate case USB_DEV_ONLINE:
21020Sstevel@tonic-gate case USB_DEV_PWRED_DOWN:
21030Sstevel@tonic-gate case USB_DEV_DISCONNECTED:
21040Sstevel@tonic-gate prev_state = scsa2usbp->scsa2usb_dev_state;
21050Sstevel@tonic-gate scsa2usbp->scsa2usb_dev_state = USB_DEV_SUSPENDED;
21060Sstevel@tonic-gate
21070Sstevel@tonic-gate /*
21080Sstevel@tonic-gate * If the device is busy, we cannot suspend
21090Sstevel@tonic-gate */
21100Sstevel@tonic-gate if (SCSA2USB_BUSY(scsa2usbp)) {
21110Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_SCSA,
21120Sstevel@tonic-gate scsa2usbp->scsa2usb_log_handle,
21130Sstevel@tonic-gate "scsa2usb_cpr_suspend: I/O active");
21140Sstevel@tonic-gate
21150Sstevel@tonic-gate /* fall back to previous state */
21160Sstevel@tonic-gate scsa2usbp->scsa2usb_dev_state = prev_state;
21170Sstevel@tonic-gate } else {
21180Sstevel@tonic-gate rval = USB_SUCCESS;
21190Sstevel@tonic-gate }
21200Sstevel@tonic-gate
21210Sstevel@tonic-gate break;
21220Sstevel@tonic-gate case USB_DEV_SUSPENDED:
21230Sstevel@tonic-gate default:
21240Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
21250Sstevel@tonic-gate "scsa2usb_cpr_suspend: Illegal dev state: %d",
21260Sstevel@tonic-gate scsa2usbp->scsa2usb_dev_state);
21270Sstevel@tonic-gate
21280Sstevel@tonic-gate break;
21290Sstevel@tonic-gate }
21300Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
21310Sstevel@tonic-gate
21320Sstevel@tonic-gate if ((rval == USB_SUCCESS) && scsa2usbp->scsa2usb_ugen_hdl) {
21330Sstevel@tonic-gate rval = usb_ugen_detach(scsa2usbp->scsa2usb_ugen_hdl,
21344700Sfb209375 DDI_SUSPEND);
21350Sstevel@tonic-gate }
21360Sstevel@tonic-gate
21370Sstevel@tonic-gate return (rval);
21380Sstevel@tonic-gate }
21390Sstevel@tonic-gate
21400Sstevel@tonic-gate
21410Sstevel@tonic-gate /*
21420Sstevel@tonic-gate * scsa2usb_cpr_resume:
21430Sstevel@tonic-gate * restore device's state
21440Sstevel@tonic-gate */
21450Sstevel@tonic-gate static void
scsa2usb_cpr_resume(dev_info_t * dip)21460Sstevel@tonic-gate scsa2usb_cpr_resume(dev_info_t *dip)
21470Sstevel@tonic-gate {
21480Sstevel@tonic-gate scsa2usb_state_t *scsa2usbp =
21490Sstevel@tonic-gate ddi_get_soft_state(scsa2usb_statep, ddi_get_instance(dip));
21500Sstevel@tonic-gate
21510Sstevel@tonic-gate ASSERT(scsa2usbp != NULL);
21520Sstevel@tonic-gate
21530Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
21546898Sfb209375 "scsa2usb_cpr_resume: dip = 0x%p", (void *)dip);
21550Sstevel@tonic-gate
21560Sstevel@tonic-gate scsa2usb_restore_device_state(dip, scsa2usbp);
21570Sstevel@tonic-gate
21580Sstevel@tonic-gate if (scsa2usbp->scsa2usb_ugen_hdl) {
21590Sstevel@tonic-gate (void) usb_ugen_attach(scsa2usbp->scsa2usb_ugen_hdl,
21604700Sfb209375 DDI_RESUME);
21610Sstevel@tonic-gate }
21620Sstevel@tonic-gate }
21630Sstevel@tonic-gate
21640Sstevel@tonic-gate
21650Sstevel@tonic-gate /*
21660Sstevel@tonic-gate * scsa2usb_restore_device_state:
21670Sstevel@tonic-gate * - raise the device's power
21680Sstevel@tonic-gate * - reopen all the pipes
21690Sstevel@tonic-gate */
21700Sstevel@tonic-gate static void
scsa2usb_restore_device_state(dev_info_t * dip,scsa2usb_state_t * scsa2usbp)21710Sstevel@tonic-gate scsa2usb_restore_device_state(dev_info_t *dip, scsa2usb_state_t *scsa2usbp)
21720Sstevel@tonic-gate {
21730Sstevel@tonic-gate uint_t prev_state;
21740Sstevel@tonic-gate
21750Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
21760Sstevel@tonic-gate "scsa2usb_restore_device_state:");
21770Sstevel@tonic-gate
21780Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
21790Sstevel@tonic-gate prev_state = scsa2usbp->scsa2usb_dev_state;
21800Sstevel@tonic-gate
21810Sstevel@tonic-gate scsa2usb_raise_power(scsa2usbp);
21820Sstevel@tonic-gate
21830Sstevel@tonic-gate ASSERT((prev_state == USB_DEV_DISCONNECTED) ||
21840Sstevel@tonic-gate (prev_state == USB_DEV_SUSPENDED));
21850Sstevel@tonic-gate
21860Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
21870Sstevel@tonic-gate
21880Sstevel@tonic-gate /* Check for the same device */
21890Sstevel@tonic-gate if (usb_check_same_device(dip, scsa2usbp->scsa2usb_log_handle,
21900Sstevel@tonic-gate USB_LOG_L0, DPRINT_MASK_ALL, USB_CHK_ALL, NULL) != USB_SUCCESS) {
21910Sstevel@tonic-gate
21920Sstevel@tonic-gate /* change the flags to active */
21930Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
21940Sstevel@tonic-gate scsa2usbp->scsa2usb_dev_state = USB_DEV_DISCONNECTED;
2195189Sfrits mutex_exit(&scsa2usbp->scsa2usb_mutex);
21960Sstevel@tonic-gate
21970Sstevel@tonic-gate scsa2usb_pm_idle_component(scsa2usbp);
21980Sstevel@tonic-gate
21990Sstevel@tonic-gate return;
22000Sstevel@tonic-gate }
22010Sstevel@tonic-gate
22020Sstevel@tonic-gate /*
22030Sstevel@tonic-gate * if the device had remote wakeup earlier,
22040Sstevel@tonic-gate * enable it again
22050Sstevel@tonic-gate */
22060Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
22070Sstevel@tonic-gate if (scsa2usbp->scsa2usb_pm &&
22080Sstevel@tonic-gate scsa2usbp->scsa2usb_pm->scsa2usb_wakeup_enabled) {
22090Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
22100Sstevel@tonic-gate (void) usb_handle_remote_wakeup(scsa2usbp->scsa2usb_dip,
22110Sstevel@tonic-gate USB_REMOTE_WAKEUP_ENABLE);
22120Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
22130Sstevel@tonic-gate }
22140Sstevel@tonic-gate
22150Sstevel@tonic-gate scsa2usbp->scsa2usb_dev_state = USB_DEV_ONLINE;
22160Sstevel@tonic-gate scsa2usbp->scsa2usb_pkt_state = SCSA2USB_PKT_NONE;
2217189Sfrits mutex_exit(&scsa2usbp->scsa2usb_mutex);
22180Sstevel@tonic-gate
22190Sstevel@tonic-gate scsa2usb_pm_idle_component(scsa2usbp);
22200Sstevel@tonic-gate }
22210Sstevel@tonic-gate
22220Sstevel@tonic-gate
22230Sstevel@tonic-gate /*
22240Sstevel@tonic-gate * SCSA entry points:
22250Sstevel@tonic-gate *
22260Sstevel@tonic-gate * scsa2usb_scsi_tgt_probe:
22270Sstevel@tonic-gate * scsa functions are exported by means of the transport table
22280Sstevel@tonic-gate * Issue a probe to get the inquiry data.
22290Sstevel@tonic-gate */
22300Sstevel@tonic-gate /* ARGSUSED */
22310Sstevel@tonic-gate static int
scsa2usb_scsi_tgt_probe(struct scsi_device * sd,int (* waitfunc)(void))22320Sstevel@tonic-gate scsa2usb_scsi_tgt_probe(struct scsi_device *sd, int (*waitfunc)(void))
22330Sstevel@tonic-gate {
22340Sstevel@tonic-gate scsi_hba_tran_t *tran;
22350Sstevel@tonic-gate scsa2usb_state_t *scsa2usbp;
22360Sstevel@tonic-gate dev_info_t *dip = ddi_get_parent(sd->sd_dev);
22371415Scg149915 int rval;
22380Sstevel@tonic-gate
22390Sstevel@tonic-gate ASSERT(dip);
22400Sstevel@tonic-gate
22410Sstevel@tonic-gate tran = ddi_get_driver_private(dip);
22420Sstevel@tonic-gate ASSERT(tran != NULL);
22430Sstevel@tonic-gate scsa2usbp = (scsa2usb_state_t *)tran->tran_hba_private;
22440Sstevel@tonic-gate ASSERT(scsa2usbp);
22450Sstevel@tonic-gate
22460Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
22470Sstevel@tonic-gate "scsa2usb_scsi_tgt_probe:");
22480Sstevel@tonic-gate
22490Sstevel@tonic-gate /* if device is disconnected (ie. pipes closed), fail immediately */
22500Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
22510Sstevel@tonic-gate if (!(SCSA2USB_DEVICE_ACCESS_OK(scsa2usbp))) {
22520Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
22530Sstevel@tonic-gate
22540Sstevel@tonic-gate return (SCSIPROBE_FAILURE);
22550Sstevel@tonic-gate }
22560Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
22570Sstevel@tonic-gate
22580Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
22596898Sfb209375 "scsa2usb_scsi_tgt_probe: scsi_device = 0x%p", (void *)sd);
22600Sstevel@tonic-gate
22610Sstevel@tonic-gate if ((rval = scsi_hba_probe(sd, waitfunc)) == SCSIPROBE_EXISTS) {
22620Sstevel@tonic-gate /*
22631415Scg149915 * respect the removable bit on all USB storage devices
22640Sstevel@tonic-gate * unless overridden by a scsa2usb.conf entry
22650Sstevel@tonic-gate */
22660Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
22671415Scg149915 if (!(scsa2usbp->scsa2usb_attrs & SCSA2USB_ATTRS_RMB)) {
22680Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("unshared", scsi_inquiry))
22690Sstevel@tonic-gate sd->sd_inq->inq_rmb = 1;
22700Sstevel@tonic-gate }
22710Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
22720Sstevel@tonic-gate }
22730Sstevel@tonic-gate
22740Sstevel@tonic-gate return (rval);
22750Sstevel@tonic-gate }
22760Sstevel@tonic-gate
22770Sstevel@tonic-gate
22780Sstevel@tonic-gate /*
22790Sstevel@tonic-gate * scsa2usb_scsi_tgt_init:
22800Sstevel@tonic-gate * check whether we created this child ourselves
22810Sstevel@tonic-gate */
22820Sstevel@tonic-gate /* ARGSUSED */
22830Sstevel@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)22840Sstevel@tonic-gate scsa2usb_scsi_tgt_init(dev_info_t *dip, dev_info_t *cdip,
22850Sstevel@tonic-gate scsi_hba_tran_t *tran, struct scsi_device *sd)
22860Sstevel@tonic-gate {
22870Sstevel@tonic-gate scsa2usb_state_t *scsa2usbp = (scsa2usb_state_t *)
22884700Sfb209375 tran->tran_hba_private;
22890Sstevel@tonic-gate int lun;
22900Sstevel@tonic-gate int t_len = sizeof (lun);
22910Sstevel@tonic-gate
22920Sstevel@tonic-gate if (ddi_prop_op(DDI_DEV_T_ANY, cdip, PROP_LEN_AND_VAL_BUF,
22930Sstevel@tonic-gate DDI_PROP_DONTPASS|DDI_PROP_CANSLEEP, "lun", (caddr_t)&lun,
22940Sstevel@tonic-gate &t_len) != DDI_PROP_SUCCESS) {
22950Sstevel@tonic-gate
22960Sstevel@tonic-gate return (DDI_FAILURE);
22970Sstevel@tonic-gate }
22980Sstevel@tonic-gate
22990Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
23000Sstevel@tonic-gate "scsa2usb_scsi_tgt_init: %s, lun%d", ddi_driver_name(cdip), lun);
23010Sstevel@tonic-gate
23020Sstevel@tonic-gate /* is this a child we created? */
23030Sstevel@tonic-gate if (scsa2usb_is_usb(cdip) == 0) {
23040Sstevel@tonic-gate
23050Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
23060Sstevel@tonic-gate "scsa2usb_scsi_tgt_init: new child %s%d",
23070Sstevel@tonic-gate ddi_driver_name(cdip), ddi_get_instance(cdip));
23080Sstevel@tonic-gate
23090Sstevel@tonic-gate /*
23100Sstevel@tonic-gate * add property "usb" so we can always verify that it
23110Sstevel@tonic-gate * is our child
23120Sstevel@tonic-gate */
23130Sstevel@tonic-gate if (ndi_prop_create_boolean(DDI_DEV_T_NONE, cdip, "usb") !=
23140Sstevel@tonic-gate DDI_PROP_SUCCESS) {
23150Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_SCSA,
23160Sstevel@tonic-gate scsa2usbp->scsa2usb_log_handle,
23170Sstevel@tonic-gate "ndi_prop_create_boolean failed");
23180Sstevel@tonic-gate
23190Sstevel@tonic-gate return (DDI_FAILURE);
23200Sstevel@tonic-gate }
23210Sstevel@tonic-gate
23220Sstevel@tonic-gate usba_set_usba_device(cdip,
23234700Sfb209375 usba_get_usba_device(scsa2usbp->scsa2usb_dip));
23240Sstevel@tonic-gate
23250Sstevel@tonic-gate /*
23260Sstevel@tonic-gate * we don't store this dip in scsa2usb_lun_dip, there
23270Sstevel@tonic-gate * might be multiple dips for the same device
23280Sstevel@tonic-gate */
23290Sstevel@tonic-gate
23300Sstevel@tonic-gate return (DDI_SUCCESS);
23310Sstevel@tonic-gate }
23320Sstevel@tonic-gate
23330Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
23340Sstevel@tonic-gate if ((lun >= scsa2usbp->scsa2usb_n_luns) ||
23350Sstevel@tonic-gate (scsa2usbp->scsa2usb_lun_dip[lun] != NULL)) {
23360Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
23370Sstevel@tonic-gate
23380Sstevel@tonic-gate return (DDI_FAILURE);
23390Sstevel@tonic-gate }
23400Sstevel@tonic-gate
23410Sstevel@tonic-gate scsa2usbp->scsa2usb_lun_dip[lun] = cdip;
23420Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
23430Sstevel@tonic-gate
23440Sstevel@tonic-gate return (DDI_SUCCESS);
23450Sstevel@tonic-gate }
23460Sstevel@tonic-gate
23470Sstevel@tonic-gate
23480Sstevel@tonic-gate /*
23490Sstevel@tonic-gate * scsa2usb_scsi_tgt_free:
23500Sstevel@tonic-gate */
23510Sstevel@tonic-gate /* ARGSUSED */
23520Sstevel@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)23530Sstevel@tonic-gate scsa2usb_scsi_tgt_free(dev_info_t *hba_dip, dev_info_t *cdip,
23540Sstevel@tonic-gate scsi_hba_tran_t *tran, struct scsi_device *sd)
23550Sstevel@tonic-gate {
23560Sstevel@tonic-gate scsa2usb_state_t *scsa2usbp = (scsa2usb_state_t *)
23574700Sfb209375 tran->tran_hba_private;
23580Sstevel@tonic-gate int lun;
23590Sstevel@tonic-gate int t_len = sizeof (lun);
23600Sstevel@tonic-gate
23610Sstevel@tonic-gate /* is this our child? */
23620Sstevel@tonic-gate if (scsa2usb_is_usb(cdip) == 0) {
23630Sstevel@tonic-gate
23640Sstevel@tonic-gate return;
23650Sstevel@tonic-gate }
23660Sstevel@tonic-gate
23670Sstevel@tonic-gate if (ddi_prop_op(DDI_DEV_T_ANY, cdip, PROP_LEN_AND_VAL_BUF,
23680Sstevel@tonic-gate DDI_PROP_DONTPASS|DDI_PROP_CANSLEEP, "lun", (caddr_t)&lun,
23690Sstevel@tonic-gate &t_len) != DDI_PROP_SUCCESS) {
23700Sstevel@tonic-gate
23710Sstevel@tonic-gate return;
23720Sstevel@tonic-gate }
23730Sstevel@tonic-gate
23740Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
23750Sstevel@tonic-gate "scsa2usb_scsi_tgt_free: %s lun%d", ddi_driver_name(cdip), lun);
23760Sstevel@tonic-gate
23770Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
23780Sstevel@tonic-gate if (lun < scsa2usbp->scsa2usb_n_luns) {
23790Sstevel@tonic-gate if (scsa2usbp->scsa2usb_lun_dip[lun] == cdip) {
23800Sstevel@tonic-gate scsa2usbp->scsa2usb_lun_dip[lun] = NULL;
23810Sstevel@tonic-gate }
23820Sstevel@tonic-gate }
23830Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
23840Sstevel@tonic-gate }
23850Sstevel@tonic-gate
23860Sstevel@tonic-gate
23870Sstevel@tonic-gate /*
23880Sstevel@tonic-gate * bus enumeration entry points
23890Sstevel@tonic-gate */
23900Sstevel@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)23910Sstevel@tonic-gate scsa2usb_scsi_bus_config(dev_info_t *dip, uint_t flag, ddi_bus_config_op_t op,
23920Sstevel@tonic-gate void *arg, dev_info_t **child)
23930Sstevel@tonic-gate {
23940Sstevel@tonic-gate int circ;
23950Sstevel@tonic-gate int rval;
23960Sstevel@tonic-gate
23970Sstevel@tonic-gate scsa2usb_state_t *scsa2usbp =
23980Sstevel@tonic-gate ddi_get_soft_state(scsa2usb_statep, ddi_get_instance(dip));
23990Sstevel@tonic-gate
24000Sstevel@tonic-gate ASSERT(scsa2usbp != NULL);
24010Sstevel@tonic-gate
24020Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
24030Sstevel@tonic-gate "scsa2usb_scsi_bus_config: op=%d", op);
24040Sstevel@tonic-gate
24050Sstevel@tonic-gate if (scsa2usb_scsi_bus_config_debug) {
24060Sstevel@tonic-gate flag |= NDI_DEVI_DEBUG;
24070Sstevel@tonic-gate }
24080Sstevel@tonic-gate
24090Sstevel@tonic-gate ndi_devi_enter(dip, &circ);
24100Sstevel@tonic-gate /* create children if necessary */
24110Sstevel@tonic-gate if (DEVI(dip)->devi_child == NULL) {
24120Sstevel@tonic-gate scsa2usb_create_luns(scsa2usbp);
24130Sstevel@tonic-gate }
24140Sstevel@tonic-gate
24150Sstevel@tonic-gate rval = ndi_busop_bus_config(dip, flag, op, arg, child, 0);
24160Sstevel@tonic-gate
24170Sstevel@tonic-gate ndi_devi_exit(dip, circ);
24180Sstevel@tonic-gate
24190Sstevel@tonic-gate return (rval);
24200Sstevel@tonic-gate }
24210Sstevel@tonic-gate
24220Sstevel@tonic-gate
24230Sstevel@tonic-gate static int
scsa2usb_scsi_bus_unconfig(dev_info_t * dip,uint_t flag,ddi_bus_config_op_t op,void * arg)24240Sstevel@tonic-gate scsa2usb_scsi_bus_unconfig(dev_info_t *dip, uint_t flag, ddi_bus_config_op_t op,
24250Sstevel@tonic-gate void *arg)
24260Sstevel@tonic-gate {
24270Sstevel@tonic-gate scsa2usb_state_t *scsa2usbp =
24280Sstevel@tonic-gate ddi_get_soft_state(scsa2usb_statep, ddi_get_instance(dip));
24290Sstevel@tonic-gate
24300Sstevel@tonic-gate int circular_count;
24310Sstevel@tonic-gate int rval = NDI_SUCCESS;
24320Sstevel@tonic-gate uint_t save_flag = flag;
24330Sstevel@tonic-gate
24340Sstevel@tonic-gate ASSERT(scsa2usbp != NULL);
24350Sstevel@tonic-gate
24360Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
24370Sstevel@tonic-gate "scsa2usb_scsi_bus_unconfig: op=%d", op);
24380Sstevel@tonic-gate
24390Sstevel@tonic-gate if (scsa2usb_scsi_bus_config_debug) {
24400Sstevel@tonic-gate flag |= NDI_DEVI_DEBUG;
24410Sstevel@tonic-gate }
24420Sstevel@tonic-gate
24430Sstevel@tonic-gate /*
24440Sstevel@tonic-gate * first offline and if offlining successful, then
24450Sstevel@tonic-gate * remove children
24460Sstevel@tonic-gate */
24470Sstevel@tonic-gate if (op == BUS_UNCONFIG_ALL) {
24480Sstevel@tonic-gate flag &= ~(NDI_DEVI_REMOVE | NDI_UNCONFIG);
24490Sstevel@tonic-gate }
24500Sstevel@tonic-gate
24510Sstevel@tonic-gate ndi_devi_enter(dip, &circular_count);
24520Sstevel@tonic-gate rval = ndi_busop_bus_unconfig(dip, flag, op, arg);
24530Sstevel@tonic-gate
24540Sstevel@tonic-gate /*
24550Sstevel@tonic-gate * If unconfig is successful and not part of modunload
24560Sstevel@tonic-gate * daemon, attempt to remove children.
24570Sstevel@tonic-gate */
24580Sstevel@tonic-gate if (op == BUS_UNCONFIG_ALL && rval == NDI_SUCCESS &&
24590Sstevel@tonic-gate (flag & NDI_AUTODETACH) == 0) {
24600Sstevel@tonic-gate flag |= NDI_DEVI_REMOVE;
24610Sstevel@tonic-gate rval = ndi_busop_bus_unconfig(dip, flag, op, arg);
24620Sstevel@tonic-gate }
24630Sstevel@tonic-gate ndi_devi_exit(dip, circular_count);
24640Sstevel@tonic-gate
24650Sstevel@tonic-gate if ((rval != NDI_SUCCESS) && (op == BUS_UNCONFIG_ALL) &&
24660Sstevel@tonic-gate (save_flag & NDI_DEVI_REMOVE)) {
24670Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
24680Sstevel@tonic-gate if (scsa2usbp->scsa2usb_warning_given != B_TRUE) {
24697231Slg150142 USB_DPRINTF_L2(DPRINT_MASK_SCSA,
24700Sstevel@tonic-gate scsa2usbp->scsa2usb_log_handle,
24710Sstevel@tonic-gate "Disconnected device was busy, "
24720Sstevel@tonic-gate "please reconnect.");
24730Sstevel@tonic-gate scsa2usbp->scsa2usb_warning_given = B_TRUE;
24740Sstevel@tonic-gate }
24750Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
24760Sstevel@tonic-gate }
24770Sstevel@tonic-gate
24780Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
24790Sstevel@tonic-gate "scsa2usb_scsi_bus_unconfig: rval=%d", rval);
24800Sstevel@tonic-gate
24810Sstevel@tonic-gate return (rval);
24820Sstevel@tonic-gate }
24830Sstevel@tonic-gate
24840Sstevel@tonic-gate
24850Sstevel@tonic-gate /*
24860Sstevel@tonic-gate * scsa2usb_scsi_init_pkt:
24870Sstevel@tonic-gate * Set up the scsi_pkt for transport. Also initialize
24880Sstevel@tonic-gate * scsa2usb_cmd struct for the transport.
24890Sstevel@tonic-gate * NOTE: We do not do any DMA setup here as USBA framework
24900Sstevel@tonic-gate * does that for us.
24910Sstevel@tonic-gate */
24920Sstevel@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)24930Sstevel@tonic-gate scsa2usb_scsi_init_pkt(struct scsi_address *ap,
24940Sstevel@tonic-gate struct scsi_pkt *pkt, struct buf *bp, int cmdlen, int statuslen,
24950Sstevel@tonic-gate int tgtlen, int flags, int (*callback)(), caddr_t arg)
24960Sstevel@tonic-gate {
24970Sstevel@tonic-gate scsa2usb_cmd_t *cmd;
24980Sstevel@tonic-gate scsa2usb_state_t *scsa2usbp;
24990Sstevel@tonic-gate struct scsi_pkt *in_pkt = pkt;
25000Sstevel@tonic-gate
25010Sstevel@tonic-gate ASSERT(callback == NULL_FUNC || callback == SLEEP_FUNC);
25020Sstevel@tonic-gate
25030Sstevel@tonic-gate scsa2usbp = (scsa2usb_state_t *)ADDR2SCSA2USB(ap);
25040Sstevel@tonic-gate
25050Sstevel@tonic-gate /* Print sync message */
25060Sstevel@tonic-gate if (ddi_in_panic()) {
25070Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
25080Sstevel@tonic-gate SCSA2USB_PRINT_SYNC_MSG(scsa2usb_sync_message, scsa2usbp);
25090Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
25100Sstevel@tonic-gate /* continue so caller will not hang or complain */
25110Sstevel@tonic-gate }
25120Sstevel@tonic-gate
25130Sstevel@tonic-gate /* allocate a pkt, if none already allocated */
25140Sstevel@tonic-gate if (pkt == NULL) {
25150Sstevel@tonic-gate if (statuslen < sizeof (struct scsi_arq_status)) {
25160Sstevel@tonic-gate statuslen = sizeof (struct scsi_arq_status);
25170Sstevel@tonic-gate }
25180Sstevel@tonic-gate
25190Sstevel@tonic-gate pkt = scsi_hba_pkt_alloc(scsa2usbp->scsa2usb_dip, ap, cmdlen,
25204700Sfb209375 statuslen, tgtlen, sizeof (scsa2usb_cmd_t),
25214700Sfb209375 callback, arg);
25220Sstevel@tonic-gate if (pkt == NULL) {
25230Sstevel@tonic-gate
25240Sstevel@tonic-gate return (NULL);
25250Sstevel@tonic-gate }
25260Sstevel@tonic-gate
25270Sstevel@tonic-gate cmd = PKT2CMD(pkt);
25280Sstevel@tonic-gate cmd->cmd_pkt = pkt; /* back link to pkt */
25290Sstevel@tonic-gate cmd->cmd_scblen = statuslen;
25300Sstevel@tonic-gate cmd->cmd_cdblen = (uchar_t)cmdlen;
25310Sstevel@tonic-gate
25320Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
25330Sstevel@tonic-gate cmd->cmd_tag = scsa2usbp->scsa2usb_tag++;
25340Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
25350Sstevel@tonic-gate
25360Sstevel@tonic-gate cmd->cmd_bp = bp;
25375727Slh195018 /*
25385727Slh195018 * The buffer size of cmd->cmd_scb is constrained
25395727Slh195018 * to sizeof (struct scsi_arq_status), if the scblen
25405727Slh195018 * is bigger than that, we use pkt->pkt_scbp directly.
25415727Slh195018 */
25425727Slh195018 if (cmd->cmd_scblen == sizeof (struct scsi_arq_status)) {
25435727Slh195018 pkt->pkt_scbp = (opaque_t)&cmd->cmd_scb;
25445727Slh195018 }
25450Sstevel@tonic-gate
25460Sstevel@tonic-gate usba_init_list(&cmd->cmd_waitQ, (usb_opaque_t)cmd,
25474700Sfb209375 scsa2usbp->scsa2usb_dev_data->dev_iblock_cookie);
25480Sstevel@tonic-gate } else {
25490Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
25500Sstevel@tonic-gate "scsa2usb: pkt != NULL");
25510Sstevel@tonic-gate
25520Sstevel@tonic-gate /* nothing to do */
25530Sstevel@tonic-gate }
25540Sstevel@tonic-gate
25552506Ssl147100 if (bp && (bp->b_bcount != 0)) {
25560Sstevel@tonic-gate if ((bp_mapin_common(bp, (callback == SLEEP_FUNC) ?
25570Sstevel@tonic-gate VM_SLEEP : VM_NOSLEEP)) == NULL) {
25580Sstevel@tonic-gate if (pkt != in_pkt) {
25590Sstevel@tonic-gate scsi_hba_pkt_free(ap, pkt);
25600Sstevel@tonic-gate }
25610Sstevel@tonic-gate
25620Sstevel@tonic-gate return (NULL);
25630Sstevel@tonic-gate }
25640Sstevel@tonic-gate
25650Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_SCSA,
25660Sstevel@tonic-gate scsa2usbp->scsa2usb_log_handle,
25670Sstevel@tonic-gate "scsa2usb_scsi_init_pkt: mapped in 0x%p, addr=0x%p",
25686898Sfb209375 (void *)bp, (void *)bp->b_un.b_addr);
25690Sstevel@tonic-gate }
25700Sstevel@tonic-gate
25710Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
25720Sstevel@tonic-gate "scsa2usb_scsi_init_pkt: ap = 0x%p pkt: 0x%p\n\t"
25730Sstevel@tonic-gate "bp = 0x%p cmdlen = %x stlen = 0x%x tlen = 0x%x flags = 0x%x",
25746898Sfb209375 (void *)ap, (void *)pkt, (void *)bp, cmdlen, statuslen,
25756898Sfb209375 tgtlen, flags);
25760Sstevel@tonic-gate
25770Sstevel@tonic-gate return (pkt);
25780Sstevel@tonic-gate }
25790Sstevel@tonic-gate
25800Sstevel@tonic-gate
25810Sstevel@tonic-gate /*
25820Sstevel@tonic-gate * scsa2usb_scsi_destroy_pkt:
25830Sstevel@tonic-gate * We are done with the packet. Get rid of it.
25840Sstevel@tonic-gate */
25850Sstevel@tonic-gate static void
scsa2usb_scsi_destroy_pkt(struct scsi_address * ap,struct scsi_pkt * pkt)25860Sstevel@tonic-gate scsa2usb_scsi_destroy_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
25870Sstevel@tonic-gate {
25880Sstevel@tonic-gate scsa2usb_cmd_t *cmd = PKT2CMD(pkt);
25890Sstevel@tonic-gate scsa2usb_state_t *scsa2usbp = ADDR2SCSA2USB(ap);
25900Sstevel@tonic-gate
25910Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
25926898Sfb209375 "scsa2usb_scsi_destroy_pkt: pkt=0x%p", (void *)pkt);
25930Sstevel@tonic-gate
25940Sstevel@tonic-gate usba_destroy_list(&cmd->cmd_waitQ);
25950Sstevel@tonic-gate scsi_hba_pkt_free(ap, pkt);
25960Sstevel@tonic-gate }
25970Sstevel@tonic-gate
25980Sstevel@tonic-gate
25990Sstevel@tonic-gate /*
26000Sstevel@tonic-gate * scsa2usb_scsi_start:
26010Sstevel@tonic-gate * For each command being issued, build up the CDB
26020Sstevel@tonic-gate * and call scsi_transport to issue the command. This
26030Sstevel@tonic-gate * function is based on the assumption that USB allows
26040Sstevel@tonic-gate * a subset of SCSI commands. Other SCSI commands we fail.
26050Sstevel@tonic-gate */
26060Sstevel@tonic-gate static int
scsa2usb_scsi_start(struct scsi_address * ap,struct scsi_pkt * pkt)26070Sstevel@tonic-gate scsa2usb_scsi_start(struct scsi_address *ap, struct scsi_pkt *pkt)
26080Sstevel@tonic-gate {
26090Sstevel@tonic-gate scsa2usb_cmd_t *cmd;
26100Sstevel@tonic-gate scsa2usb_state_t *scsa2usbp = ADDR2SCSA2USB(ap);
26110Sstevel@tonic-gate uint_t lun = ap->a_lun;
26120Sstevel@tonic-gate
26130Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
26140Sstevel@tonic-gate
26150Sstevel@tonic-gate cmd = PKT2CMD(pkt);
26160Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
26170Sstevel@tonic-gate "scsa2usb_scsi_start:\n\t"
26180Sstevel@tonic-gate "bp: 0x%p ap: 0x%p pkt: 0x%p flag: 0x%x time: 0x%x\n\tcdb0: 0x%x "
26190Sstevel@tonic-gate "dev_state: 0x%x pkt_state: 0x%x flags: 0x%x pipe_state: 0x%x",
26206898Sfb209375 (void *)cmd->cmd_bp, (void *)ap, (void *)pkt, pkt->pkt_flags,
26216898Sfb209375 pkt->pkt_time, pkt->pkt_cdbp[0], scsa2usbp->scsa2usb_dev_state,
26220Sstevel@tonic-gate scsa2usbp->scsa2usb_pkt_state, scsa2usbp->scsa2usb_flags,
26230Sstevel@tonic-gate scsa2usbp->scsa2usb_pipe_state);
26240Sstevel@tonic-gate
26250Sstevel@tonic-gate if (pkt->pkt_time == 0) {
26260Sstevel@tonic-gate USB_DPRINTF_L1(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
26270Sstevel@tonic-gate "pkt submitted with 0 timeout which may cause indefinite "
26280Sstevel@tonic-gate "hangs");
26290Sstevel@tonic-gate }
26300Sstevel@tonic-gate
26310Sstevel@tonic-gate /*
26320Sstevel@tonic-gate * if we are in panic, we are in polled mode, so we can just
26330Sstevel@tonic-gate * accept the request, drop it and return
26340Sstevel@tonic-gate * if we fail this request, the rest of the file systems do not
26350Sstevel@tonic-gate * get synced
26360Sstevel@tonic-gate */
26370Sstevel@tonic-gate if (ddi_in_panic()) {
26380Sstevel@tonic-gate extern int do_polled_io;
26390Sstevel@tonic-gate
26400Sstevel@tonic-gate ASSERT(do_polled_io);
26410Sstevel@tonic-gate scsa2usb_prepare_pkt(scsa2usbp, pkt);
26420Sstevel@tonic-gate SCSA2USB_PRINT_SYNC_MSG(scsa2usb_sync_message, scsa2usbp);
26430Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
26440Sstevel@tonic-gate
26450Sstevel@tonic-gate return (TRAN_ACCEPT);
26460Sstevel@tonic-gate }
26470Sstevel@tonic-gate
26480Sstevel@tonic-gate /* we cannot do polling, this should not happen */
26490Sstevel@tonic-gate if (pkt->pkt_flags & FLAG_NOINTR) {
26500Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
26510Sstevel@tonic-gate "NOINTR packet: opcode = 0%x", pkt->pkt_cdbp[0]);
26520Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
26530Sstevel@tonic-gate
26540Sstevel@tonic-gate return (TRAN_BADPKT);
26550Sstevel@tonic-gate }
26560Sstevel@tonic-gate
26570Sstevel@tonic-gate /* prepare packet */
26580Sstevel@tonic-gate scsa2usb_prepare_pkt(scsa2usbp, pkt);
26590Sstevel@tonic-gate
26600Sstevel@tonic-gate /* just queue up the requests in the waitQ if below max */
26610Sstevel@tonic-gate if (usba_list_entry_count(&scsa2usbp->scsa2usb_waitQ[lun]) >
26620Sstevel@tonic-gate SCSA2USB_MAX_REQ_PER_LUN) {
26630Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_SCSA,
26640Sstevel@tonic-gate scsa2usbp->scsa2usb_log_handle,
26650Sstevel@tonic-gate "scsa2usb_scsi_start: limit (%d) exceeded",
26660Sstevel@tonic-gate SCSA2USB_MAX_REQ_PER_LUN);
26670Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
26680Sstevel@tonic-gate
26690Sstevel@tonic-gate return (TRAN_BUSY);
26700Sstevel@tonic-gate }
26710Sstevel@tonic-gate
26720Sstevel@tonic-gate usba_add_to_list(&scsa2usbp->scsa2usb_waitQ[lun], &cmd->cmd_waitQ);
26730Sstevel@tonic-gate
2674189Sfrits USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
26756898Sfb209375 "scsa2usb_work_thread_id=0x%p, count=%d, lun=%d",
26766898Sfb209375 (void *)scsa2usbp->scsa2usb_work_thread_id,
2677189Sfrits usba_list_entry_count(&scsa2usbp->scsa2usb_waitQ[lun]), lun);
2678189Sfrits
26790Sstevel@tonic-gate /* fire up a thread to start executing the protocol */
26800Sstevel@tonic-gate if (scsa2usbp->scsa2usb_work_thread_id == 0) {
26810Sstevel@tonic-gate if ((usb_async_req(scsa2usbp->scsa2usb_dip,
26820Sstevel@tonic-gate scsa2usb_work_thread,
26830Sstevel@tonic-gate (void *)scsa2usbp, USB_FLAGS_SLEEP)) != USB_SUCCESS) {
26840Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_SCSA,
26850Sstevel@tonic-gate scsa2usbp->scsa2usb_log_handle,
26860Sstevel@tonic-gate "no work thread started");
26870Sstevel@tonic-gate
26880Sstevel@tonic-gate if (usba_rm_from_list(
26890Sstevel@tonic-gate &scsa2usbp->scsa2usb_waitQ[lun],
26900Sstevel@tonic-gate &cmd->cmd_waitQ) == USB_SUCCESS) {
26910Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
26920Sstevel@tonic-gate
26930Sstevel@tonic-gate return (TRAN_BUSY);
26940Sstevel@tonic-gate } else {
26950Sstevel@tonic-gate
26960Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
26970Sstevel@tonic-gate
26980Sstevel@tonic-gate return (TRAN_ACCEPT);
26990Sstevel@tonic-gate }
27000Sstevel@tonic-gate }
27010Sstevel@tonic-gate scsa2usbp->scsa2usb_work_thread_id = (kthread_t *)1;
27020Sstevel@tonic-gate }
2703189Sfrits
27040Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
27050Sstevel@tonic-gate
27060Sstevel@tonic-gate return (TRAN_ACCEPT);
27070Sstevel@tonic-gate }
27080Sstevel@tonic-gate
27090Sstevel@tonic-gate
27100Sstevel@tonic-gate /*
27110Sstevel@tonic-gate * scsa2usb_scsi_abort:
27120Sstevel@tonic-gate * Issue SCSI abort command. This function is a NOP.
27130Sstevel@tonic-gate */
27140Sstevel@tonic-gate /* ARGSUSED */
27150Sstevel@tonic-gate static int
scsa2usb_scsi_abort(struct scsi_address * ap,struct scsi_pkt * pkt)27160Sstevel@tonic-gate scsa2usb_scsi_abort(struct scsi_address *ap, struct scsi_pkt *pkt)
27170Sstevel@tonic-gate {
27180Sstevel@tonic-gate scsa2usb_state_t *scsa2usbp = (scsa2usb_state_t *)ADDR2SCSA2USB(ap);
27190Sstevel@tonic-gate
27200Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
27216898Sfb209375 "scsa2usb_scsi_abort: pkt = %p", (void *)pkt);
27220Sstevel@tonic-gate
27230Sstevel@tonic-gate /* if device is disconnected (ie. pipes closed), fail immediately */
27240Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
27250Sstevel@tonic-gate if (!(SCSA2USB_DEVICE_ACCESS_OK(scsa2usbp))) {
27260Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
27270Sstevel@tonic-gate
27280Sstevel@tonic-gate return (0);
27290Sstevel@tonic-gate }
27300Sstevel@tonic-gate
27310Sstevel@tonic-gate /* flush waitQ if target and lun match */
27320Sstevel@tonic-gate if ((ap->a_target == pkt->pkt_address.a_target) &&
27330Sstevel@tonic-gate (ap->a_lun == pkt->pkt_address.a_lun)) {
27340Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
27350Sstevel@tonic-gate scsa2usb_flush_waitQ(scsa2usbp, ap->a_lun, CMD_ABORTED);
27360Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
27370Sstevel@tonic-gate }
27380Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
27390Sstevel@tonic-gate
27400Sstevel@tonic-gate return (0);
27410Sstevel@tonic-gate }
27420Sstevel@tonic-gate
27430Sstevel@tonic-gate
27440Sstevel@tonic-gate /*
27450Sstevel@tonic-gate * scsa2usb_scsi_reset:
27460Sstevel@tonic-gate * device reset may turn the device into a brick and bus reset
27470Sstevel@tonic-gate * is not applicable.
27480Sstevel@tonic-gate * just flush the waitQ
27490Sstevel@tonic-gate * We return success, always.
27500Sstevel@tonic-gate */
27510Sstevel@tonic-gate /* ARGSUSED */
27520Sstevel@tonic-gate static int
scsa2usb_scsi_reset(struct scsi_address * ap,int level)27530Sstevel@tonic-gate scsa2usb_scsi_reset(struct scsi_address *ap, int level)
27540Sstevel@tonic-gate {
27550Sstevel@tonic-gate scsa2usb_state_t *scsa2usbp = (scsa2usb_state_t *)ADDR2SCSA2USB(ap);
27560Sstevel@tonic-gate
27570Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
27586898Sfb209375 "scsa2usb_scsi_reset: ap = 0x%p, level = %d", (void *)ap, level);
27590Sstevel@tonic-gate
27600Sstevel@tonic-gate /* flush waitQ */
27610Sstevel@tonic-gate scsa2usb_flush_waitQ(scsa2usbp, ap->a_lun, CMD_RESET);
27620Sstevel@tonic-gate
27630Sstevel@tonic-gate return (1);
27640Sstevel@tonic-gate }
27650Sstevel@tonic-gate
27660Sstevel@tonic-gate
27670Sstevel@tonic-gate /*
27680Sstevel@tonic-gate * scsa2usb_scsi_getcap:
27690Sstevel@tonic-gate * Get SCSI capabilities.
27700Sstevel@tonic-gate */
27710Sstevel@tonic-gate /* ARGSUSED */
27720Sstevel@tonic-gate static int
scsa2usb_scsi_getcap(struct scsi_address * ap,char * cap,int whom)27730Sstevel@tonic-gate scsa2usb_scsi_getcap(struct scsi_address *ap, char *cap, int whom)
27740Sstevel@tonic-gate {
27750Sstevel@tonic-gate int rval = -1;
27760Sstevel@tonic-gate uint_t cidx;
27770Sstevel@tonic-gate size_t dev_bsize_cap;
27780Sstevel@tonic-gate scsa2usb_state_t *scsa2usbp = (scsa2usb_state_t *)ADDR2SCSA2USB(ap);
27790Sstevel@tonic-gate ASSERT(scsa2usbp);
27800Sstevel@tonic-gate
27810Sstevel@tonic-gate if (cap == NULL) {
27820Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
27830Sstevel@tonic-gate "scsa2usb_scsi_getcap: invalid arg, "
27846898Sfb209375 "cap = 0x%p whom = %d", (void *)cap, whom);
27850Sstevel@tonic-gate
27860Sstevel@tonic-gate return (rval);
27870Sstevel@tonic-gate }
27880Sstevel@tonic-gate
27890Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
27900Sstevel@tonic-gate "scsa2usb_scsi_getcap: cap = %s", cap);
27910Sstevel@tonic-gate
27920Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
27930Sstevel@tonic-gate
27940Sstevel@tonic-gate /* if device is disconnected (ie. pipes closed), fail immediately */
27950Sstevel@tonic-gate if (!(SCSA2USB_DEVICE_ACCESS_OK(scsa2usbp))) {
27960Sstevel@tonic-gate
27970Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
27980Sstevel@tonic-gate
27990Sstevel@tonic-gate return (rval);
28000Sstevel@tonic-gate }
28010Sstevel@tonic-gate
28020Sstevel@tonic-gate cidx = scsi_hba_lookup_capstr(cap);
28030Sstevel@tonic-gate switch (cidx) {
28040Sstevel@tonic-gate case SCSI_CAP_GEOMETRY:
28057015Sbc224572 /* Just check and fail immediately if zero, rarely happens */
28067015Sbc224572 if (scsa2usbp->scsa2usb_secsz[ap->a_lun] == 0) {
28077015Sbc224572 USB_DPRINTF_L2(DPRINT_MASK_SCSA,
28087015Sbc224572 scsa2usbp->scsa2usb_log_handle,
28097015Sbc224572 "scsa2usb_scsi_getcap failed:"
28107015Sbc224572 "scsa2usbp->scsa2usb_secsz[ap->a_lun] == 0");
28117015Sbc224572 mutex_exit(&scsa2usbp->scsa2usb_mutex);
28127015Sbc224572
28137015Sbc224572 return (rval);
28147015Sbc224572 }
28157015Sbc224572
28160Sstevel@tonic-gate dev_bsize_cap = scsa2usbp->scsa2usb_totalsec[ap->a_lun];
28170Sstevel@tonic-gate
28180Sstevel@tonic-gate if (scsa2usbp->scsa2usb_secsz[ap->a_lun] > DEV_BSIZE) {
28190Sstevel@tonic-gate dev_bsize_cap *=
28200Sstevel@tonic-gate scsa2usbp->scsa2usb_secsz[ap->a_lun] / DEV_BSIZE;
28210Sstevel@tonic-gate } else if (scsa2usbp->scsa2usb_secsz[ap->a_lun] <
28220Sstevel@tonic-gate DEV_BSIZE) {
28230Sstevel@tonic-gate dev_bsize_cap /=
28240Sstevel@tonic-gate DEV_BSIZE / scsa2usbp->scsa2usb_secsz[ap->a_lun];
28250Sstevel@tonic-gate }
28260Sstevel@tonic-gate
28270Sstevel@tonic-gate if (dev_bsize_cap < 65536 * 2 * 18) { /* < ~1GB */
28280Sstevel@tonic-gate /* unlabeled floppy, 18k per cylinder */
28290Sstevel@tonic-gate rval = ((2 << 16) | 18);
28300Sstevel@tonic-gate } else if (dev_bsize_cap < 65536 * 64 * 32) { /* < 64GB */
28310Sstevel@tonic-gate /* 1024k per cylinder */
28320Sstevel@tonic-gate rval = ((64 << 16) | 32);
28330Sstevel@tonic-gate } else if (dev_bsize_cap < 65536 * 255 * 63) { /* < ~500GB */
28340Sstevel@tonic-gate /* ~8m per cylinder */
28350Sstevel@tonic-gate rval = ((255 << 16) | 63);
28360Sstevel@tonic-gate } else { /* .. 8TB */
28370Sstevel@tonic-gate /* 64m per cylinder */
28380Sstevel@tonic-gate rval = ((512 << 16) | 256);
28390Sstevel@tonic-gate }
28400Sstevel@tonic-gate break;
28410Sstevel@tonic-gate
28420Sstevel@tonic-gate case SCSI_CAP_DMA_MAX:
28430Sstevel@tonic-gate rval = scsa2usbp->scsa2usb_max_bulk_xfer_size;
28440Sstevel@tonic-gate break;
28450Sstevel@tonic-gate case SCSI_CAP_SCSI_VERSION:
28460Sstevel@tonic-gate rval = SCSI_VERSION_2;
28470Sstevel@tonic-gate break;
28480Sstevel@tonic-gate case SCSI_CAP_INTERCONNECT_TYPE:
28490Sstevel@tonic-gate rval = INTERCONNECT_USB;
28500Sstevel@tonic-gate break;
28510Sstevel@tonic-gate case SCSI_CAP_ARQ:
28520Sstevel@tonic-gate /* FALLTHRU */
28530Sstevel@tonic-gate case SCSI_CAP_UNTAGGED_QING:
28540Sstevel@tonic-gate rval = 1;
28550Sstevel@tonic-gate break;
28560Sstevel@tonic-gate default:
28570Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
28580Sstevel@tonic-gate "scsa2usb_scsi_getcap: unsupported cap = %s", cap);
28590Sstevel@tonic-gate break;
28600Sstevel@tonic-gate }
28610Sstevel@tonic-gate
28620Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
28630Sstevel@tonic-gate "scsa2usb_scsi_getcap: cap = %s, returned = %d", cap, rval);
28640Sstevel@tonic-gate
28650Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
28660Sstevel@tonic-gate
28670Sstevel@tonic-gate return (rval);
28680Sstevel@tonic-gate }
28690Sstevel@tonic-gate
28700Sstevel@tonic-gate
28710Sstevel@tonic-gate /*
28720Sstevel@tonic-gate * scsa2usb_scsi_setcap:
28730Sstevel@tonic-gate * Set SCSI capabilities.
28740Sstevel@tonic-gate */
28750Sstevel@tonic-gate /* ARGSUSED */
28760Sstevel@tonic-gate static int
scsa2usb_scsi_setcap(struct scsi_address * ap,char * cap,int value,int whom)28770Sstevel@tonic-gate scsa2usb_scsi_setcap(struct scsi_address *ap, char *cap, int value, int whom)
28780Sstevel@tonic-gate {
28790Sstevel@tonic-gate int rval = -1; /* default is cap undefined */
28800Sstevel@tonic-gate uint_t cidx;
28810Sstevel@tonic-gate scsa2usb_state_t *scsa2usbp = (scsa2usb_state_t *)ADDR2SCSA2USB(ap);
28820Sstevel@tonic-gate ASSERT(scsa2usbp);
28830Sstevel@tonic-gate
28840Sstevel@tonic-gate if (cap == NULL || whom == 0) {
28850Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
28860Sstevel@tonic-gate "scsa2usb_scsi_setcap: invalid arg");
28870Sstevel@tonic-gate
28880Sstevel@tonic-gate return (rval);
28890Sstevel@tonic-gate }
28900Sstevel@tonic-gate
28910Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
28920Sstevel@tonic-gate /* if device is disconnected (ie. pipes closed), fail immediately */
28930Sstevel@tonic-gate if (!(SCSA2USB_DEVICE_ACCESS_OK(scsa2usbp))) {
28940Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
28950Sstevel@tonic-gate
28960Sstevel@tonic-gate return (rval);
28970Sstevel@tonic-gate }
28980Sstevel@tonic-gate
28990Sstevel@tonic-gate cidx = scsi_hba_lookup_capstr(cap);
29000Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
29010Sstevel@tonic-gate "scsa2usb_scsi_setcap: ap = 0x%p value = 0x%x whom = 0x%x "
29026898Sfb209375 "cidx = 0x%x", (void *)ap, value, whom, cidx);
29030Sstevel@tonic-gate
29040Sstevel@tonic-gate switch (cidx) {
29050Sstevel@tonic-gate case SCSI_CAP_SECTOR_SIZE:
29060Sstevel@tonic-gate if (value) {
29070Sstevel@tonic-gate scsa2usbp->scsa2usb_secsz[ap->a_lun] = value;
29080Sstevel@tonic-gate }
29090Sstevel@tonic-gate break;
29100Sstevel@tonic-gate case SCSI_CAP_TOTAL_SECTORS:
29110Sstevel@tonic-gate if (value) {
29120Sstevel@tonic-gate scsa2usbp->scsa2usb_totalsec[ap->a_lun] = value;
29130Sstevel@tonic-gate }
29140Sstevel@tonic-gate break;
29150Sstevel@tonic-gate case SCSI_CAP_ARQ:
29160Sstevel@tonic-gate rval = 1;
29170Sstevel@tonic-gate break;
29180Sstevel@tonic-gate case SCSI_CAP_DMA_MAX:
29190Sstevel@tonic-gate case SCSI_CAP_SCSI_VERSION:
29200Sstevel@tonic-gate case SCSI_CAP_INTERCONNECT_TYPE:
29210Sstevel@tonic-gate case SCSI_CAP_UNTAGGED_QING:
29220Sstevel@tonic-gate /* supported but not settable */
29230Sstevel@tonic-gate rval = 0;
29240Sstevel@tonic-gate break;
29250Sstevel@tonic-gate default:
29260Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
29270Sstevel@tonic-gate "scsa2usb_scsi_setcap: unsupported cap = %s", cap);
29280Sstevel@tonic-gate break;
29290Sstevel@tonic-gate }
29300Sstevel@tonic-gate
29310Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
29320Sstevel@tonic-gate
29330Sstevel@tonic-gate return (rval);
29340Sstevel@tonic-gate }
29350Sstevel@tonic-gate
29360Sstevel@tonic-gate
29370Sstevel@tonic-gate /*
29380Sstevel@tonic-gate * scsa2usb - cmd and transport stuff
29390Sstevel@tonic-gate */
29400Sstevel@tonic-gate /*
29410Sstevel@tonic-gate * scsa2usb_prepare_pkt:
29420Sstevel@tonic-gate * initialize some fields of the pkt and cmd
29430Sstevel@tonic-gate * (the pkt may have been resubmitted/retried)
29440Sstevel@tonic-gate */
29450Sstevel@tonic-gate static void
scsa2usb_prepare_pkt(scsa2usb_state_t * scsa2usbp,struct scsi_pkt * pkt)29460Sstevel@tonic-gate scsa2usb_prepare_pkt(scsa2usb_state_t *scsa2usbp, struct scsi_pkt *pkt)
29470Sstevel@tonic-gate {
29480Sstevel@tonic-gate scsa2usb_cmd_t *cmd = PKT2CMD(pkt);
29490Sstevel@tonic-gate
29500Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
29510Sstevel@tonic-gate "scsa2usb_prepare_pkt: pkt=0x%p cdb: 0x%x (%s)",
29526898Sfb209375 (void *)pkt, pkt->pkt_cdbp[0],
29530Sstevel@tonic-gate scsi_cname(pkt->pkt_cdbp[0], scsa2usb_cmds));
29540Sstevel@tonic-gate
29550Sstevel@tonic-gate pkt->pkt_reason = CMD_CMPLT; /* Set reason to pkt_complete */
29560Sstevel@tonic-gate pkt->pkt_state = 0; /* Reset next three fields */
29570Sstevel@tonic-gate pkt->pkt_statistics = 0;
29580Sstevel@tonic-gate pkt->pkt_resid = 0;
29590Sstevel@tonic-gate bzero(pkt->pkt_scbp, cmd->cmd_scblen); /* Set status to good */
29600Sstevel@tonic-gate
29610Sstevel@tonic-gate if (cmd) {
29620Sstevel@tonic-gate cmd->cmd_timeout = pkt->pkt_time;
29630Sstevel@tonic-gate cmd->cmd_xfercount = 0; /* Reset the fields */
29640Sstevel@tonic-gate cmd->cmd_total_xfercount = 0;
29650Sstevel@tonic-gate cmd->cmd_lba = 0;
29660Sstevel@tonic-gate cmd->cmd_done = 0;
29670Sstevel@tonic-gate cmd->cmd_dir = 0;
29680Sstevel@tonic-gate cmd->cmd_offset = 0;
29690Sstevel@tonic-gate cmd->cmd_actual_len = cmd->cmd_cdblen;
29700Sstevel@tonic-gate }
29710Sstevel@tonic-gate }
29720Sstevel@tonic-gate
29730Sstevel@tonic-gate
29740Sstevel@tonic-gate /*
29750Sstevel@tonic-gate * scsa2usb_force_invalid_request
29760Sstevel@tonic-gate */
29770Sstevel@tonic-gate static void
scsa2usb_force_invalid_request(scsa2usb_state_t * scsa2usbp,scsa2usb_cmd_t * cmd)29780Sstevel@tonic-gate scsa2usb_force_invalid_request(scsa2usb_state_t *scsa2usbp,
29790Sstevel@tonic-gate scsa2usb_cmd_t *cmd)
29800Sstevel@tonic-gate {
29810Sstevel@tonic-gate struct scsi_arq_status *arqp;
29820Sstevel@tonic-gate
29830Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
29846898Sfb209375 "scsa2usb_force_invalid_request: pkt = 0x%p", (void *)cmd->cmd_pkt);
29850Sstevel@tonic-gate
29860Sstevel@tonic-gate if (cmd->cmd_scblen >= sizeof (struct scsi_arq_status)) {
29870Sstevel@tonic-gate arqp = (struct scsi_arq_status *)cmd->cmd_pkt->pkt_scbp;
29880Sstevel@tonic-gate bzero(arqp, cmd->cmd_scblen);
29890Sstevel@tonic-gate
29900Sstevel@tonic-gate arqp->sts_status.sts_chk = 1;
29910Sstevel@tonic-gate arqp->sts_rqpkt_reason = CMD_CMPLT;
29920Sstevel@tonic-gate arqp->sts_rqpkt_state = STATE_XFERRED_DATA |
29930Sstevel@tonic-gate STATE_GOT_BUS | STATE_GOT_STATUS;
29940Sstevel@tonic-gate arqp->sts_sensedata.es_valid = 1;
29950Sstevel@tonic-gate arqp->sts_sensedata.es_class = 7;
29960Sstevel@tonic-gate arqp->sts_sensedata.es_key = KEY_ILLEGAL_REQUEST;
29970Sstevel@tonic-gate
29980Sstevel@tonic-gate cmd->cmd_pkt->pkt_state = STATE_ARQ_DONE |
29990Sstevel@tonic-gate STATE_GOT_BUS | STATE_GOT_BUS | STATE_GOT_BUS |
30000Sstevel@tonic-gate STATE_GOT_STATUS;
30010Sstevel@tonic-gate #ifdef DEBUG
30020Sstevel@tonic-gate {
30030Sstevel@tonic-gate uchar_t *p = (uchar_t *)(&arqp->sts_sensedata);
30040Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_SCSA,
30050Sstevel@tonic-gate scsa2usbp->scsa2usb_log_handle,
30060Sstevel@tonic-gate "cdb: %x rqsense: "
30070Sstevel@tonic-gate "%x %x %x %x %x %x %x %x %x %x "
30080Sstevel@tonic-gate "%x %x %x %x %x %x %x %x %x %x",
30090Sstevel@tonic-gate cmd->cmd_pkt->pkt_cdbp[0],
30100Sstevel@tonic-gate p[0], p[1], p[2], p[3], p[4],
30110Sstevel@tonic-gate p[5], p[6], p[7], p[8], p[9],
30120Sstevel@tonic-gate p[10], p[11], p[12], p[13], p[14],
30130Sstevel@tonic-gate p[15], p[16], p[17], p[18], p[19]);
30140Sstevel@tonic-gate }
30150Sstevel@tonic-gate #endif
30160Sstevel@tonic-gate
30170Sstevel@tonic-gate }
30180Sstevel@tonic-gate }
30190Sstevel@tonic-gate
30200Sstevel@tonic-gate
30210Sstevel@tonic-gate /*
30220Sstevel@tonic-gate * scsa2usb_cmd_transport:
30230Sstevel@tonic-gate */
30240Sstevel@tonic-gate static int
scsa2usb_cmd_transport(scsa2usb_state_t * scsa2usbp,scsa2usb_cmd_t * cmd)30250Sstevel@tonic-gate scsa2usb_cmd_transport(scsa2usb_state_t *scsa2usbp, scsa2usb_cmd_t *cmd)
30260Sstevel@tonic-gate {
30270Sstevel@tonic-gate int rval, transport;
30280Sstevel@tonic-gate struct scsi_pkt *pkt;
30290Sstevel@tonic-gate
30300Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
30310Sstevel@tonic-gate "scsa2usb_cmd_transport: pkt: 0x%p, cur_pkt = 0x%p",
30326898Sfb209375 (void *)cmd->cmd_pkt, (void *)scsa2usbp->scsa2usb_cur_pkt);
30330Sstevel@tonic-gate
30340Sstevel@tonic-gate ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
30350Sstevel@tonic-gate ASSERT(scsa2usbp->scsa2usb_cur_pkt == NULL);
30360Sstevel@tonic-gate
30370Sstevel@tonic-gate pkt = scsa2usbp->scsa2usb_cur_pkt = cmd->cmd_pkt;
30380Sstevel@tonic-gate
30390Sstevel@tonic-gate /* check black-listed attrs first */
30400Sstevel@tonic-gate if (SCSA2USB_IS_BULK_ONLY(scsa2usbp)) {
30410Sstevel@tonic-gate transport = scsa2usb_check_bulkonly_blacklist_attrs(scsa2usbp,
30424700Sfb209375 cmd, pkt->pkt_cdbp[0]);
30430Sstevel@tonic-gate } else if (SCSA2USB_IS_CB(scsa2usbp) || SCSA2USB_IS_CBI(scsa2usbp)) {
30440Sstevel@tonic-gate transport = scsa2usb_check_ufi_blacklist_attrs(scsa2usbp,
30454700Sfb209375 pkt->pkt_cdbp[0], cmd);
30460Sstevel@tonic-gate }
30470Sstevel@tonic-gate
304810630SGuoqing.Zhu@Sun.COM /* just accept the command or return error */
30490Sstevel@tonic-gate if (transport == SCSA2USB_JUST_ACCEPT) {
30500Sstevel@tonic-gate SCSA2USB_SET_PKT_DO_COMP_STATE(scsa2usbp);
30510Sstevel@tonic-gate
30520Sstevel@tonic-gate return (TRAN_ACCEPT);
305310630SGuoqing.Zhu@Sun.COM } else if (transport == SCSA2USB_REJECT) {
305410630SGuoqing.Zhu@Sun.COM return (TRAN_FATAL_ERROR);
30550Sstevel@tonic-gate }
30560Sstevel@tonic-gate
30570Sstevel@tonic-gate /* check command set next */
30580Sstevel@tonic-gate if (SCSA2USB_IS_SCSI_CMDSET(scsa2usbp) ||
30590Sstevel@tonic-gate SCSA2USB_IS_ATAPI_CMDSET(scsa2usbp)) {
30600Sstevel@tonic-gate transport =
30610Sstevel@tonic-gate scsa2usb_handle_scsi_cmd_sub_class(scsa2usbp, cmd, pkt);
30620Sstevel@tonic-gate } else if (SCSA2USB_IS_UFI_CMDSET(scsa2usbp)) {
30630Sstevel@tonic-gate transport =
30640Sstevel@tonic-gate scsa2usb_handle_ufi_subclass_cmd(scsa2usbp, cmd, pkt);
30650Sstevel@tonic-gate } else {
30660Sstevel@tonic-gate transport = SCSA2USB_REJECT;
30670Sstevel@tonic-gate }
30680Sstevel@tonic-gate
30691984Scg149915 switch (transport) {
30701984Scg149915 case SCSA2USB_TRANSPORT:
30710Sstevel@tonic-gate if (SCSA2USB_IS_BULK_ONLY(scsa2usbp)) {
30720Sstevel@tonic-gate rval = scsa2usb_bulk_only_transport(scsa2usbp, cmd);
30730Sstevel@tonic-gate } else if (SCSA2USB_IS_CB(scsa2usbp) ||
30740Sstevel@tonic-gate SCSA2USB_IS_CBI(scsa2usbp)) {
30750Sstevel@tonic-gate rval = scsa2usb_cbi_transport(scsa2usbp, cmd);
30760Sstevel@tonic-gate } else {
30770Sstevel@tonic-gate rval = TRAN_FATAL_ERROR;
30780Sstevel@tonic-gate }
30791984Scg149915 break;
30801984Scg149915 case SCSA2USB_JUST_ACCEPT:
30811984Scg149915 SCSA2USB_SET_PKT_DO_COMP_STATE(scsa2usbp);
30821984Scg149915 rval = TRAN_ACCEPT;
30831984Scg149915 break;
30841984Scg149915 default:
30850Sstevel@tonic-gate rval = TRAN_FATAL_ERROR;
30860Sstevel@tonic-gate }
30870Sstevel@tonic-gate
30880Sstevel@tonic-gate return (rval);
30890Sstevel@tonic-gate }
30900Sstevel@tonic-gate
30910Sstevel@tonic-gate
30920Sstevel@tonic-gate /*
30930Sstevel@tonic-gate * scsa2usb_check_bulkonly_blacklist_attrs:
30940Sstevel@tonic-gate * validate "scsa2usb_blacklist_attrs" (see scsa2usb.h)
30950Sstevel@tonic-gate * if blacklisted attrs match accept the request
30960Sstevel@tonic-gate * attributes checked are:-
30970Sstevel@tonic-gate * SCSA2USB_ATTRS_START_STOP
30980Sstevel@tonic-gate */
30990Sstevel@tonic-gate int
scsa2usb_check_bulkonly_blacklist_attrs(scsa2usb_state_t * scsa2usbp,scsa2usb_cmd_t * cmd,uchar_t opcode)31000Sstevel@tonic-gate scsa2usb_check_bulkonly_blacklist_attrs(scsa2usb_state_t *scsa2usbp,
31010Sstevel@tonic-gate scsa2usb_cmd_t *cmd, uchar_t opcode)
31020Sstevel@tonic-gate {
3103880Sfrits struct scsi_inquiry *inq =
3104880Sfrits &scsa2usbp->scsa2usb_lun_inquiry[cmd->cmd_pkt->pkt_address.a_lun];
3105880Sfrits
31060Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
31070Sstevel@tonic-gate "scsa2usb_check_bulkonly_blacklist_attrs: opcode = %s",
31080Sstevel@tonic-gate scsi_cname(opcode, scsa2usb_cmds));
31090Sstevel@tonic-gate
31100Sstevel@tonic-gate ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
31110Sstevel@tonic-gate
31120Sstevel@tonic-gate /*
31130Sstevel@tonic-gate * decode and convert the packet
31140Sstevel@tonic-gate * for most cmds, we can bcopy the cdb
31150Sstevel@tonic-gate */
31160Sstevel@tonic-gate switch (opcode) {
31170Sstevel@tonic-gate case SCMD_DOORLOCK:
31180Sstevel@tonic-gate if (!(scsa2usbp->scsa2usb_attrs & SCSA2USB_ATTRS_DOORLOCK)) {
31190Sstevel@tonic-gate
31200Sstevel@tonic-gate return (SCSA2USB_JUST_ACCEPT);
31210Sstevel@tonic-gate
3122880Sfrits /*
3123880Sfrits * only lock the door for CD and DVD drives
3124880Sfrits */
3125880Sfrits } else if ((inq->inq_dtype == DTYPE_RODIRECT) ||
3126880Sfrits (inq->inq_dtype == DTYPE_OPTICAL)) {
3127880Sfrits
3128880Sfrits if (inq->inq_rmb) {
3129880Sfrits
3130880Sfrits break;
3131880Sfrits }
31320Sstevel@tonic-gate }
31330Sstevel@tonic-gate
31340Sstevel@tonic-gate return (SCSA2USB_JUST_ACCEPT);
31350Sstevel@tonic-gate
313611282SSheshadri.Vasudevan@Sun.COM case SCMD_START_STOP: /* SCMD_LOAD for sequential devices */
31370Sstevel@tonic-gate /*
31380Sstevel@tonic-gate * these devices don't have mechanics that spin the
31390Sstevel@tonic-gate * media up and down. So, it doesn't make much sense
31400Sstevel@tonic-gate * to issue this cmd.
31410Sstevel@tonic-gate *
31420Sstevel@tonic-gate * Furthermore, Hagiwara devices do not handle these
31430Sstevel@tonic-gate * cmds well. just accept this command as success.
31440Sstevel@tonic-gate */
31450Sstevel@tonic-gate if (!(scsa2usbp->scsa2usb_attrs & SCSA2USB_ATTRS_START_STOP)) {
31460Sstevel@tonic-gate
31470Sstevel@tonic-gate return (SCSA2USB_JUST_ACCEPT);
31480Sstevel@tonic-gate
314911282SSheshadri.Vasudevan@Sun.COM } else if (inq->inq_dtype == DTYPE_SEQUENTIAL) {
315011282SSheshadri.Vasudevan@Sun.COM /*
315111282SSheshadri.Vasudevan@Sun.COM * In case of USB tape device, we need to send the
315211282SSheshadri.Vasudevan@Sun.COM * command to the device to unload the media.
315311282SSheshadri.Vasudevan@Sun.COM */
315411282SSheshadri.Vasudevan@Sun.COM break;
315511282SSheshadri.Vasudevan@Sun.COM
31560Sstevel@tonic-gate } else if (cmd->cmd_pkt->pkt_cdbp[4] & LOEJECT) {
31570Sstevel@tonic-gate /*
31580Sstevel@tonic-gate * if the device is really a removable then
31590Sstevel@tonic-gate * pass it on to the device, else just accept
31600Sstevel@tonic-gate */
3161880Sfrits if (inq->inq_rmb) {
31620Sstevel@tonic-gate
31630Sstevel@tonic-gate break;
31640Sstevel@tonic-gate }
31650Sstevel@tonic-gate
31660Sstevel@tonic-gate return (SCSA2USB_JUST_ACCEPT);
31670Sstevel@tonic-gate
31680Sstevel@tonic-gate } else if (!scsa2usbp->scsa2usb_rcvd_not_ready) {
31690Sstevel@tonic-gate /*
31700Sstevel@tonic-gate * if we have not received a NOT READY condition,
31710Sstevel@tonic-gate * just accept since some device choke on this too.
31720Sstevel@tonic-gate * we do have to let EJECT get through though
31730Sstevel@tonic-gate */
31740Sstevel@tonic-gate return (SCSA2USB_JUST_ACCEPT);
31750Sstevel@tonic-gate }
31760Sstevel@tonic-gate
31770Sstevel@tonic-gate break;
31780Sstevel@tonic-gate case SCMD_INQUIRY:
31790Sstevel@tonic-gate /*
31800Sstevel@tonic-gate * Some devices do not handle the inquiry cmd well
31810Sstevel@tonic-gate * so build an inquiry and accept this command as
31820Sstevel@tonic-gate * success.
31830Sstevel@tonic-gate */
31840Sstevel@tonic-gate if (!(scsa2usbp->scsa2usb_attrs & SCSA2USB_ATTRS_INQUIRY)) {
31850Sstevel@tonic-gate uchar_t evpd = 0x01;
31868003SVitezslav.Batrla@Sun.COM unsigned int bufsize;
31878003SVitezslav.Batrla@Sun.COM int count;
31888003SVitezslav.Batrla@Sun.COM
318910630SGuoqing.Zhu@Sun.COM if (cmd->cmd_pkt->pkt_cdbp[1] & evpd)
31900Sstevel@tonic-gate return (SCSA2USB_REJECT);
31918003SVitezslav.Batrla@Sun.COM
31928003SVitezslav.Batrla@Sun.COM scsa2usb_fake_inquiry(scsa2usbp, inq);
31938003SVitezslav.Batrla@Sun.COM
31948003SVitezslav.Batrla@Sun.COM /* Copy no more than requested */
31958003SVitezslav.Batrla@Sun.COM count = MIN(cmd->cmd_bp->b_bcount,
31968003SVitezslav.Batrla@Sun.COM sizeof (struct scsi_inquiry));
31978003SVitezslav.Batrla@Sun.COM bufsize = cmd->cmd_pkt->pkt_cdbp[4];
31988003SVitezslav.Batrla@Sun.COM count = MIN(count, bufsize);
31998003SVitezslav.Batrla@Sun.COM bcopy(inq, cmd->cmd_bp->b_un.b_addr, count);
32008003SVitezslav.Batrla@Sun.COM
32018003SVitezslav.Batrla@Sun.COM cmd->cmd_pkt->pkt_resid = bufsize - count;
32020Sstevel@tonic-gate cmd->cmd_pkt->pkt_state |= STATE_XFERRED_DATA;
32030Sstevel@tonic-gate
32040Sstevel@tonic-gate return (SCSA2USB_JUST_ACCEPT);
320510678SGuoqing.Zhu@Sun.COM } else if (!(scsa2usbp->scsa2usb_attrs &
320610678SGuoqing.Zhu@Sun.COM SCSA2USB_ATTRS_INQUIRY_EVPD)) {
320710678SGuoqing.Zhu@Sun.COM /*
320810678SGuoqing.Zhu@Sun.COM * Some devices do not handle the inquiry cmd with
320910678SGuoqing.Zhu@Sun.COM * evpd bit set well, e.g. some devices return the
321010678SGuoqing.Zhu@Sun.COM * same page 0x83 data which will cause the generated
321110678SGuoqing.Zhu@Sun.COM * devid by sd is not unique, thus return CHECK
321210678SGuoqing.Zhu@Sun.COM * CONDITION directly to sd.
321310678SGuoqing.Zhu@Sun.COM */
321410678SGuoqing.Zhu@Sun.COM uchar_t evpd = 0x01;
321510678SGuoqing.Zhu@Sun.COM
321610678SGuoqing.Zhu@Sun.COM if (!(cmd->cmd_pkt->pkt_cdbp[1] & evpd))
321710678SGuoqing.Zhu@Sun.COM break;
321810678SGuoqing.Zhu@Sun.COM
321910678SGuoqing.Zhu@Sun.COM if (cmd->cmd_bp) {
322010678SGuoqing.Zhu@Sun.COM cmd->cmd_pkt->pkt_resid = cmd->cmd_bp->
322110678SGuoqing.Zhu@Sun.COM b_bcount;
322210678SGuoqing.Zhu@Sun.COM }
322310678SGuoqing.Zhu@Sun.COM scsa2usb_force_invalid_request(scsa2usbp, cmd);
322410678SGuoqing.Zhu@Sun.COM
322510678SGuoqing.Zhu@Sun.COM return (SCSA2USB_JUST_ACCEPT);
32260Sstevel@tonic-gate }
32270Sstevel@tonic-gate break;
32280Sstevel@tonic-gate /*
3229880Sfrits * Fake accepting the following Opcodes
3230880Sfrits * (as most drives don't support these)
32310Sstevel@tonic-gate * These are needed by format command.
32320Sstevel@tonic-gate */
32330Sstevel@tonic-gate case SCMD_RESERVE:
32340Sstevel@tonic-gate case SCMD_RELEASE:
32350Sstevel@tonic-gate case SCMD_PERSISTENT_RESERVE_IN:
32360Sstevel@tonic-gate case SCMD_PERSISTENT_RESERVE_OUT:
32370Sstevel@tonic-gate
32380Sstevel@tonic-gate return (SCSA2USB_JUST_ACCEPT);
32390Sstevel@tonic-gate
32400Sstevel@tonic-gate case SCMD_MODE_SENSE:
32410Sstevel@tonic-gate case SCMD_MODE_SELECT:
32420Sstevel@tonic-gate case SCMD_MODE_SENSE_G1:
32430Sstevel@tonic-gate case SCMD_MODE_SELECT_G1:
32440Sstevel@tonic-gate if (!(scsa2usbp->scsa2usb_attrs & SCSA2USB_ATTRS_MODE_SENSE)) {
32450Sstevel@tonic-gate if (cmd->cmd_bp) {
32460Sstevel@tonic-gate cmd->cmd_pkt->pkt_resid = cmd->cmd_bp->
32474700Sfb209375 b_bcount;
32480Sstevel@tonic-gate }
32490Sstevel@tonic-gate scsa2usb_force_invalid_request(scsa2usbp, cmd);
32500Sstevel@tonic-gate
32510Sstevel@tonic-gate return (SCSA2USB_JUST_ACCEPT);
32520Sstevel@tonic-gate }
32530Sstevel@tonic-gate
32540Sstevel@tonic-gate break;
32550Sstevel@tonic-gate default:
32560Sstevel@tonic-gate
32570Sstevel@tonic-gate break;
32580Sstevel@tonic-gate }
32590Sstevel@tonic-gate
32600Sstevel@tonic-gate return (SCSA2USB_TRANSPORT);
32610Sstevel@tonic-gate }
32620Sstevel@tonic-gate
32630Sstevel@tonic-gate
32640Sstevel@tonic-gate /*
32650Sstevel@tonic-gate * scsa2usb_handle_scsi_cmd_sub_class:
32660Sstevel@tonic-gate * prepare a scsi cmd
32670Sstevel@tonic-gate * returns SCSA2USB_TRANSPORT, SCSA2USB_REJECT, SCSA2USB_JUST_ACCEPT
32680Sstevel@tonic-gate */
32690Sstevel@tonic-gate int
scsa2usb_handle_scsi_cmd_sub_class(scsa2usb_state_t * scsa2usbp,scsa2usb_cmd_t * cmd,struct scsi_pkt * pkt)32700Sstevel@tonic-gate scsa2usb_handle_scsi_cmd_sub_class(scsa2usb_state_t *scsa2usbp,
32710Sstevel@tonic-gate scsa2usb_cmd_t *cmd, struct scsi_pkt *pkt)
32720Sstevel@tonic-gate {
327310678SGuoqing.Zhu@Sun.COM uchar_t evpd = 0x01;
32740Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
32750Sstevel@tonic-gate "scsa2usb_handle_scsi_cmd_sub_class: cmd = 0x%p pkt = 0x%p",
32766898Sfb209375 (void *)cmd, (void *)pkt);
32770Sstevel@tonic-gate
32780Sstevel@tonic-gate ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
32790Sstevel@tonic-gate
32800Sstevel@tonic-gate bzero(&cmd->cmd_cdb, SCSI_CDB_SIZE);
32810Sstevel@tonic-gate cmd->cmd_cdb[SCSA2USB_OPCODE] = pkt->pkt_cdbp[0]; /* Set the opcode */
32820Sstevel@tonic-gate cmd->cmd_cdb[SCSA2USB_LUN] = pkt->pkt_cdbp[1];
32830Sstevel@tonic-gate
32840Sstevel@tonic-gate /*
32850Sstevel@tonic-gate * decode and convert the packet
32860Sstevel@tonic-gate * for most cmds, we can bcopy the cdb
32870Sstevel@tonic-gate */
32880Sstevel@tonic-gate switch (pkt->pkt_cdbp[0]) {
32890Sstevel@tonic-gate case SCMD_FORMAT:
32900Sstevel@tonic-gate /*
32910Sstevel@tonic-gate * SCMD_FORMAT used to limit cmd->cmd_xfercount
32920Sstevel@tonic-gate * to 4 bytes, but this hangs
32930Sstevel@tonic-gate * formatting dvd media using cdrecord (that is,
32940Sstevel@tonic-gate * a SCSI FORMAT UNIT command with a parameter list > 4 bytes)
32950Sstevel@tonic-gate * (bit 4 in cdb1 is the Fmtdata bit)
32960Sstevel@tonic-gate */
32970Sstevel@tonic-gate if ((pkt->pkt_cdbp[1] & 0x10) && cmd->cmd_bp) {
32980Sstevel@tonic-gate cmd->cmd_xfercount = cmd->cmd_bp->b_bcount;
32990Sstevel@tonic-gate } else {
33000Sstevel@tonic-gate cmd->cmd_xfercount = 4;
33010Sstevel@tonic-gate }
33020Sstevel@tonic-gate cmd->cmd_dir = CBW_DIR_OUT;
33030Sstevel@tonic-gate cmd->cmd_actual_len = CDB_GROUP0;
33040Sstevel@tonic-gate bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
33050Sstevel@tonic-gate break;
33060Sstevel@tonic-gate
33070Sstevel@tonic-gate case SCMD_INQUIRY:
33080Sstevel@tonic-gate cmd->cmd_dir = CBW_DIR_IN;
33090Sstevel@tonic-gate cmd->cmd_actual_len = CDB_GROUP0;
33100Sstevel@tonic-gate cmd->cmd_cdb[SCSA2USB_LBA_0] = pkt->pkt_cdbp[2];
331110678SGuoqing.Zhu@Sun.COM
331210678SGuoqing.Zhu@Sun.COM /*
331310678SGuoqing.Zhu@Sun.COM * If vpd pages data is limited to maximum SCSA2USB_MAX_INQ_LEN,
331410678SGuoqing.Zhu@Sun.COM * the page data may be truncated, which may cause some issues
331510678SGuoqing.Zhu@Sun.COM * such as making the unique page 0x83 or 0x80 data from
331610678SGuoqing.Zhu@Sun.COM * different devices become the same. So don't limit return
331710678SGuoqing.Zhu@Sun.COM * length for vpd page inquiry cmd.
331810678SGuoqing.Zhu@Sun.COM * Another, in order to maintain compatibility, the original
331910678SGuoqing.Zhu@Sun.COM * length limitation for standard inquiry retains here. It
332010678SGuoqing.Zhu@Sun.COM * can be removed in future if it is verified that enough
332110678SGuoqing.Zhu@Sun.COM * devices can work well.
332210678SGuoqing.Zhu@Sun.COM */
332310678SGuoqing.Zhu@Sun.COM if (pkt->pkt_cdbp[1] & evpd) {
332410678SGuoqing.Zhu@Sun.COM cmd->cmd_cdb[SCSA2USB_LBA_2] = cmd->cmd_xfercount =
332510678SGuoqing.Zhu@Sun.COM (cmd->cmd_bp ? cmd->cmd_bp->b_bcount : 0);
332610678SGuoqing.Zhu@Sun.COM } else {
332710678SGuoqing.Zhu@Sun.COM cmd->cmd_cdb[SCSA2USB_LBA_2] = cmd->cmd_xfercount =
332810678SGuoqing.Zhu@Sun.COM min(SCSA2USB_MAX_INQ_LEN,
332910678SGuoqing.Zhu@Sun.COM cmd->cmd_bp ? cmd->cmd_bp->b_bcount : 0);
333010678SGuoqing.Zhu@Sun.COM }
33310Sstevel@tonic-gate break;
33320Sstevel@tonic-gate
33330Sstevel@tonic-gate case SCMD_READ_CAPACITY:
33340Sstevel@tonic-gate cmd->cmd_dir = CBW_DIR_IN;
33350Sstevel@tonic-gate bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
33360Sstevel@tonic-gate cmd->cmd_xfercount = sizeof (scsa2usb_read_cap_t);
33370Sstevel@tonic-gate break;
33380Sstevel@tonic-gate
33390Sstevel@tonic-gate /*
33400Sstevel@tonic-gate * SCMD_READ/SCMD_WRITE are converted to G1 cmds
33410Sstevel@tonic-gate * (as ATAPI devices don't recognize G0 commands)
33420Sstevel@tonic-gate *
33430Sstevel@tonic-gate * SCMD_READ_LONG/SCMD_WRITE_LONG are handled in
33440Sstevel@tonic-gate * scsa2usb_rw_transport() along with other commands.
33450Sstevel@tonic-gate *
33460Sstevel@tonic-gate * USB Host Controllers cannot handle large (read/write)
33470Sstevel@tonic-gate * xfers. We split the large request to chunks of
33480Sstevel@tonic-gate * smaller ones to meet the HCD limitations.
33490Sstevel@tonic-gate */
33500Sstevel@tonic-gate case SCMD_READ:
33510Sstevel@tonic-gate case SCMD_WRITE:
33520Sstevel@tonic-gate case SCMD_READ_G1:
33530Sstevel@tonic-gate case SCMD_WRITE_G1:
33540Sstevel@tonic-gate case SCMD_READ_G5:
33550Sstevel@tonic-gate case SCMD_WRITE_G5:
33560Sstevel@tonic-gate case SCMD_READ_LONG:
33570Sstevel@tonic-gate case SCMD_WRITE_LONG:
33580Sstevel@tonic-gate case SCMD_READ_CD:
33590Sstevel@tonic-gate switch (scsa2usbp->
33600Sstevel@tonic-gate scsa2usb_lun_inquiry[pkt->pkt_address.a_lun].
33610Sstevel@tonic-gate inq_dtype & DTYPE_MASK) {
33620Sstevel@tonic-gate case DTYPE_DIRECT:
33630Sstevel@tonic-gate case DTYPE_RODIRECT:
33640Sstevel@tonic-gate case DTYPE_OPTICAL:
33650Sstevel@tonic-gate return (scsa2usb_rw_transport(
33664700Sfb209375 scsa2usbp, pkt));
33670Sstevel@tonic-gate default:
33680Sstevel@tonic-gate bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
33690Sstevel@tonic-gate if (cmd->cmd_bp) {
33700Sstevel@tonic-gate cmd->cmd_dir =
33710Sstevel@tonic-gate (cmd->cmd_bp->b_flags & B_READ) ?
33720Sstevel@tonic-gate CBW_DIR_IN : CBW_DIR_OUT;
33730Sstevel@tonic-gate cmd->cmd_xfercount =
33740Sstevel@tonic-gate cmd->cmd_bp->b_bcount;
33750Sstevel@tonic-gate }
33760Sstevel@tonic-gate break;
33770Sstevel@tonic-gate }
33780Sstevel@tonic-gate break;
33790Sstevel@tonic-gate
33800Sstevel@tonic-gate case SCMD_REQUEST_SENSE:
33810Sstevel@tonic-gate cmd->cmd_dir = CBW_DIR_IN;
33820Sstevel@tonic-gate cmd->cmd_xfercount = pkt->pkt_cdbp[4];
33830Sstevel@tonic-gate cmd->cmd_cdb[SCSA2USB_LBA_2] = pkt->pkt_cdbp[4];
33840Sstevel@tonic-gate cmd->cmd_actual_len = CDB_GROUP0;
33850Sstevel@tonic-gate break;
33860Sstevel@tonic-gate
33870Sstevel@tonic-gate case SCMD_DOORLOCK:
33880Sstevel@tonic-gate case SCMD_START_STOP:
33890Sstevel@tonic-gate case SCMD_TEST_UNIT_READY:
33900Sstevel@tonic-gate bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
33910Sstevel@tonic-gate break;
33920Sstevel@tonic-gate
33930Sstevel@tonic-gate /*
33940Sstevel@tonic-gate * Needed by zip protocol to reset the device
33950Sstevel@tonic-gate */
33960Sstevel@tonic-gate case SCMD_SDIAG:
33970Sstevel@tonic-gate case SCMD_REZERO_UNIT:
33980Sstevel@tonic-gate bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
33990Sstevel@tonic-gate cmd->cmd_actual_len = CDB_GROUP1;
34000Sstevel@tonic-gate break;
34010Sstevel@tonic-gate
34020Sstevel@tonic-gate case SCMD_WRITE_VERIFY:
34030Sstevel@tonic-gate bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
34040Sstevel@tonic-gate cmd->cmd_dir = CBW_DIR_OUT;
34050Sstevel@tonic-gate cmd->cmd_xfercount = (pkt->pkt_cdbp[7] << 8) | pkt->pkt_cdbp[8];
34060Sstevel@tonic-gate cmd->cmd_actual_len = CDB_GROUP1;
34070Sstevel@tonic-gate break;
34080Sstevel@tonic-gate
34090Sstevel@tonic-gate /*
34100Sstevel@tonic-gate * Next command does not have a SCSI equivalent as
34110Sstevel@tonic-gate * it is vendor specific.
34120Sstevel@tonic-gate * It was listed in the vendor's ATAPI Zip specs.
34130Sstevel@tonic-gate */
34140Sstevel@tonic-gate case SCMD_READ_FORMAT_CAP:
34150Sstevel@tonic-gate bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
34160Sstevel@tonic-gate cmd->cmd_dir = CBW_DIR_IN;
34170Sstevel@tonic-gate cmd->cmd_xfercount = (pkt->pkt_cdbp[7] << 8) | pkt->pkt_cdbp[8];
34180Sstevel@tonic-gate cmd->cmd_actual_len = CDB_GROUP1;
34190Sstevel@tonic-gate break;
34200Sstevel@tonic-gate case IOMEGA_CMD_CARTRIDGE_PROTECT:
34210Sstevel@tonic-gate cmd->cmd_dir = CBW_DIR_OUT;
34220Sstevel@tonic-gate cmd->cmd_cdb[SCSA2USB_LBA_2] = pkt->pkt_cdbp[4];
34230Sstevel@tonic-gate cmd->cmd_cdb[SCSA2USB_LBA_2] &= ~1; /* Make it even */
34240Sstevel@tonic-gate cmd->cmd_cdb[SCSA2USB_LUN] = pkt->pkt_cdbp[1];
34250Sstevel@tonic-gate cmd->cmd_actual_len = CDB_GROUP0;
34260Sstevel@tonic-gate cmd->cmd_xfercount = pkt->pkt_cdbp[4]; /* Length of password */
34270Sstevel@tonic-gate break;
34280Sstevel@tonic-gate
34292057Scg149915 /*
34302057Scg149915 * Do not convert SCMD_MODE_SENSE/SELECT to G1 cmds because
34312057Scg149915 * the mode header is different as well. USB devices don't
34322057Scg149915 * support 0x03 & 0x04 mode pages, which are already obsoleted
34332057Scg149915 * by SPC-2 specification.
34342057Scg149915 */
34352057Scg149915 case SCMD_MODE_SENSE:
34362057Scg149915 case SCMD_MODE_SELECT:
343710018SGuoqing.Zhu@Sun.COM if (((pkt->pkt_cdbp[2] & SD_MODE_SENSE_PAGE_MASK)
343810018SGuoqing.Zhu@Sun.COM == SD_MODE_SENSE_PAGE3_CODE) ||
343910018SGuoqing.Zhu@Sun.COM ((pkt->pkt_cdbp[2] & SD_MODE_SENSE_PAGE_MASK)
344010018SGuoqing.Zhu@Sun.COM == SD_MODE_SENSE_PAGE4_CODE)) {
34412057Scg149915 if (cmd->cmd_bp) {
34422057Scg149915 cmd->cmd_pkt->pkt_resid = cmd->cmd_bp->b_bcount;
34432057Scg149915 }
34442057Scg149915 scsa2usb_force_invalid_request(scsa2usbp, cmd);
34452057Scg149915 return (SCSA2USB_JUST_ACCEPT);
34462057Scg149915 }
34472057Scg149915 /* FALLTHROUGH */
34482057Scg149915
34490Sstevel@tonic-gate default:
34500Sstevel@tonic-gate /*
34510Sstevel@tonic-gate * an unknown command may be a uscsi cmd which we
34520Sstevel@tonic-gate * should let go thru without mapping
34530Sstevel@tonic-gate */
34540Sstevel@tonic-gate bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
34550Sstevel@tonic-gate if (cmd->cmd_bp) {
34560Sstevel@tonic-gate cmd->cmd_dir = (cmd->cmd_bp->b_flags & B_READ) ?
34574700Sfb209375 CBW_DIR_IN : CBW_DIR_OUT;
34580Sstevel@tonic-gate cmd->cmd_xfercount = cmd->cmd_bp->b_bcount;
34590Sstevel@tonic-gate }
34600Sstevel@tonic-gate
34610Sstevel@tonic-gate break;
34620Sstevel@tonic-gate } /* end of switch */
34630Sstevel@tonic-gate
34640Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
34650Sstevel@tonic-gate "scsa2usb_handle_scsi_cmd_sub_class: opcode = 0x%x count = 0x%lx",
34660Sstevel@tonic-gate pkt->pkt_cdbp[SCSA2USB_OPCODE], cmd->cmd_xfercount);
34670Sstevel@tonic-gate
34680Sstevel@tonic-gate cmd->cmd_total_xfercount = cmd->cmd_xfercount;
34690Sstevel@tonic-gate
34700Sstevel@tonic-gate return (SCSA2USB_TRANSPORT);
34710Sstevel@tonic-gate }
34720Sstevel@tonic-gate
34730Sstevel@tonic-gate
34740Sstevel@tonic-gate /*
34752506Ssl147100 * scsa2usb_do_tur is performed before READ CAPACITY command is issued.
34762506Ssl147100 * It returns media status, 0 for media ready, -1 for media not ready
34772506Ssl147100 * or other errors.
34782506Ssl147100 */
34792506Ssl147100 static int
scsa2usb_do_tur(scsa2usb_state_t * scsa2usbp,struct scsi_address * ap)34802506Ssl147100 scsa2usb_do_tur(scsa2usb_state_t *scsa2usbp, struct scsi_address *ap)
34812506Ssl147100 {
34822506Ssl147100 struct scsi_pkt *pkt;
34832506Ssl147100 scsa2usb_cmd_t *turcmd;
34842506Ssl147100 int rval = -1;
34852506Ssl147100
34862506Ssl147100 USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
34872506Ssl147100 "scsa2usb_do_tur:");
34882506Ssl147100
34892506Ssl147100 ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
34902506Ssl147100
34912506Ssl147100 mutex_exit(&scsa2usbp->scsa2usb_mutex);
34922506Ssl147100 if ((pkt = scsi_init_pkt(ap, NULL, NULL, CDB_GROUP0, 1,
34932506Ssl147100 PKT_PRIV_LEN, PKT_CONSISTENT, SLEEP_FUNC, NULL)) == NULL) {
34942506Ssl147100 mutex_enter(&scsa2usbp->scsa2usb_mutex);
34952506Ssl147100 USB_DPRINTF_L2(DPRINT_MASK_SCSA,
34962506Ssl147100 scsa2usbp->scsa2usb_log_handle,
34972506Ssl147100 "scsa2usb_do_tur: init pkt failed");
34982506Ssl147100
34992506Ssl147100 return (rval);
35002506Ssl147100 }
35012506Ssl147100
35022506Ssl147100 RQ_MAKECOM_G0(pkt, FLAG_HEAD | FLAG_NODISCON,
35032506Ssl147100 (char)SCMD_TEST_UNIT_READY, 0, 0);
35042506Ssl147100
35052506Ssl147100 pkt->pkt_comp = NULL;
35062506Ssl147100 pkt->pkt_time = PKT_DEFAULT_TIMEOUT;
35072506Ssl147100 turcmd = PKT2CMD(pkt);
35082506Ssl147100
35092506Ssl147100 mutex_enter(&scsa2usbp->scsa2usb_mutex);
35102506Ssl147100 scsa2usb_prepare_pkt(scsa2usbp, turcmd->cmd_pkt);
35112506Ssl147100
35122506Ssl147100 if (scsa2usb_cmd_transport(scsa2usbp, turcmd) != TRAN_ACCEPT) {
35132506Ssl147100 USB_DPRINTF_L2(DPRINT_MASK_SCSA,
35142506Ssl147100 scsa2usbp->scsa2usb_log_handle,
35152506Ssl147100 "scsa2usb_do_tur: cmd transport failed, "
35162506Ssl147100 "pkt_reason=0x%x", turcmd->cmd_pkt->pkt_reason);
35172506Ssl147100 } else if (*(turcmd->cmd_pkt->pkt_scbp) != STATUS_GOOD) {
35182506Ssl147100 /*
35192506Ssl147100 * Theoretically, the sense data should be retrieved and
35202506Ssl147100 * sense key be checked when check condition happens. If
35212506Ssl147100 * the sense key is UNIT ATTENTION, TEST UNIT READY cmd
35222506Ssl147100 * needs to be sent again to clear the UNIT ATTENTION and
35232506Ssl147100 * another TUR to be sent to get the real media status.
35242506Ssl147100 * But the AMI virtual floppy device simply cannot recover
35252506Ssl147100 * from UNIT ATTENTION by re-sending a TUR cmd, so it
35262506Ssl147100 * doesn't make any difference whether to check sense key
35272506Ssl147100 * or not. Just ignore sense key checking here and assume
35282506Ssl147100 * the device is NOT READY.
35292506Ssl147100 */
35302506Ssl147100 USB_DPRINTF_L2(DPRINT_MASK_SCSA,
35312506Ssl147100 scsa2usbp->scsa2usb_log_handle,
35322506Ssl147100 "scsa2usb_do_tur: media not ready");
35332506Ssl147100 } else {
35342506Ssl147100 rval = 0;
35352506Ssl147100 }
35362506Ssl147100
35372506Ssl147100 mutex_exit(&scsa2usbp->scsa2usb_mutex);
35382506Ssl147100 scsi_destroy_pkt(pkt);
35392506Ssl147100 mutex_enter(&scsa2usbp->scsa2usb_mutex);
35402506Ssl147100
35412506Ssl147100 return (rval);
35422506Ssl147100 }
35432506Ssl147100
35442506Ssl147100
35452506Ssl147100 /*
35460Sstevel@tonic-gate * scsa2usb_check_ufi_blacklist_attrs:
35470Sstevel@tonic-gate * validate "scsa2usb_blacklist_attrs" (see scsa2usb.h)
35480Sstevel@tonic-gate * if blacklisted attrs match accept the request
35490Sstevel@tonic-gate * attributes checked are:-
35500Sstevel@tonic-gate * SCSA2USB_ATTRS_GET_CONF
35510Sstevel@tonic-gate * SCSA2USB_ATTRS_GET_PERF
35520Sstevel@tonic-gate * SCSA2USB_ATTRS_GET_START_STOP
35530Sstevel@tonic-gate */
35540Sstevel@tonic-gate static int
scsa2usb_check_ufi_blacklist_attrs(scsa2usb_state_t * scsa2usbp,uchar_t opcode,scsa2usb_cmd_t * cmd)35550Sstevel@tonic-gate scsa2usb_check_ufi_blacklist_attrs(scsa2usb_state_t *scsa2usbp, uchar_t opcode,
35560Sstevel@tonic-gate scsa2usb_cmd_t *cmd)
35570Sstevel@tonic-gate {
35580Sstevel@tonic-gate int rval = SCSA2USB_TRANSPORT;
35590Sstevel@tonic-gate
35600Sstevel@tonic-gate ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
35610Sstevel@tonic-gate
35620Sstevel@tonic-gate switch (opcode) {
35630Sstevel@tonic-gate case SCMD_PRIN:
35640Sstevel@tonic-gate case SCMD_PROUT:
35650Sstevel@tonic-gate rval = SCSA2USB_JUST_ACCEPT;
35660Sstevel@tonic-gate break;
35670Sstevel@tonic-gate case SCMD_MODE_SENSE:
35680Sstevel@tonic-gate case SCMD_MODE_SELECT:
35690Sstevel@tonic-gate if (cmd->cmd_bp) {
35700Sstevel@tonic-gate cmd->cmd_pkt->pkt_resid = cmd->cmd_bp->b_bcount;
35710Sstevel@tonic-gate }
35720Sstevel@tonic-gate scsa2usb_force_invalid_request(scsa2usbp, cmd);
35730Sstevel@tonic-gate rval = SCSA2USB_JUST_ACCEPT;
35740Sstevel@tonic-gate break;
35750Sstevel@tonic-gate case SCMD_GET_CONFIGURATION:
35760Sstevel@tonic-gate if (!(scsa2usbp->scsa2usb_attrs & SCSA2USB_ATTRS_GET_CONF)) {
35770Sstevel@tonic-gate rval = SCSA2USB_JUST_ACCEPT;
35780Sstevel@tonic-gate }
35790Sstevel@tonic-gate break;
35800Sstevel@tonic-gate case SCMD_GET_PERFORMANCE:
35810Sstevel@tonic-gate if (!(scsa2usbp->scsa2usb_attrs & SCSA2USB_ATTRS_GET_PERF)) {
35820Sstevel@tonic-gate rval = SCSA2USB_JUST_ACCEPT;
35830Sstevel@tonic-gate }
35840Sstevel@tonic-gate break;
35850Sstevel@tonic-gate case SCMD_START_STOP:
35860Sstevel@tonic-gate /*
35870Sstevel@tonic-gate * some CB/CBI devices don't have mechanics that spin the
35880Sstevel@tonic-gate * media up and down. So, it doesn't make much sense
35890Sstevel@tonic-gate * to issue this cmd to those devices.
35900Sstevel@tonic-gate */
35910Sstevel@tonic-gate if (!(scsa2usbp->scsa2usb_attrs & SCSA2USB_ATTRS_START_STOP)) {
35920Sstevel@tonic-gate rval = SCSA2USB_JUST_ACCEPT;
35930Sstevel@tonic-gate }
35940Sstevel@tonic-gate break;
35952506Ssl147100 case SCMD_READ_CAPACITY:
35962506Ssl147100 /*
35972506Ssl147100 * Some devices don't support READ CAPACITY command
35982506Ssl147100 * when media is not ready. Need to check media status
35992506Ssl147100 * before issuing the cmd to such device.
36002506Ssl147100 */
36012506Ssl147100 if (!(scsa2usbp->scsa2usb_attrs &
36022506Ssl147100 SCSA2USB_ATTRS_NO_MEDIA_CHECK)) {
36032506Ssl147100 struct scsi_pkt *pkt = cmd->cmd_pkt;
36042506Ssl147100
36052506Ssl147100 ASSERT(scsa2usbp->scsa2usb_cur_pkt == pkt);
36062506Ssl147100 scsa2usbp->scsa2usb_cur_pkt = NULL;
36072506Ssl147100
36082506Ssl147100 if (scsa2usb_do_tur(scsa2usbp,
36092506Ssl147100 &pkt->pkt_address) != 0) {
36102506Ssl147100 /* media not ready, force cmd invalid */
36112506Ssl147100 if (cmd->cmd_bp) {
36122506Ssl147100 cmd->cmd_pkt->pkt_resid =
36132506Ssl147100 cmd->cmd_bp->b_bcount;
36142506Ssl147100 }
36152506Ssl147100 scsa2usb_force_invalid_request(scsa2usbp, cmd);
36162506Ssl147100 rval = SCSA2USB_JUST_ACCEPT;
36172506Ssl147100 }
36182506Ssl147100
36192506Ssl147100 scsa2usbp->scsa2usb_cur_pkt = pkt;
36202506Ssl147100 }
36212506Ssl147100 break;
36220Sstevel@tonic-gate default:
36230Sstevel@tonic-gate break;
36240Sstevel@tonic-gate }
36250Sstevel@tonic-gate
36260Sstevel@tonic-gate return (rval);
36270Sstevel@tonic-gate }
36280Sstevel@tonic-gate
36290Sstevel@tonic-gate
36300Sstevel@tonic-gate /*
36310Sstevel@tonic-gate * scsa2usb_handle_ufi_subclass_cmd:
36320Sstevel@tonic-gate * prepare a UFI cmd
36330Sstevel@tonic-gate * returns SCSA2USB_TRANSPORT, SCSA2USB_REJECT
36340Sstevel@tonic-gate */
36350Sstevel@tonic-gate int
scsa2usb_handle_ufi_subclass_cmd(scsa2usb_state_t * scsa2usbp,scsa2usb_cmd_t * cmd,struct scsi_pkt * pkt)36360Sstevel@tonic-gate scsa2usb_handle_ufi_subclass_cmd(scsa2usb_state_t *scsa2usbp,
36370Sstevel@tonic-gate scsa2usb_cmd_t *cmd, struct scsi_pkt *pkt)
36380Sstevel@tonic-gate {
36390Sstevel@tonic-gate uchar_t opcode = pkt->pkt_cdbp[0];
36400Sstevel@tonic-gate
36410Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
36420Sstevel@tonic-gate "scsa2usb_handle_ufi_subclass_cmd: cmd = 0x%p pkt = 0x%p",
36436898Sfb209375 (void *)cmd, (void *)pkt);
36440Sstevel@tonic-gate
36450Sstevel@tonic-gate ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
36460Sstevel@tonic-gate
36470Sstevel@tonic-gate bzero(&cmd->cmd_cdb, SCSI_CDB_SIZE);
36480Sstevel@tonic-gate cmd->cmd_cdb[SCSA2USB_OPCODE] = opcode; /* Set the opcode */
36490Sstevel@tonic-gate cmd->cmd_cdb[SCSA2USB_LUN] = pkt->pkt_cdbp[1];
36500Sstevel@tonic-gate
36510Sstevel@tonic-gate /*
36520Sstevel@tonic-gate * decode and convert the packet if necessary
36530Sstevel@tonic-gate * for most cmds, we can bcopy the cdb
36540Sstevel@tonic-gate */
36550Sstevel@tonic-gate switch (opcode) {
36560Sstevel@tonic-gate case SCMD_FORMAT:
36570Sstevel@tonic-gate /* if parameter list is specified */
36580Sstevel@tonic-gate if (pkt->pkt_cdbp[1] & 0x10) {
36590Sstevel@tonic-gate cmd->cmd_xfercount =
36604700Sfb209375 (pkt->pkt_cdbp[7] << 8) | pkt->pkt_cdbp[8];
36610Sstevel@tonic-gate cmd->cmd_dir = USB_EP_DIR_OUT;
36620Sstevel@tonic-gate cmd->cmd_actual_len = CDB_GROUP5;
36630Sstevel@tonic-gate }
36640Sstevel@tonic-gate bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
36650Sstevel@tonic-gate break;
36660Sstevel@tonic-gate case SCMD_INQUIRY:
36670Sstevel@tonic-gate cmd->cmd_dir = USB_EP_DIR_IN;
36680Sstevel@tonic-gate cmd->cmd_actual_len = CDB_GROUP0;
36690Sstevel@tonic-gate cmd->cmd_cdb[SCSA2USB_LBA_0] = pkt->pkt_cdbp[2];
36700Sstevel@tonic-gate cmd->cmd_cdb[SCSA2USB_LBA_2] = cmd->cmd_xfercount =
36710Sstevel@tonic-gate min(SCSA2USB_MAX_INQ_LEN,
36720Sstevel@tonic-gate cmd->cmd_bp ? cmd->cmd_bp->b_bcount : 0);
36730Sstevel@tonic-gate break;
36740Sstevel@tonic-gate case SCMD_READ_CAPACITY:
36750Sstevel@tonic-gate cmd->cmd_dir = USB_EP_DIR_IN;
36760Sstevel@tonic-gate bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
36770Sstevel@tonic-gate cmd->cmd_xfercount = sizeof (scsa2usb_read_cap_t);
36780Sstevel@tonic-gate break;
36790Sstevel@tonic-gate case SCMD_REQUEST_SENSE:
36800Sstevel@tonic-gate cmd->cmd_dir = USB_EP_DIR_IN;
36810Sstevel@tonic-gate cmd->cmd_xfercount = pkt->pkt_cdbp[4];
36820Sstevel@tonic-gate cmd->cmd_cdb[SCSA2USB_LBA_2] = pkt->pkt_cdbp[4];
36830Sstevel@tonic-gate cmd->cmd_actual_len = CDB_GROUP0;
36840Sstevel@tonic-gate break;
36850Sstevel@tonic-gate
36860Sstevel@tonic-gate /*
36870Sstevel@tonic-gate * do not convert SCMD_MODE_SENSE/SELECT because the
36880Sstevel@tonic-gate * mode header is different as well
36890Sstevel@tonic-gate */
36900Sstevel@tonic-gate
36910Sstevel@tonic-gate /*
36920Sstevel@tonic-gate * see usb_bulkonly.c for comments on the next set of commands
36930Sstevel@tonic-gate */
36940Sstevel@tonic-gate case SCMD_READ:
36950Sstevel@tonic-gate case SCMD_WRITE:
36960Sstevel@tonic-gate case SCMD_READ_G1:
36970Sstevel@tonic-gate case SCMD_WRITE_G1:
36980Sstevel@tonic-gate case SCMD_READ_G5:
36990Sstevel@tonic-gate case SCMD_WRITE_G5:
37000Sstevel@tonic-gate case SCMD_READ_LONG:
37010Sstevel@tonic-gate case SCMD_WRITE_LONG:
37020Sstevel@tonic-gate case SCMD_READ_CD:
37030Sstevel@tonic-gate
37040Sstevel@tonic-gate return (scsa2usb_rw_transport(scsa2usbp, pkt));
37050Sstevel@tonic-gate
37060Sstevel@tonic-gate case SCMD_TEST_UNIT_READY:
37070Sstevel@tonic-gate /*
37080Sstevel@tonic-gate * Some CB/CBI devices may not support TUR.
37090Sstevel@tonic-gate */
37100Sstevel@tonic-gate bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
37110Sstevel@tonic-gate break;
37120Sstevel@tonic-gate case SCMD_READ_FORMAT_CAP:
37130Sstevel@tonic-gate bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
37140Sstevel@tonic-gate cmd->cmd_dir = USB_EP_DIR_IN;
37150Sstevel@tonic-gate cmd->cmd_actual_len = CDB_GROUP1;
37160Sstevel@tonic-gate cmd->cmd_xfercount = (pkt->pkt_cdbp[7] << 8) | pkt->pkt_cdbp[8];
37170Sstevel@tonic-gate break;
37180Sstevel@tonic-gate case SCMD_WRITE_VERIFY:
37190Sstevel@tonic-gate bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
37200Sstevel@tonic-gate cmd->cmd_dir = USB_EP_DIR_OUT;
37210Sstevel@tonic-gate cmd->cmd_actual_len = CDB_GROUP1;
37220Sstevel@tonic-gate cmd->cmd_xfercount = (pkt->pkt_cdbp[7] << 8) | pkt->pkt_cdbp[8];
37230Sstevel@tonic-gate break;
37240Sstevel@tonic-gate case SCMD_START_STOP:
37250Sstevel@tonic-gate /* A larger timeout is needed for 'flaky' CD-RW devices */
37260Sstevel@tonic-gate if (!(scsa2usbp->scsa2usb_attrs & SCSA2USB_ATTRS_BIG_TIMEOUT)) {
37270Sstevel@tonic-gate cmd->cmd_timeout = max(cmd->cmd_timeout,
37284700Sfb209375 20 * SCSA2USB_BULK_PIPE_TIMEOUT);
37290Sstevel@tonic-gate }
37300Sstevel@tonic-gate /* FALLTHRU */
37310Sstevel@tonic-gate default:
37320Sstevel@tonic-gate /*
37330Sstevel@tonic-gate * all other commands don't need special mapping
37340Sstevel@tonic-gate */
37350Sstevel@tonic-gate bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
37360Sstevel@tonic-gate if (cmd->cmd_bp) {
37370Sstevel@tonic-gate cmd->cmd_dir = (cmd->cmd_bp->b_flags & B_READ) ?
37384700Sfb209375 CBW_DIR_IN : CBW_DIR_OUT;
37390Sstevel@tonic-gate cmd->cmd_xfercount = cmd->cmd_bp->b_bcount;
37400Sstevel@tonic-gate }
37410Sstevel@tonic-gate break;
37420Sstevel@tonic-gate
37430Sstevel@tonic-gate } /* end of switch */
37440Sstevel@tonic-gate
37450Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
37460Sstevel@tonic-gate "scsa2usb_handle_ufi_subclass_cmd: opcode = 0x%x count = 0x%lx",
37470Sstevel@tonic-gate opcode, cmd->cmd_xfercount);
37480Sstevel@tonic-gate
37490Sstevel@tonic-gate cmd->cmd_total_xfercount = cmd->cmd_xfercount;
37500Sstevel@tonic-gate
37510Sstevel@tonic-gate return (SCSA2USB_TRANSPORT);
37520Sstevel@tonic-gate }
37530Sstevel@tonic-gate
37540Sstevel@tonic-gate
37550Sstevel@tonic-gate /*
37560Sstevel@tonic-gate * scsa2usb_rw_transport:
37570Sstevel@tonic-gate * Handle splitting READ and WRITE requests to the
37580Sstevel@tonic-gate * device to a size that the host controller allows.
37590Sstevel@tonic-gate *
37600Sstevel@tonic-gate * returns TRAN_* values and not USB_SUCCESS/FAILURE
37610Sstevel@tonic-gate *
37620Sstevel@tonic-gate * To support CD-R/CD-RW/DVD media, we need to support a
37630Sstevel@tonic-gate * variety of block sizes for the different types of CD
37640Sstevel@tonic-gate * data (audio, data, video, CD-XA, yellowbook, redbook etc.)
37650Sstevel@tonic-gate *
37660Sstevel@tonic-gate * Some of the block sizes used are:- 512, 1k, 2k, 2056, 2336
37670Sstevel@tonic-gate * 2340, 2352, 2368, 2448, 2646, 2647 etc.
37680Sstevel@tonic-gate *
37690Sstevel@tonic-gate * NOTE: the driver could be entertaining a SCSI CDB that uses
37700Sstevel@tonic-gate * any of the above listed block sizes at a given time, and a
37710Sstevel@tonic-gate * totally different block size at any other given time for a
37720Sstevel@tonic-gate * different CDB.
37730Sstevel@tonic-gate *
37740Sstevel@tonic-gate * We need to compute block size every time and figure out
37750Sstevel@tonic-gate * matching LBA and LEN accordingly.
37760Sstevel@tonic-gate *
37770Sstevel@tonic-gate * Also UHCI has a limitation that it can only xfer 32k at a
37780Sstevel@tonic-gate * given time. So, with "odd" sized blocks and a limitation of
37790Sstevel@tonic-gate * how much we can xfer per shot, we need to compute xfer_count
37800Sstevel@tonic-gate * as well each time.
37810Sstevel@tonic-gate *
37820Sstevel@tonic-gate * The same computation is also done in the function
37830Sstevel@tonic-gate * scsa2usb_setup_next_xfer(). To save computing block_size in
37840Sstevel@tonic-gate * this function, I am saving block_size in "cmd" now.
37850Sstevel@tonic-gate */
37860Sstevel@tonic-gate int
scsa2usb_rw_transport(scsa2usb_state_t * scsa2usbp,struct scsi_pkt * pkt)37870Sstevel@tonic-gate scsa2usb_rw_transport(scsa2usb_state_t *scsa2usbp, struct scsi_pkt *pkt)
37880Sstevel@tonic-gate {
37890Sstevel@tonic-gate scsa2usb_cmd_t *cmd = PKT2CMD(pkt);
37900Sstevel@tonic-gate int lba, dir, opcode;
37910Sstevel@tonic-gate struct buf *bp = cmd->cmd_bp;
37920Sstevel@tonic-gate size_t len, xfer_count;
37930Sstevel@tonic-gate size_t blk_size; /* calculate the block size to be used */
37940Sstevel@tonic-gate int sz;
37950Sstevel@tonic-gate
37960Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
37970Sstevel@tonic-gate "scsa2usb_rw_transport:");
37980Sstevel@tonic-gate
37990Sstevel@tonic-gate ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
38000Sstevel@tonic-gate
38010Sstevel@tonic-gate opcode = pkt->pkt_cdbp[0];
38020Sstevel@tonic-gate blk_size = scsa2usbp->scsa2usb_lbasize[pkt->pkt_address.a_lun];
38030Sstevel@tonic-gate /* set to default */
38040Sstevel@tonic-gate
38050Sstevel@tonic-gate switch (opcode) {
38060Sstevel@tonic-gate case SCMD_READ:
38070Sstevel@tonic-gate /*
38080Sstevel@tonic-gate * Note that READ/WRITE(6) are not supported by the drive.
38090Sstevel@tonic-gate * convert it into a 10 byte read/write.
38100Sstevel@tonic-gate */
38110Sstevel@tonic-gate lba = SCSA2USB_LBA_6BYTE(pkt);
38120Sstevel@tonic-gate len = SCSA2USB_LEN_6BYTE(pkt);
38130Sstevel@tonic-gate opcode = SCMD_READ_G1; /* Overwrite it w/ byte 10 cmd val */
38140Sstevel@tonic-gate dir = USB_EP_DIR_IN;
38150Sstevel@tonic-gate break;
38160Sstevel@tonic-gate case SCMD_WRITE:
38170Sstevel@tonic-gate lba = SCSA2USB_LBA_6BYTE(pkt);
38180Sstevel@tonic-gate len = SCSA2USB_LEN_6BYTE(pkt);
38190Sstevel@tonic-gate opcode = SCMD_WRITE_G1; /* Overwrite it w/ byte 10 cmd val */
38200Sstevel@tonic-gate dir = USB_EP_DIR_OUT;
38210Sstevel@tonic-gate break;
38220Sstevel@tonic-gate case SCMD_READ_G1:
38230Sstevel@tonic-gate case SCMD_READ_LONG:
38240Sstevel@tonic-gate lba = SCSA2USB_LBA_10BYTE(pkt);
38250Sstevel@tonic-gate len = SCSA2USB_LEN_10BYTE(pkt);
38260Sstevel@tonic-gate dir = USB_EP_DIR_IN;
38270Sstevel@tonic-gate break;
38280Sstevel@tonic-gate case SCMD_WRITE_G1:
38290Sstevel@tonic-gate case SCMD_WRITE_LONG:
38300Sstevel@tonic-gate lba = SCSA2USB_LBA_10BYTE(pkt);
38310Sstevel@tonic-gate len = SCSA2USB_LEN_10BYTE(pkt);
38320Sstevel@tonic-gate dir = USB_EP_DIR_OUT;
38330Sstevel@tonic-gate if (len) {
38340Sstevel@tonic-gate sz = SCSA2USB_CDRW_BLKSZ(bp ? bp->b_bcount : 0, len);
38350Sstevel@tonic-gate if (SCSA2USB_VALID_CDRW_BLKSZ(sz)) {
38360Sstevel@tonic-gate blk_size = sz; /* change it accordingly */
38370Sstevel@tonic-gate }
38380Sstevel@tonic-gate }
38390Sstevel@tonic-gate break;
38400Sstevel@tonic-gate case SCMD_READ_CD:
38410Sstevel@tonic-gate lba = SCSA2USB_LBA_10BYTE(pkt);
38420Sstevel@tonic-gate len = SCSA2USB_LEN_READ_CD(pkt);
38430Sstevel@tonic-gate dir = USB_EP_DIR_IN;
38440Sstevel@tonic-gate
38450Sstevel@tonic-gate /* Figure out the block size */
38460Sstevel@tonic-gate blk_size = scsa2usb_read_cd_blk_size(pkt->pkt_cdbp[1] >> 2);
38470Sstevel@tonic-gate break;
38480Sstevel@tonic-gate case SCMD_READ_G5:
38490Sstevel@tonic-gate lba = SCSA2USB_LBA_12BYTE(pkt);
38500Sstevel@tonic-gate len = SCSA2USB_LEN_12BYTE(pkt);
38510Sstevel@tonic-gate dir = USB_EP_DIR_IN;
38520Sstevel@tonic-gate break;
38530Sstevel@tonic-gate case SCMD_WRITE_G5:
38540Sstevel@tonic-gate lba = SCSA2USB_LBA_12BYTE(pkt);
38550Sstevel@tonic-gate len = SCSA2USB_LEN_12BYTE(pkt);
38560Sstevel@tonic-gate dir = USB_EP_DIR_OUT;
38570Sstevel@tonic-gate break;
38580Sstevel@tonic-gate }
38590Sstevel@tonic-gate
38600Sstevel@tonic-gate cmd->cmd_total_xfercount = xfer_count = len * blk_size;
38610Sstevel@tonic-gate
38620Sstevel@tonic-gate /* reduce xfer count if necessary */
38630Sstevel@tonic-gate if (blk_size &&
38640Sstevel@tonic-gate (xfer_count > scsa2usbp->scsa2usb_max_bulk_xfer_size)) {
38650Sstevel@tonic-gate /*
38660Sstevel@tonic-gate * For CD-RW devices reduce the xfer count based
38670Sstevel@tonic-gate * on the block size used by these devices. The
38680Sstevel@tonic-gate * block size could change for READ_CD and WRITE
38690Sstevel@tonic-gate * opcodes.
38700Sstevel@tonic-gate *
38710Sstevel@tonic-gate * Also as UHCI allows a max xfer of 32k at a time;
38720Sstevel@tonic-gate * compute the xfer_count based on the new block_size.
38730Sstevel@tonic-gate *
38740Sstevel@tonic-gate * The len part of the cdb changes as a result of that.
38750Sstevel@tonic-gate */
38760Sstevel@tonic-gate if (SCSA2USB_VALID_CDRW_BLKSZ(blk_size)) {
38770Sstevel@tonic-gate xfer_count = ((scsa2usbp->scsa2usb_max_bulk_xfer_size/
38784700Sfb209375 blk_size) * blk_size);
38790Sstevel@tonic-gate len = xfer_count/blk_size;
38800Sstevel@tonic-gate xfer_count = blk_size * len;
38810Sstevel@tonic-gate } else {
38820Sstevel@tonic-gate xfer_count = scsa2usbp->scsa2usb_max_bulk_xfer_size;
38830Sstevel@tonic-gate len = xfer_count/blk_size;
38840Sstevel@tonic-gate }
38850Sstevel@tonic-gate }
38860Sstevel@tonic-gate
38870Sstevel@tonic-gate cmd->cmd_xfercount = xfer_count;
38880Sstevel@tonic-gate cmd->cmd_dir = (uchar_t)dir;
38897492SZhigang.Lu@Sun.COM cmd->cmd_blksize = (int)blk_size;
38900Sstevel@tonic-gate
38910Sstevel@tonic-gate /*
38920Sstevel@tonic-gate * Having figure out the 'partial' xfer len based on he
38930Sstevel@tonic-gate * block size; fill it in to the cmd->cmd_cdb
38940Sstevel@tonic-gate */
38950Sstevel@tonic-gate cmd->cmd_cdb[SCSA2USB_OPCODE] = (uchar_t)opcode;
38960Sstevel@tonic-gate switch (opcode) {
38970Sstevel@tonic-gate case SCMD_READ_CD:
38980Sstevel@tonic-gate bcopy(pkt->pkt_cdbp, &cmd->cmd_cdb, cmd->cmd_cdblen);
38990Sstevel@tonic-gate scsa2usb_fill_up_ReadCD_cdb_len(cmd, len, CDB_GROUP5);
39000Sstevel@tonic-gate break;
39010Sstevel@tonic-gate case SCMD_WRITE_G5:
39020Sstevel@tonic-gate case SCMD_READ_G5:
39030Sstevel@tonic-gate scsa2usb_fill_up_12byte_cdb_len(cmd, len, CDB_GROUP5);
39040Sstevel@tonic-gate break;
39050Sstevel@tonic-gate default:
39060Sstevel@tonic-gate scsa2usb_fill_up_cdb_len(cmd, len);
39070Sstevel@tonic-gate cmd->cmd_actual_len = CDB_GROUP1;
39080Sstevel@tonic-gate break;
39090Sstevel@tonic-gate }
39100Sstevel@tonic-gate
39110Sstevel@tonic-gate scsa2usb_fill_up_cdb_lba(cmd, lba);
39120Sstevel@tonic-gate
39130Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
39140Sstevel@tonic-gate "bcount=0x%lx lba=0x%x len=0x%lx xfercount=0x%lx total=0x%lx",
39150Sstevel@tonic-gate bp ? bp->b_bcount : 0, lba, len, cmd->cmd_xfercount,
39160Sstevel@tonic-gate cmd->cmd_total_xfercount);
39170Sstevel@tonic-gate
39180Sstevel@tonic-gate /* Set the timeout value as per command request */
39190Sstevel@tonic-gate if ((opcode == SCMD_WRITE_G1) && SCSA2USB_VALID_CDRW_BLKSZ(blk_size)) {
39200Sstevel@tonic-gate /*
39210Sstevel@tonic-gate * We increase the time as CD-RW writes have two things
39220Sstevel@tonic-gate * to do. After writing out the data to the media, a
39230Sstevel@tonic-gate * TOC needs to be filled up at the beginning of the media
39240Sstevel@tonic-gate * This is when the write gets "finalized".
39250Sstevel@tonic-gate * Hence the actual write could take longer than the
39260Sstevel@tonic-gate * value specified in cmd->cmd_timeout.
39270Sstevel@tonic-gate */
39280Sstevel@tonic-gate cmd->cmd_timeout *= 4;
39290Sstevel@tonic-gate
39300Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA,
39310Sstevel@tonic-gate scsa2usbp->scsa2usb_log_handle,
39320Sstevel@tonic-gate "new timeout value = 0x%x", cmd->cmd_timeout);
39330Sstevel@tonic-gate }
39340Sstevel@tonic-gate
39350Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
39360Sstevel@tonic-gate "lba 0x%x len 0x%lx xfercount 0x%lx total 0x%lx",
39370Sstevel@tonic-gate lba, len, cmd->cmd_xfercount, cmd->cmd_total_xfercount);
39380Sstevel@tonic-gate
39390Sstevel@tonic-gate return (SCSA2USB_TRANSPORT);
39400Sstevel@tonic-gate }
39410Sstevel@tonic-gate
39420Sstevel@tonic-gate
39430Sstevel@tonic-gate /*
39440Sstevel@tonic-gate * scsa2usb_setup_next_xfer:
39450Sstevel@tonic-gate * For READs and WRITEs we split up the transfer in terms of
39460Sstevel@tonic-gate * HCD understood units. This function handles the split transfers.
39470Sstevel@tonic-gate *
39480Sstevel@tonic-gate * See comments in the previous function scsa2usb_rw_transport
39490Sstevel@tonic-gate *
39500Sstevel@tonic-gate * The lba computation was being done based on scsa2usb_max_bulk_xfer_size
39510Sstevel@tonic-gate * earlier. With CD-RW devices, the xfer_count and the block_size may
39520Sstevel@tonic-gate * no longer be a multiple of scsa2usb_max_bulk_xfer_size. So compute
39530Sstevel@tonic-gate * xfer_count all over again. Adjust lba, based on the previous requests'
39540Sstevel@tonic-gate * len. Find out the len and add it to cmd->cmd_lba to get the new lba
39550Sstevel@tonic-gate */
39560Sstevel@tonic-gate void
scsa2usb_setup_next_xfer(scsa2usb_state_t * scsa2usbp,scsa2usb_cmd_t * cmd)39570Sstevel@tonic-gate scsa2usb_setup_next_xfer(scsa2usb_state_t *scsa2usbp, scsa2usb_cmd_t *cmd)
39580Sstevel@tonic-gate {
39590Sstevel@tonic-gate int xfer_len = min(scsa2usbp->scsa2usb_max_bulk_xfer_size,
39604700Sfb209375 cmd->cmd_total_xfercount);
39610Sstevel@tonic-gate int cdb_len;
39620Sstevel@tonic-gate size_t blk_size;
39630Sstevel@tonic-gate
39640Sstevel@tonic-gate ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
39650Sstevel@tonic-gate
39660Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
39670Sstevel@tonic-gate "scsa2usb_setup_next_xfer: opcode = 0x%x lba = 0x%x "
39680Sstevel@tonic-gate "total count = 0x%lx", cmd->cmd_cdb[SCSA2USB_OPCODE],
39690Sstevel@tonic-gate cmd->cmd_lba, cmd->cmd_total_xfercount);
39700Sstevel@tonic-gate
39710Sstevel@tonic-gate ASSERT(cmd->cmd_total_xfercount > 0);
39720Sstevel@tonic-gate cmd->cmd_xfercount = xfer_len;
39730Sstevel@tonic-gate blk_size = scsa2usbp->scsa2usb_lbasize[
39744700Sfb209375 cmd->cmd_pkt->pkt_address.a_lun];
39750Sstevel@tonic-gate
39760Sstevel@tonic-gate /*
39770Sstevel@tonic-gate * For CD-RW devices reduce the xfer count based on the
39780Sstevel@tonic-gate * block_size used by these devices. See changes below
39790Sstevel@tonic-gate * where xfer_count is being adjusted.
39800Sstevel@tonic-gate *
39810Sstevel@tonic-gate * Also adjust len/lba based on the block_size and xfer_count.
39820Sstevel@tonic-gate * NOTE: Always calculate lba first, as it based on previous
39830Sstevel@tonic-gate * commands' values.
39840Sstevel@tonic-gate */
39850Sstevel@tonic-gate switch (cmd->cmd_cdb[SCSA2USB_OPCODE]) {
39860Sstevel@tonic-gate case SCMD_READ_CD:
39870Sstevel@tonic-gate /* calculate lba = current_lba + len_of_prev_cmd */
39880Sstevel@tonic-gate cmd->cmd_lba += (cmd->cmd_cdb[6] << 16) +
39890Sstevel@tonic-gate (cmd->cmd_cdb[7] << 8) + cmd->cmd_cdb[8];
39900Sstevel@tonic-gate cdb_len = xfer_len/cmd->cmd_blksize;
39910Sstevel@tonic-gate cmd->cmd_cdb[SCSA2USB_READ_CD_LEN_2] = (uchar_t)cdb_len;
39920Sstevel@tonic-gate /* re-adjust xfer count */
39930Sstevel@tonic-gate cmd->cmd_xfercount = cdb_len * cmd->cmd_blksize;
39940Sstevel@tonic-gate break;
39950Sstevel@tonic-gate case SCMD_WRITE_G5:
39960Sstevel@tonic-gate case SCMD_READ_G5:
39970Sstevel@tonic-gate /* calculate lba = current_lba + len_of_prev_cmd */
39980Sstevel@tonic-gate cmd->cmd_lba += (cmd->cmd_cdb[6] << 24) +
39990Sstevel@tonic-gate (cmd->cmd_cdb[7] << 16) + (cmd->cmd_cdb[8] << 8) +
40000Sstevel@tonic-gate cmd->cmd_cdb[9];
40010Sstevel@tonic-gate if (blk_size) {
40020Sstevel@tonic-gate xfer_len /= blk_size;
40030Sstevel@tonic-gate }
40040Sstevel@tonic-gate scsa2usb_fill_up_12byte_cdb_len(cmd, xfer_len, CDB_GROUP5);
40050Sstevel@tonic-gate break;
40060Sstevel@tonic-gate case SCMD_WRITE_G1:
40070Sstevel@tonic-gate case SCMD_WRITE_LONG:
40080Sstevel@tonic-gate /* calculate lba = current_lba + len_of_prev_cmd */
40090Sstevel@tonic-gate cmd->cmd_lba += (cmd->cmd_cdb[7] << 8) + cmd->cmd_cdb[8];
40100Sstevel@tonic-gate if (SCSA2USB_VALID_CDRW_BLKSZ(cmd->cmd_blksize)) {
40110Sstevel@tonic-gate blk_size = cmd->cmd_blksize;
40120Sstevel@tonic-gate }
40130Sstevel@tonic-gate cdb_len = xfer_len/blk_size;
40140Sstevel@tonic-gate scsa2usb_fill_up_cdb_len(cmd, cdb_len);
40150Sstevel@tonic-gate /* re-adjust xfer count */
40160Sstevel@tonic-gate cmd->cmd_xfercount = cdb_len * blk_size;
40170Sstevel@tonic-gate break;
40180Sstevel@tonic-gate default:
40190Sstevel@tonic-gate if (blk_size) {
40200Sstevel@tonic-gate xfer_len /= blk_size;
40210Sstevel@tonic-gate }
40220Sstevel@tonic-gate scsa2usb_fill_up_cdb_len(cmd, xfer_len);
40230Sstevel@tonic-gate cmd->cmd_lba += scsa2usbp->scsa2usb_max_bulk_xfer_size/blk_size;
40240Sstevel@tonic-gate }
40250Sstevel@tonic-gate
40260Sstevel@tonic-gate /* fill in the lba */
40270Sstevel@tonic-gate scsa2usb_fill_up_cdb_lba(cmd, cmd->cmd_lba);
40280Sstevel@tonic-gate
40290Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
40300Sstevel@tonic-gate "scsa2usb_setup_next_xfer:\n\tlba = 0x%x xfer_len = 0x%x "
40310Sstevel@tonic-gate "xfercount = 0x%lx total = 0x%lx", cmd->cmd_lba, xfer_len,
40320Sstevel@tonic-gate cmd->cmd_xfercount, cmd->cmd_total_xfercount);
40330Sstevel@tonic-gate }
40340Sstevel@tonic-gate
40350Sstevel@tonic-gate
40360Sstevel@tonic-gate /*
40370Sstevel@tonic-gate * take one request from the lun's waitQ and transport it
40380Sstevel@tonic-gate */
40390Sstevel@tonic-gate static void
scsa2usb_transport_request(scsa2usb_state_t * scsa2usbp,uint_t lun)40400Sstevel@tonic-gate scsa2usb_transport_request(scsa2usb_state_t *scsa2usbp, uint_t lun)
40410Sstevel@tonic-gate {
40420Sstevel@tonic-gate int rval;
40430Sstevel@tonic-gate struct scsi_pkt *pkt;
40440Sstevel@tonic-gate struct scsa2usb_cmd *cmd, *arqcmd;
40450Sstevel@tonic-gate
40460Sstevel@tonic-gate if ((cmd = (scsa2usb_cmd_t *)
40470Sstevel@tonic-gate usba_rm_first_pvt_from_list(
40480Sstevel@tonic-gate &scsa2usbp->scsa2usb_waitQ[lun])) == NULL) {
40490Sstevel@tonic-gate
40500Sstevel@tonic-gate return;
40510Sstevel@tonic-gate }
40520Sstevel@tonic-gate pkt = cmd->cmd_pkt;
40530Sstevel@tonic-gate
40540Sstevel@tonic-gate /*
40550Sstevel@tonic-gate * if device has been disconnected, just complete it
40560Sstevel@tonic-gate */
40570Sstevel@tonic-gate if (scsa2usbp->scsa2usb_dev_state == USB_DEV_DISCONNECTED) {
40580Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
40590Sstevel@tonic-gate "device not accessible");
40600Sstevel@tonic-gate pkt->pkt_reason = CMD_DEV_GONE;
40610Sstevel@tonic-gate SCSA2USB_SET_PKT_DO_COMP_STATE(scsa2usbp);
40620Sstevel@tonic-gate scsa2usb_pkt_completion(scsa2usbp, pkt);
40630Sstevel@tonic-gate
40640Sstevel@tonic-gate return;
40650Sstevel@tonic-gate }
40660Sstevel@tonic-gate
40670Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA,
40680Sstevel@tonic-gate scsa2usbp->scsa2usb_log_handle,
40690Sstevel@tonic-gate "scsa2usb_transport_request: cmd=0x%p bp=0x%p addr=0x%p",
40706898Sfb209375 (void *)cmd, (void *)cmd->cmd_bp,
40716898Sfb209375 (void *)(cmd->cmd_bp ? cmd->cmd_bp->b_un.b_addr : NULL));
40720Sstevel@tonic-gate
40730Sstevel@tonic-gate rval = scsa2usb_cmd_transport(scsa2usbp, cmd);
40740Sstevel@tonic-gate
40750Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_SCSA,
40760Sstevel@tonic-gate scsa2usbp->scsa2usb_log_handle,
40770Sstevel@tonic-gate "scsa2usb_transport_request: transport rval = %d",
40780Sstevel@tonic-gate rval);
40790Sstevel@tonic-gate
40800Sstevel@tonic-gate if (scsa2usbp->scsa2usb_cur_pkt == NULL) {
40810Sstevel@tonic-gate
40820Sstevel@tonic-gate return;
40830Sstevel@tonic-gate }
40840Sstevel@tonic-gate
40850Sstevel@tonic-gate ASSERT(pkt == scsa2usbp->scsa2usb_cur_pkt);
40860Sstevel@tonic-gate
40870Sstevel@tonic-gate if (ddi_in_panic()) {
40880Sstevel@tonic-gate pkt->pkt_reason = CMD_CMPLT;
40890Sstevel@tonic-gate scsa2usb_pkt_completion(scsa2usbp, pkt);
40900Sstevel@tonic-gate
40910Sstevel@tonic-gate return;
40920Sstevel@tonic-gate }
40930Sstevel@tonic-gate
40940Sstevel@tonic-gate /*
40950Sstevel@tonic-gate * start an auto-request sense iff
40960Sstevel@tonic-gate * there was a check condition, we have enough
40970Sstevel@tonic-gate * space in the status block, and we have not
40980Sstevel@tonic-gate * faked an auto request sense
40990Sstevel@tonic-gate */
41000Sstevel@tonic-gate if ((*(pkt->pkt_scbp) == STATUS_CHECK) &&
41010Sstevel@tonic-gate (cmd->cmd_scblen >= sizeof (struct scsi_arq_status)) &&
41020Sstevel@tonic-gate ((pkt->pkt_state & STATE_ARQ_DONE) == 0) &&
41030Sstevel@tonic-gate (scsa2usb_create_arq_pkt(scsa2usbp,
41040Sstevel@tonic-gate &pkt->pkt_address) == USB_SUCCESS)) {
41050Sstevel@tonic-gate arqcmd = scsa2usbp->scsa2usb_arq_cmd;
41060Sstevel@tonic-gate
41070Sstevel@tonic-gate /*
41080Sstevel@tonic-gate * copy the timeout from the
41090Sstevel@tonic-gate * original packet
41100Sstevel@tonic-gate * for lack of a better value
41110Sstevel@tonic-gate */
41120Sstevel@tonic-gate arqcmd->cmd_pkt->pkt_time = pkt->pkt_time;
41130Sstevel@tonic-gate scsa2usb_prepare_pkt(scsa2usbp,
41144700Sfb209375 arqcmd->cmd_pkt);
41150Sstevel@tonic-gate
41160Sstevel@tonic-gate scsa2usbp->scsa2usb_cur_pkt = NULL;
41170Sstevel@tonic-gate if (scsa2usb_cmd_transport(
41180Sstevel@tonic-gate scsa2usbp, arqcmd) == TRAN_ACCEPT) {
41190Sstevel@tonic-gate
41200Sstevel@tonic-gate /* finish w/ this packet */
41210Sstevel@tonic-gate scsa2usb_complete_arq_pkt(
41220Sstevel@tonic-gate scsa2usbp, arqcmd->cmd_pkt, cmd,
41230Sstevel@tonic-gate scsa2usbp->scsa2usb_arq_bp);
41240Sstevel@tonic-gate
41250Sstevel@tonic-gate /*
41260Sstevel@tonic-gate * we have valid request sense
41270Sstevel@tonic-gate * data so clear the pkt_reason
41280Sstevel@tonic-gate */
41290Sstevel@tonic-gate pkt->pkt_reason = CMD_CMPLT;
41300Sstevel@tonic-gate }
41310Sstevel@tonic-gate scsa2usbp->scsa2usb_cur_pkt = pkt;
41320Sstevel@tonic-gate scsa2usb_delete_arq_pkt(scsa2usbp);
41330Sstevel@tonic-gate }
41340Sstevel@tonic-gate
41350Sstevel@tonic-gate if ((rval != TRAN_ACCEPT) &&
41360Sstevel@tonic-gate (pkt->pkt_reason == CMD_CMPLT)) {
41370Sstevel@tonic-gate pkt->pkt_reason = CMD_TRAN_ERR;
41380Sstevel@tonic-gate }
41390Sstevel@tonic-gate
41400Sstevel@tonic-gate SCSA2USB_SET_PKT_DO_COMP_STATE(scsa2usbp);
41410Sstevel@tonic-gate scsa2usb_pkt_completion(scsa2usbp, pkt);
41420Sstevel@tonic-gate
41430Sstevel@tonic-gate ASSERT(scsa2usbp->scsa2usb_cur_pkt == NULL);
41440Sstevel@tonic-gate }
41450Sstevel@tonic-gate
41460Sstevel@tonic-gate
41470Sstevel@tonic-gate /*
41480Sstevel@tonic-gate * scsa2usb_work_thread:
41490Sstevel@tonic-gate * The taskq thread that kicks off the transport (BO and CB/CBI)
41500Sstevel@tonic-gate */
41510Sstevel@tonic-gate static void
scsa2usb_work_thread(void * arg)41520Sstevel@tonic-gate scsa2usb_work_thread(void *arg)
41530Sstevel@tonic-gate {
41540Sstevel@tonic-gate scsa2usb_state_t *scsa2usbp = (scsa2usb_state_t *)arg;
41550Sstevel@tonic-gate uint_t lun;
41560Sstevel@tonic-gate uint_t count;
41570Sstevel@tonic-gate
4158189Sfrits mutex_enter(&scsa2usbp->scsa2usb_mutex);
41590Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
41606898Sfb209375 "scsa2usb_work_thread start: thread_id=0x%p",
41616898Sfb209375 (void *)scsa2usbp->scsa2usb_work_thread_id);
4162189Sfrits
41630Sstevel@tonic-gate ASSERT(scsa2usbp->scsa2usb_work_thread_id == (kthread_t *)1);
41640Sstevel@tonic-gate scsa2usbp->scsa2usb_work_thread_id = curthread;
41650Sstevel@tonic-gate
41660Sstevel@tonic-gate /* exclude ugen accesses */
41670Sstevel@tonic-gate while (scsa2usbp->scsa2usb_transport_busy) {
41680Sstevel@tonic-gate cv_wait(&scsa2usbp->scsa2usb_transport_busy_cv,
41690Sstevel@tonic-gate &scsa2usbp->scsa2usb_mutex);
41700Sstevel@tonic-gate }
41710Sstevel@tonic-gate ASSERT(scsa2usbp->scsa2usb_ugen_open_count == 0);
41720Sstevel@tonic-gate scsa2usbp->scsa2usb_transport_busy++;
4173*11427SVincent.Wang@Sun.COM scsa2usbp->scsa2usb_busy_proc = curproc;
41740Sstevel@tonic-gate
41750Sstevel@tonic-gate scsa2usb_raise_power(scsa2usbp);
41760Sstevel@tonic-gate
41770Sstevel@tonic-gate /* reopen the pipes if necessary */
41780Sstevel@tonic-gate (void) scsa2usb_open_usb_pipes(scsa2usbp);
41790Sstevel@tonic-gate
41800Sstevel@tonic-gate for (;;) {
41810Sstevel@tonic-gate ASSERT(scsa2usbp->scsa2usb_ugen_open_count == 0);
41820Sstevel@tonic-gate for (lun = 0; lun < scsa2usbp->scsa2usb_n_luns; lun++) {
41830Sstevel@tonic-gate scsa2usb_transport_request(scsa2usbp, lun);
41840Sstevel@tonic-gate }
41850Sstevel@tonic-gate count = 0;
41860Sstevel@tonic-gate for (lun = 0; lun < SCSA2USB_MAX_LUNS; lun++) {
41870Sstevel@tonic-gate count += usba_list_entry_count(
41884700Sfb209375 &scsa2usbp->scsa2usb_waitQ[lun]);
41890Sstevel@tonic-gate }
41900Sstevel@tonic-gate
41910Sstevel@tonic-gate if (count == 0) {
41920Sstevel@tonic-gate
41930Sstevel@tonic-gate break;
41940Sstevel@tonic-gate }
41950Sstevel@tonic-gate }
41960Sstevel@tonic-gate
41970Sstevel@tonic-gate scsa2usbp->scsa2usb_work_thread_id = 0;
41980Sstevel@tonic-gate
41990Sstevel@tonic-gate ASSERT(scsa2usbp->scsa2usb_ugen_open_count == 0);
42000Sstevel@tonic-gate
42010Sstevel@tonic-gate scsa2usbp->scsa2usb_transport_busy--;
4202*11427SVincent.Wang@Sun.COM scsa2usbp->scsa2usb_busy_proc = NULL;
42030Sstevel@tonic-gate cv_signal(&scsa2usbp->scsa2usb_transport_busy_cv);
42040Sstevel@tonic-gate
42050Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
42060Sstevel@tonic-gate "scsa2usb_work_thread: exit");
4207189Sfrits
4208189Sfrits mutex_exit(&scsa2usbp->scsa2usb_mutex);
4209189Sfrits
4210189Sfrits scsa2usb_pm_idle_component(scsa2usbp);
42110Sstevel@tonic-gate }
42120Sstevel@tonic-gate
42130Sstevel@tonic-gate
42140Sstevel@tonic-gate /*
42150Sstevel@tonic-gate * scsa2usb_flush_waitQ:
42160Sstevel@tonic-gate * empties the entire waitQ with errors asap.
42170Sstevel@tonic-gate *
42180Sstevel@tonic-gate * It is called from scsa2usb_scsi_reset and scsa2usb_panic_callb.
42190Sstevel@tonic-gate * If the device is reset; we should empty the waitQ right away.
42200Sstevel@tonic-gate * If the system has paniced; we should empty the waitQ right away.
42210Sstevel@tonic-gate *
42220Sstevel@tonic-gate * CPR suspend will only succeed if device is idle. No need to call
42230Sstevel@tonic-gate * this function for CPR suspend case.
42240Sstevel@tonic-gate */
42250Sstevel@tonic-gate static void
scsa2usb_flush_waitQ(scsa2usb_state_t * scsa2usbp,uint_t lun,uchar_t error)42260Sstevel@tonic-gate scsa2usb_flush_waitQ(scsa2usb_state_t *scsa2usbp, uint_t lun,
42270Sstevel@tonic-gate uchar_t error)
42280Sstevel@tonic-gate {
42290Sstevel@tonic-gate struct scsi_pkt *pkt;
42300Sstevel@tonic-gate struct scsa2usb_cmd *cmd;
42310Sstevel@tonic-gate usba_list_entry_t head;
42320Sstevel@tonic-gate
42330Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
42340Sstevel@tonic-gate
42350Sstevel@tonic-gate usba_move_list(&scsa2usbp->scsa2usb_waitQ[lun], &head,
42360Sstevel@tonic-gate scsa2usbp->scsa2usb_dev_data->dev_iblock_cookie);
42370Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
42380Sstevel@tonic-gate
42390Sstevel@tonic-gate while ((cmd = (scsa2usb_cmd_t *)usba_rm_first_pvt_from_list(&head)) !=
42400Sstevel@tonic-gate NULL) {
42410Sstevel@tonic-gate pkt = cmd->cmd_pkt;
42420Sstevel@tonic-gate pkt->pkt_reason = error; /* set error */
42430Sstevel@tonic-gate
42440Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
42450Sstevel@tonic-gate scsa2usbp->scsa2usb_pkt_state = SCSA2USB_PKT_DO_COMP;
42460Sstevel@tonic-gate scsa2usb_pkt_completion(scsa2usbp, pkt);
42470Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
42480Sstevel@tonic-gate } /* end of while */
42490Sstevel@tonic-gate }
42500Sstevel@tonic-gate
42510Sstevel@tonic-gate
42520Sstevel@tonic-gate /*
42530Sstevel@tonic-gate * scsa2usb_do_inquiry is performed before INIT CHILD and we have
42540Sstevel@tonic-gate * to fake a few things normally done by SCSA
42550Sstevel@tonic-gate */
42560Sstevel@tonic-gate static void
scsa2usb_do_inquiry(scsa2usb_state_t * scsa2usbp,uint_t target,uint_t lun)42570Sstevel@tonic-gate scsa2usb_do_inquiry(scsa2usb_state_t *scsa2usbp, uint_t target, uint_t lun)
42580Sstevel@tonic-gate {
42590Sstevel@tonic-gate struct buf *bp;
42600Sstevel@tonic-gate struct scsi_pkt *pkt;
42610Sstevel@tonic-gate struct scsi_address ap;
42620Sstevel@tonic-gate int len = SCSA2USB_MAX_INQ_LEN;
42630Sstevel@tonic-gate
42640Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
42650Sstevel@tonic-gate "scsa2usb_do_inquiry: %d bytes", len);
42660Sstevel@tonic-gate
42670Sstevel@tonic-gate /* is it inquiry-challenged? */
42680Sstevel@tonic-gate if (!(scsa2usbp->scsa2usb_attrs & SCSA2USB_ATTRS_INQUIRY)) {
42698003SVitezslav.Batrla@Sun.COM scsa2usb_fake_inquiry(scsa2usbp,
42708003SVitezslav.Batrla@Sun.COM &scsa2usbp->scsa2usb_lun_inquiry[lun]);
42710Sstevel@tonic-gate return;
42720Sstevel@tonic-gate }
42730Sstevel@tonic-gate
42740Sstevel@tonic-gate ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
42750Sstevel@tonic-gate
42760Sstevel@tonic-gate bzero(&ap, sizeof (struct scsi_address));
42770Sstevel@tonic-gate ap.a_hba_tran = scsa2usbp->scsa2usb_tran;
42787492SZhigang.Lu@Sun.COM ap.a_target = (ushort_t)target;
42797492SZhigang.Lu@Sun.COM ap.a_lun = (uchar_t)lun;
42800Sstevel@tonic-gate
42810Sstevel@tonic-gate /* limit inquiry to 36 bytes */
42820Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
42830Sstevel@tonic-gate if ((bp = scsi_alloc_consistent_buf(&ap, (struct buf *)NULL,
42840Sstevel@tonic-gate len, B_READ, SLEEP_FUNC, NULL)) == NULL) {
42850Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
42860Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_SCSA,
42870Sstevel@tonic-gate scsa2usbp->scsa2usb_log_handle,
42880Sstevel@tonic-gate "scsa2usb_do_inquiry: failed");
42890Sstevel@tonic-gate
42900Sstevel@tonic-gate return;
42910Sstevel@tonic-gate }
42920Sstevel@tonic-gate
42930Sstevel@tonic-gate pkt = scsi_init_pkt(&ap, NULL, bp, CDB_GROUP0, 1,
42940Sstevel@tonic-gate PKT_PRIV_LEN, PKT_CONSISTENT, SLEEP_FUNC, NULL);
42950Sstevel@tonic-gate
42967492SZhigang.Lu@Sun.COM RQ_MAKECOM_G0(pkt, FLAG_NOINTR, (char)SCMD_INQUIRY, 0, (char)len);
42970Sstevel@tonic-gate
42980Sstevel@tonic-gate pkt->pkt_comp = NULL;
42990Sstevel@tonic-gate pkt->pkt_time = 5;
43000Sstevel@tonic-gate bzero(bp->b_un.b_addr, len);
43010Sstevel@tonic-gate
43020Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
43030Sstevel@tonic-gate "scsa2usb_do_inquiry:INQUIRY");
43040Sstevel@tonic-gate
43050Sstevel@tonic-gate (void) scsi_transport(pkt);
43060Sstevel@tonic-gate
43070Sstevel@tonic-gate if (pkt->pkt_reason) {
4308978Sfrits USB_DPRINTF_L2(DPRINT_MASK_SCSA,
43090Sstevel@tonic-gate scsa2usbp->scsa2usb_log_handle,
43100Sstevel@tonic-gate "INQUIRY failed, cannot determine device type, "
43110Sstevel@tonic-gate "pkt_reason=0x%x", pkt->pkt_reason);
43120Sstevel@tonic-gate
43130Sstevel@tonic-gate /* not much hope for other cmds, reduce */
43140Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
43150Sstevel@tonic-gate scsa2usbp->scsa2usb_attrs &=
43164700Sfb209375 ~SCSA2USB_ATTRS_REDUCED_CMD;
43178003SVitezslav.Batrla@Sun.COM scsa2usb_fake_inquiry(scsa2usbp,
43188003SVitezslav.Batrla@Sun.COM &scsa2usbp->scsa2usb_lun_inquiry[lun]);
43190Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
43200Sstevel@tonic-gate }
43210Sstevel@tonic-gate
43220Sstevel@tonic-gate scsi_destroy_pkt(pkt);
43230Sstevel@tonic-gate scsi_free_consistent_buf(bp);
43240Sstevel@tonic-gate
43250Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
43260Sstevel@tonic-gate }
43270Sstevel@tonic-gate
43280Sstevel@tonic-gate
43290Sstevel@tonic-gate /*
43300Sstevel@tonic-gate * scsa2usb_fake_inquiry:
43310Sstevel@tonic-gate * build an inquiry for a given device that doesnt like inquiry
43320Sstevel@tonic-gate * commands.
43330Sstevel@tonic-gate */
43348003SVitezslav.Batrla@Sun.COM static void
scsa2usb_fake_inquiry(scsa2usb_state_t * scsa2usbp,struct scsi_inquiry * inqp)43358003SVitezslav.Batrla@Sun.COM scsa2usb_fake_inquiry(scsa2usb_state_t *scsa2usbp, struct scsi_inquiry *inqp)
43360Sstevel@tonic-gate {
43370Sstevel@tonic-gate usb_client_dev_data_t *dev_data = scsa2usbp->scsa2usb_dev_data;
43380Sstevel@tonic-gate int len;
43390Sstevel@tonic-gate
43400Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
43410Sstevel@tonic-gate "scsa2usb_fake_inquiry:");
43420Sstevel@tonic-gate
43430Sstevel@tonic-gate bzero(inqp, sizeof (struct scsi_inquiry));
43440Sstevel@tonic-gate for (len = 0; len < sizeof (inqp->inq_vid); len++) {
43450Sstevel@tonic-gate *(inqp->inq_vid + len) = ' ';
43460Sstevel@tonic-gate }
43470Sstevel@tonic-gate
43480Sstevel@tonic-gate for (len = 0; len < sizeof (inqp->inq_pid); len++) {
43490Sstevel@tonic-gate *(inqp->inq_pid + len) = ' ';
43500Sstevel@tonic-gate }
43510Sstevel@tonic-gate
43520Sstevel@tonic-gate inqp->inq_dtype = DTYPE_DIRECT;
43530Sstevel@tonic-gate inqp->inq_rmb = 1;
43540Sstevel@tonic-gate inqp->inq_ansi = 2;
43550Sstevel@tonic-gate inqp->inq_rdf = RDF_SCSI2;
43560Sstevel@tonic-gate inqp->inq_len = sizeof (struct scsi_inquiry)-4;
43570Sstevel@tonic-gate
43580Sstevel@tonic-gate /* Fill in the Vendor id/Product id strings */
43590Sstevel@tonic-gate if (dev_data->dev_mfg) {
43600Sstevel@tonic-gate if ((len = strlen(dev_data->dev_mfg)) >
43610Sstevel@tonic-gate sizeof (inqp->inq_vid)) {
43620Sstevel@tonic-gate len = sizeof (inqp->inq_vid);
43630Sstevel@tonic-gate }
43640Sstevel@tonic-gate bcopy(dev_data->dev_mfg, inqp->inq_vid, len);
43650Sstevel@tonic-gate }
43660Sstevel@tonic-gate
43670Sstevel@tonic-gate if (dev_data->dev_product) {
43680Sstevel@tonic-gate if ((len = strlen(dev_data->dev_product)) >
43690Sstevel@tonic-gate sizeof (inqp->inq_pid)) {
43700Sstevel@tonic-gate len = sizeof (inqp->inq_pid);
43710Sstevel@tonic-gate }
43720Sstevel@tonic-gate bcopy(dev_data->dev_product, inqp->inq_pid, len);
43730Sstevel@tonic-gate }
43740Sstevel@tonic-gate
43750Sstevel@tonic-gate /* Set the Revision to the Device */
43760Sstevel@tonic-gate inqp->inq_revision[0] = 0x30 +
43774700Sfb209375 ((dev_data->dev_descr->bcdDevice>>12) & 0xF);
43780Sstevel@tonic-gate inqp->inq_revision[1] = 0x30 +
43794700Sfb209375 ((dev_data->dev_descr->bcdDevice>>8) & 0xF);
43800Sstevel@tonic-gate inqp->inq_revision[2] = 0x30 +
43814700Sfb209375 ((dev_data->dev_descr->bcdDevice>>4) & 0xF);
43820Sstevel@tonic-gate inqp->inq_revision[3] = 0x30 +
43834700Sfb209375 ((dev_data->dev_descr->bcdDevice) & 0xF);
43840Sstevel@tonic-gate }
43850Sstevel@tonic-gate
43860Sstevel@tonic-gate
43870Sstevel@tonic-gate /*
43880Sstevel@tonic-gate * scsa2usb_create_arq_pkt:
43890Sstevel@tonic-gate * Create and ARQ packet to get request sense data
43900Sstevel@tonic-gate */
43910Sstevel@tonic-gate static int
scsa2usb_create_arq_pkt(scsa2usb_state_t * scsa2usbp,struct scsi_address * ap)43920Sstevel@tonic-gate scsa2usb_create_arq_pkt(scsa2usb_state_t *scsa2usbp, struct scsi_address *ap)
43930Sstevel@tonic-gate {
43940Sstevel@tonic-gate struct buf *bp;
43950Sstevel@tonic-gate scsa2usb_cmd_t *arq_cmd;
43960Sstevel@tonic-gate
43970Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
43986898Sfb209375 "scsa2usb_create_arq_pkt: scsa2usbp: %p, ap: %p",
43996898Sfb209375 (void *)scsa2usbp, (void *)ap);
44000Sstevel@tonic-gate
44010Sstevel@tonic-gate ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
44020Sstevel@tonic-gate
44030Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
44040Sstevel@tonic-gate if ((bp = scsi_alloc_consistent_buf(ap, (struct buf *)NULL,
44050Sstevel@tonic-gate SENSE_LENGTH, B_READ, SLEEP_FUNC, NULL)) == NULL) {
44060Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
44070Sstevel@tonic-gate
44080Sstevel@tonic-gate return (USB_FAILURE);
44090Sstevel@tonic-gate }
44100Sstevel@tonic-gate
44110Sstevel@tonic-gate arq_cmd = PKT2CMD(scsi_init_pkt(ap, NULL, bp, CDB_GROUP0, 1,
44120Sstevel@tonic-gate PKT_PRIV_LEN, PKT_CONSISTENT, SLEEP_FUNC, NULL));
44130Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
44140Sstevel@tonic-gate
44150Sstevel@tonic-gate RQ_MAKECOM_G0(arq_cmd->cmd_pkt,
44160Sstevel@tonic-gate FLAG_SENSING | FLAG_HEAD | FLAG_NODISCON,
44170Sstevel@tonic-gate (char)SCMD_REQUEST_SENSE, 0, (char)SENSE_LENGTH);
44180Sstevel@tonic-gate
44190Sstevel@tonic-gate arq_cmd->cmd_pkt->pkt_ha_private = arq_cmd;
44200Sstevel@tonic-gate scsa2usbp->scsa2usb_arq_cmd = arq_cmd;
44210Sstevel@tonic-gate scsa2usbp->scsa2usb_arq_bp = bp;
44220Sstevel@tonic-gate arq_cmd->cmd_pkt->pkt_comp = NULL;
44230Sstevel@tonic-gate bzero(bp->b_un.b_addr, SENSE_LENGTH);
44240Sstevel@tonic-gate
44250Sstevel@tonic-gate return (USB_SUCCESS);
44260Sstevel@tonic-gate }
44270Sstevel@tonic-gate
44280Sstevel@tonic-gate
44290Sstevel@tonic-gate /*
44300Sstevel@tonic-gate * scsa2usb_delete_arq_pkt:
44310Sstevel@tonic-gate * Destroy the ARQ packet
44320Sstevel@tonic-gate */
44330Sstevel@tonic-gate static void
scsa2usb_delete_arq_pkt(scsa2usb_state_t * scsa2usbp)44340Sstevel@tonic-gate scsa2usb_delete_arq_pkt(scsa2usb_state_t *scsa2usbp)
44350Sstevel@tonic-gate {
44360Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
44376898Sfb209375 "scsa2usb_delete_arq_pkt: cmd: 0x%p",
44386898Sfb209375 (void *)scsa2usbp->scsa2usb_arq_cmd);
44390Sstevel@tonic-gate
44400Sstevel@tonic-gate ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
44410Sstevel@tonic-gate
44420Sstevel@tonic-gate if (scsa2usbp->scsa2usb_arq_cmd != NULL) {
44430Sstevel@tonic-gate scsi_destroy_pkt(scsa2usbp->scsa2usb_arq_cmd->cmd_pkt);
44440Sstevel@tonic-gate scsi_free_consistent_buf(scsa2usbp->scsa2usb_arq_bp);
44450Sstevel@tonic-gate }
44460Sstevel@tonic-gate scsa2usbp->scsa2usb_arq_cmd = NULL;
44470Sstevel@tonic-gate scsa2usbp->scsa2usb_arq_bp = NULL;
44480Sstevel@tonic-gate }
44490Sstevel@tonic-gate
44500Sstevel@tonic-gate
44510Sstevel@tonic-gate /*
44520Sstevel@tonic-gate * scsa2usb_complete_arq_pkt:
44530Sstevel@tonic-gate * finish processing the arq packet
44540Sstevel@tonic-gate */
44550Sstevel@tonic-gate static void
scsa2usb_complete_arq_pkt(scsa2usb_state_t * scsa2usbp,struct scsi_pkt * pkt,scsa2usb_cmd_t * ssp,struct buf * bp)44560Sstevel@tonic-gate scsa2usb_complete_arq_pkt(scsa2usb_state_t *scsa2usbp,
44570Sstevel@tonic-gate struct scsi_pkt *pkt, scsa2usb_cmd_t *ssp, struct buf *bp)
44580Sstevel@tonic-gate {
44590Sstevel@tonic-gate scsa2usb_cmd_t *sp = pkt->pkt_ha_private;
44600Sstevel@tonic-gate struct scsi_arq_status *arqp;
44610Sstevel@tonic-gate
44620Sstevel@tonic-gate ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
44630Sstevel@tonic-gate
44640Sstevel@tonic-gate arqp = (struct scsi_arq_status *)(ssp->cmd_pkt->pkt_scbp);
44650Sstevel@tonic-gate arqp->sts_rqpkt_status = *((struct scsi_status *)
44664700Sfb209375 (sp->cmd_pkt->pkt_scbp));
44670Sstevel@tonic-gate arqp->sts_rqpkt_reason = CMD_CMPLT;
44680Sstevel@tonic-gate arqp->sts_rqpkt_state |= STATE_XFERRED_DATA;
44690Sstevel@tonic-gate arqp->sts_rqpkt_statistics = arqp->sts_rqpkt_resid = 0;
44700Sstevel@tonic-gate
44710Sstevel@tonic-gate /* is this meaningful sense data */
44720Sstevel@tonic-gate if (*(bp->b_un.b_addr) != 0) {
44735727Slh195018 bcopy(bp->b_un.b_addr, &arqp->sts_sensedata, SENSE_LENGTH);
44740Sstevel@tonic-gate ssp->cmd_pkt->pkt_state |= STATE_ARQ_DONE;
44750Sstevel@tonic-gate }
44760Sstevel@tonic-gate
44770Sstevel@tonic-gate /* we will not sense start cmd until we receive a NOT READY */
44780Sstevel@tonic-gate if (arqp->sts_sensedata.es_key == KEY_NOT_READY) {
44790Sstevel@tonic-gate scsa2usbp->scsa2usb_rcvd_not_ready = B_TRUE;
44800Sstevel@tonic-gate }
44810Sstevel@tonic-gate }
44820Sstevel@tonic-gate
44830Sstevel@tonic-gate
44840Sstevel@tonic-gate /*
44850Sstevel@tonic-gate * Miscellaneous functions for any command/transport
44860Sstevel@tonic-gate */
44870Sstevel@tonic-gate /*
44880Sstevel@tonic-gate * scsa2usb_open_usb_pipes:
44890Sstevel@tonic-gate * set up a pipe policy
44900Sstevel@tonic-gate * open usb bulk pipes (BO and CB/CBI)
44910Sstevel@tonic-gate * open usb interrupt pipe (CBI)
44920Sstevel@tonic-gate */
44930Sstevel@tonic-gate static int
scsa2usb_open_usb_pipes(scsa2usb_state_t * scsa2usbp)44940Sstevel@tonic-gate scsa2usb_open_usb_pipes(scsa2usb_state_t *scsa2usbp)
44950Sstevel@tonic-gate {
44960Sstevel@tonic-gate int rval;
44970Sstevel@tonic-gate usb_pipe_policy_t policy; /* bulk pipe policy */
44980Sstevel@tonic-gate size_t sz;
44990Sstevel@tonic-gate
45000Sstevel@tonic-gate ASSERT(scsa2usbp);
45010Sstevel@tonic-gate ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
45020Sstevel@tonic-gate
45030Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
45040Sstevel@tonic-gate "scsa2usb_open_usb_pipes: dip = 0x%p flag = 0x%x",
45056898Sfb209375 (void *)scsa2usbp->scsa2usb_dip, scsa2usbp->scsa2usb_flags);
45060Sstevel@tonic-gate
45070Sstevel@tonic-gate if (!(scsa2usbp->scsa2usb_flags & SCSA2USB_FLAGS_PIPES_OPENED)) {
45080Sstevel@tonic-gate
45090Sstevel@tonic-gate /*
45100Sstevel@tonic-gate * one pipe policy for all bulk pipes
45110Sstevel@tonic-gate */
45120Sstevel@tonic-gate bzero(&policy, sizeof (usb_pipe_policy_t));
45130Sstevel@tonic-gate /* at least 2, for the normal and exceptional callbacks */
45140Sstevel@tonic-gate policy.pp_max_async_reqs = 1;
45150Sstevel@tonic-gate
45160Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
45170Sstevel@tonic-gate "scsa2usb_open_usb_pipes: opening bulk pipes");
45180Sstevel@tonic-gate
45190Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
45200Sstevel@tonic-gate
45210Sstevel@tonic-gate /* Open the USB bulk-in pipe */
45220Sstevel@tonic-gate if ((rval = usb_pipe_open(scsa2usbp->scsa2usb_dip,
45230Sstevel@tonic-gate &scsa2usbp->scsa2usb_bulkin_ept, &policy, USB_FLAGS_SLEEP,
45240Sstevel@tonic-gate &scsa2usbp->scsa2usb_bulkin_pipe)) != USB_SUCCESS) {
45250Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
45260Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_SCSA,
45270Sstevel@tonic-gate scsa2usbp->scsa2usb_log_handle,
45280Sstevel@tonic-gate "scsa2usb_open_usb_pipes: bulk/in pipe open "
45290Sstevel@tonic-gate " failed rval = %d", rval);
45300Sstevel@tonic-gate
45310Sstevel@tonic-gate return (USB_FAILURE);
45320Sstevel@tonic-gate }
45330Sstevel@tonic-gate
45340Sstevel@tonic-gate /* Open the bulk-out pipe using the same policy */
45350Sstevel@tonic-gate if ((rval = usb_pipe_open(scsa2usbp->scsa2usb_dip,
45360Sstevel@tonic-gate &scsa2usbp->scsa2usb_bulkout_ept, &policy, USB_FLAGS_SLEEP,
45370Sstevel@tonic-gate &scsa2usbp->scsa2usb_bulkout_pipe)) != USB_SUCCESS) {
45380Sstevel@tonic-gate usb_pipe_close(scsa2usbp->scsa2usb_dip,
45390Sstevel@tonic-gate scsa2usbp->scsa2usb_bulkin_pipe,
45400Sstevel@tonic-gate USB_FLAGS_SLEEP, NULL, NULL);
45410Sstevel@tonic-gate
45420Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
45430Sstevel@tonic-gate scsa2usbp->scsa2usb_bulkin_pipe = NULL;
45440Sstevel@tonic-gate
45450Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_SCSA,
45460Sstevel@tonic-gate scsa2usbp->scsa2usb_log_handle,
45470Sstevel@tonic-gate "scsa2usb_open_usb_pipes: bulk/out pipe open"
45480Sstevel@tonic-gate " failed rval = %d", rval);
45490Sstevel@tonic-gate
45500Sstevel@tonic-gate return (USB_FAILURE);
45510Sstevel@tonic-gate }
45520Sstevel@tonic-gate
45530Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
45540Sstevel@tonic-gate
45550Sstevel@tonic-gate /* open interrupt pipe for CBI protocol */
45560Sstevel@tonic-gate if (SCSA2USB_IS_CBI(scsa2usbp)) {
45570Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
45580Sstevel@tonic-gate
45590Sstevel@tonic-gate if ((rval = usb_pipe_open(scsa2usbp->scsa2usb_dip,
45600Sstevel@tonic-gate &scsa2usbp->scsa2usb_intr_ept, &policy,
45610Sstevel@tonic-gate USB_FLAGS_SLEEP, &scsa2usbp->scsa2usb_intr_pipe)) !=
45620Sstevel@tonic-gate USB_SUCCESS) {
45630Sstevel@tonic-gate usb_pipe_close(scsa2usbp->scsa2usb_dip,
45640Sstevel@tonic-gate scsa2usbp->scsa2usb_bulkin_pipe,
45650Sstevel@tonic-gate USB_FLAGS_SLEEP, NULL, NULL);
45660Sstevel@tonic-gate
45670Sstevel@tonic-gate usb_pipe_close(scsa2usbp->scsa2usb_dip,
45680Sstevel@tonic-gate scsa2usbp->scsa2usb_bulkout_pipe,
45690Sstevel@tonic-gate USB_FLAGS_SLEEP, NULL, NULL);
45700Sstevel@tonic-gate
45710Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
45720Sstevel@tonic-gate scsa2usbp->scsa2usb_bulkin_pipe = NULL;
45730Sstevel@tonic-gate scsa2usbp->scsa2usb_bulkout_pipe = NULL;
45740Sstevel@tonic-gate
45750Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_SCSA,
45760Sstevel@tonic-gate scsa2usbp->scsa2usb_log_handle,
45770Sstevel@tonic-gate "scsa2usb_open_usb_pipes: intr pipe open"
45780Sstevel@tonic-gate " failed rval = %d", rval);
45790Sstevel@tonic-gate
45800Sstevel@tonic-gate return (USB_FAILURE);
45810Sstevel@tonic-gate }
45820Sstevel@tonic-gate
45830Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
45840Sstevel@tonic-gate }
45850Sstevel@tonic-gate
45860Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
45870Sstevel@tonic-gate
45880Sstevel@tonic-gate /* get the max transfer size of the bulk pipe */
45890Sstevel@tonic-gate if (usb_pipe_get_max_bulk_transfer_size(scsa2usbp->scsa2usb_dip,
45900Sstevel@tonic-gate &sz) == USB_SUCCESS) {
45910Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
45920Sstevel@tonic-gate scsa2usbp->scsa2usb_max_bulk_xfer_size = sz;
45930Sstevel@tonic-gate } else {
45940Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
45950Sstevel@tonic-gate scsa2usbp->scsa2usb_max_bulk_xfer_size = DEV_BSIZE;
45960Sstevel@tonic-gate }
45970Sstevel@tonic-gate
45980Sstevel@tonic-gate /* limit the xfer size */
45990Sstevel@tonic-gate scsa2usbp->scsa2usb_max_bulk_xfer_size = min(
46004700Sfb209375 scsa2usbp->scsa2usb_max_bulk_xfer_size,
46014700Sfb209375 scsa2usb_max_bulk_xfer_size);
46020Sstevel@tonic-gate
46030Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
46040Sstevel@tonic-gate "scsa2usb_open_usb_pipes: max bulk transfer size = %lx",
46050Sstevel@tonic-gate scsa2usbp->scsa2usb_max_bulk_xfer_size);
46060Sstevel@tonic-gate
46070Sstevel@tonic-gate /* Set the pipes opened flag */
46080Sstevel@tonic-gate scsa2usbp->scsa2usb_flags |= SCSA2USB_FLAGS_PIPES_OPENED;
46090Sstevel@tonic-gate
46100Sstevel@tonic-gate scsa2usbp->scsa2usb_pipe_state = SCSA2USB_PIPE_NORMAL;
46110Sstevel@tonic-gate
46120Sstevel@tonic-gate /* Set the state to NONE */
46130Sstevel@tonic-gate scsa2usbp->scsa2usb_pkt_state = SCSA2USB_PKT_NONE;
46140Sstevel@tonic-gate }
46150Sstevel@tonic-gate
46160Sstevel@tonic-gate return (USB_SUCCESS);
46170Sstevel@tonic-gate }
46180Sstevel@tonic-gate
46190Sstevel@tonic-gate
46200Sstevel@tonic-gate /*
46210Sstevel@tonic-gate * scsa2usb_close_usb_pipes:
46220Sstevel@tonic-gate * close all pipes synchronously
46230Sstevel@tonic-gate */
46240Sstevel@tonic-gate void
scsa2usb_close_usb_pipes(scsa2usb_state_t * scsa2usbp)46250Sstevel@tonic-gate scsa2usb_close_usb_pipes(scsa2usb_state_t *scsa2usbp)
46260Sstevel@tonic-gate {
46270Sstevel@tonic-gate usb_flags_t flags = USB_FLAGS_SLEEP;
46280Sstevel@tonic-gate
46290Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
46306898Sfb209375 "scsa2usb_close_usb_pipes: scsa2usb_state = 0x%p",
46316898Sfb209375 (void *)scsa2usbp);
46320Sstevel@tonic-gate
46330Sstevel@tonic-gate ASSERT(scsa2usbp);
46340Sstevel@tonic-gate ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
46350Sstevel@tonic-gate
46360Sstevel@tonic-gate if ((scsa2usbp->scsa2usb_flags & SCSA2USB_FLAGS_PIPES_OPENED) == 0) {
46370Sstevel@tonic-gate
46380Sstevel@tonic-gate return;
46390Sstevel@tonic-gate }
46400Sstevel@tonic-gate
46410Sstevel@tonic-gate scsa2usbp->scsa2usb_pipe_state = SCSA2USB_PIPE_CLOSING;
46420Sstevel@tonic-gate /* to avoid races, reset the flag first */
46430Sstevel@tonic-gate scsa2usbp->scsa2usb_flags &= ~SCSA2USB_FLAGS_PIPES_OPENED;
46440Sstevel@tonic-gate
46450Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
46460Sstevel@tonic-gate
46470Sstevel@tonic-gate usb_pipe_close(scsa2usbp->scsa2usb_dip,
46480Sstevel@tonic-gate scsa2usbp->scsa2usb_bulkout_pipe, flags, NULL, NULL);
46490Sstevel@tonic-gate
46500Sstevel@tonic-gate usb_pipe_close(scsa2usbp->scsa2usb_dip,
46510Sstevel@tonic-gate scsa2usbp->scsa2usb_bulkin_pipe, flags, NULL, NULL);
46520Sstevel@tonic-gate
46530Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
46540Sstevel@tonic-gate if (SCSA2USB_IS_CBI(scsa2usbp)) {
46550Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
46560Sstevel@tonic-gate usb_pipe_close(scsa2usbp->scsa2usb_dip,
46570Sstevel@tonic-gate scsa2usbp->scsa2usb_intr_pipe, flags, NULL, NULL);
46580Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
46590Sstevel@tonic-gate }
46600Sstevel@tonic-gate scsa2usbp->scsa2usb_bulkout_pipe = NULL;
46610Sstevel@tonic-gate scsa2usbp->scsa2usb_bulkin_pipe = NULL;
46620Sstevel@tonic-gate scsa2usbp->scsa2usb_intr_pipe = NULL;
46630Sstevel@tonic-gate
46640Sstevel@tonic-gate scsa2usbp->scsa2usb_pipe_state = SCSA2USB_PIPE_NORMAL;
46650Sstevel@tonic-gate }
46660Sstevel@tonic-gate
46670Sstevel@tonic-gate
46680Sstevel@tonic-gate /*
46690Sstevel@tonic-gate * scsa2usb_fill_up_cdb_lba:
46700Sstevel@tonic-gate * fill up command CDBs' LBA part
46710Sstevel@tonic-gate */
46720Sstevel@tonic-gate static void
scsa2usb_fill_up_cdb_lba(scsa2usb_cmd_t * cmd,int lba)46730Sstevel@tonic-gate scsa2usb_fill_up_cdb_lba(scsa2usb_cmd_t *cmd, int lba)
46740Sstevel@tonic-gate {
46750Sstevel@tonic-gate /* zero cdb1, lba bits so they won't get copied in the new cdb */
46760Sstevel@tonic-gate cmd->cmd_cdb[SCSA2USB_LUN] &= 0xE0;
46770Sstevel@tonic-gate cmd->cmd_cdb[SCSA2USB_LBA_0] = lba >> 24;
46780Sstevel@tonic-gate cmd->cmd_cdb[SCSA2USB_LBA_1] = lba >> 16;
46790Sstevel@tonic-gate cmd->cmd_cdb[SCSA2USB_LBA_2] = lba >> 8;
46800Sstevel@tonic-gate cmd->cmd_cdb[SCSA2USB_LBA_3] = (uchar_t)lba;
46810Sstevel@tonic-gate cmd->cmd_lba = lba;
46820Sstevel@tonic-gate }
46830Sstevel@tonic-gate
46840Sstevel@tonic-gate
46850Sstevel@tonic-gate /*
46860Sstevel@tonic-gate * scsa2usb_fill_up_ReadCD_cdb_len:
46870Sstevel@tonic-gate * fill up READ_CD command CDBs' len part
46880Sstevel@tonic-gate */
46890Sstevel@tonic-gate static void
scsa2usb_fill_up_ReadCD_cdb_len(scsa2usb_cmd_t * cmd,int len,int actual_len)46900Sstevel@tonic-gate scsa2usb_fill_up_ReadCD_cdb_len(scsa2usb_cmd_t *cmd, int len, int actual_len)
46910Sstevel@tonic-gate {
46920Sstevel@tonic-gate cmd->cmd_cdb[SCSA2USB_READ_CD_LEN_0] = len >> 16;
46930Sstevel@tonic-gate cmd->cmd_cdb[SCSA2USB_READ_CD_LEN_1] = len >> 8;
46940Sstevel@tonic-gate cmd->cmd_cdb[SCSA2USB_READ_CD_LEN_2] = (uchar_t)len;
46950Sstevel@tonic-gate cmd->cmd_actual_len = (uchar_t)actual_len;
46960Sstevel@tonic-gate }
46970Sstevel@tonic-gate
46980Sstevel@tonic-gate
46990Sstevel@tonic-gate /*
47000Sstevel@tonic-gate * scsa2usb_fill_up_12byte_cdb_len:
47010Sstevel@tonic-gate * fill up generic 12-byte command CDBs' len part
47020Sstevel@tonic-gate */
47030Sstevel@tonic-gate static void
scsa2usb_fill_up_12byte_cdb_len(scsa2usb_cmd_t * cmd,int len,int actual_len)47040Sstevel@tonic-gate scsa2usb_fill_up_12byte_cdb_len(scsa2usb_cmd_t *cmd, int len, int actual_len)
47050Sstevel@tonic-gate {
47060Sstevel@tonic-gate cmd->cmd_cdb[6] = len >> 24;
47070Sstevel@tonic-gate cmd->cmd_cdb[7] = len >> 16;
47080Sstevel@tonic-gate cmd->cmd_cdb[8] = len >> 8;
47090Sstevel@tonic-gate cmd->cmd_cdb[9] = (uchar_t)len;
47100Sstevel@tonic-gate cmd->cmd_actual_len = (uchar_t)actual_len;
47110Sstevel@tonic-gate }
47120Sstevel@tonic-gate
47130Sstevel@tonic-gate
47140Sstevel@tonic-gate /*
47150Sstevel@tonic-gate * scsa2usb_fill_up_cdb_len:
47160Sstevel@tonic-gate * fill up generic 10-byte command CDBs' len part
47170Sstevel@tonic-gate */
47180Sstevel@tonic-gate static void
scsa2usb_fill_up_cdb_len(scsa2usb_cmd_t * cmd,int len)47190Sstevel@tonic-gate scsa2usb_fill_up_cdb_len(scsa2usb_cmd_t *cmd, int len)
47200Sstevel@tonic-gate {
47210Sstevel@tonic-gate cmd->cmd_cdb[SCSA2USB_LEN_0] = len >> 8;
47220Sstevel@tonic-gate cmd->cmd_cdb[SCSA2USB_LEN_1] = (uchar_t)len;
47230Sstevel@tonic-gate }
47240Sstevel@tonic-gate
47250Sstevel@tonic-gate
47260Sstevel@tonic-gate /*
47270Sstevel@tonic-gate * scsa2usb_read_cd_blk_size:
47280Sstevel@tonic-gate * For SCMD_READ_CD opcode (0xbe). Figure out the
47290Sstevel@tonic-gate * block size based on expected sector type field
47300Sstevel@tonic-gate * definition. See MMC SCSI Specs section 6.1.15
47310Sstevel@tonic-gate *
47320Sstevel@tonic-gate * Based on the value of the "expected_sector_type"
47330Sstevel@tonic-gate * field, the block size could be different.
47340Sstevel@tonic-gate */
47350Sstevel@tonic-gate static int
scsa2usb_read_cd_blk_size(uchar_t expected_sector_type)47360Sstevel@tonic-gate scsa2usb_read_cd_blk_size(uchar_t expected_sector_type)
47370Sstevel@tonic-gate {
47380Sstevel@tonic-gate int blk_size;
47390Sstevel@tonic-gate
47400Sstevel@tonic-gate switch (expected_sector_type) {
47410Sstevel@tonic-gate case READ_CD_EST_CDDA:
47420Sstevel@tonic-gate blk_size = CDROM_BLK_2352;
47430Sstevel@tonic-gate break;
47440Sstevel@tonic-gate case READ_CD_EST_MODE2:
47450Sstevel@tonic-gate blk_size = CDROM_BLK_2336;
47460Sstevel@tonic-gate break;
47470Sstevel@tonic-gate case READ_CD_EST_MODE2FORM2:
47480Sstevel@tonic-gate blk_size = CDROM_BLK_2324;
47490Sstevel@tonic-gate break;
47500Sstevel@tonic-gate case READ_CD_EST_MODE2FORM1:
47510Sstevel@tonic-gate case READ_CD_EST_ALLTYPE:
47520Sstevel@tonic-gate case READ_CD_EST_MODE1:
47530Sstevel@tonic-gate default:
47540Sstevel@tonic-gate blk_size = CDROM_BLK_2048;
47550Sstevel@tonic-gate }
47560Sstevel@tonic-gate
47570Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, NULL, "scsa2usb_read_cd_blk_size: "
47580Sstevel@tonic-gate "est = 0x%x blk_size = %d", expected_sector_type, blk_size);
47590Sstevel@tonic-gate
47600Sstevel@tonic-gate return (blk_size);
47610Sstevel@tonic-gate }
47620Sstevel@tonic-gate
47630Sstevel@tonic-gate
47640Sstevel@tonic-gate /*
47650Sstevel@tonic-gate * scsa2usb_bp_to_mblk:
47660Sstevel@tonic-gate * Convert a bp to mblk_t. USBA framework understands mblk_t.
47670Sstevel@tonic-gate */
47680Sstevel@tonic-gate static mblk_t *
scsa2usb_bp_to_mblk(scsa2usb_state_t * scsa2usbp)47690Sstevel@tonic-gate scsa2usb_bp_to_mblk(scsa2usb_state_t *scsa2usbp)
47700Sstevel@tonic-gate {
47710Sstevel@tonic-gate size_t size;
47720Sstevel@tonic-gate mblk_t *mp;
47730Sstevel@tonic-gate struct buf *bp;
47740Sstevel@tonic-gate scsa2usb_cmd_t *cmd = PKT2CMD(scsa2usbp->scsa2usb_cur_pkt);
47750Sstevel@tonic-gate
47760Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
47770Sstevel@tonic-gate "scsa2usb_bp_to_mblk: ");
47780Sstevel@tonic-gate
47790Sstevel@tonic-gate ASSERT(scsa2usbp->scsa2usb_cur_pkt);
47800Sstevel@tonic-gate ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
47810Sstevel@tonic-gate
47820Sstevel@tonic-gate bp = cmd->cmd_bp;
47830Sstevel@tonic-gate
47840Sstevel@tonic-gate if (bp && (bp->b_bcount > 0)) {
47850Sstevel@tonic-gate size = ((bp->b_bcount > cmd->cmd_xfercount) ?
47864700Sfb209375 cmd->cmd_xfercount : bp->b_bcount);
47870Sstevel@tonic-gate } else {
47880Sstevel@tonic-gate
47890Sstevel@tonic-gate return (NULL);
47900Sstevel@tonic-gate }
47910Sstevel@tonic-gate
47920Sstevel@tonic-gate mp = esballoc_wait((uchar_t *)bp->b_un.b_addr + cmd->cmd_offset,
47937062Szl227052 size, BPRI_LO, &frnop);
47940Sstevel@tonic-gate
47950Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
47960Sstevel@tonic-gate "scsa2usb_bp_to_mblk: "
47976898Sfb209375 "mp=0x%p bp=0x%p pkt=0x%p off=0x%lx sz=%lu add=0x%p",
47986898Sfb209375 (void *)mp, (void *)bp, (void *)scsa2usbp->scsa2usb_cur_pkt,
47996898Sfb209375 cmd->cmd_offset, bp->b_bcount - cmd->cmd_offset,
48006898Sfb209375 (void *)bp->b_un.b_addr);
48010Sstevel@tonic-gate
48020Sstevel@tonic-gate mp->b_wptr += size;
48030Sstevel@tonic-gate cmd->cmd_offset += size;
48040Sstevel@tonic-gate
48050Sstevel@tonic-gate return (mp);
48060Sstevel@tonic-gate }
48070Sstevel@tonic-gate
48080Sstevel@tonic-gate
48090Sstevel@tonic-gate /*
48100Sstevel@tonic-gate * scsa2usb_handle_data_start:
48110Sstevel@tonic-gate * Initiate the data xfer. It could be IN/OUT direction.
48120Sstevel@tonic-gate *
48130Sstevel@tonic-gate * Data IN:
48140Sstevel@tonic-gate * Send out the bulk-xfer request
48150Sstevel@tonic-gate * if rval implies STALL
48160Sstevel@tonic-gate * clear endpoint stall and reset bulk-in pipe
48170Sstevel@tonic-gate * handle data read in so far; set cmd->cmd_done
48180Sstevel@tonic-gate * also adjust data xfer length accordingly
48190Sstevel@tonic-gate * else other error
48200Sstevel@tonic-gate * report back to transport
48210Sstevel@tonic-gate * typically transport will call reset recovery
48220Sstevel@tonic-gate * else (no error)
48230Sstevel@tonic-gate * return success
48240Sstevel@tonic-gate *
48250Sstevel@tonic-gate * Data OUT:
48260Sstevel@tonic-gate * Send out the bulk-xfer request
48270Sstevel@tonic-gate * if rval implies STALL
48280Sstevel@tonic-gate * clear endpoint stall and reset bulk-in pipe
48290Sstevel@tonic-gate * adjust data xfer length
48300Sstevel@tonic-gate * else other error
48310Sstevel@tonic-gate * report back to transport
48320Sstevel@tonic-gate * typically transport will call reset recovery
48330Sstevel@tonic-gate * else (no error)
48340Sstevel@tonic-gate * return success
48350Sstevel@tonic-gate *
48360Sstevel@tonic-gate * NOTE: We call this function only if there is xfercount.
48370Sstevel@tonic-gate */
48380Sstevel@tonic-gate int
scsa2usb_handle_data_start(scsa2usb_state_t * scsa2usbp,scsa2usb_cmd_t * cmd,usb_bulk_req_t * req)48390Sstevel@tonic-gate scsa2usb_handle_data_start(scsa2usb_state_t *scsa2usbp,
48400Sstevel@tonic-gate scsa2usb_cmd_t *cmd, usb_bulk_req_t *req)
48410Sstevel@tonic-gate {
48420Sstevel@tonic-gate int rval = USB_SUCCESS;
48430Sstevel@tonic-gate uint_t ept_addr;
48440Sstevel@tonic-gate usb_flags_t flags = USB_FLAGS_SLEEP;
48450Sstevel@tonic-gate #ifdef SCSA2USB_BULK_ONLY_TEST
48460Sstevel@tonic-gate usb_req_attrs_t attrs = 0;
48470Sstevel@tonic-gate #else
48480Sstevel@tonic-gate usb_req_attrs_t attrs = USB_ATTRS_SHORT_XFER_OK;
48490Sstevel@tonic-gate #endif
48500Sstevel@tonic-gate
48510Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
48526898Sfb209375 "scsa2usb_handle_data_start: BEGIN cmd = %p, req = %p",
48536898Sfb209375 (void *)cmd, (void *)req);
48540Sstevel@tonic-gate
48550Sstevel@tonic-gate ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
48560Sstevel@tonic-gate
48570Sstevel@tonic-gate switch (cmd->cmd_dir) {
48580Sstevel@tonic-gate case USB_EP_DIR_IN:
48590Sstevel@tonic-gate #ifdef SCSA2USB_BULK_ONLY_TEST
48600Sstevel@tonic-gate /*
48610Sstevel@tonic-gate * This case occurs when the host expects to receive
48620Sstevel@tonic-gate * more data than the device actually transfers. Hi > Di
48630Sstevel@tonic-gate */
48640Sstevel@tonic-gate if (scsa2usb_test_case_5) {
48650Sstevel@tonic-gate usb_bulk_req_t *req2;
48660Sstevel@tonic-gate
48670Sstevel@tonic-gate req->bulk_len = cmd->cmd_xfercount - 1;
48680Sstevel@tonic-gate req->bulk_attributes = 0;
48690Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
48700Sstevel@tonic-gate SCSA2USB_FREE_MSG(req->bulk_data);
48710Sstevel@tonic-gate req->bulk_data = allocb_wait(req->bulk_len, BPRI_LO,
48720Sstevel@tonic-gate STR_NOSIG, NULL);
48730Sstevel@tonic-gate
48740Sstevel@tonic-gate ASSERT(req->bulk_timeout);
48750Sstevel@tonic-gate rval = usb_pipe_bulk_xfer(
48760Sstevel@tonic-gate scsa2usbp->scsa2usb_bulkin_pipe, req, flags);
48770Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
48780Sstevel@tonic-gate USB_DPRINTF_L1(DPRINT_MASK_SCSA,
48790Sstevel@tonic-gate scsa2usbp->scsa2usb_log_handle, "rval = %x", rval);
48800Sstevel@tonic-gate
48810Sstevel@tonic-gate req2 = scsa2usb_init_bulk_req(scsa2usbp,
48820Sstevel@tonic-gate cmd->cmd_xfercount + 2,
48830Sstevel@tonic-gate cmd->cmd_timeout, 0, flags);
48840Sstevel@tonic-gate req2->bulk_len = cmd->cmd_xfercount + 2;
48850Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
48860Sstevel@tonic-gate
48870Sstevel@tonic-gate ASSERT(req2->bulk_timeout);
48880Sstevel@tonic-gate rval = usb_pipe_bulk_xfer(
48890Sstevel@tonic-gate scsa2usbp->scsa2usb_bulkin_pipe, req2, flags);
48900Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
48910Sstevel@tonic-gate
48920Sstevel@tonic-gate USB_DPRINTF_L1(DPRINT_MASK_SCSA,
48930Sstevel@tonic-gate scsa2usbp->scsa2usb_log_handle,
48940Sstevel@tonic-gate "TEST 5: Hi > Di: rval = 0x%x", rval);
48950Sstevel@tonic-gate scsa2usb_test_case_5 = 0;
48960Sstevel@tonic-gate usb_free_bulk_req(req2);
48970Sstevel@tonic-gate
48980Sstevel@tonic-gate return (rval);
48990Sstevel@tonic-gate }
49000Sstevel@tonic-gate
49010Sstevel@tonic-gate /*
49020Sstevel@tonic-gate * This happens when the host expects to send data to the
49030Sstevel@tonic-gate * device while the device intends to send data to the host.
49040Sstevel@tonic-gate */
49050Sstevel@tonic-gate if (scsa2usb_test_case_8 && (cmd->cmd_cdb[0] == SCMD_READ_G1)) {
49060Sstevel@tonic-gate USB_DPRINTF_L1(DPRINT_MASK_SCSA,
49070Sstevel@tonic-gate scsa2usbp->scsa2usb_log_handle,
49080Sstevel@tonic-gate "TEST 8: Hi <> Do: Step 2");
49090Sstevel@tonic-gate scsa2usb_test_mblk(scsa2usbp, B_TRUE);
49100Sstevel@tonic-gate scsa2usb_test_case_8 = 0;
49110Sstevel@tonic-gate
49120Sstevel@tonic-gate return (rval);
49130Sstevel@tonic-gate }
49140Sstevel@tonic-gate #endif /* SCSA2USB_BULK_ONLY_TEST */
49150Sstevel@tonic-gate
49160Sstevel@tonic-gate ept_addr = scsa2usbp->scsa2usb_bulkin_ept.bEndpointAddress;
49170Sstevel@tonic-gate req->bulk_len = cmd->cmd_xfercount;
49180Sstevel@tonic-gate req->bulk_attributes = attrs;
49190Sstevel@tonic-gate SCSA2USB_FREE_MSG(req->bulk_data);
49200Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
49210Sstevel@tonic-gate
49220Sstevel@tonic-gate req->bulk_data = esballoc_wait(
49234700Sfb209375 (uchar_t *)cmd->cmd_bp->b_un.b_addr +
49244700Sfb209375 cmd->cmd_offset,
49257062Szl227052 req->bulk_len, BPRI_LO, &frnop);
49260Sstevel@tonic-gate
49270Sstevel@tonic-gate ASSERT(req->bulk_timeout);
49280Sstevel@tonic-gate rval = usb_pipe_bulk_xfer(scsa2usbp->scsa2usb_bulkin_pipe,
49294700Sfb209375 req, flags);
49300Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
49310Sstevel@tonic-gate
49320Sstevel@tonic-gate break;
49330Sstevel@tonic-gate
49340Sstevel@tonic-gate case USB_EP_DIR_OUT:
49350Sstevel@tonic-gate #ifdef SCSA2USB_BULK_ONLY_TEST
49360Sstevel@tonic-gate /*
49370Sstevel@tonic-gate * This happens when the host expects to receive data
49380Sstevel@tonic-gate * from the device while the device intends to receive
49390Sstevel@tonic-gate * data from the host.
49400Sstevel@tonic-gate */
49410Sstevel@tonic-gate if (scsa2usb_test_case_10 &&
49420Sstevel@tonic-gate (cmd->cmd_cdb[0] == SCMD_WRITE_G1)) {
49430Sstevel@tonic-gate req->bulk_len = CSW_LEN;
49440Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
49450Sstevel@tonic-gate
49460Sstevel@tonic-gate ASSERT(req->bulk_timeout);
49470Sstevel@tonic-gate rval = usb_pipe_bulk_xfer(
49480Sstevel@tonic-gate scsa2usbp->scsa2usb_bulkin_pipe, req, flags);
49490Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
49500Sstevel@tonic-gate
49510Sstevel@tonic-gate USB_DPRINTF_L1(DPRINT_MASK_SCSA,
49520Sstevel@tonic-gate scsa2usbp->scsa2usb_log_handle,
49530Sstevel@tonic-gate "TEST 10: Ho <> Di: done rval = 0x%x", rval);
49540Sstevel@tonic-gate scsa2usb_test_case_10 = 0;
49550Sstevel@tonic-gate
49560Sstevel@tonic-gate return (rval);
49570Sstevel@tonic-gate }
49580Sstevel@tonic-gate #endif /* SCSA2USB_BULK_ONLY_TEST */
49590Sstevel@tonic-gate
49600Sstevel@tonic-gate req->bulk_data = scsa2usb_bp_to_mblk(scsa2usbp);
49610Sstevel@tonic-gate if (req->bulk_data == NULL) {
49620Sstevel@tonic-gate
49630Sstevel@tonic-gate return (USB_FAILURE);
49640Sstevel@tonic-gate }
49650Sstevel@tonic-gate
49660Sstevel@tonic-gate #ifdef SCSA2USB_BULK_ONLY_TEST
49670Sstevel@tonic-gate if (scsa2usb_test_case_11) {
49680Sstevel@tonic-gate /*
49690Sstevel@tonic-gate * Host expects to send data to the device and
49700Sstevel@tonic-gate * device doesn't expect to receive any data
49710Sstevel@tonic-gate */
49720Sstevel@tonic-gate USB_DPRINTF_L1(DPRINT_MASK_SCSA,
49730Sstevel@tonic-gate scsa2usbp->scsa2usb_log_handle, "TEST 11: Ho > Do");
49740Sstevel@tonic-gate
49750Sstevel@tonic-gate scsa2usb_test_mblk(scsa2usbp, B_FALSE);
49760Sstevel@tonic-gate scsa2usb_test_case_11 = 0;
49770Sstevel@tonic-gate }
49780Sstevel@tonic-gate #endif /* SCSA2USB_BULK_ONLY_TEST */
49790Sstevel@tonic-gate
49800Sstevel@tonic-gate ept_addr = scsa2usbp->scsa2usb_bulkout_ept.bEndpointAddress;
49817492SZhigang.Lu@Sun.COM req->bulk_len = MBLKL(req->bulk_data);
49820Sstevel@tonic-gate req->bulk_timeout = scsa2usb_bulk_timeout(cmd->cmd_timeout);
49830Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
49840Sstevel@tonic-gate
49850Sstevel@tonic-gate ASSERT(req->bulk_timeout);
49860Sstevel@tonic-gate rval = usb_pipe_bulk_xfer(scsa2usbp->scsa2usb_bulkout_pipe,
49874700Sfb209375 req, flags);
49880Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
49890Sstevel@tonic-gate break;
49900Sstevel@tonic-gate }
49910Sstevel@tonic-gate
49920Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_SCSA,
49930Sstevel@tonic-gate scsa2usbp->scsa2usb_log_handle,
49940Sstevel@tonic-gate "scsa2usb_handle_data_start: rval=%d cr=%d", rval,
49950Sstevel@tonic-gate req->bulk_completion_reason);
49960Sstevel@tonic-gate
49970Sstevel@tonic-gate if (rval != USB_SUCCESS) {
49980Sstevel@tonic-gate /* Handle Errors now */
49990Sstevel@tonic-gate if (req->bulk_completion_reason == USB_CR_STALL) {
50000Sstevel@tonic-gate if (cmd->cmd_dir == USB_EP_DIR_IN) {
50010Sstevel@tonic-gate (void) scsa2usb_clear_ept_stall(
50020Sstevel@tonic-gate scsa2usbp, ept_addr,
50030Sstevel@tonic-gate scsa2usbp-> scsa2usb_bulkin_pipe,
50040Sstevel@tonic-gate "bulk-in");
50050Sstevel@tonic-gate } else {
50060Sstevel@tonic-gate (void) scsa2usb_clear_ept_stall(
50070Sstevel@tonic-gate scsa2usbp, ept_addr,
50080Sstevel@tonic-gate scsa2usbp-> scsa2usb_bulkout_pipe,
50090Sstevel@tonic-gate "bulk-out");
50100Sstevel@tonic-gate }
50110Sstevel@tonic-gate }
50120Sstevel@tonic-gate
50130Sstevel@tonic-gate /* no more data to transfer after this */
50140Sstevel@tonic-gate cmd->cmd_done = 1;
50150Sstevel@tonic-gate }
50160Sstevel@tonic-gate
50170Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
50180Sstevel@tonic-gate "scsa2usb_handle_data_start: END %s data rval = %d",
50190Sstevel@tonic-gate (cmd->cmd_dir == USB_EP_DIR_IN) ? "bulk-in" : "bulk-out", rval);
50200Sstevel@tonic-gate
50210Sstevel@tonic-gate return (rval);
50220Sstevel@tonic-gate }
50230Sstevel@tonic-gate
50240Sstevel@tonic-gate
50250Sstevel@tonic-gate /*
50260Sstevel@tonic-gate * scsa2usb_handle_data_done:
50270Sstevel@tonic-gate * This function handles the completion of the data xfer.
50280Sstevel@tonic-gate * It also massages the inquiry data. This function may
50290Sstevel@tonic-gate * also be called after a stall.
50300Sstevel@tonic-gate */
50310Sstevel@tonic-gate void
scsa2usb_handle_data_done(scsa2usb_state_t * scsa2usbp,scsa2usb_cmd_t * cmd,usb_bulk_req_t * req)50320Sstevel@tonic-gate scsa2usb_handle_data_done(scsa2usb_state_t *scsa2usbp,
50330Sstevel@tonic-gate scsa2usb_cmd_t *cmd, usb_bulk_req_t *req)
50340Sstevel@tonic-gate {
50350Sstevel@tonic-gate struct buf *bp = cmd->cmd_bp;
50360Sstevel@tonic-gate struct scsi_pkt *pkt = scsa2usbp->scsa2usb_cur_pkt;
50370Sstevel@tonic-gate mblk_t *data = req->bulk_data;
50387492SZhigang.Lu@Sun.COM int len = data ? MBLKL(data) : 0;
50394834Sfb209375 uint32_t max_lba;
50400Sstevel@tonic-gate
50410Sstevel@tonic-gate ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
50420Sstevel@tonic-gate
50430Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
50440Sstevel@tonic-gate "scsa2usb_handle_data_done:\n\tcmd = 0x%p data = 0x%p len = 0x%x",
50456898Sfb209375 (void *)cmd, (void *)data, len);
50460Sstevel@tonic-gate
50470Sstevel@tonic-gate cmd->cmd_resid_xfercount = cmd->cmd_xfercount - len;
50480Sstevel@tonic-gate
50490Sstevel@tonic-gate if (len) {
50500Sstevel@tonic-gate uchar_t *p;
50515652Slg150142 uchar_t dtype;
50520Sstevel@tonic-gate scsa2usb_read_cap_t *cap;
50535652Slg150142 struct scsi_inquiry *inq;
50540Sstevel@tonic-gate
50550Sstevel@tonic-gate switch (cmd->cmd_cdb[SCSA2USB_OPCODE]) {
50560Sstevel@tonic-gate case SCMD_INQUIRY:
50570Sstevel@tonic-gate /*
50580Sstevel@tonic-gate * cache a copy of the inquiry data for our own use
50590Sstevel@tonic-gate * but ensure that we have at least up to
50600Sstevel@tonic-gate * inq_revision, inq_serial is not required.
50610Sstevel@tonic-gate * ignore inquiry data returned for inquiry commands
50620Sstevel@tonic-gate * with SCSI-3 EVPD, CmdDt bits set.
50630Sstevel@tonic-gate */
50640Sstevel@tonic-gate if (((cmd->cmd_cdb[SCSA2USB_LUN] & 0x1f) == 0) &&
50650Sstevel@tonic-gate (len >= SCSA2USB_MAX_INQ_LEN)) {
50665652Slg150142 inq = (struct scsi_inquiry *)data->b_rptr;
50675652Slg150142 dtype = inq->inq_dtype & DTYPE_MASK;
50685652Slg150142 /*
50695652Slg150142 * scsi framework sends zero byte write(10) cmd
50705652Slg150142 * to (Simplified) direct-access devices with
50715652Slg150142 * inquiry version > 2 for reservation changes.
50725652Slg150142 * But some USB devices don't support zero byte
50735652Slg150142 * write(10) even though they have inquiry
50745652Slg150142 * version > 2. Considering scsa2usb driver
50755652Slg150142 * doesn't support reservation and all the
50765652Slg150142 * reservation cmds are being faked, we fake
50775652Slg150142 * the inquiry version to 0 to make scsi
50785652Slg150142 * framework send test unit ready cmd which is
50795652Slg150142 * supported by all the usb devices.
50805652Slg150142 */
50815652Slg150142 if (((dtype == DTYPE_DIRECT) ||
50825652Slg150142 (dtype == DTYPE_RBC)) &&
50835652Slg150142 (inq->inq_ansi > 2)) {
50845652Slg150142 inq->inq_ansi = 0;
50855652Slg150142 }
50865652Slg150142
50870Sstevel@tonic-gate bzero(&scsa2usbp->scsa2usb_lun_inquiry
50880Sstevel@tonic-gate [pkt->pkt_address.a_lun],
50890Sstevel@tonic-gate sizeof (struct scsi_inquiry));
50900Sstevel@tonic-gate bcopy(data->b_rptr,
50910Sstevel@tonic-gate &scsa2usbp->scsa2usb_lun_inquiry
50920Sstevel@tonic-gate [pkt->pkt_address.a_lun], len);
50930Sstevel@tonic-gate }
50940Sstevel@tonic-gate
50950Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_SCSA,
50960Sstevel@tonic-gate scsa2usbp->scsa2usb_log_handle,
50970Sstevel@tonic-gate "scsi inquiry type = 0x%x",
50980Sstevel@tonic-gate scsa2usbp->scsa2usb_lun_inquiry
50990Sstevel@tonic-gate [pkt->pkt_address.a_lun].inq_dtype);
51000Sstevel@tonic-gate
51010Sstevel@tonic-gate cmd->cmd_done = 1;
51020Sstevel@tonic-gate goto handle_data;
51030Sstevel@tonic-gate
51040Sstevel@tonic-gate case SCMD_READ_CAPACITY:
51050Sstevel@tonic-gate cap = (scsa2usb_read_cap_t *)data->b_rptr;
51060Sstevel@tonic-gate
51070Sstevel@tonic-gate /* Figure out the logical block size */
51080Sstevel@tonic-gate if ((len >= sizeof (struct scsa2usb_read_cap)) &&
51090Sstevel@tonic-gate (req->bulk_completion_reason == USB_CR_OK)) {
51100Sstevel@tonic-gate scsa2usbp->
51110Sstevel@tonic-gate scsa2usb_lbasize[pkt->pkt_address.a_lun] =
51120Sstevel@tonic-gate SCSA2USB_MK_32BIT(
51134700Sfb209375 cap->scsa2usb_read_cap_blen3,
51144700Sfb209375 cap->scsa2usb_read_cap_blen2,
51154700Sfb209375 cap->scsa2usb_read_cap_blen1,
51164700Sfb209375 cap->scsa2usb_read_cap_blen0);
51170Sstevel@tonic-gate
51184834Sfb209375 max_lba = SCSA2USB_MK_32BIT(
51194834Sfb209375 cap->scsa2usb_read_cap_lba3,
51204834Sfb209375 cap->scsa2usb_read_cap_lba2,
51214834Sfb209375 cap->scsa2usb_read_cap_lba1,
51224834Sfb209375 cap->scsa2usb_read_cap_lba0);
51234834Sfb209375
51244834Sfb209375 /*
51254834Sfb209375 * Some devices return total logical block
51264834Sfb209375 * number instead of highest logical block
51274834Sfb209375 * address. Adjust the value by minus 1.
51284834Sfb209375 */
51294834Sfb209375 if (max_lba > 0 && (scsa2usbp->scsa2usb_attrs &
51304834Sfb209375 SCSA2USB_ATTRS_NO_CAP_ADJUST) == 0) {
51314834Sfb209375 max_lba -= 1;
51324834Sfb209375 cap->scsa2usb_read_cap_lba0 =
51334834Sfb209375 (uchar_t)(max_lba & 0xFF);
51344834Sfb209375 cap->scsa2usb_read_cap_lba1 =
51354834Sfb209375 (uchar_t)(max_lba >> 8 & 0xFF);
51364834Sfb209375 cap->scsa2usb_read_cap_lba2 =
51374834Sfb209375 (uchar_t)(max_lba >> 16 & 0xFF);
51384834Sfb209375 cap->scsa2usb_read_cap_lba3 =
51394834Sfb209375 (uchar_t)(max_lba >> 24 & 0xFF);
51404834Sfb209375 }
51414834Sfb209375
51424834Sfb209375 USB_DPRINTF_L2(DPRINT_MASK_SCSA,
51430Sstevel@tonic-gate scsa2usbp->scsa2usb_log_handle,
51446898Sfb209375 "bytes in each logical block=0x%lx,"
51454834Sfb209375 "number of total logical blocks=0x%x",
51464834Sfb209375 scsa2usbp->
51474834Sfb209375 scsa2usb_lbasize[pkt->pkt_address.a_lun],
51484834Sfb209375 max_lba + 1);
51490Sstevel@tonic-gate }
51500Sstevel@tonic-gate cmd->cmd_done = 1;
51510Sstevel@tonic-gate goto handle_data;
51520Sstevel@tonic-gate
51530Sstevel@tonic-gate case SCMD_REQUEST_SENSE:
51540Sstevel@tonic-gate p = data->b_rptr;
51550Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_SCSA,
51560Sstevel@tonic-gate scsa2usbp->scsa2usb_log_handle,
51570Sstevel@tonic-gate "cdb: %x rqsense: "
51580Sstevel@tonic-gate "%x %x %x %x %x %x %x %x %x %x\n\t"
51590Sstevel@tonic-gate "%x %x %x %x %x %x %x %x %x %x",
51600Sstevel@tonic-gate cmd->cmd_cdb[0],
51610Sstevel@tonic-gate p[0], p[1], p[2], p[3], p[4],
51620Sstevel@tonic-gate p[5], p[6], p[7], p[8], p[9],
51630Sstevel@tonic-gate p[10], p[11], p[12], p[13], p[14],
51640Sstevel@tonic-gate p[15], p[16], p[17], p[18], p[19]);
51650Sstevel@tonic-gate
51660Sstevel@tonic-gate scsa2usbp->scsa2usb_last_cmd.status = p[2];
51670Sstevel@tonic-gate cmd->cmd_done = 1;
51680Sstevel@tonic-gate /* FALLTHROUGH */
51690Sstevel@tonic-gate
51705789Ssl147100 default:
51710Sstevel@tonic-gate handle_data:
51720Sstevel@tonic-gate if (bp && len && (cmd->cmd_dir == USB_EP_DIR_IN)) {
51730Sstevel@tonic-gate /*
51740Sstevel@tonic-gate * we don't have to copy the data, the
51750Sstevel@tonic-gate * data pointers for the mblk_t for
51760Sstevel@tonic-gate * the bulk-in xfer points to the
51770Sstevel@tonic-gate * struct buf * data.
51780Sstevel@tonic-gate */
51790Sstevel@tonic-gate cmd->cmd_offset += len;
51800Sstevel@tonic-gate }
51810Sstevel@tonic-gate
51820Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_SCSA,
51830Sstevel@tonic-gate scsa2usbp->scsa2usb_log_handle,
51845789Ssl147100 "len = 0x%x total = 0x%lx offset = 0x%lx",
51855789Ssl147100 len, cmd->cmd_total_xfercount, cmd->cmd_offset);
51860Sstevel@tonic-gate
51870Sstevel@tonic-gate /*
51880Sstevel@tonic-gate * update total_xfercount now but it may be
51890Sstevel@tonic-gate * adjusted after receiving the residue
51900Sstevel@tonic-gate */
51910Sstevel@tonic-gate cmd->cmd_total_xfercount -= len;
51920Sstevel@tonic-gate
51930Sstevel@tonic-gate if ((req->bulk_completion_reason != USB_CR_OK) ||
51940Sstevel@tonic-gate (cmd->cmd_resid_xfercount != 0) ||
51950Sstevel@tonic-gate (cmd->cmd_total_xfercount == 0)) {
51960Sstevel@tonic-gate /* set pkt_resid to total to be sure */
51970Sstevel@tonic-gate pkt->pkt_resid = cmd->cmd_total_xfercount;
51980Sstevel@tonic-gate cmd->cmd_done = 1;
51990Sstevel@tonic-gate }
52000Sstevel@tonic-gate
52010Sstevel@tonic-gate break;
52020Sstevel@tonic-gate }
52030Sstevel@tonic-gate } else {
52040Sstevel@tonic-gate if (cmd->cmd_dir == USB_EP_DIR_OUT) {
52050Sstevel@tonic-gate if (cmd->cmd_total_xfercount == 0) {
52060Sstevel@tonic-gate cmd->cmd_done = 1;
52070Sstevel@tonic-gate }
52080Sstevel@tonic-gate }
52090Sstevel@tonic-gate }
52100Sstevel@tonic-gate }
52110Sstevel@tonic-gate
52120Sstevel@tonic-gate
52130Sstevel@tonic-gate /*
52140Sstevel@tonic-gate * scsa2usb_init_bulk_req:
52150Sstevel@tonic-gate * Allocate (synchronously) and fill in a bulk-request
52160Sstevel@tonic-gate */
52170Sstevel@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)52180Sstevel@tonic-gate scsa2usb_init_bulk_req(scsa2usb_state_t *scsa2usbp, size_t length,
52190Sstevel@tonic-gate uint_t timeout, usb_req_attrs_t attrs, usb_flags_t flags)
52200Sstevel@tonic-gate {
52210Sstevel@tonic-gate usb_bulk_req_t *req;
52220Sstevel@tonic-gate
52230Sstevel@tonic-gate ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
52240Sstevel@tonic-gate
52250Sstevel@tonic-gate req = usb_alloc_bulk_req(scsa2usbp->scsa2usb_dip, length,
52260Sstevel@tonic-gate flags | USB_FLAGS_SLEEP);
52270Sstevel@tonic-gate
52287492SZhigang.Lu@Sun.COM req->bulk_len = (uint_t)length; /* xfer length */
52290Sstevel@tonic-gate req->bulk_timeout = scsa2usb_bulk_timeout(timeout); /* xfer timeout */
52300Sstevel@tonic-gate req->bulk_attributes = attrs; /* xfer attrs */
52310Sstevel@tonic-gate req->bulk_client_private = (usb_opaque_t)scsa2usbp; /* statep */
52320Sstevel@tonic-gate
52330Sstevel@tonic-gate return (req);
52340Sstevel@tonic-gate }
52350Sstevel@tonic-gate
52360Sstevel@tonic-gate
52370Sstevel@tonic-gate /*
52380Sstevel@tonic-gate * scsa2usb_bulk_timeout:
52390Sstevel@tonic-gate * ensure that bulk requests do not have infinite timeout values
52400Sstevel@tonic-gate */
52410Sstevel@tonic-gate int
scsa2usb_bulk_timeout(int timeout)52420Sstevel@tonic-gate scsa2usb_bulk_timeout(int timeout)
52430Sstevel@tonic-gate {
52440Sstevel@tonic-gate return ((timeout == 0) ? scsa2usb_long_timeout : timeout);
52450Sstevel@tonic-gate }
52460Sstevel@tonic-gate
52470Sstevel@tonic-gate
52480Sstevel@tonic-gate /*
52490Sstevel@tonic-gate * scsa2usb_clear_ept_stall:
52500Sstevel@tonic-gate * clear endpoint stall and reset pipes
52510Sstevel@tonic-gate */
52520Sstevel@tonic-gate int
scsa2usb_clear_ept_stall(scsa2usb_state_t * scsa2usbp,uint_t ept_addr,usb_pipe_handle_t ph,char * what)52530Sstevel@tonic-gate scsa2usb_clear_ept_stall(scsa2usb_state_t *scsa2usbp, uint_t ept_addr,
52540Sstevel@tonic-gate usb_pipe_handle_t ph, char *what)
52550Sstevel@tonic-gate {
52560Sstevel@tonic-gate int rval;
52570Sstevel@tonic-gate dev_info_t *dip = scsa2usbp->scsa2usb_dip;
52580Sstevel@tonic-gate
52590Sstevel@tonic-gate ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
52600Sstevel@tonic-gate if (!(SCSA2USB_DEVICE_ACCESS_OK(scsa2usbp))) {
52610Sstevel@tonic-gate
52620Sstevel@tonic-gate return (USB_FAILURE);
52630Sstevel@tonic-gate }
52640Sstevel@tonic-gate
52650Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
52660Sstevel@tonic-gate rval = usb_clr_feature(dip, USB_DEV_REQ_RCPT_EP, 0, ept_addr,
52670Sstevel@tonic-gate USB_FLAGS_SLEEP, NULL, NULL);
52680Sstevel@tonic-gate
52690Sstevel@tonic-gate usb_pipe_reset(dip, ph, USB_FLAGS_SLEEP, NULL, NULL);
52700Sstevel@tonic-gate
52710Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
52720Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
52730Sstevel@tonic-gate "scsa2usb_clear_ept_stall: on %s: ept = 0x%x rval = %d",
52740Sstevel@tonic-gate what, ept_addr, rval);
52750Sstevel@tonic-gate
52760Sstevel@tonic-gate return (rval);
52770Sstevel@tonic-gate }
52780Sstevel@tonic-gate
52790Sstevel@tonic-gate
52800Sstevel@tonic-gate /*
52810Sstevel@tonic-gate * scsa2usb_pkt_completion:
52820Sstevel@tonic-gate * Handle pkt completion.
52830Sstevel@tonic-gate */
52840Sstevel@tonic-gate static void
scsa2usb_pkt_completion(scsa2usb_state_t * scsa2usbp,struct scsi_pkt * pkt)52850Sstevel@tonic-gate scsa2usb_pkt_completion(scsa2usb_state_t *scsa2usbp, struct scsi_pkt *pkt)
52860Sstevel@tonic-gate {
52870Sstevel@tonic-gate scsa2usb_cmd_t *cmd = PKT2CMD(pkt);
52884700Sfb209375 size_t len;
52890Sstevel@tonic-gate
52900Sstevel@tonic-gate ASSERT(pkt);
52910Sstevel@tonic-gate ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
52920Sstevel@tonic-gate
52930Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
52940Sstevel@tonic-gate "scsa2usb_pkt_completion:\n\tscsa2usbp = 0x%p "
52950Sstevel@tonic-gate "reason=%d, status=%d state=0x%x stats=0x%x resid=0x%lx",
52966898Sfb209375 (void *)scsa2usbp, pkt->pkt_reason, *(pkt->pkt_scbp),
52970Sstevel@tonic-gate pkt->pkt_state, pkt->pkt_statistics, pkt->pkt_resid);
52980Sstevel@tonic-gate
52990Sstevel@tonic-gate if (pkt->pkt_reason == CMD_CMPLT) {
53000Sstevel@tonic-gate pkt->pkt_state |= STATE_GOT_BUS | STATE_GOT_TARGET |
53014700Sfb209375 STATE_SENT_CMD | STATE_GOT_STATUS;
53020Sstevel@tonic-gate if (cmd->cmd_xfercount) {
53030Sstevel@tonic-gate pkt->pkt_state |= STATE_XFERRED_DATA;
53040Sstevel@tonic-gate }
53050Sstevel@tonic-gate } else {
53060Sstevel@tonic-gate pkt->pkt_state |= STATE_GOT_BUS | STATE_GOT_TARGET |
53074700Sfb209375 STATE_SENT_CMD;
53080Sstevel@tonic-gate }
53090Sstevel@tonic-gate
53100Sstevel@tonic-gate /*
53110Sstevel@tonic-gate * don't zap the current state when in panic as this will
53120Sstevel@tonic-gate * make debugging harder
53130Sstevel@tonic-gate */
53140Sstevel@tonic-gate if ((scsa2usbp->scsa2usb_cur_pkt == pkt) && !ddi_in_panic()) {
53150Sstevel@tonic-gate SCSA2USB_RESET_CUR_PKT(scsa2usbp);
53160Sstevel@tonic-gate
53174700Sfb209375 len = sizeof (scsa2usbp->scsa2usb_last_cmd.cdb);
53184700Sfb209375 bzero(scsa2usbp->scsa2usb_last_cmd.cdb, len);
53194700Sfb209375
53204700Sfb209375 len = (len < cmd->cmd_cdblen) ? len : cmd->cmd_cdblen;
53214700Sfb209375 USB_DPRINTF_L3(DPRINT_MASK_SCSA,
53224700Sfb209375 scsa2usbp->scsa2usb_log_handle,
53236898Sfb209375 "scsa2usb_pkt_completion: save last cmd, len=%ld", len);
53244700Sfb209375
53250Sstevel@tonic-gate /* save the last command */
53264700Sfb209375 bcopy(pkt->pkt_cdbp, scsa2usbp->scsa2usb_last_cmd.cdb, len);
53270Sstevel@tonic-gate
53280Sstevel@tonic-gate /* reset the scsa2usb_last_cmd.status value */
53290Sstevel@tonic-gate if ((pkt->pkt_cdbp[0] != SCMD_REQUEST_SENSE) &&
53300Sstevel@tonic-gate (pkt->pkt_cdbp[0] != SCMD_INQUIRY)) {
53310Sstevel@tonic-gate scsa2usbp->scsa2usb_last_cmd.status = 0;
53320Sstevel@tonic-gate }
53330Sstevel@tonic-gate
53340Sstevel@tonic-gate /*
53350Sstevel@tonic-gate * set pkt state to NONE *before* calling back as the target
53360Sstevel@tonic-gate * driver will immediately submit the next packet
53370Sstevel@tonic-gate */
53380Sstevel@tonic-gate scsa2usbp->scsa2usb_pkt_state = SCSA2USB_PKT_NONE;
53390Sstevel@tonic-gate }
53400Sstevel@tonic-gate
53410Sstevel@tonic-gate if (pkt->pkt_comp) {
53420Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
53439106SSrivijitha.Dugganapalli@Sun.COM scsi_hba_pkt_comp(pkt);
53440Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
53450Sstevel@tonic-gate
53460Sstevel@tonic-gate }
53470Sstevel@tonic-gate }
53480Sstevel@tonic-gate
53490Sstevel@tonic-gate
53500Sstevel@tonic-gate /*
53510Sstevel@tonic-gate * Even handling functions:
53520Sstevel@tonic-gate *
53530Sstevel@tonic-gate * scsa2usb_reconnect_event_cb:
53540Sstevel@tonic-gate * event handling
53550Sstevel@tonic-gate */
53560Sstevel@tonic-gate static int
scsa2usb_reconnect_event_cb(dev_info_t * dip)53570Sstevel@tonic-gate scsa2usb_reconnect_event_cb(dev_info_t *dip)
53580Sstevel@tonic-gate {
53590Sstevel@tonic-gate scsa2usb_state_t *scsa2usbp =
53600Sstevel@tonic-gate ddi_get_soft_state(scsa2usb_statep, ddi_get_instance(dip));
53610Sstevel@tonic-gate dev_info_t *cdip;
53620Sstevel@tonic-gate int circ;
53630Sstevel@tonic-gate int rval = USB_SUCCESS;
53640Sstevel@tonic-gate
53650Sstevel@tonic-gate ASSERT(scsa2usbp != NULL);
53660Sstevel@tonic-gate
53670Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
53686898Sfb209375 "scsa2usb_reconnect_event_cb: dip = 0x%p", (void *)dip);
53690Sstevel@tonic-gate
53700Sstevel@tonic-gate scsa2usb_restore_device_state(dip, scsa2usbp);
53710Sstevel@tonic-gate
5372880Sfrits USB_DPRINTF_L0(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
5373880Sfrits "Reinserted device is accessible again.");
5374880Sfrits
53750Sstevel@tonic-gate ndi_devi_enter(dip, &circ);
53760Sstevel@tonic-gate for (cdip = ddi_get_child(dip); cdip; ) {
53770Sstevel@tonic-gate dev_info_t *next = ddi_get_next_sibling(cdip);
53780Sstevel@tonic-gate
53790Sstevel@tonic-gate mutex_enter(&DEVI(cdip)->devi_lock);
53800Sstevel@tonic-gate DEVI_SET_DEVICE_REINSERTED(cdip);
53810Sstevel@tonic-gate mutex_exit(&DEVI(cdip)->devi_lock);
53820Sstevel@tonic-gate
53830Sstevel@tonic-gate cdip = next;
53840Sstevel@tonic-gate }
53850Sstevel@tonic-gate ndi_devi_exit(dip, circ);
53860Sstevel@tonic-gate
53870Sstevel@tonic-gate /* stop suppressing warnings */
53880Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
53890Sstevel@tonic-gate scsa2usbp->scsa2usb_warning_given = B_FALSE;
53900Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
53910Sstevel@tonic-gate
53920Sstevel@tonic-gate if (scsa2usbp->scsa2usb_ugen_hdl) {
53930Sstevel@tonic-gate rval = usb_ugen_reconnect_ev_cb(
53944700Sfb209375 scsa2usbp->scsa2usb_ugen_hdl);
53950Sstevel@tonic-gate }
53960Sstevel@tonic-gate
53970Sstevel@tonic-gate return (rval);
53980Sstevel@tonic-gate }
53990Sstevel@tonic-gate
54000Sstevel@tonic-gate
54010Sstevel@tonic-gate /*
54020Sstevel@tonic-gate * scsa2usb_all_waitQs_empty:
54030Sstevel@tonic-gate * check if all waitQs empty
54040Sstevel@tonic-gate */
54050Sstevel@tonic-gate static int
scsa2usb_all_waitQs_empty(scsa2usb_state_t * scsa2usbp)54060Sstevel@tonic-gate scsa2usb_all_waitQs_empty(scsa2usb_state_t *scsa2usbp)
54070Sstevel@tonic-gate {
54080Sstevel@tonic-gate uint_t lun;
54090Sstevel@tonic-gate
54100Sstevel@tonic-gate for (lun = 0; lun < SCSA2USB_MAX_LUNS; lun++) {
54110Sstevel@tonic-gate if (usba_list_entry_count(
54120Sstevel@tonic-gate &scsa2usbp->scsa2usb_waitQ[lun])) {
54130Sstevel@tonic-gate
54140Sstevel@tonic-gate return (USB_FAILURE);
54150Sstevel@tonic-gate }
54160Sstevel@tonic-gate }
54170Sstevel@tonic-gate
54180Sstevel@tonic-gate return (USB_SUCCESS);
54190Sstevel@tonic-gate }
54200Sstevel@tonic-gate
54210Sstevel@tonic-gate
54220Sstevel@tonic-gate /*
54230Sstevel@tonic-gate * scsa2usb_disconnect_event_cb:
54240Sstevel@tonic-gate * callback for disconnect events
54250Sstevel@tonic-gate */
54260Sstevel@tonic-gate static int
scsa2usb_disconnect_event_cb(dev_info_t * dip)54270Sstevel@tonic-gate scsa2usb_disconnect_event_cb(dev_info_t *dip)
54280Sstevel@tonic-gate {
54290Sstevel@tonic-gate scsa2usb_state_t *scsa2usbp =
54300Sstevel@tonic-gate ddi_get_soft_state(scsa2usb_statep, ddi_get_instance(dip));
54310Sstevel@tonic-gate dev_info_t *cdip;
54320Sstevel@tonic-gate int circ, i;
54330Sstevel@tonic-gate int rval = USB_SUCCESS;
54340Sstevel@tonic-gate
54350Sstevel@tonic-gate ASSERT(scsa2usbp != NULL);
54360Sstevel@tonic-gate
54370Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
54386898Sfb209375 "scsa2usb_disconnect_event_cb: dip = 0x%p", (void *)dip);
54390Sstevel@tonic-gate
54400Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
54410Sstevel@tonic-gate scsa2usbp->scsa2usb_dev_state = USB_DEV_DISCONNECTED;
54420Sstevel@tonic-gate
54430Sstevel@tonic-gate /*
54440Sstevel@tonic-gate * wait till the work thread is done, carry on regardless
54450Sstevel@tonic-gate * if not.
54460Sstevel@tonic-gate */
54470Sstevel@tonic-gate for (i = 0; i < SCSA2USB_DRAIN_TIMEOUT; i++) {
54480Sstevel@tonic-gate if ((scsa2usbp->scsa2usb_work_thread_id == NULL) &&
54490Sstevel@tonic-gate (scsa2usbp->scsa2usb_cur_pkt == NULL) &&
54500Sstevel@tonic-gate (scsa2usb_all_waitQs_empty(scsa2usbp) ==
54510Sstevel@tonic-gate USB_SUCCESS)) {
54520Sstevel@tonic-gate
54530Sstevel@tonic-gate break;
54540Sstevel@tonic-gate }
54550Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
54560Sstevel@tonic-gate delay(drv_usectohz(1000000));
54570Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
54580Sstevel@tonic-gate }
54590Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
54600Sstevel@tonic-gate
54610Sstevel@tonic-gate ndi_devi_enter(dip, &circ);
54620Sstevel@tonic-gate for (cdip = ddi_get_child(dip); cdip; ) {
54630Sstevel@tonic-gate dev_info_t *next = ddi_get_next_sibling(cdip);
54640Sstevel@tonic-gate
54650Sstevel@tonic-gate mutex_enter(&DEVI(cdip)->devi_lock);
54660Sstevel@tonic-gate DEVI_SET_DEVICE_REMOVED(cdip);
54670Sstevel@tonic-gate mutex_exit(&DEVI(cdip)->devi_lock);
54680Sstevel@tonic-gate
54690Sstevel@tonic-gate cdip = next;
54700Sstevel@tonic-gate }
54710Sstevel@tonic-gate ndi_devi_exit(dip, circ);
54720Sstevel@tonic-gate
54730Sstevel@tonic-gate if (scsa2usbp->scsa2usb_ugen_hdl) {
54740Sstevel@tonic-gate rval = usb_ugen_disconnect_ev_cb(
54754700Sfb209375 scsa2usbp->scsa2usb_ugen_hdl);
54760Sstevel@tonic-gate }
54770Sstevel@tonic-gate
54780Sstevel@tonic-gate return (rval);
54790Sstevel@tonic-gate }
54800Sstevel@tonic-gate
54810Sstevel@tonic-gate
54820Sstevel@tonic-gate /*
54830Sstevel@tonic-gate * PM support
54840Sstevel@tonic-gate *
54850Sstevel@tonic-gate * scsa2usb_create_pm_components:
54860Sstevel@tonic-gate * create the pm components required for power management
54870Sstevel@tonic-gate * no mutex is need when calling USBA interfaces
54880Sstevel@tonic-gate */
54890Sstevel@tonic-gate static void
scsa2usb_create_pm_components(dev_info_t * dip,scsa2usb_state_t * scsa2usbp)54900Sstevel@tonic-gate scsa2usb_create_pm_components(dev_info_t *dip, scsa2usb_state_t *scsa2usbp)
54910Sstevel@tonic-gate {
54920Sstevel@tonic-gate scsa2usb_power_t *pm;
54930Sstevel@tonic-gate uint_t pwr_states;
54940Sstevel@tonic-gate
54950Sstevel@tonic-gate ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
54960Sstevel@tonic-gate
54970Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_PM, scsa2usbp->scsa2usb_log_handle,
54980Sstevel@tonic-gate "scsa2usb_create_pm_components: dip = 0x%p, scsa2usbp = 0x%p",
54996898Sfb209375 (void *)dip, (void *)scsa2usbp);
55000Sstevel@tonic-gate
55010Sstevel@tonic-gate /*
55020Sstevel@tonic-gate * determine if this device is on the blacklist
55030Sstevel@tonic-gate * or if a conf file entry has disabled PM
55040Sstevel@tonic-gate */
55050Sstevel@tonic-gate if ((scsa2usbp->scsa2usb_attrs & SCSA2USB_ATTRS_PM) == 0) {
55060Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_PM, scsa2usbp->scsa2usb_log_handle,
55070Sstevel@tonic-gate "device cannot be power managed");
55080Sstevel@tonic-gate
55090Sstevel@tonic-gate return;
55100Sstevel@tonic-gate }
55110Sstevel@tonic-gate
55120Sstevel@tonic-gate /* Allocate the PM state structure */
55130Sstevel@tonic-gate pm = kmem_zalloc(sizeof (scsa2usb_power_t), KM_SLEEP);
55140Sstevel@tonic-gate
55150Sstevel@tonic-gate scsa2usbp->scsa2usb_pm = pm;
55160Sstevel@tonic-gate pm->scsa2usb_current_power = USB_DEV_OS_FULL_PWR;
55170Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
55180Sstevel@tonic-gate
55190Sstevel@tonic-gate if (usb_create_pm_components(dip, &pwr_states) ==
55200Sstevel@tonic-gate USB_SUCCESS) {
55210Sstevel@tonic-gate if (usb_handle_remote_wakeup(dip,
55220Sstevel@tonic-gate USB_REMOTE_WAKEUP_ENABLE) == USB_SUCCESS) {
55230Sstevel@tonic-gate pm->scsa2usb_wakeup_enabled = 1;
55240Sstevel@tonic-gate }
55250Sstevel@tonic-gate
55260Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
55270Sstevel@tonic-gate pm->scsa2usb_pwr_states = (uint8_t)pwr_states;
5528189Sfrits scsa2usb_raise_power(scsa2usbp);
55290Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
55300Sstevel@tonic-gate }
55310Sstevel@tonic-gate
55320Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
55330Sstevel@tonic-gate }
55340Sstevel@tonic-gate
55350Sstevel@tonic-gate
55360Sstevel@tonic-gate /*
55370Sstevel@tonic-gate * scsa2usb_raise_power:
55380Sstevel@tonic-gate * check if the device is using full power or not
55390Sstevel@tonic-gate */
55400Sstevel@tonic-gate static void
scsa2usb_raise_power(scsa2usb_state_t * scsa2usbp)55410Sstevel@tonic-gate scsa2usb_raise_power(scsa2usb_state_t *scsa2usbp)
55420Sstevel@tonic-gate {
55430Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_PM, scsa2usbp->scsa2usb_log_handle,
55440Sstevel@tonic-gate "scsa2usb_raise_power:");
55450Sstevel@tonic-gate
55460Sstevel@tonic-gate ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
55470Sstevel@tonic-gate
55480Sstevel@tonic-gate if (scsa2usbp->scsa2usb_pm) {
55490Sstevel@tonic-gate scsa2usb_pm_busy_component(scsa2usbp);
5550189Sfrits if (scsa2usbp->scsa2usb_pm->scsa2usb_current_power !=
5551189Sfrits USB_DEV_OS_FULL_PWR) {
55520Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
55530Sstevel@tonic-gate (void) pm_raise_power(scsa2usbp->scsa2usb_dip,
55540Sstevel@tonic-gate 0, USB_DEV_OS_FULL_PWR);
55550Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
55560Sstevel@tonic-gate }
55570Sstevel@tonic-gate }
55580Sstevel@tonic-gate }
55590Sstevel@tonic-gate
55600Sstevel@tonic-gate
55610Sstevel@tonic-gate /*
55620Sstevel@tonic-gate * functions to handle power transition for OS levels 0 -> 3
55630Sstevel@tonic-gate */
55640Sstevel@tonic-gate static int
scsa2usb_pwrlvl0(scsa2usb_state_t * scsa2usbp)55650Sstevel@tonic-gate scsa2usb_pwrlvl0(scsa2usb_state_t *scsa2usbp)
55660Sstevel@tonic-gate {
55670Sstevel@tonic-gate int rval;
55680Sstevel@tonic-gate
55690Sstevel@tonic-gate switch (scsa2usbp->scsa2usb_dev_state) {
55700Sstevel@tonic-gate case USB_DEV_ONLINE:
55710Sstevel@tonic-gate /* Deny the powerdown request if the device is busy */
55720Sstevel@tonic-gate if (scsa2usbp->scsa2usb_pm->scsa2usb_pm_busy != 0) {
55730Sstevel@tonic-gate
55740Sstevel@tonic-gate return (USB_FAILURE);
55750Sstevel@tonic-gate }
55760Sstevel@tonic-gate
55770Sstevel@tonic-gate /*
55780Sstevel@tonic-gate * stop polling on interrupt pipe
55790Sstevel@tonic-gate */
55800Sstevel@tonic-gate scsa2usb_cbi_stop_intr_polling(scsa2usbp);
55810Sstevel@tonic-gate
55820Sstevel@tonic-gate /* Issue USB D3 command to the device here */
55830Sstevel@tonic-gate rval = usb_set_device_pwrlvl3(scsa2usbp->scsa2usb_dip);
55840Sstevel@tonic-gate ASSERT(rval == USB_SUCCESS);
55850Sstevel@tonic-gate
55860Sstevel@tonic-gate scsa2usbp->scsa2usb_dev_state = USB_DEV_PWRED_DOWN;
55870Sstevel@tonic-gate
55880Sstevel@tonic-gate /* FALLTHRU */
55890Sstevel@tonic-gate case USB_DEV_DISCONNECTED:
55900Sstevel@tonic-gate case USB_DEV_SUSPENDED:
55910Sstevel@tonic-gate case USB_DEV_PWRED_DOWN:
55920Sstevel@tonic-gate default:
55930Sstevel@tonic-gate scsa2usbp->scsa2usb_pm->scsa2usb_current_power =
55944700Sfb209375 USB_DEV_OS_PWR_OFF;
55950Sstevel@tonic-gate
55960Sstevel@tonic-gate return (USB_SUCCESS);
55970Sstevel@tonic-gate }
55980Sstevel@tonic-gate }
55990Sstevel@tonic-gate
56000Sstevel@tonic-gate
56010Sstevel@tonic-gate static int
scsa2usb_pwrlvl1(scsa2usb_state_t * scsa2usbp)56020Sstevel@tonic-gate scsa2usb_pwrlvl1(scsa2usb_state_t *scsa2usbp)
56030Sstevel@tonic-gate {
56040Sstevel@tonic-gate int rval;
56050Sstevel@tonic-gate
56060Sstevel@tonic-gate /* Issue USB D2 command to the device here */
56070Sstevel@tonic-gate rval = usb_set_device_pwrlvl2(scsa2usbp->scsa2usb_dip);
56080Sstevel@tonic-gate ASSERT(rval == USB_SUCCESS);
56090Sstevel@tonic-gate
56100Sstevel@tonic-gate return (DDI_FAILURE);
56110Sstevel@tonic-gate }
56120Sstevel@tonic-gate
56130Sstevel@tonic-gate
56140Sstevel@tonic-gate static int
scsa2usb_pwrlvl2(scsa2usb_state_t * scsa2usbp)56150Sstevel@tonic-gate scsa2usb_pwrlvl2(scsa2usb_state_t *scsa2usbp)
56160Sstevel@tonic-gate {
56170Sstevel@tonic-gate int rval;
56180Sstevel@tonic-gate
56190Sstevel@tonic-gate /* Issue USB D1 command to the device here */
56200Sstevel@tonic-gate rval = usb_set_device_pwrlvl1(scsa2usbp->scsa2usb_dip);
56210Sstevel@tonic-gate ASSERT(rval == USB_SUCCESS);
56220Sstevel@tonic-gate
56230Sstevel@tonic-gate return (DDI_FAILURE);
56240Sstevel@tonic-gate }
56250Sstevel@tonic-gate
56260Sstevel@tonic-gate
56270Sstevel@tonic-gate static int
scsa2usb_pwrlvl3(scsa2usb_state_t * scsa2usbp)56280Sstevel@tonic-gate scsa2usb_pwrlvl3(scsa2usb_state_t *scsa2usbp)
56290Sstevel@tonic-gate {
56300Sstevel@tonic-gate int rval;
56310Sstevel@tonic-gate
56320Sstevel@tonic-gate /*
56330Sstevel@tonic-gate * PM framework tries to put us in full power
56340Sstevel@tonic-gate * during system shutdown. If we are disconnected
56350Sstevel@tonic-gate * return success anyways
56360Sstevel@tonic-gate */
56370Sstevel@tonic-gate if (scsa2usbp->scsa2usb_dev_state != USB_DEV_DISCONNECTED) {
56380Sstevel@tonic-gate /* Issue USB D0 command to the device here */
56390Sstevel@tonic-gate rval = usb_set_device_pwrlvl0(scsa2usbp->scsa2usb_dip);
56400Sstevel@tonic-gate ASSERT(rval == USB_SUCCESS);
56410Sstevel@tonic-gate
56420Sstevel@tonic-gate scsa2usbp->scsa2usb_dev_state = USB_DEV_ONLINE;
56430Sstevel@tonic-gate }
56440Sstevel@tonic-gate scsa2usbp->scsa2usb_pm->scsa2usb_current_power = USB_DEV_OS_FULL_PWR;
56450Sstevel@tonic-gate
56460Sstevel@tonic-gate return (DDI_SUCCESS);
56470Sstevel@tonic-gate }
56480Sstevel@tonic-gate
56490Sstevel@tonic-gate
56500Sstevel@tonic-gate /*
56510Sstevel@tonic-gate * scsa2usb_power:
56520Sstevel@tonic-gate * power entry point
56530Sstevel@tonic-gate */
56540Sstevel@tonic-gate /* ARGSUSED */
56550Sstevel@tonic-gate static int
scsa2usb_power(dev_info_t * dip,int comp,int level)56560Sstevel@tonic-gate scsa2usb_power(dev_info_t *dip, int comp, int level)
56570Sstevel@tonic-gate {
56580Sstevel@tonic-gate scsa2usb_state_t *scsa2usbp;
56590Sstevel@tonic-gate scsa2usb_power_t *pm;
56600Sstevel@tonic-gate int rval = DDI_FAILURE;
56610Sstevel@tonic-gate
56620Sstevel@tonic-gate scsa2usbp = ddi_get_soft_state(scsa2usb_statep, ddi_get_instance(dip));
56630Sstevel@tonic-gate
56640Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_PM, scsa2usbp->scsa2usb_log_handle,
56650Sstevel@tonic-gate "scsa2usb_power: Begin scsa2usbp (%p): level = %d",
56666898Sfb209375 (void *)scsa2usbp, level);
56670Sstevel@tonic-gate
56680Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
56690Sstevel@tonic-gate if (SCSA2USB_BUSY(scsa2usbp)) {
56700Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_PM, scsa2usbp->scsa2usb_log_handle,
56710Sstevel@tonic-gate "scsa2usb_power: busy");
56720Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
56730Sstevel@tonic-gate
56740Sstevel@tonic-gate return (rval);
56750Sstevel@tonic-gate }
56760Sstevel@tonic-gate
56770Sstevel@tonic-gate pm = scsa2usbp->scsa2usb_pm;
56780Sstevel@tonic-gate if (pm == NULL) {
56790Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_PM, scsa2usbp->scsa2usb_log_handle,
56800Sstevel@tonic-gate "scsa2usb_power: pm NULL");
56810Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
56820Sstevel@tonic-gate
56830Sstevel@tonic-gate return (rval);
56840Sstevel@tonic-gate }
56850Sstevel@tonic-gate
56860Sstevel@tonic-gate /* check if we are transitioning to a legal power level */
56870Sstevel@tonic-gate if (USB_DEV_PWRSTATE_OK(pm->scsa2usb_pwr_states, level)) {
56880Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_PM, scsa2usbp->scsa2usb_log_handle,
56890Sstevel@tonic-gate "scsa2usb_power: illegal power level = %d "
56900Sstevel@tonic-gate "pwr_states: %x", level, pm->scsa2usb_pwr_states);
56910Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
56920Sstevel@tonic-gate
56930Sstevel@tonic-gate return (rval);
56940Sstevel@tonic-gate }
56950Sstevel@tonic-gate
56960Sstevel@tonic-gate switch (level) {
56970Sstevel@tonic-gate case USB_DEV_OS_PWR_OFF :
56980Sstevel@tonic-gate rval = scsa2usb_pwrlvl0(scsa2usbp);
56990Sstevel@tonic-gate break;
57000Sstevel@tonic-gate case USB_DEV_OS_PWR_1 :
57010Sstevel@tonic-gate rval = scsa2usb_pwrlvl1(scsa2usbp);
57020Sstevel@tonic-gate break;
57030Sstevel@tonic-gate case USB_DEV_OS_PWR_2 :
57040Sstevel@tonic-gate rval = scsa2usb_pwrlvl2(scsa2usbp);
57050Sstevel@tonic-gate break;
57060Sstevel@tonic-gate case USB_DEV_OS_FULL_PWR :
57070Sstevel@tonic-gate rval = scsa2usb_pwrlvl3(scsa2usbp);
57080Sstevel@tonic-gate break;
57090Sstevel@tonic-gate }
57100Sstevel@tonic-gate
57110Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
57120Sstevel@tonic-gate
57130Sstevel@tonic-gate return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
57140Sstevel@tonic-gate }
57150Sstevel@tonic-gate
57160Sstevel@tonic-gate
57170Sstevel@tonic-gate static void
scsa2usb_pm_busy_component(scsa2usb_state_t * scsa2usbp)5718189Sfrits scsa2usb_pm_busy_component(scsa2usb_state_t *scsa2usbp)
57190Sstevel@tonic-gate {
5720189Sfrits ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
5721189Sfrits
5722189Sfrits if (scsa2usbp->scsa2usb_pm) {
5723189Sfrits scsa2usbp->scsa2usb_pm->scsa2usb_pm_busy++;
5724189Sfrits
5725189Sfrits USB_DPRINTF_L4(DPRINT_MASK_PM,
5726189Sfrits scsa2usbp->scsa2usb_log_handle,
5727189Sfrits "scsa2usb_pm_busy_component: %d",
5728189Sfrits scsa2usbp->scsa2usb_pm->scsa2usb_pm_busy);
5729189Sfrits
5730189Sfrits mutex_exit(&scsa2usbp->scsa2usb_mutex);
5731189Sfrits
5732189Sfrits if (pm_busy_component(scsa2usbp->scsa2usb_dip, 0) !=
5733189Sfrits DDI_SUCCESS) {
5734189Sfrits mutex_enter(&scsa2usbp->scsa2usb_mutex);
5735189Sfrits ASSERT(scsa2usbp->scsa2usb_pm->scsa2usb_pm_busy > 0);
5736189Sfrits scsa2usbp->scsa2usb_pm->scsa2usb_pm_busy--;
5737189Sfrits
5738189Sfrits USB_DPRINTF_L2(DPRINT_MASK_PM,
5739189Sfrits scsa2usbp->scsa2usb_log_handle,
5740189Sfrits "scsa2usb_pm_busy_component failed: %d",
5741189Sfrits scsa2usbp->scsa2usb_pm->scsa2usb_pm_busy);
5742189Sfrits
5743189Sfrits return;
5744189Sfrits }
5745189Sfrits mutex_enter(&scsa2usbp->scsa2usb_mutex);
57460Sstevel@tonic-gate }
57470Sstevel@tonic-gate }
57480Sstevel@tonic-gate
57490Sstevel@tonic-gate
57500Sstevel@tonic-gate /*
57510Sstevel@tonic-gate * scsa2usb_pm_idle_component:
57520Sstevel@tonic-gate * idles the device
57530Sstevel@tonic-gate */
57540Sstevel@tonic-gate static void
scsa2usb_pm_idle_component(scsa2usb_state_t * scsa2usbp)57550Sstevel@tonic-gate scsa2usb_pm_idle_component(scsa2usb_state_t *scsa2usbp)
57560Sstevel@tonic-gate {
5757189Sfrits ASSERT(!mutex_owned(&scsa2usbp->scsa2usb_mutex));
5758189Sfrits
57590Sstevel@tonic-gate if (scsa2usbp->scsa2usb_pm) {
57600Sstevel@tonic-gate if (pm_idle_component(scsa2usbp->scsa2usb_dip, 0) ==
57610Sstevel@tonic-gate DDI_SUCCESS) {
57620Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
57630Sstevel@tonic-gate ASSERT(scsa2usbp->scsa2usb_pm->scsa2usb_pm_busy > 0);
57640Sstevel@tonic-gate scsa2usbp->scsa2usb_pm->scsa2usb_pm_busy--;
5765189Sfrits
5766189Sfrits USB_DPRINTF_L4(DPRINT_MASK_PM,
5767189Sfrits scsa2usbp->scsa2usb_log_handle,
5768189Sfrits "scsa2usb_pm_idle_component: %d",
5769189Sfrits scsa2usbp->scsa2usb_pm->scsa2usb_pm_busy);
5770189Sfrits
57710Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
57720Sstevel@tonic-gate }
57730Sstevel@tonic-gate }
57740Sstevel@tonic-gate }
57750Sstevel@tonic-gate
57760Sstevel@tonic-gate
57770Sstevel@tonic-gate #ifdef DEBUG
57780Sstevel@tonic-gate /*
57790Sstevel@tonic-gate * scsa2usb_print_cdb:
57800Sstevel@tonic-gate * prints CDB
57810Sstevel@tonic-gate */
57820Sstevel@tonic-gate void
scsa2usb_print_cdb(scsa2usb_state_t * scsa2usbp,scsa2usb_cmd_t * cmd)57830Sstevel@tonic-gate scsa2usb_print_cdb(scsa2usb_state_t *scsa2usbp, scsa2usb_cmd_t *cmd)
57840Sstevel@tonic-gate {
57850Sstevel@tonic-gate uchar_t *c = (uchar_t *)&cmd->cmd_cdb;
57860Sstevel@tonic-gate
57870Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
57880Sstevel@tonic-gate "cmd = 0x%p opcode=%s "
57890Sstevel@tonic-gate "cdb: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x",
57906898Sfb209375 (void *)cmd,
57916898Sfb209375 scsi_cname(cmd->cmd_cdb[SCSA2USB_OPCODE], scsa2usb_cmds),
57920Sstevel@tonic-gate c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7], c[8],
57930Sstevel@tonic-gate c[9], c[10], c[11], c[12], c[13], c[14], c[15]);
57940Sstevel@tonic-gate }
57950Sstevel@tonic-gate #endif /* DEBUG */
57960Sstevel@tonic-gate
57970Sstevel@tonic-gate
57980Sstevel@tonic-gate #ifdef SCSA2USB_BULK_ONLY_TEST
57990Sstevel@tonic-gate /*
58000Sstevel@tonic-gate * scsa2usb_test_mblk:
58010Sstevel@tonic-gate * This function sends a dummy data mblk_t to simulate
58020Sstevel@tonic-gate * the following test cases: 5 and 11.
58030Sstevel@tonic-gate */
58040Sstevel@tonic-gate static void
scsa2usb_test_mblk(scsa2usb_state_t * scsa2usbp,boolean_t large)58050Sstevel@tonic-gate scsa2usb_test_mblk(scsa2usb_state_t *scsa2usbp, boolean_t large)
58060Sstevel@tonic-gate {
58070Sstevel@tonic-gate int i, rval;
58080Sstevel@tonic-gate size_t len;
58090Sstevel@tonic-gate usb_flags_t flags = USB_FLAGS_SLEEP;
58100Sstevel@tonic-gate usb_bulk_req_t *req;
58110Sstevel@tonic-gate
58120Sstevel@tonic-gate ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
58130Sstevel@tonic-gate
58140Sstevel@tonic-gate /* should we create a larger mblk? */
58150Sstevel@tonic-gate len = (large == B_TRUE) ? DEV_BSIZE : USB_BULK_CBWCMD_LEN;
58160Sstevel@tonic-gate
58170Sstevel@tonic-gate req = scsa2usb_init_bulk_req(scsa2usbp, len,
58184700Sfb209375 SCSA2USB_BULK_PIPE_TIMEOUT, 0, flags);
58190Sstevel@tonic-gate
58200Sstevel@tonic-gate /* fill up the data mblk */
58210Sstevel@tonic-gate for (i = 0; i < len; i++) {
58220Sstevel@tonic-gate *req->bulk_data->b_wptr++ = (uchar_t)i;
58230Sstevel@tonic-gate }
58240Sstevel@tonic-gate
58250Sstevel@tonic-gate mutex_exit(&scsa2usbp->scsa2usb_mutex);
58260Sstevel@tonic-gate ASSERT(req->bulk_timeout);
58270Sstevel@tonic-gate rval = usb_pipe_bulk_xfer(scsa2usbp->scsa2usb_bulkout_pipe, req, flags);
58280Sstevel@tonic-gate mutex_enter(&scsa2usbp->scsa2usb_mutex);
58290Sstevel@tonic-gate
58300Sstevel@tonic-gate USB_DPRINTF_L1(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
58310Sstevel@tonic-gate "scsa2usb_test_mblk: Sent Data Out rval = 0x%x", rval);
58320Sstevel@tonic-gate
58330Sstevel@tonic-gate usb_free_bulk_req(req);
58340Sstevel@tonic-gate }
58350Sstevel@tonic-gate #endif /* SCSA2USB_BULK_ONLY_TEST */
5836