xref: /onnv-gate/usr/src/uts/common/io/scsi/targets/ses.c (revision 10967:0f20d1dba80d)
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  *
2410696SDavid.Hollister@Sun.COM  * Copyright 2009 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 */
1677656SSherry.Moore@Sun.COM 	NULL,			/* power */
1687656SSherry.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 = {
1857656SSherry.Moore@Sun.COM 	&mod_driverops,
1867656SSherry.Moore@Sun.COM 	"SCSI Enclosure Services",
1877656SSherry.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
_init(void)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
_fini(void)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
_info(struct modinfo * modinfop)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
ses_probe(dev_info_t * dip)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 	if (dip == NULL)
2490Sstevel@tonic-gate 		return (DDI_PROBE_FAILURE);
25010696SDavid.Hollister@Sun.COM 	/* SES_LOG(NULL, SES_CE_DEBUG1, "ses_probe: OK"); */
25110696SDavid.Hollister@Sun.COM 	if (ddi_dev_is_sid(dip) == DDI_SUCCESS) {
25210696SDavid.Hollister@Sun.COM 		return (DDI_PROBE_DONTCARE);
25310696SDavid.Hollister@Sun.COM 	}
25410696SDavid.Hollister@Sun.COM 
25510696SDavid.Hollister@Sun.COM 	devp = ddi_get_driver_private(dip);
25610696SDavid.Hollister@Sun.COM 
25710696SDavid.Hollister@Sun.COM 	/* Legacy: prevent driver.conf specified ses nodes on atapi. */
25810696SDavid.Hollister@Sun.COM 	if (scsi_ifgetcap(&devp->sd_address, "interconnect-type", -1) ==
25910696SDavid.Hollister@Sun.COM 	    INTERCONNECT_ATAPI)
26010696SDavid.Hollister@Sun.COM 		return (DDI_PROBE_FAILURE);
26110696SDavid.Hollister@Sun.COM 
2620Sstevel@tonic-gate 	/*
2630Sstevel@tonic-gate 	 * XXX: Breakage from the x86 folks.
2640Sstevel@tonic-gate 	 */
2650Sstevel@tonic-gate 	if (strcmp(ddi_get_name(ddi_get_parent(dip)), "ata") == 0) {
2660Sstevel@tonic-gate 		return (DDI_PROBE_FAILURE);
2670Sstevel@tonic-gate 	}
26810696SDavid.Hollister@Sun.COM 
2690Sstevel@tonic-gate 	switch (err = scsi_probe(devp, SLEEP_FUNC)) {
2700Sstevel@tonic-gate 	case SCSIPROBE_EXISTS:
2716316Seschrock 		if (is_enc_dev(NULL, devp->sd_inq, SUN_INQSIZE, &ep)) {
2726316Seschrock 			break;
2736316Seschrock 		}
2740Sstevel@tonic-gate 		/* FALLTHROUGH */
2750Sstevel@tonic-gate 	case SCSIPROBE_NORESP:
2766316Seschrock 		scsi_unprobe(devp);
2776316Seschrock 		return (DDI_PROBE_FAILURE);
2780Sstevel@tonic-gate 	default:
2796316Seschrock 		SES_LOG(NULL, SES_CE_DEBUG9,
2806316Seschrock 		    "ses_probe: probe error %d", err);
2816316Seschrock 		scsi_unprobe(devp);
2826316Seschrock 		return (DDI_PROBE_FAILURE);
2830Sstevel@tonic-gate 	}
2840Sstevel@tonic-gate 	scsi_unprobe(devp);
2850Sstevel@tonic-gate 	return (DDI_PROBE_SUCCESS);
2860Sstevel@tonic-gate }
2870Sstevel@tonic-gate 
2880Sstevel@tonic-gate static int
ses_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)2890Sstevel@tonic-gate ses_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2900Sstevel@tonic-gate {
2910Sstevel@tonic-gate 	int inst, err;
2920Sstevel@tonic-gate 	ses_softc_t *ssc;
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate 	inst = ddi_get_instance(dip);
2950Sstevel@tonic-gate 	switch (cmd) {
2960Sstevel@tonic-gate 	case DDI_ATTACH:
2970Sstevel@tonic-gate 		SES_LOG(NULL, SES_CE_DEBUG9, "ses_attach: DDI_ATTACH ses%d",
2980Sstevel@tonic-gate 		    inst);
2990Sstevel@tonic-gate 
3000Sstevel@tonic-gate 		err = ses_doattach(dip);
3010Sstevel@tonic-gate 
3020Sstevel@tonic-gate 		if (err == DDI_FAILURE) {
3030Sstevel@tonic-gate 			return (DDI_FAILURE);
3040Sstevel@tonic-gate 		}
3050Sstevel@tonic-gate 		SES_LOG(NULL, SES_CE_DEBUG4,
3060Sstevel@tonic-gate 		    "ses_attach: DDI_ATTACH OK ses%d", inst);
3070Sstevel@tonic-gate 		break;
3080Sstevel@tonic-gate 
3090Sstevel@tonic-gate 	case DDI_RESUME:
3100Sstevel@tonic-gate 		if ((ssc = ddi_get_soft_state(estate, inst)) == NULL) {
3110Sstevel@tonic-gate 			return (DDI_FAILURE);
3120Sstevel@tonic-gate 		}
3130Sstevel@tonic-gate 		SES_LOG(ssc, SES_CE_DEBUG1, "ses_attach: DDI_ATTACH ses%d",
3140Sstevel@tonic-gate 		    inst);
3150Sstevel@tonic-gate 		ssc->ses_suspended = 0;
3160Sstevel@tonic-gate 		break;
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate 	default:
3190Sstevel@tonic-gate 		return (DDI_FAILURE);
3200Sstevel@tonic-gate 	}
3210Sstevel@tonic-gate 	return (DDI_SUCCESS);
3220Sstevel@tonic-gate }
3230Sstevel@tonic-gate 
3240Sstevel@tonic-gate static int
is_enc_dev(ses_softc_t * ssc,struct scsi_inquiry * inqp,int iqlen,enctyp * ep)3250Sstevel@tonic-gate is_enc_dev(ses_softc_t *ssc, struct scsi_inquiry *inqp, int iqlen, enctyp *ep)
3260Sstevel@tonic-gate {
3270Sstevel@tonic-gate 	uchar_t dt = (inqp->inq_dtype & DTYPE_MASK);
3280Sstevel@tonic-gate 	uchar_t *iqd = (uchar_t *)inqp;
3290Sstevel@tonic-gate 
3300Sstevel@tonic-gate 	if (dt == DTYPE_ESI) {
3310Sstevel@tonic-gate 		if (strncmp(inqp->inq_vid, SEN_ID, SEN_ID_LEN) == 0) {
3320Sstevel@tonic-gate 			SES_LOG(ssc, SES_CE_DEBUG3, "SEN device found");
3330Sstevel@tonic-gate 			*ep = SEN_TYPE;
3346948Sjmcp 		} else if (inqp->inq_rdf == RDF_SCSI2) {
3356948Sjmcp 			/*
3366948Sjmcp 			 * Per SPC4 #6.4.2 Standard Inquiry Data, response
3376948Sjmcp 			 * data format (RDF) values of 0 and 1 are Obsolete,
3386948Sjmcp 			 * whereas values greater than 2 are Reserved
3396948Sjmcp 			 */
3400Sstevel@tonic-gate 			SES_LOG(ssc, SES_CE_DEBUG3, "SES device found");
3410Sstevel@tonic-gate 			*ep = SES_TYPE;
3420Sstevel@tonic-gate 		} else {
3430Sstevel@tonic-gate 			SES_LOG(ssc, SES_CE_DEBUG3, "Pre-SCSI3 SES device");
3440Sstevel@tonic-gate 			*ep = SES_TYPE;
3450Sstevel@tonic-gate 		}
3460Sstevel@tonic-gate 		return (1);
3470Sstevel@tonic-gate 	}
3480Sstevel@tonic-gate 	if ((iqd[6] & 0x40) && inqp->inq_rdf >= RDF_SCSI2) {
3490Sstevel@tonic-gate 		/*
3500Sstevel@tonic-gate 		 * PassThrough Device.
3510Sstevel@tonic-gate 		 */
3520Sstevel@tonic-gate 		*ep = SES_TYPE;
3530Sstevel@tonic-gate 		SES_LOG(ssc, SES_CE_DEBUG3, "Passthru SES device");
3540Sstevel@tonic-gate 		return (1);
3550Sstevel@tonic-gate 	}
3560Sstevel@tonic-gate 
3570Sstevel@tonic-gate 	if (iqlen < 47) {
3580Sstevel@tonic-gate 		SES_LOG(ssc, CE_NOTE,
3590Sstevel@tonic-gate 		    "INQUIRY data too short to determine SAF-TE");
3600Sstevel@tonic-gate 		return (0);
3610Sstevel@tonic-gate 	}
3620Sstevel@tonic-gate 	if (strncmp((char *)&iqd[44], "SAF-TE", 4) == 0) {
3630Sstevel@tonic-gate 		*ep = SAFT_TYPE;
3640Sstevel@tonic-gate 		SES_LOG(ssc, SES_CE_DEBUG3, "SAF-TE device found");
3650Sstevel@tonic-gate 		return (1);
3660Sstevel@tonic-gate 	}
3670Sstevel@tonic-gate 	return (0);
3680Sstevel@tonic-gate }
3690Sstevel@tonic-gate 
3700Sstevel@tonic-gate 
3710Sstevel@tonic-gate /*
3720Sstevel@tonic-gate  * Attach ses device.
3730Sstevel@tonic-gate  *
3740Sstevel@tonic-gate  * XXX:  Power management is NOT supported.  A token framework
3750Sstevel@tonic-gate  *       is provided that will need to be extended assuming we have
3760Sstevel@tonic-gate  *       ses devices we can power down.  Currently, we don't have any.
3770Sstevel@tonic-gate  */
3780Sstevel@tonic-gate static int
ses_doattach(dev_info_t * dip)3790Sstevel@tonic-gate ses_doattach(dev_info_t *dip)
3800Sstevel@tonic-gate {
3810Sstevel@tonic-gate 	int inst, err;
3820Sstevel@tonic-gate 	Scsidevp devp;
3830Sstevel@tonic-gate 	ses_softc_t *ssc;
3840Sstevel@tonic-gate 	enctyp etyp;
3850Sstevel@tonic-gate 
3860Sstevel@tonic-gate 	inst = ddi_get_instance(dip);
3870Sstevel@tonic-gate 	/*
3880Sstevel@tonic-gate 	 * Workaround for bug #4154979- for some reason we can
3890Sstevel@tonic-gate 	 * be called with identical instance numbers but for
3900Sstevel@tonic-gate 	 * different dev_info_t-s- all but one are bogus.
3910Sstevel@tonic-gate 	 *
3920Sstevel@tonic-gate 	 * Bad Dog! No Biscuit!
3930Sstevel@tonic-gate 	 *
3940Sstevel@tonic-gate 	 * A quick workaround might be to call ddi_soft_state_zalloc
3950Sstevel@tonic-gate 	 * unconditionally, as the implementation fails these calls
3960Sstevel@tonic-gate 	 * if there's an item already allocated. A more reasonable
3970Sstevel@tonic-gate 	 * and longer term change is to move the allocation past
3980Sstevel@tonic-gate 	 * the probe for the device's existence as most of these
3990Sstevel@tonic-gate 	 * 'bogus' calls are for nonexistent devices.
4000Sstevel@tonic-gate 	 */
4010Sstevel@tonic-gate 
4020Sstevel@tonic-gate 	devp  = ddi_get_driver_private(dip);
4030Sstevel@tonic-gate 	devp->sd_dev = dip;
4040Sstevel@tonic-gate 
4050Sstevel@tonic-gate 	/*
4060Sstevel@tonic-gate 	 * Determine whether the { i, t, l } we're called
4070Sstevel@tonic-gate 	 * to start is an enclosure services device.
4080Sstevel@tonic-gate 	 */
4090Sstevel@tonic-gate 
4100Sstevel@tonic-gate 	/*
4110Sstevel@tonic-gate 	 * Call the scsi_probe routine to see whether
4120Sstevel@tonic-gate 	 * we actually have an Enclosure Services device at
4130Sstevel@tonic-gate 	 * this address.
4140Sstevel@tonic-gate 	 */
4150Sstevel@tonic-gate 	err = scsi_probe(devp, SLEEP_FUNC);
4160Sstevel@tonic-gate 	if (err != SCSIPROBE_EXISTS) {
4170Sstevel@tonic-gate 		SES_LOG(NULL, SES_CE_DEBUG9,
4180Sstevel@tonic-gate 		    "ses_doattach: probe error %d", err);
4190Sstevel@tonic-gate 		scsi_unprobe(devp);
4200Sstevel@tonic-gate 		return (DDI_FAILURE);
4210Sstevel@tonic-gate 	}
4220Sstevel@tonic-gate 	/* Call is_enc_dev() to get the etyp */
4230Sstevel@tonic-gate 	if (!(is_enc_dev(NULL, devp->sd_inq, SUN_INQSIZE, &etyp))) {
4240Sstevel@tonic-gate 		SES_LOG(NULL, CE_WARN,
4250Sstevel@tonic-gate 		    "ses_doattach: ses%d: is_enc_dev failure", inst);
4260Sstevel@tonic-gate 		scsi_unprobe(devp);
4270Sstevel@tonic-gate 		return (DDI_FAILURE);
4280Sstevel@tonic-gate 	}
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate 	if (ddi_soft_state_zalloc(estate, inst) != DDI_SUCCESS) {
4310Sstevel@tonic-gate 		scsi_unprobe(devp);
4320Sstevel@tonic-gate 		SES_LOG(NULL, CE_NOTE, "ses%d: softalloc fails", inst);
4330Sstevel@tonic-gate 		return (DDI_FAILURE);
4340Sstevel@tonic-gate 	}
4350Sstevel@tonic-gate 	ssc = ddi_get_soft_state(estate, inst);
4360Sstevel@tonic-gate 	if (ssc == NULL) {
4370Sstevel@tonic-gate 		scsi_unprobe(devp);
4380Sstevel@tonic-gate 		SES_LOG(NULL, CE_NOTE, "ses%d: get_soft_state fails", inst);
4390Sstevel@tonic-gate 		return (DDI_FAILURE);
4400Sstevel@tonic-gate 	}
4410Sstevel@tonic-gate 	devp->sd_private = (opaque_t)ssc;
4420Sstevel@tonic-gate 	ssc->ses_devp = devp;
4430Sstevel@tonic-gate 	err = ddi_create_minor_node(dip, "0", S_IFCHR, inst,
4446316Seschrock 	    DDI_NT_SCSI_ENCLOSURE, NULL);
4450Sstevel@tonic-gate 	if (err == DDI_FAILURE) {
4460Sstevel@tonic-gate 		ddi_remove_minor_node(dip, NULL);
4470Sstevel@tonic-gate 		SES_LOG(ssc, CE_NOTE, "minor node creation failed");
4480Sstevel@tonic-gate 		ddi_soft_state_free(estate, inst);
4490Sstevel@tonic-gate 		scsi_unprobe(devp);
4500Sstevel@tonic-gate 		return (DDI_FAILURE);
4510Sstevel@tonic-gate 	}
4520Sstevel@tonic-gate 
4530Sstevel@tonic-gate 	ssc->ses_type = etyp;
4540Sstevel@tonic-gate 	ssc->ses_vec = vecs[etyp];
4550Sstevel@tonic-gate 
4560Sstevel@tonic-gate 	/* Call SoftC Init Routine A bit later... */
4570Sstevel@tonic-gate 
4580Sstevel@tonic-gate 	ssc->ses_rqbp = scsi_alloc_consistent_buf(SES_ROUTE(ssc),
4597424SLi.He@Sun.COM 	    NULL, MAX_SENSE_LENGTH, B_READ, SLEEP_FUNC, NULL);
4600Sstevel@tonic-gate 	if (ssc->ses_rqbp != NULL) {
4610Sstevel@tonic-gate 		ssc->ses_rqpkt = scsi_init_pkt(SES_ROUTE(ssc), NULL,
4620Sstevel@tonic-gate 		    ssc->ses_rqbp, CDB_GROUP0, 1, 0, PKT_CONSISTENT,
4630Sstevel@tonic-gate 		    SLEEP_FUNC, NULL);
4640Sstevel@tonic-gate 	}
4650Sstevel@tonic-gate 	if (ssc->ses_rqbp == NULL || ssc->ses_rqpkt == NULL) {
4660Sstevel@tonic-gate 		ddi_remove_minor_node(dip, NULL);
4670Sstevel@tonic-gate 		SES_LOG(ssc, CE_NOTE, "scsi_init_pkt of rqbuf failed");
4680Sstevel@tonic-gate 		if (ssc->ses_rqbp != NULL) {
4690Sstevel@tonic-gate 			scsi_free_consistent_buf(ssc->ses_rqbp);
4700Sstevel@tonic-gate 			ssc->ses_rqbp = NULL;
4710Sstevel@tonic-gate 		}
4720Sstevel@tonic-gate 		ddi_soft_state_free(estate, inst);
4730Sstevel@tonic-gate 		scsi_unprobe(devp);
4740Sstevel@tonic-gate 		return (DDI_FAILURE);
4750Sstevel@tonic-gate 	}
4760Sstevel@tonic-gate 	ssc->ses_rqpkt->pkt_private = (opaque_t)ssc;
4770Sstevel@tonic-gate 	ssc->ses_rqpkt->pkt_address = *(SES_ROUTE(ssc));
4780Sstevel@tonic-gate 	ssc->ses_rqpkt->pkt_comp = ses_callback;
4790Sstevel@tonic-gate 	ssc->ses_rqpkt->pkt_time = ses_io_time;
4800Sstevel@tonic-gate 	ssc->ses_rqpkt->pkt_flags = FLAG_NOPARITY|FLAG_NODISCON|FLAG_SENSING;
4810Sstevel@tonic-gate 	ssc->ses_rqpkt->pkt_cdbp[0] = SCMD_REQUEST_SENSE;
4820Sstevel@tonic-gate 	ssc->ses_rqpkt->pkt_cdbp[1] = 0;
4830Sstevel@tonic-gate 	ssc->ses_rqpkt->pkt_cdbp[2] = 0;
4840Sstevel@tonic-gate 	ssc->ses_rqpkt->pkt_cdbp[3] = 0;
4857424SLi.He@Sun.COM 	ssc->ses_rqpkt->pkt_cdbp[4] = MAX_SENSE_LENGTH;
4860Sstevel@tonic-gate 	ssc->ses_rqpkt->pkt_cdbp[5] = 0;
4870Sstevel@tonic-gate 
4880Sstevel@tonic-gate 	switch (scsi_ifgetcap(SES_ROUTE(ssc), "auto-rqsense", 1)) {
4890Sstevel@tonic-gate 	case 1:
4900Sstevel@tonic-gate 		/* if already set, don't reset it */
4910Sstevel@tonic-gate 		ssc->ses_arq = 1;
4920Sstevel@tonic-gate 		break;
4930Sstevel@tonic-gate 	case 0:
4940Sstevel@tonic-gate 		/* try and set it */
4950Sstevel@tonic-gate 		ssc->ses_arq = ((scsi_ifsetcap(SES_ROUTE(ssc),
4960Sstevel@tonic-gate 		    "auto-rqsense", 1, 1) == 1) ? 1 : 0);
4970Sstevel@tonic-gate 		break;
4980Sstevel@tonic-gate 	default:
4990Sstevel@tonic-gate 		/* probably undefined, so zero it out */
5000Sstevel@tonic-gate 		ssc->ses_arq = 0;
5010Sstevel@tonic-gate 		break;
5020Sstevel@tonic-gate 	}
5030Sstevel@tonic-gate 
5040Sstevel@tonic-gate 	ssc->ses_sbufp = getrbuf(KM_SLEEP);
5050Sstevel@tonic-gate 	cv_init(&ssc->ses_sbufcv, NULL, CV_DRIVER, NULL);
5060Sstevel@tonic-gate 
5070Sstevel@tonic-gate 	/*
5080Sstevel@tonic-gate 	 * If the HBA supports wide, tell it to use wide.
5090Sstevel@tonic-gate 	 */
5100Sstevel@tonic-gate 	if (scsi_ifgetcap(SES_ROUTE(ssc), "wide-xfer", 1) != -1) {
5110Sstevel@tonic-gate 		int wd = ((devp->sd_inq->inq_rdf == RDF_SCSI2) &&
5120Sstevel@tonic-gate 		    (devp->sd_inq->inq_wbus16 || devp->sd_inq->inq_wbus32))
5130Sstevel@tonic-gate 		    ? 1 : 0;
5140Sstevel@tonic-gate 		(void) scsi_ifsetcap(SES_ROUTE(ssc), "wide-xfer", wd, 1);
5150Sstevel@tonic-gate 	}
5160Sstevel@tonic-gate 
5170Sstevel@tonic-gate 	/*
5180Sstevel@tonic-gate 	 * Now do ssc init of enclosure specifics.
5190Sstevel@tonic-gate 	 * At the same time, check to make sure getrbuf
5200Sstevel@tonic-gate 	 * actually succeeded.
5210Sstevel@tonic-gate 	 */
522752Srralphs 	if ((*ssc->ses_vec.softc_init)(ssc, 1)) {
523752Srralphs 		SES_LOG(ssc, SES_CE_DEBUG3, "failed softc init");
524752Srralphs 		(void) (*ssc->ses_vec.softc_init)(ssc, 0);
5250Sstevel@tonic-gate 		ddi_remove_minor_node(dip, NULL);
5260Sstevel@tonic-gate 		scsi_destroy_pkt(ssc->ses_rqpkt);
5270Sstevel@tonic-gate 		scsi_free_consistent_buf(ssc->ses_rqbp);
5280Sstevel@tonic-gate 		if (ssc->ses_sbufp) {
5290Sstevel@tonic-gate 			freerbuf(ssc->ses_sbufp);
5300Sstevel@tonic-gate 		}
5310Sstevel@tonic-gate 		cv_destroy(&ssc->ses_sbufcv);
5320Sstevel@tonic-gate 		ddi_soft_state_free(estate, inst);
5330Sstevel@tonic-gate 		scsi_unprobe(devp);
5340Sstevel@tonic-gate 		return (DDI_FAILURE);
5350Sstevel@tonic-gate 	}
5360Sstevel@tonic-gate 
5370Sstevel@tonic-gate 	/*
5380Sstevel@tonic-gate 	 * create this property so that PM code knows we want
5390Sstevel@tonic-gate 	 * to be suspended at PM time
5400Sstevel@tonic-gate 	 */
5410Sstevel@tonic-gate 	(void) ddi_prop_update_string(DDI_DEV_T_NONE, dip,
5420Sstevel@tonic-gate 	    PM_HARDWARE_STATE_PROP, PM_NEEDS_SUSPEND_RESUME);
5430Sstevel@tonic-gate 
5440Sstevel@tonic-gate 	/* announce the existence of this device */
5450Sstevel@tonic-gate 	ddi_report_dev(dip);
5460Sstevel@tonic-gate 	return (DDI_SUCCESS);
5470Sstevel@tonic-gate }
5480Sstevel@tonic-gate 
5490Sstevel@tonic-gate 
5500Sstevel@tonic-gate /*
5510Sstevel@tonic-gate  * Detach ses device.
5520Sstevel@tonic-gate  *
5530Sstevel@tonic-gate  * XXX:  Power management is NOT supported.  A token framework
5540Sstevel@tonic-gate  *       is provided that will need to be extended assuming we have
5550Sstevel@tonic-gate  *       ses devices we can power down.  Currently, we don't have any.
5560Sstevel@tonic-gate  */
5570Sstevel@tonic-gate static int
ses_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)5580Sstevel@tonic-gate ses_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
5590Sstevel@tonic-gate {
5600Sstevel@tonic-gate 	ses_softc_t *ssc;
5610Sstevel@tonic-gate 	int inst;
5620Sstevel@tonic-gate 
5630Sstevel@tonic-gate 	switch (cmd) {
5640Sstevel@tonic-gate 	case DDI_DETACH:
5650Sstevel@tonic-gate 		inst = ddi_get_instance(dip);
5660Sstevel@tonic-gate 		ssc = ddi_get_soft_state(estate, inst);
5670Sstevel@tonic-gate 		if (ssc == NULL) {
5680Sstevel@tonic-gate 			cmn_err(CE_NOTE,
5690Sstevel@tonic-gate 			    "ses%d: DDI_DETACH, no softstate found", inst);
5700Sstevel@tonic-gate 			return (DDI_FAILURE);
5710Sstevel@tonic-gate 		}
5720Sstevel@tonic-gate 		if (ISOPEN(ssc)) {
5730Sstevel@tonic-gate 			return (DDI_FAILURE);
5740Sstevel@tonic-gate 		}
5750Sstevel@tonic-gate 
5760Sstevel@tonic-gate #if		!defined(lint)
5770Sstevel@tonic-gate 		/* LINTED */
5780Sstevel@tonic-gate 		_NOTE(COMPETING_THREADS_NOW);
5790Sstevel@tonic-gate #endif		/* !defined(lint) */
5800Sstevel@tonic-gate 
5810Sstevel@tonic-gate 		if (ssc->ses_vec.softc_init)
5820Sstevel@tonic-gate 			(void) (*ssc->ses_vec.softc_init)(ssc, 0);
5830Sstevel@tonic-gate 
5840Sstevel@tonic-gate #if		!defined(lint)
5850Sstevel@tonic-gate 		_NOTE(NO_COMPETING_THREADS_NOW);
5860Sstevel@tonic-gate #endif 		/* !defined(lint) */
5870Sstevel@tonic-gate 
5880Sstevel@tonic-gate 		(void) scsi_ifsetcap(SES_ROUTE(ssc), "auto-rqsense", 1, 0);
5890Sstevel@tonic-gate 		scsi_destroy_pkt(ssc->ses_rqpkt);
5900Sstevel@tonic-gate 		scsi_free_consistent_buf(ssc->ses_rqbp);
5910Sstevel@tonic-gate 		freerbuf(ssc->ses_sbufp);
5920Sstevel@tonic-gate 		cv_destroy(&ssc->ses_sbufcv);
5930Sstevel@tonic-gate 		ddi_soft_state_free(estate, inst);
5940Sstevel@tonic-gate 		ddi_prop_remove_all(dip);
5950Sstevel@tonic-gate 		ddi_remove_minor_node(dip, NULL);
5960Sstevel@tonic-gate 		scsi_unprobe(ddi_get_driver_private(dip));
5970Sstevel@tonic-gate 		break;
5980Sstevel@tonic-gate 
5990Sstevel@tonic-gate 	case DDI_SUSPEND:
6000Sstevel@tonic-gate 		inst = ddi_get_instance(dip);
6010Sstevel@tonic-gate 		if ((ssc = ddi_get_soft_state(estate, inst)) == NULL) {
6020Sstevel@tonic-gate 			cmn_err(CE_NOTE,
6030Sstevel@tonic-gate 			    "ses%d: DDI_SUSPEND, no softstate found", inst);
6040Sstevel@tonic-gate 			return (DDI_FAILURE);
6050Sstevel@tonic-gate 		}
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate 		/*
6080Sstevel@tonic-gate 		 * If driver idle, accept suspend request.
6090Sstevel@tonic-gate 		 * If it's busy, reject it.  This keeps things simple!
6100Sstevel@tonic-gate 		 */
6110Sstevel@tonic-gate 		mutex_enter(SES_MUTEX);
6120Sstevel@tonic-gate 		if (ssc->ses_sbufbsy) {
6130Sstevel@tonic-gate 			mutex_exit(SES_MUTEX);
6140Sstevel@tonic-gate 			return (DDI_FAILURE);
6150Sstevel@tonic-gate 		}
6160Sstevel@tonic-gate 		ssc->ses_suspended = 1;
6170Sstevel@tonic-gate 		mutex_exit(SES_MUTEX);
6180Sstevel@tonic-gate 		break;
6190Sstevel@tonic-gate 
6200Sstevel@tonic-gate 	default:
6210Sstevel@tonic-gate 		return (DDI_FAILURE);
6220Sstevel@tonic-gate 	}
6230Sstevel@tonic-gate 	return (DDI_SUCCESS);
6240Sstevel@tonic-gate }
6250Sstevel@tonic-gate 
6260Sstevel@tonic-gate /* ARGSUSED */
6270Sstevel@tonic-gate static int
ses_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)6280Sstevel@tonic-gate ses_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
6290Sstevel@tonic-gate {
6300Sstevel@tonic-gate 	dev_t dev;
6310Sstevel@tonic-gate 	ses_softc_t *ssc;
6320Sstevel@tonic-gate 	int inst, error;
6330Sstevel@tonic-gate 
6340Sstevel@tonic-gate 	switch (infocmd) {
6350Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
6360Sstevel@tonic-gate 		dev = (dev_t)arg;
6370Sstevel@tonic-gate 		inst = getminor(dev);
6380Sstevel@tonic-gate 		if ((ssc = ddi_get_soft_state(estate, inst)) == NULL) {
6390Sstevel@tonic-gate 			return (DDI_FAILURE);
6400Sstevel@tonic-gate 		}
6410Sstevel@tonic-gate 		*result = (void *) ssc->ses_devp->sd_dev;
6420Sstevel@tonic-gate 		error = DDI_SUCCESS;
6430Sstevel@tonic-gate 		break;
6440Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
6450Sstevel@tonic-gate 		dev = (dev_t)arg;
6460Sstevel@tonic-gate 		inst = getminor(dev);
6470Sstevel@tonic-gate 		*result = (void *)(uintptr_t)inst;
6480Sstevel@tonic-gate 		error = DDI_SUCCESS;
6490Sstevel@tonic-gate 		break;
6500Sstevel@tonic-gate 	default:
6510Sstevel@tonic-gate 		error = DDI_FAILURE;
6520Sstevel@tonic-gate 	}
6530Sstevel@tonic-gate 	return (error);
6540Sstevel@tonic-gate }
6550Sstevel@tonic-gate 
6567656SSherry.Moore@Sun.COM 
6570Sstevel@tonic-gate /*
6580Sstevel@tonic-gate  * Unix Entry Points
6590Sstevel@tonic-gate  */
6600Sstevel@tonic-gate 
6610Sstevel@tonic-gate /* ARGSUSED */
6620Sstevel@tonic-gate static int
ses_open(dev_t * dev_p,int flag,int otyp,cred_t * cred_p)6630Sstevel@tonic-gate ses_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p)
6640Sstevel@tonic-gate {
6650Sstevel@tonic-gate 	ses_softc_t *ssc;
6660Sstevel@tonic-gate 
6670Sstevel@tonic-gate 	if ((ssc = ddi_get_soft_state(estate, getminor(*dev_p))) == NULL) {
6680Sstevel@tonic-gate 		return (ENXIO);
6690Sstevel@tonic-gate 	}
6700Sstevel@tonic-gate 
6710Sstevel@tonic-gate 	/*
6720Sstevel@tonic-gate 	 * If the device is powered down, request it's activation.
6730Sstevel@tonic-gate 	 * If it can't be activated, fail open.
6740Sstevel@tonic-gate 	 */
6750Sstevel@tonic-gate 	if (ssc->ses_suspended &&
6760Sstevel@tonic-gate 	    ddi_dev_is_needed(SES_DEVINFO(ssc), 0, 1) != DDI_SUCCESS) {
6770Sstevel@tonic-gate 		return (EIO);
6780Sstevel@tonic-gate 	}
6790Sstevel@tonic-gate 
6800Sstevel@tonic-gate 	mutex_enter(SES_MUTEX);
6810Sstevel@tonic-gate 	if (otyp == OTYP_LYR)
6820Sstevel@tonic-gate 		ssc->ses_lyropen++;
6830Sstevel@tonic-gate 	else
6840Sstevel@tonic-gate 		ssc->ses_oflag = 1;
6850Sstevel@tonic-gate 
6860Sstevel@tonic-gate 	ssc->ses_present = (ssc->ses_present)? ssc->ses_present: SES_OPENING;
6870Sstevel@tonic-gate 	mutex_exit(SES_MUTEX);
6880Sstevel@tonic-gate 	return (EOK);
6890Sstevel@tonic-gate }
6900Sstevel@tonic-gate 
6910Sstevel@tonic-gate /*ARGSUSED*/
6920Sstevel@tonic-gate static int
ses_close(dev_t dev,int flag,int otyp,cred_t * cred_p)6930Sstevel@tonic-gate ses_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
6940Sstevel@tonic-gate {
6950Sstevel@tonic-gate 	ses_softc_t *ssc;
6960Sstevel@tonic-gate 	if ((ssc = ddi_get_soft_state(estate, getminor(dev))) == NULL) {
6970Sstevel@tonic-gate 		return (ENXIO);
6980Sstevel@tonic-gate 	}
6990Sstevel@tonic-gate 
7000Sstevel@tonic-gate 	if (ssc->ses_suspended) {
7010Sstevel@tonic-gate 		(void) ddi_dev_is_needed(SES_DEVINFO(ssc), 0, 1);
7020Sstevel@tonic-gate 	}
7030Sstevel@tonic-gate 
7040Sstevel@tonic-gate 	mutex_enter(SES_MUTEX);
7050Sstevel@tonic-gate 	if (otyp == OTYP_LYR)
7060Sstevel@tonic-gate 		ssc->ses_lyropen -= (ssc->ses_lyropen)? 1: 0;
7070Sstevel@tonic-gate 	else
7080Sstevel@tonic-gate 		ssc->ses_oflag = 0;
7090Sstevel@tonic-gate 	mutex_exit(SES_MUTEX);
7100Sstevel@tonic-gate 	return (0);
7110Sstevel@tonic-gate }
7120Sstevel@tonic-gate 
7130Sstevel@tonic-gate 
7140Sstevel@tonic-gate /*ARGSUSED3*/
7150Sstevel@tonic-gate static int
ses_ioctl(dev_t dev,int cmd,intptr_t arg,int flg,cred_t * cred_p,int * rvalp)7160Sstevel@tonic-gate ses_ioctl(dev_t dev, int cmd, intptr_t arg, int flg, cred_t *cred_p, int *rvalp)
7170Sstevel@tonic-gate {
7180Sstevel@tonic-gate 	ses_softc_t *ssc;
7190Sstevel@tonic-gate 	ses_object k, *up;
7200Sstevel@tonic-gate 	ses_objarg x;
7210Sstevel@tonic-gate 	uchar_t t;
7220Sstevel@tonic-gate 	uchar_t i;
7230Sstevel@tonic-gate 	int rv = 0;
7240Sstevel@tonic-gate 
7250Sstevel@tonic-gate 	if ((ssc = ddi_get_soft_state(estate, getminor(dev))) == NULL ||
7260Sstevel@tonic-gate 	    ssc->ses_present == SES_CLOSED) {
7270Sstevel@tonic-gate 		return (ENXIO);
7280Sstevel@tonic-gate 	}
7290Sstevel@tonic-gate 
7300Sstevel@tonic-gate 
7310Sstevel@tonic-gate 	switch (cmd) {
7320Sstevel@tonic-gate 	case SESIOC_GETNOBJ:
7330Sstevel@tonic-gate 		if (ddi_copyout(&ssc->ses_nobjects, (void *)arg,
7340Sstevel@tonic-gate 		    sizeof (int), flg)) {
7350Sstevel@tonic-gate 			rv = EFAULT;
7360Sstevel@tonic-gate 			break;
7370Sstevel@tonic-gate 		}
7380Sstevel@tonic-gate 		break;
7390Sstevel@tonic-gate 
7400Sstevel@tonic-gate 	case SESIOC_GETOBJMAP:
7410Sstevel@tonic-gate 		up = (ses_object *) arg;
7420Sstevel@tonic-gate 		mutex_enter(SES_MUTEX);
7430Sstevel@tonic-gate 		for (i = 0; i != ssc->ses_nobjects; i++) {
7440Sstevel@tonic-gate 			k.obj_id = i;
7450Sstevel@tonic-gate 			k.subencid = ssc->ses_objmap[i].subenclosure;
7460Sstevel@tonic-gate 			k.elem_type = ssc->ses_objmap[i].enctype;
7470Sstevel@tonic-gate 			if (ddi_copyout(&k, up, sizeof (k), flg)) {
7480Sstevel@tonic-gate 				rv = EFAULT;
7490Sstevel@tonic-gate 				break;
7500Sstevel@tonic-gate 			}
7510Sstevel@tonic-gate 			up++;
7520Sstevel@tonic-gate 		}
7530Sstevel@tonic-gate 		mutex_exit(SES_MUTEX);
7540Sstevel@tonic-gate 		break;
7550Sstevel@tonic-gate 
7560Sstevel@tonic-gate 	case SESIOC_INIT:
757*10967SRandall.Ralphs@Sun.COM 		if (drv_priv(cred_p) != 0) {
758*10967SRandall.Ralphs@Sun.COM 			rv = EPERM;
759*10967SRandall.Ralphs@Sun.COM 			break;
760*10967SRandall.Ralphs@Sun.COM 		}
7610Sstevel@tonic-gate 		rv = (*ssc->ses_vec.init_enc)(ssc);
7620Sstevel@tonic-gate 		break;
7630Sstevel@tonic-gate 
7640Sstevel@tonic-gate 	case SESIOC_GETENCSTAT:
7650Sstevel@tonic-gate 		if ((ssc->ses_encstat & ENCI_SVALID) == 0) {
7660Sstevel@tonic-gate 			rv = (*ssc->ses_vec.get_encstat)(ssc, KM_SLEEP);
7670Sstevel@tonic-gate 			if (rv) {
7680Sstevel@tonic-gate 				break;
7690Sstevel@tonic-gate 			}
7700Sstevel@tonic-gate 		}
7710Sstevel@tonic-gate 		t = ssc->ses_encstat & 0xf;
7720Sstevel@tonic-gate 		if (ddi_copyout(&t, (void *)arg, sizeof (t), flg))
7730Sstevel@tonic-gate 			rv = EFAULT;
7740Sstevel@tonic-gate 		/*
7750Sstevel@tonic-gate 		 * And always invalidate enclosure status on the way out.
7760Sstevel@tonic-gate 		 */
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_SETENCSTAT:
783*10967SRandall.Ralphs@Sun.COM 		if (drv_priv(cred_p) != 0) {
784*10967SRandall.Ralphs@Sun.COM 			rv = EPERM;
785*10967SRandall.Ralphs@Sun.COM 			break;
786*10967SRandall.Ralphs@Sun.COM 		}
7870Sstevel@tonic-gate 		if (ddi_copyin((void *)arg, &t, sizeof (t), flg))
7880Sstevel@tonic-gate 			rv = EFAULT;
7890Sstevel@tonic-gate 		else
7900Sstevel@tonic-gate 			rv = (*ssc->ses_vec.set_encstat)(ssc, t, KM_SLEEP);
7910Sstevel@tonic-gate 		mutex_enter(SES_MUTEX);
7920Sstevel@tonic-gate 		ssc->ses_encstat &= ~ENCI_SVALID;
7930Sstevel@tonic-gate 		mutex_exit(SES_MUTEX);
7940Sstevel@tonic-gate 		break;
7950Sstevel@tonic-gate 
7960Sstevel@tonic-gate 	case SESIOC_GETOBJSTAT:
7970Sstevel@tonic-gate 		if (ddi_copyin((void *)arg, &x, sizeof (x), flg)) {
7980Sstevel@tonic-gate 			rv = EFAULT;
7990Sstevel@tonic-gate 			break;
8000Sstevel@tonic-gate 		}
8010Sstevel@tonic-gate 		if (x.obj_id >= ssc->ses_nobjects) {
8020Sstevel@tonic-gate 			rv = EINVAL;
8030Sstevel@tonic-gate 			break;
8040Sstevel@tonic-gate 		}
8050Sstevel@tonic-gate 		if ((rv = (*ssc->ses_vec.get_objstat)(ssc, &x, KM_SLEEP)) != 0)
8060Sstevel@tonic-gate 			break;
8070Sstevel@tonic-gate 		if (ddi_copyout(&x, (void *)arg, sizeof (x), flg))
8080Sstevel@tonic-gate 			rv = EFAULT;
8090Sstevel@tonic-gate 		else {
8100Sstevel@tonic-gate 			/*
8110Sstevel@tonic-gate 			 * Now that we no longer poll, svalid never stays true.
8120Sstevel@tonic-gate 			 */
8130Sstevel@tonic-gate 			mutex_enter(SES_MUTEX);
8140Sstevel@tonic-gate 			ssc->ses_objmap[x.obj_id].svalid = 0;
8150Sstevel@tonic-gate 			mutex_exit(SES_MUTEX);
8160Sstevel@tonic-gate 		}
8170Sstevel@tonic-gate 		break;
8180Sstevel@tonic-gate 
8190Sstevel@tonic-gate 	case SESIOC_SETOBJSTAT:
820*10967SRandall.Ralphs@Sun.COM 		if (drv_priv(cred_p) != 0) {
821*10967SRandall.Ralphs@Sun.COM 			rv = EPERM;
822*10967SRandall.Ralphs@Sun.COM 			break;
823*10967SRandall.Ralphs@Sun.COM 		}
8240Sstevel@tonic-gate 		if (ddi_copyin((void *)arg, &x, sizeof (x), flg)) {
8250Sstevel@tonic-gate 			rv = EFAULT;
8260Sstevel@tonic-gate 			break;
8270Sstevel@tonic-gate 		}
8280Sstevel@tonic-gate 		if (x.obj_id >= ssc->ses_nobjects) {
8290Sstevel@tonic-gate 			rv = EINVAL;
8300Sstevel@tonic-gate 			break;
8310Sstevel@tonic-gate 		}
8320Sstevel@tonic-gate 		rv = (*ssc->ses_vec.set_objstat)(ssc, &x, KM_SLEEP);
8330Sstevel@tonic-gate 		if (rv == 0) {
8340Sstevel@tonic-gate 			mutex_enter(SES_MUTEX);
8350Sstevel@tonic-gate 			ssc->ses_objmap[x.obj_id].svalid = 0;
8360Sstevel@tonic-gate 			mutex_exit(SES_MUTEX);
8370Sstevel@tonic-gate 		}
8380Sstevel@tonic-gate 		break;
8390Sstevel@tonic-gate 
8400Sstevel@tonic-gate 	case USCSICMD:
841*10967SRandall.Ralphs@Sun.COM 		if (drv_priv(cred_p) != 0) {
842*10967SRandall.Ralphs@Sun.COM 			rv = EPERM;
843*10967SRandall.Ralphs@Sun.COM 			break;
844*10967SRandall.Ralphs@Sun.COM 		}
8453368Slh195018 		rv = ses_uscsi_cmd(ssc, (Uscmd *)arg, flg);
8460Sstevel@tonic-gate 		break;
8470Sstevel@tonic-gate 
8480Sstevel@tonic-gate 	default:
8490Sstevel@tonic-gate 		rv = ENOTTY;
8500Sstevel@tonic-gate 		break;
8510Sstevel@tonic-gate 	}
8520Sstevel@tonic-gate 	return (rv);
8530Sstevel@tonic-gate }
8540Sstevel@tonic-gate 
8550Sstevel@tonic-gate 
8560Sstevel@tonic-gate /*
8570Sstevel@tonic-gate  * Loop on running a kernel based command
8580Sstevel@tonic-gate  *
8590Sstevel@tonic-gate  * FIXME:  This routine is not really needed.
8600Sstevel@tonic-gate  */
8610Sstevel@tonic-gate int
ses_runcmd(ses_softc_t * ssc,Uscmd * lp)8620Sstevel@tonic-gate ses_runcmd(ses_softc_t *ssc, Uscmd *lp)
8630Sstevel@tonic-gate {
8640Sstevel@tonic-gate 	int e;
8650Sstevel@tonic-gate 
8660Sstevel@tonic-gate 	lp->uscsi_status = 0;
8673368Slh195018 	e = ses_uscsi_cmd(ssc, lp, FKIOCTL);
8680Sstevel@tonic-gate 
8690Sstevel@tonic-gate #ifdef	not
8700Sstevel@tonic-gate 	/*
8710Sstevel@tonic-gate 	 * Debug:  Nice cross-check code for verifying consistent status.
8720Sstevel@tonic-gate 	 */
8730Sstevel@tonic-gate 	if (lp->uscsi_status) {
8740Sstevel@tonic-gate 		if (lp->uscsi_status == STATUS_CHECK) {
8750Sstevel@tonic-gate 			SES_LOG(ssc, CE_NOTE, "runcmd<cdb[0]="
8760Sstevel@tonic-gate 			    "0x%x->%s ASC/ASCQ=0x%x/0x%x>",
8770Sstevel@tonic-gate 			    lp->uscsi_cdb[0],
8780Sstevel@tonic-gate 			    scsi_sname(lp->uscsi_rqbuf[2] & 0xf),
8790Sstevel@tonic-gate 			    lp->uscsi_rqbuf[12] & 0xff,
8800Sstevel@tonic-gate 			    lp->uscsi_rqbuf[13] & 0xff);
8810Sstevel@tonic-gate 		} else {
8820Sstevel@tonic-gate 			SES_LOG(ssc, CE_NOTE, "runcmd<cdb[0]="
8830Sstevel@tonic-gate 			    "0x%x -> Status 0x%x", lp->uscsi_cdb[0],
8840Sstevel@tonic-gate 			    lp->uscsi_status);
8850Sstevel@tonic-gate 		}
8860Sstevel@tonic-gate 	}
8870Sstevel@tonic-gate #endif	/* not */
8880Sstevel@tonic-gate 	return (e);
8890Sstevel@tonic-gate }
8900Sstevel@tonic-gate 
8910Sstevel@tonic-gate 
8920Sstevel@tonic-gate /*
8930Sstevel@tonic-gate  * Run a scsi command.
8940Sstevel@tonic-gate  */
8950Sstevel@tonic-gate int
ses_uscsi_cmd(ses_softc_t * ssc,Uscmd * Uc,int Uf)8963368Slh195018 ses_uscsi_cmd(ses_softc_t *ssc, Uscmd *Uc, int Uf)
8970Sstevel@tonic-gate {
8983368Slh195018 	Uscmd	*uscmd;
8993368Slh195018 	struct buf	*bp;
9003368Slh195018 	enum uio_seg	uioseg;
9013368Slh195018 	int	err;
9020Sstevel@tonic-gate 
9030Sstevel@tonic-gate 	/*
9040Sstevel@tonic-gate 	 * Grab local 'special' buffer
9050Sstevel@tonic-gate 	 */
9060Sstevel@tonic-gate 	mutex_enter(SES_MUTEX);
9070Sstevel@tonic-gate 	while (ssc->ses_sbufbsy) {
9080Sstevel@tonic-gate 		cv_wait(&ssc->ses_sbufcv, &ssc->ses_devp->sd_mutex);
9090Sstevel@tonic-gate 	}
9100Sstevel@tonic-gate 	ssc->ses_sbufbsy = 1;
9110Sstevel@tonic-gate 	mutex_exit(SES_MUTEX);
9120Sstevel@tonic-gate 
9130Sstevel@tonic-gate 	/*
9140Sstevel@tonic-gate 	 * If the device is powered down, request it's activation.
9150Sstevel@tonic-gate 	 * This check must be done after setting ses_sbufbsy!
9160Sstevel@tonic-gate 	 */
9170Sstevel@tonic-gate 	if (ssc->ses_suspended &&
9180Sstevel@tonic-gate 	    ddi_dev_is_needed(SES_DEVINFO(ssc), 0, 1) != DDI_SUCCESS) {
9190Sstevel@tonic-gate 		mutex_enter(SES_MUTEX);
9200Sstevel@tonic-gate 		ssc->ses_sbufbsy = 0;
9210Sstevel@tonic-gate 		mutex_exit(SES_MUTEX);
9220Sstevel@tonic-gate 		return (EIO);
9230Sstevel@tonic-gate 	}
9240Sstevel@tonic-gate 
9253368Slh195018 	err = scsi_uscsi_alloc_and_copyin((intptr_t)Uc, Uf,
9263368Slh195018 	    SES_ROUTE(ssc), &uscmd);
9273368Slh195018 	if (err != 0) {
9283368Slh195018 		SES_LOG(ssc, SES_CE_DEBUG1, "ses_uscsi_cmd: "
9293368Slh195018 		    "scsi_uscsi_alloc_and_copyin failed\n");
9300Sstevel@tonic-gate 		mutex_enter(SES_MUTEX);
9310Sstevel@tonic-gate 		ssc->ses_sbufbsy = 0;
9320Sstevel@tonic-gate 		cv_signal(&ssc->ses_sbufcv);
9330Sstevel@tonic-gate 		mutex_exit(SES_MUTEX);
9340Sstevel@tonic-gate 		SES_LOG(ssc, SES_CE_DEBUG2, efl, __LINE__);
9353368Slh195018 		return (err);
9360Sstevel@tonic-gate 	}
9370Sstevel@tonic-gate 
9380Sstevel@tonic-gate 	/*
9393368Slh195018 	 * Copy the uscsi command related infos to ssc for use in ses_start()
9403368Slh195018 	 * and ses_callback().
9410Sstevel@tonic-gate 	 */
9423368Slh195018 	bcopy(uscmd, &ssc->ses_uscsicmd, sizeof (Uscmd));
9433368Slh195018 	if (uscmd->uscsi_cdb != NULL) {
9443368Slh195018 		bcopy(uscmd->uscsi_cdb, &ssc->ses_srqcdb,
9453368Slh195018 		    (size_t)(uscmd->uscsi_cdblen));
9463368Slh195018 	}
9476316Seschrock 	ssc->ses_uscsicmd.uscsi_status = 0;
9480Sstevel@tonic-gate 
9490Sstevel@tonic-gate 	bp = ssc->ses_sbufp;
9500Sstevel@tonic-gate 	bp->av_back = (struct buf *)NULL;
9510Sstevel@tonic-gate 	bp->av_forw = (struct buf *)NULL;
9520Sstevel@tonic-gate 	bp->b_back = (struct buf *)ssc;
9530Sstevel@tonic-gate 	bp->b_edev = NODEV;
9540Sstevel@tonic-gate 
9553368Slh195018 	if (uscmd->uscsi_cdb != NULL) {
9563368Slh195018 		if (uscmd->uscsi_cdblen == CDB_GROUP0) {
9573368Slh195018 			SES_LOG(ssc, SES_CE_DEBUG7,
9583368Slh195018 			    "scsi_cmd: %x %x %x %x %x %x",
9593368Slh195018 			    ((char *)uscmd->uscsi_cdb)[0],
9603368Slh195018 			    ((char *)uscmd->uscsi_cdb)[1],
9613368Slh195018 			    ((char *)uscmd->uscsi_cdb)[2],
9623368Slh195018 			    ((char *)uscmd->uscsi_cdb)[3],
9633368Slh195018 			    ((char *)uscmd->uscsi_cdb)[4],
9643368Slh195018 			    ((char *)uscmd->uscsi_cdb)[5]);
9653368Slh195018 		} else {
9663368Slh195018 			SES_LOG(ssc, SES_CE_DEBUG7,
9673368Slh195018 			    "scsi cmd: %x %x %x %x %x %x %x %x %x %x",
9683368Slh195018 			    ((char *)uscmd->uscsi_cdb)[0],
9693368Slh195018 			    ((char *)uscmd->uscsi_cdb)[1],
9703368Slh195018 			    ((char *)uscmd->uscsi_cdb)[2],
9713368Slh195018 			    ((char *)uscmd->uscsi_cdb)[3],
9723368Slh195018 			    ((char *)uscmd->uscsi_cdb)[4],
9733368Slh195018 			    ((char *)uscmd->uscsi_cdb)[5],
9743368Slh195018 			    ((char *)uscmd->uscsi_cdb)[6],
9753368Slh195018 			    ((char *)uscmd->uscsi_cdb)[7],
9763368Slh195018 			    ((char *)uscmd->uscsi_cdb)[8],
9773368Slh195018 			    ((char *)uscmd->uscsi_cdb)[9]);
9780Sstevel@tonic-gate 		}
9790Sstevel@tonic-gate 	}
9800Sstevel@tonic-gate 
9813368Slh195018 	uioseg = (Uf & FKIOCTL) ? UIO_SYSSPACE : UIO_USERSPACE;
9823368Slh195018 	err = scsi_uscsi_handle_cmd(NODEV, uioseg, uscmd,
9833368Slh195018 	    ses_start, bp, NULL);
9843368Slh195018 
9850Sstevel@tonic-gate 	/*
9863368Slh195018 	 * ses_callback() may set values for ssc->ses_uscsicmd or
9873368Slh195018 	 * ssc->ses_srqsbuf, so copy them back to uscmd.
9880Sstevel@tonic-gate 	 */
9893368Slh195018 	if (uscmd->uscsi_rqbuf != NULL) {
9903368Slh195018 		bcopy(&ssc->ses_srqsbuf, uscmd->uscsi_rqbuf,
9913368Slh195018 		    (size_t)(uscmd->uscsi_rqlen));
9923368Slh195018 		uscmd->uscsi_rqresid = ssc->ses_uscsicmd.uscsi_rqresid;
9933368Slh195018 	}
9943368Slh195018 	uscmd->uscsi_status = ssc->ses_uscsicmd.uscsi_status;
9953368Slh195018 
9963368Slh195018 	(void) scsi_uscsi_copyout_and_free((intptr_t)Uc, uscmd);
9970Sstevel@tonic-gate 	mutex_enter(SES_MUTEX);
9980Sstevel@tonic-gate 	ssc->ses_sbufbsy = 0;
9990Sstevel@tonic-gate 	cv_signal(&ssc->ses_sbufcv);
10000Sstevel@tonic-gate 	mutex_exit(SES_MUTEX);
10010Sstevel@tonic-gate 
10020Sstevel@tonic-gate 	return (err);
10030Sstevel@tonic-gate }
10040Sstevel@tonic-gate 
10050Sstevel@tonic-gate 
10060Sstevel@tonic-gate 
10070Sstevel@tonic-gate /*
10080Sstevel@tonic-gate  * Command start and done functions.
10090Sstevel@tonic-gate  */
10100Sstevel@tonic-gate static int
ses_start(struct buf * bp)10110Sstevel@tonic-gate ses_start(struct buf *bp)
10120Sstevel@tonic-gate {
10130Sstevel@tonic-gate 	ses_softc_t *ssc = (ses_softc_t *)bp->b_back;
10140Sstevel@tonic-gate 
10150Sstevel@tonic-gate 	SES_LOG(ssc, SES_CE_DEBUG9, "ses_start");
10160Sstevel@tonic-gate 	if (!BP_PKT(bp)) {
10170Sstevel@tonic-gate 		/*
10180Sstevel@tonic-gate 		 * Allocate a packet.
10190Sstevel@tonic-gate 		 */
10200Sstevel@tonic-gate 		ses_get_pkt(bp, SLEEP_FUNC);
10210Sstevel@tonic-gate 		if (!BP_PKT(bp)) {
10220Sstevel@tonic-gate 			int err;
10230Sstevel@tonic-gate 			bp->b_resid = bp->b_bcount;
10240Sstevel@tonic-gate 			if (geterror(bp) == 0)
10250Sstevel@tonic-gate 				SET_BP_ERROR(bp, EIO);
10260Sstevel@tonic-gate 			err = geterror(bp);
10270Sstevel@tonic-gate 			biodone(bp);
10280Sstevel@tonic-gate 			return (err);
10290Sstevel@tonic-gate 		}
10300Sstevel@tonic-gate 	}
10310Sstevel@tonic-gate 
10320Sstevel@tonic-gate 	/*
10330Sstevel@tonic-gate 	 * Initialize the transfer residue, error code, and retry count.
10340Sstevel@tonic-gate 	 */
10350Sstevel@tonic-gate 	bp->b_resid = 0;
10360Sstevel@tonic-gate 	SET_BP_ERROR(bp, 0);
10370Sstevel@tonic-gate 
10380Sstevel@tonic-gate #if	!defined(lint)
10390Sstevel@tonic-gate 	_NOTE(NO_COMPETING_THREADS_NOW);
10400Sstevel@tonic-gate #endif 	/* !defined(lint) */
10410Sstevel@tonic-gate 	ssc->ses_retries = ses_retry_count;
10420Sstevel@tonic-gate 
10430Sstevel@tonic-gate #if	!defined(lint)
10440Sstevel@tonic-gate 	/* LINTED */
10450Sstevel@tonic-gate 	_NOTE(COMPETING_THREADS_NOW);
10460Sstevel@tonic-gate #endif	/* !defined(lint) */
10470Sstevel@tonic-gate 
10480Sstevel@tonic-gate 	SES_LOG(ssc, SES_CE_DEBUG9, "ses_start -> scsi_transport");
10490Sstevel@tonic-gate 	switch (scsi_transport(BP_PKT(bp))) {
10500Sstevel@tonic-gate 	case TRAN_ACCEPT:
10510Sstevel@tonic-gate 		return (0);
10520Sstevel@tonic-gate 		/* break; */
10530Sstevel@tonic-gate 
10540Sstevel@tonic-gate 	case TRAN_BUSY:
10550Sstevel@tonic-gate 		SES_LOG(ssc, SES_CE_DEBUG2,
10566316Seschrock 		    "ses_start: TRANSPORT BUSY");
10570Sstevel@tonic-gate 		SES_ENABLE_RESTART(SES_RESTART_TIME, BP_PKT(bp));
10580Sstevel@tonic-gate 		return (0);
10590Sstevel@tonic-gate 		/* break; */
10600Sstevel@tonic-gate 
10610Sstevel@tonic-gate 	default:
10620Sstevel@tonic-gate 		SES_LOG(ssc, SES_CE_DEBUG2, "TRANSPORT ERROR\n");
10630Sstevel@tonic-gate 		SET_BP_ERROR(bp, EIO);
10640Sstevel@tonic-gate 		scsi_destroy_pkt(BP_PKT(bp));
10650Sstevel@tonic-gate 		SET_BP_PKT(bp, NULL);
10660Sstevel@tonic-gate 		biodone(bp);
10670Sstevel@tonic-gate 		return (EIO);
10680Sstevel@tonic-gate 		/* break; */
10690Sstevel@tonic-gate 	}
10700Sstevel@tonic-gate }
10710Sstevel@tonic-gate 
10720Sstevel@tonic-gate 
10730Sstevel@tonic-gate static void
ses_get_pkt(struct buf * bp,int (* func)())10740Sstevel@tonic-gate ses_get_pkt(struct buf *bp, int (*func)())
10750Sstevel@tonic-gate {
10760Sstevel@tonic-gate 	ses_softc_t *ssc = (ses_softc_t *)bp->b_back;
10770Sstevel@tonic-gate 	Uscmd *scmd = &ssc->ses_uscsicmd;
10780Sstevel@tonic-gate 	struct scsi_pkt *pkt;
10797424SLi.He@Sun.COM 	int stat_size = 1;
10807424SLi.He@Sun.COM 	int flags = 0;
10810Sstevel@tonic-gate 
10820Sstevel@tonic-gate 	if ((scmd->uscsi_flags & USCSI_RQENABLE) && ssc->ses_arq) {
10837424SLi.He@Sun.COM 		if (scmd->uscsi_rqlen > SENSE_LENGTH) {
10847424SLi.He@Sun.COM 			stat_size = (int)(scmd->uscsi_rqlen) +
10857424SLi.He@Sun.COM 			    sizeof (struct scsi_arq_status) -
10867424SLi.He@Sun.COM 			    sizeof (struct scsi_extended_sense);
10877424SLi.He@Sun.COM 			flags = PKT_XARQ;
10887424SLi.He@Sun.COM 		} else {
10897424SLi.He@Sun.COM 			stat_size = sizeof (struct scsi_arq_status);
10907424SLi.He@Sun.COM 		}
10910Sstevel@tonic-gate 	}
10920Sstevel@tonic-gate 
10930Sstevel@tonic-gate 	if (bp->b_bcount) {
10940Sstevel@tonic-gate 		pkt = scsi_init_pkt(SES_ROUTE(ssc), NULL, bp,
10957424SLi.He@Sun.COM 		    scmd->uscsi_cdblen, stat_size, 0, flags,
10967424SLi.He@Sun.COM 		    func, (caddr_t)ssc);
10970Sstevel@tonic-gate 	} else {
10980Sstevel@tonic-gate 		pkt = scsi_init_pkt(SES_ROUTE(ssc), NULL, NULL,
10997424SLi.He@Sun.COM 		    scmd->uscsi_cdblen, stat_size, 0, flags,
11007424SLi.He@Sun.COM 		    func, (caddr_t)ssc);
11010Sstevel@tonic-gate 	}
11020Sstevel@tonic-gate 	SET_BP_PKT(bp, pkt);
11030Sstevel@tonic-gate 	if (pkt == (struct scsi_pkt *)NULL)
11040Sstevel@tonic-gate 		return;
11050Sstevel@tonic-gate 	bcopy(scmd->uscsi_cdb, pkt->pkt_cdbp, (size_t)scmd->uscsi_cdblen);
11060Sstevel@tonic-gate 	pkt->pkt_time = scmd->uscsi_timeout;
11070Sstevel@tonic-gate 
11080Sstevel@tonic-gate 	pkt->pkt_comp = ses_callback;
11090Sstevel@tonic-gate 	pkt->pkt_private = (opaque_t)ssc;
11100Sstevel@tonic-gate }
11110Sstevel@tonic-gate 
11120Sstevel@tonic-gate 
11130Sstevel@tonic-gate /*
11140Sstevel@tonic-gate  * Restart ses command.
11150Sstevel@tonic-gate  */
11160Sstevel@tonic-gate static void
ses_restart(void * arg)11170Sstevel@tonic-gate ses_restart(void *arg)
11180Sstevel@tonic-gate {
11190Sstevel@tonic-gate 	struct scsi_pkt *pkt = (struct scsi_pkt *)arg;
11200Sstevel@tonic-gate 	ses_softc_t *ssc = (ses_softc_t *)pkt->pkt_private;
11210Sstevel@tonic-gate 	struct buf *bp = ssc->ses_sbufp;
11220Sstevel@tonic-gate 	SES_LOG(ssc, SES_CE_DEBUG9, "ses_restart");
11230Sstevel@tonic-gate 
11240Sstevel@tonic-gate 	ssc->ses_restart_id = NULL;
11250Sstevel@tonic-gate 
11260Sstevel@tonic-gate 	switch (scsi_transport(pkt)) {
11270Sstevel@tonic-gate 	case TRAN_ACCEPT:
11280Sstevel@tonic-gate 		SES_LOG(ssc, SES_CE_DEBUG9,
11290Sstevel@tonic-gate 		    "RESTART %d ok", ssc->ses_retries);
11300Sstevel@tonic-gate 		return;
11310Sstevel@tonic-gate 		/* break; */
11320Sstevel@tonic-gate 	case TRAN_BUSY:
11330Sstevel@tonic-gate 		SES_LOG(ssc, SES_CE_DEBUG1,
11340Sstevel@tonic-gate 		    "RESTART %d TRANSPORT BUSY\n", ssc->ses_retries);
11350Sstevel@tonic-gate 		if (ssc->ses_retries > SES_NO_RETRY) {
11366316Seschrock 			ssc->ses_retries -= SES_BUSY_RETRY;
11376316Seschrock 			SES_ENABLE_RESTART(SES_RESTART_TIME, pkt);
11386316Seschrock 			return;
11390Sstevel@tonic-gate 		}
11400Sstevel@tonic-gate 		SET_BP_ERROR(bp, EBUSY);
11410Sstevel@tonic-gate 		break;
11420Sstevel@tonic-gate 	default:
11430Sstevel@tonic-gate 		SET_BP_ERROR(bp, EIO);
11440Sstevel@tonic-gate 		break;
11450Sstevel@tonic-gate 	}
11460Sstevel@tonic-gate 	SES_LOG(ssc, SES_CE_DEBUG1,
11470Sstevel@tonic-gate 	    "RESTART %d TRANSPORT FAILED\n", ssc->ses_retries);
11480Sstevel@tonic-gate 
11490Sstevel@tonic-gate 	pkt = (struct scsi_pkt *)bp->av_back;
11500Sstevel@tonic-gate 	scsi_destroy_pkt(pkt);
11510Sstevel@tonic-gate 	bp->b_resid = bp->b_bcount;
11520Sstevel@tonic-gate 	SET_BP_PKT(bp, NULL);
11530Sstevel@tonic-gate 	biodone(bp);
11540Sstevel@tonic-gate }
11550Sstevel@tonic-gate 
11560Sstevel@tonic-gate 
11570Sstevel@tonic-gate /*
11580Sstevel@tonic-gate  * Command completion processing
11590Sstevel@tonic-gate  */
11600Sstevel@tonic-gate #define	HBA_RESET	(STAT_BUS_RESET|STAT_DEV_RESET|STAT_ABORTED)
11610Sstevel@tonic-gate static void
ses_callback(struct scsi_pkt * pkt)11620Sstevel@tonic-gate ses_callback(struct scsi_pkt *pkt)
11630Sstevel@tonic-gate {
11640Sstevel@tonic-gate 	ses_softc_t *ssc = (ses_softc_t *)pkt->pkt_private;
11650Sstevel@tonic-gate 	struct buf *bp;
11660Sstevel@tonic-gate 	Uscmd *scmd;
11670Sstevel@tonic-gate 	int err;
11680Sstevel@tonic-gate 	char action;
11690Sstevel@tonic-gate 
11700Sstevel@tonic-gate 	bp = ssc->ses_sbufp;
11710Sstevel@tonic-gate 	scmd = &ssc->ses_uscsicmd;
11720Sstevel@tonic-gate 	/* SES_LOG(ssc, SES_CE_DEBUG9, "ses_callback"); */
11730Sstevel@tonic-gate 
11740Sstevel@tonic-gate 	/*
11750Sstevel@tonic-gate 	 * Optimization: Normal completion.
11760Sstevel@tonic-gate 	 */
11770Sstevel@tonic-gate 	if (pkt->pkt_reason == CMD_CMPLT &&
11780Sstevel@tonic-gate 	    !SCBP_C(pkt) &&
11790Sstevel@tonic-gate 	    !(pkt->pkt_flags & FLAG_SENSING) &&
11806673Seschrock 	    !pkt->pkt_resid) {
11816316Seschrock 		scsi_destroy_pkt(pkt);
11826316Seschrock 		SET_BP_PKT(bp, NULL);
11836316Seschrock 		biodone(bp);
11846316Seschrock 		return;
11850Sstevel@tonic-gate 	}
11860Sstevel@tonic-gate 
11870Sstevel@tonic-gate 
11880Sstevel@tonic-gate 	/*
11890Sstevel@tonic-gate 	 * Abnormal completion.
11900Sstevel@tonic-gate 	 *
11910Sstevel@tonic-gate 	 * Assume most common error initially.
11920Sstevel@tonic-gate 	 */
11930Sstevel@tonic-gate 	err = EIO;
11940Sstevel@tonic-gate 	action = COMMAND_DONE;
11950Sstevel@tonic-gate 	if (scmd->uscsi_flags & USCSI_DIAGNOSE) {
11960Sstevel@tonic-gate 		ssc->ses_retries = SES_NO_RETRY;
11970Sstevel@tonic-gate 	}
11980Sstevel@tonic-gate 
11990Sstevel@tonic-gate CHECK_PKT:
12000Sstevel@tonic-gate 	if (pkt->pkt_reason != CMD_CMPLT) {
12010Sstevel@tonic-gate 		/* Process transport errors. */
12020Sstevel@tonic-gate 		switch (pkt->pkt_reason) {
12030Sstevel@tonic-gate 		case CMD_TIMEOUT:
12040Sstevel@tonic-gate 			/*
12050Sstevel@tonic-gate 			 * If the transport layer didn't clear the problem,
12060Sstevel@tonic-gate 			 * reset the target.
12070Sstevel@tonic-gate 			 */
12080Sstevel@tonic-gate 			if (! (pkt->pkt_statistics & HBA_RESET)) {
12096316Seschrock 				(void) scsi_reset(&pkt->pkt_address,
12106316Seschrock 				    RESET_TARGET);
12110Sstevel@tonic-gate 			}
12120Sstevel@tonic-gate 			err = ETIMEDOUT;
12130Sstevel@tonic-gate 			break;
12140Sstevel@tonic-gate 
12150Sstevel@tonic-gate 		case CMD_INCOMPLETE:
12160Sstevel@tonic-gate 		case CMD_UNX_BUS_FREE:
12170Sstevel@tonic-gate 			/*
12180Sstevel@tonic-gate 			 * No response?  If probing, give up.
12190Sstevel@tonic-gate 			 * Otherwise, keep trying until retries exhausted.
12200Sstevel@tonic-gate 			 * Then lockdown the driver as the device is
12210Sstevel@tonic-gate 			 * unplugged.
12220Sstevel@tonic-gate 			 */
12230Sstevel@tonic-gate 			if (ssc->ses_retries <= SES_NO_RETRY &&
12240Sstevel@tonic-gate 			    !(scmd->uscsi_flags & USCSI_DIAGNOSE)) {
12250Sstevel@tonic-gate 				ssc->ses_present = SES_CLOSED;
12260Sstevel@tonic-gate 			}
12270Sstevel@tonic-gate 			/* Inhibit retries to speed probe/attach. */
12280Sstevel@tonic-gate 			if (ssc->ses_present < SES_OPEN) {
12290Sstevel@tonic-gate 				ssc->ses_retries = SES_NO_RETRY;
12300Sstevel@tonic-gate 			}
12310Sstevel@tonic-gate 			/* SES_CMD_RETRY4(ssc->ses_retries); */
12320Sstevel@tonic-gate 			err = ENXIO;
12330Sstevel@tonic-gate 			break;
12340Sstevel@tonic-gate 
12350Sstevel@tonic-gate 		case CMD_DATA_OVR:
12360Sstevel@tonic-gate 			/*
12370Sstevel@tonic-gate 			 * XXX:	Some HBA's (e.g. Adaptec 1740 and
12380Sstevel@tonic-gate 			 *	earlier ISP revs) report a DATA OVERRUN
12390Sstevel@tonic-gate 			 *	error instead of a transfer residue.  So,
12400Sstevel@tonic-gate 			 *	we convert the error and restart.
12410Sstevel@tonic-gate 			 */
12420Sstevel@tonic-gate 			if ((bp->b_bcount - pkt->pkt_resid) > 0) {
12430Sstevel@tonic-gate 				SES_LOG(ssc, SES_CE_DEBUG6,
12446316Seschrock 				    "ignoring overrun");
12450Sstevel@tonic-gate 				pkt->pkt_reason = CMD_CMPLT;
12460Sstevel@tonic-gate 				err = EOK;
12470Sstevel@tonic-gate 				goto CHECK_PKT;
12480Sstevel@tonic-gate 			}
12490Sstevel@tonic-gate 			ssc->ses_retries = SES_NO_RETRY;
12500Sstevel@tonic-gate 			/* err = EIO; */
12510Sstevel@tonic-gate 			break;
12520Sstevel@tonic-gate 
12530Sstevel@tonic-gate 		case CMD_DMA_DERR:
12540Sstevel@tonic-gate 			ssc->ses_retries = SES_NO_RETRY;
12550Sstevel@tonic-gate 			err = EFAULT;
12560Sstevel@tonic-gate 			break;
12570Sstevel@tonic-gate 
12580Sstevel@tonic-gate 		default:
12590Sstevel@tonic-gate 			/* err = EIO; */
12600Sstevel@tonic-gate 			break;
12610Sstevel@tonic-gate 		}
12620Sstevel@tonic-gate 		if (pkt == ssc->ses_rqpkt) {
12630Sstevel@tonic-gate 			SES_LOG(ssc, CE_WARN, fail_msg,
12646316Seschrock 			    "Request Sense ",
12656316Seschrock 			    scsi_rname(pkt->pkt_reason),
12666316Seschrock 			    (ssc->ses_retries > 0)?
12676316Seschrock 			    "retrying": "giving up");
12680Sstevel@tonic-gate 			pkt = (struct scsi_pkt *)bp->av_back;
12690Sstevel@tonic-gate 			action = QUE_SENSE;
12700Sstevel@tonic-gate 		} else {
12710Sstevel@tonic-gate 			SES_LOG(ssc, CE_WARN, fail_msg,
12726316Seschrock 			    "", scsi_rname(pkt->pkt_reason),
12736316Seschrock 			    (ssc->ses_retries > 0)?
12746316Seschrock 			    "retrying": "giving up");
12750Sstevel@tonic-gate 			action = QUE_COMMAND;
12760Sstevel@tonic-gate 		}
12770Sstevel@tonic-gate 		/* Device exists, allow full error recovery. */
12780Sstevel@tonic-gate 		if (ssc->ses_retries > SES_NO_RETRY) {
12790Sstevel@tonic-gate 			ssc->ses_present = SES_OPEN;
12800Sstevel@tonic-gate 		}
12810Sstevel@tonic-gate 
12820Sstevel@tonic-gate 
12830Sstevel@tonic-gate 	/*
12840Sstevel@tonic-gate 	 * Process status and sense data errors.
12850Sstevel@tonic-gate 	 */
12860Sstevel@tonic-gate 	} else {
12870Sstevel@tonic-gate 		ssc->ses_present = SES_OPEN;
12880Sstevel@tonic-gate 		action = ses_decode_sense(pkt, &err);
12890Sstevel@tonic-gate 	}
12900Sstevel@tonic-gate 
12910Sstevel@tonic-gate 
12920Sstevel@tonic-gate 	/*
12930Sstevel@tonic-gate 	 * Initiate error recovery action, as needed.
12940Sstevel@tonic-gate 	 */
12950Sstevel@tonic-gate 	switch (action) {
12960Sstevel@tonic-gate 	case QUE_COMMAND_NOW:
12970Sstevel@tonic-gate 		/* SES_LOG(ssc, SES_CE_DEBUG1, "retrying cmd now"); */
12980Sstevel@tonic-gate 		if (ssc->ses_retries > SES_NO_RETRY) {
12996316Seschrock 			ssc->ses_retries -= SES_CMD_RETRY;
13006316Seschrock 			scmd->uscsi_status = 0;
13016316Seschrock 			if (ssc->ses_arq)
13026316Seschrock 				bzero(pkt->pkt_scbp,
13036316Seschrock 				    sizeof (struct scsi_arq_status));
13040Sstevel@tonic-gate 
13056316Seschrock 			if (scsi_transport((struct scsi_pkt *)bp->av_back)
13066316Seschrock 			    != TRAN_ACCEPT) {
13076316Seschrock 				SES_ENABLE_RESTART(SES_RESTART_TIME,
13086316Seschrock 				    (struct scsi_pkt *)bp->av_back);
13096316Seschrock 			}
13106316Seschrock 			return;
13110Sstevel@tonic-gate 		}
13120Sstevel@tonic-gate 		break;
13130Sstevel@tonic-gate 
13140Sstevel@tonic-gate 	case QUE_COMMAND:
13150Sstevel@tonic-gate 		SES_LOG(ssc, SES_CE_DEBUG1, "retrying cmd");
13160Sstevel@tonic-gate 		if (ssc->ses_retries > SES_NO_RETRY) {
13176316Seschrock 			ssc->ses_retries -=
13186316Seschrock 			    (err == EBUSY)? SES_BUSY_RETRY: SES_CMD_RETRY;
13196316Seschrock 			scmd->uscsi_status = 0;
13206316Seschrock 			if (ssc->ses_arq)
13216316Seschrock 				bzero(pkt->pkt_scbp,
13226316Seschrock 				    sizeof (struct scsi_arq_status));
13230Sstevel@tonic-gate 
13246316Seschrock 			SES_ENABLE_RESTART(
13256316Seschrock 			    (err == EBUSY)? SES_BUSY_TIME: SES_RESTART_TIME,
13266316Seschrock 			    (struct scsi_pkt *)bp->av_back);
13276316Seschrock 			return;
13280Sstevel@tonic-gate 		}
13290Sstevel@tonic-gate 		break;
13300Sstevel@tonic-gate 
13310Sstevel@tonic-gate 	case QUE_SENSE:
13320Sstevel@tonic-gate 		SES_LOG(ssc, SES_CE_DEBUG1, "retrying sense");
13330Sstevel@tonic-gate 		if (ssc->ses_retries > SES_NO_RETRY) {
13340Sstevel@tonic-gate 			ssc->ses_retries -= SES_SENSE_RETRY;
13350Sstevel@tonic-gate 			scmd->uscsi_status = 0;
13367424SLi.He@Sun.COM 			bzero(&ssc->ses_srqsbuf, MAX_SENSE_LENGTH);
13370Sstevel@tonic-gate 
13380Sstevel@tonic-gate 			if (scsi_transport(ssc->ses_rqpkt) != TRAN_ACCEPT) {
13390Sstevel@tonic-gate 				SES_ENABLE_RESTART(SES_RESTART_TIME,
13400Sstevel@tonic-gate 				    ssc->ses_rqpkt);
13410Sstevel@tonic-gate 			}
13426316Seschrock 			return;
13430Sstevel@tonic-gate 		}
13440Sstevel@tonic-gate 		break;
13450Sstevel@tonic-gate 
13460Sstevel@tonic-gate 	case COMMAND_DONE:
13470Sstevel@tonic-gate 		SES_LOG(ssc, SES_CE_DEBUG4, "cmd done");
13480Sstevel@tonic-gate 		pkt = (struct scsi_pkt *)bp->av_back;
13490Sstevel@tonic-gate 		bp->b_resid = pkt->pkt_resid;
13500Sstevel@tonic-gate 		if (bp->b_resid) {
13516316Seschrock 			SES_LOG(ssc, SES_CE_DEBUG6,
13526316Seschrock 			    "transfer residue %ld(%ld)",
13536316Seschrock 			    bp->b_bcount - bp->b_resid, bp->b_bcount);
13540Sstevel@tonic-gate 		}
13550Sstevel@tonic-gate 		break;
13560Sstevel@tonic-gate 	}
13570Sstevel@tonic-gate 	pkt = (struct scsi_pkt *)bp->av_back;
13580Sstevel@tonic-gate 	if (err) {
13590Sstevel@tonic-gate 		SES_LOG(ssc, SES_CE_DEBUG1, "SES: ERROR %d\n", err);
13600Sstevel@tonic-gate 		SET_BP_ERROR(bp, err);
13610Sstevel@tonic-gate 		bp->b_resid = bp->b_bcount;
13620Sstevel@tonic-gate 	}
13630Sstevel@tonic-gate 	scsi_destroy_pkt(pkt);
13640Sstevel@tonic-gate 	SET_BP_PKT(bp, NULL);
13650Sstevel@tonic-gate 	biodone(bp);
13660Sstevel@tonic-gate }
13670Sstevel@tonic-gate 
13680Sstevel@tonic-gate 
13690Sstevel@tonic-gate /*
13700Sstevel@tonic-gate  * Check status and sense data and determine recovery.
13710Sstevel@tonic-gate  */
13720Sstevel@tonic-gate static int
ses_decode_sense(struct scsi_pkt * pkt,int * err)13730Sstevel@tonic-gate ses_decode_sense(struct scsi_pkt *pkt, int *err)
13740Sstevel@tonic-gate {
13750Sstevel@tonic-gate 	ses_softc_t *ssc = (ses_softc_t *)pkt->pkt_private;
13760Sstevel@tonic-gate 	struct	scsi_extended_sense *sense =
13770Sstevel@tonic-gate 	    (struct scsi_extended_sense *)&ssc->ses_srqsbuf;
13780Sstevel@tonic-gate 	Uscmd *scmd = &ssc->ses_uscsicmd;
13790Sstevel@tonic-gate 	char sense_flag = 0;
13800Sstevel@tonic-gate 	uchar_t status = SCBP_C(pkt) & STATUS_MASK;
13810Sstevel@tonic-gate 	char *err_action;
13820Sstevel@tonic-gate 	char action;
13837424SLi.He@Sun.COM 	uchar_t rqlen;
13847424SLi.He@Sun.COM 	int amt;
13850Sstevel@tonic-gate 
13860Sstevel@tonic-gate 	/*
13870Sstevel@tonic-gate 	 * Process manual request sense.
13880Sstevel@tonic-gate 	 * Copy manual request sense to sense buffer.
13890Sstevel@tonic-gate 	 *
13900Sstevel@tonic-gate 	 * This is done if auto request sense is not enabled.
13910Sstevel@tonic-gate 	 * Or the auto request sense failed and the request
13920Sstevel@tonic-gate 	 * sense needs to be retried.
13930Sstevel@tonic-gate 	 */
13940Sstevel@tonic-gate 	if (pkt->pkt_flags & FLAG_SENSING) {
13950Sstevel@tonic-gate 		struct buf *sbp = ssc->ses_rqbp;
13967424SLi.He@Sun.COM 		amt = min(MAX_SENSE_LENGTH,
13970Sstevel@tonic-gate 		    sbp->b_bcount - sbp->b_resid);
13987424SLi.He@Sun.COM 		rqlen = min((uchar_t)amt, scmd->uscsi_rqlen);
13997424SLi.He@Sun.COM 		bcopy(sbp->b_un.b_addr, sense, rqlen);
14007424SLi.He@Sun.COM 		scmd->uscsi_rqresid = scmd->uscsi_rqlen - rqlen;
14010Sstevel@tonic-gate 		sense_flag = 1;
14020Sstevel@tonic-gate 	/*
14030Sstevel@tonic-gate 	 * Process auto request sense.
14040Sstevel@tonic-gate 	 * Copy auto request sense to sense buffer.
14050Sstevel@tonic-gate 	 *
14060Sstevel@tonic-gate 	 * If auto request sense failed due to transport error,
14070Sstevel@tonic-gate 	 * retry the command.  Otherwise process the status and
14080Sstevel@tonic-gate 	 * sense data.
14090Sstevel@tonic-gate 	 */
14100Sstevel@tonic-gate 	} else if (ssc->ses_arq && pkt->pkt_state & STATE_ARQ_DONE) {
14110Sstevel@tonic-gate 		struct scsi_arq_status *arq =
14126316Seschrock 		    (struct scsi_arq_status *)(pkt->pkt_scbp);
14130Sstevel@tonic-gate 		uchar_t *arq_status = (uchar_t *)&arq->sts_rqpkt_status;
14147424SLi.He@Sun.COM 		if (pkt->pkt_state & STATE_XARQ_DONE) {
14157424SLi.He@Sun.COM 			amt = MAX_SENSE_LENGTH - arq->sts_rqpkt_resid;
14167424SLi.He@Sun.COM 		} else {
14177424SLi.He@Sun.COM 			if (arq->sts_rqpkt_resid > SENSE_LENGTH) {
14187424SLi.He@Sun.COM 				amt = MAX_SENSE_LENGTH - arq->sts_rqpkt_resid;
14197424SLi.He@Sun.COM 			} else {
14207424SLi.He@Sun.COM 				amt = SENSE_LENGTH - arq->sts_rqpkt_resid;
14217424SLi.He@Sun.COM 			}
14227424SLi.He@Sun.COM 		}
14230Sstevel@tonic-gate 
14240Sstevel@tonic-gate 		if (arq->sts_rqpkt_reason != CMD_CMPLT) {
14250Sstevel@tonic-gate 			return (QUE_COMMAND);
14260Sstevel@tonic-gate 		}
14277424SLi.He@Sun.COM 
14287424SLi.He@Sun.COM 		rqlen = min((uchar_t)amt, scmd->uscsi_rqlen);
14297424SLi.He@Sun.COM 		bcopy(&arq->sts_sensedata, sense, rqlen);
14300Sstevel@tonic-gate 		scmd->uscsi_status = status;
14317424SLi.He@Sun.COM 		scmd->uscsi_rqresid = scmd->uscsi_rqlen - rqlen;
14320Sstevel@tonic-gate 		status = *arq_status & STATUS_MASK;
14330Sstevel@tonic-gate 		pkt->pkt_state &= ~STATE_ARQ_DONE;
14340Sstevel@tonic-gate 		sense_flag = 1;
14350Sstevel@tonic-gate 	}
14360Sstevel@tonic-gate 
14370Sstevel@tonic-gate 
14380Sstevel@tonic-gate 	/*
14390Sstevel@tonic-gate 	 * Check status of REQUEST SENSE or command.
14400Sstevel@tonic-gate 	 *
14410Sstevel@tonic-gate 	 * If it's not successful, try retrying the original command
14420Sstevel@tonic-gate 	 * and hope that it goes away.  If not, we'll eventually run
14430Sstevel@tonic-gate 	 * out of retries and die.
14440Sstevel@tonic-gate 	 */
14450Sstevel@tonic-gate 	switch (status) {
14460Sstevel@tonic-gate 	case STATUS_GOOD:
14470Sstevel@tonic-gate 	case STATUS_INTERMEDIATE:
14480Sstevel@tonic-gate 	case STATUS_MET:
14490Sstevel@tonic-gate 		/*
14500Sstevel@tonic-gate 		 * If the command status is ok, we're done.
14510Sstevel@tonic-gate 		 * Otherwise, examine the request sense data.
14520Sstevel@tonic-gate 		 */
14530Sstevel@tonic-gate 		if (! sense_flag) {
14540Sstevel@tonic-gate 			*err = EOK;
14550Sstevel@tonic-gate 			return (COMMAND_DONE);
14560Sstevel@tonic-gate 		}
14570Sstevel@tonic-gate 		break;
14580Sstevel@tonic-gate 
14590Sstevel@tonic-gate 	case STATUS_CHECK:
14600Sstevel@tonic-gate 		SES_LOG(ssc, SES_CE_DEBUG3, "status decode: check");
14610Sstevel@tonic-gate 		*err = EIO;
14620Sstevel@tonic-gate 		return (QUE_SENSE);
14630Sstevel@tonic-gate 		/* break; */
14640Sstevel@tonic-gate 
14650Sstevel@tonic-gate 	case STATUS_BUSY:
14660Sstevel@tonic-gate 		SES_LOG(ssc, SES_CE_DEBUG1, "status decode: busy");
14670Sstevel@tonic-gate 		/* SES_CMD_RETRY2(ssc->ses_retries); */
14680Sstevel@tonic-gate 		*err = EBUSY;
14690Sstevel@tonic-gate 		return (QUE_COMMAND);
14700Sstevel@tonic-gate 		/* break; */
14710Sstevel@tonic-gate 
14720Sstevel@tonic-gate 	case STATUS_RESERVATION_CONFLICT:
14730Sstevel@tonic-gate 		SES_LOG(ssc, SES_CE_DEBUG1, "status decode: reserved");
14740Sstevel@tonic-gate 		*err = EACCES;
14750Sstevel@tonic-gate 		return (COMMAND_DONE_ERROR);
14760Sstevel@tonic-gate 		/* break; */
14770Sstevel@tonic-gate 
14780Sstevel@tonic-gate 	case STATUS_TERMINATED:
14790Sstevel@tonic-gate 		SES_LOG(ssc, SES_CE_DEBUG1, "status decode: terminated");
14800Sstevel@tonic-gate 		*err = ECANCELED;
14810Sstevel@tonic-gate 		return (COMMAND_DONE_ERROR);
14820Sstevel@tonic-gate 		/* break; */
14830Sstevel@tonic-gate 
14840Sstevel@tonic-gate 	default:
14850Sstevel@tonic-gate 		SES_LOG(ssc, SES_CE_DEBUG1, "status 0x%x", status);
14860Sstevel@tonic-gate 		*err = EIO;
14870Sstevel@tonic-gate 		return (QUE_COMMAND);
14880Sstevel@tonic-gate 		/* break; */
14890Sstevel@tonic-gate 	}
14900Sstevel@tonic-gate 
14910Sstevel@tonic-gate 
14920Sstevel@tonic-gate 	/*
14930Sstevel@tonic-gate 	 * Check REQUEST SENSE error code.
14940Sstevel@tonic-gate 	 *
14950Sstevel@tonic-gate 	 * Either there's no error, a retryable error,
14960Sstevel@tonic-gate 	 * or it's dead.  SES devices aren't very complex.
14970Sstevel@tonic-gate 	 */
14980Sstevel@tonic-gate 	err_action = "retrying";
14990Sstevel@tonic-gate 	switch (sense->es_key) {
15000Sstevel@tonic-gate 	case KEY_RECOVERABLE_ERROR:
15010Sstevel@tonic-gate 		*err = EOK;
15020Sstevel@tonic-gate 		err_action = "recovered";
15030Sstevel@tonic-gate 		action = COMMAND_DONE;
15040Sstevel@tonic-gate 		break;
15050Sstevel@tonic-gate 
15060Sstevel@tonic-gate 	case KEY_UNIT_ATTENTION:
15070Sstevel@tonic-gate 		/*
15080Sstevel@tonic-gate 		 * This is common for RAID!
15090Sstevel@tonic-gate 		 */
15100Sstevel@tonic-gate 		/* *err = EIO; */
15110Sstevel@tonic-gate 		SES_CMD_RETRY1(ssc->ses_retries);
15120Sstevel@tonic-gate 		action = QUE_COMMAND_NOW;
15130Sstevel@tonic-gate 		break;
15140Sstevel@tonic-gate 
15150Sstevel@tonic-gate 	case KEY_NOT_READY:
15160Sstevel@tonic-gate 	case KEY_NO_SENSE:
15170Sstevel@tonic-gate 		/* *err = EIO; */
15180Sstevel@tonic-gate 		action = QUE_COMMAND;
15190Sstevel@tonic-gate 		break;
15200Sstevel@tonic-gate 
15210Sstevel@tonic-gate 	default:
15220Sstevel@tonic-gate 		/* *err = EIO; */
15230Sstevel@tonic-gate 		err_action = "fatal";
15240Sstevel@tonic-gate 		action = COMMAND_DONE_ERROR;
15250Sstevel@tonic-gate 		break;
15260Sstevel@tonic-gate 	}
15270Sstevel@tonic-gate 	SES_LOG(ssc, SES_CE_DEBUG1,
15286316Seschrock 	    "cdb[0]= 0x%x %s,  key=0x%x, ASC/ASCQ=0x%x/0x%x",
15296316Seschrock 	    scmd->uscsi_cdb[0], err_action,
15306316Seschrock 	    sense->es_key, sense->es_add_code, sense->es_qual_code);
15310Sstevel@tonic-gate 
15320Sstevel@tonic-gate #ifdef 	not
15330Sstevel@tonic-gate 	/*
15340Sstevel@tonic-gate 	 * Dump cdb and sense data stat's for manufacturing.
15350Sstevel@tonic-gate 	 */
15360Sstevel@tonic-gate 	if (DEBUGGING_ERR || sd_error_level == SDERR_ALL) {
15370Sstevel@tonic-gate 		auto buf[128];
15380Sstevel@tonic-gate 
15390Sstevel@tonic-gate 		p = pkt->pkt_cdbp;
15400Sstevel@tonic-gate 		if ((j = scsi_cdb_size[CDB_GROUPID(*p)]) == 0)
15410Sstevel@tonic-gate 			j = CDB_SIZE;
15420Sstevel@tonic-gate 
15430Sstevel@tonic-gate 		/* Print cdb */
15440Sstevel@tonic-gate 		(void) sprintf(buf, "cmd:");
15450Sstevel@tonic-gate 		for (i = 0; i < j; i++) {
15460Sstevel@tonic-gate 			(void) sprintf(&buf[strlen(buf)],
15470Sstevel@tonic-gate 			    hex, (uchar_t)*p++);
15480Sstevel@tonic-gate 		}
15490Sstevel@tonic-gate 		SES_LOG(ssc, SES_CE_DEBUG3, "%s", buf);
15500Sstevel@tonic-gate 
15510Sstevel@tonic-gate 		/* Suppress trailing zero's in sense data */
15520Sstevel@tonic-gate 		if (amt > 3) {
15530Sstevel@tonic-gate 			p = (char *)devp->sd_sense + amt;
15540Sstevel@tonic-gate 			for (j = amt; j > 3; j--) {
15550Sstevel@tonic-gate 				if (*(--p))  break;
15560Sstevel@tonic-gate 			}
15570Sstevel@tonic-gate 		} else {
15580Sstevel@tonic-gate 			j = amt;
15590Sstevel@tonic-gate 		}
15600Sstevel@tonic-gate 
15610Sstevel@tonic-gate 		/* Print sense data. */
15620Sstevel@tonic-gate 		(void) sprintf(buf, "sense:");
15630Sstevel@tonic-gate 		p = (char *)devp->sd_sense;
15640Sstevel@tonic-gate 		for (i = 0; i < j; i++) {
15650Sstevel@tonic-gate 			(void) sprintf(&buf[strlen(buf)],
15660Sstevel@tonic-gate 			    hex, (uchar_t)*p++);
15670Sstevel@tonic-gate 		}
15680Sstevel@tonic-gate 		SES_LOG(ssc, SES_CE_DEBUG3, "%s", buf);
15690Sstevel@tonic-gate 	}
15700Sstevel@tonic-gate #endif 	/* not */
15710Sstevel@tonic-gate 	return (action);
15720Sstevel@tonic-gate }
15730Sstevel@tonic-gate 
15740Sstevel@tonic-gate 
15750Sstevel@tonic-gate /*PRINTFLIKE3*/
15760Sstevel@tonic-gate void
ses_log(ses_softc_t * ssc,int level,const char * fmt,...)15770Sstevel@tonic-gate ses_log(ses_softc_t *ssc, int level, const char *fmt, ...)
15780Sstevel@tonic-gate {
15790Sstevel@tonic-gate 	va_list	ap;
15800Sstevel@tonic-gate 	char buf[256];
15810Sstevel@tonic-gate 
15820Sstevel@tonic-gate 	va_start(ap, fmt);
15830Sstevel@tonic-gate 	(void) vsprintf(buf, fmt, ap);
15840Sstevel@tonic-gate 	va_end(ap);
15850Sstevel@tonic-gate 
15860Sstevel@tonic-gate 	if (ssc == (ses_softc_t *)NULL) {
15870Sstevel@tonic-gate 		switch (level) {
15880Sstevel@tonic-gate 		case SES_CE_DEBUG1:
15890Sstevel@tonic-gate 			if (ses_debug > 1)
15900Sstevel@tonic-gate 				cmn_err(CE_NOTE, "%s", buf);
15910Sstevel@tonic-gate 			break;
15920Sstevel@tonic-gate 		case SES_CE_DEBUG2:
15930Sstevel@tonic-gate 			if (ses_debug > 2)
15940Sstevel@tonic-gate 				cmn_err(CE_NOTE, "%s", buf);
15950Sstevel@tonic-gate 			break;
15960Sstevel@tonic-gate 		case SES_CE_DEBUG3:
15970Sstevel@tonic-gate 			if (ses_debug > 3)
15980Sstevel@tonic-gate 				cmn_err(CE_NOTE, "%s", buf);
15990Sstevel@tonic-gate 			break;
16000Sstevel@tonic-gate 		case SES_CE_DEBUG4:
16010Sstevel@tonic-gate 			if (ses_debug > 4)
16020Sstevel@tonic-gate 				cmn_err(CE_NOTE, "%s", buf);
16030Sstevel@tonic-gate 			break;
16040Sstevel@tonic-gate 		case SES_CE_DEBUG5:
16050Sstevel@tonic-gate 			if (ses_debug > 5)
16060Sstevel@tonic-gate 				cmn_err(CE_NOTE, "%s", buf);
16070Sstevel@tonic-gate 			break;
16080Sstevel@tonic-gate 		case SES_CE_DEBUG6:
16090Sstevel@tonic-gate 			if (ses_debug > 6)
16100Sstevel@tonic-gate 				cmn_err(CE_NOTE, "%s", buf);
16110Sstevel@tonic-gate 			break;
16120Sstevel@tonic-gate 		case SES_CE_DEBUG7:
16130Sstevel@tonic-gate 			if (ses_debug > 7)
16140Sstevel@tonic-gate 				cmn_err(CE_NOTE, "%s", buf);
16150Sstevel@tonic-gate 			break;
16160Sstevel@tonic-gate 		case SES_CE_DEBUG8:
16170Sstevel@tonic-gate 			if (ses_debug > 8)
16180Sstevel@tonic-gate 				cmn_err(CE_NOTE, "%s", buf);
16190Sstevel@tonic-gate 			break;
16200Sstevel@tonic-gate 		case SES_CE_DEBUG9:
16210Sstevel@tonic-gate 			if (ses_debug > 9)
16220Sstevel@tonic-gate 				cmn_err(CE_NOTE, "%s", buf);
16230Sstevel@tonic-gate 			break;
16240Sstevel@tonic-gate 		case CE_NOTE:
16250Sstevel@tonic-gate 		case CE_WARN:
16260Sstevel@tonic-gate 		case CE_PANIC:
16270Sstevel@tonic-gate 			cmn_err(level, "%s", buf);
16280Sstevel@tonic-gate 			break;
16290Sstevel@tonic-gate 		case SES_CE_DEBUG:
16300Sstevel@tonic-gate 		default:
16310Sstevel@tonic-gate 			cmn_err(CE_NOTE, "%s", buf);
16320Sstevel@tonic-gate 		break;
16330Sstevel@tonic-gate 		}
16340Sstevel@tonic-gate 		return;
16350Sstevel@tonic-gate 	}
16360Sstevel@tonic-gate 
16370Sstevel@tonic-gate 	switch (level) {
16380Sstevel@tonic-gate 	case CE_CONT:
16390Sstevel@tonic-gate 	case CE_NOTE:
16400Sstevel@tonic-gate 	case CE_WARN:
16410Sstevel@tonic-gate 	case CE_PANIC:
16420Sstevel@tonic-gate 		scsi_log(SES_DEVINFO(ssc), (char *)Snm, level, Str, buf);
16430Sstevel@tonic-gate 		break;
16440Sstevel@tonic-gate 	case SES_CE_DEBUG1:
16450Sstevel@tonic-gate 		if (ses_debug > 1)
16460Sstevel@tonic-gate 			scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG,
16470Sstevel@tonic-gate 			    Str, buf);
16480Sstevel@tonic-gate 		break;
16490Sstevel@tonic-gate 	case SES_CE_DEBUG2:
16500Sstevel@tonic-gate 		if (ses_debug > 2)
16510Sstevel@tonic-gate 			scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG,
16520Sstevel@tonic-gate 			    Str, buf);
16530Sstevel@tonic-gate 		break;
16540Sstevel@tonic-gate 	case SES_CE_DEBUG3:
16550Sstevel@tonic-gate 		if (ses_debug > 3)
16560Sstevel@tonic-gate 			scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG,
16570Sstevel@tonic-gate 			    Str, buf);
16580Sstevel@tonic-gate 		break;
16590Sstevel@tonic-gate 	case SES_CE_DEBUG4:
16600Sstevel@tonic-gate 		if (ses_debug > 4)
16610Sstevel@tonic-gate 			scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG,
16620Sstevel@tonic-gate 			    Str, buf);
16630Sstevel@tonic-gate 		break;
16640Sstevel@tonic-gate 	case SES_CE_DEBUG5:
16650Sstevel@tonic-gate 		if (ses_debug > 5)
16660Sstevel@tonic-gate 			scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG,
16670Sstevel@tonic-gate 			    Str, buf);
16680Sstevel@tonic-gate 		break;
16690Sstevel@tonic-gate 	case SES_CE_DEBUG6:
16700Sstevel@tonic-gate 		if (ses_debug > 6)
16710Sstevel@tonic-gate 			scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG,
16720Sstevel@tonic-gate 			    Str, buf);
16730Sstevel@tonic-gate 		break;
16740Sstevel@tonic-gate 	case SES_CE_DEBUG7:
16750Sstevel@tonic-gate 		if (ses_debug > 7)
16760Sstevel@tonic-gate 			scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG,
16770Sstevel@tonic-gate 			    Str, buf);
16780Sstevel@tonic-gate 		break;
16790Sstevel@tonic-gate 	case SES_CE_DEBUG8:
16800Sstevel@tonic-gate 		if (ses_debug > 8)
16810Sstevel@tonic-gate 			scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG,
16820Sstevel@tonic-gate 			    Str, buf);
16830Sstevel@tonic-gate 		break;
16840Sstevel@tonic-gate 	case SES_CE_DEBUG9:
16850Sstevel@tonic-gate 		if (ses_debug > 9)
16860Sstevel@tonic-gate 			scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG,
16870Sstevel@tonic-gate 			    Str, buf);
16880Sstevel@tonic-gate 		break;
16890Sstevel@tonic-gate 	case SES_CE_DEBUG:
16900Sstevel@tonic-gate 	default:
16910Sstevel@tonic-gate 		scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG, Str, buf);
16920Sstevel@tonic-gate 		break;
16930Sstevel@tonic-gate 	}
16940Sstevel@tonic-gate }
16950Sstevel@tonic-gate /*
16960Sstevel@tonic-gate  * mode: c
16970Sstevel@tonic-gate  * Local variables:
16980Sstevel@tonic-gate  * c-indent-level: 8
16990Sstevel@tonic-gate  * c-brace-imaginary-offset: 0
17000Sstevel@tonic-gate  * c-brace-offset: -8
17010Sstevel@tonic-gate  * c-argdecl-indent: 8
17020Sstevel@tonic-gate  * c-label-offset: -8
17030Sstevel@tonic-gate  * c-continued-statement-offset: 8
17040Sstevel@tonic-gate  * c-continued-brace-offset: 0
17050Sstevel@tonic-gate  * End:
17060Sstevel@tonic-gate  */
1707