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