xref: /titanic_50/usr/src/uts/common/io/scsi/targets/ses.c (revision 3611c1369d2adaeab19117370e92b6ed23cb8efe)
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 2007 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  */
48 int ses_io_time = SES_IO_TIME;
49 
50 static int ses_retry_count = SES_RETRY_COUNT * SES_RETRY_MULTIPLIER;
51 
52 #ifdef	DEBUG
53 int ses_debug = 0;
54 #else	/* DEBUG */
55 #define	ses_debug	0
56 #endif	/* DEBUG */
57 
58 
59 /*
60  * External Enclosure Functions
61  */
62 extern int ses_softc_init(ses_softc_t *, int);
63 extern int ses_init_enc(ses_softc_t *);
64 extern int ses_get_encstat(ses_softc_t *, int);
65 extern int ses_set_encstat(ses_softc_t *, uchar_t, int);
66 extern int ses_get_objstat(ses_softc_t *, ses_objarg *, int);
67 extern int ses_set_objstat(ses_softc_t *, ses_objarg *, int);
68 
69 extern int safte_softc_init(ses_softc_t *, int);
70 extern int safte_init_enc(ses_softc_t *);
71 extern int safte_get_encstat(ses_softc_t *, int);
72 extern int safte_set_encstat(ses_softc_t *, uchar_t, int);
73 extern int safte_get_objstat(ses_softc_t *, ses_objarg *, int);
74 extern int safte_set_objstat(ses_softc_t *, ses_objarg *, int);
75 
76 extern int sen_softc_init(ses_softc_t *, int);
77 extern int sen_init_enc(ses_softc_t *);
78 extern int sen_get_encstat(ses_softc_t *, int);
79 extern int sen_set_encstat(ses_softc_t *, uchar_t, int);
80 extern int sen_get_objstat(ses_softc_t *, ses_objarg *, int);
81 extern int sen_set_objstat(ses_softc_t *, ses_objarg *, int);
82 
83 /*
84  * Local Function prototypes
85  */
86 static int ses_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
87 static int ses_probe(dev_info_t *);
88 static int ses_attach(dev_info_t *, ddi_attach_cmd_t);
89 static int ses_detach(dev_info_t *, ddi_detach_cmd_t);
90 
91 static int is_enc_dev(ses_softc_t *, struct scsi_inquiry *, int, enctyp *);
92 static int ses_doattach(dev_info_t *dip);
93 
94 static int  ses_open(dev_t *, int, int, cred_t *);
95 static int  ses_close(dev_t, int, int, cred_t *);
96 static int  ses_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
97 
98 static 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  */
117 static int ses_start(struct buf *bp);
118 static int ses_decode_sense(struct scsi_pkt *pkt, int *err);
119 
120 static void ses_get_pkt(struct buf *bp, int (*func)(opaque_t));
121 static void ses_callback(struct scsi_pkt *pkt);
122 static 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 
132 static 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 
157 static 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 
171 static void *estate  = NULL;
172 static const char *Snm = "ses";
173 static const char *Str = "%s\n";
174 static const char *efl = "copyin/copyout EFAULT @ line %d";
175 static const char *fail_msg = "%stransport failed: reason '%s': %s";
176 
177 
178 
179 /*
180  * autoconfiguration routines.
181  */
182 char _depends_on[] = "misc/scsi";
183 
184 static struct modldrv modldrv = {
185 	&mod_driverops, "SCSI Enclosure Services %I%", &ses_dev_ops
186 };
187 
188 static struct modlinkage modlinkage = {
189 	MODREV_1, &modldrv, NULL
190 };
191 
192 
193 int
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 
206 int
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 
217 int
218 _info(struct modinfo *modinfop)
219 {
220 	return (mod_info(&modlinkage, modinfop));
221 }
222 
223 static int
224 ses_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 
280 static int
281 ses_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 
316 static int
317 is_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  */
365 static int
366 ses_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  */
544 static int
545 ses_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 */
614 static int
615 ses_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 */
648 static int
649 ses_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*/
678 static int
679 ses_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*/
701 static int
702 ses_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  */
831 int
832 ses_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  */
865 int
866 ses_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 
918 	bp = ssc->ses_sbufp;
919 	bp->av_back = (struct buf *)NULL;
920 	bp->av_forw = (struct buf *)NULL;
921 	bp->b_back = (struct buf *)ssc;
922 	bp->b_edev = NODEV;
923 
924 	if (uscmd->uscsi_cdb != NULL) {
925 		if (uscmd->uscsi_cdblen == CDB_GROUP0) {
926 			SES_LOG(ssc, SES_CE_DEBUG7,
927 			    "scsi_cmd: %x %x %x %x %x %x",
928 			    ((char *)uscmd->uscsi_cdb)[0],
929 			    ((char *)uscmd->uscsi_cdb)[1],
930 			    ((char *)uscmd->uscsi_cdb)[2],
931 			    ((char *)uscmd->uscsi_cdb)[3],
932 			    ((char *)uscmd->uscsi_cdb)[4],
933 			    ((char *)uscmd->uscsi_cdb)[5]);
934 		} else {
935 			SES_LOG(ssc, SES_CE_DEBUG7,
936 			    "scsi cmd: %x %x %x %x %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 			    ((char *)uscmd->uscsi_cdb)[6],
944 			    ((char *)uscmd->uscsi_cdb)[7],
945 			    ((char *)uscmd->uscsi_cdb)[8],
946 			    ((char *)uscmd->uscsi_cdb)[9]);
947 		}
948 	}
949 
950 	uioseg = (Uf & FKIOCTL) ? UIO_SYSSPACE : UIO_USERSPACE;
951 	err = scsi_uscsi_handle_cmd(NODEV, uioseg, uscmd,
952 	    ses_start, bp, NULL);
953 
954 	/*
955 	 * ses_callback() may set values for ssc->ses_uscsicmd or
956 	 * ssc->ses_srqsbuf, so copy them back to uscmd.
957 	 */
958 	if (uscmd->uscsi_rqbuf != NULL) {
959 		bcopy(&ssc->ses_srqsbuf, uscmd->uscsi_rqbuf,
960 		    (size_t)(uscmd->uscsi_rqlen));
961 		uscmd->uscsi_rqresid = ssc->ses_uscsicmd.uscsi_rqresid;
962 	}
963 	uscmd->uscsi_status = ssc->ses_uscsicmd.uscsi_status;
964 
965 	(void) scsi_uscsi_copyout_and_free((intptr_t)Uc, uscmd);
966 	mutex_enter(SES_MUTEX);
967 	ssc->ses_sbufbsy = 0;
968 	cv_signal(&ssc->ses_sbufcv);
969 	mutex_exit(SES_MUTEX);
970 
971 	return (err);
972 }
973 
974 
975 
976 /*
977  * Command start and done functions.
978  */
979 static int
980 ses_start(struct buf *bp)
981 {
982 	ses_softc_t *ssc = (ses_softc_t *)bp->b_back;
983 
984 	SES_LOG(ssc, SES_CE_DEBUG9, "ses_start");
985 	if (!BP_PKT(bp)) {
986 		/*
987 		 * Allocate a packet.
988 		 */
989 		ses_get_pkt(bp, SLEEP_FUNC);
990 		if (!BP_PKT(bp)) {
991 			int err;
992 			bp->b_resid = bp->b_bcount;
993 			if (geterror(bp) == 0)
994 				SET_BP_ERROR(bp, EIO);
995 			err = geterror(bp);
996 			biodone(bp);
997 			return (err);
998 		}
999 	}
1000 
1001 	/*
1002 	 * Initialize the transfer residue, error code, and retry count.
1003 	 */
1004 	bp->b_resid = 0;
1005 	SET_BP_ERROR(bp, 0);
1006 
1007 #if	!defined(lint)
1008 	_NOTE(NO_COMPETING_THREADS_NOW);
1009 #endif 	/* !defined(lint) */
1010 	ssc->ses_retries = ses_retry_count;
1011 
1012 #if	!defined(lint)
1013 	/* LINTED */
1014 	_NOTE(COMPETING_THREADS_NOW);
1015 #endif	/* !defined(lint) */
1016 
1017 	SES_LOG(ssc, SES_CE_DEBUG9, "ses_start -> scsi_transport");
1018 	switch (scsi_transport(BP_PKT(bp))) {
1019 	case TRAN_ACCEPT:
1020 		return (0);
1021 		/* break; */
1022 
1023 	case TRAN_BUSY:
1024 		SES_LOG(ssc, SES_CE_DEBUG2,
1025 			"ses_start: TRANSPORT BUSY");
1026 		SES_ENABLE_RESTART(SES_RESTART_TIME, BP_PKT(bp));
1027 		return (0);
1028 		/* break; */
1029 
1030 	default:
1031 		SES_LOG(ssc, SES_CE_DEBUG2, "TRANSPORT ERROR\n");
1032 		SET_BP_ERROR(bp, EIO);
1033 		scsi_destroy_pkt(BP_PKT(bp));
1034 		SET_BP_PKT(bp, NULL);
1035 		biodone(bp);
1036 		return (EIO);
1037 		/* break; */
1038 	}
1039 }
1040 
1041 
1042 static void
1043 ses_get_pkt(struct buf *bp, int (*func)())
1044 {
1045 	ses_softc_t *ssc = (ses_softc_t *)bp->b_back;
1046 	Uscmd *scmd = &ssc->ses_uscsicmd;
1047 	struct scsi_pkt *pkt;
1048 	int stat_size;
1049 
1050 	if ((scmd->uscsi_flags & USCSI_RQENABLE) && ssc->ses_arq) {
1051 		stat_size = sizeof (struct scsi_arq_status);
1052 	} else {
1053 		stat_size = 1;
1054 	}
1055 
1056 	if (bp->b_bcount) {
1057 		pkt = scsi_init_pkt(SES_ROUTE(ssc), NULL, bp,
1058 		    scmd->uscsi_cdblen, stat_size, 0, 0, func, (caddr_t)ssc);
1059 	} else {
1060 		pkt = scsi_init_pkt(SES_ROUTE(ssc), NULL, NULL,
1061 		    scmd->uscsi_cdblen, stat_size, 0, 0, func, (caddr_t)ssc);
1062 	}
1063 	SET_BP_PKT(bp, pkt);
1064 	if (pkt == (struct scsi_pkt *)NULL)
1065 		return;
1066 	bcopy(scmd->uscsi_cdb, pkt->pkt_cdbp, (size_t)scmd->uscsi_cdblen);
1067 	pkt->pkt_time = scmd->uscsi_timeout;
1068 
1069 	pkt->pkt_comp = ses_callback;
1070 	pkt->pkt_private = (opaque_t)ssc;
1071 }
1072 
1073 
1074 /*
1075  * Restart ses command.
1076  */
1077 static void
1078 ses_restart(void *arg)
1079 {
1080 	struct scsi_pkt *pkt = (struct scsi_pkt *)arg;
1081 	ses_softc_t *ssc = (ses_softc_t *)pkt->pkt_private;
1082 	struct buf *bp = ssc->ses_sbufp;
1083 	SES_LOG(ssc, SES_CE_DEBUG9, "ses_restart");
1084 
1085 	ssc->ses_restart_id = NULL;
1086 
1087 	switch (scsi_transport(pkt)) {
1088 	case TRAN_ACCEPT:
1089 		SES_LOG(ssc, SES_CE_DEBUG9,
1090 		    "RESTART %d ok", ssc->ses_retries);
1091 		return;
1092 		/* break; */
1093 	case TRAN_BUSY:
1094 		SES_LOG(ssc, SES_CE_DEBUG1,
1095 		    "RESTART %d TRANSPORT BUSY\n", ssc->ses_retries);
1096 		if (ssc->ses_retries > SES_NO_RETRY) {
1097 		    ssc->ses_retries -= SES_BUSY_RETRY;
1098 		    SES_ENABLE_RESTART(SES_RESTART_TIME, pkt);
1099 		    return;
1100 		}
1101 		SET_BP_ERROR(bp, EBUSY);
1102 		break;
1103 	default:
1104 		SET_BP_ERROR(bp, EIO);
1105 		break;
1106 	}
1107 	SES_LOG(ssc, SES_CE_DEBUG1,
1108 	    "RESTART %d TRANSPORT FAILED\n", ssc->ses_retries);
1109 
1110 	pkt = (struct scsi_pkt *)bp->av_back;
1111 	scsi_destroy_pkt(pkt);
1112 	bp->b_resid = bp->b_bcount;
1113 	SET_BP_PKT(bp, NULL);
1114 	biodone(bp);
1115 }
1116 
1117 
1118 /*
1119  * Command completion processing
1120  */
1121 #define	HBA_RESET	(STAT_BUS_RESET|STAT_DEV_RESET|STAT_ABORTED)
1122 static void
1123 ses_callback(struct scsi_pkt *pkt)
1124 {
1125 	ses_softc_t *ssc = (ses_softc_t *)pkt->pkt_private;
1126 	struct buf *bp;
1127 	Uscmd *scmd;
1128 	int err;
1129 	char action;
1130 
1131 	bp = ssc->ses_sbufp;
1132 	scmd = &ssc->ses_uscsicmd;
1133 	/* SES_LOG(ssc, SES_CE_DEBUG9, "ses_callback"); */
1134 
1135 	/*
1136 	 * Optimization: Normal completion.
1137 	 */
1138 	if (pkt->pkt_reason == CMD_CMPLT &&
1139 	    !SCBP_C(pkt) &&
1140 	    !(pkt->pkt_flags & FLAG_SENSING) &&
1141 	    !pkt->pkt_resid) {
1142 	    scsi_destroy_pkt(pkt);
1143 	    SET_BP_PKT(bp, NULL);
1144 	    biodone(bp);
1145 	    return;
1146 	}
1147 
1148 
1149 	/*
1150 	 * Abnormal completion.
1151 	 *
1152 	 * Assume most common error initially.
1153 	 */
1154 	err = EIO;
1155 	action = COMMAND_DONE;
1156 	if (scmd->uscsi_flags & USCSI_DIAGNOSE) {
1157 		ssc->ses_retries = SES_NO_RETRY;
1158 	}
1159 
1160 CHECK_PKT:
1161 	if (pkt->pkt_reason != CMD_CMPLT) {
1162 		/* Process transport errors. */
1163 		switch (pkt->pkt_reason) {
1164 		case CMD_TIMEOUT:
1165 			/*
1166 			 * If the transport layer didn't clear the problem,
1167 			 * reset the target.
1168 			 */
1169 			if (! (pkt->pkt_statistics & HBA_RESET)) {
1170 			    (void) scsi_reset(&pkt->pkt_address, RESET_TARGET);
1171 			}
1172 			err = ETIMEDOUT;
1173 			break;
1174 
1175 		case CMD_INCOMPLETE:
1176 		case CMD_UNX_BUS_FREE:
1177 			/*
1178 			 * No response?  If probing, give up.
1179 			 * Otherwise, keep trying until retries exhausted.
1180 			 * Then lockdown the driver as the device is
1181 			 * unplugged.
1182 			 */
1183 			if (ssc->ses_retries <= SES_NO_RETRY &&
1184 			    !(scmd->uscsi_flags & USCSI_DIAGNOSE)) {
1185 				ssc->ses_present = SES_CLOSED;
1186 			}
1187 			/* Inhibit retries to speed probe/attach. */
1188 			if (ssc->ses_present < SES_OPEN) {
1189 				ssc->ses_retries = SES_NO_RETRY;
1190 			}
1191 			/* SES_CMD_RETRY4(ssc->ses_retries); */
1192 			err = ENXIO;
1193 			break;
1194 
1195 		case CMD_DATA_OVR:
1196 			/*
1197 			 * XXX:	Some HBA's (e.g. Adaptec 1740 and
1198 			 *	earlier ISP revs) report a DATA OVERRUN
1199 			 *	error instead of a transfer residue.  So,
1200 			 *	we convert the error and restart.
1201 			 */
1202 			if ((bp->b_bcount - pkt->pkt_resid) > 0) {
1203 				SES_LOG(ssc, SES_CE_DEBUG6,
1204 					"ignoring overrun");
1205 				pkt->pkt_reason = CMD_CMPLT;
1206 				err = EOK;
1207 				goto CHECK_PKT;
1208 			}
1209 			ssc->ses_retries = SES_NO_RETRY;
1210 			/* err = EIO; */
1211 			break;
1212 
1213 		case CMD_DMA_DERR:
1214 			ssc->ses_retries = SES_NO_RETRY;
1215 			err = EFAULT;
1216 			break;
1217 
1218 		default:
1219 			/* err = EIO; */
1220 			break;
1221 		}
1222 		if (pkt == ssc->ses_rqpkt) {
1223 			SES_LOG(ssc, CE_WARN, fail_msg,
1224 				"Request Sense ",
1225 				scsi_rname(pkt->pkt_reason),
1226 				(ssc->ses_retries > 0)?
1227 					"retrying": "giving up");
1228 			pkt = (struct scsi_pkt *)bp->av_back;
1229 			action = QUE_SENSE;
1230 		} else {
1231 			SES_LOG(ssc, CE_WARN, fail_msg,
1232 				"", scsi_rname(pkt->pkt_reason),
1233 				(ssc->ses_retries > 0)?
1234 					"retrying": "giving up");
1235 			action = QUE_COMMAND;
1236 		}
1237 		/* Device exists, allow full error recovery. */
1238 		if (ssc->ses_retries > SES_NO_RETRY) {
1239 			ssc->ses_present = SES_OPEN;
1240 		}
1241 
1242 
1243 	/*
1244 	 * Process status and sense data errors.
1245 	 */
1246 	} else {
1247 		ssc->ses_present = SES_OPEN;
1248 		action = ses_decode_sense(pkt, &err);
1249 	}
1250 
1251 
1252 	/*
1253 	 * Initiate error recovery action, as needed.
1254 	 */
1255 	switch (action) {
1256 	case QUE_COMMAND_NOW:
1257 		/* SES_LOG(ssc, SES_CE_DEBUG1, "retrying cmd now"); */
1258 		if (ssc->ses_retries > SES_NO_RETRY) {
1259 		    ssc->ses_retries -= SES_CMD_RETRY;
1260 		    scmd->uscsi_status = 0;
1261 		    if (ssc->ses_arq)
1262 			bzero(pkt->pkt_scbp, sizeof (struct scsi_arq_status));
1263 
1264 		    if (scsi_transport((struct scsi_pkt *)bp->av_back)
1265 			!= TRAN_ACCEPT) {
1266 			SES_ENABLE_RESTART(SES_RESTART_TIME,
1267 				(struct scsi_pkt *)bp->av_back);
1268 		    }
1269 		    return;
1270 		}
1271 		break;
1272 
1273 	case QUE_COMMAND:
1274 		SES_LOG(ssc, SES_CE_DEBUG1, "retrying cmd");
1275 		if (ssc->ses_retries > SES_NO_RETRY) {
1276 		    ssc->ses_retries -=
1277 			(err == EBUSY)? SES_BUSY_RETRY: SES_CMD_RETRY;
1278 		    scmd->uscsi_status = 0;
1279 		    if (ssc->ses_arq)
1280 			bzero(pkt->pkt_scbp, sizeof (struct scsi_arq_status));
1281 
1282 		    SES_ENABLE_RESTART(
1283 			(err == EBUSY)? SES_BUSY_TIME: SES_RESTART_TIME,
1284 			(struct scsi_pkt *)bp->av_back);
1285 		    return;
1286 		}
1287 		break;
1288 
1289 	case QUE_SENSE:
1290 		SES_LOG(ssc, SES_CE_DEBUG1, "retrying sense");
1291 		if (ssc->ses_retries > SES_NO_RETRY) {
1292 			ssc->ses_retries -= SES_SENSE_RETRY;
1293 			scmd->uscsi_status = 0;
1294 			bzero(&ssc->ses_srqsbuf,
1295 			    sizeof (struct scsi_extended_sense));
1296 
1297 			if (scsi_transport(ssc->ses_rqpkt) != TRAN_ACCEPT) {
1298 				SES_ENABLE_RESTART(SES_RESTART_TIME,
1299 				    ssc->ses_rqpkt);
1300 			}
1301 		    return;
1302 		}
1303 		break;
1304 
1305 	case COMMAND_DONE:
1306 		SES_LOG(ssc, SES_CE_DEBUG4, "cmd done");
1307 		pkt = (struct scsi_pkt *)bp->av_back;
1308 		bp->b_resid = pkt->pkt_resid;
1309 		if (bp->b_resid) {
1310 		    SES_LOG(ssc, SES_CE_DEBUG6,
1311 			"transfer residue %ld(%ld)",
1312 			bp->b_bcount - bp->b_resid, bp->b_bcount);
1313 		}
1314 		break;
1315 	}
1316 	pkt = (struct scsi_pkt *)bp->av_back;
1317 	if (err) {
1318 		SES_LOG(ssc, SES_CE_DEBUG1, "SES: ERROR %d\n", err);
1319 		SET_BP_ERROR(bp, err);
1320 		bp->b_resid = bp->b_bcount;
1321 	}
1322 	scsi_destroy_pkt(pkt);
1323 	SET_BP_PKT(bp, NULL);
1324 	biodone(bp);
1325 }
1326 
1327 
1328 /*
1329  * Check status and sense data and determine recovery.
1330  */
1331 static int
1332 ses_decode_sense(struct scsi_pkt *pkt, int *err)
1333 {
1334 	ses_softc_t *ssc = (ses_softc_t *)pkt->pkt_private;
1335 	struct	scsi_extended_sense *sense =
1336 	    (struct scsi_extended_sense *)&ssc->ses_srqsbuf;
1337 	Uscmd *scmd = &ssc->ses_uscsicmd;
1338 	char sense_flag = 0;
1339 	uchar_t status = SCBP_C(pkt) & STATUS_MASK;
1340 	char *err_action;
1341 	char action;
1342 
1343 	/*
1344 	 * Process manual request sense.
1345 	 * Copy manual request sense to sense buffer.
1346 	 *
1347 	 * This is done if auto request sense is not enabled.
1348 	 * Or the auto request sense failed and the request
1349 	 * sense needs to be retried.
1350 	 */
1351 	if (pkt->pkt_flags & FLAG_SENSING) {
1352 		struct buf *sbp = ssc->ses_rqbp;
1353 		int amt = min(SENSE_LENGTH,
1354 		    sbp->b_bcount - sbp->b_resid);
1355 
1356 		bcopy(sbp->b_un.b_addr, sense, amt);
1357 		scmd->uscsi_rqresid = scmd->uscsi_rqlen - amt;
1358 		sense_flag = 1;
1359 
1360 	/*
1361 	 * Process auto request sense.
1362 	 * Copy auto request sense to sense buffer.
1363 	 *
1364 	 * If auto request sense failed due to transport error,
1365 	 * retry the command.  Otherwise process the status and
1366 	 * sense data.
1367 	 */
1368 	} else if (ssc->ses_arq && pkt->pkt_state & STATE_ARQ_DONE) {
1369 		struct scsi_arq_status *arq =
1370 			(struct scsi_arq_status *)(pkt->pkt_scbp);
1371 		int amt = min(sizeof (arq->sts_sensedata), SENSE_LENGTH);
1372 		uchar_t *arq_status = (uchar_t *)&arq->sts_rqpkt_status;
1373 
1374 		if (arq->sts_rqpkt_reason != CMD_CMPLT) {
1375 			return (QUE_COMMAND);
1376 		}
1377 		bcopy(&arq->sts_sensedata, sense, amt);
1378 		scmd->uscsi_status = status;
1379 		scmd->uscsi_rqresid = scmd->uscsi_rqlen - amt;
1380 		status = *arq_status & STATUS_MASK;
1381 		pkt->pkt_state &= ~STATE_ARQ_DONE;
1382 		sense_flag = 1;
1383 	}
1384 
1385 
1386 	/*
1387 	 * Check status of REQUEST SENSE or command.
1388 	 *
1389 	 * If it's not successful, try retrying the original command
1390 	 * and hope that it goes away.  If not, we'll eventually run
1391 	 * out of retries and die.
1392 	 */
1393 	switch (status) {
1394 	case STATUS_GOOD:
1395 	case STATUS_INTERMEDIATE:
1396 	case STATUS_MET:
1397 		/*
1398 		 * If the command status is ok, we're done.
1399 		 * Otherwise, examine the request sense data.
1400 		 */
1401 		if (! sense_flag) {
1402 			*err = EOK;
1403 			return (COMMAND_DONE);
1404 		}
1405 		break;
1406 
1407 	case STATUS_CHECK:
1408 		SES_LOG(ssc, SES_CE_DEBUG3, "status decode: check");
1409 		*err = EIO;
1410 		return (QUE_SENSE);
1411 		/* break; */
1412 
1413 	case STATUS_BUSY:
1414 		SES_LOG(ssc, SES_CE_DEBUG1, "status decode: busy");
1415 		/* SES_CMD_RETRY2(ssc->ses_retries); */
1416 		*err = EBUSY;
1417 		return (QUE_COMMAND);
1418 		/* break; */
1419 
1420 	case STATUS_RESERVATION_CONFLICT:
1421 		SES_LOG(ssc, SES_CE_DEBUG1, "status decode: reserved");
1422 		*err = EACCES;
1423 		return (COMMAND_DONE_ERROR);
1424 		/* break; */
1425 
1426 	case STATUS_TERMINATED:
1427 		SES_LOG(ssc, SES_CE_DEBUG1, "status decode: terminated");
1428 		*err = ECANCELED;
1429 		return (COMMAND_DONE_ERROR);
1430 		/* break; */
1431 
1432 	default:
1433 		SES_LOG(ssc, SES_CE_DEBUG1, "status 0x%x", status);
1434 		*err = EIO;
1435 		return (QUE_COMMAND);
1436 		/* break; */
1437 	}
1438 
1439 
1440 	/*
1441 	 * Check REQUEST SENSE error code.
1442 	 *
1443 	 * Either there's no error, a retryable error,
1444 	 * or it's dead.  SES devices aren't very complex.
1445 	 */
1446 	err_action = "retrying";
1447 	switch (sense->es_key) {
1448 	case KEY_RECOVERABLE_ERROR:
1449 		*err = EOK;
1450 		err_action = "recovered";
1451 		action = COMMAND_DONE;
1452 		break;
1453 
1454 	case KEY_UNIT_ATTENTION:
1455 		/*
1456 		 * This is common for RAID!
1457 		 */
1458 		/* *err = EIO; */
1459 		SES_CMD_RETRY1(ssc->ses_retries);
1460 		action = QUE_COMMAND_NOW;
1461 		break;
1462 
1463 	case KEY_NOT_READY:
1464 	case KEY_NO_SENSE:
1465 		/* *err = EIO; */
1466 		action = QUE_COMMAND;
1467 		break;
1468 
1469 	default:
1470 		/* *err = EIO; */
1471 		err_action = "fatal";
1472 		action = COMMAND_DONE_ERROR;
1473 		break;
1474 	}
1475 	SES_LOG(ssc, SES_CE_DEBUG1,
1476 		"cdb[0]= 0x%x %s,  key=0x%x, ASC/ASCQ=0x%x/0x%x",
1477 		scmd->uscsi_cdb[0], err_action,
1478 		sense->es_key, sense->es_add_code, sense->es_qual_code);
1479 
1480 #ifdef 	not
1481 	/*
1482 	 * Dump cdb and sense data stat's for manufacturing.
1483 	 */
1484 	if (DEBUGGING_ERR || sd_error_level == SDERR_ALL) {
1485 		auto buf[128];
1486 
1487 		p = pkt->pkt_cdbp;
1488 		if ((j = scsi_cdb_size[CDB_GROUPID(*p)]) == 0)
1489 			j = CDB_SIZE;
1490 
1491 		/* Print cdb */
1492 		(void) sprintf(buf, "cmd:");
1493 		for (i = 0; i < j; i++) {
1494 			(void) sprintf(&buf[strlen(buf)],
1495 			    hex, (uchar_t)*p++);
1496 		}
1497 		SES_LOG(ssc, SES_CE_DEBUG3, "%s", buf);
1498 
1499 		/* Suppress trailing zero's in sense data */
1500 		if (amt > 3) {
1501 			p = (char *)devp->sd_sense + amt;
1502 			for (j = amt; j > 3; j--) {
1503 				if (*(--p))  break;
1504 			}
1505 		} else {
1506 			j = amt;
1507 		}
1508 
1509 		/* Print sense data. */
1510 		(void) sprintf(buf, "sense:");
1511 		p = (char *)devp->sd_sense;
1512 		for (i = 0; i < j; i++) {
1513 			(void) sprintf(&buf[strlen(buf)],
1514 			    hex, (uchar_t)*p++);
1515 		}
1516 		SES_LOG(ssc, SES_CE_DEBUG3, "%s", buf);
1517 	}
1518 #endif 	/* not */
1519 	return (action);
1520 }
1521 
1522 
1523 /*PRINTFLIKE3*/
1524 void
1525 ses_log(ses_softc_t *ssc, int level, const char *fmt, ...)
1526 {
1527 	va_list	ap;
1528 	char buf[256];
1529 
1530 	va_start(ap, fmt);
1531 	(void) vsprintf(buf, fmt, ap);
1532 	va_end(ap);
1533 
1534 	if (ssc == (ses_softc_t *)NULL) {
1535 		switch (level) {
1536 		case SES_CE_DEBUG1:
1537 			if (ses_debug > 1)
1538 				cmn_err(CE_NOTE, "%s", buf);
1539 			break;
1540 		case SES_CE_DEBUG2:
1541 			if (ses_debug > 2)
1542 				cmn_err(CE_NOTE, "%s", buf);
1543 			break;
1544 		case SES_CE_DEBUG3:
1545 			if (ses_debug > 3)
1546 				cmn_err(CE_NOTE, "%s", buf);
1547 			break;
1548 		case SES_CE_DEBUG4:
1549 			if (ses_debug > 4)
1550 				cmn_err(CE_NOTE, "%s", buf);
1551 			break;
1552 		case SES_CE_DEBUG5:
1553 			if (ses_debug > 5)
1554 				cmn_err(CE_NOTE, "%s", buf);
1555 			break;
1556 		case SES_CE_DEBUG6:
1557 			if (ses_debug > 6)
1558 				cmn_err(CE_NOTE, "%s", buf);
1559 			break;
1560 		case SES_CE_DEBUG7:
1561 			if (ses_debug > 7)
1562 				cmn_err(CE_NOTE, "%s", buf);
1563 			break;
1564 		case SES_CE_DEBUG8:
1565 			if (ses_debug > 8)
1566 				cmn_err(CE_NOTE, "%s", buf);
1567 			break;
1568 		case SES_CE_DEBUG9:
1569 			if (ses_debug > 9)
1570 				cmn_err(CE_NOTE, "%s", buf);
1571 			break;
1572 		case CE_NOTE:
1573 		case CE_WARN:
1574 		case CE_PANIC:
1575 			cmn_err(level, "%s", buf);
1576 			break;
1577 		case SES_CE_DEBUG:
1578 		default:
1579 			cmn_err(CE_NOTE, "%s", buf);
1580 		break;
1581 		}
1582 		return;
1583 	}
1584 
1585 	switch (level) {
1586 	case CE_CONT:
1587 	case CE_NOTE:
1588 	case CE_WARN:
1589 	case CE_PANIC:
1590 		scsi_log(SES_DEVINFO(ssc), (char *)Snm, level, Str, buf);
1591 		break;
1592 	case SES_CE_DEBUG1:
1593 		if (ses_debug > 1)
1594 			scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG,
1595 			    Str, buf);
1596 		break;
1597 	case SES_CE_DEBUG2:
1598 		if (ses_debug > 2)
1599 			scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG,
1600 			    Str, buf);
1601 		break;
1602 	case SES_CE_DEBUG3:
1603 		if (ses_debug > 3)
1604 			scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG,
1605 			    Str, buf);
1606 		break;
1607 	case SES_CE_DEBUG4:
1608 		if (ses_debug > 4)
1609 			scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG,
1610 			    Str, buf);
1611 		break;
1612 	case SES_CE_DEBUG5:
1613 		if (ses_debug > 5)
1614 			scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG,
1615 			    Str, buf);
1616 		break;
1617 	case SES_CE_DEBUG6:
1618 		if (ses_debug > 6)
1619 			scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG,
1620 			    Str, buf);
1621 		break;
1622 	case SES_CE_DEBUG7:
1623 		if (ses_debug > 7)
1624 			scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG,
1625 			    Str, buf);
1626 		break;
1627 	case SES_CE_DEBUG8:
1628 		if (ses_debug > 8)
1629 			scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG,
1630 			    Str, buf);
1631 		break;
1632 	case SES_CE_DEBUG9:
1633 		if (ses_debug > 9)
1634 			scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG,
1635 			    Str, buf);
1636 		break;
1637 	case SES_CE_DEBUG:
1638 	default:
1639 		scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG, Str, buf);
1640 		break;
1641 	}
1642 }
1643 /*
1644  * mode: c
1645  * Local variables:
1646  * c-indent-level: 8
1647  * c-brace-imaginary-offset: 0
1648  * c-brace-offset: -8
1649  * c-argdecl-indent: 8
1650  * c-label-offset: -8
1651  * c-continued-statement-offset: 8
1652  * c-continued-brace-offset: 0
1653  * End:
1654  */
1655