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