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