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