xref: /titanic_52/usr/src/uts/common/io/scsi/targets/ses.c (revision ffc5bd0fe44a6f6529e738f1c202f788b1355046)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
56567eb0aSlh195018  * Common Development and Distribution License (the "License").
66567eb0aSlh195018  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
227c478bd9Sstevel@tonic-gate  * Enclosure Services Device target driver
237c478bd9Sstevel@tonic-gate  *
244c06356bSdh142964  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
257c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
2689b43686SBayard Bell  * Copyright (c) 2011 Bayard G. Bell. All rights reserved.
27*ffc5bd0fSKevin Crowe  * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
287c478bd9Sstevel@tonic-gate  */
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
317c478bd9Sstevel@tonic-gate #include <sys/file.h>
327c478bd9Sstevel@tonic-gate #include <sys/scsi/scsi.h>
337c478bd9Sstevel@tonic-gate #include <sys/scsi/generic/status.h>
347c478bd9Sstevel@tonic-gate #include <sys/scsi/targets/sesio.h>
357c478bd9Sstevel@tonic-gate #include <sys/scsi/targets/ses.h>
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate /*
407c478bd9Sstevel@tonic-gate  * Power management defines (should be in a common include file?)
417c478bd9Sstevel@tonic-gate  */
427c478bd9Sstevel@tonic-gate #define	PM_HARDWARE_STATE_PROP		"pm-hardware-state"
437c478bd9Sstevel@tonic-gate #define	PM_NEEDS_SUSPEND_RESUME		"needs-suspend-resume"
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate /*
477c478bd9Sstevel@tonic-gate  * Global Driver Data
487c478bd9Sstevel@tonic-gate  */
497c478bd9Sstevel@tonic-gate int ses_io_time = SES_IO_TIME;
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate static int ses_retry_count = SES_RETRY_COUNT * SES_RETRY_MULTIPLIER;
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate #ifdef	DEBUG
547c478bd9Sstevel@tonic-gate int ses_debug = 0;
557c478bd9Sstevel@tonic-gate #else	/* DEBUG */
567c478bd9Sstevel@tonic-gate #define	ses_debug	0
577c478bd9Sstevel@tonic-gate #endif	/* DEBUG */
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate /*
617c478bd9Sstevel@tonic-gate  * External Enclosure Functions
627c478bd9Sstevel@tonic-gate  */
637c478bd9Sstevel@tonic-gate extern int ses_softc_init(ses_softc_t *, int);
647c478bd9Sstevel@tonic-gate extern int ses_init_enc(ses_softc_t *);
657c478bd9Sstevel@tonic-gate extern int ses_get_encstat(ses_softc_t *, int);
667c478bd9Sstevel@tonic-gate extern int ses_set_encstat(ses_softc_t *, uchar_t, int);
677c478bd9Sstevel@tonic-gate extern int ses_get_objstat(ses_softc_t *, ses_objarg *, int);
687c478bd9Sstevel@tonic-gate extern int ses_set_objstat(ses_softc_t *, ses_objarg *, int);
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate extern int safte_softc_init(ses_softc_t *, int);
717c478bd9Sstevel@tonic-gate extern int safte_init_enc(ses_softc_t *);
727c478bd9Sstevel@tonic-gate extern int safte_get_encstat(ses_softc_t *, int);
737c478bd9Sstevel@tonic-gate extern int safte_set_encstat(ses_softc_t *, uchar_t, int);
747c478bd9Sstevel@tonic-gate extern int safte_get_objstat(ses_softc_t *, ses_objarg *, int);
757c478bd9Sstevel@tonic-gate extern int safte_set_objstat(ses_softc_t *, ses_objarg *, int);
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate extern int sen_softc_init(ses_softc_t *, int);
787c478bd9Sstevel@tonic-gate extern int sen_init_enc(ses_softc_t *);
797c478bd9Sstevel@tonic-gate extern int sen_get_encstat(ses_softc_t *, int);
807c478bd9Sstevel@tonic-gate extern int sen_set_encstat(ses_softc_t *, uchar_t, int);
817c478bd9Sstevel@tonic-gate extern int sen_get_objstat(ses_softc_t *, ses_objarg *, int);
827c478bd9Sstevel@tonic-gate extern int sen_set_objstat(ses_softc_t *, ses_objarg *, int);
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate /*
857c478bd9Sstevel@tonic-gate  * Local Function prototypes
867c478bd9Sstevel@tonic-gate  */
877c478bd9Sstevel@tonic-gate static int ses_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
887c478bd9Sstevel@tonic-gate static int ses_probe(dev_info_t *);
897c478bd9Sstevel@tonic-gate static int ses_attach(dev_info_t *, ddi_attach_cmd_t);
907c478bd9Sstevel@tonic-gate static int ses_detach(dev_info_t *, ddi_detach_cmd_t);
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate static int is_enc_dev(ses_softc_t *, struct scsi_inquiry *, int, enctyp *);
937c478bd9Sstevel@tonic-gate static int ses_doattach(dev_info_t *dip);
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate static int  ses_open(dev_t *, int, int, cred_t *);
967c478bd9Sstevel@tonic-gate static int  ses_close(dev_t, int, int, cred_t *);
977c478bd9Sstevel@tonic-gate static int  ses_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate static encvec vecs[3] = {
1007c478bd9Sstevel@tonic-gate {
1017c478bd9Sstevel@tonic-gate 	ses_softc_init, ses_init_enc, ses_get_encstat,
1027c478bd9Sstevel@tonic-gate 	ses_set_encstat, ses_get_objstat, ses_set_objstat
1037c478bd9Sstevel@tonic-gate },
1047c478bd9Sstevel@tonic-gate {
1057c478bd9Sstevel@tonic-gate 	safte_softc_init, safte_init_enc, safte_get_encstat,
1067c478bd9Sstevel@tonic-gate 	safte_set_encstat, safte_get_objstat, safte_set_objstat,
1077c478bd9Sstevel@tonic-gate },
1087c478bd9Sstevel@tonic-gate {
1097c478bd9Sstevel@tonic-gate 	sen_softc_init, sen_init_enc, sen_get_encstat,
1107c478bd9Sstevel@tonic-gate 	sen_set_encstat, sen_get_objstat, sen_set_objstat
1117c478bd9Sstevel@tonic-gate }
1127c478bd9Sstevel@tonic-gate };
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate /*
1167c478bd9Sstevel@tonic-gate  * Local Functions
1177c478bd9Sstevel@tonic-gate  */
1187c478bd9Sstevel@tonic-gate static int ses_start(struct buf *bp);
1197c478bd9Sstevel@tonic-gate static int ses_decode_sense(struct scsi_pkt *pkt, int *err);
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate static void ses_get_pkt(struct buf *bp, int (*func)(opaque_t));
1227c478bd9Sstevel@tonic-gate static void ses_callback(struct scsi_pkt *pkt);
1237c478bd9Sstevel@tonic-gate static void ses_restart(void *arg);
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate /*
1277c478bd9Sstevel@tonic-gate  * Local Static Data
1287c478bd9Sstevel@tonic-gate  */
1297c478bd9Sstevel@tonic-gate #ifndef	D_HOTPLUG
1307c478bd9Sstevel@tonic-gate #define	D_HOTPLUG	0
1317c478bd9Sstevel@tonic-gate #endif /* D_HOTPLUG */
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate static struct cb_ops ses_cb_ops = {
1347c478bd9Sstevel@tonic-gate 	ses_open,			/* open */
1357c478bd9Sstevel@tonic-gate 	ses_close,			/* close */
1367c478bd9Sstevel@tonic-gate 	nodev,				/* strategy */
1377c478bd9Sstevel@tonic-gate 	nodev,				/* print */
1387c478bd9Sstevel@tonic-gate 	nodev,				/* dump */
1397c478bd9Sstevel@tonic-gate 	nodev,				/* read */
1407c478bd9Sstevel@tonic-gate 	nodev,				/* write */
1417c478bd9Sstevel@tonic-gate 	ses_ioctl,			/* ioctl */
1427c478bd9Sstevel@tonic-gate 	nodev,				/* devmap */
1437c478bd9Sstevel@tonic-gate 	nodev,				/* mmap */
1447c478bd9Sstevel@tonic-gate 	nodev,				/* segmap */
1457c478bd9Sstevel@tonic-gate 	nochpoll,			/* poll */
1467c478bd9Sstevel@tonic-gate 	ddi_prop_op,			/* cb_prop_op */
1477c478bd9Sstevel@tonic-gate 	0,				/* streamtab  */
1487c478bd9Sstevel@tonic-gate #if	!defined(CB_REV)
1497c478bd9Sstevel@tonic-gate 	D_MP | D_NEW | D_HOTPLUG	/* Driver compatibility flag */
1507c478bd9Sstevel@tonic-gate #else	/* !defined(CB_REV) */
1517c478bd9Sstevel@tonic-gate 	D_MP | D_NEW | D_HOTPLUG,	/* Driver compatibility flag */
1527c478bd9Sstevel@tonic-gate 	CB_REV,				/* cb_ops version number */
1537c478bd9Sstevel@tonic-gate 	nodev,				/* aread */
1547c478bd9Sstevel@tonic-gate 	nodev				/* awrite */
1557c478bd9Sstevel@tonic-gate #endif	/* !defined(CB_REV) */
1567c478bd9Sstevel@tonic-gate };
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate static struct dev_ops ses_dev_ops = {
1597c478bd9Sstevel@tonic-gate 	DEVO_REV,		/* devo_rev, */
1607c478bd9Sstevel@tonic-gate 	0,			/* refcnt  */
1617c478bd9Sstevel@tonic-gate 	ses_info,		/* info */
1627c478bd9Sstevel@tonic-gate 	nulldev,		/* identify */
1637c478bd9Sstevel@tonic-gate 	ses_probe,		/* probe */
1647c478bd9Sstevel@tonic-gate 	ses_attach,		/* attach */
1657c478bd9Sstevel@tonic-gate 	ses_detach,		/* detach */
1667c478bd9Sstevel@tonic-gate 	nodev,			/* reset */
1677c478bd9Sstevel@tonic-gate 	&ses_cb_ops,		/* driver operations */
1687c478bd9Sstevel@tonic-gate 	(struct bus_ops *)NULL,	/* bus operations */
16919397407SSherry Moore 	NULL,			/* power */
17019397407SSherry Moore 	ddi_quiesce_not_needed,		/* quiesce */
1717c478bd9Sstevel@tonic-gate };
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate static void *estate  = NULL;
1747c478bd9Sstevel@tonic-gate static const char *Snm = "ses";
1757c478bd9Sstevel@tonic-gate static const char *Str = "%s\n";
1767c478bd9Sstevel@tonic-gate static const char *efl = "copyin/copyout EFAULT @ line %d";
1777c478bd9Sstevel@tonic-gate static const char *fail_msg = "%stransport failed: reason '%s': %s";
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate /*
1827c478bd9Sstevel@tonic-gate  * autoconfiguration routines.
1837c478bd9Sstevel@tonic-gate  */
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate static struct modldrv modldrv = {
18619397407SSherry Moore 	&mod_driverops,
18719397407SSherry Moore 	"SCSI Enclosure Services",
18819397407SSherry Moore 	&ses_dev_ops
1897c478bd9Sstevel@tonic-gate };
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
1927c478bd9Sstevel@tonic-gate 	MODREV_1, &modldrv, NULL
1937c478bd9Sstevel@tonic-gate };
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate int
1977c478bd9Sstevel@tonic-gate _init(void)
1987c478bd9Sstevel@tonic-gate {
1997c478bd9Sstevel@tonic-gate 	int status;
2007c478bd9Sstevel@tonic-gate 	status = ddi_soft_state_init(&estate, sizeof (ses_softc_t), 0);
2017c478bd9Sstevel@tonic-gate 	if (status == 0) {
2027c478bd9Sstevel@tonic-gate 		if ((status = mod_install(&modlinkage)) != 0) {
2037c478bd9Sstevel@tonic-gate 			ddi_soft_state_fini(&estate);
2047c478bd9Sstevel@tonic-gate 		}
2057c478bd9Sstevel@tonic-gate 	}
2067c478bd9Sstevel@tonic-gate 	return (status);
2077c478bd9Sstevel@tonic-gate }
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate int
2107c478bd9Sstevel@tonic-gate _fini(void)
2117c478bd9Sstevel@tonic-gate {
2127c478bd9Sstevel@tonic-gate 	int status;
2137c478bd9Sstevel@tonic-gate 	if ((status = mod_remove(&modlinkage)) != 0) {
2147c478bd9Sstevel@tonic-gate 		return (status);
2157c478bd9Sstevel@tonic-gate 	}
2167c478bd9Sstevel@tonic-gate 	ddi_soft_state_fini(&estate);
2177c478bd9Sstevel@tonic-gate 	return (status);
2187c478bd9Sstevel@tonic-gate }
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate int
2217c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
2227c478bd9Sstevel@tonic-gate {
2237c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
2247c478bd9Sstevel@tonic-gate }
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate static int
2277c478bd9Sstevel@tonic-gate ses_probe(dev_info_t *dip)
2287c478bd9Sstevel@tonic-gate {
2297c478bd9Sstevel@tonic-gate 	int			err;
2307c478bd9Sstevel@tonic-gate 	struct scsi_device	*devp;
2317c478bd9Sstevel@tonic-gate 	enctyp			ep;
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate 	/*
2347c478bd9Sstevel@tonic-gate 	 * I finally figured out why we return success
2357c478bd9Sstevel@tonic-gate 	 * on every probe. The devices that we attach to
2367c478bd9Sstevel@tonic-gate 	 * don't all report as being the same "device type"
2377c478bd9Sstevel@tonic-gate 	 *
2387c478bd9Sstevel@tonic-gate 	 * 1) A5x00 -- report as Enclosure Services (0xD) SES
2397c478bd9Sstevel@tonic-gate 	 * 2) A1000 -- report as Direct Access (0x0) SES
2407c478bd9Sstevel@tonic-gate 	 *    uses the same target as raid controler.
2417c478bd9Sstevel@tonic-gate 	 * 3) D1000 -- report as processor (0x3) SAFTE
2427c478bd9Sstevel@tonic-gate 	 * 3) D240  -- report as processor (0x3) SAFTE
2437c478bd9Sstevel@tonic-gate 	 *
2447c478bd9Sstevel@tonic-gate 	 * We also reportedly attach to SEN devices which I
2457c478bd9Sstevel@tonic-gate 	 * believe reside in a Tobasco tray.  I have never
2467c478bd9Sstevel@tonic-gate 	 * been able to get one to attach.
2477c478bd9Sstevel@tonic-gate 	 *
2487c478bd9Sstevel@tonic-gate 	 */
2497c478bd9Sstevel@tonic-gate 	if (dip == NULL)
2507c478bd9Sstevel@tonic-gate 		return (DDI_PROBE_FAILURE);
2514c06356bSdh142964 	/* SES_LOG(NULL, SES_CE_DEBUG1, "ses_probe: OK"); */
2524c06356bSdh142964 	if (ddi_dev_is_sid(dip) == DDI_SUCCESS) {
2534c06356bSdh142964 		return (DDI_PROBE_DONTCARE);
2544c06356bSdh142964 	}
2554c06356bSdh142964 
2564c06356bSdh142964 	devp = ddi_get_driver_private(dip);
2574c06356bSdh142964 
2584c06356bSdh142964 	/* Legacy: prevent driver.conf specified ses nodes on atapi. */
2594c06356bSdh142964 	if (scsi_ifgetcap(&devp->sd_address, "interconnect-type", -1) ==
2604c06356bSdh142964 	    INTERCONNECT_ATAPI)
2614c06356bSdh142964 		return (DDI_PROBE_FAILURE);
2624c06356bSdh142964 
2637c478bd9Sstevel@tonic-gate 	/*
2647c478bd9Sstevel@tonic-gate 	 * XXX: Breakage from the x86 folks.
2657c478bd9Sstevel@tonic-gate 	 */
2667c478bd9Sstevel@tonic-gate 	if (strcmp(ddi_get_name(ddi_get_parent(dip)), "ata") == 0) {
2677c478bd9Sstevel@tonic-gate 		return (DDI_PROBE_FAILURE);
2687c478bd9Sstevel@tonic-gate 	}
2694c06356bSdh142964 
2707c478bd9Sstevel@tonic-gate 	switch (err = scsi_probe(devp, SLEEP_FUNC)) {
2717c478bd9Sstevel@tonic-gate 	case SCSIPROBE_EXISTS:
2727c478bd9Sstevel@tonic-gate 		if (is_enc_dev(NULL, devp->sd_inq, SUN_INQSIZE, &ep)) {
2737c478bd9Sstevel@tonic-gate 			break;
2747c478bd9Sstevel@tonic-gate 		}
2757c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
2767c478bd9Sstevel@tonic-gate 	case SCSIPROBE_NORESP:
2777c478bd9Sstevel@tonic-gate 		scsi_unprobe(devp);
2787c478bd9Sstevel@tonic-gate 		return (DDI_PROBE_FAILURE);
2797c478bd9Sstevel@tonic-gate 	default:
2807c478bd9Sstevel@tonic-gate 		SES_LOG(NULL, SES_CE_DEBUG9,
2817c478bd9Sstevel@tonic-gate 		    "ses_probe: probe error %d", err);
2827c478bd9Sstevel@tonic-gate 		scsi_unprobe(devp);
2837c478bd9Sstevel@tonic-gate 		return (DDI_PROBE_FAILURE);
2847c478bd9Sstevel@tonic-gate 	}
2857c478bd9Sstevel@tonic-gate 	scsi_unprobe(devp);
2867c478bd9Sstevel@tonic-gate 	return (DDI_PROBE_SUCCESS);
2877c478bd9Sstevel@tonic-gate }
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate static int
2907c478bd9Sstevel@tonic-gate ses_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2917c478bd9Sstevel@tonic-gate {
2927c478bd9Sstevel@tonic-gate 	int inst, err;
2937c478bd9Sstevel@tonic-gate 	ses_softc_t *ssc;
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate 	inst = ddi_get_instance(dip);
2967c478bd9Sstevel@tonic-gate 	switch (cmd) {
2977c478bd9Sstevel@tonic-gate 	case DDI_ATTACH:
2987c478bd9Sstevel@tonic-gate 		SES_LOG(NULL, SES_CE_DEBUG9, "ses_attach: DDI_ATTACH ses%d",
2997c478bd9Sstevel@tonic-gate 		    inst);
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate 		err = ses_doattach(dip);
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate 		if (err == DDI_FAILURE) {
3047c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
3057c478bd9Sstevel@tonic-gate 		}
3067c478bd9Sstevel@tonic-gate 		SES_LOG(NULL, SES_CE_DEBUG4,
3077c478bd9Sstevel@tonic-gate 		    "ses_attach: DDI_ATTACH OK ses%d", inst);
3087c478bd9Sstevel@tonic-gate 		break;
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate 	case DDI_RESUME:
3117c478bd9Sstevel@tonic-gate 		if ((ssc = ddi_get_soft_state(estate, inst)) == NULL) {
3127c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
3137c478bd9Sstevel@tonic-gate 		}
3147c478bd9Sstevel@tonic-gate 		SES_LOG(ssc, SES_CE_DEBUG1, "ses_attach: DDI_ATTACH ses%d",
3157c478bd9Sstevel@tonic-gate 		    inst);
3167c478bd9Sstevel@tonic-gate 		ssc->ses_suspended = 0;
3177c478bd9Sstevel@tonic-gate 		break;
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate 	default:
3207c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
3217c478bd9Sstevel@tonic-gate 	}
3227c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
3237c478bd9Sstevel@tonic-gate }
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate static int
3267c478bd9Sstevel@tonic-gate is_enc_dev(ses_softc_t *ssc, struct scsi_inquiry *inqp, int iqlen, enctyp *ep)
3277c478bd9Sstevel@tonic-gate {
3287c478bd9Sstevel@tonic-gate 	uchar_t dt = (inqp->inq_dtype & DTYPE_MASK);
3297c478bd9Sstevel@tonic-gate 	uchar_t *iqd = (uchar_t *)inqp;
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate 	if (dt == DTYPE_ESI) {
3327c478bd9Sstevel@tonic-gate 		if (strncmp(inqp->inq_vid, SEN_ID, SEN_ID_LEN) == 0) {
3337c478bd9Sstevel@tonic-gate 			SES_LOG(ssc, SES_CE_DEBUG3, "SEN device found");
3347c478bd9Sstevel@tonic-gate 			*ep = SEN_TYPE;
33524f1a99aSjmcp 		} else if (inqp->inq_rdf == RDF_SCSI2) {
33624f1a99aSjmcp 			/*
33724f1a99aSjmcp 			 * Per SPC4 #6.4.2 Standard Inquiry Data, response
33824f1a99aSjmcp 			 * data format (RDF) values of 0 and 1 are Obsolete,
33924f1a99aSjmcp 			 * whereas values greater than 2 are Reserved
34024f1a99aSjmcp 			 */
3417c478bd9Sstevel@tonic-gate 			SES_LOG(ssc, SES_CE_DEBUG3, "SES device found");
3427c478bd9Sstevel@tonic-gate 			*ep = SES_TYPE;
3437c478bd9Sstevel@tonic-gate 		} else {
3447c478bd9Sstevel@tonic-gate 			SES_LOG(ssc, SES_CE_DEBUG3, "Pre-SCSI3 SES device");
3457c478bd9Sstevel@tonic-gate 			*ep = SES_TYPE;
3467c478bd9Sstevel@tonic-gate 		}
3477c478bd9Sstevel@tonic-gate 		return (1);
3487c478bd9Sstevel@tonic-gate 	}
3497c478bd9Sstevel@tonic-gate 	if ((iqd[6] & 0x40) && inqp->inq_rdf >= RDF_SCSI2) {
3507c478bd9Sstevel@tonic-gate 		/*
3517c478bd9Sstevel@tonic-gate 		 * PassThrough Device.
3527c478bd9Sstevel@tonic-gate 		 */
3537c478bd9Sstevel@tonic-gate 		*ep = SES_TYPE;
3547c478bd9Sstevel@tonic-gate 		SES_LOG(ssc, SES_CE_DEBUG3, "Passthru SES device");
3557c478bd9Sstevel@tonic-gate 		return (1);
3567c478bd9Sstevel@tonic-gate 	}
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate 	if (iqlen < 47) {
3597c478bd9Sstevel@tonic-gate 		SES_LOG(ssc, CE_NOTE,
3607c478bd9Sstevel@tonic-gate 		    "INQUIRY data too short to determine SAF-TE");
3617c478bd9Sstevel@tonic-gate 		return (0);
3627c478bd9Sstevel@tonic-gate 	}
3637c478bd9Sstevel@tonic-gate 	if (strncmp((char *)&iqd[44], "SAF-TE", 4) == 0) {
3647c478bd9Sstevel@tonic-gate 		*ep = SAFT_TYPE;
3657c478bd9Sstevel@tonic-gate 		SES_LOG(ssc, SES_CE_DEBUG3, "SAF-TE device found");
3667c478bd9Sstevel@tonic-gate 		return (1);
3677c478bd9Sstevel@tonic-gate 	}
3687c478bd9Sstevel@tonic-gate 	return (0);
3697c478bd9Sstevel@tonic-gate }
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate /*
3737c478bd9Sstevel@tonic-gate  * Attach ses device.
3747c478bd9Sstevel@tonic-gate  *
3757c478bd9Sstevel@tonic-gate  * XXX:  Power management is NOT supported.  A token framework
3767c478bd9Sstevel@tonic-gate  *       is provided that will need to be extended assuming we have
3777c478bd9Sstevel@tonic-gate  *       ses devices we can power down.  Currently, we don't have any.
3787c478bd9Sstevel@tonic-gate  */
3797c478bd9Sstevel@tonic-gate static int
3807c478bd9Sstevel@tonic-gate ses_doattach(dev_info_t *dip)
3817c478bd9Sstevel@tonic-gate {
3827c478bd9Sstevel@tonic-gate 	int inst, err;
3837c478bd9Sstevel@tonic-gate 	Scsidevp devp;
3847c478bd9Sstevel@tonic-gate 	ses_softc_t *ssc;
3857c478bd9Sstevel@tonic-gate 	enctyp etyp;
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate 	inst = ddi_get_instance(dip);
3887c478bd9Sstevel@tonic-gate 	/*
3897c478bd9Sstevel@tonic-gate 	 * Workaround for bug #4154979- for some reason we can
3907c478bd9Sstevel@tonic-gate 	 * be called with identical instance numbers but for
3917c478bd9Sstevel@tonic-gate 	 * different dev_info_t-s- all but one are bogus.
3927c478bd9Sstevel@tonic-gate 	 *
3937c478bd9Sstevel@tonic-gate 	 * Bad Dog! No Biscuit!
3947c478bd9Sstevel@tonic-gate 	 *
3957c478bd9Sstevel@tonic-gate 	 * A quick workaround might be to call ddi_soft_state_zalloc
3967c478bd9Sstevel@tonic-gate 	 * unconditionally, as the implementation fails these calls
3977c478bd9Sstevel@tonic-gate 	 * if there's an item already allocated. A more reasonable
3987c478bd9Sstevel@tonic-gate 	 * and longer term change is to move the allocation past
3997c478bd9Sstevel@tonic-gate 	 * the probe for the device's existence as most of these
4007c478bd9Sstevel@tonic-gate 	 * 'bogus' calls are for nonexistent devices.
4017c478bd9Sstevel@tonic-gate 	 */
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate 	devp  = ddi_get_driver_private(dip);
4047c478bd9Sstevel@tonic-gate 	devp->sd_dev = dip;
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate 	/*
4077c478bd9Sstevel@tonic-gate 	 * Determine whether the { i, t, l } we're called
4087c478bd9Sstevel@tonic-gate 	 * to start is an enclosure services device.
4097c478bd9Sstevel@tonic-gate 	 */
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate 	/*
4127c478bd9Sstevel@tonic-gate 	 * Call the scsi_probe routine to see whether
4137c478bd9Sstevel@tonic-gate 	 * we actually have an Enclosure Services device at
4147c478bd9Sstevel@tonic-gate 	 * this address.
4157c478bd9Sstevel@tonic-gate 	 */
4167c478bd9Sstevel@tonic-gate 	err = scsi_probe(devp, SLEEP_FUNC);
4177c478bd9Sstevel@tonic-gate 	if (err != SCSIPROBE_EXISTS) {
4187c478bd9Sstevel@tonic-gate 		SES_LOG(NULL, SES_CE_DEBUG9,
4197c478bd9Sstevel@tonic-gate 		    "ses_doattach: probe error %d", err);
4207c478bd9Sstevel@tonic-gate 		scsi_unprobe(devp);
4217c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
4227c478bd9Sstevel@tonic-gate 	}
4237c478bd9Sstevel@tonic-gate 	/* Call is_enc_dev() to get the etyp */
4247c478bd9Sstevel@tonic-gate 	if (!(is_enc_dev(NULL, devp->sd_inq, SUN_INQSIZE, &etyp))) {
4257c478bd9Sstevel@tonic-gate 		SES_LOG(NULL, CE_WARN,
4267c478bd9Sstevel@tonic-gate 		    "ses_doattach: ses%d: is_enc_dev failure", inst);
4277c478bd9Sstevel@tonic-gate 		scsi_unprobe(devp);
4287c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
4297c478bd9Sstevel@tonic-gate 	}
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate 	if (ddi_soft_state_zalloc(estate, inst) != DDI_SUCCESS) {
4327c478bd9Sstevel@tonic-gate 		scsi_unprobe(devp);
4337c478bd9Sstevel@tonic-gate 		SES_LOG(NULL, CE_NOTE, "ses%d: softalloc fails", inst);
4347c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
4357c478bd9Sstevel@tonic-gate 	}
4367c478bd9Sstevel@tonic-gate 	ssc = ddi_get_soft_state(estate, inst);
4377c478bd9Sstevel@tonic-gate 	if (ssc == NULL) {
4387c478bd9Sstevel@tonic-gate 		scsi_unprobe(devp);
4397c478bd9Sstevel@tonic-gate 		SES_LOG(NULL, CE_NOTE, "ses%d: get_soft_state fails", inst);
4407c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
4417c478bd9Sstevel@tonic-gate 	}
4427c478bd9Sstevel@tonic-gate 	devp->sd_private = (opaque_t)ssc;
4437c478bd9Sstevel@tonic-gate 	ssc->ses_devp = devp;
4447c478bd9Sstevel@tonic-gate 	err = ddi_create_minor_node(dip, "0", S_IFCHR, inst,
4457c478bd9Sstevel@tonic-gate 	    DDI_NT_SCSI_ENCLOSURE, NULL);
4467c478bd9Sstevel@tonic-gate 	if (err == DDI_FAILURE) {
4477c478bd9Sstevel@tonic-gate 		ddi_remove_minor_node(dip, NULL);
4487c478bd9Sstevel@tonic-gate 		SES_LOG(ssc, CE_NOTE, "minor node creation failed");
4497c478bd9Sstevel@tonic-gate 		ddi_soft_state_free(estate, inst);
4507c478bd9Sstevel@tonic-gate 		scsi_unprobe(devp);
4517c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
4527c478bd9Sstevel@tonic-gate 	}
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate 	ssc->ses_type = etyp;
4557c478bd9Sstevel@tonic-gate 	ssc->ses_vec = vecs[etyp];
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate 	/* Call SoftC Init Routine A bit later... */
4587c478bd9Sstevel@tonic-gate 
4597c478bd9Sstevel@tonic-gate 	ssc->ses_rqbp = scsi_alloc_consistent_buf(SES_ROUTE(ssc),
4600a2f1c3aSNikko He 	    NULL, MAX_SENSE_LENGTH, B_READ, SLEEP_FUNC, NULL);
4617c478bd9Sstevel@tonic-gate 	if (ssc->ses_rqbp != NULL) {
4627c478bd9Sstevel@tonic-gate 		ssc->ses_rqpkt = scsi_init_pkt(SES_ROUTE(ssc), NULL,
4637c478bd9Sstevel@tonic-gate 		    ssc->ses_rqbp, CDB_GROUP0, 1, 0, PKT_CONSISTENT,
4647c478bd9Sstevel@tonic-gate 		    SLEEP_FUNC, NULL);
4657c478bd9Sstevel@tonic-gate 	}
4667c478bd9Sstevel@tonic-gate 	if (ssc->ses_rqbp == NULL || ssc->ses_rqpkt == NULL) {
4677c478bd9Sstevel@tonic-gate 		ddi_remove_minor_node(dip, NULL);
4687c478bd9Sstevel@tonic-gate 		SES_LOG(ssc, CE_NOTE, "scsi_init_pkt of rqbuf failed");
4697c478bd9Sstevel@tonic-gate 		if (ssc->ses_rqbp != NULL) {
4707c478bd9Sstevel@tonic-gate 			scsi_free_consistent_buf(ssc->ses_rqbp);
4717c478bd9Sstevel@tonic-gate 			ssc->ses_rqbp = NULL;
4727c478bd9Sstevel@tonic-gate 		}
4737c478bd9Sstevel@tonic-gate 		ddi_soft_state_free(estate, inst);
4747c478bd9Sstevel@tonic-gate 		scsi_unprobe(devp);
4757c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
4767c478bd9Sstevel@tonic-gate 	}
4777c478bd9Sstevel@tonic-gate 	ssc->ses_rqpkt->pkt_private = (opaque_t)ssc;
4787c478bd9Sstevel@tonic-gate 	ssc->ses_rqpkt->pkt_address = *(SES_ROUTE(ssc));
4797c478bd9Sstevel@tonic-gate 	ssc->ses_rqpkt->pkt_comp = ses_callback;
4807c478bd9Sstevel@tonic-gate 	ssc->ses_rqpkt->pkt_time = ses_io_time;
4817c478bd9Sstevel@tonic-gate 	ssc->ses_rqpkt->pkt_flags = FLAG_NOPARITY|FLAG_NODISCON|FLAG_SENSING;
4827c478bd9Sstevel@tonic-gate 	ssc->ses_rqpkt->pkt_cdbp[0] = SCMD_REQUEST_SENSE;
4837c478bd9Sstevel@tonic-gate 	ssc->ses_rqpkt->pkt_cdbp[1] = 0;
4847c478bd9Sstevel@tonic-gate 	ssc->ses_rqpkt->pkt_cdbp[2] = 0;
4857c478bd9Sstevel@tonic-gate 	ssc->ses_rqpkt->pkt_cdbp[3] = 0;
4860a2f1c3aSNikko He 	ssc->ses_rqpkt->pkt_cdbp[4] = MAX_SENSE_LENGTH;
4877c478bd9Sstevel@tonic-gate 	ssc->ses_rqpkt->pkt_cdbp[5] = 0;
4887c478bd9Sstevel@tonic-gate 
4897c478bd9Sstevel@tonic-gate 	switch (scsi_ifgetcap(SES_ROUTE(ssc), "auto-rqsense", 1)) {
4907c478bd9Sstevel@tonic-gate 	case 1:
4917c478bd9Sstevel@tonic-gate 		/* if already set, don't reset it */
4927c478bd9Sstevel@tonic-gate 		ssc->ses_arq = 1;
4937c478bd9Sstevel@tonic-gate 		break;
4947c478bd9Sstevel@tonic-gate 	case 0:
4957c478bd9Sstevel@tonic-gate 		/* try and set it */
4967c478bd9Sstevel@tonic-gate 		ssc->ses_arq = ((scsi_ifsetcap(SES_ROUTE(ssc),
4977c478bd9Sstevel@tonic-gate 		    "auto-rqsense", 1, 1) == 1) ? 1 : 0);
4987c478bd9Sstevel@tonic-gate 		break;
4997c478bd9Sstevel@tonic-gate 	default:
5007c478bd9Sstevel@tonic-gate 		/* probably undefined, so zero it out */
5017c478bd9Sstevel@tonic-gate 		ssc->ses_arq = 0;
5027c478bd9Sstevel@tonic-gate 		break;
5037c478bd9Sstevel@tonic-gate 	}
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate 	ssc->ses_sbufp = getrbuf(KM_SLEEP);
5067c478bd9Sstevel@tonic-gate 	cv_init(&ssc->ses_sbufcv, NULL, CV_DRIVER, NULL);
5077c478bd9Sstevel@tonic-gate 
5087c478bd9Sstevel@tonic-gate 	/*
5097c478bd9Sstevel@tonic-gate 	 * If the HBA supports wide, tell it to use wide.
5107c478bd9Sstevel@tonic-gate 	 */
5117c478bd9Sstevel@tonic-gate 	if (scsi_ifgetcap(SES_ROUTE(ssc), "wide-xfer", 1) != -1) {
5127c478bd9Sstevel@tonic-gate 		int wd = ((devp->sd_inq->inq_rdf == RDF_SCSI2) &&
5137c478bd9Sstevel@tonic-gate 		    (devp->sd_inq->inq_wbus16 || devp->sd_inq->inq_wbus32))
5147c478bd9Sstevel@tonic-gate 		    ? 1 : 0;
5157c478bd9Sstevel@tonic-gate 		(void) scsi_ifsetcap(SES_ROUTE(ssc), "wide-xfer", wd, 1);
5167c478bd9Sstevel@tonic-gate 	}
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate 	/*
5197c478bd9Sstevel@tonic-gate 	 * Now do ssc init of enclosure specifics.
5207c478bd9Sstevel@tonic-gate 	 * At the same time, check to make sure getrbuf
5217c478bd9Sstevel@tonic-gate 	 * actually succeeded.
5227c478bd9Sstevel@tonic-gate 	 */
52315e38525Srralphs 	if ((*ssc->ses_vec.softc_init)(ssc, 1)) {
52415e38525Srralphs 		SES_LOG(ssc, SES_CE_DEBUG3, "failed softc init");
52515e38525Srralphs 		(void) (*ssc->ses_vec.softc_init)(ssc, 0);
5267c478bd9Sstevel@tonic-gate 		ddi_remove_minor_node(dip, NULL);
5277c478bd9Sstevel@tonic-gate 		scsi_destroy_pkt(ssc->ses_rqpkt);
5287c478bd9Sstevel@tonic-gate 		scsi_free_consistent_buf(ssc->ses_rqbp);
5297c478bd9Sstevel@tonic-gate 		if (ssc->ses_sbufp) {
5307c478bd9Sstevel@tonic-gate 			freerbuf(ssc->ses_sbufp);
5317c478bd9Sstevel@tonic-gate 		}
5327c478bd9Sstevel@tonic-gate 		cv_destroy(&ssc->ses_sbufcv);
5337c478bd9Sstevel@tonic-gate 		ddi_soft_state_free(estate, inst);
5347c478bd9Sstevel@tonic-gate 		scsi_unprobe(devp);
5357c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
5367c478bd9Sstevel@tonic-gate 	}
5377c478bd9Sstevel@tonic-gate 
5387c478bd9Sstevel@tonic-gate 	/*
5397c478bd9Sstevel@tonic-gate 	 * create this property so that PM code knows we want
5407c478bd9Sstevel@tonic-gate 	 * to be suspended at PM time
5417c478bd9Sstevel@tonic-gate 	 */
5427c478bd9Sstevel@tonic-gate 	(void) ddi_prop_update_string(DDI_DEV_T_NONE, dip,
5437c478bd9Sstevel@tonic-gate 	    PM_HARDWARE_STATE_PROP, PM_NEEDS_SUSPEND_RESUME);
5447c478bd9Sstevel@tonic-gate 
5457c478bd9Sstevel@tonic-gate 	/* announce the existence of this device */
5467c478bd9Sstevel@tonic-gate 	ddi_report_dev(dip);
5477c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
5487c478bd9Sstevel@tonic-gate }
5497c478bd9Sstevel@tonic-gate 
5507c478bd9Sstevel@tonic-gate 
5517c478bd9Sstevel@tonic-gate /*
5527c478bd9Sstevel@tonic-gate  * Detach ses device.
5537c478bd9Sstevel@tonic-gate  *
5547c478bd9Sstevel@tonic-gate  * XXX:  Power management is NOT supported.  A token framework
5557c478bd9Sstevel@tonic-gate  *       is provided that will need to be extended assuming we have
5567c478bd9Sstevel@tonic-gate  *       ses devices we can power down.  Currently, we don't have any.
5577c478bd9Sstevel@tonic-gate  */
5587c478bd9Sstevel@tonic-gate static int
5597c478bd9Sstevel@tonic-gate ses_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
5607c478bd9Sstevel@tonic-gate {
5617c478bd9Sstevel@tonic-gate 	ses_softc_t *ssc;
5627c478bd9Sstevel@tonic-gate 	int inst;
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate 	switch (cmd) {
5657c478bd9Sstevel@tonic-gate 	case DDI_DETACH:
5667c478bd9Sstevel@tonic-gate 		inst = ddi_get_instance(dip);
5677c478bd9Sstevel@tonic-gate 		ssc = ddi_get_soft_state(estate, inst);
5687c478bd9Sstevel@tonic-gate 		if (ssc == NULL) {
5697c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE,
5707c478bd9Sstevel@tonic-gate 			    "ses%d: DDI_DETACH, no softstate found", inst);
5717c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
5727c478bd9Sstevel@tonic-gate 		}
5737c478bd9Sstevel@tonic-gate 		if (ISOPEN(ssc)) {
5747c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
5757c478bd9Sstevel@tonic-gate 		}
5767c478bd9Sstevel@tonic-gate 
5777c478bd9Sstevel@tonic-gate #if		!defined(lint)
5787c478bd9Sstevel@tonic-gate 		/* LINTED */
5797c478bd9Sstevel@tonic-gate 		_NOTE(COMPETING_THREADS_NOW);
5807c478bd9Sstevel@tonic-gate #endif		/* !defined(lint) */
5817c478bd9Sstevel@tonic-gate 
5827c478bd9Sstevel@tonic-gate 		if (ssc->ses_vec.softc_init)
5837c478bd9Sstevel@tonic-gate 			(void) (*ssc->ses_vec.softc_init)(ssc, 0);
5847c478bd9Sstevel@tonic-gate 
5857c478bd9Sstevel@tonic-gate #if		!defined(lint)
5867c478bd9Sstevel@tonic-gate 		_NOTE(NO_COMPETING_THREADS_NOW);
5877c478bd9Sstevel@tonic-gate #endif 		/* !defined(lint) */
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate 		(void) scsi_ifsetcap(SES_ROUTE(ssc), "auto-rqsense", 1, 0);
5907c478bd9Sstevel@tonic-gate 		scsi_destroy_pkt(ssc->ses_rqpkt);
5917c478bd9Sstevel@tonic-gate 		scsi_free_consistent_buf(ssc->ses_rqbp);
5927c478bd9Sstevel@tonic-gate 		freerbuf(ssc->ses_sbufp);
5937c478bd9Sstevel@tonic-gate 		cv_destroy(&ssc->ses_sbufcv);
5947c478bd9Sstevel@tonic-gate 		ddi_soft_state_free(estate, inst);
5957c478bd9Sstevel@tonic-gate 		ddi_prop_remove_all(dip);
5967c478bd9Sstevel@tonic-gate 		ddi_remove_minor_node(dip, NULL);
5977c478bd9Sstevel@tonic-gate 		scsi_unprobe(ddi_get_driver_private(dip));
5987c478bd9Sstevel@tonic-gate 		break;
5997c478bd9Sstevel@tonic-gate 
6007c478bd9Sstevel@tonic-gate 	case DDI_SUSPEND:
6017c478bd9Sstevel@tonic-gate 		inst = ddi_get_instance(dip);
6027c478bd9Sstevel@tonic-gate 		if ((ssc = ddi_get_soft_state(estate, inst)) == NULL) {
6037c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE,
6047c478bd9Sstevel@tonic-gate 			    "ses%d: DDI_SUSPEND, no softstate found", inst);
6057c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
6067c478bd9Sstevel@tonic-gate 		}
6077c478bd9Sstevel@tonic-gate 
6087c478bd9Sstevel@tonic-gate 		/*
6097c478bd9Sstevel@tonic-gate 		 * If driver idle, accept suspend request.
6107c478bd9Sstevel@tonic-gate 		 * If it's busy, reject it.  This keeps things simple!
6117c478bd9Sstevel@tonic-gate 		 */
6127c478bd9Sstevel@tonic-gate 		mutex_enter(SES_MUTEX);
6137c478bd9Sstevel@tonic-gate 		if (ssc->ses_sbufbsy) {
6147c478bd9Sstevel@tonic-gate 			mutex_exit(SES_MUTEX);
6157c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
6167c478bd9Sstevel@tonic-gate 		}
6177c478bd9Sstevel@tonic-gate 		ssc->ses_suspended = 1;
6187c478bd9Sstevel@tonic-gate 		mutex_exit(SES_MUTEX);
6197c478bd9Sstevel@tonic-gate 		break;
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate 	default:
6227c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
6237c478bd9Sstevel@tonic-gate 	}
6247c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
6257c478bd9Sstevel@tonic-gate }
6267c478bd9Sstevel@tonic-gate 
6277c478bd9Sstevel@tonic-gate /* ARGSUSED */
6287c478bd9Sstevel@tonic-gate static int
6297c478bd9Sstevel@tonic-gate ses_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
6307c478bd9Sstevel@tonic-gate {
6317c478bd9Sstevel@tonic-gate 	dev_t dev;
6327c478bd9Sstevel@tonic-gate 	ses_softc_t *ssc;
6337c478bd9Sstevel@tonic-gate 	int inst, error;
6347c478bd9Sstevel@tonic-gate 
6357c478bd9Sstevel@tonic-gate 	switch (infocmd) {
6367c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
6377c478bd9Sstevel@tonic-gate 		dev = (dev_t)arg;
6387c478bd9Sstevel@tonic-gate 		inst = getminor(dev);
6397c478bd9Sstevel@tonic-gate 		if ((ssc = ddi_get_soft_state(estate, inst)) == NULL) {
6407c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
6417c478bd9Sstevel@tonic-gate 		}
6427c478bd9Sstevel@tonic-gate 		*result = (void *) ssc->ses_devp->sd_dev;
6437c478bd9Sstevel@tonic-gate 		error = DDI_SUCCESS;
6447c478bd9Sstevel@tonic-gate 		break;
6457c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
6467c478bd9Sstevel@tonic-gate 		dev = (dev_t)arg;
6477c478bd9Sstevel@tonic-gate 		inst = getminor(dev);
6487c478bd9Sstevel@tonic-gate 		*result = (void *)(uintptr_t)inst;
6497c478bd9Sstevel@tonic-gate 		error = DDI_SUCCESS;
6507c478bd9Sstevel@tonic-gate 		break;
6517c478bd9Sstevel@tonic-gate 	default:
6527c478bd9Sstevel@tonic-gate 		error = DDI_FAILURE;
6537c478bd9Sstevel@tonic-gate 	}
6547c478bd9Sstevel@tonic-gate 	return (error);
6557c478bd9Sstevel@tonic-gate }
6567c478bd9Sstevel@tonic-gate 
65719397407SSherry Moore 
6587c478bd9Sstevel@tonic-gate /*
6597c478bd9Sstevel@tonic-gate  * Unix Entry Points
6607c478bd9Sstevel@tonic-gate  */
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate /* ARGSUSED */
6637c478bd9Sstevel@tonic-gate static int
6647c478bd9Sstevel@tonic-gate ses_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p)
6657c478bd9Sstevel@tonic-gate {
6667c478bd9Sstevel@tonic-gate 	ses_softc_t *ssc;
6677c478bd9Sstevel@tonic-gate 
6687c478bd9Sstevel@tonic-gate 	if ((ssc = ddi_get_soft_state(estate, getminor(*dev_p))) == NULL) {
6697c478bd9Sstevel@tonic-gate 		return (ENXIO);
6707c478bd9Sstevel@tonic-gate 	}
6717c478bd9Sstevel@tonic-gate 
6727c478bd9Sstevel@tonic-gate 	/*
6737c478bd9Sstevel@tonic-gate 	 * If the device is powered down, request it's activation.
6747c478bd9Sstevel@tonic-gate 	 * If it can't be activated, fail open.
6757c478bd9Sstevel@tonic-gate 	 */
6767c478bd9Sstevel@tonic-gate 	if (ssc->ses_suspended &&
6777c478bd9Sstevel@tonic-gate 	    ddi_dev_is_needed(SES_DEVINFO(ssc), 0, 1) != DDI_SUCCESS) {
6787c478bd9Sstevel@tonic-gate 		return (EIO);
6797c478bd9Sstevel@tonic-gate 	}
6807c478bd9Sstevel@tonic-gate 
6817c478bd9Sstevel@tonic-gate 	mutex_enter(SES_MUTEX);
6827c478bd9Sstevel@tonic-gate 	if (otyp == OTYP_LYR)
6837c478bd9Sstevel@tonic-gate 		ssc->ses_lyropen++;
6847c478bd9Sstevel@tonic-gate 	else
6857c478bd9Sstevel@tonic-gate 		ssc->ses_oflag = 1;
6867c478bd9Sstevel@tonic-gate 
6877c478bd9Sstevel@tonic-gate 	ssc->ses_present = (ssc->ses_present)? ssc->ses_present: SES_OPENING;
6887c478bd9Sstevel@tonic-gate 	mutex_exit(SES_MUTEX);
6897c478bd9Sstevel@tonic-gate 	return (EOK);
6907c478bd9Sstevel@tonic-gate }
6917c478bd9Sstevel@tonic-gate 
6927c478bd9Sstevel@tonic-gate /*ARGSUSED*/
6937c478bd9Sstevel@tonic-gate static int
6947c478bd9Sstevel@tonic-gate ses_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
6957c478bd9Sstevel@tonic-gate {
6967c478bd9Sstevel@tonic-gate 	ses_softc_t *ssc;
6977c478bd9Sstevel@tonic-gate 	if ((ssc = ddi_get_soft_state(estate, getminor(dev))) == NULL) {
6987c478bd9Sstevel@tonic-gate 		return (ENXIO);
6997c478bd9Sstevel@tonic-gate 	}
7007c478bd9Sstevel@tonic-gate 
7017c478bd9Sstevel@tonic-gate 	if (ssc->ses_suspended) {
7027c478bd9Sstevel@tonic-gate 		(void) ddi_dev_is_needed(SES_DEVINFO(ssc), 0, 1);
7037c478bd9Sstevel@tonic-gate 	}
7047c478bd9Sstevel@tonic-gate 
7057c478bd9Sstevel@tonic-gate 	mutex_enter(SES_MUTEX);
7067c478bd9Sstevel@tonic-gate 	if (otyp == OTYP_LYR)
7077c478bd9Sstevel@tonic-gate 		ssc->ses_lyropen -= (ssc->ses_lyropen)? 1: 0;
7087c478bd9Sstevel@tonic-gate 	else
7097c478bd9Sstevel@tonic-gate 		ssc->ses_oflag = 0;
7107c478bd9Sstevel@tonic-gate 	mutex_exit(SES_MUTEX);
7117c478bd9Sstevel@tonic-gate 	return (0);
7127c478bd9Sstevel@tonic-gate }
7137c478bd9Sstevel@tonic-gate 
7147c478bd9Sstevel@tonic-gate 
7157c478bd9Sstevel@tonic-gate /*ARGSUSED3*/
7167c478bd9Sstevel@tonic-gate static int
7177c478bd9Sstevel@tonic-gate ses_ioctl(dev_t dev, int cmd, intptr_t arg, int flg, cred_t *cred_p, int *rvalp)
7187c478bd9Sstevel@tonic-gate {
7197c478bd9Sstevel@tonic-gate 	ses_softc_t *ssc;
7207c478bd9Sstevel@tonic-gate 	ses_object k, *up;
7217c478bd9Sstevel@tonic-gate 	ses_objarg x;
7227c478bd9Sstevel@tonic-gate 	uchar_t t;
7237c478bd9Sstevel@tonic-gate 	uchar_t i;
7247c478bd9Sstevel@tonic-gate 	int rv = 0;
7257c478bd9Sstevel@tonic-gate 
7267c478bd9Sstevel@tonic-gate 	if ((ssc = ddi_get_soft_state(estate, getminor(dev))) == NULL ||
7277c478bd9Sstevel@tonic-gate 	    ssc->ses_present == SES_CLOSED) {
7287c478bd9Sstevel@tonic-gate 		return (ENXIO);
7297c478bd9Sstevel@tonic-gate 	}
7307c478bd9Sstevel@tonic-gate 
7317c478bd9Sstevel@tonic-gate 
7327c478bd9Sstevel@tonic-gate 	switch (cmd) {
7337c478bd9Sstevel@tonic-gate 	case SESIOC_GETNOBJ:
7347c478bd9Sstevel@tonic-gate 		if (ddi_copyout(&ssc->ses_nobjects, (void *)arg,
7357c478bd9Sstevel@tonic-gate 		    sizeof (int), flg)) {
7367c478bd9Sstevel@tonic-gate 			rv = EFAULT;
7377c478bd9Sstevel@tonic-gate 			break;
7387c478bd9Sstevel@tonic-gate 		}
7397c478bd9Sstevel@tonic-gate 		break;
7407c478bd9Sstevel@tonic-gate 
7417c478bd9Sstevel@tonic-gate 	case SESIOC_GETOBJMAP:
7427c478bd9Sstevel@tonic-gate 		up = (ses_object *) arg;
7437c478bd9Sstevel@tonic-gate 		mutex_enter(SES_MUTEX);
7447c478bd9Sstevel@tonic-gate 		for (i = 0; i != ssc->ses_nobjects; i++) {
7457c478bd9Sstevel@tonic-gate 			k.obj_id = i;
7467c478bd9Sstevel@tonic-gate 			k.subencid = ssc->ses_objmap[i].subenclosure;
7477c478bd9Sstevel@tonic-gate 			k.elem_type = ssc->ses_objmap[i].enctype;
7487c478bd9Sstevel@tonic-gate 			if (ddi_copyout(&k, up, sizeof (k), flg)) {
7497c478bd9Sstevel@tonic-gate 				rv = EFAULT;
7507c478bd9Sstevel@tonic-gate 				break;
7517c478bd9Sstevel@tonic-gate 			}
7527c478bd9Sstevel@tonic-gate 			up++;
7537c478bd9Sstevel@tonic-gate 		}
7547c478bd9Sstevel@tonic-gate 		mutex_exit(SES_MUTEX);
7557c478bd9Sstevel@tonic-gate 		break;
7567c478bd9Sstevel@tonic-gate 
7577c478bd9Sstevel@tonic-gate 	case SESIOC_INIT:
7581cba8b6cSRandall Ralphs 		if (drv_priv(cred_p) != 0) {
7591cba8b6cSRandall Ralphs 			rv = EPERM;
7601cba8b6cSRandall Ralphs 			break;
7611cba8b6cSRandall Ralphs 		}
7627c478bd9Sstevel@tonic-gate 		rv = (*ssc->ses_vec.init_enc)(ssc);
7637c478bd9Sstevel@tonic-gate 		break;
7647c478bd9Sstevel@tonic-gate 
7657c478bd9Sstevel@tonic-gate 	case SESIOC_GETENCSTAT:
7667c478bd9Sstevel@tonic-gate 		if ((ssc->ses_encstat & ENCI_SVALID) == 0) {
7677c478bd9Sstevel@tonic-gate 			rv = (*ssc->ses_vec.get_encstat)(ssc, KM_SLEEP);
7687c478bd9Sstevel@tonic-gate 			if (rv) {
7697c478bd9Sstevel@tonic-gate 				break;
7707c478bd9Sstevel@tonic-gate 			}
7717c478bd9Sstevel@tonic-gate 		}
7727c478bd9Sstevel@tonic-gate 		t = ssc->ses_encstat & 0xf;
7737c478bd9Sstevel@tonic-gate 		if (ddi_copyout(&t, (void *)arg, sizeof (t), flg))
7747c478bd9Sstevel@tonic-gate 			rv = EFAULT;
7757c478bd9Sstevel@tonic-gate 		/*
7767c478bd9Sstevel@tonic-gate 		 * And always invalidate enclosure status on the way out.
7777c478bd9Sstevel@tonic-gate 		 */
7787c478bd9Sstevel@tonic-gate 		mutex_enter(SES_MUTEX);
7797c478bd9Sstevel@tonic-gate 		ssc->ses_encstat &= ~ENCI_SVALID;
7807c478bd9Sstevel@tonic-gate 		mutex_exit(SES_MUTEX);
7817c478bd9Sstevel@tonic-gate 		break;
7827c478bd9Sstevel@tonic-gate 
7837c478bd9Sstevel@tonic-gate 	case SESIOC_SETENCSTAT:
7841cba8b6cSRandall Ralphs 		if (drv_priv(cred_p) != 0) {
7851cba8b6cSRandall Ralphs 			rv = EPERM;
7861cba8b6cSRandall Ralphs 			break;
7871cba8b6cSRandall Ralphs 		}
7887c478bd9Sstevel@tonic-gate 		if (ddi_copyin((void *)arg, &t, sizeof (t), flg))
7897c478bd9Sstevel@tonic-gate 			rv = EFAULT;
7907c478bd9Sstevel@tonic-gate 		else
7917c478bd9Sstevel@tonic-gate 			rv = (*ssc->ses_vec.set_encstat)(ssc, t, KM_SLEEP);
7927c478bd9Sstevel@tonic-gate 		mutex_enter(SES_MUTEX);
7937c478bd9Sstevel@tonic-gate 		ssc->ses_encstat &= ~ENCI_SVALID;
7947c478bd9Sstevel@tonic-gate 		mutex_exit(SES_MUTEX);
7957c478bd9Sstevel@tonic-gate 		break;
7967c478bd9Sstevel@tonic-gate 
7977c478bd9Sstevel@tonic-gate 	case SESIOC_GETOBJSTAT:
7987c478bd9Sstevel@tonic-gate 		if (ddi_copyin((void *)arg, &x, sizeof (x), flg)) {
7997c478bd9Sstevel@tonic-gate 			rv = EFAULT;
8007c478bd9Sstevel@tonic-gate 			break;
8017c478bd9Sstevel@tonic-gate 		}
8027c478bd9Sstevel@tonic-gate 		if (x.obj_id >= ssc->ses_nobjects) {
8037c478bd9Sstevel@tonic-gate 			rv = EINVAL;
8047c478bd9Sstevel@tonic-gate 			break;
8057c478bd9Sstevel@tonic-gate 		}
8067c478bd9Sstevel@tonic-gate 		if ((rv = (*ssc->ses_vec.get_objstat)(ssc, &x, KM_SLEEP)) != 0)
8077c478bd9Sstevel@tonic-gate 			break;
8087c478bd9Sstevel@tonic-gate 		if (ddi_copyout(&x, (void *)arg, sizeof (x), flg))
8097c478bd9Sstevel@tonic-gate 			rv = EFAULT;
8107c478bd9Sstevel@tonic-gate 		else {
8117c478bd9Sstevel@tonic-gate 			/*
8127c478bd9Sstevel@tonic-gate 			 * Now that we no longer poll, svalid never stays true.
8137c478bd9Sstevel@tonic-gate 			 */
8147c478bd9Sstevel@tonic-gate 			mutex_enter(SES_MUTEX);
8157c478bd9Sstevel@tonic-gate 			ssc->ses_objmap[x.obj_id].svalid = 0;
8167c478bd9Sstevel@tonic-gate 			mutex_exit(SES_MUTEX);
8177c478bd9Sstevel@tonic-gate 		}
8187c478bd9Sstevel@tonic-gate 		break;
8197c478bd9Sstevel@tonic-gate 
8207c478bd9Sstevel@tonic-gate 	case SESIOC_SETOBJSTAT:
8211cba8b6cSRandall Ralphs 		if (drv_priv(cred_p) != 0) {
8221cba8b6cSRandall Ralphs 			rv = EPERM;
8231cba8b6cSRandall Ralphs 			break;
8241cba8b6cSRandall Ralphs 		}
8257c478bd9Sstevel@tonic-gate 		if (ddi_copyin((void *)arg, &x, sizeof (x), flg)) {
8267c478bd9Sstevel@tonic-gate 			rv = EFAULT;
8277c478bd9Sstevel@tonic-gate 			break;
8287c478bd9Sstevel@tonic-gate 		}
8297c478bd9Sstevel@tonic-gate 		if (x.obj_id >= ssc->ses_nobjects) {
8307c478bd9Sstevel@tonic-gate 			rv = EINVAL;
8317c478bd9Sstevel@tonic-gate 			break;
8327c478bd9Sstevel@tonic-gate 		}
8337c478bd9Sstevel@tonic-gate 		rv = (*ssc->ses_vec.set_objstat)(ssc, &x, KM_SLEEP);
8347c478bd9Sstevel@tonic-gate 		if (rv == 0) {
8357c478bd9Sstevel@tonic-gate 			mutex_enter(SES_MUTEX);
8367c478bd9Sstevel@tonic-gate 			ssc->ses_objmap[x.obj_id].svalid = 0;
8377c478bd9Sstevel@tonic-gate 			mutex_exit(SES_MUTEX);
8387c478bd9Sstevel@tonic-gate 		}
8397c478bd9Sstevel@tonic-gate 		break;
8407c478bd9Sstevel@tonic-gate 
8417c478bd9Sstevel@tonic-gate 	case USCSICMD:
8421cba8b6cSRandall Ralphs 		if (drv_priv(cred_p) != 0) {
8431cba8b6cSRandall Ralphs 			rv = EPERM;
8441cba8b6cSRandall Ralphs 			break;
8451cba8b6cSRandall Ralphs 		}
8466567eb0aSlh195018 		rv = ses_uscsi_cmd(ssc, (Uscmd *)arg, flg);
8477c478bd9Sstevel@tonic-gate 		break;
8487c478bd9Sstevel@tonic-gate 
8497c478bd9Sstevel@tonic-gate 	default:
8507c478bd9Sstevel@tonic-gate 		rv = ENOTTY;
8517c478bd9Sstevel@tonic-gate 		break;
8527c478bd9Sstevel@tonic-gate 	}
8537c478bd9Sstevel@tonic-gate 	return (rv);
8547c478bd9Sstevel@tonic-gate }
8557c478bd9Sstevel@tonic-gate 
8567c478bd9Sstevel@tonic-gate 
8577c478bd9Sstevel@tonic-gate /*
8587c478bd9Sstevel@tonic-gate  * Loop on running a kernel based command
8597c478bd9Sstevel@tonic-gate  *
8607c478bd9Sstevel@tonic-gate  * FIXME:  This routine is not really needed.
8617c478bd9Sstevel@tonic-gate  */
8627c478bd9Sstevel@tonic-gate int
8637c478bd9Sstevel@tonic-gate ses_runcmd(ses_softc_t *ssc, Uscmd *lp)
8647c478bd9Sstevel@tonic-gate {
8657c478bd9Sstevel@tonic-gate 	int e;
8667c478bd9Sstevel@tonic-gate 
8677c478bd9Sstevel@tonic-gate 	lp->uscsi_status = 0;
8686567eb0aSlh195018 	e = ses_uscsi_cmd(ssc, lp, FKIOCTL);
8697c478bd9Sstevel@tonic-gate 
8707c478bd9Sstevel@tonic-gate #ifdef	not
8717c478bd9Sstevel@tonic-gate 	/*
8727c478bd9Sstevel@tonic-gate 	 * Debug:  Nice cross-check code for verifying consistent status.
8737c478bd9Sstevel@tonic-gate 	 */
8747c478bd9Sstevel@tonic-gate 	if (lp->uscsi_status) {
8757c478bd9Sstevel@tonic-gate 		if (lp->uscsi_status == STATUS_CHECK) {
8767c478bd9Sstevel@tonic-gate 			SES_LOG(ssc, CE_NOTE, "runcmd<cdb[0]="
8777c478bd9Sstevel@tonic-gate 			    "0x%x->%s ASC/ASCQ=0x%x/0x%x>",
8787c478bd9Sstevel@tonic-gate 			    lp->uscsi_cdb[0],
8797c478bd9Sstevel@tonic-gate 			    scsi_sname(lp->uscsi_rqbuf[2] & 0xf),
8807c478bd9Sstevel@tonic-gate 			    lp->uscsi_rqbuf[12] & 0xff,
8817c478bd9Sstevel@tonic-gate 			    lp->uscsi_rqbuf[13] & 0xff);
8827c478bd9Sstevel@tonic-gate 		} else {
8837c478bd9Sstevel@tonic-gate 			SES_LOG(ssc, CE_NOTE, "runcmd<cdb[0]="
8847c478bd9Sstevel@tonic-gate 			    "0x%x -> Status 0x%x", lp->uscsi_cdb[0],
8857c478bd9Sstevel@tonic-gate 			    lp->uscsi_status);
8867c478bd9Sstevel@tonic-gate 		}
8877c478bd9Sstevel@tonic-gate 	}
8887c478bd9Sstevel@tonic-gate #endif	/* not */
8897c478bd9Sstevel@tonic-gate 	return (e);
8907c478bd9Sstevel@tonic-gate }
8917c478bd9Sstevel@tonic-gate 
8927c478bd9Sstevel@tonic-gate 
8937c478bd9Sstevel@tonic-gate /*
8947c478bd9Sstevel@tonic-gate  * Run a scsi command.
8957c478bd9Sstevel@tonic-gate  */
8967c478bd9Sstevel@tonic-gate int
8976567eb0aSlh195018 ses_uscsi_cmd(ses_softc_t *ssc, Uscmd *Uc, int Uf)
8987c478bd9Sstevel@tonic-gate {
8996567eb0aSlh195018 	Uscmd	*uscmd;
9007c478bd9Sstevel@tonic-gate 	struct buf	*bp;
9016567eb0aSlh195018 	enum uio_seg	uioseg;
9026567eb0aSlh195018 	int	err;
9037c478bd9Sstevel@tonic-gate 
9047c478bd9Sstevel@tonic-gate 	/*
9057c478bd9Sstevel@tonic-gate 	 * Grab local 'special' buffer
9067c478bd9Sstevel@tonic-gate 	 */
9077c478bd9Sstevel@tonic-gate 	mutex_enter(SES_MUTEX);
9087c478bd9Sstevel@tonic-gate 	while (ssc->ses_sbufbsy) {
9097c478bd9Sstevel@tonic-gate 		cv_wait(&ssc->ses_sbufcv, &ssc->ses_devp->sd_mutex);
9107c478bd9Sstevel@tonic-gate 	}
9117c478bd9Sstevel@tonic-gate 	ssc->ses_sbufbsy = 1;
9127c478bd9Sstevel@tonic-gate 	mutex_exit(SES_MUTEX);
9137c478bd9Sstevel@tonic-gate 
9147c478bd9Sstevel@tonic-gate 	/*
9157c478bd9Sstevel@tonic-gate 	 * If the device is powered down, request it's activation.
9167c478bd9Sstevel@tonic-gate 	 * This check must be done after setting ses_sbufbsy!
9177c478bd9Sstevel@tonic-gate 	 */
9187c478bd9Sstevel@tonic-gate 	if (ssc->ses_suspended &&
9197c478bd9Sstevel@tonic-gate 	    ddi_dev_is_needed(SES_DEVINFO(ssc), 0, 1) != DDI_SUCCESS) {
9207c478bd9Sstevel@tonic-gate 		mutex_enter(SES_MUTEX);
9217c478bd9Sstevel@tonic-gate 		ssc->ses_sbufbsy = 0;
9227c478bd9Sstevel@tonic-gate 		mutex_exit(SES_MUTEX);
9237c478bd9Sstevel@tonic-gate 		return (EIO);
9247c478bd9Sstevel@tonic-gate 	}
9257c478bd9Sstevel@tonic-gate 
9266567eb0aSlh195018 	err = scsi_uscsi_alloc_and_copyin((intptr_t)Uc, Uf,
9276567eb0aSlh195018 	    SES_ROUTE(ssc), &uscmd);
9286567eb0aSlh195018 	if (err != 0) {
9296567eb0aSlh195018 		SES_LOG(ssc, SES_CE_DEBUG1, "ses_uscsi_cmd: "
9306567eb0aSlh195018 		    "scsi_uscsi_alloc_and_copyin failed\n");
9317c478bd9Sstevel@tonic-gate 		mutex_enter(SES_MUTEX);
9327c478bd9Sstevel@tonic-gate 		ssc->ses_sbufbsy = 0;
9337c478bd9Sstevel@tonic-gate 		cv_signal(&ssc->ses_sbufcv);
9347c478bd9Sstevel@tonic-gate 		mutex_exit(SES_MUTEX);
9357c478bd9Sstevel@tonic-gate 		SES_LOG(ssc, SES_CE_DEBUG2, efl, __LINE__);
9366567eb0aSlh195018 		return (err);
9377c478bd9Sstevel@tonic-gate 	}
9387c478bd9Sstevel@tonic-gate 
9397c478bd9Sstevel@tonic-gate 	/*
9406567eb0aSlh195018 	 * Copy the uscsi command related infos to ssc for use in ses_start()
9416567eb0aSlh195018 	 * and ses_callback().
9427c478bd9Sstevel@tonic-gate 	 */
9436567eb0aSlh195018 	bcopy(uscmd, &ssc->ses_uscsicmd, sizeof (Uscmd));
9446567eb0aSlh195018 	if (uscmd->uscsi_cdb != NULL) {
9456567eb0aSlh195018 		bcopy(uscmd->uscsi_cdb, &ssc->ses_srqcdb,
9466567eb0aSlh195018 		    (size_t)(uscmd->uscsi_cdblen));
9476567eb0aSlh195018 	}
948275c9da8Seschrock 	ssc->ses_uscsicmd.uscsi_status = 0;
9497c478bd9Sstevel@tonic-gate 
9507c478bd9Sstevel@tonic-gate 	bp = ssc->ses_sbufp;
9517c478bd9Sstevel@tonic-gate 	bp->av_back = (struct buf *)NULL;
9527c478bd9Sstevel@tonic-gate 	bp->av_forw = (struct buf *)NULL;
9537c478bd9Sstevel@tonic-gate 	bp->b_back = (struct buf *)ssc;
9547c478bd9Sstevel@tonic-gate 	bp->b_edev = NODEV;
9557c478bd9Sstevel@tonic-gate 
9566567eb0aSlh195018 	if (uscmd->uscsi_cdb != NULL) {
9576567eb0aSlh195018 		if (uscmd->uscsi_cdblen == CDB_GROUP0) {
9587c478bd9Sstevel@tonic-gate 			SES_LOG(ssc, SES_CE_DEBUG7,
9597c478bd9Sstevel@tonic-gate 			    "scsi_cmd: %x %x %x %x %x %x",
9606567eb0aSlh195018 			    ((char *)uscmd->uscsi_cdb)[0],
9616567eb0aSlh195018 			    ((char *)uscmd->uscsi_cdb)[1],
9626567eb0aSlh195018 			    ((char *)uscmd->uscsi_cdb)[2],
9636567eb0aSlh195018 			    ((char *)uscmd->uscsi_cdb)[3],
9646567eb0aSlh195018 			    ((char *)uscmd->uscsi_cdb)[4],
9656567eb0aSlh195018 			    ((char *)uscmd->uscsi_cdb)[5]);
9667c478bd9Sstevel@tonic-gate 		} else {
9677c478bd9Sstevel@tonic-gate 			SES_LOG(ssc, SES_CE_DEBUG7,
9687c478bd9Sstevel@tonic-gate 			    "scsi cmd: %x %x %x %x %x %x %x %x %x %x",
9696567eb0aSlh195018 			    ((char *)uscmd->uscsi_cdb)[0],
9706567eb0aSlh195018 			    ((char *)uscmd->uscsi_cdb)[1],
9716567eb0aSlh195018 			    ((char *)uscmd->uscsi_cdb)[2],
9726567eb0aSlh195018 			    ((char *)uscmd->uscsi_cdb)[3],
9736567eb0aSlh195018 			    ((char *)uscmd->uscsi_cdb)[4],
9746567eb0aSlh195018 			    ((char *)uscmd->uscsi_cdb)[5],
9756567eb0aSlh195018 			    ((char *)uscmd->uscsi_cdb)[6],
9766567eb0aSlh195018 			    ((char *)uscmd->uscsi_cdb)[7],
9776567eb0aSlh195018 			    ((char *)uscmd->uscsi_cdb)[8],
9786567eb0aSlh195018 			    ((char *)uscmd->uscsi_cdb)[9]);
9797c478bd9Sstevel@tonic-gate 		}
9807c478bd9Sstevel@tonic-gate 	}
9817c478bd9Sstevel@tonic-gate 
9826567eb0aSlh195018 	uioseg = (Uf & FKIOCTL) ? UIO_SYSSPACE : UIO_USERSPACE;
9836567eb0aSlh195018 	err = scsi_uscsi_handle_cmd(NODEV, uioseg, uscmd,
9846567eb0aSlh195018 	    ses_start, bp, NULL);
9856567eb0aSlh195018 
9867c478bd9Sstevel@tonic-gate 	/*
9876567eb0aSlh195018 	 * ses_callback() may set values for ssc->ses_uscsicmd or
9886567eb0aSlh195018 	 * ssc->ses_srqsbuf, so copy them back to uscmd.
9897c478bd9Sstevel@tonic-gate 	 */
9906567eb0aSlh195018 	if (uscmd->uscsi_rqbuf != NULL) {
9916567eb0aSlh195018 		bcopy(&ssc->ses_srqsbuf, uscmd->uscsi_rqbuf,
9926567eb0aSlh195018 		    (size_t)(uscmd->uscsi_rqlen));
9936567eb0aSlh195018 		uscmd->uscsi_rqresid = ssc->ses_uscsicmd.uscsi_rqresid;
9946567eb0aSlh195018 	}
9956567eb0aSlh195018 	uscmd->uscsi_status = ssc->ses_uscsicmd.uscsi_status;
9966567eb0aSlh195018 
9976567eb0aSlh195018 	(void) scsi_uscsi_copyout_and_free((intptr_t)Uc, uscmd);
9987c478bd9Sstevel@tonic-gate 	mutex_enter(SES_MUTEX);
9997c478bd9Sstevel@tonic-gate 	ssc->ses_sbufbsy = 0;
10007c478bd9Sstevel@tonic-gate 	cv_signal(&ssc->ses_sbufcv);
10017c478bd9Sstevel@tonic-gate 	mutex_exit(SES_MUTEX);
10027c478bd9Sstevel@tonic-gate 
10037c478bd9Sstevel@tonic-gate 	return (err);
10047c478bd9Sstevel@tonic-gate }
10057c478bd9Sstevel@tonic-gate 
10067c478bd9Sstevel@tonic-gate 
10077c478bd9Sstevel@tonic-gate 
10087c478bd9Sstevel@tonic-gate /*
10097c478bd9Sstevel@tonic-gate  * Command start and done functions.
10107c478bd9Sstevel@tonic-gate  */
10117c478bd9Sstevel@tonic-gate static int
10127c478bd9Sstevel@tonic-gate ses_start(struct buf *bp)
10137c478bd9Sstevel@tonic-gate {
10147c478bd9Sstevel@tonic-gate 	ses_softc_t *ssc = (ses_softc_t *)bp->b_back;
10157c478bd9Sstevel@tonic-gate 
10167c478bd9Sstevel@tonic-gate 	SES_LOG(ssc, SES_CE_DEBUG9, "ses_start");
10177c478bd9Sstevel@tonic-gate 	if (!BP_PKT(bp)) {
10187c478bd9Sstevel@tonic-gate 		/*
10197c478bd9Sstevel@tonic-gate 		 * Allocate a packet.
10207c478bd9Sstevel@tonic-gate 		 */
10217c478bd9Sstevel@tonic-gate 		ses_get_pkt(bp, SLEEP_FUNC);
10227c478bd9Sstevel@tonic-gate 		if (!BP_PKT(bp)) {
10237c478bd9Sstevel@tonic-gate 			int err;
10247c478bd9Sstevel@tonic-gate 			bp->b_resid = bp->b_bcount;
10257c478bd9Sstevel@tonic-gate 			if (geterror(bp) == 0)
10267c478bd9Sstevel@tonic-gate 				SET_BP_ERROR(bp, EIO);
10277c478bd9Sstevel@tonic-gate 			err = geterror(bp);
10287c478bd9Sstevel@tonic-gate 			biodone(bp);
10297c478bd9Sstevel@tonic-gate 			return (err);
10307c478bd9Sstevel@tonic-gate 		}
10317c478bd9Sstevel@tonic-gate 	}
10327c478bd9Sstevel@tonic-gate 
10337c478bd9Sstevel@tonic-gate 	/*
10347c478bd9Sstevel@tonic-gate 	 * Initialize the transfer residue, error code, and retry count.
10357c478bd9Sstevel@tonic-gate 	 */
10367c478bd9Sstevel@tonic-gate 	bp->b_resid = 0;
10377c478bd9Sstevel@tonic-gate 	SET_BP_ERROR(bp, 0);
10387c478bd9Sstevel@tonic-gate 
10397c478bd9Sstevel@tonic-gate #if	!defined(lint)
10407c478bd9Sstevel@tonic-gate 	_NOTE(NO_COMPETING_THREADS_NOW);
10417c478bd9Sstevel@tonic-gate #endif 	/* !defined(lint) */
10427c478bd9Sstevel@tonic-gate 	ssc->ses_retries = ses_retry_count;
10437c478bd9Sstevel@tonic-gate 
10447c478bd9Sstevel@tonic-gate #if	!defined(lint)
10457c478bd9Sstevel@tonic-gate 	/* LINTED */
10467c478bd9Sstevel@tonic-gate 	_NOTE(COMPETING_THREADS_NOW);
10477c478bd9Sstevel@tonic-gate #endif	/* !defined(lint) */
10487c478bd9Sstevel@tonic-gate 
10497c478bd9Sstevel@tonic-gate 	SES_LOG(ssc, SES_CE_DEBUG9, "ses_start -> scsi_transport");
10507c478bd9Sstevel@tonic-gate 	switch (scsi_transport(BP_PKT(bp))) {
10517c478bd9Sstevel@tonic-gate 	case TRAN_ACCEPT:
10527c478bd9Sstevel@tonic-gate 		return (0);
10537c478bd9Sstevel@tonic-gate 		/* break; */
10547c478bd9Sstevel@tonic-gate 
10557c478bd9Sstevel@tonic-gate 	case TRAN_BUSY:
10567c478bd9Sstevel@tonic-gate 		SES_LOG(ssc, SES_CE_DEBUG2,
10577c478bd9Sstevel@tonic-gate 		    "ses_start: TRANSPORT BUSY");
10587c478bd9Sstevel@tonic-gate 		SES_ENABLE_RESTART(SES_RESTART_TIME, BP_PKT(bp));
10597c478bd9Sstevel@tonic-gate 		return (0);
10607c478bd9Sstevel@tonic-gate 		/* break; */
10617c478bd9Sstevel@tonic-gate 
10627c478bd9Sstevel@tonic-gate 	default:
10637c478bd9Sstevel@tonic-gate 		SES_LOG(ssc, SES_CE_DEBUG2, "TRANSPORT ERROR\n");
10647c478bd9Sstevel@tonic-gate 		SET_BP_ERROR(bp, EIO);
10657c478bd9Sstevel@tonic-gate 		scsi_destroy_pkt(BP_PKT(bp));
10667c478bd9Sstevel@tonic-gate 		SET_BP_PKT(bp, NULL);
10677c478bd9Sstevel@tonic-gate 		biodone(bp);
10687c478bd9Sstevel@tonic-gate 		return (EIO);
10697c478bd9Sstevel@tonic-gate 		/* break; */
10707c478bd9Sstevel@tonic-gate 	}
10717c478bd9Sstevel@tonic-gate }
10727c478bd9Sstevel@tonic-gate 
10737c478bd9Sstevel@tonic-gate 
10747c478bd9Sstevel@tonic-gate static void
10757c478bd9Sstevel@tonic-gate ses_get_pkt(struct buf *bp, int (*func)())
10767c478bd9Sstevel@tonic-gate {
10777c478bd9Sstevel@tonic-gate 	ses_softc_t *ssc = (ses_softc_t *)bp->b_back;
10787c478bd9Sstevel@tonic-gate 	Uscmd *scmd = &ssc->ses_uscsicmd;
10797c478bd9Sstevel@tonic-gate 	struct scsi_pkt *pkt;
10800a2f1c3aSNikko He 	int stat_size = 1;
10810a2f1c3aSNikko He 	int flags = 0;
10827c478bd9Sstevel@tonic-gate 
10837c478bd9Sstevel@tonic-gate 	if ((scmd->uscsi_flags & USCSI_RQENABLE) && ssc->ses_arq) {
10840a2f1c3aSNikko He 		if (scmd->uscsi_rqlen > SENSE_LENGTH) {
10850a2f1c3aSNikko He 			stat_size = (int)(scmd->uscsi_rqlen) +
10860a2f1c3aSNikko He 			    sizeof (struct scsi_arq_status) -
10870a2f1c3aSNikko He 			    sizeof (struct scsi_extended_sense);
10880a2f1c3aSNikko He 			flags = PKT_XARQ;
10897c478bd9Sstevel@tonic-gate 		} else {
10900a2f1c3aSNikko He 			stat_size = sizeof (struct scsi_arq_status);
10910a2f1c3aSNikko He 		}
10927c478bd9Sstevel@tonic-gate 	}
10937c478bd9Sstevel@tonic-gate 
10947c478bd9Sstevel@tonic-gate 	if (bp->b_bcount) {
10957c478bd9Sstevel@tonic-gate 		pkt = scsi_init_pkt(SES_ROUTE(ssc), NULL, bp,
10960a2f1c3aSNikko He 		    scmd->uscsi_cdblen, stat_size, 0, flags,
10970a2f1c3aSNikko He 		    func, (caddr_t)ssc);
10987c478bd9Sstevel@tonic-gate 	} else {
10997c478bd9Sstevel@tonic-gate 		pkt = scsi_init_pkt(SES_ROUTE(ssc), NULL, NULL,
11000a2f1c3aSNikko He 		    scmd->uscsi_cdblen, stat_size, 0, flags,
11010a2f1c3aSNikko He 		    func, (caddr_t)ssc);
11027c478bd9Sstevel@tonic-gate 	}
11037c478bd9Sstevel@tonic-gate 	SET_BP_PKT(bp, pkt);
11047c478bd9Sstevel@tonic-gate 	if (pkt == (struct scsi_pkt *)NULL)
11057c478bd9Sstevel@tonic-gate 		return;
11067c478bd9Sstevel@tonic-gate 	bcopy(scmd->uscsi_cdb, pkt->pkt_cdbp, (size_t)scmd->uscsi_cdblen);
1107*ffc5bd0fSKevin Crowe 
1108*ffc5bd0fSKevin Crowe 	/* Set an upper bound timeout of ses_io_time if zero is passed in */
1109*ffc5bd0fSKevin Crowe 	pkt->pkt_time = (scmd->uscsi_timeout == 0) ?
1110*ffc5bd0fSKevin Crowe 	    ses_io_time : scmd->uscsi_timeout;
11117c478bd9Sstevel@tonic-gate 
11127c478bd9Sstevel@tonic-gate 	pkt->pkt_comp = ses_callback;
11137c478bd9Sstevel@tonic-gate 	pkt->pkt_private = (opaque_t)ssc;
11147c478bd9Sstevel@tonic-gate }
11157c478bd9Sstevel@tonic-gate 
11167c478bd9Sstevel@tonic-gate 
11177c478bd9Sstevel@tonic-gate /*
11187c478bd9Sstevel@tonic-gate  * Restart ses command.
11197c478bd9Sstevel@tonic-gate  */
11207c478bd9Sstevel@tonic-gate static void
11217c478bd9Sstevel@tonic-gate ses_restart(void *arg)
11227c478bd9Sstevel@tonic-gate {
11237c478bd9Sstevel@tonic-gate 	struct scsi_pkt *pkt = (struct scsi_pkt *)arg;
11247c478bd9Sstevel@tonic-gate 	ses_softc_t *ssc = (ses_softc_t *)pkt->pkt_private;
11257c478bd9Sstevel@tonic-gate 	struct buf *bp = ssc->ses_sbufp;
11267c478bd9Sstevel@tonic-gate 	SES_LOG(ssc, SES_CE_DEBUG9, "ses_restart");
11277c478bd9Sstevel@tonic-gate 
11287c478bd9Sstevel@tonic-gate 	ssc->ses_restart_id = NULL;
11297c478bd9Sstevel@tonic-gate 
11307c478bd9Sstevel@tonic-gate 	switch (scsi_transport(pkt)) {
11317c478bd9Sstevel@tonic-gate 	case TRAN_ACCEPT:
11327c478bd9Sstevel@tonic-gate 		SES_LOG(ssc, SES_CE_DEBUG9,
11337c478bd9Sstevel@tonic-gate 		    "RESTART %d ok", ssc->ses_retries);
11347c478bd9Sstevel@tonic-gate 		return;
11357c478bd9Sstevel@tonic-gate 		/* break; */
11367c478bd9Sstevel@tonic-gate 	case TRAN_BUSY:
11377c478bd9Sstevel@tonic-gate 		SES_LOG(ssc, SES_CE_DEBUG1,
11387c478bd9Sstevel@tonic-gate 		    "RESTART %d TRANSPORT BUSY\n", ssc->ses_retries);
11397c478bd9Sstevel@tonic-gate 		if (ssc->ses_retries > SES_NO_RETRY) {
11407c478bd9Sstevel@tonic-gate 			ssc->ses_retries -= SES_BUSY_RETRY;
11417c478bd9Sstevel@tonic-gate 			SES_ENABLE_RESTART(SES_RESTART_TIME, pkt);
11427c478bd9Sstevel@tonic-gate 			return;
11437c478bd9Sstevel@tonic-gate 		}
11447c478bd9Sstevel@tonic-gate 		SET_BP_ERROR(bp, EBUSY);
11457c478bd9Sstevel@tonic-gate 		break;
11467c478bd9Sstevel@tonic-gate 	default:
11477c478bd9Sstevel@tonic-gate 		SET_BP_ERROR(bp, EIO);
11487c478bd9Sstevel@tonic-gate 		break;
11497c478bd9Sstevel@tonic-gate 	}
11507c478bd9Sstevel@tonic-gate 	SES_LOG(ssc, SES_CE_DEBUG1,
11517c478bd9Sstevel@tonic-gate 	    "RESTART %d TRANSPORT FAILED\n", ssc->ses_retries);
11527c478bd9Sstevel@tonic-gate 
11537c478bd9Sstevel@tonic-gate 	pkt = (struct scsi_pkt *)bp->av_back;
11547c478bd9Sstevel@tonic-gate 	scsi_destroy_pkt(pkt);
11557c478bd9Sstevel@tonic-gate 	bp->b_resid = bp->b_bcount;
11567c478bd9Sstevel@tonic-gate 	SET_BP_PKT(bp, NULL);
11577c478bd9Sstevel@tonic-gate 	biodone(bp);
11587c478bd9Sstevel@tonic-gate }
11597c478bd9Sstevel@tonic-gate 
11607c478bd9Sstevel@tonic-gate 
11617c478bd9Sstevel@tonic-gate /*
11627c478bd9Sstevel@tonic-gate  * Command completion processing
11637c478bd9Sstevel@tonic-gate  */
11647c478bd9Sstevel@tonic-gate #define	HBA_RESET	(STAT_BUS_RESET|STAT_DEV_RESET|STAT_ABORTED)
11657c478bd9Sstevel@tonic-gate static void
11667c478bd9Sstevel@tonic-gate ses_callback(struct scsi_pkt *pkt)
11677c478bd9Sstevel@tonic-gate {
11687c478bd9Sstevel@tonic-gate 	ses_softc_t *ssc = (ses_softc_t *)pkt->pkt_private;
11697c478bd9Sstevel@tonic-gate 	struct buf *bp;
11707c478bd9Sstevel@tonic-gate 	Uscmd *scmd;
11717c478bd9Sstevel@tonic-gate 	int err;
11727c478bd9Sstevel@tonic-gate 	char action;
11737c478bd9Sstevel@tonic-gate 
11747c478bd9Sstevel@tonic-gate 	bp = ssc->ses_sbufp;
11757c478bd9Sstevel@tonic-gate 	scmd = &ssc->ses_uscsicmd;
11767c478bd9Sstevel@tonic-gate 	/* SES_LOG(ssc, SES_CE_DEBUG9, "ses_callback"); */
11777c478bd9Sstevel@tonic-gate 
11787c478bd9Sstevel@tonic-gate 	/*
11797c478bd9Sstevel@tonic-gate 	 * Optimization: Normal completion.
11807c478bd9Sstevel@tonic-gate 	 */
11817c478bd9Sstevel@tonic-gate 	if (pkt->pkt_reason == CMD_CMPLT &&
11827c478bd9Sstevel@tonic-gate 	    !SCBP_C(pkt) &&
11837c478bd9Sstevel@tonic-gate 	    !(pkt->pkt_flags & FLAG_SENSING) &&
1184bf82a41bSeschrock 	    !pkt->pkt_resid) {
11857c478bd9Sstevel@tonic-gate 		scsi_destroy_pkt(pkt);
11867c478bd9Sstevel@tonic-gate 		SET_BP_PKT(bp, NULL);
11877c478bd9Sstevel@tonic-gate 		biodone(bp);
11887c478bd9Sstevel@tonic-gate 		return;
11897c478bd9Sstevel@tonic-gate 	}
11907c478bd9Sstevel@tonic-gate 
11917c478bd9Sstevel@tonic-gate 
11927c478bd9Sstevel@tonic-gate 	/*
11937c478bd9Sstevel@tonic-gate 	 * Abnormal completion.
11947c478bd9Sstevel@tonic-gate 	 *
11957c478bd9Sstevel@tonic-gate 	 * Assume most common error initially.
11967c478bd9Sstevel@tonic-gate 	 */
11977c478bd9Sstevel@tonic-gate 	err = EIO;
11987c478bd9Sstevel@tonic-gate 	action = COMMAND_DONE;
11997c478bd9Sstevel@tonic-gate 	if (scmd->uscsi_flags & USCSI_DIAGNOSE) {
12007c478bd9Sstevel@tonic-gate 		ssc->ses_retries = SES_NO_RETRY;
12017c478bd9Sstevel@tonic-gate 	}
12027c478bd9Sstevel@tonic-gate 
12037c478bd9Sstevel@tonic-gate CHECK_PKT:
12047c478bd9Sstevel@tonic-gate 	if (pkt->pkt_reason != CMD_CMPLT) {
12057c478bd9Sstevel@tonic-gate 		/* Process transport errors. */
12067c478bd9Sstevel@tonic-gate 		switch (pkt->pkt_reason) {
12077c478bd9Sstevel@tonic-gate 		case CMD_TIMEOUT:
12087c478bd9Sstevel@tonic-gate 			/*
12097c478bd9Sstevel@tonic-gate 			 * If the transport layer didn't clear the problem,
12107c478bd9Sstevel@tonic-gate 			 * reset the target.
12117c478bd9Sstevel@tonic-gate 			 */
12127c478bd9Sstevel@tonic-gate 			if (! (pkt->pkt_statistics & HBA_RESET)) {
1213275c9da8Seschrock 				(void) scsi_reset(&pkt->pkt_address,
1214275c9da8Seschrock 				    RESET_TARGET);
12157c478bd9Sstevel@tonic-gate 			}
12167c478bd9Sstevel@tonic-gate 			err = ETIMEDOUT;
12177c478bd9Sstevel@tonic-gate 			break;
12187c478bd9Sstevel@tonic-gate 
12197c478bd9Sstevel@tonic-gate 		case CMD_INCOMPLETE:
12207c478bd9Sstevel@tonic-gate 		case CMD_UNX_BUS_FREE:
12217c478bd9Sstevel@tonic-gate 			/*
12227c478bd9Sstevel@tonic-gate 			 * No response?  If probing, give up.
12237c478bd9Sstevel@tonic-gate 			 * Otherwise, keep trying until retries exhausted.
12247c478bd9Sstevel@tonic-gate 			 * Then lockdown the driver as the device is
12257c478bd9Sstevel@tonic-gate 			 * unplugged.
12267c478bd9Sstevel@tonic-gate 			 */
12277c478bd9Sstevel@tonic-gate 			if (ssc->ses_retries <= SES_NO_RETRY &&
12287c478bd9Sstevel@tonic-gate 			    !(scmd->uscsi_flags & USCSI_DIAGNOSE)) {
12297c478bd9Sstevel@tonic-gate 				ssc->ses_present = SES_CLOSED;
12307c478bd9Sstevel@tonic-gate 			}
12317c478bd9Sstevel@tonic-gate 			/* Inhibit retries to speed probe/attach. */
12327c478bd9Sstevel@tonic-gate 			if (ssc->ses_present < SES_OPEN) {
12337c478bd9Sstevel@tonic-gate 				ssc->ses_retries = SES_NO_RETRY;
12347c478bd9Sstevel@tonic-gate 			}
12357c478bd9Sstevel@tonic-gate 			/* SES_CMD_RETRY4(ssc->ses_retries); */
12367c478bd9Sstevel@tonic-gate 			err = ENXIO;
12377c478bd9Sstevel@tonic-gate 			break;
12387c478bd9Sstevel@tonic-gate 
12397c478bd9Sstevel@tonic-gate 		case CMD_DATA_OVR:
12407c478bd9Sstevel@tonic-gate 			/*
12417c478bd9Sstevel@tonic-gate 			 * XXX:	Some HBA's (e.g. Adaptec 1740 and
12427c478bd9Sstevel@tonic-gate 			 *	earlier ISP revs) report a DATA OVERRUN
12437c478bd9Sstevel@tonic-gate 			 *	error instead of a transfer residue.  So,
12447c478bd9Sstevel@tonic-gate 			 *	we convert the error and restart.
12457c478bd9Sstevel@tonic-gate 			 */
12467c478bd9Sstevel@tonic-gate 			if ((bp->b_bcount - pkt->pkt_resid) > 0) {
12477c478bd9Sstevel@tonic-gate 				SES_LOG(ssc, SES_CE_DEBUG6,
12487c478bd9Sstevel@tonic-gate 				    "ignoring overrun");
12497c478bd9Sstevel@tonic-gate 				pkt->pkt_reason = CMD_CMPLT;
12507c478bd9Sstevel@tonic-gate 				err = EOK;
12517c478bd9Sstevel@tonic-gate 				goto CHECK_PKT;
12527c478bd9Sstevel@tonic-gate 			}
12537c478bd9Sstevel@tonic-gate 			ssc->ses_retries = SES_NO_RETRY;
12547c478bd9Sstevel@tonic-gate 			/* err = EIO; */
12557c478bd9Sstevel@tonic-gate 			break;
12567c478bd9Sstevel@tonic-gate 
12577c478bd9Sstevel@tonic-gate 		case CMD_DMA_DERR:
12587c478bd9Sstevel@tonic-gate 			ssc->ses_retries = SES_NO_RETRY;
12597c478bd9Sstevel@tonic-gate 			err = EFAULT;
12607c478bd9Sstevel@tonic-gate 			break;
12617c478bd9Sstevel@tonic-gate 
12627c478bd9Sstevel@tonic-gate 		default:
12637c478bd9Sstevel@tonic-gate 			/* err = EIO; */
12647c478bd9Sstevel@tonic-gate 			break;
12657c478bd9Sstevel@tonic-gate 		}
12667c478bd9Sstevel@tonic-gate 		if (pkt == ssc->ses_rqpkt) {
12677c478bd9Sstevel@tonic-gate 			SES_LOG(ssc, CE_WARN, fail_msg,
12687c478bd9Sstevel@tonic-gate 			    "Request Sense ",
12697c478bd9Sstevel@tonic-gate 			    scsi_rname(pkt->pkt_reason),
12707c478bd9Sstevel@tonic-gate 			    (ssc->ses_retries > 0)?
12717c478bd9Sstevel@tonic-gate 			    "retrying": "giving up");
12727c478bd9Sstevel@tonic-gate 			pkt = (struct scsi_pkt *)bp->av_back;
12737c478bd9Sstevel@tonic-gate 			action = QUE_SENSE;
12747c478bd9Sstevel@tonic-gate 		} else {
12757c478bd9Sstevel@tonic-gate 			SES_LOG(ssc, CE_WARN, fail_msg,
12767c478bd9Sstevel@tonic-gate 			    "", scsi_rname(pkt->pkt_reason),
12777c478bd9Sstevel@tonic-gate 			    (ssc->ses_retries > 0)?
12787c478bd9Sstevel@tonic-gate 			    "retrying": "giving up");
12797c478bd9Sstevel@tonic-gate 			action = QUE_COMMAND;
12807c478bd9Sstevel@tonic-gate 		}
12817c478bd9Sstevel@tonic-gate 		/* Device exists, allow full error recovery. */
12827c478bd9Sstevel@tonic-gate 		if (ssc->ses_retries > SES_NO_RETRY) {
12837c478bd9Sstevel@tonic-gate 			ssc->ses_present = SES_OPEN;
12847c478bd9Sstevel@tonic-gate 		}
12857c478bd9Sstevel@tonic-gate 
12867c478bd9Sstevel@tonic-gate 
12877c478bd9Sstevel@tonic-gate 	/*
12887c478bd9Sstevel@tonic-gate 	 * Process status and sense data errors.
12897c478bd9Sstevel@tonic-gate 	 */
12907c478bd9Sstevel@tonic-gate 	} else {
12917c478bd9Sstevel@tonic-gate 		ssc->ses_present = SES_OPEN;
12927c478bd9Sstevel@tonic-gate 		action = ses_decode_sense(pkt, &err);
12937c478bd9Sstevel@tonic-gate 	}
12947c478bd9Sstevel@tonic-gate 
12957c478bd9Sstevel@tonic-gate 
12967c478bd9Sstevel@tonic-gate 	/*
12977c478bd9Sstevel@tonic-gate 	 * Initiate error recovery action, as needed.
12987c478bd9Sstevel@tonic-gate 	 */
12997c478bd9Sstevel@tonic-gate 	switch (action) {
13007c478bd9Sstevel@tonic-gate 	case QUE_COMMAND_NOW:
13017c478bd9Sstevel@tonic-gate 		/* SES_LOG(ssc, SES_CE_DEBUG1, "retrying cmd now"); */
13027c478bd9Sstevel@tonic-gate 		if (ssc->ses_retries > SES_NO_RETRY) {
13037c478bd9Sstevel@tonic-gate 			ssc->ses_retries -= SES_CMD_RETRY;
13047c478bd9Sstevel@tonic-gate 			scmd->uscsi_status = 0;
13057c478bd9Sstevel@tonic-gate 			if (ssc->ses_arq)
1306275c9da8Seschrock 				bzero(pkt->pkt_scbp,
1307275c9da8Seschrock 				    sizeof (struct scsi_arq_status));
13087c478bd9Sstevel@tonic-gate 
13097c478bd9Sstevel@tonic-gate 			if (scsi_transport((struct scsi_pkt *)bp->av_back)
13107c478bd9Sstevel@tonic-gate 			    != TRAN_ACCEPT) {
13117c478bd9Sstevel@tonic-gate 				SES_ENABLE_RESTART(SES_RESTART_TIME,
13127c478bd9Sstevel@tonic-gate 				    (struct scsi_pkt *)bp->av_back);
13137c478bd9Sstevel@tonic-gate 			}
13147c478bd9Sstevel@tonic-gate 			return;
13157c478bd9Sstevel@tonic-gate 		}
13167c478bd9Sstevel@tonic-gate 		break;
13177c478bd9Sstevel@tonic-gate 
13187c478bd9Sstevel@tonic-gate 	case QUE_COMMAND:
13197c478bd9Sstevel@tonic-gate 		SES_LOG(ssc, SES_CE_DEBUG1, "retrying cmd");
13207c478bd9Sstevel@tonic-gate 		if (ssc->ses_retries > SES_NO_RETRY) {
13217c478bd9Sstevel@tonic-gate 			ssc->ses_retries -=
13227c478bd9Sstevel@tonic-gate 			    (err == EBUSY)? SES_BUSY_RETRY: SES_CMD_RETRY;
13237c478bd9Sstevel@tonic-gate 			scmd->uscsi_status = 0;
13247c478bd9Sstevel@tonic-gate 			if (ssc->ses_arq)
1325275c9da8Seschrock 				bzero(pkt->pkt_scbp,
1326275c9da8Seschrock 				    sizeof (struct scsi_arq_status));
13277c478bd9Sstevel@tonic-gate 
13287c478bd9Sstevel@tonic-gate 			SES_ENABLE_RESTART(
13297c478bd9Sstevel@tonic-gate 			    (err == EBUSY)? SES_BUSY_TIME: SES_RESTART_TIME,
13307c478bd9Sstevel@tonic-gate 			    (struct scsi_pkt *)bp->av_back);
13317c478bd9Sstevel@tonic-gate 			return;
13327c478bd9Sstevel@tonic-gate 		}
13337c478bd9Sstevel@tonic-gate 		break;
13347c478bd9Sstevel@tonic-gate 
13357c478bd9Sstevel@tonic-gate 	case QUE_SENSE:
13367c478bd9Sstevel@tonic-gate 		SES_LOG(ssc, SES_CE_DEBUG1, "retrying sense");
13377c478bd9Sstevel@tonic-gate 		if (ssc->ses_retries > SES_NO_RETRY) {
13387c478bd9Sstevel@tonic-gate 			ssc->ses_retries -= SES_SENSE_RETRY;
13397c478bd9Sstevel@tonic-gate 			scmd->uscsi_status = 0;
13400a2f1c3aSNikko He 			bzero(&ssc->ses_srqsbuf, MAX_SENSE_LENGTH);
13417c478bd9Sstevel@tonic-gate 
13427c478bd9Sstevel@tonic-gate 			if (scsi_transport(ssc->ses_rqpkt) != TRAN_ACCEPT) {
13437c478bd9Sstevel@tonic-gate 				SES_ENABLE_RESTART(SES_RESTART_TIME,
13447c478bd9Sstevel@tonic-gate 				    ssc->ses_rqpkt);
13457c478bd9Sstevel@tonic-gate 			}
13467c478bd9Sstevel@tonic-gate 			return;
13477c478bd9Sstevel@tonic-gate 		}
13487c478bd9Sstevel@tonic-gate 		break;
13497c478bd9Sstevel@tonic-gate 
13507c478bd9Sstevel@tonic-gate 	case COMMAND_DONE:
13517c478bd9Sstevel@tonic-gate 		SES_LOG(ssc, SES_CE_DEBUG4, "cmd done");
13527c478bd9Sstevel@tonic-gate 		pkt = (struct scsi_pkt *)bp->av_back;
13537c478bd9Sstevel@tonic-gate 		bp->b_resid = pkt->pkt_resid;
13547c478bd9Sstevel@tonic-gate 		if (bp->b_resid) {
13557c478bd9Sstevel@tonic-gate 			SES_LOG(ssc, SES_CE_DEBUG6,
13567c478bd9Sstevel@tonic-gate 			    "transfer residue %ld(%ld)",
13577c478bd9Sstevel@tonic-gate 			    bp->b_bcount - bp->b_resid, bp->b_bcount);
13587c478bd9Sstevel@tonic-gate 		}
13597c478bd9Sstevel@tonic-gate 		break;
13607c478bd9Sstevel@tonic-gate 	}
13617c478bd9Sstevel@tonic-gate 	pkt = (struct scsi_pkt *)bp->av_back;
13627c478bd9Sstevel@tonic-gate 	if (err) {
13637c478bd9Sstevel@tonic-gate 		SES_LOG(ssc, SES_CE_DEBUG1, "SES: ERROR %d\n", err);
13647c478bd9Sstevel@tonic-gate 		SET_BP_ERROR(bp, err);
13657c478bd9Sstevel@tonic-gate 		bp->b_resid = bp->b_bcount;
13667c478bd9Sstevel@tonic-gate 	}
13677c478bd9Sstevel@tonic-gate 	scsi_destroy_pkt(pkt);
13687c478bd9Sstevel@tonic-gate 	SET_BP_PKT(bp, NULL);
13697c478bd9Sstevel@tonic-gate 	biodone(bp);
13707c478bd9Sstevel@tonic-gate }
13717c478bd9Sstevel@tonic-gate 
13727c478bd9Sstevel@tonic-gate 
13737c478bd9Sstevel@tonic-gate /*
13747c478bd9Sstevel@tonic-gate  * Check status and sense data and determine recovery.
13757c478bd9Sstevel@tonic-gate  */
13767c478bd9Sstevel@tonic-gate static int
13777c478bd9Sstevel@tonic-gate ses_decode_sense(struct scsi_pkt *pkt, int *err)
13787c478bd9Sstevel@tonic-gate {
13797c478bd9Sstevel@tonic-gate 	ses_softc_t *ssc = (ses_softc_t *)pkt->pkt_private;
13807c478bd9Sstevel@tonic-gate 	struct	scsi_extended_sense *sense =
13817c478bd9Sstevel@tonic-gate 	    (struct scsi_extended_sense *)&ssc->ses_srqsbuf;
13827c478bd9Sstevel@tonic-gate 	Uscmd *scmd = &ssc->ses_uscsicmd;
13837c478bd9Sstevel@tonic-gate 	char sense_flag = 0;
13847c478bd9Sstevel@tonic-gate 	uchar_t status = SCBP_C(pkt) & STATUS_MASK;
13857c478bd9Sstevel@tonic-gate 	char *err_action;
13867c478bd9Sstevel@tonic-gate 	char action;
13870a2f1c3aSNikko He 	uchar_t rqlen;
13880a2f1c3aSNikko He 	int amt;
13897c478bd9Sstevel@tonic-gate 
13907c478bd9Sstevel@tonic-gate 	/*
13917c478bd9Sstevel@tonic-gate 	 * Process manual request sense.
13927c478bd9Sstevel@tonic-gate 	 * Copy manual request sense to sense buffer.
13937c478bd9Sstevel@tonic-gate 	 *
13947c478bd9Sstevel@tonic-gate 	 * This is done if auto request sense is not enabled.
13957c478bd9Sstevel@tonic-gate 	 * Or the auto request sense failed and the request
13967c478bd9Sstevel@tonic-gate 	 * sense needs to be retried.
13977c478bd9Sstevel@tonic-gate 	 */
13987c478bd9Sstevel@tonic-gate 	if (pkt->pkt_flags & FLAG_SENSING) {
13997c478bd9Sstevel@tonic-gate 		struct buf *sbp = ssc->ses_rqbp;
14000a2f1c3aSNikko He 		amt = min(MAX_SENSE_LENGTH,
14017c478bd9Sstevel@tonic-gate 		    sbp->b_bcount - sbp->b_resid);
14020a2f1c3aSNikko He 		rqlen = min((uchar_t)amt, scmd->uscsi_rqlen);
14030a2f1c3aSNikko He 		bcopy(sbp->b_un.b_addr, sense, rqlen);
14040a2f1c3aSNikko He 		scmd->uscsi_rqresid = scmd->uscsi_rqlen - rqlen;
14057c478bd9Sstevel@tonic-gate 		sense_flag = 1;
14067c478bd9Sstevel@tonic-gate 	/*
14077c478bd9Sstevel@tonic-gate 	 * Process auto request sense.
14087c478bd9Sstevel@tonic-gate 	 * Copy auto request sense to sense buffer.
14097c478bd9Sstevel@tonic-gate 	 *
14107c478bd9Sstevel@tonic-gate 	 * If auto request sense failed due to transport error,
14117c478bd9Sstevel@tonic-gate 	 * retry the command.  Otherwise process the status and
14127c478bd9Sstevel@tonic-gate 	 * sense data.
14137c478bd9Sstevel@tonic-gate 	 */
14147c478bd9Sstevel@tonic-gate 	} else if (ssc->ses_arq && pkt->pkt_state & STATE_ARQ_DONE) {
14157c478bd9Sstevel@tonic-gate 		struct scsi_arq_status *arq =
14167c478bd9Sstevel@tonic-gate 		    (struct scsi_arq_status *)(pkt->pkt_scbp);
14177c478bd9Sstevel@tonic-gate 		uchar_t *arq_status = (uchar_t *)&arq->sts_rqpkt_status;
14180a2f1c3aSNikko He 		if (pkt->pkt_state & STATE_XARQ_DONE) {
14190a2f1c3aSNikko He 			amt = MAX_SENSE_LENGTH - arq->sts_rqpkt_resid;
14200a2f1c3aSNikko He 		} else {
14210a2f1c3aSNikko He 			if (arq->sts_rqpkt_resid > SENSE_LENGTH) {
14220a2f1c3aSNikko He 				amt = MAX_SENSE_LENGTH - arq->sts_rqpkt_resid;
14230a2f1c3aSNikko He 			} else {
14240a2f1c3aSNikko He 				amt = SENSE_LENGTH - arq->sts_rqpkt_resid;
14250a2f1c3aSNikko He 			}
14260a2f1c3aSNikko He 		}
14277c478bd9Sstevel@tonic-gate 
14287c478bd9Sstevel@tonic-gate 		if (arq->sts_rqpkt_reason != CMD_CMPLT) {
14297c478bd9Sstevel@tonic-gate 			return (QUE_COMMAND);
14307c478bd9Sstevel@tonic-gate 		}
14310a2f1c3aSNikko He 
14320a2f1c3aSNikko He 		rqlen = min((uchar_t)amt, scmd->uscsi_rqlen);
14330a2f1c3aSNikko He 		bcopy(&arq->sts_sensedata, sense, rqlen);
14347c478bd9Sstevel@tonic-gate 		scmd->uscsi_status = status;
14350a2f1c3aSNikko He 		scmd->uscsi_rqresid = scmd->uscsi_rqlen - rqlen;
14367c478bd9Sstevel@tonic-gate 		status = *arq_status & STATUS_MASK;
14377c478bd9Sstevel@tonic-gate 		pkt->pkt_state &= ~STATE_ARQ_DONE;
14387c478bd9Sstevel@tonic-gate 		sense_flag = 1;
14397c478bd9Sstevel@tonic-gate 	}
14407c478bd9Sstevel@tonic-gate 
14417c478bd9Sstevel@tonic-gate 
14427c478bd9Sstevel@tonic-gate 	/*
14437c478bd9Sstevel@tonic-gate 	 * Check status of REQUEST SENSE or command.
14447c478bd9Sstevel@tonic-gate 	 *
14457c478bd9Sstevel@tonic-gate 	 * If it's not successful, try retrying the original command
14467c478bd9Sstevel@tonic-gate 	 * and hope that it goes away.  If not, we'll eventually run
14477c478bd9Sstevel@tonic-gate 	 * out of retries and die.
14487c478bd9Sstevel@tonic-gate 	 */
14497c478bd9Sstevel@tonic-gate 	switch (status) {
14507c478bd9Sstevel@tonic-gate 	case STATUS_GOOD:
14517c478bd9Sstevel@tonic-gate 	case STATUS_INTERMEDIATE:
14527c478bd9Sstevel@tonic-gate 	case STATUS_MET:
14537c478bd9Sstevel@tonic-gate 		/*
14547c478bd9Sstevel@tonic-gate 		 * If the command status is ok, we're done.
14557c478bd9Sstevel@tonic-gate 		 * Otherwise, examine the request sense data.
14567c478bd9Sstevel@tonic-gate 		 */
14577c478bd9Sstevel@tonic-gate 		if (! sense_flag) {
14587c478bd9Sstevel@tonic-gate 			*err = EOK;
14597c478bd9Sstevel@tonic-gate 			return (COMMAND_DONE);
14607c478bd9Sstevel@tonic-gate 		}
14617c478bd9Sstevel@tonic-gate 		break;
14627c478bd9Sstevel@tonic-gate 
14637c478bd9Sstevel@tonic-gate 	case STATUS_CHECK:
14647c478bd9Sstevel@tonic-gate 		SES_LOG(ssc, SES_CE_DEBUG3, "status decode: check");
14657c478bd9Sstevel@tonic-gate 		*err = EIO;
14667c478bd9Sstevel@tonic-gate 		return (QUE_SENSE);
14677c478bd9Sstevel@tonic-gate 		/* break; */
14687c478bd9Sstevel@tonic-gate 
14697c478bd9Sstevel@tonic-gate 	case STATUS_BUSY:
14707c478bd9Sstevel@tonic-gate 		SES_LOG(ssc, SES_CE_DEBUG1, "status decode: busy");
14717c478bd9Sstevel@tonic-gate 		/* SES_CMD_RETRY2(ssc->ses_retries); */
14727c478bd9Sstevel@tonic-gate 		*err = EBUSY;
14737c478bd9Sstevel@tonic-gate 		return (QUE_COMMAND);
14747c478bd9Sstevel@tonic-gate 		/* break; */
14757c478bd9Sstevel@tonic-gate 
14767c478bd9Sstevel@tonic-gate 	case STATUS_RESERVATION_CONFLICT:
14777c478bd9Sstevel@tonic-gate 		SES_LOG(ssc, SES_CE_DEBUG1, "status decode: reserved");
14787c478bd9Sstevel@tonic-gate 		*err = EACCES;
14797c478bd9Sstevel@tonic-gate 		return (COMMAND_DONE_ERROR);
14807c478bd9Sstevel@tonic-gate 		/* break; */
14817c478bd9Sstevel@tonic-gate 
14827c478bd9Sstevel@tonic-gate 	case STATUS_TERMINATED:
14837c478bd9Sstevel@tonic-gate 		SES_LOG(ssc, SES_CE_DEBUG1, "status decode: terminated");
14847c478bd9Sstevel@tonic-gate 		*err = ECANCELED;
14857c478bd9Sstevel@tonic-gate 		return (COMMAND_DONE_ERROR);
14867c478bd9Sstevel@tonic-gate 		/* break; */
14877c478bd9Sstevel@tonic-gate 
14887c478bd9Sstevel@tonic-gate 	default:
14897c478bd9Sstevel@tonic-gate 		SES_LOG(ssc, SES_CE_DEBUG1, "status 0x%x", status);
14907c478bd9Sstevel@tonic-gate 		*err = EIO;
14917c478bd9Sstevel@tonic-gate 		return (QUE_COMMAND);
14927c478bd9Sstevel@tonic-gate 		/* break; */
14937c478bd9Sstevel@tonic-gate 	}
14947c478bd9Sstevel@tonic-gate 
14957c478bd9Sstevel@tonic-gate 
14967c478bd9Sstevel@tonic-gate 	/*
14977c478bd9Sstevel@tonic-gate 	 * Check REQUEST SENSE error code.
14987c478bd9Sstevel@tonic-gate 	 *
14997c478bd9Sstevel@tonic-gate 	 * Either there's no error, a retryable error,
15007c478bd9Sstevel@tonic-gate 	 * or it's dead.  SES devices aren't very complex.
15017c478bd9Sstevel@tonic-gate 	 */
15027c478bd9Sstevel@tonic-gate 	err_action = "retrying";
15037c478bd9Sstevel@tonic-gate 	switch (sense->es_key) {
15047c478bd9Sstevel@tonic-gate 	case KEY_RECOVERABLE_ERROR:
15057c478bd9Sstevel@tonic-gate 		*err = EOK;
15067c478bd9Sstevel@tonic-gate 		err_action = "recovered";
15077c478bd9Sstevel@tonic-gate 		action = COMMAND_DONE;
15087c478bd9Sstevel@tonic-gate 		break;
15097c478bd9Sstevel@tonic-gate 
15107c478bd9Sstevel@tonic-gate 	case KEY_UNIT_ATTENTION:
15117c478bd9Sstevel@tonic-gate 		/*
15127c478bd9Sstevel@tonic-gate 		 * This is common for RAID!
15137c478bd9Sstevel@tonic-gate 		 */
15147c478bd9Sstevel@tonic-gate 		/* *err = EIO; */
15157c478bd9Sstevel@tonic-gate 		SES_CMD_RETRY1(ssc->ses_retries);
15167c478bd9Sstevel@tonic-gate 		action = QUE_COMMAND_NOW;
15177c478bd9Sstevel@tonic-gate 		break;
15187c478bd9Sstevel@tonic-gate 
15197c478bd9Sstevel@tonic-gate 	case KEY_NOT_READY:
15207c478bd9Sstevel@tonic-gate 	case KEY_NO_SENSE:
15217c478bd9Sstevel@tonic-gate 		/* *err = EIO; */
15227c478bd9Sstevel@tonic-gate 		action = QUE_COMMAND;
15237c478bd9Sstevel@tonic-gate 		break;
15247c478bd9Sstevel@tonic-gate 
15257c478bd9Sstevel@tonic-gate 	default:
15267c478bd9Sstevel@tonic-gate 		/* *err = EIO; */
15277c478bd9Sstevel@tonic-gate 		err_action = "fatal";
15287c478bd9Sstevel@tonic-gate 		action = COMMAND_DONE_ERROR;
15297c478bd9Sstevel@tonic-gate 		break;
15307c478bd9Sstevel@tonic-gate 	}
15317c478bd9Sstevel@tonic-gate 	SES_LOG(ssc, SES_CE_DEBUG1,
15327c478bd9Sstevel@tonic-gate 	    "cdb[0]= 0x%x %s,  key=0x%x, ASC/ASCQ=0x%x/0x%x",
15337c478bd9Sstevel@tonic-gate 	    scmd->uscsi_cdb[0], err_action,
15347c478bd9Sstevel@tonic-gate 	    sense->es_key, sense->es_add_code, sense->es_qual_code);
15357c478bd9Sstevel@tonic-gate 
15367c478bd9Sstevel@tonic-gate #ifdef 	not
15377c478bd9Sstevel@tonic-gate 	/*
15387c478bd9Sstevel@tonic-gate 	 * Dump cdb and sense data stat's for manufacturing.
15397c478bd9Sstevel@tonic-gate 	 */
15407c478bd9Sstevel@tonic-gate 	if (DEBUGGING_ERR || sd_error_level == SDERR_ALL) {
15417c478bd9Sstevel@tonic-gate 		auto buf[128];
15427c478bd9Sstevel@tonic-gate 
15437c478bd9Sstevel@tonic-gate 		p = pkt->pkt_cdbp;
15447c478bd9Sstevel@tonic-gate 		if ((j = scsi_cdb_size[CDB_GROUPID(*p)]) == 0)
15457c478bd9Sstevel@tonic-gate 			j = CDB_SIZE;
15467c478bd9Sstevel@tonic-gate 
15477c478bd9Sstevel@tonic-gate 		/* Print cdb */
15487c478bd9Sstevel@tonic-gate 		(void) sprintf(buf, "cmd:");
15497c478bd9Sstevel@tonic-gate 		for (i = 0; i < j; i++) {
15507c478bd9Sstevel@tonic-gate 			(void) sprintf(&buf[strlen(buf)],
15517c478bd9Sstevel@tonic-gate 			    hex, (uchar_t)*p++);
15527c478bd9Sstevel@tonic-gate 		}
15537c478bd9Sstevel@tonic-gate 		SES_LOG(ssc, SES_CE_DEBUG3, "%s", buf);
15547c478bd9Sstevel@tonic-gate 
15557c478bd9Sstevel@tonic-gate 		/* Suppress trailing zero's in sense data */
15567c478bd9Sstevel@tonic-gate 		if (amt > 3) {
15577c478bd9Sstevel@tonic-gate 			p = (char *)devp->sd_sense + amt;
15587c478bd9Sstevel@tonic-gate 			for (j = amt; j > 3; j--) {
15597c478bd9Sstevel@tonic-gate 				if (*(--p))  break;
15607c478bd9Sstevel@tonic-gate 			}
15617c478bd9Sstevel@tonic-gate 		} else {
15627c478bd9Sstevel@tonic-gate 			j = amt;
15637c478bd9Sstevel@tonic-gate 		}
15647c478bd9Sstevel@tonic-gate 
15657c478bd9Sstevel@tonic-gate 		/* Print sense data. */
15667c478bd9Sstevel@tonic-gate 		(void) sprintf(buf, "sense:");
15677c478bd9Sstevel@tonic-gate 		p = (char *)devp->sd_sense;
15687c478bd9Sstevel@tonic-gate 		for (i = 0; i < j; i++) {
15697c478bd9Sstevel@tonic-gate 			(void) sprintf(&buf[strlen(buf)],
15707c478bd9Sstevel@tonic-gate 			    hex, (uchar_t)*p++);
15717c478bd9Sstevel@tonic-gate 		}
15727c478bd9Sstevel@tonic-gate 		SES_LOG(ssc, SES_CE_DEBUG3, "%s", buf);
15737c478bd9Sstevel@tonic-gate 	}
15747c478bd9Sstevel@tonic-gate #endif 	/* not */
15757c478bd9Sstevel@tonic-gate 	return (action);
15767c478bd9Sstevel@tonic-gate }
15777c478bd9Sstevel@tonic-gate 
15787c478bd9Sstevel@tonic-gate 
15797c478bd9Sstevel@tonic-gate /*PRINTFLIKE3*/
15807c478bd9Sstevel@tonic-gate void
15817c478bd9Sstevel@tonic-gate ses_log(ses_softc_t *ssc, int level, const char *fmt, ...)
15827c478bd9Sstevel@tonic-gate {
15837c478bd9Sstevel@tonic-gate 	va_list	ap;
15847c478bd9Sstevel@tonic-gate 	char buf[256];
15857c478bd9Sstevel@tonic-gate 
15867c478bd9Sstevel@tonic-gate 	va_start(ap, fmt);
15877c478bd9Sstevel@tonic-gate 	(void) vsprintf(buf, fmt, ap);
15887c478bd9Sstevel@tonic-gate 	va_end(ap);
15897c478bd9Sstevel@tonic-gate 
15907c478bd9Sstevel@tonic-gate 	if (ssc == (ses_softc_t *)NULL) {
15917c478bd9Sstevel@tonic-gate 		switch (level) {
15927c478bd9Sstevel@tonic-gate 		case SES_CE_DEBUG1:
15937c478bd9Sstevel@tonic-gate 			if (ses_debug > 1)
15947c478bd9Sstevel@tonic-gate 				cmn_err(CE_NOTE, "%s", buf);
15957c478bd9Sstevel@tonic-gate 			break;
15967c478bd9Sstevel@tonic-gate 		case SES_CE_DEBUG2:
15977c478bd9Sstevel@tonic-gate 			if (ses_debug > 2)
15987c478bd9Sstevel@tonic-gate 				cmn_err(CE_NOTE, "%s", buf);
15997c478bd9Sstevel@tonic-gate 			break;
16007c478bd9Sstevel@tonic-gate 		case SES_CE_DEBUG3:
16017c478bd9Sstevel@tonic-gate 			if (ses_debug > 3)
16027c478bd9Sstevel@tonic-gate 				cmn_err(CE_NOTE, "%s", buf);
16037c478bd9Sstevel@tonic-gate 			break;
16047c478bd9Sstevel@tonic-gate 		case SES_CE_DEBUG4:
16057c478bd9Sstevel@tonic-gate 			if (ses_debug > 4)
16067c478bd9Sstevel@tonic-gate 				cmn_err(CE_NOTE, "%s", buf);
16077c478bd9Sstevel@tonic-gate 			break;
16087c478bd9Sstevel@tonic-gate 		case SES_CE_DEBUG5:
16097c478bd9Sstevel@tonic-gate 			if (ses_debug > 5)
16107c478bd9Sstevel@tonic-gate 				cmn_err(CE_NOTE, "%s", buf);
16117c478bd9Sstevel@tonic-gate 			break;
16127c478bd9Sstevel@tonic-gate 		case SES_CE_DEBUG6:
16137c478bd9Sstevel@tonic-gate 			if (ses_debug > 6)
16147c478bd9Sstevel@tonic-gate 				cmn_err(CE_NOTE, "%s", buf);
16157c478bd9Sstevel@tonic-gate 			break;
16167c478bd9Sstevel@tonic-gate 		case SES_CE_DEBUG7:
16177c478bd9Sstevel@tonic-gate 			if (ses_debug > 7)
16187c478bd9Sstevel@tonic-gate 				cmn_err(CE_NOTE, "%s", buf);
16197c478bd9Sstevel@tonic-gate 			break;
16207c478bd9Sstevel@tonic-gate 		case SES_CE_DEBUG8:
16217c478bd9Sstevel@tonic-gate 			if (ses_debug > 8)
16227c478bd9Sstevel@tonic-gate 				cmn_err(CE_NOTE, "%s", buf);
16237c478bd9Sstevel@tonic-gate 			break;
16247c478bd9Sstevel@tonic-gate 		case SES_CE_DEBUG9:
16257c478bd9Sstevel@tonic-gate 			if (ses_debug > 9)
16267c478bd9Sstevel@tonic-gate 				cmn_err(CE_NOTE, "%s", buf);
16277c478bd9Sstevel@tonic-gate 			break;
16287c478bd9Sstevel@tonic-gate 		case CE_NOTE:
16297c478bd9Sstevel@tonic-gate 		case CE_WARN:
16307c478bd9Sstevel@tonic-gate 		case CE_PANIC:
16317c478bd9Sstevel@tonic-gate 			cmn_err(level, "%s", buf);
16327c478bd9Sstevel@tonic-gate 			break;
16337c478bd9Sstevel@tonic-gate 		case SES_CE_DEBUG:
16347c478bd9Sstevel@tonic-gate 		default:
16357c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE, "%s", buf);
16367c478bd9Sstevel@tonic-gate 		break;
16377c478bd9Sstevel@tonic-gate 		}
16387c478bd9Sstevel@tonic-gate 		return;
16397c478bd9Sstevel@tonic-gate 	}
16407c478bd9Sstevel@tonic-gate 
16417c478bd9Sstevel@tonic-gate 	switch (level) {
16427c478bd9Sstevel@tonic-gate 	case CE_CONT:
16437c478bd9Sstevel@tonic-gate 	case CE_NOTE:
16447c478bd9Sstevel@tonic-gate 	case CE_WARN:
16457c478bd9Sstevel@tonic-gate 	case CE_PANIC:
16467c478bd9Sstevel@tonic-gate 		scsi_log(SES_DEVINFO(ssc), (char *)Snm, level, Str, buf);
16477c478bd9Sstevel@tonic-gate 		break;
16487c478bd9Sstevel@tonic-gate 	case SES_CE_DEBUG1:
16497c478bd9Sstevel@tonic-gate 		if (ses_debug > 1)
16507c478bd9Sstevel@tonic-gate 			scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG,
16517c478bd9Sstevel@tonic-gate 			    Str, buf);
16527c478bd9Sstevel@tonic-gate 		break;
16537c478bd9Sstevel@tonic-gate 	case SES_CE_DEBUG2:
16547c478bd9Sstevel@tonic-gate 		if (ses_debug > 2)
16557c478bd9Sstevel@tonic-gate 			scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG,
16567c478bd9Sstevel@tonic-gate 			    Str, buf);
16577c478bd9Sstevel@tonic-gate 		break;
16587c478bd9Sstevel@tonic-gate 	case SES_CE_DEBUG3:
16597c478bd9Sstevel@tonic-gate 		if (ses_debug > 3)
16607c478bd9Sstevel@tonic-gate 			scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG,
16617c478bd9Sstevel@tonic-gate 			    Str, buf);
16627c478bd9Sstevel@tonic-gate 		break;
16637c478bd9Sstevel@tonic-gate 	case SES_CE_DEBUG4:
16647c478bd9Sstevel@tonic-gate 		if (ses_debug > 4)
16657c478bd9Sstevel@tonic-gate 			scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG,
16667c478bd9Sstevel@tonic-gate 			    Str, buf);
16677c478bd9Sstevel@tonic-gate 		break;
16687c478bd9Sstevel@tonic-gate 	case SES_CE_DEBUG5:
16697c478bd9Sstevel@tonic-gate 		if (ses_debug > 5)
16707c478bd9Sstevel@tonic-gate 			scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG,
16717c478bd9Sstevel@tonic-gate 			    Str, buf);
16727c478bd9Sstevel@tonic-gate 		break;
16737c478bd9Sstevel@tonic-gate 	case SES_CE_DEBUG6:
16747c478bd9Sstevel@tonic-gate 		if (ses_debug > 6)
16757c478bd9Sstevel@tonic-gate 			scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG,
16767c478bd9Sstevel@tonic-gate 			    Str, buf);
16777c478bd9Sstevel@tonic-gate 		break;
16787c478bd9Sstevel@tonic-gate 	case SES_CE_DEBUG7:
16797c478bd9Sstevel@tonic-gate 		if (ses_debug > 7)
16807c478bd9Sstevel@tonic-gate 			scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG,
16817c478bd9Sstevel@tonic-gate 			    Str, buf);
16827c478bd9Sstevel@tonic-gate 		break;
16837c478bd9Sstevel@tonic-gate 	case SES_CE_DEBUG8:
16847c478bd9Sstevel@tonic-gate 		if (ses_debug > 8)
16857c478bd9Sstevel@tonic-gate 			scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG,
16867c478bd9Sstevel@tonic-gate 			    Str, buf);
16877c478bd9Sstevel@tonic-gate 		break;
16887c478bd9Sstevel@tonic-gate 	case SES_CE_DEBUG9:
16897c478bd9Sstevel@tonic-gate 		if (ses_debug > 9)
16907c478bd9Sstevel@tonic-gate 			scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG,
16917c478bd9Sstevel@tonic-gate 			    Str, buf);
16927c478bd9Sstevel@tonic-gate 		break;
16937c478bd9Sstevel@tonic-gate 	case SES_CE_DEBUG:
16947c478bd9Sstevel@tonic-gate 	default:
16957c478bd9Sstevel@tonic-gate 		scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG, Str, buf);
16967c478bd9Sstevel@tonic-gate 		break;
16977c478bd9Sstevel@tonic-gate 	}
16987c478bd9Sstevel@tonic-gate }
16997c478bd9Sstevel@tonic-gate /*
17007c478bd9Sstevel@tonic-gate  * mode: c
17017c478bd9Sstevel@tonic-gate  * Local variables:
17027c478bd9Sstevel@tonic-gate  * c-indent-level: 8
17037c478bd9Sstevel@tonic-gate  * c-brace-imaginary-offset: 0
17047c478bd9Sstevel@tonic-gate  * c-brace-offset: -8
17057c478bd9Sstevel@tonic-gate  * c-argdecl-indent: 8
17067c478bd9Sstevel@tonic-gate  * c-label-offset: -8
17077c478bd9Sstevel@tonic-gate  * c-continued-statement-offset: 8
17087c478bd9Sstevel@tonic-gate  * c-continued-brace-offset: 0
17097c478bd9Sstevel@tonic-gate  * End:
17107c478bd9Sstevel@tonic-gate  */
1711