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