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 /*
23 * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2022 Garrett D'Amore
25 */
26
27 #include <sys/scsi/scsi.h>
28 #include <sys/file.h>
29
30 /*
31 * Utility SCSI routines
32 */
33
34 /*
35 * Polling support routines
36 */
37
38 int scsi_pkt_allow_naca = 0;
39 extern uintptr_t scsi_callback_id;
40
41 extern uchar_t scsi_cdb_size[];
42
43 /*
44 * Common buffer for scsi_log
45 */
46
47 extern kmutex_t scsi_log_mutex;
48 static char scsi_log_buffer[MAXPATHLEN + 1];
49
50
51 #define A_TO_TRAN(ap) (ap->a_hba_tran)
52 #define P_TO_TRAN(pkt) ((pkt)->pkt_address.a_hba_tran)
53 #define P_TO_ADDR(pkt) (&((pkt)->pkt_address))
54
55 #define CSEC 10000 /* usecs */
56 #define SEC_TO_CSEC (1000000/CSEC)
57
58 extern ddi_dma_attr_t scsi_alloc_attr;
59
60 /*PRINTFLIKE4*/
61 static void impl_scsi_log(dev_info_t *dev, char *label, uint_t level,
62 const char *fmt, ...) __KPRINTFLIKE(4);
63 /*PRINTFLIKE4*/
64 static void v_scsi_log(dev_info_t *dev, char *label, uint_t level,
65 const char *fmt, va_list ap) __KVPRINTFLIKE(4);
66
67 static int
68 scsi_get_next_descr(uint8_t *sdsp,
69 int sense_buf_len, struct scsi_descr_template **descrpp);
70
71 #define DESCR_GOOD 0
72 #define DESCR_PARTIAL 1
73 #define DESCR_END 2
74
75 static int
76 scsi_validate_descr(struct scsi_descr_sense_hdr *sdsp,
77 int valid_sense_length, struct scsi_descr_template *descrp);
78
79 int
scsi_poll(struct scsi_pkt * pkt)80 scsi_poll(struct scsi_pkt *pkt)
81 {
82 int rval = -1;
83 int savef;
84 long savet;
85 void (*savec)();
86 int timeout;
87 int busy_count;
88 int poll_delay;
89 int rc;
90 uint8_t *sensep;
91 struct scsi_arq_status *arqstat;
92 extern int do_polled_io;
93
94 ASSERT(pkt->pkt_scbp);
95
96 /*
97 * save old flags..
98 */
99 savef = pkt->pkt_flags;
100 savec = pkt->pkt_comp;
101 savet = pkt->pkt_time;
102
103 pkt->pkt_flags |= FLAG_NOINTR;
104
105 /*
106 * XXX there is nothing in the SCSA spec that states that we should not
107 * do a callback for polled cmds; however, removing this will break sd
108 * and probably other target drivers
109 */
110 pkt->pkt_comp = NULL;
111
112 /*
113 * we don't like a polled command without timeout.
114 * 60 seconds seems long enough.
115 */
116 if (pkt->pkt_time == 0)
117 pkt->pkt_time = SCSI_POLL_TIMEOUT;
118
119 /*
120 * Send polled cmd.
121 *
122 * We do some error recovery for various errors. Tran_busy,
123 * queue full, and non-dispatched commands are retried every 10 msec.
124 * as they are typically transient failures. Busy status and Not
125 * Ready are retried every second as this status takes a while to
126 * change.
127 */
128 timeout = pkt->pkt_time * SEC_TO_CSEC;
129
130 for (busy_count = 0; busy_count < timeout; busy_count++) {
131 /*
132 * Initialize pkt status variables.
133 */
134 *pkt->pkt_scbp = pkt->pkt_reason = pkt->pkt_state = 0;
135
136 if ((rc = scsi_transport(pkt)) != TRAN_ACCEPT) {
137 if (rc != TRAN_BUSY) {
138 /* Transport failed - give up. */
139 break;
140 } else {
141 /* Transport busy - try again. */
142 poll_delay = 1 * CSEC; /* 10 msec. */
143 }
144 } else {
145 /*
146 * Transport accepted - check pkt status.
147 */
148 rc = (*pkt->pkt_scbp) & STATUS_MASK;
149 if ((pkt->pkt_reason == CMD_CMPLT) &&
150 (rc == STATUS_CHECK) &&
151 (pkt->pkt_state & STATE_ARQ_DONE)) {
152 arqstat =
153 (struct scsi_arq_status *)(pkt->pkt_scbp);
154 sensep = (uint8_t *)&arqstat->sts_sensedata;
155 } else {
156 sensep = NULL;
157 }
158
159 if ((pkt->pkt_reason == CMD_CMPLT) &&
160 (rc == STATUS_GOOD)) {
161 /* No error - we're done */
162 rval = 0;
163 break;
164
165 } else if (pkt->pkt_reason == CMD_DEV_GONE) {
166 /* Lost connection - give up */
167 break;
168
169 } else if ((pkt->pkt_reason == CMD_INCOMPLETE) &&
170 (pkt->pkt_state == 0)) {
171 /* Pkt not dispatched - try again. */
172 poll_delay = 1 * CSEC; /* 10 msec. */
173
174 } else if ((pkt->pkt_reason == CMD_CMPLT) &&
175 (rc == STATUS_QFULL)) {
176 /* Queue full - try again. */
177 poll_delay = 1 * CSEC; /* 10 msec. */
178
179 } else if ((pkt->pkt_reason == CMD_CMPLT) &&
180 (rc == STATUS_BUSY)) {
181 /* Busy - try again. */
182 poll_delay = 100 * CSEC; /* 1 sec. */
183 busy_count += (SEC_TO_CSEC - 1);
184
185 } else if ((sensep != NULL) &&
186 (scsi_sense_key(sensep) == KEY_NOT_READY) &&
187 (scsi_sense_asc(sensep) == 0x04) &&
188 (scsi_sense_ascq(sensep) == 0x01)) {
189 /*
190 * Not ready -> ready - try again.
191 * 04h/01h: LUN IS IN PROCESS OF BECOMING READY
192 * ...same as STATUS_BUSY
193 */
194 poll_delay = 100 * CSEC; /* 1 sec. */
195 busy_count += (SEC_TO_CSEC - 1);
196
197 } else {
198 /* BAD status - give up. */
199 break;
200 }
201 }
202
203 if (((curthread->t_flag & T_INTR_THREAD) == 0) &&
204 !do_polled_io) {
205 delay(drv_usectohz(poll_delay));
206 } else {
207 /* we busy wait during cpr_dump or interrupt threads */
208 drv_usecwait(poll_delay);
209 }
210 }
211
212 pkt->pkt_flags = savef;
213 pkt->pkt_comp = savec;
214 pkt->pkt_time = savet;
215
216 /* return on error */
217 if (rval)
218 return (rval);
219
220 /*
221 * This is not a performance critical code path.
222 *
223 * As an accommodation for scsi_poll callers, to avoid ddi_dma_sync()
224 * issues associated with looking at DMA memory prior to
225 * scsi_pkt_destroy(), we scsi_sync_pkt() prior to return.
226 */
227 scsi_sync_pkt(pkt);
228 return (0);
229 }
230
231 /*
232 * Command packaging routines.
233 *
234 * makecom_g*() are original routines and scsi_setup_cdb()
235 * is the new and preferred routine.
236 */
237
238 /*
239 * These routines put LUN information in CDB byte 1 bits 7-5.
240 * This was required in SCSI-1. SCSI-2 allowed it but it preferred
241 * sending LUN information as part of IDENTIFY message.
242 * This is not allowed in SCSI-3.
243 */
244
245 void
makecom_g0(struct scsi_pkt * pkt,struct scsi_device * devp,int flag,int cmd,int addr,int cnt)246 makecom_g0(struct scsi_pkt *pkt, struct scsi_device *devp,
247 int flag, int cmd, int addr, int cnt)
248 {
249 MAKECOM_G0(pkt, devp, flag, cmd, addr, (uchar_t)cnt);
250 }
251
252 void
makecom_g0_s(struct scsi_pkt * pkt,struct scsi_device * devp,int flag,int cmd,int cnt,int fixbit)253 makecom_g0_s(struct scsi_pkt *pkt, struct scsi_device *devp,
254 int flag, int cmd, int cnt, int fixbit)
255 {
256 MAKECOM_G0_S(pkt, devp, flag, cmd, cnt, (uchar_t)fixbit);
257 }
258
259 void
makecom_g1(struct scsi_pkt * pkt,struct scsi_device * devp,int flag,int cmd,int addr,int cnt)260 makecom_g1(struct scsi_pkt *pkt, struct scsi_device *devp,
261 int flag, int cmd, int addr, int cnt)
262 {
263 MAKECOM_G1(pkt, devp, flag, cmd, addr, cnt);
264 }
265
266 void
makecom_g5(struct scsi_pkt * pkt,struct scsi_device * devp,int flag,int cmd,int addr,int cnt)267 makecom_g5(struct scsi_pkt *pkt, struct scsi_device *devp,
268 int flag, int cmd, int addr, int cnt)
269 {
270 MAKECOM_G5(pkt, devp, flag, cmd, addr, cnt);
271 }
272
273 /*
274 * Following routine does not put LUN information in CDB.
275 * This interface must be used for SCSI-2 targets having
276 * more than 8 LUNs or a SCSI-3 target.
277 */
278 int
scsi_setup_cdb(union scsi_cdb * cdbp,uchar_t cmd,uint_t addr,uint_t cnt,uint_t addtl_cdb_data)279 scsi_setup_cdb(union scsi_cdb *cdbp, uchar_t cmd, uint_t addr, uint_t cnt,
280 uint_t addtl_cdb_data)
281 {
282 uint_t addr_cnt;
283
284 cdbp->scc_cmd = cmd;
285
286 switch (CDB_GROUPID(cmd)) {
287 case CDB_GROUPID_0:
288 /*
289 * The following calculation is to take care of
290 * the fact that format of some 6 bytes tape
291 * command is different (compare 6 bytes disk and
292 * tape read commands).
293 */
294 addr_cnt = (addr << 8) + cnt;
295 addr = (addr_cnt & 0x1fffff00) >> 8;
296 cnt = addr_cnt & 0xff;
297 FORMG0ADDR(cdbp, addr);
298 FORMG0COUNT(cdbp, cnt);
299 break;
300
301 case CDB_GROUPID_1:
302 case CDB_GROUPID_2:
303 FORMG1ADDR(cdbp, addr);
304 FORMG1COUNT(cdbp, cnt);
305 break;
306
307 case CDB_GROUPID_4:
308 FORMG4ADDR(cdbp, addr);
309 FORMG4COUNT(cdbp, cnt);
310 FORMG4ADDTL(cdbp, addtl_cdb_data);
311 break;
312
313 case CDB_GROUPID_5:
314 FORMG5ADDR(cdbp, addr);
315 FORMG5COUNT(cdbp, cnt);
316 break;
317
318 default:
319 return (0);
320 }
321
322 return (1);
323 }
324
325
326 /*
327 * Common iopbmap data area packet allocation routines
328 */
329
330 struct scsi_pkt *
get_pktiopb(struct scsi_address * ap,caddr_t * datap,int cdblen,int statuslen,int datalen,int readflag,int (* func)())331 get_pktiopb(struct scsi_address *ap, caddr_t *datap, int cdblen, int statuslen,
332 int datalen, int readflag, int (*func)())
333 {
334 scsi_hba_tran_t *tran = A_TO_TRAN(ap);
335 dev_info_t *pdip = tran->tran_hba_dip;
336 struct scsi_pkt *pkt = NULL;
337 struct buf local;
338 size_t rlen;
339
340 if (!datap)
341 return (pkt);
342 *datap = (caddr_t)0;
343 bzero((caddr_t)&local, sizeof (struct buf));
344
345 /*
346 * use i_ddi_mem_alloc() for now until we have an interface to allocate
347 * memory for DMA which doesn't require a DMA handle.
348 */
349 if (i_ddi_mem_alloc(pdip, &scsi_alloc_attr, datalen,
350 ((func == SLEEP_FUNC) ? 1 : 0), 0, NULL, &local.b_un.b_addr, &rlen,
351 NULL) != DDI_SUCCESS) {
352 return (pkt);
353 }
354 if (readflag)
355 local.b_flags = B_READ;
356 local.b_bcount = datalen;
357 pkt = (*tran->tran_init_pkt) (ap, NULL, &local,
358 cdblen, statuslen, 0, PKT_CONSISTENT,
359 (func == SLEEP_FUNC) ? SLEEP_FUNC : NULL_FUNC, NULL);
360 if (!pkt) {
361 i_ddi_mem_free(local.b_un.b_addr, NULL);
362 if (func != NULL_FUNC) {
363 ddi_set_callback(func, NULL, &scsi_callback_id);
364 }
365 } else {
366 *datap = local.b_un.b_addr;
367 }
368 return (pkt);
369 }
370
371 /*
372 * Equivalent deallocation wrapper
373 */
374
375 void
free_pktiopb(struct scsi_pkt * pkt,caddr_t datap,int datalen)376 free_pktiopb(struct scsi_pkt *pkt, caddr_t datap, int datalen)
377 {
378 register struct scsi_address *ap = P_TO_ADDR(pkt);
379 register scsi_hba_tran_t *tran = A_TO_TRAN(ap);
380
381 (*tran->tran_destroy_pkt)(ap, pkt);
382 if (datap && datalen) {
383 i_ddi_mem_free(datap, NULL);
384 }
385 if (scsi_callback_id != 0) {
386 ddi_run_callback(&scsi_callback_id);
387 }
388 }
389
390 /*
391 * Common naming functions
392 */
393
394 char *
scsi_dname(int dtyp)395 scsi_dname(int dtyp)
396 {
397 static char *dnames[] = DTYPE_ASCII;
398 char *dname = NULL;
399
400 if ((dtyp & DTYPE_MASK) < (sizeof (dnames) / sizeof (*dnames)))
401 dname = dnames[dtyp&DTYPE_MASK];
402 else if (dtyp == DTYPE_NOTPRESENT)
403 dname = "Not Present";
404 if ((dname == NULL) || (*dname == '\0'))
405 dname = "<unknown device type>";
406 return (dname);
407 }
408
409 char *
scsi_rname(uchar_t reason)410 scsi_rname(uchar_t reason)
411 {
412 static char *rnames[] = CMD_REASON_ASCII;
413 char *rname = NULL;
414
415 if (reason < (sizeof (rnames) / sizeof (*rnames)))
416 rname = rnames[reason];
417 if ((rname == NULL) || (*rname == '\0'))
418 rname = "<unknown reason>";
419 return (rname);
420 }
421
422 char *
scsi_mname(uchar_t msg)423 scsi_mname(uchar_t msg)
424 {
425 static char *imsgs[23] = {
426 "COMMAND COMPLETE",
427 "EXTENDED",
428 "SAVE DATA POINTER",
429 "RESTORE POINTERS",
430 "DISCONNECT",
431 "INITIATOR DETECTED ERROR",
432 "ABORT",
433 "REJECT",
434 "NO-OP",
435 "MESSAGE PARITY",
436 "LINKED COMMAND COMPLETE",
437 "LINKED COMMAND COMPLETE (W/FLAG)",
438 "BUS DEVICE RESET",
439 "ABORT TAG",
440 "CLEAR QUEUE",
441 "INITIATE RECOVERY",
442 "RELEASE RECOVERY",
443 "TERMINATE PROCESS",
444 "CONTINUE TASK",
445 "TARGET TRANSFER DISABLE",
446 "RESERVED (0x14)",
447 "RESERVED (0x15)",
448 "CLEAR ACA"
449 };
450 static char *imsgs_2[6] = {
451 "SIMPLE QUEUE TAG",
452 "HEAD OF QUEUE TAG",
453 "ORDERED QUEUE TAG",
454 "IGNORE WIDE RESIDUE",
455 "ACA",
456 "LOGICAL UNIT RESET"
457 };
458
459 if (msg < 23) {
460 return (imsgs[msg]);
461 } else if (IS_IDENTIFY_MSG(msg)) {
462 return ("IDENTIFY");
463 } else if (IS_2BYTE_MSG(msg) &&
464 (int)((msg) & 0xF) < (sizeof (imsgs_2) / sizeof (char *))) {
465 return (imsgs_2[msg & 0xF]);
466 } else {
467 return ("<unknown msg>");
468 }
469
470 }
471
472 char *
scsi_cname(uchar_t cmd,register char ** cmdvec)473 scsi_cname(uchar_t cmd, register char **cmdvec)
474 {
475 while (*cmdvec != (char *)0) {
476 if (cmd == **cmdvec) {
477 return ((char *)((long)(*cmdvec)+1));
478 }
479 cmdvec++;
480 }
481 return ("<undecoded cmd>");
482 }
483
484 char *
scsi_cmd_name(uchar_t cmd,struct scsi_key_strings * cmdlist,char * tmpstr)485 scsi_cmd_name(uchar_t cmd, struct scsi_key_strings *cmdlist, char *tmpstr)
486 {
487 int i = 0;
488
489 while (cmdlist[i].key != -1) {
490 if (cmd == cmdlist[i].key) {
491 return ((char *)cmdlist[i].message);
492 }
493 i++;
494 }
495 return (sprintf(tmpstr, "<undecoded cmd 0x%x>", cmd));
496 }
497
498 static struct scsi_asq_key_strings extended_sense_list[] = {
499 0x00, 0x00, "no additional sense info",
500 0x00, 0x01, "filemark detected",
501 0x00, 0x02, "end of partition/medium detected",
502 0x00, 0x03, "setmark detected",
503 0x00, 0x04, "beginning of partition/medium detected",
504 0x00, 0x05, "end of data detected",
505 0x00, 0x06, "i/o process terminated",
506 0x00, 0x11, "audio play operation in progress",
507 0x00, 0x12, "audio play operation paused",
508 0x00, 0x13, "audio play operation successfully completed",
509 0x00, 0x14, "audio play operation stopped due to error",
510 0x00, 0x15, "no current audio status to return",
511 0x00, 0x16, "operation in progress",
512 0x00, 0x17, "cleaning requested",
513 0x00, 0x18, "erase operation in progress",
514 0x00, 0x19, "locate operation in progress",
515 0x00, 0x1A, "rewind operation in progress",
516 0x00, 0x1B, "set capacity operation in progress",
517 0x00, 0x1C, "verify operation in progress",
518 0x00, 0x1D, "ATA passthrough information available",
519 0x01, 0x00, "no index/sector signal",
520 0x02, 0x00, "no seek complete",
521 0x03, 0x00, "peripheral device write fault",
522 0x03, 0x01, "no write current",
523 0x03, 0x02, "excessive write errors",
524 0x04, 0x00, "LUN not ready",
525 0x04, 0x01, "LUN is becoming ready",
526 0x04, 0x02, "LUN initializing command required",
527 0x04, 0x03, "LUN not ready intervention required",
528 0x04, 0x04, "LUN not ready format in progress",
529 0x04, 0x05, "LUN not ready, rebuild in progress",
530 0x04, 0x06, "LUN not ready, recalculation in progress",
531 0x04, 0x07, "LUN not ready, operation in progress",
532 0x04, 0x08, "LUN not ready, long write in progress",
533 0x04, 0x09, "LUN not ready, self-test in progress",
534 0x04, 0x0A, "LUN not accessible, asymmetric access state transition",
535 0x04, 0x0B, "LUN not accessible, target port in standby state",
536 0x04, 0x0C, "LUN not accessible, target port in unavailable state",
537 0x04, 0x10, "LUN not ready, auxiliary memory not accessible",
538 0x05, 0x00, "LUN does not respond to selection",
539 0x06, 0x00, "reference position found",
540 0x07, 0x00, "multiple peripheral devices selected",
541 0x08, 0x00, "LUN communication failure",
542 0x08, 0x01, "LUN communication time-out",
543 0x08, 0x02, "LUN communication parity error",
544 0x08, 0x03, "LUN communication crc error (ultra-DMA/32)",
545 0x08, 0x04, "unreachable copy target",
546 0x09, 0x00, "track following error",
547 0x09, 0x01, "tracking servo failure",
548 0x09, 0x02, "focus servo failure",
549 0x09, 0x03, "spindle servo failure",
550 0x09, 0x04, "head select fault",
551 0x0a, 0x00, "error log overflow",
552 0x0b, 0x00, "warning",
553 0x0b, 0x01, "warning - specified temperature exceeded",
554 0x0b, 0x02, "warning - enclosure degraded",
555 0x0c, 0x00, "write error",
556 0x0c, 0x01, "write error - recovered with auto reallocation",
557 0x0c, 0x02, "write error - auto reallocation failed",
558 0x0c, 0x03, "write error - recommend reassignment",
559 0x0c, 0x04, "compression check miscompare error",
560 0x0c, 0x05, "data expansion occurred during compression",
561 0x0c, 0x06, "block not compressible",
562 0x0c, 0x07, "write error - recovery needed",
563 0x0c, 0x08, "write error - recovery failed",
564 0x0c, 0x09, "write error - loss of streaming",
565 0x0c, 0x0a, "write error - padding blocks added",
566 0x0c, 0x0b, "auxiliary memory write error",
567 0x0c, 0x0c, "write error - unexpected unsolicited data",
568 0x0c, 0x0d, "write error - not enough unsolicited data",
569 0x0d, 0x00, "error detected by third party temporary initiator",
570 0x0d, 0x01, "third party device failure",
571 0x0d, 0x02, "copy target device not reachable",
572 0x0d, 0x03, "incorrect copy target device type",
573 0x0d, 0x04, "copy target device data underrun",
574 0x0d, 0x05, "copy target device data overrun",
575 0x0e, 0x00, "invalid information unit",
576 0x0e, 0x01, "information unit too short",
577 0x0e, 0x02, "information unit too long",
578 0x10, 0x00, "ID CRC or ECC error",
579 0x11, 0x00, "unrecovered read error",
580 0x11, 0x01, "read retries exhausted",
581 0x11, 0x02, "error too long to correct",
582 0x11, 0x03, "multiple read errors",
583 0x11, 0x04, "unrecovered read error - auto reallocate failed",
584 0x11, 0x05, "L-EC uncorrectable error",
585 0x11, 0x06, "CIRC unrecovered error",
586 0x11, 0x07, "data re-synchronization error",
587 0x11, 0x08, "incomplete block read",
588 0x11, 0x09, "no gap found",
589 0x11, 0x0a, "miscorrected error",
590 0x11, 0x0b, "unrecovered read error - recommend reassignment",
591 0x11, 0x0c, "unrecovered read error - recommend rewrite the data",
592 0x11, 0x0d, "de-compression crc error",
593 0x11, 0x0e, "cannot decompress using declared algorithm",
594 0x11, 0x0f, "error reading UPC/EAN number",
595 0x11, 0x10, "error reading ISRC number",
596 0x11, 0x11, "read error - loss of streaming",
597 0x11, 0x12, "auxiliary memory read error",
598 0x11, 0x13, "read error - failed retransmission request",
599 0x12, 0x00, "address mark not found for ID field",
600 0x13, 0x00, "address mark not found for data field",
601 0x14, 0x00, "recorded entity not found",
602 0x14, 0x01, "record not found",
603 0x14, 0x02, "filemark or setmark not found",
604 0x14, 0x03, "end-of-data not found",
605 0x14, 0x04, "block sequence error",
606 0x14, 0x05, "record not found - recommend reassignment",
607 0x14, 0x06, "record not found - data auto-reallocated",
608 0x14, 0x07, "locate operation failure",
609 0x15, 0x00, "random positioning error",
610 0x15, 0x01, "mechanical positioning error",
611 0x15, 0x02, "positioning error detected by read of medium",
612 0x16, 0x00, "data sync mark error",
613 0x16, 0x01, "data sync error - data rewritten",
614 0x16, 0x02, "data sync error - recommend rewrite",
615 0x16, 0x03, "data sync error - data auto-reallocated",
616 0x16, 0x04, "data sync error - recommend reassignment",
617 0x17, 0x00, "recovered data with no error correction",
618 0x17, 0x01, "recovered data with retries",
619 0x17, 0x02, "recovered data with positive head offset",
620 0x17, 0x03, "recovered data with negative head offset",
621 0x17, 0x04, "recovered data with retries and/or CIRC applied",
622 0x17, 0x05, "recovered data using previous sector id",
623 0x17, 0x06, "recovered data without ECC - data auto-reallocated",
624 0x17, 0x07, "recovered data without ECC - recommend reassignment",
625 0x17, 0x08, "recovered data without ECC - recommend rewrite",
626 0x17, 0x09, "recovered data without ECC - data rewritten",
627 0x18, 0x00, "recovered data with error correction",
628 0x18, 0x01, "recovered data with error corr. & retries applied",
629 0x18, 0x02, "recovered data - data auto-reallocated",
630 0x18, 0x03, "recovered data with CIRC",
631 0x18, 0x04, "recovered data with L-EC",
632 0x18, 0x05, "recovered data - recommend reassignment",
633 0x18, 0x06, "recovered data - recommend rewrite",
634 0x18, 0x07, "recovered data with ECC - data rewritten",
635 0x18, 0x08, "recovered data with linking",
636 0x19, 0x00, "defect list error",
637 0x1a, 0x00, "parameter list length error",
638 0x1b, 0x00, "synchronous data xfer error",
639 0x1c, 0x00, "defect list not found",
640 0x1c, 0x01, "primary defect list not found",
641 0x1c, 0x02, "grown defect list not found",
642 0x1d, 0x00, "miscompare during verify",
643 0x1e, 0x00, "recovered ID with ECC",
644 0x1f, 0x00, "partial defect list transfer",
645 0x20, 0x00, "invalid command operation code",
646 0x20, 0x01, "access denied - initiator pending-enrolled",
647 0x20, 0x02, "access denied - no access rights",
648 0x20, 0x03, "access denied - invalid mgmt id key",
649 0x20, 0x04, "illegal command while in write capable state",
650 0x20, 0x06, "illegal command while in explicit address mode",
651 0x20, 0x07, "illegal command while in implicit address mode",
652 0x20, 0x08, "access denied - enrollment conflict",
653 0x20, 0x09, "access denied - invalid lu identifier",
654 0x20, 0x0a, "access denied - invalid proxy token",
655 0x20, 0x0b, "access denied - ACL LUN conflict",
656 0x21, 0x00, "logical block address out of range",
657 0x21, 0x01, "invalid element address",
658 0x21, 0x02, "invalid address for write",
659 0x22, 0x00, "illegal function",
660 0x24, 0x00, "invalid field in cdb",
661 0x24, 0x01, "cdb decryption error",
662 0x25, 0x00, "LUN not supported",
663 0x26, 0x00, "invalid field in param list",
664 0x26, 0x01, "parameter not supported",
665 0x26, 0x02, "parameter value invalid",
666 0x26, 0x03, "threshold parameters not supported",
667 0x26, 0x04, "invalid release of persistent reservation",
668 0x26, 0x05, "data decryption error",
669 0x26, 0x06, "too many target descriptors",
670 0x26, 0x07, "unsupported target descriptor type code",
671 0x26, 0x08, "too many segment descriptors",
672 0x26, 0x09, "unsupported segment descriptor type code",
673 0x26, 0x0a, "unexpected inexact segment",
674 0x26, 0x0b, "inline data length exceeded",
675 0x26, 0x0c, "invalid operation for copy source or destination",
676 0x26, 0x0d, "copy segment granularity violation",
677 0x27, 0x00, "write protected",
678 0x27, 0x01, "hardware write protected",
679 0x27, 0x02, "LUN software write protected",
680 0x27, 0x03, "associated write protect",
681 0x27, 0x04, "persistent write protect",
682 0x27, 0x05, "permanent write protect",
683 0x27, 0x06, "conditional write protect",
684 0x27, 0x80, "unable to overwrite data",
685 0x28, 0x00, "medium may have changed",
686 0x28, 0x01, "import or export element accessed",
687 0x29, 0x00, "power on, reset, or bus reset occurred",
688 0x29, 0x01, "power on occurred",
689 0x29, 0x02, "scsi bus reset occurred",
690 0x29, 0x03, "bus device reset message occurred",
691 0x29, 0x04, "device internal reset",
692 0x29, 0x05, "transceiver mode changed to single-ended",
693 0x29, 0x06, "transceiver mode changed to LVD",
694 0x29, 0x07, "i_t nexus loss occurred",
695 0x2a, 0x00, "parameters changed",
696 0x2a, 0x01, "mode parameters changed",
697 0x2a, 0x02, "log parameters changed",
698 0x2a, 0x03, "reservations preempted",
699 0x2a, 0x04, "reservations released",
700 0x2a, 0x05, "registrations preempted",
701 0x2a, 0x06, "asymmetric access state changed",
702 0x2a, 0x07, "implicit asymmetric access state transition failed",
703 0x2b, 0x00, "copy cannot execute since host cannot disconnect",
704 0x2c, 0x00, "command sequence error",
705 0x2c, 0x03, "current program area is not empty",
706 0x2c, 0x04, "current program area is empty",
707 0x2c, 0x06, "persistent prevent conflict",
708 0x2c, 0x07, "previous busy status",
709 0x2c, 0x08, "previous task set full status",
710 0x2c, 0x09, "previous reservation conflict status",
711 0x2d, 0x00, "overwrite error on update in place",
712 0x2e, 0x00, "insufficient time for operation",
713 0x2f, 0x00, "commands cleared by another initiator",
714 0x30, 0x00, "incompatible medium installed",
715 0x30, 0x01, "cannot read medium - unknown format",
716 0x30, 0x02, "cannot read medium - incompatible format",
717 0x30, 0x03, "cleaning cartridge installed",
718 0x30, 0x04, "cannot write medium - unknown format",
719 0x30, 0x05, "cannot write medium - incompatible format",
720 0x30, 0x06, "cannot format medium - incompatible medium",
721 0x30, 0x07, "cleaning failure",
722 0x30, 0x08, "cannot write - application code mismatch",
723 0x30, 0x09, "current session not fixated for append",
724 0x30, 0x0b, "WORM medium - Overwrite attempted",
725 0x30, 0x0c, "WORM medium - Cannot Erase",
726 0x30, 0x0d, "WORM medium - Integrity Check",
727 0x30, 0x10, "medium not formatted",
728 0x31, 0x00, "medium format corrupted",
729 0x31, 0x01, "format command failed",
730 0x31, 0x02, "zoned formatting failed due to spare linking",
731 0x31, 0x94, "WORM media corrupted",
732 0x32, 0x00, "no defect spare location available",
733 0x32, 0x01, "defect list update failure",
734 0x33, 0x00, "tape length error",
735 0x34, 0x00, "enclosure failure",
736 0x35, 0x00, "enclosure services failure",
737 0x35, 0x01, "unsupported enclosure function",
738 0x35, 0x02, "enclosure services unavailable",
739 0x35, 0x03, "enclosure services transfer failure",
740 0x35, 0x04, "enclosure services transfer refused",
741 0x36, 0x00, "ribbon, ink, or toner failure",
742 0x37, 0x00, "rounded parameter",
743 0x39, 0x00, "saving parameters not supported",
744 0x3a, 0x00, "medium not present",
745 0x3a, 0x01, "medium not present - tray closed",
746 0x3a, 0x02, "medium not present - tray open",
747 0x3a, 0x03, "medium not present - loadable",
748 0x3a, 0x04, "medium not present - medium auxiliary memory accessible",
749 0x3b, 0x00, "sequential positioning error",
750 0x3b, 0x01, "tape position error at beginning-of-medium",
751 0x3b, 0x02, "tape position error at end-of-medium",
752 0x3b, 0x08, "reposition error",
753 0x3b, 0x0c, "position past beginning of medium",
754 0x3b, 0x0d, "medium destination element full",
755 0x3b, 0x0e, "medium source element empty",
756 0x3b, 0x0f, "end of medium reached",
757 0x3b, 0x11, "medium magazine not accessible",
758 0x3b, 0x12, "medium magazine removed",
759 0x3b, 0x13, "medium magazine inserted",
760 0x3b, 0x14, "medium magazine locked",
761 0x3b, 0x15, "medium magazine unlocked",
762 0x3b, 0x16, "mechanical positioning or changer error",
763 0x3d, 0x00, "invalid bits in indentify message",
764 0x3e, 0x00, "LUN has not self-configured yet",
765 0x3e, 0x01, "LUN failure",
766 0x3e, 0x02, "timeout on LUN",
767 0x3e, 0x03, "LUN failed self-test",
768 0x3e, 0x04, "LUN unable to update self-test log",
769 0x3f, 0x00, "target operating conditions have changed",
770 0x3f, 0x01, "microcode has been changed",
771 0x3f, 0x02, "changed operating definition",
772 0x3f, 0x03, "inquiry data has changed",
773 0x3f, 0x04, "component device attached",
774 0x3f, 0x05, "device identifier changed",
775 0x3f, 0x06, "redundancy group created or modified",
776 0x3f, 0x07, "redundancy group deleted",
777 0x3f, 0x08, "spare created or modified",
778 0x3f, 0x09, "spare deleted",
779 0x3f, 0x0a, "volume set created or modified",
780 0x3f, 0x0b, "volume set deleted",
781 0x3f, 0x0c, "volume set deassigned",
782 0x3f, 0x0d, "volume set reassigned",
783 0x3f, 0x0e, "reported LUNs data has changed",
784 0x3f, 0x0f, "echo buffer overwritten",
785 0x3f, 0x10, "medium loadable",
786 0x3f, 0x11, "medium auxiliary memory accessible",
787 0x40, 0x00, "ram failure",
788 0x41, 0x00, "data path failure",
789 0x42, 0x00, "power-on or self-test failure",
790 0x43, 0x00, "message error",
791 0x44, 0x00, "internal target failure",
792 0x45, 0x00, "select or reselect failure",
793 0x46, 0x00, "unsuccessful soft reset",
794 0x47, 0x00, "scsi parity error",
795 0x47, 0x01, "data phase crc error detected",
796 0x47, 0x02, "scsi parity error detected during st data phase",
797 0x47, 0x03, "information unit iucrc error detected",
798 0x47, 0x04, "asynchronous information protection error detected",
799 0x47, 0x05, "protocol service crc error",
800 0x47, 0x7f, "some commands cleared by iscsi protocol event",
801 0x48, 0x00, "initiator detected error message received",
802 0x49, 0x00, "invalid message error",
803 0x4a, 0x00, "command phase error",
804 0x4b, 0x00, "data phase error",
805 0x4b, 0x01, "invalid target port transfer tag received",
806 0x4b, 0x02, "too much write data",
807 0x4b, 0x03, "ack/nak timeout",
808 0x4b, 0x04, "nak received",
809 0x4b, 0x05, "data offset error",
810 0x4c, 0x00, "logical unit failed self-configuration",
811 0x4d, 0x00, "tagged overlapped commands (ASCQ = queue tag)",
812 0x4e, 0x00, "overlapped commands attempted",
813 0x50, 0x00, "write append error",
814 0x50, 0x01, "data protect write append error",
815 0x50, 0x95, "data protect write append error",
816 0x51, 0x00, "erase failure",
817 0x52, 0x00, "cartridge fault",
818 0x53, 0x00, "media load or eject failed",
819 0x53, 0x01, "unload tape failure",
820 0x53, 0x02, "medium removal prevented",
821 0x54, 0x00, "scsi to host system interface failure",
822 0x55, 0x00, "system resource failure",
823 0x55, 0x01, "system buffer full",
824 0x55, 0x02, "insufficient reservation resources",
825 0x55, 0x03, "insufficient resources",
826 0x55, 0x04, "insufficient registration resources",
827 0x55, 0x05, "insufficient access control resources",
828 0x55, 0x06, "auxiliary memory out of space",
829 0x57, 0x00, "unable to recover TOC",
830 0x58, 0x00, "generation does not exist",
831 0x59, 0x00, "updated block read",
832 0x5a, 0x00, "operator request or state change input",
833 0x5a, 0x01, "operator medium removal request",
834 0x5a, 0x02, "operator selected write protect",
835 0x5a, 0x03, "operator selected write permit",
836 0x5b, 0x00, "log exception",
837 0x5b, 0x01, "threshold condition met",
838 0x5b, 0x02, "log counter at maximum",
839 0x5b, 0x03, "log list codes exhausted",
840 0x5c, 0x00, "RPL status change",
841 0x5c, 0x01, "spindles synchronized",
842 0x5c, 0x02, "spindles not synchronized",
843 0x5d, 0x00, "drive operation marginal, service immediately"
844 " (failure prediction threshold exceeded)",
845 0x5d, 0x01, "media failure prediction threshold exceeded",
846 0x5d, 0x02, "LUN failure prediction threshold exceeded",
847 0x5d, 0x03, "spare area exhaustion prediction threshold exceeded",
848 0x5d, 0x10, "hardware impending failure general hard drive failure",
849 0x5d, 0x11, "hardware impending failure drive error rate too high",
850 0x5d, 0x12, "hardware impending failure data error rate too high",
851 0x5d, 0x13, "hardware impending failure seek error rate too high",
852 0x5d, 0x14, "hardware impending failure too many block reassigns",
853 0x5d, 0x15, "hardware impending failure access times too high",
854 0x5d, 0x16, "hardware impending failure start unit times too high",
855 0x5d, 0x17, "hardware impending failure channel parametrics",
856 0x5d, 0x18, "hardware impending failure controller detected",
857 0x5d, 0x19, "hardware impending failure throughput performance",
858 0x5d, 0x1a, "hardware impending failure seek time performance",
859 0x5d, 0x1b, "hardware impending failure spin-up retry count",
860 0x5d, 0x1c, "hardware impending failure drive calibration retry count",
861 0x5d, 0x20, "controller impending failure general hard drive failure",
862 0x5d, 0x21, "controller impending failure drive error rate too high",
863 0x5d, 0x22, "controller impending failure data error rate too high",
864 0x5d, 0x23, "controller impending failure seek error rate too high",
865 0x5d, 0x24, "controller impending failure too many block reassigns",
866 0x5d, 0x25, "controller impending failure access times too high",
867 0x5d, 0x26, "controller impending failure start unit times too high",
868 0x5d, 0x27, "controller impending failure channel parametrics",
869 0x5d, 0x28, "controller impending failure controller detected",
870 0x5d, 0x29, "controller impending failure throughput performance",
871 0x5d, 0x2a, "controller impending failure seek time performance",
872 0x5d, 0x2b, "controller impending failure spin-up retry count",
873 0x5d, 0x2c, "controller impending failure drive calibration retry cnt",
874 0x5d, 0x30, "data channel impending failure general hard drive failure",
875 0x5d, 0x31, "data channel impending failure drive error rate too high",
876 0x5d, 0x32, "data channel impending failure data error rate too high",
877 0x5d, 0x33, "data channel impending failure seek error rate too high",
878 0x5d, 0x34, "data channel impending failure too many block reassigns",
879 0x5d, 0x35, "data channel impending failure access times too high",
880 0x5d, 0x36, "data channel impending failure start unit times too high",
881 0x5d, 0x37, "data channel impending failure channel parametrics",
882 0x5d, 0x38, "data channel impending failure controller detected",
883 0x5d, 0x39, "data channel impending failure throughput performance",
884 0x5d, 0x3a, "data channel impending failure seek time performance",
885 0x5d, 0x3b, "data channel impending failure spin-up retry count",
886 0x5d, 0x3c, "data channel impending failure drive calibrate retry cnt",
887 0x5d, 0x40, "servo impending failure general hard drive failure",
888 0x5d, 0x41, "servo impending failure drive error rate too high",
889 0x5d, 0x42, "servo impending failure data error rate too high",
890 0x5d, 0x43, "servo impending failure seek error rate too high",
891 0x5d, 0x44, "servo impending failure too many block reassigns",
892 0x5d, 0x45, "servo impending failure access times too high",
893 0x5d, 0x46, "servo impending failure start unit times too high",
894 0x5d, 0x47, "servo impending failure channel parametrics",
895 0x5d, 0x48, "servo impending failure controller detected",
896 0x5d, 0x49, "servo impending failure throughput performance",
897 0x5d, 0x4a, "servo impending failure seek time performance",
898 0x5d, 0x4b, "servo impending failure spin-up retry count",
899 0x5d, 0x4c, "servo impending failure drive calibration retry count",
900 0x5d, 0x50, "spindle impending failure general hard drive failure",
901 0x5d, 0x51, "spindle impending failure drive error rate too high",
902 0x5d, 0x52, "spindle impending failure data error rate too high",
903 0x5d, 0x53, "spindle impending failure seek error rate too high",
904 0x5d, 0x54, "spindle impending failure too many block reassigns",
905 0x5d, 0x55, "spindle impending failure access times too high",
906 0x5d, 0x56, "spindle impending failure start unit times too high",
907 0x5d, 0x57, "spindle impending failure channel parametrics",
908 0x5d, 0x58, "spindle impending failure controller detected",
909 0x5d, 0x59, "spindle impending failure throughput performance",
910 0x5d, 0x5a, "spindle impending failure seek time performance",
911 0x5d, 0x5b, "spindle impending failure spin-up retry count",
912 0x5d, 0x5c, "spindle impending failure drive calibration retry count",
913 0x5d, 0x60, "firmware impending failure general hard drive failure",
914 0x5d, 0x61, "firmware impending failure drive error rate too high",
915 0x5d, 0x62, "firmware impending failure data error rate too high",
916 0x5d, 0x63, "firmware impending failure seek error rate too high",
917 0x5d, 0x64, "firmware impending failure too many block reassigns",
918 0x5d, 0x65, "firmware impending failure access times too high",
919 0x5d, 0x66, "firmware impending failure start unit times too high",
920 0x5d, 0x67, "firmware impending failure channel parametrics",
921 0x5d, 0x68, "firmware impending failure controller detected",
922 0x5d, 0x69, "firmware impending failure throughput performance",
923 0x5d, 0x6a, "firmware impending failure seek time performance",
924 0x5d, 0x6b, "firmware impending failure spin-up retry count",
925 0x5d, 0x6c, "firmware impending failure drive calibration retry count",
926 0x5d, 0xff, "failure prediction threshold exceeded (false)",
927 0x5e, 0x00, "low power condition active",
928 0x5e, 0x01, "idle condition activated by timer",
929 0x5e, 0x02, "standby condition activated by timer",
930 0x5e, 0x03, "idle condition activated by command",
931 0x5e, 0x04, "standby condition activated by command",
932 0x60, 0x00, "lamp failure",
933 0x61, 0x00, "video acquisition error",
934 0x62, 0x00, "scan head positioning error",
935 0x63, 0x00, "end of user area encountered on this track",
936 0x63, 0x01, "packet does not fit in available space",
937 0x64, 0x00, "illegal mode for this track",
938 0x64, 0x01, "invalid packet size",
939 0x65, 0x00, "voltage fault",
940 0x66, 0x00, "automatic document feeder cover up",
941 0x67, 0x00, "configuration failure",
942 0x67, 0x01, "configuration of incapable LUNs failed",
943 0x67, 0x02, "add LUN failed",
944 0x67, 0x03, "modification of LUN failed",
945 0x67, 0x04, "exchange of LUN failed",
946 0x67, 0x05, "remove of LUN failed",
947 0x67, 0x06, "attachment of LUN failed",
948 0x67, 0x07, "creation of LUN failed",
949 0x67, 0x08, "assign failure occurred",
950 0x67, 0x09, "multiply assigned LUN",
951 0x67, 0x0a, "set target port groups command failed",
952 0x68, 0x00, "logical unit not configured",
953 0x69, 0x00, "data loss on logical unit",
954 0x69, 0x01, "multiple LUN failures",
955 0x69, 0x02, "parity/data mismatch",
956 0x6a, 0x00, "informational, refer to log",
957 0x6b, 0x00, "state change has occurred",
958 0x6b, 0x01, "redundancy level got better",
959 0x6b, 0x02, "redundancy level got worse",
960 0x6c, 0x00, "rebuild failure occurred",
961 0x6d, 0x00, "recalculate failure occurred",
962 0x6e, 0x00, "command to logical unit failed",
963 0x6f, 0x00, "copy protect key exchange failure authentication failure",
964 0x6f, 0x01, "copy protect key exchange failure key not present",
965 0x6f, 0x02, "copy protect key exchange failure key not established",
966 0x6f, 0x03, "read of scrambled sector without authentication",
967 0x6f, 0x04, "media region code is mismatched to LUN region",
968 0x6f, 0x05, "drive region must be permanent/region reset count error",
969 0x70, 0xffff, "decompression exception short algorithm id of ASCQ",
970 0x71, 0x00, "decompression exception long algorithm id",
971 0x72, 0x00, "session fixation error",
972 0x72, 0x01, "session fixation error writing lead-in",
973 0x72, 0x02, "session fixation error writing lead-out",
974 0x72, 0x03, "session fixation error - incomplete track in session",
975 0x72, 0x04, "empty or partially written reserved track",
976 0x72, 0x05, "no more track reservations allowed",
977 0x73, 0x00, "cd control error",
978 0x73, 0x01, "power calibration area almost full",
979 0x73, 0x02, "power calibration area is full",
980 0x73, 0x03, "power calibration area error",
981 0x73, 0x04, "program memory area update failure",
982 0x73, 0x05, "program memory area is full",
983 0x73, 0x06, "rma/pma is almost full",
984 0xffff, 0xffff, NULL
985 };
986
987 char *
scsi_esname(uint_t key,char * tmpstr)988 scsi_esname(uint_t key, char *tmpstr)
989 {
990 int i = 0;
991
992 while (extended_sense_list[i].asc != 0xffff) {
993 if (key == extended_sense_list[i].asc) {
994 return ((char *)extended_sense_list[i].message);
995 }
996 i++;
997 }
998 return (sprintf(tmpstr, "<vendor unique code 0x%x>", key));
999 }
1000
1001 char *
scsi_asc_name(uint_t asc,uint_t ascq,char * tmpstr)1002 scsi_asc_name(uint_t asc, uint_t ascq, char *tmpstr)
1003 {
1004 int i = 0;
1005
1006 while (extended_sense_list[i].asc != 0xffff) {
1007 if ((asc == extended_sense_list[i].asc) &&
1008 ((ascq == extended_sense_list[i].ascq) ||
1009 (extended_sense_list[i].ascq == 0xffff))) {
1010 return ((char *)extended_sense_list[i].message);
1011 }
1012 i++;
1013 }
1014 return (sprintf(tmpstr, "<vendor unique code 0x%x>", asc));
1015 }
1016
1017 char *
scsi_sname(uchar_t sense_key)1018 scsi_sname(uchar_t sense_key)
1019 {
1020 if (sense_key >= (uchar_t)(NUM_SENSE_KEYS+NUM_IMPL_SENSE_KEYS)) {
1021 return ("<unknown sense key>");
1022 } else {
1023 return (sense_keys[sense_key]);
1024 }
1025 }
1026
1027
1028 /*
1029 * Print a piece of inquiry data- cleaned up for non-printable characters.
1030 */
1031 static void
inq_fill(char * p,int l,char * s)1032 inq_fill(char *p, int l, char *s)
1033 {
1034 register unsigned i = 0;
1035 char c;
1036
1037 if (!p)
1038 return;
1039
1040 while (i++ < l) {
1041 /* clean string of non-printing chars */
1042 if ((c = *p++) < ' ' || c >= 0177) {
1043 c = ' ';
1044 }
1045 *s++ = c;
1046 }
1047 *s++ = 0;
1048 }
1049
1050 static char *
scsi_asc_search(uint_t asc,uint_t ascq,struct scsi_asq_key_strings * list)1051 scsi_asc_search(uint_t asc, uint_t ascq,
1052 struct scsi_asq_key_strings *list)
1053 {
1054 int i = 0;
1055
1056 while (list[i].asc != 0xffff) {
1057 if ((asc == list[i].asc) &&
1058 ((ascq == list[i].ascq) ||
1059 (list[i].ascq == 0xffff))) {
1060 return ((char *)list[i].message);
1061 }
1062 i++;
1063 }
1064 return (NULL);
1065 }
1066
1067 static char *
scsi_asc_ascq_name(uint_t asc,uint_t ascq,char * tmpstr,struct scsi_asq_key_strings * list)1068 scsi_asc_ascq_name(uint_t asc, uint_t ascq, char *tmpstr,
1069 struct scsi_asq_key_strings *list)
1070 {
1071 char *message;
1072
1073 if (list) {
1074 if (message = scsi_asc_search(asc, ascq, list)) {
1075 return (message);
1076 }
1077 }
1078 if (message = scsi_asc_search(asc, ascq, extended_sense_list)) {
1079 return (message);
1080 }
1081
1082 return (sprintf(tmpstr, "<vendor unique code 0x%x>", asc));
1083 }
1084
1085 /*
1086 * The first part/column of the error message will be at least this length.
1087 * This number has been calculated so that each line fits in 80 chars.
1088 */
1089 #define SCSI_ERRMSG_COLUMN_LEN 42
1090 #define SCSI_ERRMSG_BUF_LEN 256
1091
1092 void
scsi_generic_errmsg(struct scsi_device * devp,char * label,int severity,daddr_t blkno,daddr_t err_blkno,uchar_t cmd_name,struct scsi_key_strings * cmdlist,uint8_t * sensep,struct scsi_asq_key_strings * asc_list,char * (* decode_fru)(struct scsi_device *,char *,int,uchar_t))1093 scsi_generic_errmsg(struct scsi_device *devp, char *label, int severity,
1094 daddr_t blkno, daddr_t err_blkno,
1095 uchar_t cmd_name, struct scsi_key_strings *cmdlist,
1096 uint8_t *sensep, struct scsi_asq_key_strings *asc_list,
1097 char *(*decode_fru)(struct scsi_device *, char *, int, uchar_t))
1098 {
1099 uchar_t com;
1100 static char buf[SCSI_ERRMSG_BUF_LEN];
1101 static char buf1[SCSI_ERRMSG_BUF_LEN];
1102 static char tmpbuf[64];
1103 static char pad[SCSI_ERRMSG_COLUMN_LEN];
1104 dev_info_t *dev = devp->sd_dev;
1105 static char *error_classes[] = {
1106 "All", "Unknown", "Informational",
1107 "Recovered", "Retryable", "Fatal"
1108 };
1109 uchar_t sense_key, asc, ascq, fru_code;
1110 uchar_t *fru_code_ptr;
1111 int i, buflen;
1112
1113 mutex_enter(&scsi_log_mutex);
1114
1115 /*
1116 * We need to put our space padding code because kernel version
1117 * of sprintf(9F) doesn't support %-<number>s type of left alignment.
1118 */
1119 for (i = 0; i < SCSI_ERRMSG_COLUMN_LEN; i++) {
1120 pad[i] = ' ';
1121 }
1122
1123 bzero(buf, SCSI_ERRMSG_BUF_LEN);
1124 com = cmd_name;
1125 (void) sprintf(buf, "Error for Command: %s",
1126 scsi_cmd_name(com, cmdlist, tmpbuf));
1127 buflen = strlen(buf);
1128 if (buflen < SCSI_ERRMSG_COLUMN_LEN) {
1129 pad[SCSI_ERRMSG_COLUMN_LEN - buflen] = '\0';
1130 (void) sprintf(&buf[buflen], "%s Error Level: %s",
1131 pad, error_classes[severity]);
1132 pad[SCSI_ERRMSG_COLUMN_LEN - buflen] = ' ';
1133 } else {
1134 (void) sprintf(&buf[buflen], " Error Level: %s",
1135 error_classes[severity]);
1136 }
1137 impl_scsi_log(dev, label, CE_WARN, buf);
1138
1139 if (blkno != -1 || err_blkno != -1 &&
1140 ((com & 0xf) == SCMD_READ) || ((com & 0xf) == SCMD_WRITE)) {
1141 bzero(buf, SCSI_ERRMSG_BUF_LEN);
1142 (void) sprintf(buf, "Requested Block: %ld", blkno);
1143 buflen = strlen(buf);
1144 if (buflen < SCSI_ERRMSG_COLUMN_LEN) {
1145 pad[SCSI_ERRMSG_COLUMN_LEN - buflen] = '\0';
1146 (void) sprintf(&buf[buflen], "%s Error Block: %ld\n",
1147 pad, err_blkno);
1148 pad[SCSI_ERRMSG_COLUMN_LEN - buflen] = ' ';
1149 } else {
1150 (void) sprintf(&buf[buflen], " Error Block: %ld\n",
1151 err_blkno);
1152 }
1153 impl_scsi_log(dev, label, CE_CONT, buf);
1154 }
1155
1156 bzero(buf, SCSI_ERRMSG_BUF_LEN);
1157 (void) strcpy(buf, "Vendor: ");
1158 inq_fill(devp->sd_inq->inq_vid, 8, &buf[strlen(buf)]);
1159 buflen = strlen(buf);
1160 if (buflen < SCSI_ERRMSG_COLUMN_LEN) {
1161 pad[SCSI_ERRMSG_COLUMN_LEN - buflen] = '\0';
1162 (void) sprintf(&buf[strlen(buf)], "%s Serial Number: ", pad);
1163 pad[SCSI_ERRMSG_COLUMN_LEN - buflen] = ' ';
1164 } else {
1165 (void) sprintf(&buf[strlen(buf)], " Serial Number: ");
1166 }
1167 inq_fill(devp->sd_inq->inq_serial, 12, &buf[strlen(buf)]);
1168 impl_scsi_log(dev, label, CE_CONT, "%s\n", buf);
1169
1170 if (sensep) {
1171 sense_key = scsi_sense_key(sensep);
1172 asc = scsi_sense_asc(sensep);
1173 ascq = scsi_sense_ascq(sensep);
1174 scsi_ext_sense_fields(sensep, SENSE_LENGTH,
1175 NULL, NULL, &fru_code_ptr, NULL, NULL);
1176 fru_code = (fru_code_ptr ? *fru_code_ptr : 0);
1177
1178 bzero(buf, SCSI_ERRMSG_BUF_LEN);
1179 (void) sprintf(buf, "Sense Key: %s\n",
1180 sense_keys[sense_key]);
1181 impl_scsi_log(dev, label, CE_CONT, buf);
1182
1183 bzero(buf, SCSI_ERRMSG_BUF_LEN);
1184 if ((fru_code != 0) &&
1185 (decode_fru != NULL)) {
1186 (*decode_fru)(devp, buf, SCSI_ERRMSG_BUF_LEN,
1187 fru_code);
1188 if (buf[0] != '\0') {
1189 bzero(buf1, SCSI_ERRMSG_BUF_LEN);
1190 (void) sprintf(&buf1[strlen(buf1)],
1191 "ASC: 0x%x (%s)", asc,
1192 scsi_asc_ascq_name(asc, ascq,
1193 tmpbuf, asc_list));
1194 buflen = strlen(buf1);
1195 if (buflen < SCSI_ERRMSG_COLUMN_LEN) {
1196 pad[SCSI_ERRMSG_COLUMN_LEN - buflen] =
1197 '\0';
1198 (void) sprintf(&buf1[buflen],
1199 "%s ASCQ: 0x%x", pad, ascq);
1200 } else {
1201 (void) sprintf(&buf1[buflen],
1202 " ASCQ: 0x%x", ascq);
1203 }
1204 impl_scsi_log(dev,
1205 label, CE_CONT, "%s\n", buf1);
1206 impl_scsi_log(dev,
1207 label, CE_CONT, "FRU: 0x%x (%s)\n",
1208 fru_code, buf);
1209 mutex_exit(&scsi_log_mutex);
1210 return;
1211 }
1212 }
1213 (void) sprintf(&buf[strlen(buf)],
1214 "ASC: 0x%x (%s), ASCQ: 0x%x, FRU: 0x%x",
1215 asc, scsi_asc_ascq_name(asc, ascq, tmpbuf, asc_list),
1216 ascq, fru_code);
1217 impl_scsi_log(dev, label, CE_CONT, "%s\n", buf);
1218 }
1219 mutex_exit(&scsi_log_mutex);
1220 }
1221
1222 void
scsi_vu_errmsg(struct scsi_device * devp,struct scsi_pkt * pkt,char * label,int severity,daddr_t blkno,daddr_t err_blkno,struct scsi_key_strings * cmdlist,struct scsi_extended_sense * sensep,struct scsi_asq_key_strings * asc_list,char * (* decode_fru)(struct scsi_device *,char *,int,uchar_t))1223 scsi_vu_errmsg(struct scsi_device *devp, struct scsi_pkt *pkt, char *label,
1224 int severity, daddr_t blkno, daddr_t err_blkno,
1225 struct scsi_key_strings *cmdlist, struct scsi_extended_sense *sensep,
1226 struct scsi_asq_key_strings *asc_list,
1227 char *(*decode_fru)(struct scsi_device *, char *, int, uchar_t))
1228 {
1229 uchar_t com;
1230
1231 com = ((union scsi_cdb *)pkt->pkt_cdbp)->scc_cmd;
1232
1233 scsi_generic_errmsg(devp, label, severity, blkno, err_blkno,
1234 com, cmdlist, (uint8_t *)sensep, asc_list, decode_fru);
1235
1236
1237 }
1238
1239 void
scsi_errmsg(struct scsi_device * devp,struct scsi_pkt * pkt,char * label,int severity,daddr_t blkno,daddr_t err_blkno,struct scsi_key_strings * cmdlist,struct scsi_extended_sense * sensep)1240 scsi_errmsg(struct scsi_device *devp, struct scsi_pkt *pkt, char *label,
1241 int severity, daddr_t blkno, daddr_t err_blkno,
1242 struct scsi_key_strings *cmdlist, struct scsi_extended_sense *sensep)
1243 {
1244 scsi_vu_errmsg(devp, pkt, label, severity, blkno,
1245 err_blkno, cmdlist, sensep, NULL, NULL);
1246 }
1247
1248 /*PRINTFLIKE4*/
1249 void
scsi_log(dev_info_t * dev,char * label,uint_t level,const char * fmt,...)1250 scsi_log(dev_info_t *dev, char *label, uint_t level,
1251 const char *fmt, ...)
1252 {
1253 va_list ap;
1254
1255 va_start(ap, fmt);
1256 mutex_enter(&scsi_log_mutex);
1257 v_scsi_log(dev, label, level, fmt, ap);
1258 mutex_exit(&scsi_log_mutex);
1259 va_end(ap);
1260 }
1261
1262 /*PRINTFLIKE4*/
1263 static void
impl_scsi_log(dev_info_t * dev,char * label,uint_t level,const char * fmt,...)1264 impl_scsi_log(dev_info_t *dev, char *label, uint_t level,
1265 const char *fmt, ...)
1266 {
1267 va_list ap;
1268
1269 ASSERT(mutex_owned(&scsi_log_mutex));
1270
1271 va_start(ap, fmt);
1272 v_scsi_log(dev, label, level, fmt, ap);
1273 va_end(ap);
1274 }
1275
1276
1277 char *ddi_pathname(dev_info_t *dip, char *path);
1278
1279 /*PRINTFLIKE4*/
1280 static void
v_scsi_log(dev_info_t * dev,char * label,uint_t level,const char * fmt,va_list ap)1281 v_scsi_log(dev_info_t *dev, char *label, uint_t level,
1282 const char *fmt, va_list ap)
1283 {
1284 static char name[256];
1285 int log_only = 0;
1286 int boot_only = 0;
1287 int console_only = 0;
1288
1289 ASSERT(mutex_owned(&scsi_log_mutex));
1290
1291 if (dev) {
1292 if (level == CE_PANIC || level == CE_WARN ||
1293 level == CE_NOTE) {
1294 (void) sprintf(name, "%s (%s%d):\n",
1295 ddi_pathname(dev, scsi_log_buffer),
1296 label, ddi_get_instance(dev));
1297 } else if (level >= (uint_t)SCSI_DEBUG) {
1298 (void) sprintf(name,
1299 "%s%d:", label, ddi_get_instance(dev));
1300 } else {
1301 name[0] = '\0';
1302 }
1303 } else {
1304 (void) sprintf(name, "%s:", label);
1305 }
1306
1307 (void) vsprintf(scsi_log_buffer, fmt, ap);
1308
1309 switch (scsi_log_buffer[0]) {
1310 case '!':
1311 log_only = 1;
1312 break;
1313 case '?':
1314 boot_only = 1;
1315 break;
1316 case '^':
1317 console_only = 1;
1318 break;
1319 }
1320
1321 switch (level) {
1322 case CE_NOTE:
1323 level = CE_CONT;
1324 /* FALLTHROUGH */
1325 case CE_CONT:
1326 case CE_WARN:
1327 case CE_PANIC:
1328 if (boot_only) {
1329 cmn_err(level, "?%s\t%s", name, &scsi_log_buffer[1]);
1330 } else if (console_only) {
1331 cmn_err(level, "^%s\t%s", name, &scsi_log_buffer[1]);
1332 } else if (log_only) {
1333 cmn_err(level, "!%s\t%s", name, &scsi_log_buffer[1]);
1334 } else {
1335 cmn_err(level, "%s\t%s", name, scsi_log_buffer);
1336 }
1337 break;
1338 case (uint_t)SCSI_DEBUG:
1339 default:
1340 cmn_err(CE_CONT, "^DEBUG: %s\t%s", name, scsi_log_buffer);
1341 break;
1342 }
1343 }
1344
1345 /*
1346 * Lookup the 'prop_name' string array property and walk thru its list of
1347 * tuple values looking for a tuple who's VID/PID string (first part of tuple)
1348 * matches the inquiry VID/PID information for the scsi_device. On a match,
1349 * return a duplicate of the second part of the tuple. If no match is found,
1350 * return NULL. On non-NULL return, caller is responsible for freeing return
1351 * result via:
1352 * kmem_free(string, strlen(string) + 1);
1353 *
1354 * This interface can either be used directly, or indirectly by
1355 * scsi_get_device_type_scsi_options.
1356 */
1357 char *
scsi_get_device_type_string(char * prop_name,dev_info_t * dip,struct scsi_device * devp)1358 scsi_get_device_type_string(char *prop_name,
1359 dev_info_t *dip, struct scsi_device *devp)
1360 {
1361 struct scsi_inquiry *inq = devp->sd_inq;
1362 char **tuples;
1363 uint_t ntuples;
1364 int i;
1365 char *tvp; /* tuple vid/pid */
1366 char *trs; /* tuple return string */
1367 int tvp_len;
1368
1369 /* if we have no inquiry data then we can't do this */
1370 if (inq == NULL)
1371 return (NULL);
1372
1373 /*
1374 * So that we can establish a 'prop_name' for all instances of a
1375 * device in the system in a single place if needed (via options.conf),
1376 * we loop going up to the root ourself. This way root lookup does
1377 * *not* specify DDI_PROP_DONTPASS, and the code will look on the
1378 * options node.
1379 */
1380 do {
1381 if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, dip,
1382 (ddi_get_parent(dip) ? DDI_PROP_DONTPASS : 0) |
1383 DDI_PROP_NOTPROM, prop_name, &tuples, &ntuples) ==
1384 DDI_PROP_SUCCESS) {
1385
1386 /* loop over tuples */
1387 for (i = 0; i < (ntuples/2); i++) {
1388 /* split into vid/pid and return-string */
1389 tvp = tuples[i * 2];
1390 trs = tuples[(i * 2) + 1];
1391 tvp_len = strlen(tvp);
1392
1393 /* check for vid/pid match */
1394 if ((tvp_len == 0) ||
1395 bcmp(tvp, inq->inq_vid, tvp_len))
1396 continue; /* no match */
1397
1398 /* match, dup return-string */
1399 trs = i_ddi_strdup(trs, KM_SLEEP);
1400 ddi_prop_free(tuples);
1401 return (trs);
1402 }
1403 ddi_prop_free(tuples);
1404 }
1405
1406 /* climb up to root one step at a time */
1407 dip = ddi_get_parent(dip);
1408 } while (dip);
1409
1410 return (NULL);
1411 }
1412
1413 /*
1414 * The 'device-type-scsi-options' mechanism can be used to establish a device
1415 * specific scsi_options value for a particular device. This mechanism uses
1416 * paired strings ("vendor_info", "options_property_name") from the string
1417 * array "device-type-scsi-options" definition. A bcmp of the vendor info is
1418 * done against the inquiry data (inq_vid). Here is an example of use:
1419 *
1420 * device-type-scsi-options-list =
1421 * "FOOLCO Special x1000", "foolco-scsi-options",
1422 * "FOOLCO Special y1000", "foolco-scsi-options";
1423 * foolco-scsi-options = 0xXXXXXXXX;
1424 */
1425 int
scsi_get_device_type_scsi_options(dev_info_t * dip,struct scsi_device * devp,int options)1426 scsi_get_device_type_scsi_options(dev_info_t *dip,
1427 struct scsi_device *devp, int options)
1428 {
1429 char *string;
1430
1431 if ((string = scsi_get_device_type_string(
1432 "device-type-scsi-options-list", dip, devp)) != NULL) {
1433 options = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
1434 string, options);
1435 kmem_free(string, strlen(string) + 1);
1436 }
1437 return (options);
1438 }
1439
1440 /*
1441 * Find the scsi_options for a scsi_device. The precedence is:
1442 *
1443 * target<%d>-scsi-options highest
1444 * device-type-scsi-options
1445 * per bus scsi-options (parent)
1446 * global scsi-options
1447 * default_scsi_options argument lowest
1448 *
1449 * If the global is used then it has already been established
1450 * on the parent scsi_hba_attach_setup.
1451 */
1452 int
scsi_get_scsi_options(struct scsi_device * sd,int default_scsi_options)1453 scsi_get_scsi_options(struct scsi_device *sd, int default_scsi_options)
1454 {
1455 dev_info_t *parent;
1456 int options = -1;
1457 int tgt;
1458 char topt[32];
1459
1460 if ((sd == NULL) || (sd->sd_dev == NULL))
1461 return (default_scsi_options);
1462
1463 parent = ddi_get_parent(sd->sd_dev);
1464
1465 if ((tgt = ddi_prop_get_int(DDI_DEV_T_ANY, sd->sd_dev,
1466 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "target", -1)) != -1) {
1467 (void) sprintf(topt, "target%d-scsi-options", tgt);
1468 options = ddi_prop_get_int(DDI_DEV_T_ANY, parent,
1469 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, topt, -1);
1470 }
1471
1472 if (options == -1)
1473 options = scsi_get_device_type_scsi_options(parent, sd, -1);
1474
1475 if (options == -1)
1476 options = ddi_prop_get_int(DDI_DEV_T_ANY, parent,
1477 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "scsi-options", -1);
1478
1479 if (options == -1)
1480 options = default_scsi_options;
1481
1482 return (options);
1483 }
1484
1485 /*
1486 * Use scsi-options to return the maximum number of LUNs.
1487 */
1488 int
scsi_get_scsi_maxluns(struct scsi_device * sd)1489 scsi_get_scsi_maxluns(struct scsi_device *sd)
1490 {
1491 int options;
1492 int maxluns;
1493
1494 ASSERT(sd && sd->sd_inq);
1495 options = scsi_get_scsi_options(sd, SCSI_OPTIONS_NLUNS_DEFAULT);
1496
1497 switch (SCSI_OPTIONS_NLUNS(options)) {
1498 default:
1499 case SCSI_OPTIONS_NLUNS_DEFAULT:
1500 /* based on scsi version of target */
1501 if (sd->sd_inq->inq_ansi < SCSI_VERSION_3)
1502 maxluns = SCSI_8LUN_PER_TARGET; /* 8 */
1503 else
1504 maxluns = SCSI_16LUNS_PER_TARGET; /* 16 */
1505 break;
1506 case SCSI_OPTIONS_NLUNS_1:
1507 maxluns = SCSI_1LUN_PER_TARGET; /* 1 */
1508 break;
1509 case SCSI_OPTIONS_NLUNS_8:
1510 maxluns = SCSI_8LUN_PER_TARGET; /* 8 */
1511 break;
1512 case SCSI_OPTIONS_NLUNS_16:
1513 maxluns = SCSI_16LUNS_PER_TARGET; /* 16 */
1514 break;
1515 case SCSI_OPTIONS_NLUNS_32:
1516 maxluns = SCSI_32LUNS_PER_TARGET; /* 32 */
1517 break;
1518 }
1519
1520 /* For SCSI-1 we never support > 8 LUNs */
1521 if ((sd->sd_inq->inq_ansi <= SCSI_VERSION_1) &&
1522 (maxluns > SCSI_8LUN_PER_TARGET))
1523 maxluns = SCSI_8LUN_PER_TARGET;
1524
1525 return (maxluns);
1526 }
1527
1528 /*
1529 * Functions for format-neutral sense data functions
1530 */
1531 int
scsi_validate_sense(uint8_t * sense_buffer,int sense_buf_len,int * flags)1532 scsi_validate_sense(uint8_t *sense_buffer, int sense_buf_len, int *flags)
1533 {
1534 int result;
1535 struct scsi_extended_sense *es =
1536 (struct scsi_extended_sense *)sense_buffer;
1537
1538 /*
1539 * Init flags if present
1540 */
1541 if (flags != NULL) {
1542 *flags = 0;
1543 }
1544
1545 /*
1546 * Check response code (Solaris breaks this into a 3-bit class
1547 * and 4-bit code field.
1548 */
1549 if ((es->es_class != CLASS_EXTENDED_SENSE) ||
1550 ((es->es_code != CODE_FMT_FIXED_CURRENT) &&
1551 (es->es_code != CODE_FMT_FIXED_DEFERRED) &&
1552 (es->es_code != CODE_FMT_DESCR_CURRENT) &&
1553 (es->es_code != CODE_FMT_DESCR_DEFERRED))) {
1554 /*
1555 * Sense data (if there's actually anything here) is not
1556 * in a format we can handle).
1557 */
1558 return (SENSE_UNUSABLE);
1559 }
1560
1561 /*
1562 * Check if this is deferred sense
1563 */
1564 if ((flags != NULL) &&
1565 ((es->es_code == CODE_FMT_FIXED_DEFERRED) ||
1566 (es->es_code == CODE_FMT_DESCR_DEFERRED))) {
1567 *flags |= SNS_BUF_DEFERRED;
1568 }
1569
1570 /*
1571 * Make sure length is OK
1572 */
1573 if (es->es_code == CODE_FMT_FIXED_CURRENT ||
1574 es->es_code == CODE_FMT_FIXED_DEFERRED) {
1575 /*
1576 * We can get by with a buffer that only includes the key,
1577 * asc, and ascq. In reality the minimum length we should
1578 * ever see is 18 bytes.
1579 */
1580 if ((sense_buf_len < MIN_FIXED_SENSE_LEN) ||
1581 ((es->es_add_len + ADDL_SENSE_ADJUST) <
1582 MIN_FIXED_SENSE_LEN)) {
1583 result = SENSE_UNUSABLE;
1584 } else {
1585 /*
1586 * The es_add_len field contains the number of sense
1587 * data bytes that follow the es_add_len field.
1588 */
1589 if ((flags != NULL) &&
1590 (sense_buf_len <
1591 (es->es_add_len + ADDL_SENSE_ADJUST))) {
1592 *flags |= SNS_BUF_OVERFLOW;
1593 }
1594
1595 result = SENSE_FIXED_FORMAT;
1596 }
1597 } else {
1598 struct scsi_descr_sense_hdr *ds =
1599 (struct scsi_descr_sense_hdr *)sense_buffer;
1600
1601 /*
1602 * For descriptor format we need at least the descriptor
1603 * header
1604 */
1605 if (sense_buf_len < sizeof (struct scsi_descr_sense_hdr)) {
1606 result = SENSE_UNUSABLE;
1607 } else {
1608 /*
1609 * Check for overflow
1610 */
1611 if ((flags != NULL) &&
1612 (sense_buf_len <
1613 (ds->ds_addl_sense_length + sizeof (*ds)))) {
1614 *flags |= SNS_BUF_OVERFLOW;
1615 }
1616
1617 result = SENSE_DESCR_FORMAT;
1618 }
1619 }
1620
1621 return (result);
1622 }
1623
1624
1625 uint8_t
scsi_sense_key(uint8_t * sense_buffer)1626 scsi_sense_key(uint8_t *sense_buffer)
1627 {
1628 uint8_t skey;
1629 if (SCSI_IS_DESCR_SENSE(sense_buffer)) {
1630 struct scsi_descr_sense_hdr *sdsp =
1631 (struct scsi_descr_sense_hdr *)sense_buffer;
1632 skey = sdsp->ds_key;
1633 } else {
1634 struct scsi_extended_sense *ext_sensep =
1635 (struct scsi_extended_sense *)sense_buffer;
1636 skey = ext_sensep->es_key;
1637 }
1638 return (skey);
1639 }
1640
1641 uint8_t
scsi_sense_asc(uint8_t * sense_buffer)1642 scsi_sense_asc(uint8_t *sense_buffer)
1643 {
1644 uint8_t asc;
1645 if (SCSI_IS_DESCR_SENSE(sense_buffer)) {
1646 struct scsi_descr_sense_hdr *sdsp =
1647 (struct scsi_descr_sense_hdr *)sense_buffer;
1648 asc = sdsp->ds_add_code;
1649 } else {
1650 struct scsi_extended_sense *ext_sensep =
1651 (struct scsi_extended_sense *)sense_buffer;
1652 asc = ext_sensep->es_add_code;
1653 }
1654 return (asc);
1655 }
1656
1657 uint8_t
scsi_sense_ascq(uint8_t * sense_buffer)1658 scsi_sense_ascq(uint8_t *sense_buffer)
1659 {
1660 uint8_t ascq;
1661 if (SCSI_IS_DESCR_SENSE(sense_buffer)) {
1662 struct scsi_descr_sense_hdr *sdsp =
1663 (struct scsi_descr_sense_hdr *)sense_buffer;
1664 ascq = sdsp->ds_qual_code;
1665 } else {
1666 struct scsi_extended_sense *ext_sensep =
1667 (struct scsi_extended_sense *)sense_buffer;
1668 ascq = ext_sensep->es_qual_code;
1669 }
1670 return (ascq);
1671 }
1672
scsi_ext_sense_fields(uint8_t * sense_buffer,int sense_buf_len,uint8_t ** information,uint8_t ** cmd_spec_info,uint8_t ** fru_code,uint8_t ** sk_specific,uint8_t ** stream_flags)1673 void scsi_ext_sense_fields(uint8_t *sense_buffer, int sense_buf_len,
1674 uint8_t **information, uint8_t **cmd_spec_info, uint8_t **fru_code,
1675 uint8_t **sk_specific, uint8_t **stream_flags)
1676 {
1677 int sense_fmt;
1678
1679 /*
1680 * Sanity check sense data and determine the format
1681 */
1682 sense_fmt = scsi_validate_sense(sense_buffer, sense_buf_len, NULL);
1683
1684 /*
1685 * Initialize any requested data to 0
1686 */
1687 if (information) {
1688 *information = NULL;
1689 }
1690 if (cmd_spec_info) {
1691 *cmd_spec_info = NULL;
1692 }
1693 if (fru_code) {
1694 *fru_code = NULL;
1695 }
1696 if (sk_specific) {
1697 *sk_specific = NULL;
1698 }
1699 if (stream_flags) {
1700 *stream_flags = NULL;
1701 }
1702
1703 if (sense_fmt == SENSE_DESCR_FORMAT) {
1704 struct scsi_descr_template *sdt = NULL;
1705
1706 while (scsi_get_next_descr(sense_buffer,
1707 sense_buf_len, &sdt) != -1) {
1708 switch (sdt->sdt_descr_type) {
1709 case DESCR_INFORMATION: {
1710 struct scsi_information_sense_descr *isd =
1711 (struct scsi_information_sense_descr *)
1712 sdt;
1713 if (information) {
1714 *information =
1715 &isd->isd_information[0];
1716 }
1717 break;
1718 }
1719 case DESCR_COMMAND_SPECIFIC: {
1720 struct scsi_cmd_specific_sense_descr *csd =
1721 (struct scsi_cmd_specific_sense_descr *)
1722 sdt;
1723 if (cmd_spec_info) {
1724 *cmd_spec_info =
1725 &csd->css_cmd_specific_info[0];
1726 }
1727 break;
1728 }
1729 case DESCR_SENSE_KEY_SPECIFIC: {
1730 struct scsi_sk_specific_sense_descr *ssd =
1731 (struct scsi_sk_specific_sense_descr *)
1732 sdt;
1733 if (sk_specific) {
1734 *sk_specific =
1735 (uint8_t *)&ssd->sss_data;
1736 }
1737 break;
1738 }
1739 case DESCR_FRU: {
1740 struct scsi_fru_sense_descr *fsd =
1741 (struct scsi_fru_sense_descr *)
1742 sdt;
1743 if (fru_code) {
1744 *fru_code = &fsd->fs_fru_code;
1745 }
1746 break;
1747 }
1748 case DESCR_STREAM_COMMANDS: {
1749 struct scsi_stream_cmd_sense_descr *strsd =
1750 (struct scsi_stream_cmd_sense_descr *)
1751 sdt;
1752 if (stream_flags) {
1753 *stream_flags =
1754 (uint8_t *)&strsd->scs_data;
1755 }
1756 break;
1757 }
1758 case DESCR_BLOCK_COMMANDS: {
1759 struct scsi_block_cmd_sense_descr *bsd =
1760 (struct scsi_block_cmd_sense_descr *)
1761 sdt;
1762 /*
1763 * The "Block Command" sense descriptor
1764 * contains an ili bit that we can store
1765 * in the stream specific data if it is
1766 * available. We shouldn't see both
1767 * a block command and a stream command
1768 * descriptor in the same collection
1769 * of sense data.
1770 */
1771 if (stream_flags) {
1772 /*
1773 * Can't take an address of a bitfield,
1774 * but the flags are just after the
1775 * bcs_reserved field.
1776 */
1777 *stream_flags =
1778 (uint8_t *)&bsd->bcs_reserved + 1;
1779 }
1780 break;
1781 }
1782 }
1783 }
1784 } else {
1785 struct scsi_extended_sense *es =
1786 (struct scsi_extended_sense *)sense_buffer;
1787
1788 /* Get data from fixed sense buffer */
1789 if (information && es->es_valid) {
1790 *information = &es->es_info_1;
1791 }
1792 if (cmd_spec_info && es->es_valid) {
1793 *cmd_spec_info = &es->es_cmd_info[0];
1794 }
1795 if (fru_code) {
1796 *fru_code = &es->es_fru_code;
1797 }
1798 if (sk_specific) {
1799 *sk_specific = &es->es_skey_specific[0];
1800 }
1801 if (stream_flags) {
1802 /*
1803 * Can't take the address of a bit field,
1804 * but the stream flags are located just after
1805 * the es_segnum field;
1806 */
1807 *stream_flags = &es->es_segnum + 1;
1808 }
1809 }
1810 }
1811
1812 boolean_t
scsi_sense_info_uint64(uint8_t * sense_buffer,int sense_buf_len,uint64_t * information)1813 scsi_sense_info_uint64(uint8_t *sense_buffer, int sense_buf_len,
1814 uint64_t *information)
1815 {
1816 boolean_t valid;
1817 int sense_fmt;
1818
1819 ASSERT(sense_buffer != NULL);
1820 ASSERT(information != NULL);
1821
1822 /* Validate sense data and get format */
1823 sense_fmt = scsi_validate_sense(sense_buffer, sense_buf_len, NULL);
1824
1825 if (sense_fmt == SENSE_UNUSABLE) {
1826 /* Information is not valid */
1827 valid = 0;
1828 } else if (sense_fmt == SENSE_FIXED_FORMAT) {
1829 struct scsi_extended_sense *es =
1830 (struct scsi_extended_sense *)sense_buffer;
1831
1832 *information = (uint64_t)SCSI_READ32(&es->es_info_1);
1833
1834 valid = es->es_valid;
1835 } else {
1836 /* Sense data is descriptor format */
1837 struct scsi_information_sense_descr *isd;
1838
1839 isd = (struct scsi_information_sense_descr *)
1840 scsi_find_sense_descr(sense_buffer, sense_buf_len,
1841 DESCR_INFORMATION);
1842
1843 if (isd) {
1844 *information = SCSI_READ64(isd->isd_information);
1845 valid = 1;
1846 } else {
1847 valid = 0;
1848 }
1849 }
1850
1851 return (valid);
1852 }
1853
1854 boolean_t
scsi_sense_cmdspecific_uint64(uint8_t * sense_buffer,int sense_buf_len,uint64_t * cmd_specific_info)1855 scsi_sense_cmdspecific_uint64(uint8_t *sense_buffer, int sense_buf_len,
1856 uint64_t *cmd_specific_info)
1857 {
1858 boolean_t valid;
1859 int sense_fmt;
1860
1861 ASSERT(sense_buffer != NULL);
1862 ASSERT(cmd_specific_info != NULL);
1863
1864 /* Validate sense data and get format */
1865 sense_fmt = scsi_validate_sense(sense_buffer, sense_buf_len, NULL);
1866
1867 if (sense_fmt == SENSE_UNUSABLE) {
1868 /* Command specific info is not valid */
1869 valid = 0;
1870 } else if (sense_fmt == SENSE_FIXED_FORMAT) {
1871 struct scsi_extended_sense *es =
1872 (struct scsi_extended_sense *)sense_buffer;
1873
1874 *cmd_specific_info = (uint64_t)SCSI_READ32(es->es_cmd_info);
1875
1876 valid = es->es_valid;
1877 } else {
1878 /* Sense data is descriptor format */
1879 struct scsi_cmd_specific_sense_descr *c;
1880
1881 c = (struct scsi_cmd_specific_sense_descr *)
1882 scsi_find_sense_descr(sense_buffer, sense_buf_len,
1883 DESCR_COMMAND_SPECIFIC);
1884
1885 if (c) {
1886 valid = 1;
1887 *cmd_specific_info =
1888 SCSI_READ64(c->css_cmd_specific_info);
1889 } else {
1890 valid = 0;
1891 }
1892 }
1893
1894 return (valid);
1895 }
1896
1897 uint8_t *
scsi_find_sense_descr(uint8_t * sdsp,int sense_buf_len,int req_descr_type)1898 scsi_find_sense_descr(uint8_t *sdsp, int sense_buf_len, int req_descr_type)
1899 {
1900 struct scsi_descr_template *sdt = NULL;
1901
1902 while (scsi_get_next_descr(sdsp, sense_buf_len, &sdt) != -1) {
1903 ASSERT(sdt != NULL);
1904 if (sdt->sdt_descr_type == req_descr_type) {
1905 /* Found requested descriptor type */
1906 break;
1907 }
1908 }
1909
1910 return ((uint8_t *)sdt);
1911 }
1912
1913 /*
1914 * Sense Descriptor format is:
1915 *
1916 * <Descriptor type> <Descriptor length> <Descriptor data> ...
1917 *
1918 * 2 must be added to the descriptor length value to get the
1919 * total descriptor length sense the stored length does not
1920 * include the "type" and "additional length" fields.
1921 */
1922
1923 #define NEXT_DESCR_PTR(ndp_descr) \
1924 ((struct scsi_descr_template *)(((uint8_t *)(ndp_descr)) + \
1925 ((ndp_descr)->sdt_addl_length + \
1926 sizeof (struct scsi_descr_template))))
1927
1928 static int
scsi_get_next_descr(uint8_t * sense_buffer,int sense_buf_len,struct scsi_descr_template ** descrpp)1929 scsi_get_next_descr(uint8_t *sense_buffer,
1930 int sense_buf_len, struct scsi_descr_template **descrpp)
1931 {
1932 struct scsi_descr_sense_hdr *sdsp =
1933 (struct scsi_descr_sense_hdr *)sense_buffer;
1934 struct scsi_descr_template *cur_descr;
1935 boolean_t find_first;
1936 int valid_sense_length;
1937
1938 ASSERT(descrpp != NULL);
1939 find_first = (*descrpp == NULL);
1940
1941 /*
1942 * If no descriptor is passed in then return the first
1943 * descriptor
1944 */
1945 if (find_first) {
1946 /*
1947 * The first descriptor will immediately follow the header
1948 * (Pointer arithmetic)
1949 */
1950 cur_descr = (struct scsi_descr_template *)(sdsp+1);
1951 } else {
1952 cur_descr = *descrpp;
1953 ASSERT(cur_descr > (struct scsi_descr_template *)sdsp);
1954 }
1955
1956 /* Assume no more descriptors are available */
1957 *descrpp = NULL;
1958
1959 /*
1960 * Calculate the amount of valid sense data -- make sure the length
1961 * byte in this descriptor lies within the valid sense data.
1962 */
1963 valid_sense_length =
1964 min((sizeof (struct scsi_descr_sense_hdr) +
1965 sdsp->ds_addl_sense_length),
1966 sense_buf_len);
1967
1968 /*
1969 * Make sure this descriptor is complete (either the first
1970 * descriptor or the descriptor passed in)
1971 */
1972 if (scsi_validate_descr(sdsp, valid_sense_length, cur_descr) !=
1973 DESCR_GOOD) {
1974 return (-1);
1975 }
1976
1977 /*
1978 * If we were looking for the first descriptor go ahead and return it
1979 */
1980 if (find_first) {
1981 *descrpp = cur_descr;
1982 return ((*descrpp)->sdt_descr_type);
1983 }
1984
1985 /*
1986 * Get pointer to next descriptor
1987 */
1988 cur_descr = NEXT_DESCR_PTR(cur_descr);
1989
1990 /*
1991 * Make sure this descriptor is also complete.
1992 */
1993 if (scsi_validate_descr(sdsp, valid_sense_length, cur_descr) !=
1994 DESCR_GOOD) {
1995 return (-1);
1996 }
1997
1998 *descrpp = (struct scsi_descr_template *)cur_descr;
1999 return ((*descrpp)->sdt_descr_type);
2000 }
2001
2002 static int
scsi_validate_descr(struct scsi_descr_sense_hdr * sdsp,int valid_sense_length,struct scsi_descr_template * descrp)2003 scsi_validate_descr(struct scsi_descr_sense_hdr *sdsp,
2004 int valid_sense_length, struct scsi_descr_template *descrp)
2005 {
2006 int descr_offset, next_descr_offset;
2007
2008 /*
2009 * Make sure length is present
2010 */
2011 descr_offset = (uint8_t *)descrp - (uint8_t *)sdsp;
2012 if (descr_offset + sizeof (struct scsi_descr_template) >
2013 valid_sense_length) {
2014 return (DESCR_PARTIAL);
2015 }
2016
2017 /*
2018 * Check if length is 0 (no more descriptors)
2019 */
2020 if (descrp->sdt_addl_length == 0) {
2021 return (DESCR_END);
2022 }
2023
2024 /*
2025 * Make sure the rest of the descriptor is present
2026 */
2027 next_descr_offset =
2028 (uint8_t *)NEXT_DESCR_PTR(descrp) - (uint8_t *)sdsp;
2029 if (next_descr_offset > valid_sense_length) {
2030 return (DESCR_PARTIAL);
2031 }
2032
2033 return (DESCR_GOOD);
2034 }
2035
2036 /*
2037 * Internal data structure for handling uscsi command.
2038 */
2039 typedef struct uscsi_i_cmd {
2040 struct uscsi_cmd uic_cmd;
2041 caddr_t uic_rqbuf;
2042 uchar_t uic_rqlen;
2043 caddr_t uic_cdb;
2044 int uic_flag;
2045 struct scsi_address *uic_ap;
2046 } uscsi_i_cmd_t;
2047
2048 #if !defined(lint)
2049 _NOTE(SCHEME_PROTECTS_DATA("unshared data", uscsi_i_cmd))
2050 #endif
2051
2052 /*ARGSUSED*/
2053 static void
scsi_uscsi_mincnt(struct buf * bp)2054 scsi_uscsi_mincnt(struct buf *bp)
2055 {
2056 /*
2057 * Do not break up because the CDB count would then be
2058 * incorrect and create spurious data underrun errors.
2059 */
2060 }
2061
2062 /*
2063 * Function: scsi_uscsi_alloc_and_copyin
2064 *
2065 * Description: Target drivers call this function to allocate memeory,
2066 * copy in, and convert ILP32/LP64 to make preparations for handling
2067 * uscsi commands.
2068 *
2069 * Arguments:
2070 * arg - pointer to the caller's uscsi command struct
2071 * flag - mode, corresponds to ioctl(9e) 'mode'
2072 * ap - SCSI address structure
2073 * uscmdp - pointer to the converted uscsi command
2074 *
2075 * Return code: 0
2076 * EFAULT
2077 * EINVAL
2078 *
2079 * Context: Never called at interrupt context.
2080 */
2081
2082 int
scsi_uscsi_alloc_and_copyin(intptr_t arg,int flag,struct scsi_address * ap,struct uscsi_cmd ** uscmdp)2083 scsi_uscsi_alloc_and_copyin(intptr_t arg, int flag, struct scsi_address *ap,
2084 struct uscsi_cmd **uscmdp)
2085 {
2086 int rval = 0;
2087 struct uscsi_cmd *uscmd;
2088
2089 /*
2090 * In order to not worry about where the uscsi structure came
2091 * from (or where the cdb it points to came from) we're going
2092 * to make kmem_alloc'd copies of them here. This will also
2093 * allow reference to the data they contain long after this
2094 * process has gone to sleep and its kernel stack has been
2095 * unmapped, etc. First get some memory for the uscsi_cmd
2096 * struct and copy the contents of the given uscsi_cmd struct
2097 * into it. We also save infos of the uscsi command by using
2098 * uicmd to supply referrence for the copyout operation.
2099 */
2100 uscmd = scsi_uscsi_alloc();
2101
2102 if ((rval = scsi_uscsi_copyin(arg, flag, ap, &uscmd)) != 0) {
2103 scsi_uscsi_free(uscmd);
2104 *uscmdp = NULL;
2105 rval = EFAULT;
2106 } else {
2107 *uscmdp = uscmd;
2108 }
2109
2110 return (rval);
2111 }
2112
2113 struct uscsi_cmd *
scsi_uscsi_alloc()2114 scsi_uscsi_alloc()
2115 {
2116 struct uscsi_i_cmd *uicmd;
2117
2118 uicmd = (struct uscsi_i_cmd *)
2119 kmem_zalloc(sizeof (struct uscsi_i_cmd), KM_SLEEP);
2120
2121 /*
2122 * It is supposed that the uscsi_cmd has been alloced correctly,
2123 * we need to check is it NULL or mis-created.
2124 */
2125 ASSERT(uicmd && (offsetof(struct uscsi_i_cmd, uic_cmd) == 0));
2126
2127 return (&uicmd->uic_cmd);
2128 }
2129
2130 int
scsi_uscsi_copyin(intptr_t arg,int flag,struct scsi_address * ap,struct uscsi_cmd ** uscmdp)2131 scsi_uscsi_copyin(intptr_t arg, int flag, struct scsi_address *ap,
2132 struct uscsi_cmd **uscmdp)
2133 {
2134 #ifdef _MULTI_DATAMODEL
2135 /*
2136 * For use when a 32 bit app makes a call into a
2137 * 64 bit ioctl
2138 */
2139 struct uscsi_cmd32 uscsi_cmd_32_for_64;
2140 struct uscsi_cmd32 *ucmd32 = &uscsi_cmd_32_for_64;
2141 #endif /* _MULTI_DATAMODEL */
2142 struct uscsi_cmd *uscmd = *uscmdp;
2143 struct uscsi_i_cmd *uicmd = (struct uscsi_i_cmd *)(uscmd);
2144 int max_hba_cdb;
2145 int rval;
2146 extern dev_info_t *scsi_vhci_dip;
2147
2148 ASSERT(uscmd != NULL);
2149 ASSERT(uicmd != NULL);
2150
2151 /*
2152 * To be able to issue multiple commands off a single uscmdp
2153 * We need to free the original cdb, rqbuf and bzero the uscmdp
2154 * if the cdb, rqbuf and uscmdp is not NULL
2155 */
2156 if (uscmd->uscsi_rqbuf != NULL)
2157 kmem_free(uscmd->uscsi_rqbuf, uscmd->uscsi_rqlen);
2158 if (uscmd->uscsi_cdb != NULL)
2159 kmem_free(uscmd->uscsi_cdb, uscmd->uscsi_cdblen);
2160 bzero(uscmd, sizeof (struct uscsi_cmd));
2161
2162
2163 #ifdef _MULTI_DATAMODEL
2164 switch (ddi_model_convert_from(flag & FMODELS)) {
2165 case DDI_MODEL_ILP32:
2166 if (ddi_copyin((void *)arg, ucmd32, sizeof (*ucmd32), flag)) {
2167 rval = EFAULT;
2168 goto scsi_uscsi_copyin_failed;
2169 }
2170 /*
2171 * Convert the ILP32 uscsi data from the
2172 * application to LP64 for internal use.
2173 */
2174 uscsi_cmd32touscsi_cmd(ucmd32, uscmd);
2175 break;
2176 case DDI_MODEL_NONE:
2177 if (ddi_copyin((void *)arg, uscmd, sizeof (*uscmd), flag)) {
2178 rval = EFAULT;
2179 goto scsi_uscsi_copyin_failed;
2180 }
2181 break;
2182 default:
2183 rval = EFAULT;
2184 goto scsi_uscsi_copyin_failed;
2185 }
2186 #else /* ! _MULTI_DATAMODEL */
2187 if (ddi_copyin((void *)arg, uscmd, sizeof (*uscmd), flag)) {
2188 rval = EFAULT;
2189 goto scsi_uscsi_copyin_failed;
2190 }
2191 #endif /* _MULTI_DATAMODEL */
2192
2193 /*
2194 * We are going to allocate kernel virtual addresses for
2195 * uscsi_rqbuf and uscsi_cdb pointers, so save off the
2196 * original, possibly user virtual, uscsi_addresses
2197 * in uic_fields
2198 */
2199 uicmd->uic_rqbuf = uscmd->uscsi_rqbuf;
2200 uicmd->uic_rqlen = uscmd->uscsi_rqlen;
2201 uicmd->uic_cdb = uscmd->uscsi_cdb;
2202 uicmd->uic_flag = flag;
2203 uicmd->uic_ap = ap;
2204
2205 /*
2206 * Skip the following steps if we meet RESET commands.
2207 */
2208 if (uscmd->uscsi_flags &
2209 (USCSI_RESET_LUN | USCSI_RESET_TARGET | USCSI_RESET_ALL)) {
2210 uscmd->uscsi_rqbuf = NULL;
2211 uscmd->uscsi_cdb = NULL;
2212 return (0);
2213 }
2214
2215 /*
2216 * Currently, USCSI_PATH_INSTANCE is only valid when directed
2217 * to scsi_vhci.
2218 */
2219 if ((uscmd->uscsi_flags & USCSI_PATH_INSTANCE) &&
2220 (A_TO_TRAN(ap)->tran_hba_dip != scsi_vhci_dip)) {
2221 rval = EFAULT;
2222 goto scsi_uscsi_copyin_failed;
2223 }
2224
2225 /*
2226 * Perfunctory sanity checks. Get the maximum hba supported
2227 * cdb length first.
2228 */
2229 max_hba_cdb = scsi_ifgetcap(ap, "max-cdb-length", 1);
2230 if (max_hba_cdb < CDB_GROUP0) {
2231 max_hba_cdb = CDB_GROUP4;
2232 }
2233 if (uscmd->uscsi_cdblen < CDB_GROUP0 ||
2234 uscmd->uscsi_cdblen > max_hba_cdb) {
2235 rval = EINVAL;
2236 goto scsi_uscsi_copyin_failed;
2237 }
2238 if ((uscmd->uscsi_flags & USCSI_RQENABLE) &&
2239 (uscmd->uscsi_rqlen == 0 || uscmd->uscsi_rqbuf == NULL)) {
2240 rval = EINVAL;
2241 goto scsi_uscsi_copyin_failed;
2242 }
2243
2244 /*
2245 * To extend uscsi_cmd in the future, we need to ensure current
2246 * reserved bits remain unused (zero).
2247 */
2248 if (uscmd->uscsi_flags & USCSI_RESERVED) {
2249 rval = EINVAL;
2250 goto scsi_uscsi_copyin_failed;
2251 }
2252
2253 /*
2254 * Now we get some space for the CDB, and copy the given CDB into
2255 * it. Use ddi_copyin() in case the data is in user space.
2256 */
2257 uscmd->uscsi_cdb = kmem_zalloc((size_t)uscmd->uscsi_cdblen, KM_SLEEP);
2258 if (ddi_copyin(uicmd->uic_cdb, uscmd->uscsi_cdb,
2259 (uint_t)uscmd->uscsi_cdblen, flag) != 0) {
2260 kmem_free(uscmd->uscsi_cdb, (size_t)uscmd->uscsi_cdblen);
2261 rval = EFAULT;
2262 goto scsi_uscsi_copyin_failed;
2263 }
2264
2265 if (uscmd->uscsi_cdb[0] != SCMD_VAR_LEN) {
2266 if (uscmd->uscsi_cdblen > SCSI_CDB_SIZE ||
2267 scsi_cdb_size[CDB_GROUPID(uscmd->uscsi_cdb[0])] >
2268 uscmd->uscsi_cdblen) {
2269 kmem_free(uscmd->uscsi_cdb,
2270 (size_t)uscmd->uscsi_cdblen);
2271 rval = EINVAL;
2272 goto scsi_uscsi_copyin_failed;
2273 }
2274 } else {
2275 if ((uscmd->uscsi_cdblen % 4) != 0) {
2276 kmem_free(uscmd->uscsi_cdb,
2277 (size_t)uscmd->uscsi_cdblen);
2278 rval = EINVAL;
2279 goto scsi_uscsi_copyin_failed;
2280 }
2281 }
2282
2283 /*
2284 * Initialize Request Sense buffering, if requested.
2285 */
2286 if (uscmd->uscsi_flags & USCSI_RQENABLE) {
2287 /*
2288 * Here uscmd->uscsi_rqbuf currently points to the caller's
2289 * buffer, but we replace this with a kernel buffer that
2290 * we allocate to use with the sense data. The sense data
2291 * (if present) gets copied into this new buffer before the
2292 * command is completed. Then we copy the sense data from
2293 * our allocated buf into the caller's buffer below. Note
2294 * that uscmd->uscsi_rqbuf and uscmd->uscsi_rqlen are used
2295 * below to perform the copy back to the caller's buf.
2296 */
2297 if (uicmd->uic_rqlen <= SENSE_LENGTH) {
2298 uscmd->uscsi_rqlen = SENSE_LENGTH;
2299 uscmd->uscsi_rqbuf = kmem_zalloc(SENSE_LENGTH,
2300 KM_SLEEP);
2301 } else {
2302 uscmd->uscsi_rqlen = MAX_SENSE_LENGTH;
2303 uscmd->uscsi_rqbuf = kmem_zalloc(MAX_SENSE_LENGTH,
2304 KM_SLEEP);
2305 }
2306 uscmd->uscsi_rqresid = uscmd->uscsi_rqlen;
2307 } else {
2308 uscmd->uscsi_rqbuf = NULL;
2309 uscmd->uscsi_rqlen = 0;
2310 uscmd->uscsi_rqresid = 0;
2311 }
2312 return (0);
2313
2314 scsi_uscsi_copyin_failed:
2315 /*
2316 * The uscsi_rqbuf and uscsi_cdb is refering to user-land
2317 * address now, no need to free them.
2318 */
2319 uscmd->uscsi_rqbuf = NULL;
2320 uscmd->uscsi_cdb = NULL;
2321
2322 return (rval);
2323 }
2324
2325 /*
2326 * Function: scsi_uscsi_handle_cmd
2327 *
2328 * Description: Target drivers call this function to handle uscsi commands.
2329 *
2330 * Arguments:
2331 * dev - device number
2332 * dataspace - UIO_USERSPACE or UIO_SYSSPACE
2333 * uscmd - pointer to the converted uscsi command
2334 * strat - pointer to the driver's strategy routine
2335 * bp - buf struct ptr
2336 * private_data - pointer to bp->b_private
2337 *
2338 * Return code: 0
2339 * EIO - scsi_reset() failed, or see biowait()/physio() codes.
2340 * EINVAL
2341 * return code of biowait(9F) or physio(9F):
2342 * EIO - IO error
2343 * ENXIO
2344 * EACCES - reservation conflict
2345 *
2346 * Context: Never called at interrupt context.
2347 */
2348
2349 int
scsi_uscsi_handle_cmd(dev_t dev,enum uio_seg dataspace,struct uscsi_cmd * uscmd,int (* strat)(struct buf *),struct buf * bp,void * private_data)2350 scsi_uscsi_handle_cmd(dev_t dev, enum uio_seg dataspace,
2351 struct uscsi_cmd *uscmd, int (*strat)(struct buf *),
2352 struct buf *bp, void *private_data)
2353 {
2354 struct uscsi_i_cmd *uicmd = (struct uscsi_i_cmd *)uscmd;
2355 int bp_alloc_flag = 0;
2356 int rval;
2357
2358 /*
2359 * Perform resets directly; no need to generate a command to do it.
2360 */
2361 if (uscmd->uscsi_flags &
2362 (USCSI_RESET_LUN | USCSI_RESET_TARGET | USCSI_RESET_ALL)) {
2363 int flags = (uscmd->uscsi_flags & USCSI_RESET_ALL) ?
2364 RESET_ALL : ((uscmd->uscsi_flags & USCSI_RESET_TARGET) ?
2365 RESET_TARGET : RESET_LUN);
2366 if (scsi_reset(uicmd->uic_ap, flags) == 0) {
2367 /* Reset attempt was unsuccessful */
2368 return (EIO);
2369 }
2370 return (0);
2371 }
2372
2373 /*
2374 * Force asynchronous mode, if necessary. Doing this here
2375 * has the unfortunate effect of running other queued
2376 * commands async also, but since the main purpose of this
2377 * capability is downloading new drive firmware, we can
2378 * probably live with it.
2379 */
2380 if (uscmd->uscsi_flags & USCSI_ASYNC) {
2381 if (scsi_ifgetcap(uicmd->uic_ap, "synchronous", 1) == 1) {
2382 if (scsi_ifsetcap(uicmd->uic_ap, "synchronous",
2383 0, 1) != 1) {
2384 return (EINVAL);
2385 }
2386 }
2387 }
2388
2389 /*
2390 * Re-enable synchronous mode, if requested.
2391 */
2392 if (uscmd->uscsi_flags & USCSI_SYNC) {
2393 if (scsi_ifgetcap(uicmd->uic_ap, "synchronous", 1) == 0) {
2394 rval = scsi_ifsetcap(uicmd->uic_ap, "synchronous",
2395 1, 1);
2396 }
2397 }
2398
2399 /*
2400 * If bp is NULL, allocate space here.
2401 */
2402 if (bp == NULL) {
2403 bp = getrbuf(KM_SLEEP);
2404 bp->b_private = private_data;
2405 bp_alloc_flag = 1;
2406 }
2407
2408 /*
2409 * If we're going to do actual I/O, let physio do all the right things.
2410 */
2411 if (uscmd->uscsi_buflen != 0) {
2412 struct iovec aiov;
2413 struct uio auio;
2414 struct uio *uio = &auio;
2415
2416 bzero(&auio, sizeof (struct uio));
2417 bzero(&aiov, sizeof (struct iovec));
2418 aiov.iov_base = uscmd->uscsi_bufaddr;
2419 aiov.iov_len = uscmd->uscsi_buflen;
2420 uio->uio_iov = &aiov;
2421
2422 uio->uio_iovcnt = 1;
2423 uio->uio_resid = uscmd->uscsi_buflen;
2424 uio->uio_segflg = dataspace;
2425
2426 /*
2427 * physio() will block here until the command completes....
2428 */
2429 rval = physio(strat, bp, dev,
2430 ((uscmd->uscsi_flags & USCSI_READ) ? B_READ : B_WRITE),
2431 scsi_uscsi_mincnt, uio);
2432 } else {
2433 /*
2434 * We have to mimic that physio would do here! Argh!
2435 */
2436 bp->b_flags = B_BUSY |
2437 ((uscmd->uscsi_flags & USCSI_READ) ? B_READ : B_WRITE);
2438 bp->b_edev = dev;
2439 bp->b_dev = cmpdev(dev); /* maybe unnecessary? */
2440 bp->b_bcount = 0;
2441 bp->b_blkno = 0;
2442 bp->b_resid = 0;
2443
2444 (void) (*strat)(bp);
2445 rval = biowait(bp);
2446 }
2447 uscmd->uscsi_resid = bp->b_resid;
2448
2449 if (bp_alloc_flag == 1) {
2450 bp_mapout(bp);
2451 freerbuf(bp);
2452 }
2453
2454 return (rval);
2455 }
2456
2457 /*
2458 * Function: scsi_uscsi_pktinit
2459 *
2460 * Description: Target drivers call this function to transfer uscsi_cmd
2461 * information into a scsi_pkt before sending the scsi_pkt.
2462 *
2463 * NB: At this point the implementation is limited to path_instance.
2464 * At some point more code could be removed from the target driver by
2465 * enhancing this function - with the added benifit of making the uscsi
2466 * implementation more consistent accross all drivers.
2467 *
2468 * Arguments:
2469 * uscmd - pointer to the uscsi command
2470 * pkt - pointer to the scsi_pkt
2471 *
2472 * Return code: 1 on successfull transfer, 0 on failure.
2473 */
2474 int
scsi_uscsi_pktinit(struct uscsi_cmd * uscmd,struct scsi_pkt * pkt)2475 scsi_uscsi_pktinit(struct uscsi_cmd *uscmd, struct scsi_pkt *pkt)
2476 {
2477
2478 /*
2479 * Check if the NACA flag is set. If one initiator sets it
2480 * but does not clear it, other initiators would end up
2481 * waiting indefinitely for the first to clear NACA. If the
2482 * the system allows NACA to be set, then warn the user but
2483 * still pass the command down, otherwise, clear the flag.
2484 */
2485 if (uscmd->uscsi_cdb[uscmd->uscsi_cdblen - 1] & CDB_FLAG_NACA) {
2486 if (scsi_pkt_allow_naca) {
2487 cmn_err(CE_WARN, "scsi_uscsi_pktinit: "
2488 "NACA flag is set");
2489 } else {
2490 uscmd->uscsi_cdb[uscmd->uscsi_cdblen - 1] &=
2491 ~CDB_FLAG_NACA;
2492 cmn_err(CE_WARN, "scsi_uscsi_pktinit: "
2493 "NACA flag is cleared");
2494 }
2495 }
2496
2497 /*
2498 * See if path_instance was requested in uscsi_cmd.
2499 */
2500 if ((uscmd->uscsi_flags & USCSI_PATH_INSTANCE) &&
2501 (uscmd->uscsi_path_instance != 0)) {
2502 /*
2503 * Check to make sure the scsi_pkt was allocated correctly
2504 * before transferring uscsi(4I) path_instance to scsi_pkt(9S).
2505 */
2506 if (scsi_pkt_allocated_correctly(pkt)) {
2507 /* set pkt_path_instance and flag. */
2508 pkt->pkt_flags |= FLAG_PKT_PATH_INSTANCE;
2509 pkt->pkt_path_instance = uscmd->uscsi_path_instance;
2510 } else {
2511 return (0); /* failure */
2512 }
2513 } else {
2514 /*
2515 * Can only use pkt_path_instance if the packet
2516 * was correctly allocated.
2517 */
2518 if (scsi_pkt_allocated_correctly(pkt)) {
2519 pkt->pkt_path_instance = 0;
2520 }
2521 pkt->pkt_flags &= ~FLAG_PKT_PATH_INSTANCE;
2522 }
2523
2524 return (1); /* success */
2525 }
2526
2527 /*
2528 * Function: scsi_uscsi_pktfini
2529 *
2530 * Description: Target drivers call this function to transfer completed
2531 * scsi_pkt information back into uscsi_cmd.
2532 *
2533 * NB: At this point the implementation is limited to path_instance.
2534 * At some point more code could be removed from the target driver by
2535 * enhancing this function - with the added benifit of making the uscsi
2536 * implementation more consistent accross all drivers.
2537 *
2538 * Arguments:
2539 * pkt - pointer to the scsi_pkt
2540 * uscmd - pointer to the uscsi command
2541 *
2542 * Return code: 1 on successfull transfer, 0 on failure.
2543 */
2544 int
scsi_uscsi_pktfini(struct scsi_pkt * pkt,struct uscsi_cmd * uscmd)2545 scsi_uscsi_pktfini(struct scsi_pkt *pkt, struct uscsi_cmd *uscmd)
2546 {
2547 /*
2548 * Check to make sure the scsi_pkt was allocated correctly before
2549 * transferring scsi_pkt(9S) path_instance to uscsi(4I).
2550 */
2551 if (!scsi_pkt_allocated_correctly(pkt)) {
2552 uscmd->uscsi_path_instance = 0;
2553 return (0); /* failure */
2554 }
2555
2556 uscmd->uscsi_path_instance = pkt->pkt_path_instance;
2557 /* reset path_instance */
2558 pkt->pkt_flags &= ~FLAG_PKT_PATH_INSTANCE;
2559 pkt->pkt_path_instance = 0;
2560 return (1); /* success */
2561 }
2562
2563 /*
2564 * Function: scsi_uscsi_copyout_and_free
2565 *
2566 * Description: Target drivers call this function to undo what was done by
2567 * scsi_uscsi_alloc_and_copyin.
2568 *
2569 * Arguments: arg - pointer to the uscsi command to be returned
2570 * uscmd - pointer to the converted uscsi command
2571 *
2572 * Return code: 0
2573 * EFAULT
2574 *
2575 * Context: Never called at interrupt context.
2576 */
2577 int
scsi_uscsi_copyout_and_free(intptr_t arg,struct uscsi_cmd * uscmd)2578 scsi_uscsi_copyout_and_free(intptr_t arg, struct uscsi_cmd *uscmd)
2579 {
2580 int rval = 0;
2581
2582 rval = scsi_uscsi_copyout(arg, uscmd);
2583
2584 scsi_uscsi_free(uscmd);
2585
2586 return (rval);
2587 }
2588
2589 int
scsi_uscsi_copyout(intptr_t arg,struct uscsi_cmd * uscmd)2590 scsi_uscsi_copyout(intptr_t arg, struct uscsi_cmd *uscmd)
2591 {
2592 #ifdef _MULTI_DATAMODEL
2593 /*
2594 * For use when a 32 bit app makes a call into a
2595 * 64 bit ioctl.
2596 */
2597 struct uscsi_cmd32 uscsi_cmd_32_for_64;
2598 struct uscsi_cmd32 *ucmd32 = &uscsi_cmd_32_for_64;
2599 #endif /* _MULTI_DATAMODEL */
2600 struct uscsi_i_cmd *uicmd = (struct uscsi_i_cmd *)uscmd;
2601 caddr_t k_rqbuf;
2602 int k_rqlen;
2603 caddr_t k_cdb;
2604 int rval = 0;
2605
2606 /*
2607 * If the caller wants sense data, copy back whatever sense data
2608 * we may have gotten, and update the relevant rqsense info.
2609 */
2610 if ((uscmd->uscsi_flags & USCSI_RQENABLE) &&
2611 (uscmd->uscsi_rqbuf != NULL)) {
2612 int rqlen = uscmd->uscsi_rqlen - uscmd->uscsi_rqresid;
2613 rqlen = min(((int)uicmd->uic_rqlen), rqlen);
2614 uscmd->uscsi_rqresid = uicmd->uic_rqlen - rqlen;
2615 /*
2616 * Copy out the sense data for user process.
2617 */
2618 if ((uicmd->uic_rqbuf != NULL) && (rqlen != 0)) {
2619 if (ddi_copyout(uscmd->uscsi_rqbuf,
2620 uicmd->uic_rqbuf, rqlen, uicmd->uic_flag) != 0) {
2621 rval = EFAULT;
2622 }
2623 }
2624 }
2625
2626 /*
2627 * Restore original uscsi_values, saved in uic_fields for
2628 * copyout (so caller does not experience a change in these
2629 * fields)
2630 */
2631 k_rqbuf = uscmd->uscsi_rqbuf;
2632 k_rqlen = uscmd->uscsi_rqlen;
2633 k_cdb = uscmd->uscsi_cdb;
2634 uscmd->uscsi_rqbuf = uicmd->uic_rqbuf;
2635 uscmd->uscsi_rqlen = uicmd->uic_rqlen;
2636 uscmd->uscsi_cdb = uicmd->uic_cdb;
2637
2638 #ifdef _MULTI_DATAMODEL
2639 switch (ddi_model_convert_from(uicmd->uic_flag & FMODELS)) {
2640 case DDI_MODEL_ILP32:
2641 /*
2642 * Convert back to ILP32 before copyout to the
2643 * application
2644 */
2645 uscsi_cmdtouscsi_cmd32(uscmd, ucmd32);
2646 if (ddi_copyout(ucmd32, (void *)arg, sizeof (*ucmd32),
2647 uicmd->uic_flag)) {
2648 rval = EFAULT;
2649 }
2650 break;
2651 case DDI_MODEL_NONE:
2652 if (ddi_copyout(uscmd, (void *)arg, sizeof (*uscmd),
2653 uicmd->uic_flag)) {
2654 rval = EFAULT;
2655 }
2656 break;
2657 default:
2658 rval = EFAULT;
2659 }
2660 #else /* _MULTI_DATAMODE */
2661 if (ddi_copyout(uscmd, (void *)arg, sizeof (*uscmd), uicmd->uic_flag)) {
2662 rval = EFAULT;
2663 }
2664 #endif /* _MULTI_DATAMODE */
2665
2666 /*
2667 * Copyout done, restore kernel virtual addresses for further
2668 * scsi_uscsi_free().
2669 */
2670 uscmd->uscsi_rqbuf = k_rqbuf;
2671 uscmd->uscsi_rqlen = k_rqlen;
2672 uscmd->uscsi_cdb = k_cdb;
2673
2674 return (rval);
2675 }
2676
2677 void
scsi_uscsi_free(struct uscsi_cmd * uscmd)2678 scsi_uscsi_free(struct uscsi_cmd *uscmd)
2679 {
2680 struct uscsi_i_cmd *uicmd = (struct uscsi_i_cmd *)uscmd;
2681
2682 ASSERT(uicmd != NULL);
2683
2684 if ((uscmd->uscsi_rqbuf != NULL) && (uscmd->uscsi_rqlen != 0)) {
2685 kmem_free(uscmd->uscsi_rqbuf, (size_t)uscmd->uscsi_rqlen);
2686 uscmd->uscsi_rqbuf = NULL;
2687 }
2688
2689 if ((uscmd->uscsi_cdb != NULL) && (uscmd->uscsi_cdblen != 0)) {
2690 kmem_free(uscmd->uscsi_cdb, (size_t)uscmd->uscsi_cdblen);
2691 uscmd->uscsi_cdb = NULL;
2692 }
2693
2694 kmem_free(uicmd, sizeof (struct uscsi_i_cmd));
2695 }
2696