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