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