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