xref: /illumos-gate/usr/src/uts/common/io/scsi/targets/ses.c (revision bf82a41b)
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  */
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 	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  */
980 static int
981 ses_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 
1043 static void
1044 ses_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  */
1078 static void
1079 ses_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)
1123 static void
1124 ses_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 		scsi_destroy_pkt(pkt);
1144 		SET_BP_PKT(bp, NULL);
1145 		biodone(bp);
1146 		return;
1147 	}
1148 
1149 
1150 	/*
1151 	 * Abnormal completion.
1152 	 *
1153 	 * Assume most common error initially.
1154 	 */
1155 	err = EIO;
1156 	action = COMMAND_DONE;
1157 	if (scmd->uscsi_flags & USCSI_DIAGNOSE) {
1158 		ssc->ses_retries = SES_NO_RETRY;
1159 	}
1160 
1161 CHECK_PKT:
1162 	if (pkt->pkt_reason != CMD_CMPLT) {
1163 		/* Process transport errors. */
1164 		switch (pkt->pkt_reason) {
1165 		case CMD_TIMEOUT:
1166 			/*
1167 			 * If the transport layer didn't clear the problem,
1168 			 * reset the target.
1169 			 */
1170 			if (! (pkt->pkt_statistics & HBA_RESET)) {
1171 				(void) scsi_reset(&pkt->pkt_address,
1172 				    RESET_TARGET);
1173 			}
1174 			err = ETIMEDOUT;
1175 			break;
1176 
1177 		case CMD_INCOMPLETE:
1178 		case CMD_UNX_BUS_FREE:
1179 			/*
1180 			 * No response?  If probing, give up.
1181 			 * Otherwise, keep trying until retries exhausted.
1182 			 * Then lockdown the driver as the device is
1183 			 * unplugged.
1184 			 */
1185 			if (ssc->ses_retries <= SES_NO_RETRY &&
1186 			    !(scmd->uscsi_flags & USCSI_DIAGNOSE)) {
1187 				ssc->ses_present = SES_CLOSED;
1188 			}
1189 			/* Inhibit retries to speed probe/attach. */
1190 			if (ssc->ses_present < SES_OPEN) {
1191 				ssc->ses_retries = SES_NO_RETRY;
1192 			}
1193 			/* SES_CMD_RETRY4(ssc->ses_retries); */
1194 			err = ENXIO;
1195 			break;
1196 
1197 		case CMD_DATA_OVR:
1198 			/*
1199 			 * XXX:	Some HBA's (e.g. Adaptec 1740 and
1200 			 *	earlier ISP revs) report a DATA OVERRUN
1201 			 *	error instead of a transfer residue.  So,
1202 			 *	we convert the error and restart.
1203 			 */
1204 			if ((bp->b_bcount - pkt->pkt_resid) > 0) {
1205 				SES_LOG(ssc, SES_CE_DEBUG6,
1206 				    "ignoring overrun");
1207 				pkt->pkt_reason = CMD_CMPLT;
1208 				err = EOK;
1209 				goto CHECK_PKT;
1210 			}
1211 			ssc->ses_retries = SES_NO_RETRY;
1212 			/* err = EIO; */
1213 			break;
1214 
1215 		case CMD_DMA_DERR:
1216 			ssc->ses_retries = SES_NO_RETRY;
1217 			err = EFAULT;
1218 			break;
1219 
1220 		default:
1221 			/* err = EIO; */
1222 			break;
1223 		}
1224 		if (pkt == ssc->ses_rqpkt) {
1225 			SES_LOG(ssc, CE_WARN, fail_msg,
1226 			    "Request Sense ",
1227 			    scsi_rname(pkt->pkt_reason),
1228 			    (ssc->ses_retries > 0)?
1229 			    "retrying": "giving up");
1230 			pkt = (struct scsi_pkt *)bp->av_back;
1231 			action = QUE_SENSE;
1232 		} else {
1233 			SES_LOG(ssc, CE_WARN, fail_msg,
1234 			    "", scsi_rname(pkt->pkt_reason),
1235 			    (ssc->ses_retries > 0)?
1236 			    "retrying": "giving up");
1237 			action = QUE_COMMAND;
1238 		}
1239 		/* Device exists, allow full error recovery. */
1240 		if (ssc->ses_retries > SES_NO_RETRY) {
1241 			ssc->ses_present = SES_OPEN;
1242 		}
1243 
1244 
1245 	/*
1246 	 * Process status and sense data errors.
1247 	 */
1248 	} else {
1249 		ssc->ses_present = SES_OPEN;
1250 		action = ses_decode_sense(pkt, &err);
1251 	}
1252 
1253 
1254 	/*
1255 	 * Initiate error recovery action, as needed.
1256 	 */
1257 	switch (action) {
1258 	case QUE_COMMAND_NOW:
1259 		/* SES_LOG(ssc, SES_CE_DEBUG1, "retrying cmd now"); */
1260 		if (ssc->ses_retries > SES_NO_RETRY) {
1261 			ssc->ses_retries -= SES_CMD_RETRY;
1262 			scmd->uscsi_status = 0;
1263 			if (ssc->ses_arq)
1264 				bzero(pkt->pkt_scbp,
1265 				    sizeof (struct scsi_arq_status));
1266 
1267 			if (scsi_transport((struct scsi_pkt *)bp->av_back)
1268 			    != TRAN_ACCEPT) {
1269 				SES_ENABLE_RESTART(SES_RESTART_TIME,
1270 				    (struct scsi_pkt *)bp->av_back);
1271 			}
1272 			return;
1273 		}
1274 		break;
1275 
1276 	case QUE_COMMAND:
1277 		SES_LOG(ssc, SES_CE_DEBUG1, "retrying cmd");
1278 		if (ssc->ses_retries > SES_NO_RETRY) {
1279 			ssc->ses_retries -=
1280 			    (err == EBUSY)? SES_BUSY_RETRY: SES_CMD_RETRY;
1281 			scmd->uscsi_status = 0;
1282 			if (ssc->ses_arq)
1283 				bzero(pkt->pkt_scbp,
1284 				    sizeof (struct scsi_arq_status));
1285 
1286 			SES_ENABLE_RESTART(
1287 			    (err == EBUSY)? SES_BUSY_TIME: SES_RESTART_TIME,
1288 			    (struct scsi_pkt *)bp->av_back);
1289 			return;
1290 		}
1291 		break;
1292 
1293 	case QUE_SENSE:
1294 		SES_LOG(ssc, SES_CE_DEBUG1, "retrying sense");
1295 		if (ssc->ses_retries > SES_NO_RETRY) {
1296 			ssc->ses_retries -= SES_SENSE_RETRY;
1297 			scmd->uscsi_status = 0;
1298 			bzero(&ssc->ses_srqsbuf,
1299 			    sizeof (struct scsi_extended_sense));
1300 
1301 			if (scsi_transport(ssc->ses_rqpkt) != TRAN_ACCEPT) {
1302 				SES_ENABLE_RESTART(SES_RESTART_TIME,
1303 				    ssc->ses_rqpkt);
1304 			}
1305 			return;
1306 		}
1307 		break;
1308 
1309 	case COMMAND_DONE:
1310 		SES_LOG(ssc, SES_CE_DEBUG4, "cmd done");
1311 		pkt = (struct scsi_pkt *)bp->av_back;
1312 		bp->b_resid = pkt->pkt_resid;
1313 		if (bp->b_resid) {
1314 			SES_LOG(ssc, SES_CE_DEBUG6,
1315 			    "transfer residue %ld(%ld)",
1316 			    bp->b_bcount - bp->b_resid, bp->b_bcount);
1317 		}
1318 		break;
1319 	}
1320 	pkt = (struct scsi_pkt *)bp->av_back;
1321 	if (err) {
1322 		SES_LOG(ssc, SES_CE_DEBUG1, "SES: ERROR %d\n", err);
1323 		SET_BP_ERROR(bp, err);
1324 		bp->b_resid = bp->b_bcount;
1325 	}
1326 	scsi_destroy_pkt(pkt);
1327 	SET_BP_PKT(bp, NULL);
1328 	biodone(bp);
1329 }
1330 
1331 
1332 /*
1333  * Check status and sense data and determine recovery.
1334  */
1335 static int
1336 ses_decode_sense(struct scsi_pkt *pkt, int *err)
1337 {
1338 	ses_softc_t *ssc = (ses_softc_t *)pkt->pkt_private;
1339 	struct	scsi_extended_sense *sense =
1340 	    (struct scsi_extended_sense *)&ssc->ses_srqsbuf;
1341 	Uscmd *scmd = &ssc->ses_uscsicmd;
1342 	char sense_flag = 0;
1343 	uchar_t status = SCBP_C(pkt) & STATUS_MASK;
1344 	char *err_action;
1345 	char action;
1346 
1347 	/*
1348 	 * Process manual request sense.
1349 	 * Copy manual request sense to sense buffer.
1350 	 *
1351 	 * This is done if auto request sense is not enabled.
1352 	 * Or the auto request sense failed and the request
1353 	 * sense needs to be retried.
1354 	 */
1355 	if (pkt->pkt_flags & FLAG_SENSING) {
1356 		struct buf *sbp = ssc->ses_rqbp;
1357 		int amt = min(SENSE_LENGTH,
1358 		    sbp->b_bcount - sbp->b_resid);
1359 
1360 		bcopy(sbp->b_un.b_addr, sense, amt);
1361 		scmd->uscsi_rqresid = scmd->uscsi_rqlen - amt;
1362 		sense_flag = 1;
1363 
1364 	/*
1365 	 * Process auto request sense.
1366 	 * Copy auto request sense to sense buffer.
1367 	 *
1368 	 * If auto request sense failed due to transport error,
1369 	 * retry the command.  Otherwise process the status and
1370 	 * sense data.
1371 	 */
1372 	} else if (ssc->ses_arq && pkt->pkt_state & STATE_ARQ_DONE) {
1373 		struct scsi_arq_status *arq =
1374 		    (struct scsi_arq_status *)(pkt->pkt_scbp);
1375 		int amt = min(sizeof (arq->sts_sensedata), SENSE_LENGTH);
1376 		uchar_t *arq_status = (uchar_t *)&arq->sts_rqpkt_status;
1377 
1378 		if (arq->sts_rqpkt_reason != CMD_CMPLT) {
1379 			return (QUE_COMMAND);
1380 		}
1381 		bcopy(&arq->sts_sensedata, sense, amt);
1382 		scmd->uscsi_status = status;
1383 		scmd->uscsi_rqresid = scmd->uscsi_rqlen - amt;
1384 		status = *arq_status & STATUS_MASK;
1385 		pkt->pkt_state &= ~STATE_ARQ_DONE;
1386 		sense_flag = 1;
1387 	}
1388 
1389 
1390 	/*
1391 	 * Check status of REQUEST SENSE or command.
1392 	 *
1393 	 * If it's not successful, try retrying the original command
1394 	 * and hope that it goes away.  If not, we'll eventually run
1395 	 * out of retries and die.
1396 	 */
1397 	switch (status) {
1398 	case STATUS_GOOD:
1399 	case STATUS_INTERMEDIATE:
1400 	case STATUS_MET:
1401 		/*
1402 		 * If the command status is ok, we're done.
1403 		 * Otherwise, examine the request sense data.
1404 		 */
1405 		if (! sense_flag) {
1406 			*err = EOK;
1407 			return (COMMAND_DONE);
1408 		}
1409 		break;
1410 
1411 	case STATUS_CHECK:
1412 		SES_LOG(ssc, SES_CE_DEBUG3, "status decode: check");
1413 		*err = EIO;
1414 		return (QUE_SENSE);
1415 		/* break; */
1416 
1417 	case STATUS_BUSY:
1418 		SES_LOG(ssc, SES_CE_DEBUG1, "status decode: busy");
1419 		/* SES_CMD_RETRY2(ssc->ses_retries); */
1420 		*err = EBUSY;
1421 		return (QUE_COMMAND);
1422 		/* break; */
1423 
1424 	case STATUS_RESERVATION_CONFLICT:
1425 		SES_LOG(ssc, SES_CE_DEBUG1, "status decode: reserved");
1426 		*err = EACCES;
1427 		return (COMMAND_DONE_ERROR);
1428 		/* break; */
1429 
1430 	case STATUS_TERMINATED:
1431 		SES_LOG(ssc, SES_CE_DEBUG1, "status decode: terminated");
1432 		*err = ECANCELED;
1433 		return (COMMAND_DONE_ERROR);
1434 		/* break; */
1435 
1436 	default:
1437 		SES_LOG(ssc, SES_CE_DEBUG1, "status 0x%x", status);
1438 		*err = EIO;
1439 		return (QUE_COMMAND);
1440 		/* break; */
1441 	}
1442 
1443 
1444 	/*
1445 	 * Check REQUEST SENSE error code.
1446 	 *
1447 	 * Either there's no error, a retryable error,
1448 	 * or it's dead.  SES devices aren't very complex.
1449 	 */
1450 	err_action = "retrying";
1451 	switch (sense->es_key) {
1452 	case KEY_RECOVERABLE_ERROR:
1453 		*err = EOK;
1454 		err_action = "recovered";
1455 		action = COMMAND_DONE;
1456 		break;
1457 
1458 	case KEY_UNIT_ATTENTION:
1459 		/*
1460 		 * This is common for RAID!
1461 		 */
1462 		/* *err = EIO; */
1463 		SES_CMD_RETRY1(ssc->ses_retries);
1464 		action = QUE_COMMAND_NOW;
1465 		break;
1466 
1467 	case KEY_NOT_READY:
1468 	case KEY_NO_SENSE:
1469 		/* *err = EIO; */
1470 		action = QUE_COMMAND;
1471 		break;
1472 
1473 	default:
1474 		/* *err = EIO; */
1475 		err_action = "fatal";
1476 		action = COMMAND_DONE_ERROR;
1477 		break;
1478 	}
1479 	SES_LOG(ssc, SES_CE_DEBUG1,
1480 	    "cdb[0]= 0x%x %s,  key=0x%x, ASC/ASCQ=0x%x/0x%x",
1481 	    scmd->uscsi_cdb[0], err_action,
1482 	    sense->es_key, sense->es_add_code, sense->es_qual_code);
1483 
1484 #ifdef 	not
1485 	/*
1486 	 * Dump cdb and sense data stat's for manufacturing.
1487 	 */
1488 	if (DEBUGGING_ERR || sd_error_level == SDERR_ALL) {
1489 		auto buf[128];
1490 
1491 		p = pkt->pkt_cdbp;
1492 		if ((j = scsi_cdb_size[CDB_GROUPID(*p)]) == 0)
1493 			j = CDB_SIZE;
1494 
1495 		/* Print cdb */
1496 		(void) sprintf(buf, "cmd:");
1497 		for (i = 0; i < j; i++) {
1498 			(void) sprintf(&buf[strlen(buf)],
1499 			    hex, (uchar_t)*p++);
1500 		}
1501 		SES_LOG(ssc, SES_CE_DEBUG3, "%s", buf);
1502 
1503 		/* Suppress trailing zero's in sense data */
1504 		if (amt > 3) {
1505 			p = (char *)devp->sd_sense + amt;
1506 			for (j = amt; j > 3; j--) {
1507 				if (*(--p))  break;
1508 			}
1509 		} else {
1510 			j = amt;
1511 		}
1512 
1513 		/* Print sense data. */
1514 		(void) sprintf(buf, "sense:");
1515 		p = (char *)devp->sd_sense;
1516 		for (i = 0; i < j; i++) {
1517 			(void) sprintf(&buf[strlen(buf)],
1518 			    hex, (uchar_t)*p++);
1519 		}
1520 		SES_LOG(ssc, SES_CE_DEBUG3, "%s", buf);
1521 	}
1522 #endif 	/* not */
1523 	return (action);
1524 }
1525 
1526 
1527 /*PRINTFLIKE3*/
1528 void
1529 ses_log(ses_softc_t *ssc, int level, const char *fmt, ...)
1530 {
1531 	va_list	ap;
1532 	char buf[256];
1533 
1534 	va_start(ap, fmt);
1535 	(void) vsprintf(buf, fmt, ap);
1536 	va_end(ap);
1537 
1538 	if (ssc == (ses_softc_t *)NULL) {
1539 		switch (level) {
1540 		case SES_CE_DEBUG1:
1541 			if (ses_debug > 1)
1542 				cmn_err(CE_NOTE, "%s", buf);
1543 			break;
1544 		case SES_CE_DEBUG2:
1545 			if (ses_debug > 2)
1546 				cmn_err(CE_NOTE, "%s", buf);
1547 			break;
1548 		case SES_CE_DEBUG3:
1549 			if (ses_debug > 3)
1550 				cmn_err(CE_NOTE, "%s", buf);
1551 			break;
1552 		case SES_CE_DEBUG4:
1553 			if (ses_debug > 4)
1554 				cmn_err(CE_NOTE, "%s", buf);
1555 			break;
1556 		case SES_CE_DEBUG5:
1557 			if (ses_debug > 5)
1558 				cmn_err(CE_NOTE, "%s", buf);
1559 			break;
1560 		case SES_CE_DEBUG6:
1561 			if (ses_debug > 6)
1562 				cmn_err(CE_NOTE, "%s", buf);
1563 			break;
1564 		case SES_CE_DEBUG7:
1565 			if (ses_debug > 7)
1566 				cmn_err(CE_NOTE, "%s", buf);
1567 			break;
1568 		case SES_CE_DEBUG8:
1569 			if (ses_debug > 8)
1570 				cmn_err(CE_NOTE, "%s", buf);
1571 			break;
1572 		case SES_CE_DEBUG9:
1573 			if (ses_debug > 9)
1574 				cmn_err(CE_NOTE, "%s", buf);
1575 			break;
1576 		case CE_NOTE:
1577 		case CE_WARN:
1578 		case CE_PANIC:
1579 			cmn_err(level, "%s", buf);
1580 			break;
1581 		case SES_CE_DEBUG:
1582 		default:
1583 			cmn_err(CE_NOTE, "%s", buf);
1584 		break;
1585 		}
1586 		return;
1587 	}
1588 
1589 	switch (level) {
1590 	case CE_CONT:
1591 	case CE_NOTE:
1592 	case CE_WARN:
1593 	case CE_PANIC:
1594 		scsi_log(SES_DEVINFO(ssc), (char *)Snm, level, Str, buf);
1595 		break;
1596 	case SES_CE_DEBUG1:
1597 		if (ses_debug > 1)
1598 			scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG,
1599 			    Str, buf);
1600 		break;
1601 	case SES_CE_DEBUG2:
1602 		if (ses_debug > 2)
1603 			scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG,
1604 			    Str, buf);
1605 		break;
1606 	case SES_CE_DEBUG3:
1607 		if (ses_debug > 3)
1608 			scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG,
1609 			    Str, buf);
1610 		break;
1611 	case SES_CE_DEBUG4:
1612 		if (ses_debug > 4)
1613 			scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG,
1614 			    Str, buf);
1615 		break;
1616 	case SES_CE_DEBUG5:
1617 		if (ses_debug > 5)
1618 			scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG,
1619 			    Str, buf);
1620 		break;
1621 	case SES_CE_DEBUG6:
1622 		if (ses_debug > 6)
1623 			scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG,
1624 			    Str, buf);
1625 		break;
1626 	case SES_CE_DEBUG7:
1627 		if (ses_debug > 7)
1628 			scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG,
1629 			    Str, buf);
1630 		break;
1631 	case SES_CE_DEBUG8:
1632 		if (ses_debug > 8)
1633 			scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG,
1634 			    Str, buf);
1635 		break;
1636 	case SES_CE_DEBUG9:
1637 		if (ses_debug > 9)
1638 			scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG,
1639 			    Str, buf);
1640 		break;
1641 	case SES_CE_DEBUG:
1642 	default:
1643 		scsi_log(SES_DEVINFO(ssc), (char *)Snm, SCSI_DEBUG, Str, buf);
1644 		break;
1645 	}
1646 }
1647 /*
1648  * mode: c
1649  * Local variables:
1650  * c-indent-level: 8
1651  * c-brace-imaginary-offset: 0
1652  * c-brace-offset: -8
1653  * c-argdecl-indent: 8
1654  * c-label-offset: -8
1655  * c-continued-statement-offset: 8
1656  * c-continued-brace-offset: 0
1657  * End:
1658  */
1659