ses.c revision 7656:2621e50fdf4a
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Enclosure Services Device target driver
23 *
24 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
25 * Use is subject to license terms.
26 */
27
28#include <sys/modctl.h>
29#include <sys/file.h>
30#include <sys/scsi/scsi.h>
31#include <sys/scsi/generic/status.h>
32#include <sys/scsi/targets/sesio.h>
33#include <sys/scsi/targets/ses.h>
34
35
36
37/*
38 * Power management defines (should be in a common include file?)
39 */
40#define	PM_HARDWARE_STATE_PROP		"pm-hardware-state"
41#define	PM_NEEDS_SUSPEND_RESUME		"needs-suspend-resume"
42
43
44/*
45 * Global Driver Data
46 */
47int ses_io_time = SES_IO_TIME;
48
49static int ses_retry_count = SES_RETRY_COUNT * SES_RETRY_MULTIPLIER;
50
51#ifdef	DEBUG
52int ses_debug = 0;
53#else	/* DEBUG */
54#define	ses_debug	0
55#endif	/* DEBUG */
56
57
58/*
59 * External Enclosure Functions
60 */
61extern int ses_softc_init(ses_softc_t *, int);
62extern int ses_init_enc(ses_softc_t *);
63extern int ses_get_encstat(ses_softc_t *, int);
64extern int ses_set_encstat(ses_softc_t *, uchar_t, int);
65extern int ses_get_objstat(ses_softc_t *, ses_objarg *, int);
66extern int ses_set_objstat(ses_softc_t *, ses_objarg *, int);
67
68extern int safte_softc_init(ses_softc_t *, int);
69extern int safte_init_enc(ses_softc_t *);
70extern int safte_get_encstat(ses_softc_t *, int);
71extern int safte_set_encstat(ses_softc_t *, uchar_t, int);
72extern int safte_get_objstat(ses_softc_t *, ses_objarg *, int);
73extern int safte_set_objstat(ses_softc_t *, ses_objarg *, int);
74
75extern int sen_softc_init(ses_softc_t *, int);
76extern int sen_init_enc(ses_softc_t *);
77extern int sen_get_encstat(ses_softc_t *, int);
78extern int sen_set_encstat(ses_softc_t *, uchar_t, int);
79extern int sen_get_objstat(ses_softc_t *, ses_objarg *, int);
80extern int sen_set_objstat(ses_softc_t *, ses_objarg *, int);
81
82/*
83 * Local Function prototypes
84 */
85static int ses_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
86static int ses_probe(dev_info_t *);
87static int ses_attach(dev_info_t *, ddi_attach_cmd_t);
88static int ses_detach(dev_info_t *, ddi_detach_cmd_t);
89
90static int is_enc_dev(ses_softc_t *, struct scsi_inquiry *, int, enctyp *);
91static int ses_doattach(dev_info_t *dip);
92
93static int  ses_open(dev_t *, int, int, cred_t *);
94static int  ses_close(dev_t, int, int, cred_t *);
95static int  ses_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
96
97static encvec vecs[3] = {
98{
99	ses_softc_init, ses_init_enc, ses_get_encstat,
100	ses_set_encstat, ses_get_objstat, ses_set_objstat
101},
102{
103	safte_softc_init, safte_init_enc, safte_get_encstat,
104	safte_set_encstat, safte_get_objstat, safte_set_objstat,
105},
106{
107	sen_softc_init, sen_init_enc, sen_get_encstat,
108	sen_set_encstat, sen_get_objstat, sen_set_objstat
109}
110};
111
112
113/*
114 * Local Functions
115 */
116static int ses_start(struct buf *bp);
117static int ses_decode_sense(struct scsi_pkt *pkt, int *err);
118
119static void ses_get_pkt(struct buf *bp, int (*func)(opaque_t));
120static void ses_callback(struct scsi_pkt *pkt);
121static void ses_restart(void *arg);
122
123
124/*
125 * Local Static Data
126 */
127#ifndef	D_HOTPLUG
128#define	D_HOTPLUG	0
129#endif /* D_HOTPLUG */
130
131static struct cb_ops ses_cb_ops = {
132	ses_open,			/* open */
133	ses_close,			/* close */
134	nodev,				/* strategy */
135	nodev,				/* print */
136	nodev,				/* dump */
137	nodev,				/* read */
138	nodev,				/* write */
139	ses_ioctl,			/* ioctl */
140	nodev,				/* devmap */
141	nodev,				/* mmap */
142	nodev,				/* segmap */
143	nochpoll,			/* poll */
144	ddi_prop_op,			/* cb_prop_op */
145	0,				/* streamtab  */
146#if	!defined(CB_REV)
147	D_MP | D_NEW | D_HOTPLUG	/* Driver compatibility flag */
148#else	/* !defined(CB_REV) */
149	D_MP | D_NEW | D_HOTPLUG,	/* Driver compatibility flag */
150	CB_REV,				/* cb_ops version number */
151	nodev,				/* aread */
152	nodev				/* awrite */
153#endif	/* !defined(CB_REV) */
154};
155
156static struct dev_ops ses_dev_ops = {
157	DEVO_REV,		/* devo_rev, */
158	0,			/* refcnt  */
159	ses_info,		/* info */
160	nulldev,		/* identify */
161	ses_probe,		/* probe */
162	ses_attach,		/* attach */
163	ses_detach,		/* detach */
164	nodev,			/* reset */
165	&ses_cb_ops,		/* driver operations */
166	(struct bus_ops *)NULL,	/* bus operations */
167	NULL,			/* power */
168	ddi_quiesce_not_needed,		/* quiesce */
169};
170
171static void *estate  = NULL;
172static const char *Snm = "ses";
173static const char *Str = "%s\n";
174static const char *efl = "copyin/copyout EFAULT @ line %d";
175static const char *fail_msg = "%stransport failed: reason '%s': %s";
176
177
178
179/*
180 * autoconfiguration routines.
181 */
182char _depends_on[] = "misc/scsi";
183
184static struct modldrv modldrv = {
185	&mod_driverops,
186	"SCSI Enclosure Services",
187	&ses_dev_ops
188};
189
190static struct modlinkage modlinkage = {
191	MODREV_1, &modldrv, NULL
192};
193
194
195int
196_init(void)
197{
198	int status;
199	status = ddi_soft_state_init(&estate, sizeof (ses_softc_t), 0);
200	if (status == 0) {
201		if ((status = mod_install(&modlinkage)) != 0) {
202			ddi_soft_state_fini(&estate);
203		}
204	}
205	return (status);
206}
207
208int
209_fini(void)
210{
211	int status;
212	if ((status = mod_remove(&modlinkage)) != 0) {
213		return (status);
214	}
215	ddi_soft_state_fini(&estate);
216	return (status);
217}
218
219int
220_info(struct modinfo *modinfop)
221{
222	return (mod_info(&modlinkage, modinfop));
223}
224
225static int
226ses_probe(dev_info_t *dip)
227{
228	int			err;
229	struct scsi_device	*devp;
230	enctyp			ep;
231
232	/*
233	 * I finally figured out why we return success
234	 * on every probe. The devices that we attach to
235	 * don't all report as being the same "device type"
236	 *
237	 * 1) A5x00 -- report as Enclosure Services (0xD) SES
238	 * 2) A1000 -- report as Direct Access (0x0) SES
239	 *    uses the same target as raid controler.
240	 * 3) D1000 -- report as processor (0x3) SAFTE
241	 * 3) D240  -- report as processor (0x3) SAFTE
242	 *
243	 * We also reportedly attach to SEN devices which I
244	 * believe reside in a Tobasco tray.  I have never
245	 * been able to get one to attach.
246	 *
247	 */
248
249
250	if (dip == NULL)
251		return (DDI_PROBE_FAILURE);
252	/*
253	 * XXX: Breakage from the x86 folks.
254	 */
255	if (strcmp(ddi_get_name(ddi_get_parent(dip)), "ata") == 0) {
256		return (DDI_PROBE_FAILURE);
257	}
258	/* SES_LOG(NULL, SES_CE_DEBUG1, "ses_probe: OK"); */
259	if (ddi_dev_is_sid(dip) == DDI_SUCCESS) {
260		return (DDI_PROBE_DONTCARE);
261	}
262	devp = ddi_get_driver_private(dip);
263	switch (err = scsi_probe(devp, SLEEP_FUNC)) {
264	case SCSIPROBE_EXISTS:
265		if (is_enc_dev(NULL, devp->sd_inq, SUN_INQSIZE, &ep)) {
266			break;
267		}
268		/* FALLTHROUGH */
269	case SCSIPROBE_NORESP:
270		scsi_unprobe(devp);
271		return (DDI_PROBE_FAILURE);
272	default:
273		SES_LOG(NULL, SES_CE_DEBUG9,
274		    "ses_probe: probe error %d", err);
275		scsi_unprobe(devp);
276		return (DDI_PROBE_FAILURE);
277	}
278	scsi_unprobe(devp);
279	return (DDI_PROBE_SUCCESS);
280}
281
282static int
283ses_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
284{
285	int inst, err;
286	ses_softc_t *ssc;
287
288	inst = ddi_get_instance(dip);
289	switch (cmd) {
290	case DDI_ATTACH:
291		SES_LOG(NULL, SES_CE_DEBUG9, "ses_attach: DDI_ATTACH ses%d",
292		    inst);
293
294		err = ses_doattach(dip);
295
296		if (err == DDI_FAILURE) {
297			return (DDI_FAILURE);
298		}
299		SES_LOG(NULL, SES_CE_DEBUG4,
300		    "ses_attach: DDI_ATTACH OK ses%d", inst);
301		break;
302
303	case DDI_RESUME:
304		if ((ssc = ddi_get_soft_state(estate, inst)) == NULL) {
305			return (DDI_FAILURE);
306		}
307		SES_LOG(ssc, SES_CE_DEBUG1, "ses_attach: DDI_ATTACH ses%d",
308		    inst);
309		ssc->ses_suspended = 0;
310		break;
311
312	default:
313		return (DDI_FAILURE);
314	}
315	return (DDI_SUCCESS);
316}
317
318static int
319is_enc_dev(ses_softc_t *ssc, struct scsi_inquiry *inqp, int iqlen, enctyp *ep)
320{
321	uchar_t dt = (inqp->inq_dtype & DTYPE_MASK);
322	uchar_t *iqd = (uchar_t *)inqp;
323
324	if (dt == DTYPE_ESI) {
325		if (strncmp(inqp->inq_vid, SEN_ID, SEN_ID_LEN) == 0) {
326			SES_LOG(ssc, SES_CE_DEBUG3, "SEN device found");
327			*ep = SEN_TYPE;
328		} else if (inqp->inq_rdf == RDF_SCSI2) {
329			/*
330			 * Per SPC4 #6.4.2 Standard Inquiry Data, response
331			 * data format (RDF) values of 0 and 1 are Obsolete,
332			 * whereas values greater than 2 are Reserved
333			 */
334			SES_LOG(ssc, SES_CE_DEBUG3, "SES device found");
335			*ep = SES_TYPE;
336		} else {
337			SES_LOG(ssc, SES_CE_DEBUG3, "Pre-SCSI3 SES device");
338			*ep = SES_TYPE;
339		}
340		return (1);
341	}
342	if ((iqd[6] & 0x40) && inqp->inq_rdf >= RDF_SCSI2) {
343		/*
344		 * PassThrough Device.
345		 */
346		*ep = SES_TYPE;
347		SES_LOG(ssc, SES_CE_DEBUG3, "Passthru SES device");
348		return (1);
349	}
350
351	if (iqlen < 47) {
352		SES_LOG(ssc, CE_NOTE,
353		    "INQUIRY data too short to determine SAF-TE");
354		return (0);
355	}
356	if (strncmp((char *)&iqd[44], "SAF-TE", 4) == 0) {
357		*ep = SAFT_TYPE;
358		SES_LOG(ssc, SES_CE_DEBUG3, "SAF-TE device found");
359		return (1);
360	}
361	return (0);
362}
363
364
365/*
366 * Attach ses device.
367 *
368 * XXX:  Power management is NOT supported.  A token framework
369 *       is provided that will need to be extended assuming we have
370 *       ses devices we can power down.  Currently, we don't have any.
371 */
372static int
373ses_doattach(dev_info_t *dip)
374{
375	int inst, err;
376	Scsidevp devp;
377	ses_softc_t *ssc;
378	enctyp etyp;
379
380	inst = ddi_get_instance(dip);
381	/*
382	 * Workaround for bug #4154979- for some reason we can
383	 * be called with identical instance numbers but for
384	 * different dev_info_t-s- all but one are bogus.
385	 *
386	 * Bad Dog! No Biscuit!
387	 *
388	 * A quick workaround might be to call ddi_soft_state_zalloc
389	 * unconditionally, as the implementation fails these calls
390	 * if there's an item already allocated. A more reasonable
391	 * and longer term change is to move the allocation past
392	 * the probe for the device's existence as most of these
393	 * 'bogus' calls are for nonexistent devices.
394	 */
395
396	devp  = ddi_get_driver_private(dip);
397	devp->sd_dev = dip;
398
399	/*
400	 * Determine whether the { i, t, l } we're called
401	 * to start is an enclosure services device.
402	 */
403
404	/*
405	 * Call the scsi_probe routine to see whether
406	 * we actually have an Enclosure Services device at
407	 * this address.
408	 */
409	err = scsi_probe(devp, SLEEP_FUNC);
410	if (err != SCSIPROBE_EXISTS) {
411		SES_LOG(NULL, SES_CE_DEBUG9,
412		    "ses_doattach: probe error %d", err);
413		scsi_unprobe(devp);
414		return (DDI_FAILURE);
415	}
416	/* Call is_enc_dev() to get the etyp */
417	if (!(is_enc_dev(NULL, devp->sd_inq, SUN_INQSIZE, &etyp))) {
418		SES_LOG(NULL, CE_WARN,
419		    "ses_doattach: ses%d: is_enc_dev failure", inst);
420		scsi_unprobe(devp);
421		return (DDI_FAILURE);
422	}
423
424	if (ddi_soft_state_zalloc(estate, inst) != DDI_SUCCESS) {
425		scsi_unprobe(devp);
426		SES_LOG(NULL, CE_NOTE, "ses%d: softalloc fails", inst);
427		return (DDI_FAILURE);
428	}
429	ssc = ddi_get_soft_state(estate, inst);
430	if (ssc == NULL) {
431		scsi_unprobe(devp);
432		SES_LOG(NULL, CE_NOTE, "ses%d: get_soft_state fails", inst);
433		return (DDI_FAILURE);
434	}
435	devp->sd_private = (opaque_t)ssc;
436	ssc->ses_devp = devp;
437	err = ddi_create_minor_node(dip, "0", S_IFCHR, inst,
438	    DDI_NT_SCSI_ENCLOSURE, NULL);
439	if (err == DDI_FAILURE) {
440		ddi_remove_minor_node(dip, NULL);
441		SES_LOG(ssc, CE_NOTE, "minor node creation failed");
442		ddi_soft_state_free(estate, inst);
443		scsi_unprobe(devp);
444		return (DDI_FAILURE);
445	}
446
447	ssc->ses_type = etyp;
448	ssc->ses_vec = vecs[etyp];
449
450	/* Call SoftC Init Routine A bit later... */
451
452	ssc->ses_rqbp = scsi_alloc_consistent_buf(SES_ROUTE(ssc),
453	    NULL, MAX_SENSE_LENGTH, B_READ, SLEEP_FUNC, NULL);
454	if (ssc->ses_rqbp != NULL) {
455		ssc->ses_rqpkt = scsi_init_pkt(SES_ROUTE(ssc), NULL,
456		    ssc->ses_rqbp, CDB_GROUP0, 1, 0, PKT_CONSISTENT,
457		    SLEEP_FUNC, NULL);
458	}
459	if (ssc->ses_rqbp == NULL || ssc->ses_rqpkt == NULL) {
460		ddi_remove_minor_node(dip, NULL);
461		SES_LOG(ssc, CE_NOTE, "scsi_init_pkt of rqbuf failed");
462		if (ssc->ses_rqbp != NULL) {
463			scsi_free_consistent_buf(ssc->ses_rqbp);
464			ssc->ses_rqbp = NULL;
465		}
466		ddi_soft_state_free(estate, inst);
467		scsi_unprobe(devp);
468		return (DDI_FAILURE);
469	}
470	ssc->ses_rqpkt->pkt_private = (opaque_t)ssc;
471	ssc->ses_rqpkt->pkt_address = *(SES_ROUTE(ssc));
472	ssc->ses_rqpkt->pkt_comp = ses_callback;
473	ssc->ses_rqpkt->pkt_time = ses_io_time;
474	ssc->ses_rqpkt->pkt_flags = FLAG_NOPARITY|FLAG_NODISCON|FLAG_SENSING;
475	ssc->ses_rqpkt->pkt_cdbp[0] = SCMD_REQUEST_SENSE;
476	ssc->ses_rqpkt->pkt_cdbp[1] = 0;
477	ssc->ses_rqpkt->pkt_cdbp[2] = 0;
478	ssc->ses_rqpkt->pkt_cdbp[3] = 0;
479	ssc->ses_rqpkt->pkt_cdbp[4] = MAX_SENSE_LENGTH;
480	ssc->ses_rqpkt->pkt_cdbp[5] = 0;
481
482	switch (scsi_ifgetcap(SES_ROUTE(ssc), "auto-rqsense", 1)) {
483	case 1:
484		/* if already set, don't reset it */
485		ssc->ses_arq = 1;
486		break;
487	case 0:
488		/* try and set it */
489		ssc->ses_arq = ((scsi_ifsetcap(SES_ROUTE(ssc),
490		    "auto-rqsense", 1, 1) == 1) ? 1 : 0);
491		break;
492	default:
493		/* probably undefined, so zero it out */
494		ssc->ses_arq = 0;
495		break;
496	}
497
498	ssc->ses_sbufp = getrbuf(KM_SLEEP);
499	cv_init(&ssc->ses_sbufcv, NULL, CV_DRIVER, NULL);
500
501	/*
502	 * If the HBA supports wide, tell it to use wide.
503	 */
504	if (scsi_ifgetcap(SES_ROUTE(ssc), "wide-xfer", 1) != -1) {
505		int wd = ((devp->sd_inq->inq_rdf == RDF_SCSI2) &&
506		    (devp->sd_inq->inq_wbus16 || devp->sd_inq->inq_wbus32))
507		    ? 1 : 0;
508		(void) scsi_ifsetcap(SES_ROUTE(ssc), "wide-xfer", wd, 1);
509	}
510
511	/*
512	 * Now do ssc init of enclosure specifics.
513	 * At the same time, check to make sure getrbuf
514	 * actually succeeded.
515	 */
516	if ((*ssc->ses_vec.softc_init)(ssc, 1)) {
517		SES_LOG(ssc, SES_CE_DEBUG3, "failed softc init");
518		(void) (*ssc->ses_vec.softc_init)(ssc, 0);
519		ddi_remove_minor_node(dip, NULL);
520		scsi_destroy_pkt(ssc->ses_rqpkt);
521		scsi_free_consistent_buf(ssc->ses_rqbp);
522		if (ssc->ses_sbufp) {
523			freerbuf(ssc->ses_sbufp);
524		}
525		cv_destroy(&ssc->ses_sbufcv);
526		ddi_soft_state_free(estate, inst);
527		scsi_unprobe(devp);
528		return (DDI_FAILURE);
529	}
530
531	/*
532	 * create this property so that PM code knows we want
533	 * to be suspended at PM time
534	 */
535	(void) ddi_prop_update_string(DDI_DEV_T_NONE, dip,
536	    PM_HARDWARE_STATE_PROP, PM_NEEDS_SUSPEND_RESUME);
537
538	/* announce the existence of this device */
539	ddi_report_dev(dip);
540	return (DDI_SUCCESS);
541}
542
543
544/*
545 * Detach ses device.
546 *
547 * XXX:  Power management is NOT supported.  A token framework
548 *       is provided that will need to be extended assuming we have
549 *       ses devices we can power down.  Currently, we don't have any.
550 */
551static int
552ses_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
553{
554	ses_softc_t *ssc;
555	int inst;
556
557	switch (cmd) {
558	case DDI_DETACH:
559		inst = ddi_get_instance(dip);
560		ssc = ddi_get_soft_state(estate, inst);
561		if (ssc == NULL) {
562			cmn_err(CE_NOTE,
563			    "ses%d: DDI_DETACH, no softstate found", inst);
564			return (DDI_FAILURE);
565		}
566		if (ISOPEN(ssc)) {
567			return (DDI_FAILURE);
568		}
569
570#if		!defined(lint)
571		/* LINTED */
572		_NOTE(COMPETING_THREADS_NOW);
573#endif		/* !defined(lint) */
574
575		if (ssc->ses_vec.softc_init)
576			(void) (*ssc->ses_vec.softc_init)(ssc, 0);
577
578#if		!defined(lint)
579		_NOTE(NO_COMPETING_THREADS_NOW);
580#endif 		/* !defined(lint) */
581
582		(void) scsi_ifsetcap(SES_ROUTE(ssc), "auto-rqsense", 1, 0);
583		scsi_destroy_pkt(ssc->ses_rqpkt);
584		scsi_free_consistent_buf(ssc->ses_rqbp);
585		freerbuf(ssc->ses_sbufp);
586		cv_destroy(&ssc->ses_sbufcv);
587		ddi_soft_state_free(estate, inst);
588		ddi_prop_remove_all(dip);
589		ddi_remove_minor_node(dip, NULL);
590		scsi_unprobe(ddi_get_driver_private(dip));
591		break;
592
593	case DDI_SUSPEND:
594		inst = ddi_get_instance(dip);
595		if ((ssc = ddi_get_soft_state(estate, inst)) == NULL) {
596			cmn_err(CE_NOTE,
597			    "ses%d: DDI_SUSPEND, no softstate found", inst);
598			return (DDI_FAILURE);
599		}
600
601		/*
602		 * If driver idle, accept suspend request.
603		 * If it's busy, reject it.  This keeps things simple!
604		 */
605		mutex_enter(SES_MUTEX);
606		if (ssc->ses_sbufbsy) {
607			mutex_exit(SES_MUTEX);
608			return (DDI_FAILURE);
609		}
610		ssc->ses_suspended = 1;
611		mutex_exit(SES_MUTEX);
612		break;
613
614	default:
615		return (DDI_FAILURE);
616	}
617	return (DDI_SUCCESS);
618}
619
620/* ARGSUSED */
621static int
622ses_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
623{
624	dev_t dev;
625	ses_softc_t *ssc;
626	int inst, error;
627
628	switch (infocmd) {
629	case DDI_INFO_DEVT2DEVINFO:
630		dev = (dev_t)arg;
631		inst = getminor(dev);
632		if ((ssc = ddi_get_soft_state(estate, inst)) == NULL) {
633			return (DDI_FAILURE);
634		}
635		*result = (void *) ssc->ses_devp->sd_dev;
636		error = DDI_SUCCESS;
637		break;
638	case DDI_INFO_DEVT2INSTANCE:
639		dev = (dev_t)arg;
640		inst = getminor(dev);
641		*result = (void *)(uintptr_t)inst;
642		error = DDI_SUCCESS;
643		break;
644	default:
645		error = DDI_FAILURE;
646	}
647	return (error);
648}
649
650
651/*
652 * Unix Entry Points
653 */
654
655/* ARGSUSED */
656static int
657ses_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p)
658{
659	ses_softc_t *ssc;
660
661	if ((ssc = ddi_get_soft_state(estate, getminor(*dev_p))) == NULL) {
662		return (ENXIO);
663	}
664
665	/*
666	 * If the device is powered down, request it's activation.
667	 * If it can't be activated, fail open.
668	 */
669	if (ssc->ses_suspended &&
670	    ddi_dev_is_needed(SES_DEVINFO(ssc), 0, 1) != DDI_SUCCESS) {
671		return (EIO);
672	}
673
674	mutex_enter(SES_MUTEX);
675	if (otyp == OTYP_LYR)
676		ssc->ses_lyropen++;
677	else
678		ssc->ses_oflag = 1;
679
680	ssc->ses_present = (ssc->ses_present)? ssc->ses_present: SES_OPENING;
681	mutex_exit(SES_MUTEX);
682	return (EOK);
683}
684
685/*ARGSUSED*/
686static int
687ses_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
688{
689	ses_softc_t *ssc;
690	if ((ssc = ddi_get_soft_state(estate, getminor(dev))) == NULL) {
691		return (ENXIO);
692	}
693
694	if (ssc->ses_suspended) {
695		(void) ddi_dev_is_needed(SES_DEVINFO(ssc), 0, 1);
696	}
697
698	mutex_enter(SES_MUTEX);
699	if (otyp == OTYP_LYR)
700		ssc->ses_lyropen -= (ssc->ses_lyropen)? 1: 0;
701	else
702		ssc->ses_oflag = 0;
703	mutex_exit(SES_MUTEX);
704	return (0);
705}
706
707
708/*ARGSUSED3*/
709static int
710ses_ioctl(dev_t dev, int cmd, intptr_t arg, int flg, cred_t *cred_p, int *rvalp)
711{
712	ses_softc_t *ssc;
713	ses_object k, *up;
714	ses_objarg x;
715	uchar_t t;
716	uchar_t i;
717	int rv = 0;
718
719	if ((ssc = ddi_get_soft_state(estate, getminor(dev))) == NULL ||
720	    ssc->ses_present == SES_CLOSED) {
721		return (ENXIO);
722	}
723
724
725	switch (cmd) {
726	case SESIOC_GETNOBJ:
727		if (ddi_copyout(&ssc->ses_nobjects, (void *)arg,
728		    sizeof (int), flg)) {
729			rv = EFAULT;
730			break;
731		}
732		break;
733
734	case SESIOC_GETOBJMAP:
735		up = (ses_object *) arg;
736		mutex_enter(SES_MUTEX);
737		for (i = 0; i != ssc->ses_nobjects; i++) {
738			k.obj_id = i;
739			k.subencid = ssc->ses_objmap[i].subenclosure;
740			k.elem_type = ssc->ses_objmap[i].enctype;
741			if (ddi_copyout(&k, up, sizeof (k), flg)) {
742				rv = EFAULT;
743				break;
744			}
745			up++;
746		}
747		mutex_exit(SES_MUTEX);
748		break;
749
750	case SESIOC_INIT:
751		rv = (*ssc->ses_vec.init_enc)(ssc);
752		break;
753
754	case SESIOC_GETENCSTAT:
755		if ((ssc->ses_encstat & ENCI_SVALID) == 0) {
756			rv = (*ssc->ses_vec.get_encstat)(ssc, KM_SLEEP);
757			if (rv) {
758				break;
759			}
760		}
761		t = ssc->ses_encstat & 0xf;
762		if (ddi_copyout(&t, (void *)arg, sizeof (t), flg))
763			rv = EFAULT;
764		/*
765		 * And always invalidate enclosure status on the way out.
766		 */
767		mutex_enter(SES_MUTEX);
768		ssc->ses_encstat &= ~ENCI_SVALID;
769		mutex_exit(SES_MUTEX);
770		break;
771
772	case SESIOC_SETENCSTAT:
773		if (ddi_copyin((void *)arg, &t, sizeof (t), flg))
774			rv = EFAULT;
775		else
776			rv = (*ssc->ses_vec.set_encstat)(ssc, t, KM_SLEEP);
777		mutex_enter(SES_MUTEX);
778		ssc->ses_encstat &= ~ENCI_SVALID;
779		mutex_exit(SES_MUTEX);
780		break;
781
782	case SESIOC_GETOBJSTAT:
783		if (ddi_copyin((void *)arg, &x, sizeof (x), flg)) {
784			rv = EFAULT;
785			break;
786		}
787		if (x.obj_id >= ssc->ses_nobjects) {
788			rv = EINVAL;
789			break;
790		}
791		if ((rv = (*ssc->ses_vec.get_objstat)(ssc, &x, KM_SLEEP)) != 0)
792			break;
793		if (ddi_copyout(&x, (void *)arg, sizeof (x), flg))
794			rv = EFAULT;
795		else {
796			/*
797			 * Now that we no longer poll, svalid never stays true.
798			 */
799			mutex_enter(SES_MUTEX);
800			ssc->ses_objmap[x.obj_id].svalid = 0;
801			mutex_exit(SES_MUTEX);
802		}
803		break;
804
805	case SESIOC_SETOBJSTAT:
806		if (ddi_copyin((void *)arg, &x, sizeof (x), flg)) {
807			rv = EFAULT;
808			break;
809		}
810		if (x.obj_id >= ssc->ses_nobjects) {
811			rv = EINVAL;
812			break;
813		}
814		rv = (*ssc->ses_vec.set_objstat)(ssc, &x, KM_SLEEP);
815		if (rv == 0) {
816			mutex_enter(SES_MUTEX);
817			ssc->ses_objmap[x.obj_id].svalid = 0;
818			mutex_exit(SES_MUTEX);
819		}
820		break;
821
822	case USCSICMD:
823		rv = ses_uscsi_cmd(ssc, (Uscmd *)arg, flg);
824		break;
825
826	default:
827		rv = ENOTTY;
828		break;
829	}
830	return (rv);
831}
832
833
834/*
835 * Loop on running a kernel based command
836 *
837 * FIXME:  This routine is not really needed.
838 */
839int
840ses_runcmd(ses_softc_t *ssc, Uscmd *lp)
841{
842	int e;
843
844	lp->uscsi_status = 0;
845	e = ses_uscsi_cmd(ssc, lp, FKIOCTL);
846
847#ifdef	not
848	/*
849	 * Debug:  Nice cross-check code for verifying consistent status.
850	 */
851	if (lp->uscsi_status) {
852		if (lp->uscsi_status == STATUS_CHECK) {
853			SES_LOG(ssc, CE_NOTE, "runcmd<cdb[0]="
854			    "0x%x->%s ASC/ASCQ=0x%x/0x%x>",
855			    lp->uscsi_cdb[0],
856			    scsi_sname(lp->uscsi_rqbuf[2] & 0xf),
857			    lp->uscsi_rqbuf[12] & 0xff,
858			    lp->uscsi_rqbuf[13] & 0xff);
859		} else {
860			SES_LOG(ssc, CE_NOTE, "runcmd<cdb[0]="
861			    "0x%x -> Status 0x%x", lp->uscsi_cdb[0],
862			    lp->uscsi_status);
863		}
864	}
865#endif	/* not */
866	return (e);
867}
868
869
870/*
871 * Run a scsi command.
872 */
873int
874ses_uscsi_cmd(ses_softc_t *ssc, Uscmd *Uc, int Uf)
875{
876	Uscmd	*uscmd;
877	struct buf	*bp;
878	enum uio_seg	uioseg;
879	int	err;
880
881	/*
882	 * Grab local 'special' buffer
883	 */
884	mutex_enter(SES_MUTEX);
885	while (ssc->ses_sbufbsy) {
886		cv_wait(&ssc->ses_sbufcv, &ssc->ses_devp->sd_mutex);
887	}
888	ssc->ses_sbufbsy = 1;
889	mutex_exit(SES_MUTEX);
890
891	/*
892	 * If the device is powered down, request it's activation.
893	 * This check must be done after setting ses_sbufbsy!
894	 */
895	if (ssc->ses_suspended &&
896	    ddi_dev_is_needed(SES_DEVINFO(ssc), 0, 1) != DDI_SUCCESS) {
897		mutex_enter(SES_MUTEX);
898		ssc->ses_sbufbsy = 0;
899		mutex_exit(SES_MUTEX);
900		return (EIO);
901	}
902
903	err = scsi_uscsi_alloc_and_copyin((intptr_t)Uc, Uf,
904	    SES_ROUTE(ssc), &uscmd);
905	if (err != 0) {
906		SES_LOG(ssc, SES_CE_DEBUG1, "ses_uscsi_cmd: "
907		    "scsi_uscsi_alloc_and_copyin failed\n");
908		mutex_enter(SES_MUTEX);
909		ssc->ses_sbufbsy = 0;
910		cv_signal(&ssc->ses_sbufcv);
911		mutex_exit(SES_MUTEX);
912		SES_LOG(ssc, SES_CE_DEBUG2, efl, __LINE__);
913		return (err);
914	}
915
916	/*
917	 * Copy the uscsi command related infos to ssc for use in ses_start()
918	 * and ses_callback().
919	 */
920	bcopy(uscmd, &ssc->ses_uscsicmd, sizeof (Uscmd));
921	if (uscmd->uscsi_cdb != NULL) {
922		bcopy(uscmd->uscsi_cdb, &ssc->ses_srqcdb,
923		    (size_t)(uscmd->uscsi_cdblen));
924	}
925	ssc->ses_uscsicmd.uscsi_status = 0;
926
927	bp = ssc->ses_sbufp;
928	bp->av_back = (struct buf *)NULL;
929	bp->av_forw = (struct buf *)NULL;
930	bp->b_back = (struct buf *)ssc;
931	bp->b_edev = NODEV;
932
933	if (uscmd->uscsi_cdb != NULL) {
934		if (uscmd->uscsi_cdblen == CDB_GROUP0) {
935			SES_LOG(ssc, SES_CE_DEBUG7,
936			    "scsi_cmd: %x %x %x %x %x %x",
937			    ((char *)uscmd->uscsi_cdb)[0],
938			    ((char *)uscmd->uscsi_cdb)[1],
939			    ((char *)uscmd->uscsi_cdb)[2],
940			    ((char *)uscmd->uscsi_cdb)[3],
941			    ((char *)uscmd->uscsi_cdb)[4],
942			    ((char *)uscmd->uscsi_cdb)[5]);
943		} else {
944			SES_LOG(ssc, SES_CE_DEBUG7,
945			    "scsi cmd: %x %x %x %x %x %x %x %x %x %x",
946			    ((char *)uscmd->uscsi_cdb)[0],
947			    ((char *)uscmd->uscsi_cdb)[1],
948			    ((char *)uscmd->uscsi_cdb)[2],
949			    ((char *)uscmd->uscsi_cdb)[3],
950			    ((char *)uscmd->uscsi_cdb)[4],
951			    ((char *)uscmd->uscsi_cdb)[5],
952			    ((char *)uscmd->uscsi_cdb)[6],
953			    ((char *)uscmd->uscsi_cdb)[7],
954			    ((char *)uscmd->uscsi_cdb)[8],
955			    ((char *)uscmd->uscsi_cdb)[9]);
956		}
957	}
958
959	uioseg = (Uf & FKIOCTL) ? UIO_SYSSPACE : UIO_USERSPACE;
960	err = scsi_uscsi_handle_cmd(NODEV, uioseg, uscmd,
961	    ses_start, bp, NULL);
962
963	/*
964	 * ses_callback() may set values for ssc->ses_uscsicmd or
965	 * ssc->ses_srqsbuf, so copy them back to uscmd.
966	 */
967	if (uscmd->uscsi_rqbuf != NULL) {
968		bcopy(&ssc->ses_srqsbuf, uscmd->uscsi_rqbuf,
969		    (size_t)(uscmd->uscsi_rqlen));
970		uscmd->uscsi_rqresid = ssc->ses_uscsicmd.uscsi_rqresid;
971	}
972	uscmd->uscsi_status = ssc->ses_uscsicmd.uscsi_status;
973
974	(void) scsi_uscsi_copyout_and_free((intptr_t)Uc, uscmd);
975	mutex_enter(SES_MUTEX);
976	ssc->ses_sbufbsy = 0;
977	cv_signal(&ssc->ses_sbufcv);
978	mutex_exit(SES_MUTEX);
979
980	return (err);
981}
982
983
984
985/*
986 * Command start and done functions.
987 */
988static int
989ses_start(struct buf *bp)
990{
991	ses_softc_t *ssc = (ses_softc_t *)bp->b_back;
992
993	SES_LOG(ssc, SES_CE_DEBUG9, "ses_start");
994	if (!BP_PKT(bp)) {
995		/*
996		 * Allocate a packet.
997		 */
998		ses_get_pkt(bp, SLEEP_FUNC);
999		if (!BP_PKT(bp)) {
1000			int err;
1001			bp->b_resid = bp->b_bcount;
1002			if (geterror(bp) == 0)
1003				SET_BP_ERROR(bp, EIO);
1004			err = geterror(bp);
1005			biodone(bp);
1006			return (err);
1007		}
1008	}
1009
1010	/*
1011	 * Initialize the transfer residue, error code, and retry count.
1012	 */
1013	bp->b_resid = 0;
1014	SET_BP_ERROR(bp, 0);
1015
1016#if	!defined(lint)
1017	_NOTE(NO_COMPETING_THREADS_NOW);
1018#endif 	/* !defined(lint) */
1019	ssc->ses_retries = ses_retry_count;
1020
1021#if	!defined(lint)
1022	/* LINTED */
1023	_NOTE(COMPETING_THREADS_NOW);
1024#endif	/* !defined(lint) */
1025
1026	SES_LOG(ssc, SES_CE_DEBUG9, "ses_start -> scsi_transport");
1027	switch (scsi_transport(BP_PKT(bp))) {
1028	case TRAN_ACCEPT:
1029		return (0);
1030		/* break; */
1031
1032	case TRAN_BUSY:
1033		SES_LOG(ssc, SES_CE_DEBUG2,
1034		    "ses_start: TRANSPORT BUSY");
1035		SES_ENABLE_RESTART(SES_RESTART_TIME, BP_PKT(bp));
1036		return (0);
1037		/* break; */
1038
1039	default:
1040		SES_LOG(ssc, SES_CE_DEBUG2, "TRANSPORT ERROR\n");
1041		SET_BP_ERROR(bp, EIO);
1042		scsi_destroy_pkt(BP_PKT(bp));
1043		SET_BP_PKT(bp, NULL);
1044		biodone(bp);
1045		return (EIO);
1046		/* break; */
1047	}
1048}
1049
1050
1051static void
1052ses_get_pkt(struct buf *bp, int (*func)())
1053{
1054	ses_softc_t *ssc = (ses_softc_t *)bp->b_back;
1055	Uscmd *scmd = &ssc->ses_uscsicmd;
1056	struct scsi_pkt *pkt;
1057	int stat_size = 1;
1058	int flags = 0;
1059
1060	if ((scmd->uscsi_flags & USCSI_RQENABLE) && ssc->ses_arq) {
1061		if (scmd->uscsi_rqlen > SENSE_LENGTH) {
1062			stat_size = (int)(scmd->uscsi_rqlen) +
1063			    sizeof (struct scsi_arq_status) -
1064			    sizeof (struct scsi_extended_sense);
1065			flags = PKT_XARQ;
1066		} else {
1067			stat_size = sizeof (struct scsi_arq_status);
1068		}
1069	}
1070
1071	if (bp->b_bcount) {
1072		pkt = scsi_init_pkt(SES_ROUTE(ssc), NULL, bp,
1073		    scmd->uscsi_cdblen, stat_size, 0, flags,
1074		    func, (caddr_t)ssc);
1075	} else {
1076		pkt = scsi_init_pkt(SES_ROUTE(ssc), NULL, NULL,
1077		    scmd->uscsi_cdblen, stat_size, 0, flags,
1078		    func, (caddr_t)ssc);
1079	}
1080	SET_BP_PKT(bp, pkt);
1081	if (pkt == (struct scsi_pkt *)NULL)
1082		return;
1083	bcopy(scmd->uscsi_cdb, pkt->pkt_cdbp, (size_t)scmd->uscsi_cdblen);
1084	pkt->pkt_time = scmd->uscsi_timeout;
1085
1086	pkt->pkt_comp = ses_callback;
1087	pkt->pkt_private = (opaque_t)ssc;
1088}
1089
1090
1091/*
1092 * Restart ses command.
1093 */
1094static void
1095ses_restart(void *arg)
1096{
1097	struct scsi_pkt *pkt = (struct scsi_pkt *)arg;
1098	ses_softc_t *ssc = (ses_softc_t *)pkt->pkt_private;
1099	struct buf *bp = ssc->ses_sbufp;
1100	SES_LOG(ssc, SES_CE_DEBUG9, "ses_restart");
1101
1102	ssc->ses_restart_id = NULL;
1103
1104	switch (scsi_transport(pkt)) {
1105	case TRAN_ACCEPT:
1106		SES_LOG(ssc, SES_CE_DEBUG9,
1107		    "RESTART %d ok", ssc->ses_retries);
1108		return;
1109		/* break; */
1110	case TRAN_BUSY:
1111		SES_LOG(ssc, SES_CE_DEBUG1,
1112		    "RESTART %d TRANSPORT BUSY\n", ssc->ses_retries);
1113		if (ssc->ses_retries > SES_NO_RETRY) {
1114			ssc->ses_retries -= SES_BUSY_RETRY;
1115			SES_ENABLE_RESTART(SES_RESTART_TIME, pkt);
1116			return;
1117		}
1118		SET_BP_ERROR(bp, EBUSY);
1119		break;
1120	default:
1121		SET_BP_ERROR(bp, EIO);
1122		break;
1123	}
1124	SES_LOG(ssc, SES_CE_DEBUG1,
1125	    "RESTART %d TRANSPORT FAILED\n", ssc->ses_retries);
1126
1127	pkt = (struct scsi_pkt *)bp->av_back;
1128	scsi_destroy_pkt(pkt);
1129	bp->b_resid = bp->b_bcount;
1130	SET_BP_PKT(bp, NULL);
1131	biodone(bp);
1132}
1133
1134
1135/*
1136 * Command completion processing
1137 */
1138#define	HBA_RESET	(STAT_BUS_RESET|STAT_DEV_RESET|STAT_ABORTED)
1139static void
1140ses_callback(struct scsi_pkt *pkt)
1141{
1142	ses_softc_t *ssc = (ses_softc_t *)pkt->pkt_private;
1143	struct buf *bp;
1144	Uscmd *scmd;
1145	int err;
1146	char action;
1147
1148	bp = ssc->ses_sbufp;
1149	scmd = &ssc->ses_uscsicmd;
1150	/* SES_LOG(ssc, SES_CE_DEBUG9, "ses_callback"); */
1151
1152	/*
1153	 * Optimization: Normal completion.
1154	 */
1155	if (pkt->pkt_reason == CMD_CMPLT &&
1156	    !SCBP_C(pkt) &&
1157	    !(pkt->pkt_flags & FLAG_SENSING) &&
1158	    !pkt->pkt_resid) {
1159		scsi_destroy_pkt(pkt);
1160		SET_BP_PKT(bp, NULL);
1161		biodone(bp);
1162		return;
1163	}
1164
1165
1166	/*
1167	 * Abnormal completion.
1168	 *
1169	 * Assume most common error initially.
1170	 */
1171	err = EIO;
1172	action = COMMAND_DONE;
1173	if (scmd->uscsi_flags & USCSI_DIAGNOSE) {
1174		ssc->ses_retries = SES_NO_RETRY;
1175	}
1176
1177CHECK_PKT:
1178	if (pkt->pkt_reason != CMD_CMPLT) {
1179		/* Process transport errors. */
1180		switch (pkt->pkt_reason) {
1181		case CMD_TIMEOUT:
1182			/*
1183			 * If the transport layer didn't clear the problem,
1184			 * reset the target.
1185			 */
1186			if (! (pkt->pkt_statistics & HBA_RESET)) {
1187				(void) scsi_reset(&pkt->pkt_address,
1188				    RESET_TARGET);
1189			}
1190			err = ETIMEDOUT;
1191			break;
1192
1193		case CMD_INCOMPLETE:
1194		case CMD_UNX_BUS_FREE:
1195			/*
1196			 * No response?  If probing, give up.
1197			 * Otherwise, keep trying until retries exhausted.
1198			 * Then lockdown the driver as the device is
1199			 * unplugged.
1200			 */
1201			if (ssc->ses_retries <= SES_NO_RETRY &&
1202			    !(scmd->uscsi_flags & USCSI_DIAGNOSE)) {
1203				ssc->ses_present = SES_CLOSED;
1204			}
1205			/* Inhibit retries to speed probe/attach. */
1206			if (ssc->ses_present < SES_OPEN) {
1207				ssc->ses_retries = SES_NO_RETRY;
1208			}
1209			/* SES_CMD_RETRY4(ssc->ses_retries); */
1210			err = ENXIO;
1211			break;
1212
1213		case CMD_DATA_OVR:
1214			/*
1215			 * XXX:	Some HBA's (e.g. Adaptec 1740 and
1216			 *	earlier ISP revs) report a DATA OVERRUN
1217			 *	error instead of a transfer residue.  So,
1218			 *	we convert the error and restart.
1219			 */
1220			if ((bp->b_bcount - pkt->pkt_resid) > 0) {
1221				SES_LOG(ssc, SES_CE_DEBUG6,
1222				    "ignoring overrun");
1223				pkt->pkt_reason = CMD_CMPLT;
1224				err = EOK;
1225				goto CHECK_PKT;
1226			}
1227			ssc->ses_retries = SES_NO_RETRY;
1228			/* err = EIO; */
1229			break;
1230
1231		case CMD_DMA_DERR:
1232			ssc->ses_retries = SES_NO_RETRY;
1233			err = EFAULT;
1234			break;
1235
1236		default:
1237			/* err = EIO; */
1238			break;
1239		}
1240		if (pkt == ssc->ses_rqpkt) {
1241			SES_LOG(ssc, CE_WARN, fail_msg,
1242			    "Request Sense ",
1243			    scsi_rname(pkt->pkt_reason),
1244			    (ssc->ses_retries > 0)?
1245			    "retrying": "giving up");
1246			pkt = (struct scsi_pkt *)bp->av_back;
1247			action = QUE_SENSE;
1248		} else {
1249			SES_LOG(ssc, CE_WARN, fail_msg,
1250			    "", scsi_rname(pkt->pkt_reason),
1251			    (ssc->ses_retries > 0)?
1252			    "retrying": "giving up");
1253			action = QUE_COMMAND;
1254		}
1255		/* Device exists, allow full error recovery. */
1256		if (ssc->ses_retries > SES_NO_RETRY) {
1257			ssc->ses_present = SES_OPEN;
1258		}
1259
1260
1261	/*
1262	 * Process status and sense data errors.
1263	 */
1264	} else {
1265		ssc->ses_present = SES_OPEN;
1266		action = ses_decode_sense(pkt, &err);
1267	}
1268
1269
1270	/*
1271	 * Initiate error recovery action, as needed.
1272	 */
1273	switch (action) {
1274	case QUE_COMMAND_NOW:
1275		/* SES_LOG(ssc, SES_CE_DEBUG1, "retrying cmd now"); */
1276		if (ssc->ses_retries > SES_NO_RETRY) {
1277			ssc->ses_retries -= SES_CMD_RETRY;
1278			scmd->uscsi_status = 0;
1279			if (ssc->ses_arq)
1280				bzero(pkt->pkt_scbp,
1281				    sizeof (struct scsi_arq_status));
1282
1283			if (scsi_transport((struct scsi_pkt *)bp->av_back)
1284			    != TRAN_ACCEPT) {
1285				SES_ENABLE_RESTART(SES_RESTART_TIME,
1286				    (struct scsi_pkt *)bp->av_back);
1287			}
1288			return;
1289		}
1290		break;
1291
1292	case QUE_COMMAND:
1293		SES_LOG(ssc, SES_CE_DEBUG1, "retrying cmd");
1294		if (ssc->ses_retries > SES_NO_RETRY) {
1295			ssc->ses_retries -=
1296			    (err == EBUSY)? SES_BUSY_RETRY: SES_CMD_RETRY;
1297			scmd->uscsi_status = 0;
1298			if (ssc->ses_arq)
1299				bzero(pkt->pkt_scbp,
1300				    sizeof (struct scsi_arq_status));
1301
1302			SES_ENABLE_RESTART(
1303			    (err == EBUSY)? SES_BUSY_TIME: SES_RESTART_TIME,
1304			    (struct scsi_pkt *)bp->av_back);
1305			return;
1306		}
1307		break;
1308
1309	case QUE_SENSE:
1310		SES_LOG(ssc, SES_CE_DEBUG1, "retrying sense");
1311		if (ssc->ses_retries > SES_NO_RETRY) {
1312			ssc->ses_retries -= SES_SENSE_RETRY;
1313			scmd->uscsi_status = 0;
1314			bzero(&ssc->ses_srqsbuf, MAX_SENSE_LENGTH);
1315
1316			if (scsi_transport(ssc->ses_rqpkt) != TRAN_ACCEPT) {
1317				SES_ENABLE_RESTART(SES_RESTART_TIME,
1318				    ssc->ses_rqpkt);
1319			}
1320			return;
1321		}
1322		break;
1323
1324	case COMMAND_DONE:
1325		SES_LOG(ssc, SES_CE_DEBUG4, "cmd done");
1326		pkt = (struct scsi_pkt *)bp->av_back;
1327		bp->b_resid = pkt->pkt_resid;
1328		if (bp->b_resid) {
1329			SES_LOG(ssc, SES_CE_DEBUG6,
1330			    "transfer residue %ld(%ld)",
1331			    bp->b_bcount - bp->b_resid, bp->b_bcount);
1332		}
1333		break;
1334	}
1335	pkt = (struct scsi_pkt *)bp->av_back;
1336	if (err) {
1337		SES_LOG(ssc, SES_CE_DEBUG1, "SES: ERROR %d\n", err);
1338		SET_BP_ERROR(bp, err);
1339		bp->b_resid = bp->b_bcount;
1340	}
1341	scsi_destroy_pkt(pkt);
1342	SET_BP_PKT(bp, NULL);
1343	biodone(bp);
1344}
1345
1346
1347/*
1348 * Check status and sense data and determine recovery.
1349 */
1350static int
1351ses_decode_sense(struct scsi_pkt *pkt, int *err)
1352{
1353	ses_softc_t *ssc = (ses_softc_t *)pkt->pkt_private;
1354	struct	scsi_extended_sense *sense =
1355	    (struct scsi_extended_sense *)&ssc->ses_srqsbuf;
1356	Uscmd *scmd = &ssc->ses_uscsicmd;
1357	char sense_flag = 0;
1358	uchar_t status = SCBP_C(pkt) & STATUS_MASK;
1359	char *err_action;
1360	char action;
1361	uchar_t rqlen;
1362	int amt;
1363
1364	/*
1365	 * Process manual request sense.
1366	 * Copy manual request sense to sense buffer.
1367	 *
1368	 * This is done if auto request sense is not enabled.
1369	 * Or the auto request sense failed and the request
1370	 * sense needs to be retried.
1371	 */
1372	if (pkt->pkt_flags & FLAG_SENSING) {
1373		struct buf *sbp = ssc->ses_rqbp;
1374		amt = min(MAX_SENSE_LENGTH,
1375		    sbp->b_bcount - sbp->b_resid);
1376		rqlen = min((uchar_t)amt, scmd->uscsi_rqlen);
1377		bcopy(sbp->b_un.b_addr, sense, rqlen);
1378		scmd->uscsi_rqresid = scmd->uscsi_rqlen - rqlen;
1379		sense_flag = 1;
1380	/*
1381	 * Process auto request sense.
1382	 * Copy auto request sense to sense buffer.
1383	 *
1384	 * If auto request sense failed due to transport error,
1385	 * retry the command.  Otherwise process the status and
1386	 * sense data.
1387	 */
1388	} else if (ssc->ses_arq && pkt->pkt_state & STATE_ARQ_DONE) {
1389		struct scsi_arq_status *arq =
1390		    (struct scsi_arq_status *)(pkt->pkt_scbp);
1391		uchar_t *arq_status = (uchar_t *)&arq->sts_rqpkt_status;
1392		if (pkt->pkt_state & STATE_XARQ_DONE) {
1393			amt = MAX_SENSE_LENGTH - arq->sts_rqpkt_resid;
1394		} else {
1395			if (arq->sts_rqpkt_resid > SENSE_LENGTH) {
1396				amt = MAX_SENSE_LENGTH - arq->sts_rqpkt_resid;
1397			} else {
1398				amt = SENSE_LENGTH - arq->sts_rqpkt_resid;
1399			}
1400		}
1401
1402		if (arq->sts_rqpkt_reason != CMD_CMPLT) {
1403			return (QUE_COMMAND);
1404		}
1405
1406		rqlen = min((uchar_t)amt, scmd->uscsi_rqlen);
1407		bcopy(&arq->sts_sensedata, sense, rqlen);
1408		scmd->uscsi_status = status;
1409		scmd->uscsi_rqresid = scmd->uscsi_rqlen - rqlen;
1410		status = *arq_status & STATUS_MASK;
1411		pkt->pkt_state &= ~STATE_ARQ_DONE;
1412		sense_flag = 1;
1413	}
1414
1415
1416	/*
1417	 * Check status of REQUEST SENSE or command.
1418	 *
1419	 * If it's not successful, try retrying the original command
1420	 * and hope that it goes away.  If not, we'll eventually run
1421	 * out of retries and die.
1422	 */
1423	switch (status) {
1424	case STATUS_GOOD:
1425	case STATUS_INTERMEDIATE:
1426	case STATUS_MET:
1427		/*
1428		 * If the command status is ok, we're done.
1429		 * Otherwise, examine the request sense data.
1430		 */
1431		if (! sense_flag) {
1432			*err = EOK;
1433			return (COMMAND_DONE);
1434		}
1435		break;
1436
1437	case STATUS_CHECK:
1438		SES_LOG(ssc, SES_CE_DEBUG3, "status decode: check");
1439		*err = EIO;
1440		return (QUE_SENSE);
1441		/* break; */
1442
1443	case STATUS_BUSY:
1444		SES_LOG(ssc, SES_CE_DEBUG1, "status decode: busy");
1445		/* SES_CMD_RETRY2(ssc->ses_retries); */
1446		*err = EBUSY;
1447		return (QUE_COMMAND);
1448		/* break; */
1449
1450	case STATUS_RESERVATION_CONFLICT:
1451		SES_LOG(ssc, SES_CE_DEBUG1, "status decode: reserved");
1452		*err = EACCES;
1453		return (COMMAND_DONE_ERROR);
1454		/* break; */
1455
1456	case STATUS_TERMINATED:
1457		SES_LOG(ssc, SES_CE_DEBUG1, "status decode: terminated");
1458		*err = ECANCELED;
1459		return (COMMAND_DONE_ERROR);
1460		/* break; */
1461
1462	default:
1463		SES_LOG(ssc, SES_CE_DEBUG1, "status 0x%x", status);
1464		*err = EIO;
1465		return (QUE_COMMAND);
1466		/* break; */
1467	}
1468
1469
1470	/*
1471	 * Check REQUEST SENSE error code.
1472	 *
1473	 * Either there's no error, a retryable error,
1474	 * or it's dead.  SES devices aren't very complex.
1475	 */
1476	err_action = "retrying";
1477	switch (sense->es_key) {
1478	case KEY_RECOVERABLE_ERROR:
1479		*err = EOK;
1480		err_action = "recovered";
1481		action = COMMAND_DONE;
1482		break;
1483
1484	case KEY_UNIT_ATTENTION:
1485		/*
1486		 * This is common for RAID!
1487		 */
1488		/* *err = EIO; */
1489		SES_CMD_RETRY1(ssc->ses_retries);
1490		action = QUE_COMMAND_NOW;
1491		break;
1492
1493	case KEY_NOT_READY:
1494	case KEY_NO_SENSE:
1495		/* *err = EIO; */
1496		action = QUE_COMMAND;
1497		break;
1498
1499	default:
1500		/* *err = EIO; */
1501		err_action = "fatal";
1502		action = COMMAND_DONE_ERROR;
1503		break;
1504	}
1505	SES_LOG(ssc, SES_CE_DEBUG1,
1506	    "cdb[0]= 0x%x %s,  key=0x%x, ASC/ASCQ=0x%x/0x%x",
1507	    scmd->uscsi_cdb[0], err_action,
1508	    sense->es_key, sense->es_add_code, sense->es_qual_code);
1509
1510#ifdef 	not
1511	/*
1512	 * Dump cdb and sense data stat's for manufacturing.
1513	 */
1514	if (DEBUGGING_ERR || sd_error_level == SDERR_ALL) {
1515		auto buf[128];
1516
1517		p = pkt->pkt_cdbp;
1518		if ((j = scsi_cdb_size[CDB_GROUPID(*p)]) == 0)
1519			j = CDB_SIZE;
1520
1521		/* Print cdb */
1522		(void) sprintf(buf, "cmd:");
1523		for (i = 0; i < j; i++) {
1524			(void) sprintf(&buf[strlen(buf)],
1525			    hex, (uchar_t)*p++);
1526		}
1527		SES_LOG(ssc, SES_CE_DEBUG3, "%s", buf);
1528
1529		/* Suppress trailing zero's in sense data */
1530		if (amt > 3) {
1531			p = (char *)devp->sd_sense + amt;
1532			for (j = amt; j > 3; j--) {
1533				if (*(--p))  break;
1534			}
1535		} else {
1536			j = amt;
1537		}
1538
1539		/* Print sense data. */
1540		(void) sprintf(buf, "sense:");
1541		p = (char *)devp->sd_sense;
1542		for (i = 0; i < j; i++) {
1543			(void) sprintf(&buf[strlen(buf)],
1544			    hex, (uchar_t)*p++);
1545		}
1546		SES_LOG(ssc, SES_CE_DEBUG3, "%s", buf);
1547	}
1548#endif 	/* not */
1549	return (action);
1550}
1551
1552
1553/*PRINTFLIKE3*/
1554void
1555ses_log(ses_softc_t *ssc, int level, const char *fmt, ...)
1556{
1557	va_list	ap;
1558	char buf[256];
1559
1560	va_start(ap, fmt);
1561	(void) vsprintf(buf, fmt, ap);
1562	va_end(ap);
1563
1564	if (ssc == (ses_softc_t *)NULL) {
1565		switch (level) {
1566		case SES_CE_DEBUG1:
1567			if (ses_debug > 1)
1568				cmn_err(CE_NOTE, "%s", buf);
1569			break;
1570		case SES_CE_DEBUG2:
1571			if (ses_debug > 2)
1572				cmn_err(CE_NOTE, "%s", buf);
1573			break;
1574		case SES_CE_DEBUG3:
1575			if (ses_debug > 3)
1576				cmn_err(CE_NOTE, "%s", buf);
1577			break;
1578		case SES_CE_DEBUG4:
1579			if (ses_debug > 4)
1580				cmn_err(CE_NOTE, "%s", buf);
1581			break;
1582		case SES_CE_DEBUG5:
1583			if (ses_debug > 5)
1584				cmn_err(CE_NOTE, "%s", buf);
1585			break;
1586		case SES_CE_DEBUG6:
1587			if (ses_debug > 6)
1588				cmn_err(CE_NOTE, "%s", buf);
1589			break;
1590		case SES_CE_DEBUG7:
1591			if (ses_debug > 7)
1592				cmn_err(CE_NOTE, "%s", buf);
1593			break;
1594		case SES_CE_DEBUG8:
1595			if (ses_debug > 8)
1596				cmn_err(CE_NOTE, "%s", buf);
1597			break;
1598		case SES_CE_DEBUG9:
1599			if (ses_debug > 9)
1600				cmn_err(CE_NOTE, "%s", buf);
1601			break;
1602		case CE_NOTE:
1603		case CE_WARN:
1604		case CE_PANIC:
1605			cmn_err(level, "%s", buf);
1606			break;
1607		case SES_CE_DEBUG:
1608		default:
1609			cmn_err(CE_NOTE, "%s", buf);
1610		break;
1611		}
1612		return;
1613	}
1614
1615	switch (level) {
1616	case CE_CONT:
1617	case CE_NOTE:
1618	case CE_WARN:
1619	case CE_PANIC:
1620		scsi_log(SES_DEVINFO(ssc), (char *)Snm, level, Str, buf);
1621		break;
1622	case SES_CE_DEBUG1:
1623		if (ses_debug > 1)
1624			scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG,
1625			    Str, buf);
1626		break;
1627	case SES_CE_DEBUG2:
1628		if (ses_debug > 2)
1629			scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG,
1630			    Str, buf);
1631		break;
1632	case SES_CE_DEBUG3:
1633		if (ses_debug > 3)
1634			scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG,
1635			    Str, buf);
1636		break;
1637	case SES_CE_DEBUG4:
1638		if (ses_debug > 4)
1639			scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG,
1640			    Str, buf);
1641		break;
1642	case SES_CE_DEBUG5:
1643		if (ses_debug > 5)
1644			scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG,
1645			    Str, buf);
1646		break;
1647	case SES_CE_DEBUG6:
1648		if (ses_debug > 6)
1649			scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG,
1650			    Str, buf);
1651		break;
1652	case SES_CE_DEBUG7:
1653		if (ses_debug > 7)
1654			scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG,
1655			    Str, buf);
1656		break;
1657	case SES_CE_DEBUG8:
1658		if (ses_debug > 8)
1659			scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG,
1660			    Str, buf);
1661		break;
1662	case SES_CE_DEBUG9:
1663		if (ses_debug > 9)
1664			scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG,
1665			    Str, buf);
1666		break;
1667	case SES_CE_DEBUG:
1668	default:
1669		scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG, Str, buf);
1670		break;
1671	}
1672}
1673/*
1674 * mode: c
1675 * Local variables:
1676 * c-indent-level: 8
1677 * c-brace-imaginary-offset: 0
1678 * c-brace-offset: -8
1679 * c-argdecl-indent: 8
1680 * c-label-offset: -8
1681 * c-continued-statement-offset: 8
1682 * c-continued-brace-offset: 0
1683 * End:
1684 */
1685