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