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 53368Slh195018 * Common Development and Distribution License (the "License"). 63368Slh195018 * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 220Sstevel@tonic-gate * Enclosure Services Device target driver 230Sstevel@tonic-gate * 246316Seschrock * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 250Sstevel@tonic-gate * Use is subject to license terms. 260Sstevel@tonic-gate */ 270Sstevel@tonic-gate 280Sstevel@tonic-gate #include <sys/modctl.h> 290Sstevel@tonic-gate #include <sys/file.h> 300Sstevel@tonic-gate #include <sys/scsi/scsi.h> 310Sstevel@tonic-gate #include <sys/scsi/generic/status.h> 320Sstevel@tonic-gate #include <sys/scsi/targets/sesio.h> 330Sstevel@tonic-gate #include <sys/scsi/targets/ses.h> 340Sstevel@tonic-gate 350Sstevel@tonic-gate 360Sstevel@tonic-gate 370Sstevel@tonic-gate /* 380Sstevel@tonic-gate * Power management defines (should be in a common include file?) 390Sstevel@tonic-gate */ 400Sstevel@tonic-gate #define PM_HARDWARE_STATE_PROP "pm-hardware-state" 410Sstevel@tonic-gate #define PM_NEEDS_SUSPEND_RESUME "needs-suspend-resume" 420Sstevel@tonic-gate 430Sstevel@tonic-gate 440Sstevel@tonic-gate /* 450Sstevel@tonic-gate * Global Driver Data 460Sstevel@tonic-gate */ 470Sstevel@tonic-gate int ses_io_time = SES_IO_TIME; 480Sstevel@tonic-gate 490Sstevel@tonic-gate static int ses_retry_count = SES_RETRY_COUNT * SES_RETRY_MULTIPLIER; 500Sstevel@tonic-gate 510Sstevel@tonic-gate #ifdef DEBUG 520Sstevel@tonic-gate int ses_debug = 0; 530Sstevel@tonic-gate #else /* DEBUG */ 540Sstevel@tonic-gate #define ses_debug 0 550Sstevel@tonic-gate #endif /* DEBUG */ 560Sstevel@tonic-gate 570Sstevel@tonic-gate 580Sstevel@tonic-gate /* 590Sstevel@tonic-gate * External Enclosure Functions 600Sstevel@tonic-gate */ 610Sstevel@tonic-gate extern int ses_softc_init(ses_softc_t *, int); 620Sstevel@tonic-gate extern int ses_init_enc(ses_softc_t *); 630Sstevel@tonic-gate extern int ses_get_encstat(ses_softc_t *, int); 640Sstevel@tonic-gate extern int ses_set_encstat(ses_softc_t *, uchar_t, int); 650Sstevel@tonic-gate extern int ses_get_objstat(ses_softc_t *, ses_objarg *, int); 660Sstevel@tonic-gate extern int ses_set_objstat(ses_softc_t *, ses_objarg *, int); 670Sstevel@tonic-gate 680Sstevel@tonic-gate extern int safte_softc_init(ses_softc_t *, int); 690Sstevel@tonic-gate extern int safte_init_enc(ses_softc_t *); 700Sstevel@tonic-gate extern int safte_get_encstat(ses_softc_t *, int); 710Sstevel@tonic-gate extern int safte_set_encstat(ses_softc_t *, uchar_t, int); 720Sstevel@tonic-gate extern int safte_get_objstat(ses_softc_t *, ses_objarg *, int); 730Sstevel@tonic-gate extern int safte_set_objstat(ses_softc_t *, ses_objarg *, int); 740Sstevel@tonic-gate 750Sstevel@tonic-gate extern int sen_softc_init(ses_softc_t *, int); 760Sstevel@tonic-gate extern int sen_init_enc(ses_softc_t *); 770Sstevel@tonic-gate extern int sen_get_encstat(ses_softc_t *, int); 780Sstevel@tonic-gate extern int sen_set_encstat(ses_softc_t *, uchar_t, int); 790Sstevel@tonic-gate extern int sen_get_objstat(ses_softc_t *, ses_objarg *, int); 800Sstevel@tonic-gate extern int sen_set_objstat(ses_softc_t *, ses_objarg *, int); 810Sstevel@tonic-gate 820Sstevel@tonic-gate /* 830Sstevel@tonic-gate * Local Function prototypes 840Sstevel@tonic-gate */ 850Sstevel@tonic-gate static int ses_info(dev_info_t *, ddi_info_cmd_t, void *, void **); 860Sstevel@tonic-gate static int ses_probe(dev_info_t *); 870Sstevel@tonic-gate static int ses_attach(dev_info_t *, ddi_attach_cmd_t); 880Sstevel@tonic-gate static int ses_detach(dev_info_t *, ddi_detach_cmd_t); 890Sstevel@tonic-gate 900Sstevel@tonic-gate static int is_enc_dev(ses_softc_t *, struct scsi_inquiry *, int, enctyp *); 910Sstevel@tonic-gate static int ses_doattach(dev_info_t *dip); 920Sstevel@tonic-gate 930Sstevel@tonic-gate static int ses_open(dev_t *, int, int, cred_t *); 940Sstevel@tonic-gate static int ses_close(dev_t, int, int, cred_t *); 950Sstevel@tonic-gate static int ses_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 960Sstevel@tonic-gate 970Sstevel@tonic-gate static encvec vecs[3] = { 980Sstevel@tonic-gate { 990Sstevel@tonic-gate ses_softc_init, ses_init_enc, ses_get_encstat, 1000Sstevel@tonic-gate ses_set_encstat, ses_get_objstat, ses_set_objstat 1010Sstevel@tonic-gate }, 1020Sstevel@tonic-gate { 1030Sstevel@tonic-gate safte_softc_init, safte_init_enc, safte_get_encstat, 1040Sstevel@tonic-gate safte_set_encstat, safte_get_objstat, safte_set_objstat, 1050Sstevel@tonic-gate }, 1060Sstevel@tonic-gate { 1070Sstevel@tonic-gate sen_softc_init, sen_init_enc, sen_get_encstat, 1080Sstevel@tonic-gate sen_set_encstat, sen_get_objstat, sen_set_objstat 1090Sstevel@tonic-gate } 1100Sstevel@tonic-gate }; 1110Sstevel@tonic-gate 1120Sstevel@tonic-gate 1130Sstevel@tonic-gate /* 1140Sstevel@tonic-gate * Local Functions 1150Sstevel@tonic-gate */ 1160Sstevel@tonic-gate static int ses_start(struct buf *bp); 1170Sstevel@tonic-gate static int ses_decode_sense(struct scsi_pkt *pkt, int *err); 1180Sstevel@tonic-gate 1190Sstevel@tonic-gate static void ses_get_pkt(struct buf *bp, int (*func)(opaque_t)); 1200Sstevel@tonic-gate static void ses_callback(struct scsi_pkt *pkt); 1210Sstevel@tonic-gate static void ses_restart(void *arg); 1220Sstevel@tonic-gate 1230Sstevel@tonic-gate 1240Sstevel@tonic-gate /* 1250Sstevel@tonic-gate * Local Static Data 1260Sstevel@tonic-gate */ 1270Sstevel@tonic-gate #ifndef D_HOTPLUG 1280Sstevel@tonic-gate #define D_HOTPLUG 0 1290Sstevel@tonic-gate #endif /* D_HOTPLUG */ 1300Sstevel@tonic-gate 1310Sstevel@tonic-gate static struct cb_ops ses_cb_ops = { 1320Sstevel@tonic-gate ses_open, /* open */ 1330Sstevel@tonic-gate ses_close, /* close */ 1340Sstevel@tonic-gate nodev, /* strategy */ 1350Sstevel@tonic-gate nodev, /* print */ 1360Sstevel@tonic-gate nodev, /* dump */ 1370Sstevel@tonic-gate nodev, /* read */ 1380Sstevel@tonic-gate nodev, /* write */ 1390Sstevel@tonic-gate ses_ioctl, /* ioctl */ 1400Sstevel@tonic-gate nodev, /* devmap */ 1410Sstevel@tonic-gate nodev, /* mmap */ 1420Sstevel@tonic-gate nodev, /* segmap */ 1430Sstevel@tonic-gate nochpoll, /* poll */ 1440Sstevel@tonic-gate ddi_prop_op, /* cb_prop_op */ 1450Sstevel@tonic-gate 0, /* streamtab */ 1460Sstevel@tonic-gate #if !defined(CB_REV) 1470Sstevel@tonic-gate D_MP | D_NEW | D_HOTPLUG /* Driver compatibility flag */ 1480Sstevel@tonic-gate #else /* !defined(CB_REV) */ 1490Sstevel@tonic-gate D_MP | D_NEW | D_HOTPLUG, /* Driver compatibility flag */ 1500Sstevel@tonic-gate CB_REV, /* cb_ops version number */ 1510Sstevel@tonic-gate nodev, /* aread */ 1520Sstevel@tonic-gate nodev /* awrite */ 1530Sstevel@tonic-gate #endif /* !defined(CB_REV) */ 1540Sstevel@tonic-gate }; 1550Sstevel@tonic-gate 1560Sstevel@tonic-gate static struct dev_ops ses_dev_ops = { 1570Sstevel@tonic-gate DEVO_REV, /* devo_rev, */ 1580Sstevel@tonic-gate 0, /* refcnt */ 1590Sstevel@tonic-gate ses_info, /* info */ 1600Sstevel@tonic-gate nulldev, /* identify */ 1610Sstevel@tonic-gate ses_probe, /* probe */ 1620Sstevel@tonic-gate ses_attach, /* attach */ 1630Sstevel@tonic-gate ses_detach, /* detach */ 1640Sstevel@tonic-gate nodev, /* reset */ 1650Sstevel@tonic-gate &ses_cb_ops, /* driver operations */ 1660Sstevel@tonic-gate (struct bus_ops *)NULL, /* bus operations */ 167*7656SSherry.Moore@Sun.COM NULL, /* power */ 168*7656SSherry.Moore@Sun.COM ddi_quiesce_not_needed, /* quiesce */ 1690Sstevel@tonic-gate }; 1700Sstevel@tonic-gate 1710Sstevel@tonic-gate static void *estate = NULL; 1720Sstevel@tonic-gate static const char *Snm = "ses"; 1730Sstevel@tonic-gate static const char *Str = "%s\n"; 1740Sstevel@tonic-gate static const char *efl = "copyin/copyout EFAULT @ line %d"; 1750Sstevel@tonic-gate static const char *fail_msg = "%stransport failed: reason '%s': %s"; 1760Sstevel@tonic-gate 1770Sstevel@tonic-gate 1780Sstevel@tonic-gate 1790Sstevel@tonic-gate /* 1800Sstevel@tonic-gate * autoconfiguration routines. 1810Sstevel@tonic-gate */ 1820Sstevel@tonic-gate char _depends_on[] = "misc/scsi"; 1830Sstevel@tonic-gate 1840Sstevel@tonic-gate static struct modldrv modldrv = { 185*7656SSherry.Moore@Sun.COM &mod_driverops, 186*7656SSherry.Moore@Sun.COM "SCSI Enclosure Services", 187*7656SSherry.Moore@Sun.COM &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) { 2606316Seschrock 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: 2656316Seschrock if (is_enc_dev(NULL, devp->sd_inq, SUN_INQSIZE, &ep)) { 2666316Seschrock break; 2676316Seschrock } 2680Sstevel@tonic-gate /* FALLTHROUGH */ 2690Sstevel@tonic-gate case SCSIPROBE_NORESP: 2706316Seschrock scsi_unprobe(devp); 2716316Seschrock return (DDI_PROBE_FAILURE); 2720Sstevel@tonic-gate default: 2736316Seschrock SES_LOG(NULL, SES_CE_DEBUG9, 2746316Seschrock "ses_probe: probe error %d", err); 2756316Seschrock scsi_unprobe(devp); 2766316Seschrock 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; 3286948Sjmcp } else if (inqp->inq_rdf == RDF_SCSI2) { 3296948Sjmcp /* 3306948Sjmcp * Per SPC4 #6.4.2 Standard Inquiry Data, response 3316948Sjmcp * data format (RDF) values of 0 and 1 are Obsolete, 3326948Sjmcp * whereas values greater than 2 are Reserved 3336948Sjmcp */ 3340Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG3, "SES device found"); 3350Sstevel@tonic-gate *ep = SES_TYPE; 3360Sstevel@tonic-gate } else { 3370Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG3, "Pre-SCSI3 SES device"); 3380Sstevel@tonic-gate *ep = SES_TYPE; 3390Sstevel@tonic-gate } 3400Sstevel@tonic-gate return (1); 3410Sstevel@tonic-gate } 3420Sstevel@tonic-gate if ((iqd[6] & 0x40) && inqp->inq_rdf >= RDF_SCSI2) { 3430Sstevel@tonic-gate /* 3440Sstevel@tonic-gate * PassThrough Device. 3450Sstevel@tonic-gate */ 3460Sstevel@tonic-gate *ep = SES_TYPE; 3470Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG3, "Passthru SES device"); 3480Sstevel@tonic-gate return (1); 3490Sstevel@tonic-gate } 3500Sstevel@tonic-gate 3510Sstevel@tonic-gate if (iqlen < 47) { 3520Sstevel@tonic-gate SES_LOG(ssc, CE_NOTE, 3530Sstevel@tonic-gate "INQUIRY data too short to determine SAF-TE"); 3540Sstevel@tonic-gate return (0); 3550Sstevel@tonic-gate } 3560Sstevel@tonic-gate if (strncmp((char *)&iqd[44], "SAF-TE", 4) == 0) { 3570Sstevel@tonic-gate *ep = SAFT_TYPE; 3580Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG3, "SAF-TE device found"); 3590Sstevel@tonic-gate return (1); 3600Sstevel@tonic-gate } 3610Sstevel@tonic-gate return (0); 3620Sstevel@tonic-gate } 3630Sstevel@tonic-gate 3640Sstevel@tonic-gate 3650Sstevel@tonic-gate /* 3660Sstevel@tonic-gate * Attach ses device. 3670Sstevel@tonic-gate * 3680Sstevel@tonic-gate * XXX: Power management is NOT supported. A token framework 3690Sstevel@tonic-gate * is provided that will need to be extended assuming we have 3700Sstevel@tonic-gate * ses devices we can power down. Currently, we don't have any. 3710Sstevel@tonic-gate */ 3720Sstevel@tonic-gate static int 3730Sstevel@tonic-gate ses_doattach(dev_info_t *dip) 3740Sstevel@tonic-gate { 3750Sstevel@tonic-gate int inst, err; 3760Sstevel@tonic-gate Scsidevp devp; 3770Sstevel@tonic-gate ses_softc_t *ssc; 3780Sstevel@tonic-gate enctyp etyp; 3790Sstevel@tonic-gate 3800Sstevel@tonic-gate inst = ddi_get_instance(dip); 3810Sstevel@tonic-gate /* 3820Sstevel@tonic-gate * Workaround for bug #4154979- for some reason we can 3830Sstevel@tonic-gate * be called with identical instance numbers but for 3840Sstevel@tonic-gate * different dev_info_t-s- all but one are bogus. 3850Sstevel@tonic-gate * 3860Sstevel@tonic-gate * Bad Dog! No Biscuit! 3870Sstevel@tonic-gate * 3880Sstevel@tonic-gate * A quick workaround might be to call ddi_soft_state_zalloc 3890Sstevel@tonic-gate * unconditionally, as the implementation fails these calls 3900Sstevel@tonic-gate * if there's an item already allocated. A more reasonable 3910Sstevel@tonic-gate * and longer term change is to move the allocation past 3920Sstevel@tonic-gate * the probe for the device's existence as most of these 3930Sstevel@tonic-gate * 'bogus' calls are for nonexistent devices. 3940Sstevel@tonic-gate */ 3950Sstevel@tonic-gate 3960Sstevel@tonic-gate devp = ddi_get_driver_private(dip); 3970Sstevel@tonic-gate devp->sd_dev = dip; 3980Sstevel@tonic-gate 3990Sstevel@tonic-gate /* 4000Sstevel@tonic-gate * Determine whether the { i, t, l } we're called 4010Sstevel@tonic-gate * to start is an enclosure services device. 4020Sstevel@tonic-gate */ 4030Sstevel@tonic-gate 4040Sstevel@tonic-gate /* 4050Sstevel@tonic-gate * Call the scsi_probe routine to see whether 4060Sstevel@tonic-gate * we actually have an Enclosure Services device at 4070Sstevel@tonic-gate * this address. 4080Sstevel@tonic-gate */ 4090Sstevel@tonic-gate err = scsi_probe(devp, SLEEP_FUNC); 4100Sstevel@tonic-gate if (err != SCSIPROBE_EXISTS) { 4110Sstevel@tonic-gate SES_LOG(NULL, SES_CE_DEBUG9, 4120Sstevel@tonic-gate "ses_doattach: probe error %d", err); 4130Sstevel@tonic-gate scsi_unprobe(devp); 4140Sstevel@tonic-gate return (DDI_FAILURE); 4150Sstevel@tonic-gate } 4160Sstevel@tonic-gate /* Call is_enc_dev() to get the etyp */ 4170Sstevel@tonic-gate if (!(is_enc_dev(NULL, devp->sd_inq, SUN_INQSIZE, &etyp))) { 4180Sstevel@tonic-gate SES_LOG(NULL, CE_WARN, 4190Sstevel@tonic-gate "ses_doattach: ses%d: is_enc_dev failure", inst); 4200Sstevel@tonic-gate scsi_unprobe(devp); 4210Sstevel@tonic-gate return (DDI_FAILURE); 4220Sstevel@tonic-gate } 4230Sstevel@tonic-gate 4240Sstevel@tonic-gate if (ddi_soft_state_zalloc(estate, inst) != DDI_SUCCESS) { 4250Sstevel@tonic-gate scsi_unprobe(devp); 4260Sstevel@tonic-gate SES_LOG(NULL, CE_NOTE, "ses%d: softalloc fails", inst); 4270Sstevel@tonic-gate return (DDI_FAILURE); 4280Sstevel@tonic-gate } 4290Sstevel@tonic-gate ssc = ddi_get_soft_state(estate, inst); 4300Sstevel@tonic-gate if (ssc == NULL) { 4310Sstevel@tonic-gate scsi_unprobe(devp); 4320Sstevel@tonic-gate SES_LOG(NULL, CE_NOTE, "ses%d: get_soft_state fails", inst); 4330Sstevel@tonic-gate return (DDI_FAILURE); 4340Sstevel@tonic-gate } 4350Sstevel@tonic-gate devp->sd_private = (opaque_t)ssc; 4360Sstevel@tonic-gate ssc->ses_devp = devp; 4370Sstevel@tonic-gate err = ddi_create_minor_node(dip, "0", S_IFCHR, inst, 4386316Seschrock DDI_NT_SCSI_ENCLOSURE, NULL); 4390Sstevel@tonic-gate if (err == DDI_FAILURE) { 4400Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL); 4410Sstevel@tonic-gate SES_LOG(ssc, CE_NOTE, "minor node creation failed"); 4420Sstevel@tonic-gate ddi_soft_state_free(estate, inst); 4430Sstevel@tonic-gate scsi_unprobe(devp); 4440Sstevel@tonic-gate return (DDI_FAILURE); 4450Sstevel@tonic-gate } 4460Sstevel@tonic-gate 4470Sstevel@tonic-gate ssc->ses_type = etyp; 4480Sstevel@tonic-gate ssc->ses_vec = vecs[etyp]; 4490Sstevel@tonic-gate 4500Sstevel@tonic-gate /* Call SoftC Init Routine A bit later... */ 4510Sstevel@tonic-gate 4520Sstevel@tonic-gate ssc->ses_rqbp = scsi_alloc_consistent_buf(SES_ROUTE(ssc), 4537424SLi.He@Sun.COM NULL, MAX_SENSE_LENGTH, B_READ, SLEEP_FUNC, NULL); 4540Sstevel@tonic-gate if (ssc->ses_rqbp != NULL) { 4550Sstevel@tonic-gate ssc->ses_rqpkt = scsi_init_pkt(SES_ROUTE(ssc), NULL, 4560Sstevel@tonic-gate ssc->ses_rqbp, CDB_GROUP0, 1, 0, PKT_CONSISTENT, 4570Sstevel@tonic-gate SLEEP_FUNC, NULL); 4580Sstevel@tonic-gate } 4590Sstevel@tonic-gate if (ssc->ses_rqbp == NULL || ssc->ses_rqpkt == NULL) { 4600Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL); 4610Sstevel@tonic-gate SES_LOG(ssc, CE_NOTE, "scsi_init_pkt of rqbuf failed"); 4620Sstevel@tonic-gate if (ssc->ses_rqbp != NULL) { 4630Sstevel@tonic-gate scsi_free_consistent_buf(ssc->ses_rqbp); 4640Sstevel@tonic-gate ssc->ses_rqbp = NULL; 4650Sstevel@tonic-gate } 4660Sstevel@tonic-gate ddi_soft_state_free(estate, inst); 4670Sstevel@tonic-gate scsi_unprobe(devp); 4680Sstevel@tonic-gate return (DDI_FAILURE); 4690Sstevel@tonic-gate } 4700Sstevel@tonic-gate ssc->ses_rqpkt->pkt_private = (opaque_t)ssc; 4710Sstevel@tonic-gate ssc->ses_rqpkt->pkt_address = *(SES_ROUTE(ssc)); 4720Sstevel@tonic-gate ssc->ses_rqpkt->pkt_comp = ses_callback; 4730Sstevel@tonic-gate ssc->ses_rqpkt->pkt_time = ses_io_time; 4740Sstevel@tonic-gate ssc->ses_rqpkt->pkt_flags = FLAG_NOPARITY|FLAG_NODISCON|FLAG_SENSING; 4750Sstevel@tonic-gate ssc->ses_rqpkt->pkt_cdbp[0] = SCMD_REQUEST_SENSE; 4760Sstevel@tonic-gate ssc->ses_rqpkt->pkt_cdbp[1] = 0; 4770Sstevel@tonic-gate ssc->ses_rqpkt->pkt_cdbp[2] = 0; 4780Sstevel@tonic-gate ssc->ses_rqpkt->pkt_cdbp[3] = 0; 4797424SLi.He@Sun.COM ssc->ses_rqpkt->pkt_cdbp[4] = MAX_SENSE_LENGTH; 4800Sstevel@tonic-gate ssc->ses_rqpkt->pkt_cdbp[5] = 0; 4810Sstevel@tonic-gate 4820Sstevel@tonic-gate switch (scsi_ifgetcap(SES_ROUTE(ssc), "auto-rqsense", 1)) { 4830Sstevel@tonic-gate case 1: 4840Sstevel@tonic-gate /* if already set, don't reset it */ 4850Sstevel@tonic-gate ssc->ses_arq = 1; 4860Sstevel@tonic-gate break; 4870Sstevel@tonic-gate case 0: 4880Sstevel@tonic-gate /* try and set it */ 4890Sstevel@tonic-gate ssc->ses_arq = ((scsi_ifsetcap(SES_ROUTE(ssc), 4900Sstevel@tonic-gate "auto-rqsense", 1, 1) == 1) ? 1 : 0); 4910Sstevel@tonic-gate break; 4920Sstevel@tonic-gate default: 4930Sstevel@tonic-gate /* probably undefined, so zero it out */ 4940Sstevel@tonic-gate ssc->ses_arq = 0; 4950Sstevel@tonic-gate break; 4960Sstevel@tonic-gate } 4970Sstevel@tonic-gate 4980Sstevel@tonic-gate ssc->ses_sbufp = getrbuf(KM_SLEEP); 4990Sstevel@tonic-gate cv_init(&ssc->ses_sbufcv, NULL, CV_DRIVER, NULL); 5000Sstevel@tonic-gate 5010Sstevel@tonic-gate /* 5020Sstevel@tonic-gate * If the HBA supports wide, tell it to use wide. 5030Sstevel@tonic-gate */ 5040Sstevel@tonic-gate if (scsi_ifgetcap(SES_ROUTE(ssc), "wide-xfer", 1) != -1) { 5050Sstevel@tonic-gate int wd = ((devp->sd_inq->inq_rdf == RDF_SCSI2) && 5060Sstevel@tonic-gate (devp->sd_inq->inq_wbus16 || devp->sd_inq->inq_wbus32)) 5070Sstevel@tonic-gate ? 1 : 0; 5080Sstevel@tonic-gate (void) scsi_ifsetcap(SES_ROUTE(ssc), "wide-xfer", wd, 1); 5090Sstevel@tonic-gate } 5100Sstevel@tonic-gate 5110Sstevel@tonic-gate /* 5120Sstevel@tonic-gate * Now do ssc init of enclosure specifics. 5130Sstevel@tonic-gate * At the same time, check to make sure getrbuf 5140Sstevel@tonic-gate * actually succeeded. 5150Sstevel@tonic-gate */ 516752Srralphs if ((*ssc->ses_vec.softc_init)(ssc, 1)) { 517752Srralphs SES_LOG(ssc, SES_CE_DEBUG3, "failed softc init"); 518752Srralphs (void) (*ssc->ses_vec.softc_init)(ssc, 0); 5190Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL); 5200Sstevel@tonic-gate scsi_destroy_pkt(ssc->ses_rqpkt); 5210Sstevel@tonic-gate scsi_free_consistent_buf(ssc->ses_rqbp); 5220Sstevel@tonic-gate if (ssc->ses_sbufp) { 5230Sstevel@tonic-gate freerbuf(ssc->ses_sbufp); 5240Sstevel@tonic-gate } 5250Sstevel@tonic-gate cv_destroy(&ssc->ses_sbufcv); 5260Sstevel@tonic-gate ddi_soft_state_free(estate, inst); 5270Sstevel@tonic-gate scsi_unprobe(devp); 5280Sstevel@tonic-gate return (DDI_FAILURE); 5290Sstevel@tonic-gate } 5300Sstevel@tonic-gate 5310Sstevel@tonic-gate /* 5320Sstevel@tonic-gate * create this property so that PM code knows we want 5330Sstevel@tonic-gate * to be suspended at PM time 5340Sstevel@tonic-gate */ 5350Sstevel@tonic-gate (void) ddi_prop_update_string(DDI_DEV_T_NONE, dip, 5360Sstevel@tonic-gate PM_HARDWARE_STATE_PROP, PM_NEEDS_SUSPEND_RESUME); 5370Sstevel@tonic-gate 5380Sstevel@tonic-gate /* announce the existence of this device */ 5390Sstevel@tonic-gate ddi_report_dev(dip); 5400Sstevel@tonic-gate return (DDI_SUCCESS); 5410Sstevel@tonic-gate } 5420Sstevel@tonic-gate 5430Sstevel@tonic-gate 5440Sstevel@tonic-gate /* 5450Sstevel@tonic-gate * Detach ses device. 5460Sstevel@tonic-gate * 5470Sstevel@tonic-gate * XXX: Power management is NOT supported. A token framework 5480Sstevel@tonic-gate * is provided that will need to be extended assuming we have 5490Sstevel@tonic-gate * ses devices we can power down. Currently, we don't have any. 5500Sstevel@tonic-gate */ 5510Sstevel@tonic-gate static int 5520Sstevel@tonic-gate ses_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 5530Sstevel@tonic-gate { 5540Sstevel@tonic-gate ses_softc_t *ssc; 5550Sstevel@tonic-gate int inst; 5560Sstevel@tonic-gate 5570Sstevel@tonic-gate switch (cmd) { 5580Sstevel@tonic-gate case DDI_DETACH: 5590Sstevel@tonic-gate inst = ddi_get_instance(dip); 5600Sstevel@tonic-gate ssc = ddi_get_soft_state(estate, inst); 5610Sstevel@tonic-gate if (ssc == NULL) { 5620Sstevel@tonic-gate cmn_err(CE_NOTE, 5630Sstevel@tonic-gate "ses%d: DDI_DETACH, no softstate found", inst); 5640Sstevel@tonic-gate return (DDI_FAILURE); 5650Sstevel@tonic-gate } 5660Sstevel@tonic-gate if (ISOPEN(ssc)) { 5670Sstevel@tonic-gate return (DDI_FAILURE); 5680Sstevel@tonic-gate } 5690Sstevel@tonic-gate 5700Sstevel@tonic-gate #if !defined(lint) 5710Sstevel@tonic-gate /* LINTED */ 5720Sstevel@tonic-gate _NOTE(COMPETING_THREADS_NOW); 5730Sstevel@tonic-gate #endif /* !defined(lint) */ 5740Sstevel@tonic-gate 5750Sstevel@tonic-gate if (ssc->ses_vec.softc_init) 5760Sstevel@tonic-gate (void) (*ssc->ses_vec.softc_init)(ssc, 0); 5770Sstevel@tonic-gate 5780Sstevel@tonic-gate #if !defined(lint) 5790Sstevel@tonic-gate _NOTE(NO_COMPETING_THREADS_NOW); 5800Sstevel@tonic-gate #endif /* !defined(lint) */ 5810Sstevel@tonic-gate 5820Sstevel@tonic-gate (void) scsi_ifsetcap(SES_ROUTE(ssc), "auto-rqsense", 1, 0); 5830Sstevel@tonic-gate scsi_destroy_pkt(ssc->ses_rqpkt); 5840Sstevel@tonic-gate scsi_free_consistent_buf(ssc->ses_rqbp); 5850Sstevel@tonic-gate freerbuf(ssc->ses_sbufp); 5860Sstevel@tonic-gate cv_destroy(&ssc->ses_sbufcv); 5870Sstevel@tonic-gate ddi_soft_state_free(estate, inst); 5880Sstevel@tonic-gate ddi_prop_remove_all(dip); 5890Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL); 5900Sstevel@tonic-gate scsi_unprobe(ddi_get_driver_private(dip)); 5910Sstevel@tonic-gate break; 5920Sstevel@tonic-gate 5930Sstevel@tonic-gate case DDI_SUSPEND: 5940Sstevel@tonic-gate inst = ddi_get_instance(dip); 5950Sstevel@tonic-gate if ((ssc = ddi_get_soft_state(estate, inst)) == NULL) { 5960Sstevel@tonic-gate cmn_err(CE_NOTE, 5970Sstevel@tonic-gate "ses%d: DDI_SUSPEND, no softstate found", inst); 5980Sstevel@tonic-gate return (DDI_FAILURE); 5990Sstevel@tonic-gate } 6000Sstevel@tonic-gate 6010Sstevel@tonic-gate /* 6020Sstevel@tonic-gate * If driver idle, accept suspend request. 6030Sstevel@tonic-gate * If it's busy, reject it. This keeps things simple! 6040Sstevel@tonic-gate */ 6050Sstevel@tonic-gate mutex_enter(SES_MUTEX); 6060Sstevel@tonic-gate if (ssc->ses_sbufbsy) { 6070Sstevel@tonic-gate mutex_exit(SES_MUTEX); 6080Sstevel@tonic-gate return (DDI_FAILURE); 6090Sstevel@tonic-gate } 6100Sstevel@tonic-gate ssc->ses_suspended = 1; 6110Sstevel@tonic-gate mutex_exit(SES_MUTEX); 6120Sstevel@tonic-gate break; 6130Sstevel@tonic-gate 6140Sstevel@tonic-gate default: 6150Sstevel@tonic-gate return (DDI_FAILURE); 6160Sstevel@tonic-gate } 6170Sstevel@tonic-gate return (DDI_SUCCESS); 6180Sstevel@tonic-gate } 6190Sstevel@tonic-gate 6200Sstevel@tonic-gate /* ARGSUSED */ 6210Sstevel@tonic-gate static int 6220Sstevel@tonic-gate ses_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 6230Sstevel@tonic-gate { 6240Sstevel@tonic-gate dev_t dev; 6250Sstevel@tonic-gate ses_softc_t *ssc; 6260Sstevel@tonic-gate int inst, error; 6270Sstevel@tonic-gate 6280Sstevel@tonic-gate switch (infocmd) { 6290Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 6300Sstevel@tonic-gate dev = (dev_t)arg; 6310Sstevel@tonic-gate inst = getminor(dev); 6320Sstevel@tonic-gate if ((ssc = ddi_get_soft_state(estate, inst)) == NULL) { 6330Sstevel@tonic-gate return (DDI_FAILURE); 6340Sstevel@tonic-gate } 6350Sstevel@tonic-gate *result = (void *) ssc->ses_devp->sd_dev; 6360Sstevel@tonic-gate error = DDI_SUCCESS; 6370Sstevel@tonic-gate break; 6380Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 6390Sstevel@tonic-gate dev = (dev_t)arg; 6400Sstevel@tonic-gate inst = getminor(dev); 6410Sstevel@tonic-gate *result = (void *)(uintptr_t)inst; 6420Sstevel@tonic-gate error = DDI_SUCCESS; 6430Sstevel@tonic-gate break; 6440Sstevel@tonic-gate default: 6450Sstevel@tonic-gate error = DDI_FAILURE; 6460Sstevel@tonic-gate } 6470Sstevel@tonic-gate return (error); 6480Sstevel@tonic-gate } 6490Sstevel@tonic-gate 650*7656SSherry.Moore@Sun.COM 6510Sstevel@tonic-gate /* 6520Sstevel@tonic-gate * Unix Entry Points 6530Sstevel@tonic-gate */ 6540Sstevel@tonic-gate 6550Sstevel@tonic-gate /* ARGSUSED */ 6560Sstevel@tonic-gate static int 6570Sstevel@tonic-gate ses_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p) 6580Sstevel@tonic-gate { 6590Sstevel@tonic-gate ses_softc_t *ssc; 6600Sstevel@tonic-gate 6610Sstevel@tonic-gate if ((ssc = ddi_get_soft_state(estate, getminor(*dev_p))) == NULL) { 6620Sstevel@tonic-gate return (ENXIO); 6630Sstevel@tonic-gate } 6640Sstevel@tonic-gate 6650Sstevel@tonic-gate /* 6660Sstevel@tonic-gate * If the device is powered down, request it's activation. 6670Sstevel@tonic-gate * If it can't be activated, fail open. 6680Sstevel@tonic-gate */ 6690Sstevel@tonic-gate if (ssc->ses_suspended && 6700Sstevel@tonic-gate ddi_dev_is_needed(SES_DEVINFO(ssc), 0, 1) != DDI_SUCCESS) { 6710Sstevel@tonic-gate return (EIO); 6720Sstevel@tonic-gate } 6730Sstevel@tonic-gate 6740Sstevel@tonic-gate mutex_enter(SES_MUTEX); 6750Sstevel@tonic-gate if (otyp == OTYP_LYR) 6760Sstevel@tonic-gate ssc->ses_lyropen++; 6770Sstevel@tonic-gate else 6780Sstevel@tonic-gate ssc->ses_oflag = 1; 6790Sstevel@tonic-gate 6800Sstevel@tonic-gate ssc->ses_present = (ssc->ses_present)? ssc->ses_present: SES_OPENING; 6810Sstevel@tonic-gate mutex_exit(SES_MUTEX); 6820Sstevel@tonic-gate return (EOK); 6830Sstevel@tonic-gate } 6840Sstevel@tonic-gate 6850Sstevel@tonic-gate /*ARGSUSED*/ 6860Sstevel@tonic-gate static int 6870Sstevel@tonic-gate ses_close(dev_t dev, int flag, int otyp, cred_t *cred_p) 6880Sstevel@tonic-gate { 6890Sstevel@tonic-gate ses_softc_t *ssc; 6900Sstevel@tonic-gate if ((ssc = ddi_get_soft_state(estate, getminor(dev))) == NULL) { 6910Sstevel@tonic-gate return (ENXIO); 6920Sstevel@tonic-gate } 6930Sstevel@tonic-gate 6940Sstevel@tonic-gate if (ssc->ses_suspended) { 6950Sstevel@tonic-gate (void) ddi_dev_is_needed(SES_DEVINFO(ssc), 0, 1); 6960Sstevel@tonic-gate } 6970Sstevel@tonic-gate 6980Sstevel@tonic-gate mutex_enter(SES_MUTEX); 6990Sstevel@tonic-gate if (otyp == OTYP_LYR) 7000Sstevel@tonic-gate ssc->ses_lyropen -= (ssc->ses_lyropen)? 1: 0; 7010Sstevel@tonic-gate else 7020Sstevel@tonic-gate ssc->ses_oflag = 0; 7030Sstevel@tonic-gate mutex_exit(SES_MUTEX); 7040Sstevel@tonic-gate return (0); 7050Sstevel@tonic-gate } 7060Sstevel@tonic-gate 7070Sstevel@tonic-gate 7080Sstevel@tonic-gate /*ARGSUSED3*/ 7090Sstevel@tonic-gate static int 7100Sstevel@tonic-gate ses_ioctl(dev_t dev, int cmd, intptr_t arg, int flg, cred_t *cred_p, int *rvalp) 7110Sstevel@tonic-gate { 7120Sstevel@tonic-gate ses_softc_t *ssc; 7130Sstevel@tonic-gate ses_object k, *up; 7140Sstevel@tonic-gate ses_objarg x; 7150Sstevel@tonic-gate uchar_t t; 7160Sstevel@tonic-gate uchar_t i; 7170Sstevel@tonic-gate int rv = 0; 7180Sstevel@tonic-gate 7190Sstevel@tonic-gate if ((ssc = ddi_get_soft_state(estate, getminor(dev))) == NULL || 7200Sstevel@tonic-gate ssc->ses_present == SES_CLOSED) { 7210Sstevel@tonic-gate return (ENXIO); 7220Sstevel@tonic-gate } 7230Sstevel@tonic-gate 7240Sstevel@tonic-gate 7250Sstevel@tonic-gate switch (cmd) { 7260Sstevel@tonic-gate case SESIOC_GETNOBJ: 7270Sstevel@tonic-gate if (ddi_copyout(&ssc->ses_nobjects, (void *)arg, 7280Sstevel@tonic-gate sizeof (int), flg)) { 7290Sstevel@tonic-gate rv = EFAULT; 7300Sstevel@tonic-gate break; 7310Sstevel@tonic-gate } 7320Sstevel@tonic-gate break; 7330Sstevel@tonic-gate 7340Sstevel@tonic-gate case SESIOC_GETOBJMAP: 7350Sstevel@tonic-gate up = (ses_object *) arg; 7360Sstevel@tonic-gate mutex_enter(SES_MUTEX); 7370Sstevel@tonic-gate for (i = 0; i != ssc->ses_nobjects; i++) { 7380Sstevel@tonic-gate k.obj_id = i; 7390Sstevel@tonic-gate k.subencid = ssc->ses_objmap[i].subenclosure; 7400Sstevel@tonic-gate k.elem_type = ssc->ses_objmap[i].enctype; 7410Sstevel@tonic-gate if (ddi_copyout(&k, up, sizeof (k), flg)) { 7420Sstevel@tonic-gate rv = EFAULT; 7430Sstevel@tonic-gate break; 7440Sstevel@tonic-gate } 7450Sstevel@tonic-gate up++; 7460Sstevel@tonic-gate } 7470Sstevel@tonic-gate mutex_exit(SES_MUTEX); 7480Sstevel@tonic-gate break; 7490Sstevel@tonic-gate 7500Sstevel@tonic-gate case SESIOC_INIT: 7510Sstevel@tonic-gate rv = (*ssc->ses_vec.init_enc)(ssc); 7520Sstevel@tonic-gate break; 7530Sstevel@tonic-gate 7540Sstevel@tonic-gate case SESIOC_GETENCSTAT: 7550Sstevel@tonic-gate if ((ssc->ses_encstat & ENCI_SVALID) == 0) { 7560Sstevel@tonic-gate rv = (*ssc->ses_vec.get_encstat)(ssc, KM_SLEEP); 7570Sstevel@tonic-gate if (rv) { 7580Sstevel@tonic-gate break; 7590Sstevel@tonic-gate } 7600Sstevel@tonic-gate } 7610Sstevel@tonic-gate t = ssc->ses_encstat & 0xf; 7620Sstevel@tonic-gate if (ddi_copyout(&t, (void *)arg, sizeof (t), flg)) 7630Sstevel@tonic-gate rv = EFAULT; 7640Sstevel@tonic-gate /* 7650Sstevel@tonic-gate * And always invalidate enclosure status on the way out. 7660Sstevel@tonic-gate */ 7670Sstevel@tonic-gate mutex_enter(SES_MUTEX); 7680Sstevel@tonic-gate ssc->ses_encstat &= ~ENCI_SVALID; 7690Sstevel@tonic-gate mutex_exit(SES_MUTEX); 7700Sstevel@tonic-gate break; 7710Sstevel@tonic-gate 7720Sstevel@tonic-gate case SESIOC_SETENCSTAT: 7730Sstevel@tonic-gate if (ddi_copyin((void *)arg, &t, sizeof (t), flg)) 7740Sstevel@tonic-gate rv = EFAULT; 7750Sstevel@tonic-gate else 7760Sstevel@tonic-gate rv = (*ssc->ses_vec.set_encstat)(ssc, t, KM_SLEEP); 7770Sstevel@tonic-gate mutex_enter(SES_MUTEX); 7780Sstevel@tonic-gate ssc->ses_encstat &= ~ENCI_SVALID; 7790Sstevel@tonic-gate mutex_exit(SES_MUTEX); 7800Sstevel@tonic-gate break; 7810Sstevel@tonic-gate 7820Sstevel@tonic-gate case SESIOC_GETOBJSTAT: 7830Sstevel@tonic-gate if (ddi_copyin((void *)arg, &x, sizeof (x), flg)) { 7840Sstevel@tonic-gate rv = EFAULT; 7850Sstevel@tonic-gate break; 7860Sstevel@tonic-gate } 7870Sstevel@tonic-gate if (x.obj_id >= ssc->ses_nobjects) { 7880Sstevel@tonic-gate rv = EINVAL; 7890Sstevel@tonic-gate break; 7900Sstevel@tonic-gate } 7910Sstevel@tonic-gate if ((rv = (*ssc->ses_vec.get_objstat)(ssc, &x, KM_SLEEP)) != 0) 7920Sstevel@tonic-gate break; 7930Sstevel@tonic-gate if (ddi_copyout(&x, (void *)arg, sizeof (x), flg)) 7940Sstevel@tonic-gate rv = EFAULT; 7950Sstevel@tonic-gate else { 7960Sstevel@tonic-gate /* 7970Sstevel@tonic-gate * Now that we no longer poll, svalid never stays true. 7980Sstevel@tonic-gate */ 7990Sstevel@tonic-gate mutex_enter(SES_MUTEX); 8000Sstevel@tonic-gate ssc->ses_objmap[x.obj_id].svalid = 0; 8010Sstevel@tonic-gate mutex_exit(SES_MUTEX); 8020Sstevel@tonic-gate } 8030Sstevel@tonic-gate break; 8040Sstevel@tonic-gate 8050Sstevel@tonic-gate case SESIOC_SETOBJSTAT: 8060Sstevel@tonic-gate if (ddi_copyin((void *)arg, &x, sizeof (x), flg)) { 8070Sstevel@tonic-gate rv = EFAULT; 8080Sstevel@tonic-gate break; 8090Sstevel@tonic-gate } 8100Sstevel@tonic-gate if (x.obj_id >= ssc->ses_nobjects) { 8110Sstevel@tonic-gate rv = EINVAL; 8120Sstevel@tonic-gate break; 8130Sstevel@tonic-gate } 8140Sstevel@tonic-gate rv = (*ssc->ses_vec.set_objstat)(ssc, &x, KM_SLEEP); 8150Sstevel@tonic-gate if (rv == 0) { 8160Sstevel@tonic-gate mutex_enter(SES_MUTEX); 8170Sstevel@tonic-gate ssc->ses_objmap[x.obj_id].svalid = 0; 8180Sstevel@tonic-gate mutex_exit(SES_MUTEX); 8190Sstevel@tonic-gate } 8200Sstevel@tonic-gate break; 8210Sstevel@tonic-gate 8220Sstevel@tonic-gate case USCSICMD: 8233368Slh195018 rv = ses_uscsi_cmd(ssc, (Uscmd *)arg, flg); 8240Sstevel@tonic-gate break; 8250Sstevel@tonic-gate 8260Sstevel@tonic-gate default: 8270Sstevel@tonic-gate rv = ENOTTY; 8280Sstevel@tonic-gate break; 8290Sstevel@tonic-gate } 8300Sstevel@tonic-gate return (rv); 8310Sstevel@tonic-gate } 8320Sstevel@tonic-gate 8330Sstevel@tonic-gate 8340Sstevel@tonic-gate /* 8350Sstevel@tonic-gate * Loop on running a kernel based command 8360Sstevel@tonic-gate * 8370Sstevel@tonic-gate * FIXME: This routine is not really needed. 8380Sstevel@tonic-gate */ 8390Sstevel@tonic-gate int 8400Sstevel@tonic-gate ses_runcmd(ses_softc_t *ssc, Uscmd *lp) 8410Sstevel@tonic-gate { 8420Sstevel@tonic-gate int e; 8430Sstevel@tonic-gate 8440Sstevel@tonic-gate lp->uscsi_status = 0; 8453368Slh195018 e = ses_uscsi_cmd(ssc, lp, FKIOCTL); 8460Sstevel@tonic-gate 8470Sstevel@tonic-gate #ifdef not 8480Sstevel@tonic-gate /* 8490Sstevel@tonic-gate * Debug: Nice cross-check code for verifying consistent status. 8500Sstevel@tonic-gate */ 8510Sstevel@tonic-gate if (lp->uscsi_status) { 8520Sstevel@tonic-gate if (lp->uscsi_status == STATUS_CHECK) { 8530Sstevel@tonic-gate SES_LOG(ssc, CE_NOTE, "runcmd<cdb[0]=" 8540Sstevel@tonic-gate "0x%x->%s ASC/ASCQ=0x%x/0x%x>", 8550Sstevel@tonic-gate lp->uscsi_cdb[0], 8560Sstevel@tonic-gate scsi_sname(lp->uscsi_rqbuf[2] & 0xf), 8570Sstevel@tonic-gate lp->uscsi_rqbuf[12] & 0xff, 8580Sstevel@tonic-gate lp->uscsi_rqbuf[13] & 0xff); 8590Sstevel@tonic-gate } else { 8600Sstevel@tonic-gate SES_LOG(ssc, CE_NOTE, "runcmd<cdb[0]=" 8610Sstevel@tonic-gate "0x%x -> Status 0x%x", lp->uscsi_cdb[0], 8620Sstevel@tonic-gate lp->uscsi_status); 8630Sstevel@tonic-gate } 8640Sstevel@tonic-gate } 8650Sstevel@tonic-gate #endif /* not */ 8660Sstevel@tonic-gate return (e); 8670Sstevel@tonic-gate } 8680Sstevel@tonic-gate 8690Sstevel@tonic-gate 8700Sstevel@tonic-gate /* 8710Sstevel@tonic-gate * Run a scsi command. 8720Sstevel@tonic-gate */ 8730Sstevel@tonic-gate int 8743368Slh195018 ses_uscsi_cmd(ses_softc_t *ssc, Uscmd *Uc, int Uf) 8750Sstevel@tonic-gate { 8763368Slh195018 Uscmd *uscmd; 8773368Slh195018 struct buf *bp; 8783368Slh195018 enum uio_seg uioseg; 8793368Slh195018 int err; 8800Sstevel@tonic-gate 8810Sstevel@tonic-gate /* 8820Sstevel@tonic-gate * Grab local 'special' buffer 8830Sstevel@tonic-gate */ 8840Sstevel@tonic-gate mutex_enter(SES_MUTEX); 8850Sstevel@tonic-gate while (ssc->ses_sbufbsy) { 8860Sstevel@tonic-gate cv_wait(&ssc->ses_sbufcv, &ssc->ses_devp->sd_mutex); 8870Sstevel@tonic-gate } 8880Sstevel@tonic-gate ssc->ses_sbufbsy = 1; 8890Sstevel@tonic-gate mutex_exit(SES_MUTEX); 8900Sstevel@tonic-gate 8910Sstevel@tonic-gate /* 8920Sstevel@tonic-gate * If the device is powered down, request it's activation. 8930Sstevel@tonic-gate * This check must be done after setting ses_sbufbsy! 8940Sstevel@tonic-gate */ 8950Sstevel@tonic-gate if (ssc->ses_suspended && 8960Sstevel@tonic-gate ddi_dev_is_needed(SES_DEVINFO(ssc), 0, 1) != DDI_SUCCESS) { 8970Sstevel@tonic-gate mutex_enter(SES_MUTEX); 8980Sstevel@tonic-gate ssc->ses_sbufbsy = 0; 8990Sstevel@tonic-gate mutex_exit(SES_MUTEX); 9000Sstevel@tonic-gate return (EIO); 9010Sstevel@tonic-gate } 9020Sstevel@tonic-gate 9033368Slh195018 err = scsi_uscsi_alloc_and_copyin((intptr_t)Uc, Uf, 9043368Slh195018 SES_ROUTE(ssc), &uscmd); 9053368Slh195018 if (err != 0) { 9063368Slh195018 SES_LOG(ssc, SES_CE_DEBUG1, "ses_uscsi_cmd: " 9073368Slh195018 "scsi_uscsi_alloc_and_copyin failed\n"); 9080Sstevel@tonic-gate mutex_enter(SES_MUTEX); 9090Sstevel@tonic-gate ssc->ses_sbufbsy = 0; 9100Sstevel@tonic-gate cv_signal(&ssc->ses_sbufcv); 9110Sstevel@tonic-gate mutex_exit(SES_MUTEX); 9120Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG2, efl, __LINE__); 9133368Slh195018 return (err); 9140Sstevel@tonic-gate } 9150Sstevel@tonic-gate 9160Sstevel@tonic-gate /* 9173368Slh195018 * Copy the uscsi command related infos to ssc for use in ses_start() 9183368Slh195018 * and ses_callback(). 9190Sstevel@tonic-gate */ 9203368Slh195018 bcopy(uscmd, &ssc->ses_uscsicmd, sizeof (Uscmd)); 9213368Slh195018 if (uscmd->uscsi_cdb != NULL) { 9223368Slh195018 bcopy(uscmd->uscsi_cdb, &ssc->ses_srqcdb, 9233368Slh195018 (size_t)(uscmd->uscsi_cdblen)); 9243368Slh195018 } 9256316Seschrock ssc->ses_uscsicmd.uscsi_status = 0; 9260Sstevel@tonic-gate 9270Sstevel@tonic-gate bp = ssc->ses_sbufp; 9280Sstevel@tonic-gate bp->av_back = (struct buf *)NULL; 9290Sstevel@tonic-gate bp->av_forw = (struct buf *)NULL; 9300Sstevel@tonic-gate bp->b_back = (struct buf *)ssc; 9310Sstevel@tonic-gate bp->b_edev = NODEV; 9320Sstevel@tonic-gate 9333368Slh195018 if (uscmd->uscsi_cdb != NULL) { 9343368Slh195018 if (uscmd->uscsi_cdblen == CDB_GROUP0) { 9353368Slh195018 SES_LOG(ssc, SES_CE_DEBUG7, 9363368Slh195018 "scsi_cmd: %x %x %x %x %x %x", 9373368Slh195018 ((char *)uscmd->uscsi_cdb)[0], 9383368Slh195018 ((char *)uscmd->uscsi_cdb)[1], 9393368Slh195018 ((char *)uscmd->uscsi_cdb)[2], 9403368Slh195018 ((char *)uscmd->uscsi_cdb)[3], 9413368Slh195018 ((char *)uscmd->uscsi_cdb)[4], 9423368Slh195018 ((char *)uscmd->uscsi_cdb)[5]); 9433368Slh195018 } else { 9443368Slh195018 SES_LOG(ssc, SES_CE_DEBUG7, 9453368Slh195018 "scsi cmd: %x %x %x %x %x %x %x %x %x %x", 9463368Slh195018 ((char *)uscmd->uscsi_cdb)[0], 9473368Slh195018 ((char *)uscmd->uscsi_cdb)[1], 9483368Slh195018 ((char *)uscmd->uscsi_cdb)[2], 9493368Slh195018 ((char *)uscmd->uscsi_cdb)[3], 9503368Slh195018 ((char *)uscmd->uscsi_cdb)[4], 9513368Slh195018 ((char *)uscmd->uscsi_cdb)[5], 9523368Slh195018 ((char *)uscmd->uscsi_cdb)[6], 9533368Slh195018 ((char *)uscmd->uscsi_cdb)[7], 9543368Slh195018 ((char *)uscmd->uscsi_cdb)[8], 9553368Slh195018 ((char *)uscmd->uscsi_cdb)[9]); 9560Sstevel@tonic-gate } 9570Sstevel@tonic-gate } 9580Sstevel@tonic-gate 9593368Slh195018 uioseg = (Uf & FKIOCTL) ? UIO_SYSSPACE : UIO_USERSPACE; 9603368Slh195018 err = scsi_uscsi_handle_cmd(NODEV, uioseg, uscmd, 9613368Slh195018 ses_start, bp, NULL); 9623368Slh195018 9630Sstevel@tonic-gate /* 9643368Slh195018 * ses_callback() may set values for ssc->ses_uscsicmd or 9653368Slh195018 * ssc->ses_srqsbuf, so copy them back to uscmd. 9660Sstevel@tonic-gate */ 9673368Slh195018 if (uscmd->uscsi_rqbuf != NULL) { 9683368Slh195018 bcopy(&ssc->ses_srqsbuf, uscmd->uscsi_rqbuf, 9693368Slh195018 (size_t)(uscmd->uscsi_rqlen)); 9703368Slh195018 uscmd->uscsi_rqresid = ssc->ses_uscsicmd.uscsi_rqresid; 9713368Slh195018 } 9723368Slh195018 uscmd->uscsi_status = ssc->ses_uscsicmd.uscsi_status; 9733368Slh195018 9743368Slh195018 (void) scsi_uscsi_copyout_and_free((intptr_t)Uc, uscmd); 9750Sstevel@tonic-gate mutex_enter(SES_MUTEX); 9760Sstevel@tonic-gate ssc->ses_sbufbsy = 0; 9770Sstevel@tonic-gate cv_signal(&ssc->ses_sbufcv); 9780Sstevel@tonic-gate mutex_exit(SES_MUTEX); 9790Sstevel@tonic-gate 9800Sstevel@tonic-gate return (err); 9810Sstevel@tonic-gate } 9820Sstevel@tonic-gate 9830Sstevel@tonic-gate 9840Sstevel@tonic-gate 9850Sstevel@tonic-gate /* 9860Sstevel@tonic-gate * Command start and done functions. 9870Sstevel@tonic-gate */ 9880Sstevel@tonic-gate static int 9890Sstevel@tonic-gate ses_start(struct buf *bp) 9900Sstevel@tonic-gate { 9910Sstevel@tonic-gate ses_softc_t *ssc = (ses_softc_t *)bp->b_back; 9920Sstevel@tonic-gate 9930Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG9, "ses_start"); 9940Sstevel@tonic-gate if (!BP_PKT(bp)) { 9950Sstevel@tonic-gate /* 9960Sstevel@tonic-gate * Allocate a packet. 9970Sstevel@tonic-gate */ 9980Sstevel@tonic-gate ses_get_pkt(bp, SLEEP_FUNC); 9990Sstevel@tonic-gate if (!BP_PKT(bp)) { 10000Sstevel@tonic-gate int err; 10010Sstevel@tonic-gate bp->b_resid = bp->b_bcount; 10020Sstevel@tonic-gate if (geterror(bp) == 0) 10030Sstevel@tonic-gate SET_BP_ERROR(bp, EIO); 10040Sstevel@tonic-gate err = geterror(bp); 10050Sstevel@tonic-gate biodone(bp); 10060Sstevel@tonic-gate return (err); 10070Sstevel@tonic-gate } 10080Sstevel@tonic-gate } 10090Sstevel@tonic-gate 10100Sstevel@tonic-gate /* 10110Sstevel@tonic-gate * Initialize the transfer residue, error code, and retry count. 10120Sstevel@tonic-gate */ 10130Sstevel@tonic-gate bp->b_resid = 0; 10140Sstevel@tonic-gate SET_BP_ERROR(bp, 0); 10150Sstevel@tonic-gate 10160Sstevel@tonic-gate #if !defined(lint) 10170Sstevel@tonic-gate _NOTE(NO_COMPETING_THREADS_NOW); 10180Sstevel@tonic-gate #endif /* !defined(lint) */ 10190Sstevel@tonic-gate ssc->ses_retries = ses_retry_count; 10200Sstevel@tonic-gate 10210Sstevel@tonic-gate #if !defined(lint) 10220Sstevel@tonic-gate /* LINTED */ 10230Sstevel@tonic-gate _NOTE(COMPETING_THREADS_NOW); 10240Sstevel@tonic-gate #endif /* !defined(lint) */ 10250Sstevel@tonic-gate 10260Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG9, "ses_start -> scsi_transport"); 10270Sstevel@tonic-gate switch (scsi_transport(BP_PKT(bp))) { 10280Sstevel@tonic-gate case TRAN_ACCEPT: 10290Sstevel@tonic-gate return (0); 10300Sstevel@tonic-gate /* break; */ 10310Sstevel@tonic-gate 10320Sstevel@tonic-gate case TRAN_BUSY: 10330Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG2, 10346316Seschrock "ses_start: TRANSPORT BUSY"); 10350Sstevel@tonic-gate SES_ENABLE_RESTART(SES_RESTART_TIME, BP_PKT(bp)); 10360Sstevel@tonic-gate return (0); 10370Sstevel@tonic-gate /* break; */ 10380Sstevel@tonic-gate 10390Sstevel@tonic-gate default: 10400Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG2, "TRANSPORT ERROR\n"); 10410Sstevel@tonic-gate SET_BP_ERROR(bp, EIO); 10420Sstevel@tonic-gate scsi_destroy_pkt(BP_PKT(bp)); 10430Sstevel@tonic-gate SET_BP_PKT(bp, NULL); 10440Sstevel@tonic-gate biodone(bp); 10450Sstevel@tonic-gate return (EIO); 10460Sstevel@tonic-gate /* break; */ 10470Sstevel@tonic-gate } 10480Sstevel@tonic-gate } 10490Sstevel@tonic-gate 10500Sstevel@tonic-gate 10510Sstevel@tonic-gate static void 10520Sstevel@tonic-gate ses_get_pkt(struct buf *bp, int (*func)()) 10530Sstevel@tonic-gate { 10540Sstevel@tonic-gate ses_softc_t *ssc = (ses_softc_t *)bp->b_back; 10550Sstevel@tonic-gate Uscmd *scmd = &ssc->ses_uscsicmd; 10560Sstevel@tonic-gate struct scsi_pkt *pkt; 10577424SLi.He@Sun.COM int stat_size = 1; 10587424SLi.He@Sun.COM int flags = 0; 10590Sstevel@tonic-gate 10600Sstevel@tonic-gate if ((scmd->uscsi_flags & USCSI_RQENABLE) && ssc->ses_arq) { 10617424SLi.He@Sun.COM if (scmd->uscsi_rqlen > SENSE_LENGTH) { 10627424SLi.He@Sun.COM stat_size = (int)(scmd->uscsi_rqlen) + 10637424SLi.He@Sun.COM sizeof (struct scsi_arq_status) - 10647424SLi.He@Sun.COM sizeof (struct scsi_extended_sense); 10657424SLi.He@Sun.COM flags = PKT_XARQ; 10667424SLi.He@Sun.COM } else { 10677424SLi.He@Sun.COM stat_size = sizeof (struct scsi_arq_status); 10687424SLi.He@Sun.COM } 10690Sstevel@tonic-gate } 10700Sstevel@tonic-gate 10710Sstevel@tonic-gate if (bp->b_bcount) { 10720Sstevel@tonic-gate pkt = scsi_init_pkt(SES_ROUTE(ssc), NULL, bp, 10737424SLi.He@Sun.COM scmd->uscsi_cdblen, stat_size, 0, flags, 10747424SLi.He@Sun.COM func, (caddr_t)ssc); 10750Sstevel@tonic-gate } else { 10760Sstevel@tonic-gate pkt = scsi_init_pkt(SES_ROUTE(ssc), NULL, NULL, 10777424SLi.He@Sun.COM scmd->uscsi_cdblen, stat_size, 0, flags, 10787424SLi.He@Sun.COM func, (caddr_t)ssc); 10790Sstevel@tonic-gate } 10800Sstevel@tonic-gate SET_BP_PKT(bp, pkt); 10810Sstevel@tonic-gate if (pkt == (struct scsi_pkt *)NULL) 10820Sstevel@tonic-gate return; 10830Sstevel@tonic-gate bcopy(scmd->uscsi_cdb, pkt->pkt_cdbp, (size_t)scmd->uscsi_cdblen); 10840Sstevel@tonic-gate pkt->pkt_time = scmd->uscsi_timeout; 10850Sstevel@tonic-gate 10860Sstevel@tonic-gate pkt->pkt_comp = ses_callback; 10870Sstevel@tonic-gate pkt->pkt_private = (opaque_t)ssc; 10880Sstevel@tonic-gate } 10890Sstevel@tonic-gate 10900Sstevel@tonic-gate 10910Sstevel@tonic-gate /* 10920Sstevel@tonic-gate * Restart ses command. 10930Sstevel@tonic-gate */ 10940Sstevel@tonic-gate static void 10950Sstevel@tonic-gate ses_restart(void *arg) 10960Sstevel@tonic-gate { 10970Sstevel@tonic-gate struct scsi_pkt *pkt = (struct scsi_pkt *)arg; 10980Sstevel@tonic-gate ses_softc_t *ssc = (ses_softc_t *)pkt->pkt_private; 10990Sstevel@tonic-gate struct buf *bp = ssc->ses_sbufp; 11000Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG9, "ses_restart"); 11010Sstevel@tonic-gate 11020Sstevel@tonic-gate ssc->ses_restart_id = NULL; 11030Sstevel@tonic-gate 11040Sstevel@tonic-gate switch (scsi_transport(pkt)) { 11050Sstevel@tonic-gate case TRAN_ACCEPT: 11060Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG9, 11070Sstevel@tonic-gate "RESTART %d ok", ssc->ses_retries); 11080Sstevel@tonic-gate return; 11090Sstevel@tonic-gate /* break; */ 11100Sstevel@tonic-gate case TRAN_BUSY: 11110Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG1, 11120Sstevel@tonic-gate "RESTART %d TRANSPORT BUSY\n", ssc->ses_retries); 11130Sstevel@tonic-gate if (ssc->ses_retries > SES_NO_RETRY) { 11146316Seschrock ssc->ses_retries -= SES_BUSY_RETRY; 11156316Seschrock SES_ENABLE_RESTART(SES_RESTART_TIME, pkt); 11166316Seschrock return; 11170Sstevel@tonic-gate } 11180Sstevel@tonic-gate SET_BP_ERROR(bp, EBUSY); 11190Sstevel@tonic-gate break; 11200Sstevel@tonic-gate default: 11210Sstevel@tonic-gate SET_BP_ERROR(bp, EIO); 11220Sstevel@tonic-gate break; 11230Sstevel@tonic-gate } 11240Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG1, 11250Sstevel@tonic-gate "RESTART %d TRANSPORT FAILED\n", ssc->ses_retries); 11260Sstevel@tonic-gate 11270Sstevel@tonic-gate pkt = (struct scsi_pkt *)bp->av_back; 11280Sstevel@tonic-gate scsi_destroy_pkt(pkt); 11290Sstevel@tonic-gate bp->b_resid = bp->b_bcount; 11300Sstevel@tonic-gate SET_BP_PKT(bp, NULL); 11310Sstevel@tonic-gate biodone(bp); 11320Sstevel@tonic-gate } 11330Sstevel@tonic-gate 11340Sstevel@tonic-gate 11350Sstevel@tonic-gate /* 11360Sstevel@tonic-gate * Command completion processing 11370Sstevel@tonic-gate */ 11380Sstevel@tonic-gate #define HBA_RESET (STAT_BUS_RESET|STAT_DEV_RESET|STAT_ABORTED) 11390Sstevel@tonic-gate static void 11400Sstevel@tonic-gate ses_callback(struct scsi_pkt *pkt) 11410Sstevel@tonic-gate { 11420Sstevel@tonic-gate ses_softc_t *ssc = (ses_softc_t *)pkt->pkt_private; 11430Sstevel@tonic-gate struct buf *bp; 11440Sstevel@tonic-gate Uscmd *scmd; 11450Sstevel@tonic-gate int err; 11460Sstevel@tonic-gate char action; 11470Sstevel@tonic-gate 11480Sstevel@tonic-gate bp = ssc->ses_sbufp; 11490Sstevel@tonic-gate scmd = &ssc->ses_uscsicmd; 11500Sstevel@tonic-gate /* SES_LOG(ssc, SES_CE_DEBUG9, "ses_callback"); */ 11510Sstevel@tonic-gate 11520Sstevel@tonic-gate /* 11530Sstevel@tonic-gate * Optimization: Normal completion. 11540Sstevel@tonic-gate */ 11550Sstevel@tonic-gate if (pkt->pkt_reason == CMD_CMPLT && 11560Sstevel@tonic-gate !SCBP_C(pkt) && 11570Sstevel@tonic-gate !(pkt->pkt_flags & FLAG_SENSING) && 11586673Seschrock !pkt->pkt_resid) { 11596316Seschrock scsi_destroy_pkt(pkt); 11606316Seschrock SET_BP_PKT(bp, NULL); 11616316Seschrock biodone(bp); 11626316Seschrock return; 11630Sstevel@tonic-gate } 11640Sstevel@tonic-gate 11650Sstevel@tonic-gate 11660Sstevel@tonic-gate /* 11670Sstevel@tonic-gate * Abnormal completion. 11680Sstevel@tonic-gate * 11690Sstevel@tonic-gate * Assume most common error initially. 11700Sstevel@tonic-gate */ 11710Sstevel@tonic-gate err = EIO; 11720Sstevel@tonic-gate action = COMMAND_DONE; 11730Sstevel@tonic-gate if (scmd->uscsi_flags & USCSI_DIAGNOSE) { 11740Sstevel@tonic-gate ssc->ses_retries = SES_NO_RETRY; 11750Sstevel@tonic-gate } 11760Sstevel@tonic-gate 11770Sstevel@tonic-gate CHECK_PKT: 11780Sstevel@tonic-gate if (pkt->pkt_reason != CMD_CMPLT) { 11790Sstevel@tonic-gate /* Process transport errors. */ 11800Sstevel@tonic-gate switch (pkt->pkt_reason) { 11810Sstevel@tonic-gate case CMD_TIMEOUT: 11820Sstevel@tonic-gate /* 11830Sstevel@tonic-gate * If the transport layer didn't clear the problem, 11840Sstevel@tonic-gate * reset the target. 11850Sstevel@tonic-gate */ 11860Sstevel@tonic-gate if (! (pkt->pkt_statistics & HBA_RESET)) { 11876316Seschrock (void) scsi_reset(&pkt->pkt_address, 11886316Seschrock RESET_TARGET); 11890Sstevel@tonic-gate } 11900Sstevel@tonic-gate err = ETIMEDOUT; 11910Sstevel@tonic-gate break; 11920Sstevel@tonic-gate 11930Sstevel@tonic-gate case CMD_INCOMPLETE: 11940Sstevel@tonic-gate case CMD_UNX_BUS_FREE: 11950Sstevel@tonic-gate /* 11960Sstevel@tonic-gate * No response? If probing, give up. 11970Sstevel@tonic-gate * Otherwise, keep trying until retries exhausted. 11980Sstevel@tonic-gate * Then lockdown the driver as the device is 11990Sstevel@tonic-gate * unplugged. 12000Sstevel@tonic-gate */ 12010Sstevel@tonic-gate if (ssc->ses_retries <= SES_NO_RETRY && 12020Sstevel@tonic-gate !(scmd->uscsi_flags & USCSI_DIAGNOSE)) { 12030Sstevel@tonic-gate ssc->ses_present = SES_CLOSED; 12040Sstevel@tonic-gate } 12050Sstevel@tonic-gate /* Inhibit retries to speed probe/attach. */ 12060Sstevel@tonic-gate if (ssc->ses_present < SES_OPEN) { 12070Sstevel@tonic-gate ssc->ses_retries = SES_NO_RETRY; 12080Sstevel@tonic-gate } 12090Sstevel@tonic-gate /* SES_CMD_RETRY4(ssc->ses_retries); */ 12100Sstevel@tonic-gate err = ENXIO; 12110Sstevel@tonic-gate break; 12120Sstevel@tonic-gate 12130Sstevel@tonic-gate case CMD_DATA_OVR: 12140Sstevel@tonic-gate /* 12150Sstevel@tonic-gate * XXX: Some HBA's (e.g. Adaptec 1740 and 12160Sstevel@tonic-gate * earlier ISP revs) report a DATA OVERRUN 12170Sstevel@tonic-gate * error instead of a transfer residue. So, 12180Sstevel@tonic-gate * we convert the error and restart. 12190Sstevel@tonic-gate */ 12200Sstevel@tonic-gate if ((bp->b_bcount - pkt->pkt_resid) > 0) { 12210Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG6, 12226316Seschrock "ignoring overrun"); 12230Sstevel@tonic-gate pkt->pkt_reason = CMD_CMPLT; 12240Sstevel@tonic-gate err = EOK; 12250Sstevel@tonic-gate goto CHECK_PKT; 12260Sstevel@tonic-gate } 12270Sstevel@tonic-gate ssc->ses_retries = SES_NO_RETRY; 12280Sstevel@tonic-gate /* err = EIO; */ 12290Sstevel@tonic-gate break; 12300Sstevel@tonic-gate 12310Sstevel@tonic-gate case CMD_DMA_DERR: 12320Sstevel@tonic-gate ssc->ses_retries = SES_NO_RETRY; 12330Sstevel@tonic-gate err = EFAULT; 12340Sstevel@tonic-gate break; 12350Sstevel@tonic-gate 12360Sstevel@tonic-gate default: 12370Sstevel@tonic-gate /* err = EIO; */ 12380Sstevel@tonic-gate break; 12390Sstevel@tonic-gate } 12400Sstevel@tonic-gate if (pkt == ssc->ses_rqpkt) { 12410Sstevel@tonic-gate SES_LOG(ssc, CE_WARN, fail_msg, 12426316Seschrock "Request Sense ", 12436316Seschrock scsi_rname(pkt->pkt_reason), 12446316Seschrock (ssc->ses_retries > 0)? 12456316Seschrock "retrying": "giving up"); 12460Sstevel@tonic-gate pkt = (struct scsi_pkt *)bp->av_back; 12470Sstevel@tonic-gate action = QUE_SENSE; 12480Sstevel@tonic-gate } else { 12490Sstevel@tonic-gate SES_LOG(ssc, CE_WARN, fail_msg, 12506316Seschrock "", scsi_rname(pkt->pkt_reason), 12516316Seschrock (ssc->ses_retries > 0)? 12526316Seschrock "retrying": "giving up"); 12530Sstevel@tonic-gate action = QUE_COMMAND; 12540Sstevel@tonic-gate } 12550Sstevel@tonic-gate /* Device exists, allow full error recovery. */ 12560Sstevel@tonic-gate if (ssc->ses_retries > SES_NO_RETRY) { 12570Sstevel@tonic-gate ssc->ses_present = SES_OPEN; 12580Sstevel@tonic-gate } 12590Sstevel@tonic-gate 12600Sstevel@tonic-gate 12610Sstevel@tonic-gate /* 12620Sstevel@tonic-gate * Process status and sense data errors. 12630Sstevel@tonic-gate */ 12640Sstevel@tonic-gate } else { 12650Sstevel@tonic-gate ssc->ses_present = SES_OPEN; 12660Sstevel@tonic-gate action = ses_decode_sense(pkt, &err); 12670Sstevel@tonic-gate } 12680Sstevel@tonic-gate 12690Sstevel@tonic-gate 12700Sstevel@tonic-gate /* 12710Sstevel@tonic-gate * Initiate error recovery action, as needed. 12720Sstevel@tonic-gate */ 12730Sstevel@tonic-gate switch (action) { 12740Sstevel@tonic-gate case QUE_COMMAND_NOW: 12750Sstevel@tonic-gate /* SES_LOG(ssc, SES_CE_DEBUG1, "retrying cmd now"); */ 12760Sstevel@tonic-gate if (ssc->ses_retries > SES_NO_RETRY) { 12776316Seschrock ssc->ses_retries -= SES_CMD_RETRY; 12786316Seschrock scmd->uscsi_status = 0; 12796316Seschrock if (ssc->ses_arq) 12806316Seschrock bzero(pkt->pkt_scbp, 12816316Seschrock sizeof (struct scsi_arq_status)); 12820Sstevel@tonic-gate 12836316Seschrock if (scsi_transport((struct scsi_pkt *)bp->av_back) 12846316Seschrock != TRAN_ACCEPT) { 12856316Seschrock SES_ENABLE_RESTART(SES_RESTART_TIME, 12866316Seschrock (struct scsi_pkt *)bp->av_back); 12876316Seschrock } 12886316Seschrock return; 12890Sstevel@tonic-gate } 12900Sstevel@tonic-gate break; 12910Sstevel@tonic-gate 12920Sstevel@tonic-gate case QUE_COMMAND: 12930Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG1, "retrying cmd"); 12940Sstevel@tonic-gate if (ssc->ses_retries > SES_NO_RETRY) { 12956316Seschrock ssc->ses_retries -= 12966316Seschrock (err == EBUSY)? SES_BUSY_RETRY: SES_CMD_RETRY; 12976316Seschrock scmd->uscsi_status = 0; 12986316Seschrock if (ssc->ses_arq) 12996316Seschrock bzero(pkt->pkt_scbp, 13006316Seschrock sizeof (struct scsi_arq_status)); 13010Sstevel@tonic-gate 13026316Seschrock SES_ENABLE_RESTART( 13036316Seschrock (err == EBUSY)? SES_BUSY_TIME: SES_RESTART_TIME, 13046316Seschrock (struct scsi_pkt *)bp->av_back); 13056316Seschrock return; 13060Sstevel@tonic-gate } 13070Sstevel@tonic-gate break; 13080Sstevel@tonic-gate 13090Sstevel@tonic-gate case QUE_SENSE: 13100Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG1, "retrying sense"); 13110Sstevel@tonic-gate if (ssc->ses_retries > SES_NO_RETRY) { 13120Sstevel@tonic-gate ssc->ses_retries -= SES_SENSE_RETRY; 13130Sstevel@tonic-gate scmd->uscsi_status = 0; 13147424SLi.He@Sun.COM bzero(&ssc->ses_srqsbuf, MAX_SENSE_LENGTH); 13150Sstevel@tonic-gate 13160Sstevel@tonic-gate if (scsi_transport(ssc->ses_rqpkt) != TRAN_ACCEPT) { 13170Sstevel@tonic-gate SES_ENABLE_RESTART(SES_RESTART_TIME, 13180Sstevel@tonic-gate ssc->ses_rqpkt); 13190Sstevel@tonic-gate } 13206316Seschrock return; 13210Sstevel@tonic-gate } 13220Sstevel@tonic-gate break; 13230Sstevel@tonic-gate 13240Sstevel@tonic-gate case COMMAND_DONE: 13250Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG4, "cmd done"); 13260Sstevel@tonic-gate pkt = (struct scsi_pkt *)bp->av_back; 13270Sstevel@tonic-gate bp->b_resid = pkt->pkt_resid; 13280Sstevel@tonic-gate if (bp->b_resid) { 13296316Seschrock SES_LOG(ssc, SES_CE_DEBUG6, 13306316Seschrock "transfer residue %ld(%ld)", 13316316Seschrock bp->b_bcount - bp->b_resid, bp->b_bcount); 13320Sstevel@tonic-gate } 13330Sstevel@tonic-gate break; 13340Sstevel@tonic-gate } 13350Sstevel@tonic-gate pkt = (struct scsi_pkt *)bp->av_back; 13360Sstevel@tonic-gate if (err) { 13370Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG1, "SES: ERROR %d\n", err); 13380Sstevel@tonic-gate SET_BP_ERROR(bp, err); 13390Sstevel@tonic-gate bp->b_resid = bp->b_bcount; 13400Sstevel@tonic-gate } 13410Sstevel@tonic-gate scsi_destroy_pkt(pkt); 13420Sstevel@tonic-gate SET_BP_PKT(bp, NULL); 13430Sstevel@tonic-gate biodone(bp); 13440Sstevel@tonic-gate } 13450Sstevel@tonic-gate 13460Sstevel@tonic-gate 13470Sstevel@tonic-gate /* 13480Sstevel@tonic-gate * Check status and sense data and determine recovery. 13490Sstevel@tonic-gate */ 13500Sstevel@tonic-gate static int 13510Sstevel@tonic-gate ses_decode_sense(struct scsi_pkt *pkt, int *err) 13520Sstevel@tonic-gate { 13530Sstevel@tonic-gate ses_softc_t *ssc = (ses_softc_t *)pkt->pkt_private; 13540Sstevel@tonic-gate struct scsi_extended_sense *sense = 13550Sstevel@tonic-gate (struct scsi_extended_sense *)&ssc->ses_srqsbuf; 13560Sstevel@tonic-gate Uscmd *scmd = &ssc->ses_uscsicmd; 13570Sstevel@tonic-gate char sense_flag = 0; 13580Sstevel@tonic-gate uchar_t status = SCBP_C(pkt) & STATUS_MASK; 13590Sstevel@tonic-gate char *err_action; 13600Sstevel@tonic-gate char action; 13617424SLi.He@Sun.COM uchar_t rqlen; 13627424SLi.He@Sun.COM int amt; 13630Sstevel@tonic-gate 13640Sstevel@tonic-gate /* 13650Sstevel@tonic-gate * Process manual request sense. 13660Sstevel@tonic-gate * Copy manual request sense to sense buffer. 13670Sstevel@tonic-gate * 13680Sstevel@tonic-gate * This is done if auto request sense is not enabled. 13690Sstevel@tonic-gate * Or the auto request sense failed and the request 13700Sstevel@tonic-gate * sense needs to be retried. 13710Sstevel@tonic-gate */ 13720Sstevel@tonic-gate if (pkt->pkt_flags & FLAG_SENSING) { 13730Sstevel@tonic-gate struct buf *sbp = ssc->ses_rqbp; 13747424SLi.He@Sun.COM amt = min(MAX_SENSE_LENGTH, 13750Sstevel@tonic-gate sbp->b_bcount - sbp->b_resid); 13767424SLi.He@Sun.COM rqlen = min((uchar_t)amt, scmd->uscsi_rqlen); 13777424SLi.He@Sun.COM bcopy(sbp->b_un.b_addr, sense, rqlen); 13787424SLi.He@Sun.COM scmd->uscsi_rqresid = scmd->uscsi_rqlen - rqlen; 13790Sstevel@tonic-gate sense_flag = 1; 13800Sstevel@tonic-gate /* 13810Sstevel@tonic-gate * Process auto request sense. 13820Sstevel@tonic-gate * Copy auto request sense to sense buffer. 13830Sstevel@tonic-gate * 13840Sstevel@tonic-gate * If auto request sense failed due to transport error, 13850Sstevel@tonic-gate * retry the command. Otherwise process the status and 13860Sstevel@tonic-gate * sense data. 13870Sstevel@tonic-gate */ 13880Sstevel@tonic-gate } else if (ssc->ses_arq && pkt->pkt_state & STATE_ARQ_DONE) { 13890Sstevel@tonic-gate struct scsi_arq_status *arq = 13906316Seschrock (struct scsi_arq_status *)(pkt->pkt_scbp); 13910Sstevel@tonic-gate uchar_t *arq_status = (uchar_t *)&arq->sts_rqpkt_status; 13927424SLi.He@Sun.COM if (pkt->pkt_state & STATE_XARQ_DONE) { 13937424SLi.He@Sun.COM amt = MAX_SENSE_LENGTH - arq->sts_rqpkt_resid; 13947424SLi.He@Sun.COM } else { 13957424SLi.He@Sun.COM if (arq->sts_rqpkt_resid > SENSE_LENGTH) { 13967424SLi.He@Sun.COM amt = MAX_SENSE_LENGTH - arq->sts_rqpkt_resid; 13977424SLi.He@Sun.COM } else { 13987424SLi.He@Sun.COM amt = SENSE_LENGTH - arq->sts_rqpkt_resid; 13997424SLi.He@Sun.COM } 14007424SLi.He@Sun.COM } 14010Sstevel@tonic-gate 14020Sstevel@tonic-gate if (arq->sts_rqpkt_reason != CMD_CMPLT) { 14030Sstevel@tonic-gate return (QUE_COMMAND); 14040Sstevel@tonic-gate } 14057424SLi.He@Sun.COM 14067424SLi.He@Sun.COM rqlen = min((uchar_t)amt, scmd->uscsi_rqlen); 14077424SLi.He@Sun.COM bcopy(&arq->sts_sensedata, sense, rqlen); 14080Sstevel@tonic-gate scmd->uscsi_status = status; 14097424SLi.He@Sun.COM scmd->uscsi_rqresid = scmd->uscsi_rqlen - rqlen; 14100Sstevel@tonic-gate status = *arq_status & STATUS_MASK; 14110Sstevel@tonic-gate pkt->pkt_state &= ~STATE_ARQ_DONE; 14120Sstevel@tonic-gate sense_flag = 1; 14130Sstevel@tonic-gate } 14140Sstevel@tonic-gate 14150Sstevel@tonic-gate 14160Sstevel@tonic-gate /* 14170Sstevel@tonic-gate * Check status of REQUEST SENSE or command. 14180Sstevel@tonic-gate * 14190Sstevel@tonic-gate * If it's not successful, try retrying the original command 14200Sstevel@tonic-gate * and hope that it goes away. If not, we'll eventually run 14210Sstevel@tonic-gate * out of retries and die. 14220Sstevel@tonic-gate */ 14230Sstevel@tonic-gate switch (status) { 14240Sstevel@tonic-gate case STATUS_GOOD: 14250Sstevel@tonic-gate case STATUS_INTERMEDIATE: 14260Sstevel@tonic-gate case STATUS_MET: 14270Sstevel@tonic-gate /* 14280Sstevel@tonic-gate * If the command status is ok, we're done. 14290Sstevel@tonic-gate * Otherwise, examine the request sense data. 14300Sstevel@tonic-gate */ 14310Sstevel@tonic-gate if (! sense_flag) { 14320Sstevel@tonic-gate *err = EOK; 14330Sstevel@tonic-gate return (COMMAND_DONE); 14340Sstevel@tonic-gate } 14350Sstevel@tonic-gate break; 14360Sstevel@tonic-gate 14370Sstevel@tonic-gate case STATUS_CHECK: 14380Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG3, "status decode: check"); 14390Sstevel@tonic-gate *err = EIO; 14400Sstevel@tonic-gate return (QUE_SENSE); 14410Sstevel@tonic-gate /* break; */ 14420Sstevel@tonic-gate 14430Sstevel@tonic-gate case STATUS_BUSY: 14440Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG1, "status decode: busy"); 14450Sstevel@tonic-gate /* SES_CMD_RETRY2(ssc->ses_retries); */ 14460Sstevel@tonic-gate *err = EBUSY; 14470Sstevel@tonic-gate return (QUE_COMMAND); 14480Sstevel@tonic-gate /* break; */ 14490Sstevel@tonic-gate 14500Sstevel@tonic-gate case STATUS_RESERVATION_CONFLICT: 14510Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG1, "status decode: reserved"); 14520Sstevel@tonic-gate *err = EACCES; 14530Sstevel@tonic-gate return (COMMAND_DONE_ERROR); 14540Sstevel@tonic-gate /* break; */ 14550Sstevel@tonic-gate 14560Sstevel@tonic-gate case STATUS_TERMINATED: 14570Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG1, "status decode: terminated"); 14580Sstevel@tonic-gate *err = ECANCELED; 14590Sstevel@tonic-gate return (COMMAND_DONE_ERROR); 14600Sstevel@tonic-gate /* break; */ 14610Sstevel@tonic-gate 14620Sstevel@tonic-gate default: 14630Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG1, "status 0x%x", status); 14640Sstevel@tonic-gate *err = EIO; 14650Sstevel@tonic-gate return (QUE_COMMAND); 14660Sstevel@tonic-gate /* break; */ 14670Sstevel@tonic-gate } 14680Sstevel@tonic-gate 14690Sstevel@tonic-gate 14700Sstevel@tonic-gate /* 14710Sstevel@tonic-gate * Check REQUEST SENSE error code. 14720Sstevel@tonic-gate * 14730Sstevel@tonic-gate * Either there's no error, a retryable error, 14740Sstevel@tonic-gate * or it's dead. SES devices aren't very complex. 14750Sstevel@tonic-gate */ 14760Sstevel@tonic-gate err_action = "retrying"; 14770Sstevel@tonic-gate switch (sense->es_key) { 14780Sstevel@tonic-gate case KEY_RECOVERABLE_ERROR: 14790Sstevel@tonic-gate *err = EOK; 14800Sstevel@tonic-gate err_action = "recovered"; 14810Sstevel@tonic-gate action = COMMAND_DONE; 14820Sstevel@tonic-gate break; 14830Sstevel@tonic-gate 14840Sstevel@tonic-gate case KEY_UNIT_ATTENTION: 14850Sstevel@tonic-gate /* 14860Sstevel@tonic-gate * This is common for RAID! 14870Sstevel@tonic-gate */ 14880Sstevel@tonic-gate /* *err = EIO; */ 14890Sstevel@tonic-gate SES_CMD_RETRY1(ssc->ses_retries); 14900Sstevel@tonic-gate action = QUE_COMMAND_NOW; 14910Sstevel@tonic-gate break; 14920Sstevel@tonic-gate 14930Sstevel@tonic-gate case KEY_NOT_READY: 14940Sstevel@tonic-gate case KEY_NO_SENSE: 14950Sstevel@tonic-gate /* *err = EIO; */ 14960Sstevel@tonic-gate action = QUE_COMMAND; 14970Sstevel@tonic-gate break; 14980Sstevel@tonic-gate 14990Sstevel@tonic-gate default: 15000Sstevel@tonic-gate /* *err = EIO; */ 15010Sstevel@tonic-gate err_action = "fatal"; 15020Sstevel@tonic-gate action = COMMAND_DONE_ERROR; 15030Sstevel@tonic-gate break; 15040Sstevel@tonic-gate } 15050Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG1, 15066316Seschrock "cdb[0]= 0x%x %s, key=0x%x, ASC/ASCQ=0x%x/0x%x", 15076316Seschrock scmd->uscsi_cdb[0], err_action, 15086316Seschrock sense->es_key, sense->es_add_code, sense->es_qual_code); 15090Sstevel@tonic-gate 15100Sstevel@tonic-gate #ifdef not 15110Sstevel@tonic-gate /* 15120Sstevel@tonic-gate * Dump cdb and sense data stat's for manufacturing. 15130Sstevel@tonic-gate */ 15140Sstevel@tonic-gate if (DEBUGGING_ERR || sd_error_level == SDERR_ALL) { 15150Sstevel@tonic-gate auto buf[128]; 15160Sstevel@tonic-gate 15170Sstevel@tonic-gate p = pkt->pkt_cdbp; 15180Sstevel@tonic-gate if ((j = scsi_cdb_size[CDB_GROUPID(*p)]) == 0) 15190Sstevel@tonic-gate j = CDB_SIZE; 15200Sstevel@tonic-gate 15210Sstevel@tonic-gate /* Print cdb */ 15220Sstevel@tonic-gate (void) sprintf(buf, "cmd:"); 15230Sstevel@tonic-gate for (i = 0; i < j; i++) { 15240Sstevel@tonic-gate (void) sprintf(&buf[strlen(buf)], 15250Sstevel@tonic-gate hex, (uchar_t)*p++); 15260Sstevel@tonic-gate } 15270Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG3, "%s", buf); 15280Sstevel@tonic-gate 15290Sstevel@tonic-gate /* Suppress trailing zero's in sense data */ 15300Sstevel@tonic-gate if (amt > 3) { 15310Sstevel@tonic-gate p = (char *)devp->sd_sense + amt; 15320Sstevel@tonic-gate for (j = amt; j > 3; j--) { 15330Sstevel@tonic-gate if (*(--p)) break; 15340Sstevel@tonic-gate } 15350Sstevel@tonic-gate } else { 15360Sstevel@tonic-gate j = amt; 15370Sstevel@tonic-gate } 15380Sstevel@tonic-gate 15390Sstevel@tonic-gate /* Print sense data. */ 15400Sstevel@tonic-gate (void) sprintf(buf, "sense:"); 15410Sstevel@tonic-gate p = (char *)devp->sd_sense; 15420Sstevel@tonic-gate for (i = 0; i < j; i++) { 15430Sstevel@tonic-gate (void) sprintf(&buf[strlen(buf)], 15440Sstevel@tonic-gate hex, (uchar_t)*p++); 15450Sstevel@tonic-gate } 15460Sstevel@tonic-gate SES_LOG(ssc, SES_CE_DEBUG3, "%s", buf); 15470Sstevel@tonic-gate } 15480Sstevel@tonic-gate #endif /* not */ 15490Sstevel@tonic-gate return (action); 15500Sstevel@tonic-gate } 15510Sstevel@tonic-gate 15520Sstevel@tonic-gate 15530Sstevel@tonic-gate /*PRINTFLIKE3*/ 15540Sstevel@tonic-gate void 15550Sstevel@tonic-gate ses_log(ses_softc_t *ssc, int level, const char *fmt, ...) 15560Sstevel@tonic-gate { 15570Sstevel@tonic-gate va_list ap; 15580Sstevel@tonic-gate char buf[256]; 15590Sstevel@tonic-gate 15600Sstevel@tonic-gate va_start(ap, fmt); 15610Sstevel@tonic-gate (void) vsprintf(buf, fmt, ap); 15620Sstevel@tonic-gate va_end(ap); 15630Sstevel@tonic-gate 15640Sstevel@tonic-gate if (ssc == (ses_softc_t *)NULL) { 15650Sstevel@tonic-gate switch (level) { 15660Sstevel@tonic-gate case SES_CE_DEBUG1: 15670Sstevel@tonic-gate if (ses_debug > 1) 15680Sstevel@tonic-gate cmn_err(CE_NOTE, "%s", buf); 15690Sstevel@tonic-gate break; 15700Sstevel@tonic-gate case SES_CE_DEBUG2: 15710Sstevel@tonic-gate if (ses_debug > 2) 15720Sstevel@tonic-gate cmn_err(CE_NOTE, "%s", buf); 15730Sstevel@tonic-gate break; 15740Sstevel@tonic-gate case SES_CE_DEBUG3: 15750Sstevel@tonic-gate if (ses_debug > 3) 15760Sstevel@tonic-gate cmn_err(CE_NOTE, "%s", buf); 15770Sstevel@tonic-gate break; 15780Sstevel@tonic-gate case SES_CE_DEBUG4: 15790Sstevel@tonic-gate if (ses_debug > 4) 15800Sstevel@tonic-gate cmn_err(CE_NOTE, "%s", buf); 15810Sstevel@tonic-gate break; 15820Sstevel@tonic-gate case SES_CE_DEBUG5: 15830Sstevel@tonic-gate if (ses_debug > 5) 15840Sstevel@tonic-gate cmn_err(CE_NOTE, "%s", buf); 15850Sstevel@tonic-gate break; 15860Sstevel@tonic-gate case SES_CE_DEBUG6: 15870Sstevel@tonic-gate if (ses_debug > 6) 15880Sstevel@tonic-gate cmn_err(CE_NOTE, "%s", buf); 15890Sstevel@tonic-gate break; 15900Sstevel@tonic-gate case SES_CE_DEBUG7: 15910Sstevel@tonic-gate if (ses_debug > 7) 15920Sstevel@tonic-gate cmn_err(CE_NOTE, "%s", buf); 15930Sstevel@tonic-gate break; 15940Sstevel@tonic-gate case SES_CE_DEBUG8: 15950Sstevel@tonic-gate if (ses_debug > 8) 15960Sstevel@tonic-gate cmn_err(CE_NOTE, "%s", buf); 15970Sstevel@tonic-gate break; 15980Sstevel@tonic-gate case SES_CE_DEBUG9: 15990Sstevel@tonic-gate if (ses_debug > 9) 16000Sstevel@tonic-gate cmn_err(CE_NOTE, "%s", buf); 16010Sstevel@tonic-gate break; 16020Sstevel@tonic-gate case CE_NOTE: 16030Sstevel@tonic-gate case CE_WARN: 16040Sstevel@tonic-gate case CE_PANIC: 16050Sstevel@tonic-gate cmn_err(level, "%s", buf); 16060Sstevel@tonic-gate break; 16070Sstevel@tonic-gate case SES_CE_DEBUG: 16080Sstevel@tonic-gate default: 16090Sstevel@tonic-gate cmn_err(CE_NOTE, "%s", buf); 16100Sstevel@tonic-gate break; 16110Sstevel@tonic-gate } 16120Sstevel@tonic-gate return; 16130Sstevel@tonic-gate } 16140Sstevel@tonic-gate 16150Sstevel@tonic-gate switch (level) { 16160Sstevel@tonic-gate case CE_CONT: 16170Sstevel@tonic-gate case CE_NOTE: 16180Sstevel@tonic-gate case CE_WARN: 16190Sstevel@tonic-gate case CE_PANIC: 16200Sstevel@tonic-gate scsi_log(SES_DEVINFO(ssc), (char *)Snm, level, Str, buf); 16210Sstevel@tonic-gate break; 16220Sstevel@tonic-gate case SES_CE_DEBUG1: 16230Sstevel@tonic-gate if (ses_debug > 1) 16240Sstevel@tonic-gate scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG, 16250Sstevel@tonic-gate Str, buf); 16260Sstevel@tonic-gate break; 16270Sstevel@tonic-gate case SES_CE_DEBUG2: 16280Sstevel@tonic-gate if (ses_debug > 2) 16290Sstevel@tonic-gate scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG, 16300Sstevel@tonic-gate Str, buf); 16310Sstevel@tonic-gate break; 16320Sstevel@tonic-gate case SES_CE_DEBUG3: 16330Sstevel@tonic-gate if (ses_debug > 3) 16340Sstevel@tonic-gate scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG, 16350Sstevel@tonic-gate Str, buf); 16360Sstevel@tonic-gate break; 16370Sstevel@tonic-gate case SES_CE_DEBUG4: 16380Sstevel@tonic-gate if (ses_debug > 4) 16390Sstevel@tonic-gate scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG, 16400Sstevel@tonic-gate Str, buf); 16410Sstevel@tonic-gate break; 16420Sstevel@tonic-gate case SES_CE_DEBUG5: 16430Sstevel@tonic-gate if (ses_debug > 5) 16440Sstevel@tonic-gate scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG, 16450Sstevel@tonic-gate Str, buf); 16460Sstevel@tonic-gate break; 16470Sstevel@tonic-gate case SES_CE_DEBUG6: 16480Sstevel@tonic-gate if (ses_debug > 6) 16490Sstevel@tonic-gate scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG, 16500Sstevel@tonic-gate Str, buf); 16510Sstevel@tonic-gate break; 16520Sstevel@tonic-gate case SES_CE_DEBUG7: 16530Sstevel@tonic-gate if (ses_debug > 7) 16540Sstevel@tonic-gate scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG, 16550Sstevel@tonic-gate Str, buf); 16560Sstevel@tonic-gate break; 16570Sstevel@tonic-gate case SES_CE_DEBUG8: 16580Sstevel@tonic-gate if (ses_debug > 8) 16590Sstevel@tonic-gate scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG, 16600Sstevel@tonic-gate Str, buf); 16610Sstevel@tonic-gate break; 16620Sstevel@tonic-gate case SES_CE_DEBUG9: 16630Sstevel@tonic-gate if (ses_debug > 9) 16640Sstevel@tonic-gate scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG, 16650Sstevel@tonic-gate Str, buf); 16660Sstevel@tonic-gate break; 16670Sstevel@tonic-gate case SES_CE_DEBUG: 16680Sstevel@tonic-gate default: 16690Sstevel@tonic-gate scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG, Str, buf); 16700Sstevel@tonic-gate break; 16710Sstevel@tonic-gate } 16720Sstevel@tonic-gate } 16730Sstevel@tonic-gate /* 16740Sstevel@tonic-gate * mode: c 16750Sstevel@tonic-gate * Local variables: 16760Sstevel@tonic-gate * c-indent-level: 8 16770Sstevel@tonic-gate * c-brace-imaginary-offset: 0 16780Sstevel@tonic-gate * c-brace-offset: -8 16790Sstevel@tonic-gate * c-argdecl-indent: 8 16800Sstevel@tonic-gate * c-label-offset: -8 16810Sstevel@tonic-gate * c-continued-statement-offset: 8 16820Sstevel@tonic-gate * c-continued-brace-offset: 0 16830Sstevel@tonic-gate * End: 16840Sstevel@tonic-gate */ 1685