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