10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 220Sstevel@tonic-gate /* 230Sstevel@tonic-gate * Enclosure Services Device target driver 240Sstevel@tonic-gate * 250Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 260Sstevel@tonic-gate * Use is subject to license terms. 270Sstevel@tonic-gate */ 280Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 290Sstevel@tonic-gate 300Sstevel@tonic-gate #include <sys/modctl.h> 310Sstevel@tonic-gate #include <sys/file.h> 320Sstevel@tonic-gate #include <sys/stat.h> 330Sstevel@tonic-gate #include <sys/scsi/scsi.h> 340Sstevel@tonic-gate #include <sys/scsi/generic/status.h> 350Sstevel@tonic-gate #include <sys/scsi/targets/sesio.h> 360Sstevel@tonic-gate #include <sys/scsi/targets/ses.h> 370Sstevel@tonic-gate 380Sstevel@tonic-gate 390Sstevel@tonic-gate 400Sstevel@tonic-gate /* 410Sstevel@tonic-gate * Power management defines (should be in a common include file?) 420Sstevel@tonic-gate */ 430Sstevel@tonic-gate #define PM_HARDWARE_STATE_PROP "pm-hardware-state" 440Sstevel@tonic-gate #define PM_NEEDS_SUSPEND_RESUME "needs-suspend-resume" 450Sstevel@tonic-gate 460Sstevel@tonic-gate 470Sstevel@tonic-gate /* 480Sstevel@tonic-gate * Global Driver Data 490Sstevel@tonic-gate */ 500Sstevel@tonic-gate int ses_io_time = SES_IO_TIME; 510Sstevel@tonic-gate 520Sstevel@tonic-gate static int ses_retry_count = SES_RETRY_COUNT * SES_RETRY_MULTIPLIER; 530Sstevel@tonic-gate 540Sstevel@tonic-gate #ifdef DEBUG 550Sstevel@tonic-gate int ses_debug = 0; 560Sstevel@tonic-gate #else /* DEBUG */ 570Sstevel@tonic-gate #define ses_debug 0 580Sstevel@tonic-gate #endif /* DEBUG */ 590Sstevel@tonic-gate 600Sstevel@tonic-gate 610Sstevel@tonic-gate /* 620Sstevel@tonic-gate * External Enclosure Functions 630Sstevel@tonic-gate */ 640Sstevel@tonic-gate extern int ses_softc_init(ses_softc_t *, int); 650Sstevel@tonic-gate extern int ses_init_enc(ses_softc_t *); 660Sstevel@tonic-gate extern int ses_get_encstat(ses_softc_t *, int); 670Sstevel@tonic-gate extern int ses_set_encstat(ses_softc_t *, uchar_t, int); 680Sstevel@tonic-gate extern int ses_get_objstat(ses_softc_t *, ses_objarg *, int); 690Sstevel@tonic-gate extern int ses_set_objstat(ses_softc_t *, ses_objarg *, int); 700Sstevel@tonic-gate 710Sstevel@tonic-gate extern int safte_softc_init(ses_softc_t *, int); 720Sstevel@tonic-gate extern int safte_init_enc(ses_softc_t *); 730Sstevel@tonic-gate extern int safte_get_encstat(ses_softc_t *, int); 740Sstevel@tonic-gate extern int safte_set_encstat(ses_softc_t *, uchar_t, int); 750Sstevel@tonic-gate extern int safte_get_objstat(ses_softc_t *, ses_objarg *, int); 760Sstevel@tonic-gate extern int safte_set_objstat(ses_softc_t *, ses_objarg *, int); 770Sstevel@tonic-gate 780Sstevel@tonic-gate extern int sen_softc_init(ses_softc_t *, int); 790Sstevel@tonic-gate extern int sen_init_enc(ses_softc_t *); 800Sstevel@tonic-gate extern int sen_get_encstat(ses_softc_t *, int); 810Sstevel@tonic-gate extern int sen_set_encstat(ses_softc_t *, uchar_t, int); 820Sstevel@tonic-gate extern int sen_get_objstat(ses_softc_t *, ses_objarg *, int); 830Sstevel@tonic-gate extern int sen_set_objstat(ses_softc_t *, ses_objarg *, int); 840Sstevel@tonic-gate 850Sstevel@tonic-gate /* 860Sstevel@tonic-gate * Local Function prototypes 870Sstevel@tonic-gate */ 880Sstevel@tonic-gate static int ses_info(dev_info_t *, ddi_info_cmd_t, void *, void **); 890Sstevel@tonic-gate static int ses_probe(dev_info_t *); 900Sstevel@tonic-gate static int ses_attach(dev_info_t *, ddi_attach_cmd_t); 910Sstevel@tonic-gate static int ses_detach(dev_info_t *, ddi_detach_cmd_t); 920Sstevel@tonic-gate 930Sstevel@tonic-gate static int is_enc_dev(ses_softc_t *, struct scsi_inquiry *, int, enctyp *); 940Sstevel@tonic-gate static int ses_doattach(dev_info_t *dip); 950Sstevel@tonic-gate 960Sstevel@tonic-gate static int ses_open(dev_t *, int, int, cred_t *); 970Sstevel@tonic-gate static int ses_close(dev_t, int, int, cred_t *); 980Sstevel@tonic-gate static int ses_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 990Sstevel@tonic-gate 1000Sstevel@tonic-gate static encvec vecs[3] = { 1010Sstevel@tonic-gate { 1020Sstevel@tonic-gate ses_softc_init, ses_init_enc, ses_get_encstat, 1030Sstevel@tonic-gate ses_set_encstat, ses_get_objstat, ses_set_objstat 1040Sstevel@tonic-gate }, 1050Sstevel@tonic-gate { 1060Sstevel@tonic-gate safte_softc_init, safte_init_enc, safte_get_encstat, 1070Sstevel@tonic-gate safte_set_encstat, safte_get_objstat, safte_set_objstat, 1080Sstevel@tonic-gate }, 1090Sstevel@tonic-gate { 1100Sstevel@tonic-gate sen_softc_init, sen_init_enc, sen_get_encstat, 1110Sstevel@tonic-gate sen_set_encstat, sen_get_objstat, sen_set_objstat 1120Sstevel@tonic-gate } 1130Sstevel@tonic-gate }; 1140Sstevel@tonic-gate 1150Sstevel@tonic-gate 1160Sstevel@tonic-gate /* 1170Sstevel@tonic-gate * Local Functions 1180Sstevel@tonic-gate */ 1190Sstevel@tonic-gate static int ses_start(struct buf *bp); 1200Sstevel@tonic-gate static int ses_decode_sense(struct scsi_pkt *pkt, int *err); 1210Sstevel@tonic-gate 1220Sstevel@tonic-gate static void ses_get_pkt(struct buf *bp, int (*func)(opaque_t)); 1230Sstevel@tonic-gate static void ses_callback(struct scsi_pkt *pkt); 1240Sstevel@tonic-gate static void ses_restart(void *arg); 1250Sstevel@tonic-gate 1260Sstevel@tonic-gate 1270Sstevel@tonic-gate /* 1280Sstevel@tonic-gate * Local Static Data 1290Sstevel@tonic-gate */ 1300Sstevel@tonic-gate #ifndef D_HOTPLUG 1310Sstevel@tonic-gate #define D_HOTPLUG 0 1320Sstevel@tonic-gate #endif /* D_HOTPLUG */ 1330Sstevel@tonic-gate 1340Sstevel@tonic-gate static struct cb_ops ses_cb_ops = { 1350Sstevel@tonic-gate ses_open, /* open */ 1360Sstevel@tonic-gate ses_close, /* close */ 1370Sstevel@tonic-gate nodev, /* strategy */ 1380Sstevel@tonic-gate nodev, /* print */ 1390Sstevel@tonic-gate nodev, /* dump */ 1400Sstevel@tonic-gate nodev, /* read */ 1410Sstevel@tonic-gate nodev, /* write */ 1420Sstevel@tonic-gate ses_ioctl, /* ioctl */ 1430Sstevel@tonic-gate nodev, /* devmap */ 1440Sstevel@tonic-gate nodev, /* mmap */ 1450Sstevel@tonic-gate nodev, /* segmap */ 1460Sstevel@tonic-gate nochpoll, /* poll */ 1470Sstevel@tonic-gate ddi_prop_op, /* cb_prop_op */ 1480Sstevel@tonic-gate 0, /* streamtab */ 1490Sstevel@tonic-gate #if !defined(CB_REV) 1500Sstevel@tonic-gate D_MP | D_NEW | D_HOTPLUG /* Driver compatibility flag */ 1510Sstevel@tonic-gate #else /* !defined(CB_REV) */ 1520Sstevel@tonic-gate D_MP | D_NEW | D_HOTPLUG, /* Driver compatibility flag */ 1530Sstevel@tonic-gate CB_REV, /* cb_ops version number */ 1540Sstevel@tonic-gate nodev, /* aread */ 1550Sstevel@tonic-gate nodev /* awrite */ 1560Sstevel@tonic-gate #endif /* !defined(CB_REV) */ 1570Sstevel@tonic-gate }; 1580Sstevel@tonic-gate 1590Sstevel@tonic-gate static struct dev_ops ses_dev_ops = { 1600Sstevel@tonic-gate DEVO_REV, /* devo_rev, */ 1610Sstevel@tonic-gate 0, /* refcnt */ 1620Sstevel@tonic-gate ses_info, /* info */ 1630Sstevel@tonic-gate nulldev, /* identify */ 1640Sstevel@tonic-gate ses_probe, /* probe */ 1650Sstevel@tonic-gate ses_attach, /* attach */ 1660Sstevel@tonic-gate ses_detach, /* detach */ 1670Sstevel@tonic-gate nodev, /* reset */ 1680Sstevel@tonic-gate &ses_cb_ops, /* driver operations */ 1690Sstevel@tonic-gate (struct bus_ops *)NULL, /* bus operations */ 1700Sstevel@tonic-gate NULL /* power */ 1710Sstevel@tonic-gate }; 1720Sstevel@tonic-gate 1730Sstevel@tonic-gate static void *estate = NULL; 1740Sstevel@tonic-gate static const char *Snm = "ses"; 1750Sstevel@tonic-gate static const char *Str = "%s\n"; 1760Sstevel@tonic-gate static const char *efl = "copyin/copyout EFAULT @ line %d"; 1770Sstevel@tonic-gate static const char *fail_msg = "%stransport failed: reason '%s': %s"; 1780Sstevel@tonic-gate 1790Sstevel@tonic-gate 1800Sstevel@tonic-gate 1810Sstevel@tonic-gate /* 1820Sstevel@tonic-gate * autoconfiguration routines. 1830Sstevel@tonic-gate */ 1840Sstevel@tonic-gate char _depends_on[] = "misc/scsi"; 1850Sstevel@tonic-gate 1860Sstevel@tonic-gate static struct modldrv modldrv = { 187*752Srralphs &mod_driverops, "SCSI Enclosure Services %I%", &ses_dev_ops 1880Sstevel@tonic-gate }; 1890Sstevel@tonic-gate 1900Sstevel@tonic-gate static struct modlinkage modlinkage = { 1910Sstevel@tonic-gate MODREV_1, &modldrv, NULL 1920Sstevel@tonic-gate }; 1930Sstevel@tonic-gate 1940Sstevel@tonic-gate 1950Sstevel@tonic-gate int 1960Sstevel@tonic-gate _init(void) 1970Sstevel@tonic-gate { 1980Sstevel@tonic-gate int status; 1990Sstevel@tonic-gate status = ddi_soft_state_init(&estate, sizeof (ses_softc_t), 0); 2000Sstevel@tonic-gate if (status == 0) { 2010Sstevel@tonic-gate if ((status = mod_install(&modlinkage)) != 0) { 2020Sstevel@tonic-gate ddi_soft_state_fini(&estate); 2030Sstevel@tonic-gate } 2040Sstevel@tonic-gate } 2050Sstevel@tonic-gate return (status); 2060Sstevel@tonic-gate } 2070Sstevel@tonic-gate 2080Sstevel@tonic-gate int 2090Sstevel@tonic-gate _fini(void) 2100Sstevel@tonic-gate { 2110Sstevel@tonic-gate int status; 2120Sstevel@tonic-gate if ((status = mod_remove(&modlinkage)) != 0) { 2130Sstevel@tonic-gate return (status); 2140Sstevel@tonic-gate } 2150Sstevel@tonic-gate ddi_soft_state_fini(&estate); 2160Sstevel@tonic-gate return (status); 2170Sstevel@tonic-gate } 2180Sstevel@tonic-gate 2190Sstevel@tonic-gate int 2200Sstevel@tonic-gate _info(struct modinfo *modinfop) 2210Sstevel@tonic-gate { 2220Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 2230Sstevel@tonic-gate } 2240Sstevel@tonic-gate 2250Sstevel@tonic-gate static int 2260Sstevel@tonic-gate ses_probe(dev_info_t *dip) 2270Sstevel@tonic-gate { 2280Sstevel@tonic-gate int err; 2290Sstevel@tonic-gate struct scsi_device *devp; 2300Sstevel@tonic-gate enctyp ep; 2310Sstevel@tonic-gate 2320Sstevel@tonic-gate /* 2330Sstevel@tonic-gate * I finally figured out why we return success 2340Sstevel@tonic-gate * on every probe. The devices that we attach to 2350Sstevel@tonic-gate * don't all report as being the same "device type" 2360Sstevel@tonic-gate * 2370Sstevel@tonic-gate * 1) A5x00 -- report as Enclosure Services (0xD) SES 2380Sstevel@tonic-gate * 2) A1000 -- report as Direct Access (0x0) SES 2390Sstevel@tonic-gate * uses the same target as raid controler. 2400Sstevel@tonic-gate * 3) D1000 -- report as processor (0x3) SAFTE 2410Sstevel@tonic-gate * 3) D240 -- report as processor (0x3) SAFTE 2420Sstevel@tonic-gate * 2430Sstevel@tonic-gate * We also reportedly attach to SEN devices which I 2440Sstevel@tonic-gate * believe reside in a Tobasco tray. I have never 2450Sstevel@tonic-gate * been able to get one to attach. 2460Sstevel@tonic-gate * 2470Sstevel@tonic-gate */ 2480Sstevel@tonic-gate 2490Sstevel@tonic-gate 2500Sstevel@tonic-gate if (dip == NULL) 2510Sstevel@tonic-gate return (DDI_PROBE_FAILURE); 2520Sstevel@tonic-gate /* 2530Sstevel@tonic-gate * XXX: Breakage from the x86 folks. 2540Sstevel@tonic-gate */ 2550Sstevel@tonic-gate if (strcmp(ddi_get_name(ddi_get_parent(dip)), "ata") == 0) { 2560Sstevel@tonic-gate return (DDI_PROBE_FAILURE); 2570Sstevel@tonic-gate } 2580Sstevel@tonic-gate /* SES_LOG(NULL, SES_CE_DEBUG1, "ses_probe: OK"); */ 2590Sstevel@tonic-gate if (ddi_dev_is_sid(dip) == DDI_SUCCESS) { 2600Sstevel@tonic-gate return (DDI_PROBE_DONTCARE); 2610Sstevel@tonic-gate } 2620Sstevel@tonic-gate devp = ddi_get_driver_private(dip); 2630Sstevel@tonic-gate switch (err = scsi_probe(devp, SLEEP_FUNC)) { 2640Sstevel@tonic-gate case SCSIPROBE_EXISTS: 2650Sstevel@tonic-gate if (is_enc_dev(NULL, devp->sd_inq, SUN_INQSIZE, &ep)) { 2660Sstevel@tonic-gate break; 2670Sstevel@tonic-gate } 2680Sstevel@tonic-gate /* FALLTHROUGH */ 2690Sstevel@tonic-gate case SCSIPROBE_NORESP: 2700Sstevel@tonic-gate scsi_unprobe(devp); 2710Sstevel@tonic-gate return (DDI_PROBE_FAILURE); 2720Sstevel@tonic-gate default: 2730Sstevel@tonic-gate SES_LOG(NULL, SES_CE_DEBUG9, 2740Sstevel@tonic-gate "ses_probe: probe error %d", err); 2750Sstevel@tonic-gate scsi_unprobe(devp); 2760Sstevel@tonic-gate return (DDI_PROBE_FAILURE); 2770Sstevel@tonic-gate } 2780Sstevel@tonic-gate scsi_unprobe(devp); 2790Sstevel@tonic-gate return (DDI_PROBE_SUCCESS); 2800Sstevel@tonic-gate } 2810Sstevel@tonic-gate 2820Sstevel@tonic-gate static int 2830Sstevel@tonic-gate ses_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 2840Sstevel@tonic-gate { 2850Sstevel@tonic-gate int inst, err; 2860Sstevel@tonic-gate ses_softc_t *ssc; 2870Sstevel@tonic-gate 2880Sstevel@tonic-gate inst = ddi_get_instance(dip); 2890Sstevel@tonic-gate switch (cmd) { 2900Sstevel@tonic-gate case DDI_ATTACH: 2910Sstevel@tonic-gate SES_LOG(NULL, SES_CE_DEBUG9, "ses_attach: DDI_ATTACH ses%d", 2920Sstevel@tonic-gate inst); 2930Sstevel@tonic-gate 2940Sstevel@tonic-gate err = ses_doattach(dip); 2950Sstevel@tonic-gate 2960Sstevel@tonic-gate if (err == DDI_FAILURE) { 2970Sstevel@tonic-gate return (DDI_FAILURE); 2980Sstevel@tonic-gate } 2990Sstevel@tonic-gate SES_LOG(NULL, SES_CE_DEBUG4, 3000Sstevel@tonic-gate "ses_attach: DDI_ATTACH OK ses%d", inst); 3010Sstevel@tonic-gate break; 3020Sstevel@tonic-gate 3030Sstevel@tonic-gate case DDI_RESUME: 3040Sstevel@tonic-gate if ((ssc = ddi_get_soft_state(estate, inst)) == NULL) { 3050Sstevel@tonic-gate return (DDI_FAILURE); 3060Sstevel@tonic-gate } 3070Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG1, "ses_attach: DDI_ATTACH ses%d", 3080Sstevel@tonic-gate inst); 3090Sstevel@tonic-gate ssc->ses_suspended = 0; 3100Sstevel@tonic-gate break; 3110Sstevel@tonic-gate 3120Sstevel@tonic-gate default: 3130Sstevel@tonic-gate return (DDI_FAILURE); 3140Sstevel@tonic-gate } 3150Sstevel@tonic-gate return (DDI_SUCCESS); 3160Sstevel@tonic-gate } 3170Sstevel@tonic-gate 3180Sstevel@tonic-gate static int 3190Sstevel@tonic-gate is_enc_dev(ses_softc_t *ssc, struct scsi_inquiry *inqp, int iqlen, enctyp *ep) 3200Sstevel@tonic-gate { 3210Sstevel@tonic-gate uchar_t dt = (inqp->inq_dtype & DTYPE_MASK); 3220Sstevel@tonic-gate uchar_t *iqd = (uchar_t *)inqp; 3230Sstevel@tonic-gate 3240Sstevel@tonic-gate if (dt == DTYPE_ESI) { 3250Sstevel@tonic-gate if (strncmp(inqp->inq_vid, SEN_ID, SEN_ID_LEN) == 0) { 3260Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG3, "SEN device found"); 3270Sstevel@tonic-gate *ep = SEN_TYPE; 3280Sstevel@tonic-gate } else if (inqp->inq_rdf > RDF_SCSI2) { 3290Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG3, "SES device found"); 3300Sstevel@tonic-gate *ep = SES_TYPE; 3310Sstevel@tonic-gate } else { 3320Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG3, "Pre-SCSI3 SES device"); 3330Sstevel@tonic-gate *ep = SES_TYPE; 3340Sstevel@tonic-gate } 3350Sstevel@tonic-gate return (1); 3360Sstevel@tonic-gate } 3370Sstevel@tonic-gate if ((iqd[6] & 0x40) && inqp->inq_rdf >= RDF_SCSI2) { 3380Sstevel@tonic-gate /* 3390Sstevel@tonic-gate * PassThrough Device. 3400Sstevel@tonic-gate */ 3410Sstevel@tonic-gate *ep = SES_TYPE; 3420Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG3, "Passthru SES device"); 3430Sstevel@tonic-gate return (1); 3440Sstevel@tonic-gate } 3450Sstevel@tonic-gate 3460Sstevel@tonic-gate if (iqlen < 47) { 3470Sstevel@tonic-gate SES_LOG(ssc, CE_NOTE, 3480Sstevel@tonic-gate "INQUIRY data too short to determine SAF-TE"); 3490Sstevel@tonic-gate return (0); 3500Sstevel@tonic-gate } 3510Sstevel@tonic-gate if (strncmp((char *)&iqd[44], "SAF-TE", 4) == 0) { 3520Sstevel@tonic-gate *ep = SAFT_TYPE; 3530Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG3, "SAF-TE device found"); 3540Sstevel@tonic-gate return (1); 3550Sstevel@tonic-gate } 3560Sstevel@tonic-gate return (0); 3570Sstevel@tonic-gate } 3580Sstevel@tonic-gate 3590Sstevel@tonic-gate 3600Sstevel@tonic-gate /* 3610Sstevel@tonic-gate * Attach ses device. 3620Sstevel@tonic-gate * 3630Sstevel@tonic-gate * XXX: Power management is NOT supported. A token framework 3640Sstevel@tonic-gate * is provided that will need to be extended assuming we have 3650Sstevel@tonic-gate * ses devices we can power down. Currently, we don't have any. 3660Sstevel@tonic-gate */ 3670Sstevel@tonic-gate static int 3680Sstevel@tonic-gate ses_doattach(dev_info_t *dip) 3690Sstevel@tonic-gate { 3700Sstevel@tonic-gate int inst, err; 3710Sstevel@tonic-gate Scsidevp devp; 3720Sstevel@tonic-gate ses_softc_t *ssc; 3730Sstevel@tonic-gate enctyp etyp; 3740Sstevel@tonic-gate 3750Sstevel@tonic-gate inst = ddi_get_instance(dip); 3760Sstevel@tonic-gate /* 3770Sstevel@tonic-gate * Workaround for bug #4154979- for some reason we can 3780Sstevel@tonic-gate * be called with identical instance numbers but for 3790Sstevel@tonic-gate * different dev_info_t-s- all but one are bogus. 3800Sstevel@tonic-gate * 3810Sstevel@tonic-gate * Bad Dog! No Biscuit! 3820Sstevel@tonic-gate * 3830Sstevel@tonic-gate * A quick workaround might be to call ddi_soft_state_zalloc 3840Sstevel@tonic-gate * unconditionally, as the implementation fails these calls 3850Sstevel@tonic-gate * if there's an item already allocated. A more reasonable 3860Sstevel@tonic-gate * and longer term change is to move the allocation past 3870Sstevel@tonic-gate * the probe for the device's existence as most of these 3880Sstevel@tonic-gate * 'bogus' calls are for nonexistent devices. 3890Sstevel@tonic-gate */ 3900Sstevel@tonic-gate 3910Sstevel@tonic-gate devp = ddi_get_driver_private(dip); 3920Sstevel@tonic-gate devp->sd_dev = dip; 3930Sstevel@tonic-gate 3940Sstevel@tonic-gate /* 3950Sstevel@tonic-gate * Determine whether the { i, t, l } we're called 3960Sstevel@tonic-gate * to start is an enclosure services device. 3970Sstevel@tonic-gate */ 3980Sstevel@tonic-gate 3990Sstevel@tonic-gate /* 4000Sstevel@tonic-gate * Call the scsi_probe routine to see whether 4010Sstevel@tonic-gate * we actually have an Enclosure Services device at 4020Sstevel@tonic-gate * this address. 4030Sstevel@tonic-gate */ 4040Sstevel@tonic-gate err = scsi_probe(devp, SLEEP_FUNC); 4050Sstevel@tonic-gate if (err != SCSIPROBE_EXISTS) { 4060Sstevel@tonic-gate SES_LOG(NULL, SES_CE_DEBUG9, 4070Sstevel@tonic-gate "ses_doattach: probe error %d", err); 4080Sstevel@tonic-gate scsi_unprobe(devp); 4090Sstevel@tonic-gate return (DDI_FAILURE); 4100Sstevel@tonic-gate } 4110Sstevel@tonic-gate /* Call is_enc_dev() to get the etyp */ 4120Sstevel@tonic-gate if (!(is_enc_dev(NULL, devp->sd_inq, SUN_INQSIZE, &etyp))) { 4130Sstevel@tonic-gate SES_LOG(NULL, CE_WARN, 4140Sstevel@tonic-gate "ses_doattach: ses%d: is_enc_dev failure", inst); 4150Sstevel@tonic-gate scsi_unprobe(devp); 4160Sstevel@tonic-gate return (DDI_FAILURE); 4170Sstevel@tonic-gate } 4180Sstevel@tonic-gate 4190Sstevel@tonic-gate if (ddi_soft_state_zalloc(estate, inst) != DDI_SUCCESS) { 4200Sstevel@tonic-gate scsi_unprobe(devp); 4210Sstevel@tonic-gate SES_LOG(NULL, CE_NOTE, "ses%d: softalloc fails", inst); 4220Sstevel@tonic-gate return (DDI_FAILURE); 4230Sstevel@tonic-gate } 4240Sstevel@tonic-gate ssc = ddi_get_soft_state(estate, inst); 4250Sstevel@tonic-gate if (ssc == NULL) { 4260Sstevel@tonic-gate scsi_unprobe(devp); 4270Sstevel@tonic-gate SES_LOG(NULL, CE_NOTE, "ses%d: get_soft_state fails", inst); 4280Sstevel@tonic-gate return (DDI_FAILURE); 4290Sstevel@tonic-gate } 4300Sstevel@tonic-gate devp->sd_private = (opaque_t)ssc; 4310Sstevel@tonic-gate ssc->ses_devp = devp; 4320Sstevel@tonic-gate err = ddi_create_minor_node(dip, "0", S_IFCHR, inst, 4330Sstevel@tonic-gate DDI_NT_SCSI_ENCLOSURE, NULL); 4340Sstevel@tonic-gate if (err == DDI_FAILURE) { 4350Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL); 4360Sstevel@tonic-gate SES_LOG(ssc, CE_NOTE, "minor node creation failed"); 4370Sstevel@tonic-gate ddi_soft_state_free(estate, inst); 4380Sstevel@tonic-gate scsi_unprobe(devp); 4390Sstevel@tonic-gate return (DDI_FAILURE); 4400Sstevel@tonic-gate } 4410Sstevel@tonic-gate 4420Sstevel@tonic-gate ssc->ses_type = etyp; 4430Sstevel@tonic-gate ssc->ses_vec = vecs[etyp]; 4440Sstevel@tonic-gate 4450Sstevel@tonic-gate /* Call SoftC Init Routine A bit later... */ 4460Sstevel@tonic-gate 4470Sstevel@tonic-gate ssc->ses_rqbp = scsi_alloc_consistent_buf(SES_ROUTE(ssc), 4480Sstevel@tonic-gate NULL, SENSE_LENGTH, B_READ, SLEEP_FUNC, NULL); 4490Sstevel@tonic-gate if (ssc->ses_rqbp != NULL) { 4500Sstevel@tonic-gate ssc->ses_rqpkt = scsi_init_pkt(SES_ROUTE(ssc), NULL, 4510Sstevel@tonic-gate ssc->ses_rqbp, CDB_GROUP0, 1, 0, PKT_CONSISTENT, 4520Sstevel@tonic-gate SLEEP_FUNC, NULL); 4530Sstevel@tonic-gate } 4540Sstevel@tonic-gate if (ssc->ses_rqbp == NULL || ssc->ses_rqpkt == NULL) { 4550Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL); 4560Sstevel@tonic-gate SES_LOG(ssc, CE_NOTE, "scsi_init_pkt of rqbuf failed"); 4570Sstevel@tonic-gate if (ssc->ses_rqbp != NULL) { 4580Sstevel@tonic-gate scsi_free_consistent_buf(ssc->ses_rqbp); 4590Sstevel@tonic-gate ssc->ses_rqbp = NULL; 4600Sstevel@tonic-gate } 4610Sstevel@tonic-gate ddi_soft_state_free(estate, inst); 4620Sstevel@tonic-gate scsi_unprobe(devp); 4630Sstevel@tonic-gate return (DDI_FAILURE); 4640Sstevel@tonic-gate } 4650Sstevel@tonic-gate ssc->ses_rqpkt->pkt_private = (opaque_t)ssc; 4660Sstevel@tonic-gate ssc->ses_rqpkt->pkt_address = *(SES_ROUTE(ssc)); 4670Sstevel@tonic-gate ssc->ses_rqpkt->pkt_comp = ses_callback; 4680Sstevel@tonic-gate ssc->ses_rqpkt->pkt_time = ses_io_time; 4690Sstevel@tonic-gate ssc->ses_rqpkt->pkt_flags = FLAG_NOPARITY|FLAG_NODISCON|FLAG_SENSING; 4700Sstevel@tonic-gate ssc->ses_rqpkt->pkt_cdbp[0] = SCMD_REQUEST_SENSE; 4710Sstevel@tonic-gate ssc->ses_rqpkt->pkt_cdbp[1] = 0; 4720Sstevel@tonic-gate ssc->ses_rqpkt->pkt_cdbp[2] = 0; 4730Sstevel@tonic-gate ssc->ses_rqpkt->pkt_cdbp[3] = 0; 4740Sstevel@tonic-gate ssc->ses_rqpkt->pkt_cdbp[4] = SENSE_LENGTH; 4750Sstevel@tonic-gate ssc->ses_rqpkt->pkt_cdbp[5] = 0; 4760Sstevel@tonic-gate 4770Sstevel@tonic-gate switch (scsi_ifgetcap(SES_ROUTE(ssc), "auto-rqsense", 1)) { 4780Sstevel@tonic-gate case 1: 4790Sstevel@tonic-gate /* if already set, don't reset it */ 4800Sstevel@tonic-gate ssc->ses_arq = 1; 4810Sstevel@tonic-gate break; 4820Sstevel@tonic-gate case 0: 4830Sstevel@tonic-gate /* try and set it */ 4840Sstevel@tonic-gate ssc->ses_arq = ((scsi_ifsetcap(SES_ROUTE(ssc), 4850Sstevel@tonic-gate "auto-rqsense", 1, 1) == 1) ? 1 : 0); 4860Sstevel@tonic-gate break; 4870Sstevel@tonic-gate default: 4880Sstevel@tonic-gate /* probably undefined, so zero it out */ 4890Sstevel@tonic-gate ssc->ses_arq = 0; 4900Sstevel@tonic-gate break; 4910Sstevel@tonic-gate } 4920Sstevel@tonic-gate 4930Sstevel@tonic-gate ssc->ses_sbufp = getrbuf(KM_SLEEP); 4940Sstevel@tonic-gate cv_init(&ssc->ses_sbufcv, NULL, CV_DRIVER, NULL); 4950Sstevel@tonic-gate 4960Sstevel@tonic-gate /* 4970Sstevel@tonic-gate * If the HBA supports wide, tell it to use wide. 4980Sstevel@tonic-gate */ 4990Sstevel@tonic-gate if (scsi_ifgetcap(SES_ROUTE(ssc), "wide-xfer", 1) != -1) { 5000Sstevel@tonic-gate int wd = ((devp->sd_inq->inq_rdf == RDF_SCSI2) && 5010Sstevel@tonic-gate (devp->sd_inq->inq_wbus16 || devp->sd_inq->inq_wbus32)) 5020Sstevel@tonic-gate ? 1 : 0; 5030Sstevel@tonic-gate (void) scsi_ifsetcap(SES_ROUTE(ssc), "wide-xfer", wd, 1); 5040Sstevel@tonic-gate } 5050Sstevel@tonic-gate 5060Sstevel@tonic-gate /* 5070Sstevel@tonic-gate * Now do ssc init of enclosure specifics. 5080Sstevel@tonic-gate * At the same time, check to make sure getrbuf 5090Sstevel@tonic-gate * actually succeeded. 5100Sstevel@tonic-gate */ 511*752Srralphs if ((*ssc->ses_vec.softc_init)(ssc, 1)) { 512*752Srralphs SES_LOG(ssc, SES_CE_DEBUG3, "failed softc init"); 513*752Srralphs (void) (*ssc->ses_vec.softc_init)(ssc, 0); 5140Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL); 5150Sstevel@tonic-gate scsi_destroy_pkt(ssc->ses_rqpkt); 5160Sstevel@tonic-gate scsi_free_consistent_buf(ssc->ses_rqbp); 5170Sstevel@tonic-gate if (ssc->ses_sbufp) { 5180Sstevel@tonic-gate freerbuf(ssc->ses_sbufp); 5190Sstevel@tonic-gate } 5200Sstevel@tonic-gate cv_destroy(&ssc->ses_sbufcv); 5210Sstevel@tonic-gate ddi_soft_state_free(estate, inst); 5220Sstevel@tonic-gate scsi_unprobe(devp); 5230Sstevel@tonic-gate return (DDI_FAILURE); 5240Sstevel@tonic-gate } 5250Sstevel@tonic-gate 5260Sstevel@tonic-gate /* 5270Sstevel@tonic-gate * create this property so that PM code knows we want 5280Sstevel@tonic-gate * to be suspended at PM time 5290Sstevel@tonic-gate */ 5300Sstevel@tonic-gate (void) ddi_prop_update_string(DDI_DEV_T_NONE, dip, 5310Sstevel@tonic-gate PM_HARDWARE_STATE_PROP, PM_NEEDS_SUSPEND_RESUME); 5320Sstevel@tonic-gate 5330Sstevel@tonic-gate /* announce the existence of this device */ 5340Sstevel@tonic-gate ddi_report_dev(dip); 5350Sstevel@tonic-gate return (DDI_SUCCESS); 5360Sstevel@tonic-gate } 5370Sstevel@tonic-gate 5380Sstevel@tonic-gate 5390Sstevel@tonic-gate /* 5400Sstevel@tonic-gate * Detach ses device. 5410Sstevel@tonic-gate * 5420Sstevel@tonic-gate * XXX: Power management is NOT supported. A token framework 5430Sstevel@tonic-gate * is provided that will need to be extended assuming we have 5440Sstevel@tonic-gate * ses devices we can power down. Currently, we don't have any. 5450Sstevel@tonic-gate */ 5460Sstevel@tonic-gate static int 5470Sstevel@tonic-gate ses_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 5480Sstevel@tonic-gate { 5490Sstevel@tonic-gate ses_softc_t *ssc; 5500Sstevel@tonic-gate int inst; 5510Sstevel@tonic-gate 5520Sstevel@tonic-gate switch (cmd) { 5530Sstevel@tonic-gate case DDI_DETACH: 5540Sstevel@tonic-gate inst = ddi_get_instance(dip); 5550Sstevel@tonic-gate ssc = ddi_get_soft_state(estate, inst); 5560Sstevel@tonic-gate if (ssc == NULL) { 5570Sstevel@tonic-gate cmn_err(CE_NOTE, 5580Sstevel@tonic-gate "ses%d: DDI_DETACH, no softstate found", inst); 5590Sstevel@tonic-gate return (DDI_FAILURE); 5600Sstevel@tonic-gate } 5610Sstevel@tonic-gate if (ISOPEN(ssc)) { 5620Sstevel@tonic-gate return (DDI_FAILURE); 5630Sstevel@tonic-gate } 5640Sstevel@tonic-gate 5650Sstevel@tonic-gate #if !defined(lint) 5660Sstevel@tonic-gate /* LINTED */ 5670Sstevel@tonic-gate _NOTE(COMPETING_THREADS_NOW); 5680Sstevel@tonic-gate #endif /* !defined(lint) */ 5690Sstevel@tonic-gate 5700Sstevel@tonic-gate if (ssc->ses_vec.softc_init) 5710Sstevel@tonic-gate (void) (*ssc->ses_vec.softc_init)(ssc, 0); 5720Sstevel@tonic-gate 5730Sstevel@tonic-gate #if !defined(lint) 5740Sstevel@tonic-gate _NOTE(NO_COMPETING_THREADS_NOW); 5750Sstevel@tonic-gate #endif /* !defined(lint) */ 5760Sstevel@tonic-gate 5770Sstevel@tonic-gate (void) scsi_ifsetcap(SES_ROUTE(ssc), "auto-rqsense", 1, 0); 5780Sstevel@tonic-gate scsi_destroy_pkt(ssc->ses_rqpkt); 5790Sstevel@tonic-gate scsi_free_consistent_buf(ssc->ses_rqbp); 5800Sstevel@tonic-gate freerbuf(ssc->ses_sbufp); 5810Sstevel@tonic-gate cv_destroy(&ssc->ses_sbufcv); 5820Sstevel@tonic-gate ddi_soft_state_free(estate, inst); 5830Sstevel@tonic-gate ddi_prop_remove_all(dip); 5840Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL); 5850Sstevel@tonic-gate scsi_unprobe(ddi_get_driver_private(dip)); 5860Sstevel@tonic-gate break; 5870Sstevel@tonic-gate 5880Sstevel@tonic-gate case DDI_SUSPEND: 5890Sstevel@tonic-gate inst = ddi_get_instance(dip); 5900Sstevel@tonic-gate if ((ssc = ddi_get_soft_state(estate, inst)) == NULL) { 5910Sstevel@tonic-gate cmn_err(CE_NOTE, 5920Sstevel@tonic-gate "ses%d: DDI_SUSPEND, no softstate found", inst); 5930Sstevel@tonic-gate return (DDI_FAILURE); 5940Sstevel@tonic-gate } 5950Sstevel@tonic-gate 5960Sstevel@tonic-gate /* 5970Sstevel@tonic-gate * If driver idle, accept suspend request. 5980Sstevel@tonic-gate * If it's busy, reject it. This keeps things simple! 5990Sstevel@tonic-gate */ 6000Sstevel@tonic-gate mutex_enter(SES_MUTEX); 6010Sstevel@tonic-gate if (ssc->ses_sbufbsy) { 6020Sstevel@tonic-gate mutex_exit(SES_MUTEX); 6030Sstevel@tonic-gate return (DDI_FAILURE); 6040Sstevel@tonic-gate } 6050Sstevel@tonic-gate ssc->ses_suspended = 1; 6060Sstevel@tonic-gate mutex_exit(SES_MUTEX); 6070Sstevel@tonic-gate break; 6080Sstevel@tonic-gate 6090Sstevel@tonic-gate default: 6100Sstevel@tonic-gate return (DDI_FAILURE); 6110Sstevel@tonic-gate } 6120Sstevel@tonic-gate return (DDI_SUCCESS); 6130Sstevel@tonic-gate } 6140Sstevel@tonic-gate 6150Sstevel@tonic-gate /* ARGSUSED */ 6160Sstevel@tonic-gate static int 6170Sstevel@tonic-gate ses_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 6180Sstevel@tonic-gate { 6190Sstevel@tonic-gate dev_t dev; 6200Sstevel@tonic-gate ses_softc_t *ssc; 6210Sstevel@tonic-gate int inst, error; 6220Sstevel@tonic-gate 6230Sstevel@tonic-gate switch (infocmd) { 6240Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 6250Sstevel@tonic-gate dev = (dev_t)arg; 6260Sstevel@tonic-gate inst = getminor(dev); 6270Sstevel@tonic-gate if ((ssc = ddi_get_soft_state(estate, inst)) == NULL) { 6280Sstevel@tonic-gate return (DDI_FAILURE); 6290Sstevel@tonic-gate } 6300Sstevel@tonic-gate *result = (void *) ssc->ses_devp->sd_dev; 6310Sstevel@tonic-gate error = DDI_SUCCESS; 6320Sstevel@tonic-gate break; 6330Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 6340Sstevel@tonic-gate dev = (dev_t)arg; 6350Sstevel@tonic-gate inst = getminor(dev); 6360Sstevel@tonic-gate *result = (void *)(uintptr_t)inst; 6370Sstevel@tonic-gate error = DDI_SUCCESS; 6380Sstevel@tonic-gate break; 6390Sstevel@tonic-gate default: 6400Sstevel@tonic-gate error = DDI_FAILURE; 6410Sstevel@tonic-gate } 6420Sstevel@tonic-gate return (error); 6430Sstevel@tonic-gate } 6440Sstevel@tonic-gate 6450Sstevel@tonic-gate /* 6460Sstevel@tonic-gate * Unix Entry Points 6470Sstevel@tonic-gate */ 6480Sstevel@tonic-gate 6490Sstevel@tonic-gate /* ARGSUSED */ 6500Sstevel@tonic-gate static int 6510Sstevel@tonic-gate ses_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p) 6520Sstevel@tonic-gate { 6530Sstevel@tonic-gate ses_softc_t *ssc; 6540Sstevel@tonic-gate 6550Sstevel@tonic-gate if ((ssc = ddi_get_soft_state(estate, getminor(*dev_p))) == NULL) { 6560Sstevel@tonic-gate return (ENXIO); 6570Sstevel@tonic-gate } 6580Sstevel@tonic-gate 6590Sstevel@tonic-gate /* 6600Sstevel@tonic-gate * If the device is powered down, request it's activation. 6610Sstevel@tonic-gate * If it can't be activated, fail open. 6620Sstevel@tonic-gate */ 6630Sstevel@tonic-gate if (ssc->ses_suspended && 6640Sstevel@tonic-gate ddi_dev_is_needed(SES_DEVINFO(ssc), 0, 1) != DDI_SUCCESS) { 6650Sstevel@tonic-gate return (EIO); 6660Sstevel@tonic-gate } 6670Sstevel@tonic-gate 6680Sstevel@tonic-gate mutex_enter(SES_MUTEX); 6690Sstevel@tonic-gate if (otyp == OTYP_LYR) 6700Sstevel@tonic-gate ssc->ses_lyropen++; 6710Sstevel@tonic-gate else 6720Sstevel@tonic-gate ssc->ses_oflag = 1; 6730Sstevel@tonic-gate 6740Sstevel@tonic-gate ssc->ses_present = (ssc->ses_present)? ssc->ses_present: SES_OPENING; 6750Sstevel@tonic-gate mutex_exit(SES_MUTEX); 6760Sstevel@tonic-gate return (EOK); 6770Sstevel@tonic-gate } 6780Sstevel@tonic-gate 6790Sstevel@tonic-gate /*ARGSUSED*/ 6800Sstevel@tonic-gate static int 6810Sstevel@tonic-gate ses_close(dev_t dev, int flag, int otyp, cred_t *cred_p) 6820Sstevel@tonic-gate { 6830Sstevel@tonic-gate ses_softc_t *ssc; 6840Sstevel@tonic-gate if ((ssc = ddi_get_soft_state(estate, getminor(dev))) == NULL) { 6850Sstevel@tonic-gate return (ENXIO); 6860Sstevel@tonic-gate } 6870Sstevel@tonic-gate 6880Sstevel@tonic-gate if (ssc->ses_suspended) { 6890Sstevel@tonic-gate (void) ddi_dev_is_needed(SES_DEVINFO(ssc), 0, 1); 6900Sstevel@tonic-gate } 6910Sstevel@tonic-gate 6920Sstevel@tonic-gate mutex_enter(SES_MUTEX); 6930Sstevel@tonic-gate if (otyp == OTYP_LYR) 6940Sstevel@tonic-gate ssc->ses_lyropen -= (ssc->ses_lyropen)? 1: 0; 6950Sstevel@tonic-gate else 6960Sstevel@tonic-gate ssc->ses_oflag = 0; 6970Sstevel@tonic-gate mutex_exit(SES_MUTEX); 6980Sstevel@tonic-gate return (0); 6990Sstevel@tonic-gate } 7000Sstevel@tonic-gate 7010Sstevel@tonic-gate 7020Sstevel@tonic-gate /*ARGSUSED3*/ 7030Sstevel@tonic-gate static int 7040Sstevel@tonic-gate ses_ioctl(dev_t dev, int cmd, intptr_t arg, int flg, cred_t *cred_p, int *rvalp) 7050Sstevel@tonic-gate { 7060Sstevel@tonic-gate ses_softc_t *ssc; 7070Sstevel@tonic-gate ses_object k, *up; 7080Sstevel@tonic-gate ses_objarg x; 7090Sstevel@tonic-gate uchar_t t; 7100Sstevel@tonic-gate uchar_t i; 7110Sstevel@tonic-gate int rv = 0; 7120Sstevel@tonic-gate 7130Sstevel@tonic-gate if ((ssc = ddi_get_soft_state(estate, getminor(dev))) == NULL || 7140Sstevel@tonic-gate ssc->ses_present == SES_CLOSED) { 7150Sstevel@tonic-gate return (ENXIO); 7160Sstevel@tonic-gate } 7170Sstevel@tonic-gate 7180Sstevel@tonic-gate 7190Sstevel@tonic-gate switch (cmd) { 7200Sstevel@tonic-gate case SESIOC_GETNOBJ: 7210Sstevel@tonic-gate if (ddi_copyout(&ssc->ses_nobjects, (void *)arg, 7220Sstevel@tonic-gate sizeof (int), flg)) { 7230Sstevel@tonic-gate rv = EFAULT; 7240Sstevel@tonic-gate break; 7250Sstevel@tonic-gate } 7260Sstevel@tonic-gate break; 7270Sstevel@tonic-gate 7280Sstevel@tonic-gate case SESIOC_GETOBJMAP: 7290Sstevel@tonic-gate up = (ses_object *) arg; 7300Sstevel@tonic-gate mutex_enter(SES_MUTEX); 7310Sstevel@tonic-gate for (i = 0; i != ssc->ses_nobjects; i++) { 7320Sstevel@tonic-gate k.obj_id = i; 7330Sstevel@tonic-gate k.subencid = ssc->ses_objmap[i].subenclosure; 7340Sstevel@tonic-gate k.elem_type = ssc->ses_objmap[i].enctype; 7350Sstevel@tonic-gate if (ddi_copyout(&k, up, sizeof (k), flg)) { 7360Sstevel@tonic-gate rv = EFAULT; 7370Sstevel@tonic-gate break; 7380Sstevel@tonic-gate } 7390Sstevel@tonic-gate up++; 7400Sstevel@tonic-gate } 7410Sstevel@tonic-gate mutex_exit(SES_MUTEX); 7420Sstevel@tonic-gate break; 7430Sstevel@tonic-gate 7440Sstevel@tonic-gate case SESIOC_INIT: 7450Sstevel@tonic-gate rv = (*ssc->ses_vec.init_enc)(ssc); 7460Sstevel@tonic-gate break; 7470Sstevel@tonic-gate 7480Sstevel@tonic-gate case SESIOC_GETENCSTAT: 7490Sstevel@tonic-gate if ((ssc->ses_encstat & ENCI_SVALID) == 0) { 7500Sstevel@tonic-gate rv = (*ssc->ses_vec.get_encstat)(ssc, KM_SLEEP); 7510Sstevel@tonic-gate if (rv) { 7520Sstevel@tonic-gate break; 7530Sstevel@tonic-gate } 7540Sstevel@tonic-gate } 7550Sstevel@tonic-gate t = ssc->ses_encstat & 0xf; 7560Sstevel@tonic-gate if (ddi_copyout(&t, (void *)arg, sizeof (t), flg)) 7570Sstevel@tonic-gate rv = EFAULT; 7580Sstevel@tonic-gate /* 7590Sstevel@tonic-gate * And always invalidate enclosure status on the way out. 7600Sstevel@tonic-gate */ 7610Sstevel@tonic-gate mutex_enter(SES_MUTEX); 7620Sstevel@tonic-gate ssc->ses_encstat &= ~ENCI_SVALID; 7630Sstevel@tonic-gate mutex_exit(SES_MUTEX); 7640Sstevel@tonic-gate break; 7650Sstevel@tonic-gate 7660Sstevel@tonic-gate case SESIOC_SETENCSTAT: 7670Sstevel@tonic-gate if (ddi_copyin((void *)arg, &t, sizeof (t), flg)) 7680Sstevel@tonic-gate rv = EFAULT; 7690Sstevel@tonic-gate else 7700Sstevel@tonic-gate rv = (*ssc->ses_vec.set_encstat)(ssc, t, KM_SLEEP); 7710Sstevel@tonic-gate mutex_enter(SES_MUTEX); 7720Sstevel@tonic-gate ssc->ses_encstat &= ~ENCI_SVALID; 7730Sstevel@tonic-gate mutex_exit(SES_MUTEX); 7740Sstevel@tonic-gate break; 7750Sstevel@tonic-gate 7760Sstevel@tonic-gate case SESIOC_GETOBJSTAT: 7770Sstevel@tonic-gate if (ddi_copyin((void *)arg, &x, sizeof (x), flg)) { 7780Sstevel@tonic-gate rv = EFAULT; 7790Sstevel@tonic-gate break; 7800Sstevel@tonic-gate } 7810Sstevel@tonic-gate if (x.obj_id >= ssc->ses_nobjects) { 7820Sstevel@tonic-gate rv = EINVAL; 7830Sstevel@tonic-gate break; 7840Sstevel@tonic-gate } 7850Sstevel@tonic-gate if ((rv = (*ssc->ses_vec.get_objstat)(ssc, &x, KM_SLEEP)) != 0) 7860Sstevel@tonic-gate break; 7870Sstevel@tonic-gate if (ddi_copyout(&x, (void *)arg, sizeof (x), flg)) 7880Sstevel@tonic-gate rv = EFAULT; 7890Sstevel@tonic-gate else { 7900Sstevel@tonic-gate /* 7910Sstevel@tonic-gate * Now that we no longer poll, svalid never stays true. 7920Sstevel@tonic-gate */ 7930Sstevel@tonic-gate mutex_enter(SES_MUTEX); 7940Sstevel@tonic-gate ssc->ses_objmap[x.obj_id].svalid = 0; 7950Sstevel@tonic-gate mutex_exit(SES_MUTEX); 7960Sstevel@tonic-gate } 7970Sstevel@tonic-gate break; 7980Sstevel@tonic-gate 7990Sstevel@tonic-gate case SESIOC_SETOBJSTAT: 8000Sstevel@tonic-gate if (ddi_copyin((void *)arg, &x, sizeof (x), flg)) { 8010Sstevel@tonic-gate rv = EFAULT; 8020Sstevel@tonic-gate break; 8030Sstevel@tonic-gate } 8040Sstevel@tonic-gate if (x.obj_id >= ssc->ses_nobjects) { 8050Sstevel@tonic-gate rv = EINVAL; 8060Sstevel@tonic-gate break; 8070Sstevel@tonic-gate } 8080Sstevel@tonic-gate rv = (*ssc->ses_vec.set_objstat)(ssc, &x, KM_SLEEP); 8090Sstevel@tonic-gate if (rv == 0) { 8100Sstevel@tonic-gate mutex_enter(SES_MUTEX); 8110Sstevel@tonic-gate ssc->ses_objmap[x.obj_id].svalid = 0; 8120Sstevel@tonic-gate mutex_exit(SES_MUTEX); 8130Sstevel@tonic-gate } 8140Sstevel@tonic-gate break; 8150Sstevel@tonic-gate 8160Sstevel@tonic-gate case USCSICMD: 8170Sstevel@tonic-gate rv = ses_uscsi_cmd(ssc, (Uscmd *) arg, flg, flg, flg, flg); 8180Sstevel@tonic-gate break; 8190Sstevel@tonic-gate 8200Sstevel@tonic-gate default: 8210Sstevel@tonic-gate rv = ENOTTY; 8220Sstevel@tonic-gate break; 8230Sstevel@tonic-gate } 8240Sstevel@tonic-gate return (rv); 8250Sstevel@tonic-gate } 8260Sstevel@tonic-gate 8270Sstevel@tonic-gate 8280Sstevel@tonic-gate /* 8290Sstevel@tonic-gate * Loop on running a kernel based command 8300Sstevel@tonic-gate * 8310Sstevel@tonic-gate * FIXME: This routine is not really needed. 8320Sstevel@tonic-gate */ 8330Sstevel@tonic-gate int 8340Sstevel@tonic-gate ses_runcmd(ses_softc_t *ssc, Uscmd *lp) 8350Sstevel@tonic-gate { 8360Sstevel@tonic-gate int e; 8370Sstevel@tonic-gate 8380Sstevel@tonic-gate lp->uscsi_status = 0; 8390Sstevel@tonic-gate e = ses_uscsi_cmd(ssc, lp, FKIOCTL, FKIOCTL, FKIOCTL, FKIOCTL); 8400Sstevel@tonic-gate 8410Sstevel@tonic-gate #ifdef not 8420Sstevel@tonic-gate /* 8430Sstevel@tonic-gate * Debug: Nice cross-check code for verifying consistent status. 8440Sstevel@tonic-gate */ 8450Sstevel@tonic-gate if (lp->uscsi_status) { 8460Sstevel@tonic-gate if (lp->uscsi_status == STATUS_CHECK) { 8470Sstevel@tonic-gate SES_LOG(ssc, CE_NOTE, "runcmd<cdb[0]=" 8480Sstevel@tonic-gate "0x%x->%s ASC/ASCQ=0x%x/0x%x>", 8490Sstevel@tonic-gate lp->uscsi_cdb[0], 8500Sstevel@tonic-gate scsi_sname(lp->uscsi_rqbuf[2] & 0xf), 8510Sstevel@tonic-gate lp->uscsi_rqbuf[12] & 0xff, 8520Sstevel@tonic-gate lp->uscsi_rqbuf[13] & 0xff); 8530Sstevel@tonic-gate } else { 8540Sstevel@tonic-gate SES_LOG(ssc, CE_NOTE, "runcmd<cdb[0]=" 8550Sstevel@tonic-gate "0x%x -> Status 0x%x", lp->uscsi_cdb[0], 8560Sstevel@tonic-gate lp->uscsi_status); 8570Sstevel@tonic-gate } 8580Sstevel@tonic-gate } 8590Sstevel@tonic-gate #endif /* not */ 8600Sstevel@tonic-gate return (e); 8610Sstevel@tonic-gate } 8620Sstevel@tonic-gate 8630Sstevel@tonic-gate 8640Sstevel@tonic-gate /* 8650Sstevel@tonic-gate * Run a scsi command. 8660Sstevel@tonic-gate */ 8670Sstevel@tonic-gate int 8680Sstevel@tonic-gate ses_uscsi_cmd(ses_softc_t *ssc, Uscmd *Uc, int Uf, int Cf, int Df, int Rf) 8690Sstevel@tonic-gate { 8700Sstevel@tonic-gate Uscmd local, *lc = &local, *scmd = &ssc->ses_uscsicmd; 8710Sstevel@tonic-gate int err = EOK; 8720Sstevel@tonic-gate int rw, rqlen; 8730Sstevel@tonic-gate struct buf *bp; 8740Sstevel@tonic-gate 8750Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 8760Sstevel@tonic-gate /* 8770Sstevel@tonic-gate * 32 bit application to 64 bit kernel call. 8780Sstevel@tonic-gate */ 8790Sstevel@tonic-gate struct uscsi_cmd32 ucmd_32, *uc = &ucmd_32; 8800Sstevel@tonic-gate 8810Sstevel@tonic-gate switch (ddi_model_convert_from(Uf & FMODELS)) { 8820Sstevel@tonic-gate case DDI_MODEL_ILP32: 8830Sstevel@tonic-gate if (ddi_copyin(Uc, uc, sizeof (*uc), Uf)) { 8840Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG2, efl, __LINE__); 8850Sstevel@tonic-gate return (EFAULT); 8860Sstevel@tonic-gate } 8870Sstevel@tonic-gate uscsi_cmd32touscsi_cmd(uc, lc); 8880Sstevel@tonic-gate break; 8890Sstevel@tonic-gate case DDI_MODEL_NONE: 8900Sstevel@tonic-gate uc = NULL; 8910Sstevel@tonic-gate if (ddi_copyin(Uc, lc, sizeof (*lc), Uf)) { 8920Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG2, efl, __LINE__); 8930Sstevel@tonic-gate return (EFAULT); 8940Sstevel@tonic-gate } 8950Sstevel@tonic-gate break; 8960Sstevel@tonic-gate default: 8970Sstevel@tonic-gate SES_LOG(ssc, CE_NOTE, "Unknown model conversion flag %x", 8980Sstevel@tonic-gate Uf & FMODELS); 8990Sstevel@tonic-gate return (EINVAL); 9000Sstevel@tonic-gate } 9010Sstevel@tonic-gate #else /* _MULTI_DATAMODEL */ 9020Sstevel@tonic-gate if (ddi_copyin(Uc, lc, sizeof (*lc), Uf)) { 9030Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG2, efl, __LINE__); 9040Sstevel@tonic-gate return (EFAULT); 9050Sstevel@tonic-gate } 9060Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 9070Sstevel@tonic-gate 9080Sstevel@tonic-gate /* 9090Sstevel@tonic-gate * Is this a request to reset the bus? 9100Sstevel@tonic-gate * If so, we need go no further. 9110Sstevel@tonic-gate */ 9120Sstevel@tonic-gate if (lc->uscsi_flags & (USCSI_RESET|USCSI_RESET_ALL)) { 9130Sstevel@tonic-gate int flag = ((lc->uscsi_flags & USCSI_RESET_ALL)) ? 9140Sstevel@tonic-gate RESET_ALL : RESET_TARGET; 9150Sstevel@tonic-gate err = (scsi_reset(SES_ROUTE(ssc), flag))? 0 : EIO; 9160Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG1, "reset %s %s\n", 9170Sstevel@tonic-gate (flag == RESET_ALL)? "all" : "target", 9180Sstevel@tonic-gate (err)? "failed" : "ok"); 9190Sstevel@tonic-gate return (err); 9200Sstevel@tonic-gate } 9210Sstevel@tonic-gate 9220Sstevel@tonic-gate /* 9230Sstevel@tonic-gate * First do some sanity checks. 9240Sstevel@tonic-gate */ 9250Sstevel@tonic-gate if (lc->uscsi_cdblen == 0) { 9260Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG1, "cblen %d", lc->uscsi_cdblen); 9270Sstevel@tonic-gate return (EINVAL); 9280Sstevel@tonic-gate } 9290Sstevel@tonic-gate if (lc->uscsi_flags & USCSI_RQENABLE && 9300Sstevel@tonic-gate (lc->uscsi_rqlen == 0 || lc->uscsi_rqbuf == NULL)) { 9310Sstevel@tonic-gate return (EINVAL); 9320Sstevel@tonic-gate } 9330Sstevel@tonic-gate 9340Sstevel@tonic-gate 9350Sstevel@tonic-gate /* 9360Sstevel@tonic-gate * Grab local 'special' buffer 9370Sstevel@tonic-gate */ 9380Sstevel@tonic-gate mutex_enter(SES_MUTEX); 9390Sstevel@tonic-gate while (ssc->ses_sbufbsy) { 9400Sstevel@tonic-gate cv_wait(&ssc->ses_sbufcv, &ssc->ses_devp->sd_mutex); 9410Sstevel@tonic-gate } 9420Sstevel@tonic-gate ssc->ses_sbufbsy = 1; 9430Sstevel@tonic-gate mutex_exit(SES_MUTEX); 9440Sstevel@tonic-gate 9450Sstevel@tonic-gate /* 9460Sstevel@tonic-gate * If the device is powered down, request it's activation. 9470Sstevel@tonic-gate * This check must be done after setting ses_sbufbsy! 9480Sstevel@tonic-gate */ 9490Sstevel@tonic-gate if (ssc->ses_suspended && 9500Sstevel@tonic-gate ddi_dev_is_needed(SES_DEVINFO(ssc), 0, 1) != DDI_SUCCESS) { 9510Sstevel@tonic-gate mutex_enter(SES_MUTEX); 9520Sstevel@tonic-gate ssc->ses_sbufbsy = 0; 9530Sstevel@tonic-gate mutex_exit(SES_MUTEX); 9540Sstevel@tonic-gate return (EIO); 9550Sstevel@tonic-gate } 9560Sstevel@tonic-gate 9570Sstevel@tonic-gate 9580Sstevel@tonic-gate bcopy(lc, scmd, sizeof (Uscmd)); 9590Sstevel@tonic-gate 9600Sstevel@tonic-gate if (ddi_copyin(lc->uscsi_cdb, &ssc->ses_srqcdb, 9610Sstevel@tonic-gate (size_t)scmd->uscsi_cdblen, Cf)) { 9620Sstevel@tonic-gate mutex_enter(SES_MUTEX); 9630Sstevel@tonic-gate ssc->ses_sbufbsy = 0; 9640Sstevel@tonic-gate cv_signal(&ssc->ses_sbufcv); 9650Sstevel@tonic-gate mutex_exit(SES_MUTEX); 9660Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG2, efl, __LINE__); 9670Sstevel@tonic-gate return (EFAULT); 9680Sstevel@tonic-gate } 9690Sstevel@tonic-gate scmd->uscsi_cdb = (char *)ssc->ses_srqcdb; 9700Sstevel@tonic-gate 9710Sstevel@tonic-gate 9720Sstevel@tonic-gate if (scmd->uscsi_flags & USCSI_RQENABLE) { 9730Sstevel@tonic-gate scmd->uscsi_rqlen = min(SENSE_LENGTH, scmd->uscsi_rqlen); 9740Sstevel@tonic-gate scmd->uscsi_rqresid = scmd->uscsi_rqlen; 9750Sstevel@tonic-gate scmd->uscsi_rqbuf = (char *)&ssc->ses_srqsbuf; 9760Sstevel@tonic-gate } else { 9770Sstevel@tonic-gate scmd->uscsi_flags &= ~USCSI_RQENABLE; 9780Sstevel@tonic-gate scmd->uscsi_rqlen = 0; 9790Sstevel@tonic-gate scmd->uscsi_rqresid = 0; 9800Sstevel@tonic-gate scmd->uscsi_rqbuf = (char *)NULL; 9810Sstevel@tonic-gate } 9820Sstevel@tonic-gate 9830Sstevel@tonic-gate /* 9840Sstevel@tonic-gate * Drive on.. 9850Sstevel@tonic-gate */ 9860Sstevel@tonic-gate rw = (scmd->uscsi_flags & USCSI_READ) ? B_READ : B_WRITE; 9870Sstevel@tonic-gate 9880Sstevel@tonic-gate /* 9890Sstevel@tonic-gate * We're going to do actual I/O, 9900Sstevel@tonic-gate * let physio do all the right things. 9910Sstevel@tonic-gate */ 9920Sstevel@tonic-gate bp = ssc->ses_sbufp; 9930Sstevel@tonic-gate bp->av_back = (struct buf *)NULL; 9940Sstevel@tonic-gate bp->av_forw = (struct buf *)NULL; 9950Sstevel@tonic-gate bp->b_back = (struct buf *)ssc; 9960Sstevel@tonic-gate bp->b_edev = NODEV; 9970Sstevel@tonic-gate 9980Sstevel@tonic-gate if (scmd->uscsi_cdblen == CDB_GROUP0) { 9990Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG7, 10000Sstevel@tonic-gate "scsi_cmd: %x %x %x %x %x %x", 10010Sstevel@tonic-gate ssc->ses_srqcdb[0], ssc->ses_srqcdb[1], 10020Sstevel@tonic-gate ssc->ses_srqcdb[2], ssc->ses_srqcdb[3], 10030Sstevel@tonic-gate ssc->ses_srqcdb[4], ssc->ses_srqcdb[5]); 10040Sstevel@tonic-gate } else { 10050Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG7, 10060Sstevel@tonic-gate "scsi cmd: %x %x %x %x %x %x %x %x %x %x", 10070Sstevel@tonic-gate ssc->ses_srqcdb[0], ssc->ses_srqcdb[1], 10080Sstevel@tonic-gate ssc->ses_srqcdb[2], ssc->ses_srqcdb[3], 10090Sstevel@tonic-gate ssc->ses_srqcdb[4], ssc->ses_srqcdb[5], 10100Sstevel@tonic-gate ssc->ses_srqcdb[6], ssc->ses_srqcdb[7], 10110Sstevel@tonic-gate ssc->ses_srqcdb[8], ssc->ses_srqcdb[9]); 10120Sstevel@tonic-gate } 10130Sstevel@tonic-gate 10140Sstevel@tonic-gate if (scmd->uscsi_buflen) { 10150Sstevel@tonic-gate struct iovec aiov; 10160Sstevel@tonic-gate struct uio auio; 10170Sstevel@tonic-gate struct uio *uio = &auio; 10180Sstevel@tonic-gate 10190Sstevel@tonic-gate bzero(&auio, sizeof (struct uio)); 10200Sstevel@tonic-gate bzero(&aiov, sizeof (struct iovec)); 10210Sstevel@tonic-gate 10220Sstevel@tonic-gate aiov.iov_base = scmd->uscsi_bufaddr; 10230Sstevel@tonic-gate aiov.iov_len = scmd->uscsi_buflen; 10240Sstevel@tonic-gate uio->uio_iov = &aiov; 10250Sstevel@tonic-gate uio->uio_iovcnt = 1; 10260Sstevel@tonic-gate uio->uio_resid = aiov.iov_len; 10270Sstevel@tonic-gate uio->uio_segflg = 10280Sstevel@tonic-gate (Df & FKIOCTL)? UIO_SYSSPACE : UIO_USERSPACE; 10290Sstevel@tonic-gate 10300Sstevel@tonic-gate /* 10310Sstevel@tonic-gate * Call physio and let that do the rest. 10320Sstevel@tonic-gate * Note: we wait there until the command is complete. 10330Sstevel@tonic-gate */ 10340Sstevel@tonic-gate err = physio(ses_start, bp, NODEV, rw, minphys, uio); 10350Sstevel@tonic-gate scmd->uscsi_resid = bp->b_resid; 10360Sstevel@tonic-gate } else { 10370Sstevel@tonic-gate /* 10380Sstevel@tonic-gate * Since we do not move any data in this section 10390Sstevel@tonic-gate * call ses_start directly. Mimic physio. 10400Sstevel@tonic-gate */ 10410Sstevel@tonic-gate bp->b_flags = B_BUSY | rw; 10420Sstevel@tonic-gate bp->b_bcount = 0; 10430Sstevel@tonic-gate (void) ses_start(bp); 10440Sstevel@tonic-gate scmd->uscsi_resid = 0; 10450Sstevel@tonic-gate err = biowait(bp); 10460Sstevel@tonic-gate } 10470Sstevel@tonic-gate 10480Sstevel@tonic-gate 10490Sstevel@tonic-gate /* 10500Sstevel@tonic-gate * Copy status and sense data to where it needs to be.. 10510Sstevel@tonic-gate * If the sender of the scsi command is in user space, 10520Sstevel@tonic-gate * mask off the high bits. 10530Sstevel@tonic-gate */ 10540Sstevel@tonic-gate lc->uscsi_status = scmd->uscsi_status; 10550Sstevel@tonic-gate if (lc->uscsi_status) 10560Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG5, "status %x", lc->uscsi_status); 10570Sstevel@tonic-gate lc->uscsi_resid = scmd->uscsi_resid; 10580Sstevel@tonic-gate 10590Sstevel@tonic-gate rqlen = scmd->uscsi_rqlen - scmd->uscsi_rqresid; 10600Sstevel@tonic-gate lc->uscsi_rqresid = scmd->uscsi_rqlen - rqlen; 10610Sstevel@tonic-gate 10620Sstevel@tonic-gate if (lc->uscsi_rqbuf && rqlen) { 10630Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG5, "Sense Key %x", 10640Sstevel@tonic-gate scmd->uscsi_rqbuf[2] & 0xf); 10650Sstevel@tonic-gate if (ddi_copyout(scmd->uscsi_rqbuf, lc->uscsi_rqbuf, 10660Sstevel@tonic-gate rqlen, Rf)) { 10670Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG2, 10680Sstevel@tonic-gate "ses_uscsi_cmd: rqbuf copy-out problem"); 10690Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG2, efl, __LINE__); 10700Sstevel@tonic-gate err = EFAULT; 10710Sstevel@tonic-gate } 10720Sstevel@tonic-gate } 10730Sstevel@tonic-gate 10740Sstevel@tonic-gate /* 10750Sstevel@tonic-gate * Free up allocated resources. 10760Sstevel@tonic-gate */ 10770Sstevel@tonic-gate mutex_enter(SES_MUTEX); 10780Sstevel@tonic-gate ssc->ses_sbufbsy = 0; 10790Sstevel@tonic-gate cv_signal(&ssc->ses_sbufcv); 10800Sstevel@tonic-gate mutex_exit(SES_MUTEX); 10810Sstevel@tonic-gate 10820Sstevel@tonic-gate /* 10830Sstevel@tonic-gate * Copy out changed values 10840Sstevel@tonic-gate */ 10850Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 10860Sstevel@tonic-gate if (uc != NULL) { 10870Sstevel@tonic-gate uscsi_cmdtouscsi_cmd32(lc, uc); 10880Sstevel@tonic-gate if (ddi_copyout(uc, Uc, sizeof (*uc), Uf)) { 10890Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG2, efl, __LINE__); 10900Sstevel@tonic-gate return (EFAULT); 10910Sstevel@tonic-gate } 10920Sstevel@tonic-gate } else 10930Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 10940Sstevel@tonic-gate 10950Sstevel@tonic-gate if (ddi_copyout(lc, Uc, sizeof (*lc), Uf)) { 10960Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG2, efl, __LINE__); 10970Sstevel@tonic-gate if (err == 0) 10980Sstevel@tonic-gate err = EFAULT; 10990Sstevel@tonic-gate } 11000Sstevel@tonic-gate if (err) 11010Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG5, "ses_uscsi_cmd returning %d", err); 11020Sstevel@tonic-gate return (err); 11030Sstevel@tonic-gate } 11040Sstevel@tonic-gate 11050Sstevel@tonic-gate 11060Sstevel@tonic-gate 11070Sstevel@tonic-gate /* 11080Sstevel@tonic-gate * Command start and done functions. 11090Sstevel@tonic-gate */ 11100Sstevel@tonic-gate static int 11110Sstevel@tonic-gate ses_start(struct buf *bp) 11120Sstevel@tonic-gate { 11130Sstevel@tonic-gate ses_softc_t *ssc = (ses_softc_t *)bp->b_back; 11140Sstevel@tonic-gate 11150Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG9, "ses_start"); 11160Sstevel@tonic-gate if (!BP_PKT(bp)) { 11170Sstevel@tonic-gate /* 11180Sstevel@tonic-gate * Allocate a packet. 11190Sstevel@tonic-gate */ 11200Sstevel@tonic-gate ses_get_pkt(bp, SLEEP_FUNC); 11210Sstevel@tonic-gate if (!BP_PKT(bp)) { 11220Sstevel@tonic-gate int err; 11230Sstevel@tonic-gate bp->b_resid = bp->b_bcount; 11240Sstevel@tonic-gate if (geterror(bp) == 0) 11250Sstevel@tonic-gate SET_BP_ERROR(bp, EIO); 11260Sstevel@tonic-gate err = geterror(bp); 11270Sstevel@tonic-gate biodone(bp); 11280Sstevel@tonic-gate return (err); 11290Sstevel@tonic-gate } 11300Sstevel@tonic-gate } 11310Sstevel@tonic-gate 11320Sstevel@tonic-gate /* 11330Sstevel@tonic-gate * Initialize the transfer residue, error code, and retry count. 11340Sstevel@tonic-gate */ 11350Sstevel@tonic-gate bp->b_resid = 0; 11360Sstevel@tonic-gate SET_BP_ERROR(bp, 0); 11370Sstevel@tonic-gate 11380Sstevel@tonic-gate #if !defined(lint) 11390Sstevel@tonic-gate _NOTE(NO_COMPETING_THREADS_NOW); 11400Sstevel@tonic-gate #endif /* !defined(lint) */ 11410Sstevel@tonic-gate ssc->ses_retries = ses_retry_count; 11420Sstevel@tonic-gate 11430Sstevel@tonic-gate #if !defined(lint) 11440Sstevel@tonic-gate /* LINTED */ 11450Sstevel@tonic-gate _NOTE(COMPETING_THREADS_NOW); 11460Sstevel@tonic-gate #endif /* !defined(lint) */ 11470Sstevel@tonic-gate 11480Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG9, "ses_start -> scsi_transport"); 11490Sstevel@tonic-gate switch (scsi_transport(BP_PKT(bp))) { 11500Sstevel@tonic-gate case TRAN_ACCEPT: 11510Sstevel@tonic-gate return (0); 11520Sstevel@tonic-gate /* break; */ 11530Sstevel@tonic-gate 11540Sstevel@tonic-gate case TRAN_BUSY: 11550Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG2, 11560Sstevel@tonic-gate "ses_start: TRANSPORT BUSY"); 11570Sstevel@tonic-gate SES_ENABLE_RESTART(SES_RESTART_TIME, BP_PKT(bp)); 11580Sstevel@tonic-gate return (0); 11590Sstevel@tonic-gate /* break; */ 11600Sstevel@tonic-gate 11610Sstevel@tonic-gate default: 11620Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG2, "TRANSPORT ERROR\n"); 11630Sstevel@tonic-gate SET_BP_ERROR(bp, EIO); 11640Sstevel@tonic-gate scsi_destroy_pkt(BP_PKT(bp)); 11650Sstevel@tonic-gate SET_BP_PKT(bp, NULL); 11660Sstevel@tonic-gate biodone(bp); 11670Sstevel@tonic-gate return (EIO); 11680Sstevel@tonic-gate /* break; */ 11690Sstevel@tonic-gate } 11700Sstevel@tonic-gate } 11710Sstevel@tonic-gate 11720Sstevel@tonic-gate 11730Sstevel@tonic-gate static void 11740Sstevel@tonic-gate ses_get_pkt(struct buf *bp, int (*func)()) 11750Sstevel@tonic-gate { 11760Sstevel@tonic-gate ses_softc_t *ssc = (ses_softc_t *)bp->b_back; 11770Sstevel@tonic-gate Uscmd *scmd = &ssc->ses_uscsicmd; 11780Sstevel@tonic-gate struct scsi_pkt *pkt; 11790Sstevel@tonic-gate int stat_size; 11800Sstevel@tonic-gate 11810Sstevel@tonic-gate if ((scmd->uscsi_flags & USCSI_RQENABLE) && ssc->ses_arq) { 11820Sstevel@tonic-gate stat_size = sizeof (struct scsi_arq_status); 11830Sstevel@tonic-gate } else { 11840Sstevel@tonic-gate stat_size = 1; 11850Sstevel@tonic-gate } 11860Sstevel@tonic-gate 11870Sstevel@tonic-gate if (bp->b_bcount) { 11880Sstevel@tonic-gate pkt = scsi_init_pkt(SES_ROUTE(ssc), NULL, bp, 11890Sstevel@tonic-gate scmd->uscsi_cdblen, stat_size, 0, 0, func, (caddr_t)ssc); 11900Sstevel@tonic-gate } else { 11910Sstevel@tonic-gate pkt = scsi_init_pkt(SES_ROUTE(ssc), NULL, NULL, 11920Sstevel@tonic-gate scmd->uscsi_cdblen, stat_size, 0, 0, func, (caddr_t)ssc); 11930Sstevel@tonic-gate } 11940Sstevel@tonic-gate SET_BP_PKT(bp, pkt); 11950Sstevel@tonic-gate if (pkt == (struct scsi_pkt *)NULL) 11960Sstevel@tonic-gate return; 11970Sstevel@tonic-gate bcopy(scmd->uscsi_cdb, pkt->pkt_cdbp, (size_t)scmd->uscsi_cdblen); 11980Sstevel@tonic-gate pkt->pkt_time = scmd->uscsi_timeout; 11990Sstevel@tonic-gate 12000Sstevel@tonic-gate pkt->pkt_comp = ses_callback; 12010Sstevel@tonic-gate pkt->pkt_private = (opaque_t)ssc; 12020Sstevel@tonic-gate } 12030Sstevel@tonic-gate 12040Sstevel@tonic-gate 12050Sstevel@tonic-gate /* 12060Sstevel@tonic-gate * Restart ses command. 12070Sstevel@tonic-gate */ 12080Sstevel@tonic-gate static void 12090Sstevel@tonic-gate ses_restart(void *arg) 12100Sstevel@tonic-gate { 12110Sstevel@tonic-gate struct scsi_pkt *pkt = (struct scsi_pkt *)arg; 12120Sstevel@tonic-gate ses_softc_t *ssc = (ses_softc_t *)pkt->pkt_private; 12130Sstevel@tonic-gate struct buf *bp = ssc->ses_sbufp; 12140Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG9, "ses_restart"); 12150Sstevel@tonic-gate 12160Sstevel@tonic-gate ssc->ses_restart_id = NULL; 12170Sstevel@tonic-gate 12180Sstevel@tonic-gate switch (scsi_transport(pkt)) { 12190Sstevel@tonic-gate case TRAN_ACCEPT: 12200Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG9, 12210Sstevel@tonic-gate "RESTART %d ok", ssc->ses_retries); 12220Sstevel@tonic-gate return; 12230Sstevel@tonic-gate /* break; */ 12240Sstevel@tonic-gate case TRAN_BUSY: 12250Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG1, 12260Sstevel@tonic-gate "RESTART %d TRANSPORT BUSY\n", ssc->ses_retries); 12270Sstevel@tonic-gate if (ssc->ses_retries > SES_NO_RETRY) { 12280Sstevel@tonic-gate ssc->ses_retries -= SES_BUSY_RETRY; 12290Sstevel@tonic-gate SES_ENABLE_RESTART(SES_RESTART_TIME, pkt); 12300Sstevel@tonic-gate return; 12310Sstevel@tonic-gate } 12320Sstevel@tonic-gate SET_BP_ERROR(bp, EBUSY); 12330Sstevel@tonic-gate break; 12340Sstevel@tonic-gate default: 12350Sstevel@tonic-gate SET_BP_ERROR(bp, EIO); 12360Sstevel@tonic-gate break; 12370Sstevel@tonic-gate } 12380Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG1, 12390Sstevel@tonic-gate "RESTART %d TRANSPORT FAILED\n", ssc->ses_retries); 12400Sstevel@tonic-gate 12410Sstevel@tonic-gate pkt = (struct scsi_pkt *)bp->av_back; 12420Sstevel@tonic-gate scsi_destroy_pkt(pkt); 12430Sstevel@tonic-gate bp->b_resid = bp->b_bcount; 12440Sstevel@tonic-gate SET_BP_PKT(bp, NULL); 12450Sstevel@tonic-gate biodone(bp); 12460Sstevel@tonic-gate } 12470Sstevel@tonic-gate 12480Sstevel@tonic-gate 12490Sstevel@tonic-gate /* 12500Sstevel@tonic-gate * Command completion processing 12510Sstevel@tonic-gate */ 12520Sstevel@tonic-gate #define HBA_RESET (STAT_BUS_RESET|STAT_DEV_RESET|STAT_ABORTED) 12530Sstevel@tonic-gate static void 12540Sstevel@tonic-gate ses_callback(struct scsi_pkt *pkt) 12550Sstevel@tonic-gate { 12560Sstevel@tonic-gate ses_softc_t *ssc = (ses_softc_t *)pkt->pkt_private; 12570Sstevel@tonic-gate struct buf *bp; 12580Sstevel@tonic-gate Uscmd *scmd; 12590Sstevel@tonic-gate int err; 12600Sstevel@tonic-gate char action; 12610Sstevel@tonic-gate 12620Sstevel@tonic-gate bp = ssc->ses_sbufp; 12630Sstevel@tonic-gate scmd = &ssc->ses_uscsicmd; 12640Sstevel@tonic-gate /* SES_LOG(ssc, SES_CE_DEBUG9, "ses_callback"); */ 12650Sstevel@tonic-gate 12660Sstevel@tonic-gate /* 12670Sstevel@tonic-gate * Optimization: Normal completion. 12680Sstevel@tonic-gate */ 12690Sstevel@tonic-gate if (pkt->pkt_reason == CMD_CMPLT && 12700Sstevel@tonic-gate !SCBP_C(pkt) && 12710Sstevel@tonic-gate !(pkt->pkt_flags & FLAG_SENSING) && 12720Sstevel@tonic-gate !pkt->pkt_resid) { 12730Sstevel@tonic-gate scsi_destroy_pkt(pkt); 12740Sstevel@tonic-gate SET_BP_PKT(bp, NULL); 12750Sstevel@tonic-gate biodone(bp); 12760Sstevel@tonic-gate return; 12770Sstevel@tonic-gate } 12780Sstevel@tonic-gate 12790Sstevel@tonic-gate 12800Sstevel@tonic-gate /* 12810Sstevel@tonic-gate * Abnormal completion. 12820Sstevel@tonic-gate * 12830Sstevel@tonic-gate * Assume most common error initially. 12840Sstevel@tonic-gate */ 12850Sstevel@tonic-gate err = EIO; 12860Sstevel@tonic-gate action = COMMAND_DONE; 12870Sstevel@tonic-gate if (scmd->uscsi_flags & USCSI_DIAGNOSE) { 12880Sstevel@tonic-gate ssc->ses_retries = SES_NO_RETRY; 12890Sstevel@tonic-gate } 12900Sstevel@tonic-gate 12910Sstevel@tonic-gate CHECK_PKT: 12920Sstevel@tonic-gate if (pkt->pkt_reason != CMD_CMPLT) { 12930Sstevel@tonic-gate /* Process transport errors. */ 12940Sstevel@tonic-gate switch (pkt->pkt_reason) { 12950Sstevel@tonic-gate case CMD_TIMEOUT: 12960Sstevel@tonic-gate /* 12970Sstevel@tonic-gate * If the transport layer didn't clear the problem, 12980Sstevel@tonic-gate * reset the target. 12990Sstevel@tonic-gate */ 13000Sstevel@tonic-gate if (! (pkt->pkt_statistics & HBA_RESET)) { 13010Sstevel@tonic-gate (void) scsi_reset(&pkt->pkt_address, RESET_TARGET); 13020Sstevel@tonic-gate } 13030Sstevel@tonic-gate err = ETIMEDOUT; 13040Sstevel@tonic-gate break; 13050Sstevel@tonic-gate 13060Sstevel@tonic-gate case CMD_INCOMPLETE: 13070Sstevel@tonic-gate case CMD_UNX_BUS_FREE: 13080Sstevel@tonic-gate /* 13090Sstevel@tonic-gate * No response? If probing, give up. 13100Sstevel@tonic-gate * Otherwise, keep trying until retries exhausted. 13110Sstevel@tonic-gate * Then lockdown the driver as the device is 13120Sstevel@tonic-gate * unplugged. 13130Sstevel@tonic-gate */ 13140Sstevel@tonic-gate if (ssc->ses_retries <= SES_NO_RETRY && 13150Sstevel@tonic-gate !(scmd->uscsi_flags & USCSI_DIAGNOSE)) { 13160Sstevel@tonic-gate ssc->ses_present = SES_CLOSED; 13170Sstevel@tonic-gate } 13180Sstevel@tonic-gate /* Inhibit retries to speed probe/attach. */ 13190Sstevel@tonic-gate if (ssc->ses_present < SES_OPEN) { 13200Sstevel@tonic-gate ssc->ses_retries = SES_NO_RETRY; 13210Sstevel@tonic-gate } 13220Sstevel@tonic-gate /* SES_CMD_RETRY4(ssc->ses_retries); */ 13230Sstevel@tonic-gate err = ENXIO; 13240Sstevel@tonic-gate break; 13250Sstevel@tonic-gate 13260Sstevel@tonic-gate case CMD_DATA_OVR: 13270Sstevel@tonic-gate /* 13280Sstevel@tonic-gate * XXX: Some HBA's (e.g. Adaptec 1740 and 13290Sstevel@tonic-gate * earlier ISP revs) report a DATA OVERRUN 13300Sstevel@tonic-gate * error instead of a transfer residue. So, 13310Sstevel@tonic-gate * we convert the error and restart. 13320Sstevel@tonic-gate */ 13330Sstevel@tonic-gate if ((bp->b_bcount - pkt->pkt_resid) > 0) { 13340Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG6, 13350Sstevel@tonic-gate "ignoring overrun"); 13360Sstevel@tonic-gate pkt->pkt_reason = CMD_CMPLT; 13370Sstevel@tonic-gate err = EOK; 13380Sstevel@tonic-gate goto CHECK_PKT; 13390Sstevel@tonic-gate } 13400Sstevel@tonic-gate ssc->ses_retries = SES_NO_RETRY; 13410Sstevel@tonic-gate /* err = EIO; */ 13420Sstevel@tonic-gate break; 13430Sstevel@tonic-gate 13440Sstevel@tonic-gate case CMD_DMA_DERR: 13450Sstevel@tonic-gate ssc->ses_retries = SES_NO_RETRY; 13460Sstevel@tonic-gate err = EFAULT; 13470Sstevel@tonic-gate break; 13480Sstevel@tonic-gate 13490Sstevel@tonic-gate default: 13500Sstevel@tonic-gate /* err = EIO; */ 13510Sstevel@tonic-gate break; 13520Sstevel@tonic-gate } 13530Sstevel@tonic-gate if (pkt == ssc->ses_rqpkt) { 13540Sstevel@tonic-gate SES_LOG(ssc, CE_WARN, fail_msg, 13550Sstevel@tonic-gate "Request Sense ", 13560Sstevel@tonic-gate scsi_rname(pkt->pkt_reason), 13570Sstevel@tonic-gate (ssc->ses_retries > 0)? 13580Sstevel@tonic-gate "retrying": "giving up"); 13590Sstevel@tonic-gate pkt = (struct scsi_pkt *)bp->av_back; 13600Sstevel@tonic-gate action = QUE_SENSE; 13610Sstevel@tonic-gate } else { 13620Sstevel@tonic-gate SES_LOG(ssc, CE_WARN, fail_msg, 13630Sstevel@tonic-gate "", scsi_rname(pkt->pkt_reason), 13640Sstevel@tonic-gate (ssc->ses_retries > 0)? 13650Sstevel@tonic-gate "retrying": "giving up"); 13660Sstevel@tonic-gate action = QUE_COMMAND; 13670Sstevel@tonic-gate } 13680Sstevel@tonic-gate /* Device exists, allow full error recovery. */ 13690Sstevel@tonic-gate if (ssc->ses_retries > SES_NO_RETRY) { 13700Sstevel@tonic-gate ssc->ses_present = SES_OPEN; 13710Sstevel@tonic-gate } 13720Sstevel@tonic-gate 13730Sstevel@tonic-gate 13740Sstevel@tonic-gate /* 13750Sstevel@tonic-gate * Process status and sense data errors. 13760Sstevel@tonic-gate */ 13770Sstevel@tonic-gate } else { 13780Sstevel@tonic-gate ssc->ses_present = SES_OPEN; 13790Sstevel@tonic-gate action = ses_decode_sense(pkt, &err); 13800Sstevel@tonic-gate } 13810Sstevel@tonic-gate 13820Sstevel@tonic-gate 13830Sstevel@tonic-gate /* 13840Sstevel@tonic-gate * Initiate error recovery action, as needed. 13850Sstevel@tonic-gate */ 13860Sstevel@tonic-gate switch (action) { 13870Sstevel@tonic-gate case QUE_COMMAND_NOW: 13880Sstevel@tonic-gate /* SES_LOG(ssc, SES_CE_DEBUG1, "retrying cmd now"); */ 13890Sstevel@tonic-gate if (ssc->ses_retries > SES_NO_RETRY) { 13900Sstevel@tonic-gate ssc->ses_retries -= SES_CMD_RETRY; 13910Sstevel@tonic-gate scmd->uscsi_status = 0; 13920Sstevel@tonic-gate if (ssc->ses_arq) 13930Sstevel@tonic-gate bzero(pkt->pkt_scbp, sizeof (struct scsi_arq_status)); 13940Sstevel@tonic-gate 13950Sstevel@tonic-gate if (scsi_transport((struct scsi_pkt *)bp->av_back) 13960Sstevel@tonic-gate != TRAN_ACCEPT) { 13970Sstevel@tonic-gate SES_ENABLE_RESTART(SES_RESTART_TIME, 13980Sstevel@tonic-gate (struct scsi_pkt *)bp->av_back); 13990Sstevel@tonic-gate } 14000Sstevel@tonic-gate return; 14010Sstevel@tonic-gate } 14020Sstevel@tonic-gate break; 14030Sstevel@tonic-gate 14040Sstevel@tonic-gate case QUE_COMMAND: 14050Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG1, "retrying cmd"); 14060Sstevel@tonic-gate if (ssc->ses_retries > SES_NO_RETRY) { 14070Sstevel@tonic-gate ssc->ses_retries -= 14080Sstevel@tonic-gate (err == EBUSY)? SES_BUSY_RETRY: SES_CMD_RETRY; 14090Sstevel@tonic-gate scmd->uscsi_status = 0; 14100Sstevel@tonic-gate if (ssc->ses_arq) 14110Sstevel@tonic-gate bzero(pkt->pkt_scbp, sizeof (struct scsi_arq_status)); 14120Sstevel@tonic-gate 14130Sstevel@tonic-gate SES_ENABLE_RESTART( 14140Sstevel@tonic-gate (err == EBUSY)? SES_BUSY_TIME: SES_RESTART_TIME, 14150Sstevel@tonic-gate (struct scsi_pkt *)bp->av_back); 14160Sstevel@tonic-gate return; 14170Sstevel@tonic-gate } 14180Sstevel@tonic-gate break; 14190Sstevel@tonic-gate 14200Sstevel@tonic-gate case QUE_SENSE: 14210Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG1, "retrying sense"); 14220Sstevel@tonic-gate if (ssc->ses_retries > SES_NO_RETRY) { 14230Sstevel@tonic-gate ssc->ses_retries -= SES_SENSE_RETRY; 14240Sstevel@tonic-gate scmd->uscsi_status = 0; 14250Sstevel@tonic-gate bzero(&ssc->ses_srqsbuf, 14260Sstevel@tonic-gate sizeof (struct scsi_extended_sense)); 14270Sstevel@tonic-gate 14280Sstevel@tonic-gate if (scsi_transport(ssc->ses_rqpkt) != TRAN_ACCEPT) { 14290Sstevel@tonic-gate SES_ENABLE_RESTART(SES_RESTART_TIME, 14300Sstevel@tonic-gate ssc->ses_rqpkt); 14310Sstevel@tonic-gate } 14320Sstevel@tonic-gate return; 14330Sstevel@tonic-gate } 14340Sstevel@tonic-gate break; 14350Sstevel@tonic-gate 14360Sstevel@tonic-gate case COMMAND_DONE: 14370Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG4, "cmd done"); 14380Sstevel@tonic-gate pkt = (struct scsi_pkt *)bp->av_back; 14390Sstevel@tonic-gate bp->b_resid = pkt->pkt_resid; 14400Sstevel@tonic-gate if (bp->b_resid) { 14410Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG6, 14420Sstevel@tonic-gate "transfer residue %ld(%ld)", 14430Sstevel@tonic-gate bp->b_bcount - bp->b_resid, bp->b_bcount); 14440Sstevel@tonic-gate } 14450Sstevel@tonic-gate break; 14460Sstevel@tonic-gate } 14470Sstevel@tonic-gate pkt = (struct scsi_pkt *)bp->av_back; 14480Sstevel@tonic-gate if (err) { 14490Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG1, "SES: ERROR %d\n", err); 14500Sstevel@tonic-gate SET_BP_ERROR(bp, err); 14510Sstevel@tonic-gate bp->b_resid = bp->b_bcount; 14520Sstevel@tonic-gate } 14530Sstevel@tonic-gate scsi_destroy_pkt(pkt); 14540Sstevel@tonic-gate SET_BP_PKT(bp, NULL); 14550Sstevel@tonic-gate biodone(bp); 14560Sstevel@tonic-gate } 14570Sstevel@tonic-gate 14580Sstevel@tonic-gate 14590Sstevel@tonic-gate /* 14600Sstevel@tonic-gate * Check status and sense data and determine recovery. 14610Sstevel@tonic-gate */ 14620Sstevel@tonic-gate static int 14630Sstevel@tonic-gate ses_decode_sense(struct scsi_pkt *pkt, int *err) 14640Sstevel@tonic-gate { 14650Sstevel@tonic-gate ses_softc_t *ssc = (ses_softc_t *)pkt->pkt_private; 14660Sstevel@tonic-gate struct scsi_extended_sense *sense = 14670Sstevel@tonic-gate (struct scsi_extended_sense *)&ssc->ses_srqsbuf; 14680Sstevel@tonic-gate Uscmd *scmd = &ssc->ses_uscsicmd; 14690Sstevel@tonic-gate char sense_flag = 0; 14700Sstevel@tonic-gate uchar_t status = SCBP_C(pkt) & STATUS_MASK; 14710Sstevel@tonic-gate char *err_action; 14720Sstevel@tonic-gate char action; 14730Sstevel@tonic-gate 14740Sstevel@tonic-gate /* 14750Sstevel@tonic-gate * Process manual request sense. 14760Sstevel@tonic-gate * Copy manual request sense to sense buffer. 14770Sstevel@tonic-gate * 14780Sstevel@tonic-gate * This is done if auto request sense is not enabled. 14790Sstevel@tonic-gate * Or the auto request sense failed and the request 14800Sstevel@tonic-gate * sense needs to be retried. 14810Sstevel@tonic-gate */ 14820Sstevel@tonic-gate if (pkt->pkt_flags & FLAG_SENSING) { 14830Sstevel@tonic-gate struct buf *sbp = ssc->ses_rqbp; 14840Sstevel@tonic-gate int amt = min(SENSE_LENGTH, 14850Sstevel@tonic-gate sbp->b_bcount - sbp->b_resid); 14860Sstevel@tonic-gate 14870Sstevel@tonic-gate bcopy(sbp->b_un.b_addr, sense, amt); 14880Sstevel@tonic-gate scmd->uscsi_rqresid = scmd->uscsi_rqlen - amt; 14890Sstevel@tonic-gate sense_flag = 1; 14900Sstevel@tonic-gate 14910Sstevel@tonic-gate /* 14920Sstevel@tonic-gate * Process auto request sense. 14930Sstevel@tonic-gate * Copy auto request sense to sense buffer. 14940Sstevel@tonic-gate * 14950Sstevel@tonic-gate * If auto request sense failed due to transport error, 14960Sstevel@tonic-gate * retry the command. Otherwise process the status and 14970Sstevel@tonic-gate * sense data. 14980Sstevel@tonic-gate */ 14990Sstevel@tonic-gate } else if (ssc->ses_arq && pkt->pkt_state & STATE_ARQ_DONE) { 15000Sstevel@tonic-gate struct scsi_arq_status *arq = 15010Sstevel@tonic-gate (struct scsi_arq_status *)(pkt->pkt_scbp); 15020Sstevel@tonic-gate int amt = min(sizeof (arq->sts_sensedata), SENSE_LENGTH); 15030Sstevel@tonic-gate uchar_t *arq_status = (uchar_t *)&arq->sts_rqpkt_status; 15040Sstevel@tonic-gate 15050Sstevel@tonic-gate if (arq->sts_rqpkt_reason != CMD_CMPLT) { 15060Sstevel@tonic-gate return (QUE_COMMAND); 15070Sstevel@tonic-gate } 15080Sstevel@tonic-gate bcopy(&arq->sts_sensedata, sense, amt); 15090Sstevel@tonic-gate scmd->uscsi_status = status; 15100Sstevel@tonic-gate scmd->uscsi_rqresid = scmd->uscsi_rqlen - amt; 15110Sstevel@tonic-gate status = *arq_status & STATUS_MASK; 15120Sstevel@tonic-gate pkt->pkt_state &= ~STATE_ARQ_DONE; 15130Sstevel@tonic-gate sense_flag = 1; 15140Sstevel@tonic-gate } 15150Sstevel@tonic-gate 15160Sstevel@tonic-gate 15170Sstevel@tonic-gate /* 15180Sstevel@tonic-gate * Check status of REQUEST SENSE or command. 15190Sstevel@tonic-gate * 15200Sstevel@tonic-gate * If it's not successful, try retrying the original command 15210Sstevel@tonic-gate * and hope that it goes away. If not, we'll eventually run 15220Sstevel@tonic-gate * out of retries and die. 15230Sstevel@tonic-gate */ 15240Sstevel@tonic-gate switch (status) { 15250Sstevel@tonic-gate case STATUS_GOOD: 15260Sstevel@tonic-gate case STATUS_INTERMEDIATE: 15270Sstevel@tonic-gate case STATUS_MET: 15280Sstevel@tonic-gate /* 15290Sstevel@tonic-gate * If the command status is ok, we're done. 15300Sstevel@tonic-gate * Otherwise, examine the request sense data. 15310Sstevel@tonic-gate */ 15320Sstevel@tonic-gate if (! sense_flag) { 15330Sstevel@tonic-gate *err = EOK; 15340Sstevel@tonic-gate return (COMMAND_DONE); 15350Sstevel@tonic-gate } 15360Sstevel@tonic-gate break; 15370Sstevel@tonic-gate 15380Sstevel@tonic-gate case STATUS_CHECK: 15390Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG3, "status decode: check"); 15400Sstevel@tonic-gate *err = EIO; 15410Sstevel@tonic-gate return (QUE_SENSE); 15420Sstevel@tonic-gate /* break; */ 15430Sstevel@tonic-gate 15440Sstevel@tonic-gate case STATUS_BUSY: 15450Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG1, "status decode: busy"); 15460Sstevel@tonic-gate /* SES_CMD_RETRY2(ssc->ses_retries); */ 15470Sstevel@tonic-gate *err = EBUSY; 15480Sstevel@tonic-gate return (QUE_COMMAND); 15490Sstevel@tonic-gate /* break; */ 15500Sstevel@tonic-gate 15510Sstevel@tonic-gate case STATUS_RESERVATION_CONFLICT: 15520Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG1, "status decode: reserved"); 15530Sstevel@tonic-gate *err = EACCES; 15540Sstevel@tonic-gate return (COMMAND_DONE_ERROR); 15550Sstevel@tonic-gate /* break; */ 15560Sstevel@tonic-gate 15570Sstevel@tonic-gate case STATUS_TERMINATED: 15580Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG1, "status decode: terminated"); 15590Sstevel@tonic-gate *err = ECANCELED; 15600Sstevel@tonic-gate return (COMMAND_DONE_ERROR); 15610Sstevel@tonic-gate /* break; */ 15620Sstevel@tonic-gate 15630Sstevel@tonic-gate default: 15640Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG1, "status 0x%x", status); 15650Sstevel@tonic-gate *err = EIO; 15660Sstevel@tonic-gate return (QUE_COMMAND); 15670Sstevel@tonic-gate /* break; */ 15680Sstevel@tonic-gate } 15690Sstevel@tonic-gate 15700Sstevel@tonic-gate 15710Sstevel@tonic-gate /* 15720Sstevel@tonic-gate * Check REQUEST SENSE error code. 15730Sstevel@tonic-gate * 15740Sstevel@tonic-gate * Either there's no error, a retryable error, 15750Sstevel@tonic-gate * or it's dead. SES devices aren't very complex. 15760Sstevel@tonic-gate */ 15770Sstevel@tonic-gate err_action = "retrying"; 15780Sstevel@tonic-gate switch (sense->es_key) { 15790Sstevel@tonic-gate case KEY_RECOVERABLE_ERROR: 15800Sstevel@tonic-gate *err = EOK; 15810Sstevel@tonic-gate err_action = "recovered"; 15820Sstevel@tonic-gate action = COMMAND_DONE; 15830Sstevel@tonic-gate break; 15840Sstevel@tonic-gate 15850Sstevel@tonic-gate case KEY_UNIT_ATTENTION: 15860Sstevel@tonic-gate /* 15870Sstevel@tonic-gate * This is common for RAID! 15880Sstevel@tonic-gate */ 15890Sstevel@tonic-gate /* *err = EIO; */ 15900Sstevel@tonic-gate SES_CMD_RETRY1(ssc->ses_retries); 15910Sstevel@tonic-gate action = QUE_COMMAND_NOW; 15920Sstevel@tonic-gate break; 15930Sstevel@tonic-gate 15940Sstevel@tonic-gate case KEY_NOT_READY: 15950Sstevel@tonic-gate case KEY_NO_SENSE: 15960Sstevel@tonic-gate /* *err = EIO; */ 15970Sstevel@tonic-gate action = QUE_COMMAND; 15980Sstevel@tonic-gate break; 15990Sstevel@tonic-gate 16000Sstevel@tonic-gate default: 16010Sstevel@tonic-gate /* *err = EIO; */ 16020Sstevel@tonic-gate err_action = "fatal"; 16030Sstevel@tonic-gate action = COMMAND_DONE_ERROR; 16040Sstevel@tonic-gate break; 16050Sstevel@tonic-gate } 16060Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG1, 16070Sstevel@tonic-gate "cdb[0]= 0x%x %s, key=0x%x, ASC/ASCQ=0x%x/0x%x", 16080Sstevel@tonic-gate scmd->uscsi_cdb[0], err_action, 16090Sstevel@tonic-gate sense->es_key, sense->es_add_code, sense->es_qual_code); 16100Sstevel@tonic-gate 16110Sstevel@tonic-gate #ifdef not 16120Sstevel@tonic-gate /* 16130Sstevel@tonic-gate * Dump cdb and sense data stat's for manufacturing. 16140Sstevel@tonic-gate */ 16150Sstevel@tonic-gate if (DEBUGGING_ERR || sd_error_level == SDERR_ALL) { 16160Sstevel@tonic-gate auto buf[128]; 16170Sstevel@tonic-gate 16180Sstevel@tonic-gate p = pkt->pkt_cdbp; 16190Sstevel@tonic-gate if ((j = scsi_cdb_size[CDB_GROUPID(*p)]) == 0) 16200Sstevel@tonic-gate j = CDB_SIZE; 16210Sstevel@tonic-gate 16220Sstevel@tonic-gate /* Print cdb */ 16230Sstevel@tonic-gate (void) sprintf(buf, "cmd:"); 16240Sstevel@tonic-gate for (i = 0; i < j; i++) { 16250Sstevel@tonic-gate (void) sprintf(&buf[strlen(buf)], 16260Sstevel@tonic-gate hex, (uchar_t)*p++); 16270Sstevel@tonic-gate } 16280Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG3, "%s", buf); 16290Sstevel@tonic-gate 16300Sstevel@tonic-gate /* Suppress trailing zero's in sense data */ 16310Sstevel@tonic-gate if (amt > 3) { 16320Sstevel@tonic-gate p = (char *)devp->sd_sense + amt; 16330Sstevel@tonic-gate for (j = amt; j > 3; j--) { 16340Sstevel@tonic-gate if (*(--p)) break; 16350Sstevel@tonic-gate } 16360Sstevel@tonic-gate } else { 16370Sstevel@tonic-gate j = amt; 16380Sstevel@tonic-gate } 16390Sstevel@tonic-gate 16400Sstevel@tonic-gate /* Print sense data. */ 16410Sstevel@tonic-gate (void) sprintf(buf, "sense:"); 16420Sstevel@tonic-gate p = (char *)devp->sd_sense; 16430Sstevel@tonic-gate for (i = 0; i < j; i++) { 16440Sstevel@tonic-gate (void) sprintf(&buf[strlen(buf)], 16450Sstevel@tonic-gate hex, (uchar_t)*p++); 16460Sstevel@tonic-gate } 16470Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG3, "%s", buf); 16480Sstevel@tonic-gate } 16490Sstevel@tonic-gate #endif /* not */ 16500Sstevel@tonic-gate return (action); 16510Sstevel@tonic-gate } 16520Sstevel@tonic-gate 16530Sstevel@tonic-gate 16540Sstevel@tonic-gate /*PRINTFLIKE3*/ 16550Sstevel@tonic-gate void 16560Sstevel@tonic-gate ses_log(ses_softc_t *ssc, int level, const char *fmt, ...) 16570Sstevel@tonic-gate { 16580Sstevel@tonic-gate va_list ap; 16590Sstevel@tonic-gate char buf[256]; 16600Sstevel@tonic-gate 16610Sstevel@tonic-gate va_start(ap, fmt); 16620Sstevel@tonic-gate (void) vsprintf(buf, fmt, ap); 16630Sstevel@tonic-gate va_end(ap); 16640Sstevel@tonic-gate 16650Sstevel@tonic-gate if (ssc == (ses_softc_t *)NULL) { 16660Sstevel@tonic-gate switch (level) { 16670Sstevel@tonic-gate case SES_CE_DEBUG1: 16680Sstevel@tonic-gate if (ses_debug > 1) 16690Sstevel@tonic-gate cmn_err(CE_NOTE, "%s", buf); 16700Sstevel@tonic-gate break; 16710Sstevel@tonic-gate case SES_CE_DEBUG2: 16720Sstevel@tonic-gate if (ses_debug > 2) 16730Sstevel@tonic-gate cmn_err(CE_NOTE, "%s", buf); 16740Sstevel@tonic-gate break; 16750Sstevel@tonic-gate case SES_CE_DEBUG3: 16760Sstevel@tonic-gate if (ses_debug > 3) 16770Sstevel@tonic-gate cmn_err(CE_NOTE, "%s", buf); 16780Sstevel@tonic-gate break; 16790Sstevel@tonic-gate case SES_CE_DEBUG4: 16800Sstevel@tonic-gate if (ses_debug > 4) 16810Sstevel@tonic-gate cmn_err(CE_NOTE, "%s", buf); 16820Sstevel@tonic-gate break; 16830Sstevel@tonic-gate case SES_CE_DEBUG5: 16840Sstevel@tonic-gate if (ses_debug > 5) 16850Sstevel@tonic-gate cmn_err(CE_NOTE, "%s", buf); 16860Sstevel@tonic-gate break; 16870Sstevel@tonic-gate case SES_CE_DEBUG6: 16880Sstevel@tonic-gate if (ses_debug > 6) 16890Sstevel@tonic-gate cmn_err(CE_NOTE, "%s", buf); 16900Sstevel@tonic-gate break; 16910Sstevel@tonic-gate case SES_CE_DEBUG7: 16920Sstevel@tonic-gate if (ses_debug > 7) 16930Sstevel@tonic-gate cmn_err(CE_NOTE, "%s", buf); 16940Sstevel@tonic-gate break; 16950Sstevel@tonic-gate case SES_CE_DEBUG8: 16960Sstevel@tonic-gate if (ses_debug > 8) 16970Sstevel@tonic-gate cmn_err(CE_NOTE, "%s", buf); 16980Sstevel@tonic-gate break; 16990Sstevel@tonic-gate case SES_CE_DEBUG9: 17000Sstevel@tonic-gate if (ses_debug > 9) 17010Sstevel@tonic-gate cmn_err(CE_NOTE, "%s", buf); 17020Sstevel@tonic-gate break; 17030Sstevel@tonic-gate case CE_NOTE: 17040Sstevel@tonic-gate case CE_WARN: 17050Sstevel@tonic-gate case CE_PANIC: 17060Sstevel@tonic-gate cmn_err(level, "%s", buf); 17070Sstevel@tonic-gate break; 17080Sstevel@tonic-gate case SES_CE_DEBUG: 17090Sstevel@tonic-gate default: 17100Sstevel@tonic-gate cmn_err(CE_NOTE, "%s", buf); 17110Sstevel@tonic-gate break; 17120Sstevel@tonic-gate } 17130Sstevel@tonic-gate return; 17140Sstevel@tonic-gate } 17150Sstevel@tonic-gate 17160Sstevel@tonic-gate switch (level) { 17170Sstevel@tonic-gate case CE_CONT: 17180Sstevel@tonic-gate case CE_NOTE: 17190Sstevel@tonic-gate case CE_WARN: 17200Sstevel@tonic-gate case CE_PANIC: 17210Sstevel@tonic-gate scsi_log(SES_DEVINFO(ssc), (char *)Snm, level, Str, buf); 17220Sstevel@tonic-gate break; 17230Sstevel@tonic-gate case SES_CE_DEBUG1: 17240Sstevel@tonic-gate if (ses_debug > 1) 17250Sstevel@tonic-gate scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG, 17260Sstevel@tonic-gate Str, buf); 17270Sstevel@tonic-gate break; 17280Sstevel@tonic-gate case SES_CE_DEBUG2: 17290Sstevel@tonic-gate if (ses_debug > 2) 17300Sstevel@tonic-gate scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG, 17310Sstevel@tonic-gate Str, buf); 17320Sstevel@tonic-gate break; 17330Sstevel@tonic-gate case SES_CE_DEBUG3: 17340Sstevel@tonic-gate if (ses_debug > 3) 17350Sstevel@tonic-gate scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG, 17360Sstevel@tonic-gate Str, buf); 17370Sstevel@tonic-gate break; 17380Sstevel@tonic-gate case SES_CE_DEBUG4: 17390Sstevel@tonic-gate if (ses_debug > 4) 17400Sstevel@tonic-gate scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG, 17410Sstevel@tonic-gate Str, buf); 17420Sstevel@tonic-gate break; 17430Sstevel@tonic-gate case SES_CE_DEBUG5: 17440Sstevel@tonic-gate if (ses_debug > 5) 17450Sstevel@tonic-gate scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG, 17460Sstevel@tonic-gate Str, buf); 17470Sstevel@tonic-gate break; 17480Sstevel@tonic-gate case SES_CE_DEBUG6: 17490Sstevel@tonic-gate if (ses_debug > 6) 17500Sstevel@tonic-gate scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG, 17510Sstevel@tonic-gate Str, buf); 17520Sstevel@tonic-gate break; 17530Sstevel@tonic-gate case SES_CE_DEBUG7: 17540Sstevel@tonic-gate if (ses_debug > 7) 17550Sstevel@tonic-gate scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG, 17560Sstevel@tonic-gate Str, buf); 17570Sstevel@tonic-gate break; 17580Sstevel@tonic-gate case SES_CE_DEBUG8: 17590Sstevel@tonic-gate if (ses_debug > 8) 17600Sstevel@tonic-gate scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG, 17610Sstevel@tonic-gate Str, buf); 17620Sstevel@tonic-gate break; 17630Sstevel@tonic-gate case SES_CE_DEBUG9: 17640Sstevel@tonic-gate if (ses_debug > 9) 17650Sstevel@tonic-gate scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG, 17660Sstevel@tonic-gate Str, buf); 17670Sstevel@tonic-gate break; 17680Sstevel@tonic-gate case SES_CE_DEBUG: 17690Sstevel@tonic-gate default: 17700Sstevel@tonic-gate scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG, Str, buf); 17710Sstevel@tonic-gate break; 17720Sstevel@tonic-gate } 17730Sstevel@tonic-gate } 17740Sstevel@tonic-gate /* 17750Sstevel@tonic-gate * mode: c 17760Sstevel@tonic-gate * Local variables: 17770Sstevel@tonic-gate * c-indent-level: 8 17780Sstevel@tonic-gate * c-brace-imaginary-offset: 0 17790Sstevel@tonic-gate * c-brace-offset: -8 17800Sstevel@tonic-gate * c-argdecl-indent: 8 17810Sstevel@tonic-gate * c-label-offset: -8 17820Sstevel@tonic-gate * c-continued-statement-offset: 8 17830Sstevel@tonic-gate * c-continued-brace-offset: 0 17840Sstevel@tonic-gate * End: 17850Sstevel@tonic-gate */ 1786