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 */
25
26 #include <sys/scsi/scsi.h>
27 #include <sys/file.h>
28
29 /*
30 * Utility SCSI routines
31 */
32
33 /*
34 * Polling support routines
35 */
36
37 int scsi_pkt_allow_naca = 0;
38 extern uintptr_t scsi_callback_id;
39
40 extern uchar_t scsi_cdb_size[];
41
42 /*
43 * Common buffer for scsi_log
44 */
45
46 extern kmutex_t scsi_log_mutex;
47 static char scsi_log_buffer[MAXPATHLEN + 1];
48
49
50 #define A_TO_TRAN(ap) (ap->a_hba_tran)
51 #define P_TO_TRAN(pkt) ((pkt)->pkt_address.a_hba_tran)
52 #define P_TO_ADDR(pkt) (&((pkt)->pkt_address))
53
54 #define CSEC 10000 /* usecs */
55 #define SEC_TO_CSEC (1000000/CSEC)
56
57 extern ddi_dma_attr_t scsi_alloc_attr;
58
59 /*PRINTFLIKE4*/
60 static void impl_scsi_log(dev_info_t *dev, char *label, uint_t level,
61 const char *fmt, ...) __KPRINTFLIKE(4);
62 /*PRINTFLIKE4*/
63 static void v_scsi_log(dev_info_t *dev, char *label, uint_t level,
64 const char *fmt, va_list ap) __KVPRINTFLIKE(4);
65
66 static int
67 scsi_get_next_descr(uint8_t *sdsp,
68 int sense_buf_len, struct scsi_descr_template **descrpp);
69
70 #define DESCR_GOOD 0
71 #define DESCR_PARTIAL 1
72 #define DESCR_END 2
73
74 static int
75 scsi_validate_descr(struct scsi_descr_sense_hdr *sdsp,
76 int valid_sense_length, struct scsi_descr_template *descrp);
77
78 int
79 scsi_poll(struct scsi_pkt *pkt)
80 {
81 int rval = -1;
82 int savef;
83 long savet;
84 void (*savec)();
85 int timeout;
86 int busy_count;
87 int poll_delay;
88 int rc;
89 uint8_t *sensep;
90 struct scsi_arq_status *arqstat;
91 extern int do_polled_io;
92
93 ASSERT(pkt->pkt_scbp);
94
95 /*
96 * save old flags..
97 */
98 savef = pkt->pkt_flags;
99 savec = pkt->pkt_comp;
100 savet = pkt->pkt_time;
101
102 pkt->pkt_flags |= FLAG_NOINTR;
103
104 /*
105 * XXX there is nothing in the SCSA spec that states that we should not
106 * do a callback for polled cmds; however, removing this will break sd
107 * and probably other target drivers
108 */
109 pkt->pkt_comp = NULL;
110
111 /*
112 * we don't like a polled command without timeout.
113 * 60 seconds seems long enough.
114 */
115 if (pkt->pkt_time == 0)
116 pkt->pkt_time = SCSI_POLL_TIMEOUT;
117
118 /*
119 * Send polled cmd.
120 *
121 * We do some error recovery for various errors. Tran_busy,
122 * queue full, and non-dispatched commands are retried every 10 msec.
123 * as they are typically transient failures. Busy status and Not
124 * Ready are retried every second as this status takes a while to
125 * change.
126 */
127 timeout = pkt->pkt_time * SEC_TO_CSEC;
128
129 for (busy_count = 0; busy_count < timeout; busy_count++) {
130 /*
131 * Initialize pkt status variables.
132 */
133 *pkt->pkt_scbp = pkt->pkt_reason = pkt->pkt_state = 0;
134
135 if ((rc = scsi_transport(pkt)) != TRAN_ACCEPT) {
136 if (rc != TRAN_BUSY) {
137 /* Transport failed - give up. */
138 break;
139 } else {
140 /* Transport busy - try again. */
141 poll_delay = 1 * CSEC; /* 10 msec. */
142 }
143 } else {
144 /*
145 * Transport accepted - check pkt status.
146 */
147 rc = (*pkt->pkt_scbp) & STATUS_MASK;
148 if ((pkt->pkt_reason == CMD_CMPLT) &&
149 (rc == STATUS_CHECK) &&
150 (pkt->pkt_state & STATE_ARQ_DONE)) {
151 arqstat =
152 (struct scsi_arq_status *)(pkt->pkt_scbp);
153 sensep = (uint8_t *)&arqstat->sts_sensedata;
154 } else {
155 sensep = NULL;
156 }
157
158 if ((pkt->pkt_reason == CMD_CMPLT) &&
159 (rc == STATUS_GOOD)) {
160 /* No error - we're done */
161 rval = 0;
162 break;
163
164 } else if (pkt->pkt_reason == CMD_DEV_GONE) {
165 /* Lost connection - give up */
166 break;
167
168 } else if ((pkt->pkt_reason == CMD_INCOMPLETE) &&
169 (pkt->pkt_state == 0)) {
170 /* Pkt not dispatched - try again. */
171 poll_delay = 1 * CSEC; /* 10 msec. */
172
173 } else if ((pkt->pkt_reason == CMD_CMPLT) &&
174 (rc == STATUS_QFULL)) {
175 /* Queue full - try again. */
176 poll_delay = 1 * CSEC; /* 10 msec. */
177
178 } else if ((pkt->pkt_reason == CMD_CMPLT) &&
179 (rc == STATUS_BUSY)) {
180 /* Busy - try again. */
181 poll_delay = 100 * CSEC; /* 1 sec. */
182 busy_count += (SEC_TO_CSEC - 1);
183
184 } else if ((sensep != NULL) &&
185 (scsi_sense_key(sensep) == KEY_NOT_READY) &&
186 (scsi_sense_asc(sensep) == 0x04) &&
187 (scsi_sense_ascq(sensep) == 0x01)) {
188 /*
189 * Not ready -> ready - try again.
190 * 04h/01h: LUN IS IN PROCESS OF BECOMING READY
191 * ...same as STATUS_BUSY
192 */
193 poll_delay = 100 * CSEC; /* 1 sec. */
194 busy_count += (SEC_TO_CSEC - 1);
195
196 } else {
197 /* BAD status - give up. */
198 break;
199 }
200 }
201
202 if (((curthread->t_flag & T_INTR_THREAD) == 0) &&
203 !do_polled_io) {
204 delay(drv_usectohz(poll_delay));
205 } else {
206 /* we busy wait during cpr_dump or interrupt threads */
207 drv_usecwait(poll_delay);
208 }
209 }
210
211 pkt->pkt_flags = savef;
212 pkt->pkt_comp = savec;
213 pkt->pkt_time = savet;
214
215 /* return on error */
216 if (rval)
217 return (rval);
218
219 /*
220 * This is not a performance critical code path.
221 *
222 * As an accommodation for scsi_poll callers, to avoid ddi_dma_sync()
223 * issues associated with looking at DMA memory prior to
224 * scsi_pkt_destroy(), we scsi_sync_pkt() prior to return.
225 */
226 scsi_sync_pkt(pkt);
227 return (0);
228 }
229
230 /*
231 * Command packaging routines.
232 *
233 * makecom_g*() are original routines and scsi_setup_cdb()
234 * is the new and preferred routine.
235 */
236
237 /*
238 * These routines put LUN information in CDB byte 1 bits 7-5.
239 * This was required in SCSI-1. SCSI-2 allowed it but it preferred
240 * sending LUN information as part of IDENTIFY message.
241 * This is not allowed in SCSI-3.
242 */
243
244 void
245 makecom_g0(struct scsi_pkt *pkt, struct scsi_device *devp,
246 int flag, int cmd, int addr, int cnt)
247 {
248 MAKECOM_G0(pkt, devp, flag, cmd, addr, (uchar_t)cnt);
249 }
250
251 void
252 makecom_g0_s(struct scsi_pkt *pkt, struct scsi_device *devp,
253 int flag, int cmd, int cnt, int fixbit)
254 {
255 MAKECOM_G0_S(pkt, devp, flag, cmd, cnt, (uchar_t)fixbit);
256 }
257
258 void
259 makecom_g1(struct scsi_pkt *pkt, struct scsi_device *devp,
260 int flag, int cmd, int addr, int cnt)
261 {
262 MAKECOM_G1(pkt, devp, flag, cmd, addr, cnt);
263 }
264
265 void
266 makecom_g5(struct scsi_pkt *pkt, struct scsi_device *devp,
267 int flag, int cmd, int addr, int cnt)
268 {
269 MAKECOM_G5(pkt, devp, flag, cmd, addr, cnt);
270 }
271
272 /*
273 * Following routine does not put LUN information in CDB.
274 * This interface must be used for SCSI-2 targets having
275 * more than 8 LUNs or a SCSI-3 target.
276 */
277 int
278 scsi_setup_cdb(union scsi_cdb *cdbp, uchar_t cmd, uint_t addr, uint_t cnt,
279 uint_t addtl_cdb_data)
280 {
281 uint_t addr_cnt;
282
283 cdbp->scc_cmd = cmd;
284
285 switch (CDB_GROUPID(cmd)) {
286 case CDB_GROUPID_0:
287 /*
288 * The following calculation is to take care of
289 * the fact that format of some 6 bytes tape
290 * command is different (compare 6 bytes disk and
291 * tape read commands).
292 */
293 addr_cnt = (addr << 8) + cnt;
294 addr = (addr_cnt & 0x1fffff00) >> 8;
295 cnt = addr_cnt & 0xff;
296 FORMG0ADDR(cdbp, addr);
297 FORMG0COUNT(cdbp, cnt);
298 break;
299
300 case CDB_GROUPID_1:
301 case CDB_GROUPID_2:
302 FORMG1ADDR(cdbp, addr);
303 FORMG1COUNT(cdbp, cnt);
304 break;
305
306 case CDB_GROUPID_4:
307 FORMG4ADDR(cdbp, addr);
308 FORMG4COUNT(cdbp, cnt);
309 FORMG4ADDTL(cdbp, addtl_cdb_data);
310 break;
311
312 case CDB_GROUPID_5:
313 FORMG5ADDR(cdbp, addr);
314 FORMG5COUNT(cdbp, cnt);
315 break;
316
317 default:
318 return (0);
319 }
320
321 return (1);
322 }
323
324
325 /*
326 * Common iopbmap data area packet allocation routines
327 */
328
329 struct scsi_pkt *
330 get_pktiopb(struct scsi_address *ap, caddr_t *datap, int cdblen, int statuslen,
331 int datalen, int readflag, int (*func)())
332 {
333 scsi_hba_tran_t *tran = A_TO_TRAN(ap);
334 dev_info_t *pdip = tran->tran_hba_dip;
335 struct scsi_pkt *pkt = NULL;
336 struct buf local;
337 size_t rlen;
338
339 if (!datap)
340 return (pkt);
341 *datap = (caddr_t)0;
342 bzero((caddr_t)&local, sizeof (struct buf));
343
344 /*
345 * use i_ddi_mem_alloc() for now until we have an interface to allocate
346 * memory for DMA which doesn't require a DMA handle.
347 */
348 if (i_ddi_mem_alloc(pdip, &scsi_alloc_attr, datalen,
349 ((func == SLEEP_FUNC) ? 1 : 0), 0, NULL, &local.b_un.b_addr, &rlen,
350 NULL) != DDI_SUCCESS) {
351 return (pkt);
352 }
353 if (readflag)
354 local.b_flags = B_READ;
355 local.b_bcount = datalen;
356 pkt = (*tran->tran_init_pkt) (ap, NULL, &local,
357 cdblen, statuslen, 0, PKT_CONSISTENT,
358 (func == SLEEP_FUNC) ? SLEEP_FUNC : NULL_FUNC, NULL);
359 if (!pkt) {
360 i_ddi_mem_free(local.b_un.b_addr, NULL);
361 if (func != NULL_FUNC) {
362 ddi_set_callback(func, NULL, &scsi_callback_id);
363 }
364 } else {
365 *datap = local.b_un.b_addr;
366 }
367 return (pkt);
368 }
369
370 /*
371 * Equivalent deallocation wrapper
372 */
373
374 void
375 free_pktiopb(struct scsi_pkt *pkt, caddr_t datap, int datalen)
376 {
377 register struct scsi_address *ap = P_TO_ADDR(pkt);
378 register scsi_hba_tran_t *tran = A_TO_TRAN(ap);
379
380 (*tran->tran_destroy_pkt)(ap, pkt);
381 if (datap && datalen) {
382 i_ddi_mem_free(datap, NULL);
383 }
384 if (scsi_callback_id != 0) {
385 ddi_run_callback(&scsi_callback_id);
386 }
387 }
388
389 /*
390 * Common naming functions
391 */
392
393 static char scsi_tmpname[64];
394
395 char *
396 scsi_dname(int dtyp)
397 {
398 static char *dnames[] = DTYPE_ASCII;
399 char *dname = NULL;
400
401 if ((dtyp & DTYPE_MASK) < (sizeof (dnames) / sizeof (*dnames)))
402 dname = dnames[dtyp&DTYPE_MASK];
403 else if (dtyp == DTYPE_NOTPRESENT)
404 dname = "Not Present";
405 if ((dname == NULL) || (*dname == '\0'))
406 dname = "<unknown device type>";
407 return (dname);
408 }
409
410 char *
411 scsi_rname(uchar_t reason)
412 {
413 static char *rnames[] = CMD_REASON_ASCII;
414 char *rname = NULL;
415
416 if (reason < (sizeof (rnames) / sizeof (*rnames)))
417 rname = rnames[reason];
418 if ((rname == NULL) || (*rname == '\0'))
419 rname = "<unknown reason>";
420 return (rname);
421 }
422
423 char *
424 scsi_mname(uchar_t msg)
425 {
426 static char *imsgs[23] = {
427 "COMMAND COMPLETE",
428 "EXTENDED",
429 "SAVE DATA POINTER",
430 "RESTORE POINTERS",
431 "DISCONNECT",
432 "INITIATOR DETECTED ERROR",
433 "ABORT",
434 "REJECT",
435 "NO-OP",
436 "MESSAGE PARITY",
437 "LINKED COMMAND COMPLETE",
438 "LINKED COMMAND COMPLETE (W/FLAG)",
439 "BUS DEVICE RESET",
440 "ABORT TAG",
441 "CLEAR QUEUE",
442 "INITIATE RECOVERY",
443 "RELEASE RECOVERY",
444 "TERMINATE PROCESS",
445 "CONTINUE TASK",
446 "TARGET TRANSFER DISABLE",
447 "RESERVED (0x14)",
448 "RESERVED (0x15)",
449 "CLEAR ACA"
450 };
451 static char *imsgs_2[6] = {
452 "SIMPLE QUEUE TAG",
453 "HEAD OF QUEUE TAG",
454 "ORDERED QUEUE TAG",
455 "IGNORE WIDE RESIDUE",
456 "ACA",
457 "LOGICAL UNIT RESET"
458 };
459
460 if (msg < 23) {
461 return (imsgs[msg]);
462 } else if (IS_IDENTIFY_MSG(msg)) {
463 return ("IDENTIFY");
464 } else if (IS_2BYTE_MSG(msg) &&
465 (int)((msg) & 0xF) < (sizeof (imsgs_2) / sizeof (char *))) {
466 return (imsgs_2[msg & 0xF]);
467 } else {
468 return ("<unknown msg>");
469 }
470
471 }
472
473 char *
474 scsi_cname(uchar_t cmd, char **cmdvec)
475 {
476 while (*cmdvec != NULL) {
477 if (cmd == **cmdvec)
478 return ((char *)(uintptr_t)(*cmdvec + 1));
479 cmdvec++;
480 }
481 return (sprintf(scsi_tmpname, "<undecoded cmd 0x%x>", cmd));
482 }
483
484 char *
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 *
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 *
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 *
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 static char *
1028 scsi_asc_search(uint_t asc, uint_t ascq,
1029 struct scsi_asq_key_strings *list)
1030 {
1031 int i = 0;
1032
1033 while (list[i].asc != 0xffff) {
1034 if ((asc == list[i].asc) &&
1035 ((ascq == list[i].ascq) ||
1036 (list[i].ascq == 0xffff))) {
1037 return ((char *)list[i].message);
1038 }
1039 i++;
1040 }
1041 return (NULL);
1042 }
1043
1044 static char *
1045 scsi_asc_ascq_name(uint_t asc, uint_t ascq, char *tmpstr,
1046 struct scsi_asq_key_strings *list)
1047 {
1048 char *message;
1049
1050 if (list) {
1051 if (message = scsi_asc_search(asc, ascq, list)) {
1052 return (message);
1053 }
1054 }
1055 if (message = scsi_asc_search(asc, ascq, extended_sense_list)) {
1056 return (message);
1057 }
1058
1059 return (sprintf(tmpstr, "<vendor unique code 0x%x>", asc));
1060 }
1061
1062 #define SCSI_LOGBUF_LEN 512
1063
1064 void
1065 scsi_generic_errmsg(struct scsi_device *devp, char *label, int severity,
1066 daddr_t blkno, daddr_t err_blkno,
1067 uchar_t cmd_name, struct scsi_key_strings *cmdlist,
1068 uint8_t *sensep, struct scsi_asq_key_strings *asc_list,
1069 char *(*decode_fru)(struct scsi_device *, char *, int, uchar_t))
1070 {
1071 char cmdbuf[SCSI_LOGBUF_LEN];
1072 char blkbuf[SCSI_LOGBUF_LEN];
1073 char sensebuf[SCSI_LOGBUF_LEN];
1074 char frubuf[SCSI_LOGBUF_LEN];
1075 char tmpbuf[SCSI_LOGBUF_LEN];
1076 static char *error_classes[] = {
1077 "All", "Unknown", "Informational",
1078 "Recovered", "Retryable", "Fatal"
1079 };
1080
1081 mutex_enter(&scsi_log_mutex);
1082
1083 (void) snprintf(cmdbuf, sizeof (cmdbuf), "%s: cmd=%s",
1084 error_classes[severity], scsi_cmd_name(cmd_name, cmdlist, tmpbuf));
1085
1086 blkbuf[0] = '\0';
1087 if ((blkno != -1 || err_blkno != -1) &&
1088 ((cmd_name & 0xf) == SCMD_READ || (cmd_name & 0xf) == SCMD_WRITE)) {
1089 (void) snprintf(blkbuf, sizeof (blkbuf),
1090 " (reqblk=%ld errblk=%ld)", blkno, err_blkno);
1091 }
1092
1093 sensebuf[0] = '\0';
1094 frubuf[0] = '\0';
1095 if (sensep != NULL) {
1096 uchar_t sense_key, asc, ascq, fru_code;
1097 uchar_t *fru_code_ptr;
1098
1099 sense_key = scsi_sense_key(sensep);
1100 asc = scsi_sense_asc(sensep);
1101 ascq = scsi_sense_ascq(sensep);
1102 scsi_ext_sense_fields(sensep, SENSE_LENGTH,
1103 NULL, NULL, &fru_code_ptr, NULL, NULL);
1104
1105 (void) snprintf(sensebuf, sizeof (sensebuf),
1106 " key=%s asc/ascq=0x%x/0x%x (\"%s\")",
1107 sense_keys[sense_key], asc, ascq,
1108 scsi_asc_ascq_name(asc, ascq, tmpbuf, asc_list));
1109
1110 fru_code = (fru_code_ptr != NULL ? *fru_code_ptr : 0);
1111 if (fru_code != 0 &&
1112 decode_fru != NULL) {
1113 (*decode_fru)(devp, tmpbuf, sizeof (tmpbuf), fru_code);
1114 if (tmpbuf[0] != '\0') {
1115 (void) snprintf(frubuf, sizeof (frubuf),
1116 " fru=0x%x (\"%s\")", fru_code, tmpbuf);
1117 }
1118 }
1119 }
1120
1121 impl_scsi_log(devp->sd_dev, label, CE_WARN, "!%s%s%s%s",
1122 cmdbuf, blkbuf, sensebuf, frubuf);
1123
1124 mutex_exit(&scsi_log_mutex);
1125 }
1126
1127 void
1128 scsi_vu_errmsg(struct scsi_device *devp, struct scsi_pkt *pkt, char *label,
1129 int severity, daddr_t blkno, daddr_t err_blkno,
1130 struct scsi_key_strings *cmdlist, struct scsi_extended_sense *sensep,
1131 struct scsi_asq_key_strings *asc_list,
1132 char *(*decode_fru)(struct scsi_device *, char *, int, uchar_t))
1133 {
1134 uchar_t com;
1135
1136 com = ((union scsi_cdb *)pkt->pkt_cdbp)->scc_cmd;
1137
1138 scsi_generic_errmsg(devp, label, severity, blkno, err_blkno,
1139 com, cmdlist, (uint8_t *)sensep, asc_list, decode_fru);
1140 }
1141
1142 void
1143 scsi_errmsg(struct scsi_device *devp, struct scsi_pkt *pkt, char *label,
1144 int severity, daddr_t blkno, daddr_t err_blkno,
1145 struct scsi_key_strings *cmdlist, struct scsi_extended_sense *sensep)
1146 {
1147 scsi_vu_errmsg(devp, pkt, label, severity, blkno,
1148 err_blkno, cmdlist, sensep, NULL, NULL);
1149 }
1150
1151 /*PRINTFLIKE4*/
1152 void
1153 scsi_log(dev_info_t *dev, char *label, uint_t level,
1154 const char *fmt, ...)
1155 {
1156 va_list ap;
1157
1158 va_start(ap, fmt);
1159 mutex_enter(&scsi_log_mutex);
1160 v_scsi_log(dev, label, level, fmt, ap);
1161 mutex_exit(&scsi_log_mutex);
1162 va_end(ap);
1163 }
1164
1165 /*PRINTFLIKE4*/
1166 static void
1167 impl_scsi_log(dev_info_t *dev, char *label, uint_t level,
1168 const char *fmt, ...)
1169 {
1170 va_list ap;
1171
1172 ASSERT(mutex_owned(&scsi_log_mutex));
1173
1174 va_start(ap, fmt);
1175 v_scsi_log(dev, label, level, fmt, ap);
1176 va_end(ap);
1177 }
1178
1179 /*PRINTFLIKE4*/
1180 static void
1181 v_scsi_log(dev_info_t *dev, char *label, uint_t level,
1182 const char *fmt, va_list ap)
1183 {
1184 static char name[256];
1185 int log_only = 0;
1186 int boot_only = 0;
1187 int console_only = 0;
1188
1189 ASSERT(mutex_owned(&scsi_log_mutex));
1190
1191 if (dev != NULL) {
1192 if (level == CE_PANIC || level == CE_WARN ||
1193 level == CE_NOTE || level >= (uint_t)SCSI_DEBUG) {
1194 (void) snprintf(name, sizeof (name), "%s%d: ",
1195 ddi_driver_name(dev), ddi_get_instance(dev));
1196 } else {
1197 name[0] = '\0';
1198 }
1199 } else {
1200 (void) sprintf(name, "%s: ", label);
1201 }
1202
1203 (void) vsprintf(scsi_log_buffer, fmt, ap);
1204
1205 switch (scsi_log_buffer[0]) {
1206 case '!':
1207 log_only = 1;
1208 break;
1209 case '?':
1210 boot_only = 1;
1211 break;
1212 case '^':
1213 console_only = 1;
1214 break;
1215 }
1216
1217 switch (level) {
1218 case CE_NOTE:
1219 level = CE_CONT;
1220 /* FALLTHROUGH */
1221 case CE_CONT:
1222 case CE_WARN:
1223 case CE_PANIC:
1224 if (boot_only) {
1225 cmn_err(level, "?%s%s", name, &scsi_log_buffer[1]);
1226 } else if (console_only) {
1227 cmn_err(level, "^%s%s", name, &scsi_log_buffer[1]);
1228 } else if (log_only) {
1229 cmn_err(level, "!%s%s", name, &scsi_log_buffer[1]);
1230 } else {
1231 cmn_err(level, "%s%s", name, scsi_log_buffer);
1232 }
1233 break;
1234 case (uint_t)SCSI_DEBUG:
1235 default:
1236 cmn_err(CE_CONT, "?DEBUG: %s%s", name, scsi_log_buffer);
1237 break;
1238 }
1239 }
1240
1241 /*
1242 * Lookup the 'prop_name' string array property and walk thru its list of
1243 * tuple values looking for a tuple who's VID/PID string (first part of tuple)
1244 * matches the inquiry VID/PID information for the scsi_device. On a match,
1245 * return a duplicate of the second part of the tuple. If no match is found,
1246 * return NULL. On non-NULL return, caller is responsible for freeing return
1247 * result via:
1248 * kmem_free(string, strlen(string) + 1);
1249 *
1250 * This interface can either be used directly, or indirectly by
1251 * scsi_get_device_type_scsi_options.
1252 */
1253 char *
1254 scsi_get_device_type_string(char *prop_name,
1255 dev_info_t *dip, struct scsi_device *devp)
1256 {
1257 struct scsi_inquiry *inq = devp->sd_inq;
1258 char **tuples;
1259 uint_t ntuples;
1260 int i;
1261 char *tvp; /* tuple vid/pid */
1262 char *trs; /* tuple return string */
1263 int tvp_len;
1264
1265 /* if we have no inquiry data then we can't do this */
1266 if (inq == NULL)
1267 return (NULL);
1268
1269 /*
1270 * So that we can establish a 'prop_name' for all instances of a
1271 * device in the system in a single place if needed (via options.conf),
1272 * we loop going up to the root ourself. This way root lookup does
1273 * *not* specify DDI_PROP_DONTPASS, and the code will look on the
1274 * options node.
1275 */
1276 do {
1277 if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, dip,
1278 (ddi_get_parent(dip) ? DDI_PROP_DONTPASS : 0) |
1279 DDI_PROP_NOTPROM, prop_name, &tuples, &ntuples) ==
1280 DDI_PROP_SUCCESS) {
1281
1282 /* loop over tuples */
1283 for (i = 0; i < (ntuples/2); i++) {
1284 /* split into vid/pid and return-string */
1285 tvp = tuples[i * 2];
1286 trs = tuples[(i * 2) + 1];
1287 tvp_len = strlen(tvp);
1288
1289 /* check for vid/pid match */
1290 if ((tvp_len == 0) ||
1291 bcmp(tvp, inq->inq_vid, tvp_len))
1292 continue; /* no match */
1293
1294 /* match, dup return-string */
1295 trs = i_ddi_strdup(trs, KM_SLEEP);
1296 ddi_prop_free(tuples);
1297 return (trs);
1298 }
1299 ddi_prop_free(tuples);
1300 }
1301
1302 /* climb up to root one step at a time */
1303 dip = ddi_get_parent(dip);
1304 } while (dip);
1305
1306 return (NULL);
1307 }
1308
1309 /*
1310 * The 'device-type-scsi-options' mechanism can be used to establish a device
1311 * specific scsi_options value for a particular device. This mechanism uses
1312 * paired strings ("vendor_info", "options_property_name") from the string
1313 * array "device-type-scsi-options" definition. A bcmp of the vendor info is
1314 * done against the inquiry data (inq_vid). Here is an example of use:
1315 *
1316 * device-type-scsi-options-list =
1317 * "FOOLCO Special x1000", "foolco-scsi-options",
1318 * "FOOLCO Special y1000", "foolco-scsi-options";
1319 * foolco-scsi-options = 0xXXXXXXXX;
1320 */
1321 int
1322 scsi_get_device_type_scsi_options(dev_info_t *dip,
1323 struct scsi_device *devp, int options)
1324 {
1325 char *string;
1326
1327 if ((string = scsi_get_device_type_string(
1328 "device-type-scsi-options-list", dip, devp)) != NULL) {
1329 options = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
1330 string, options);
1331 kmem_free(string, strlen(string) + 1);
1332 }
1333 return (options);
1334 }
1335
1336 /*
1337 * Find the scsi_options for a scsi_device. The precedence is:
1338 *
1339 * target<%d>-scsi-options highest
1340 * device-type-scsi-options
1341 * per bus scsi-options (parent)
1342 * global scsi-options
1343 * default_scsi_options argument lowest
1344 *
1345 * If the global is used then it has already been established
1346 * on the parent scsi_hba_attach_setup.
1347 */
1348 int
1349 scsi_get_scsi_options(struct scsi_device *sd, int default_scsi_options)
1350 {
1351 dev_info_t *parent;
1352 int options = -1;
1353 int tgt;
1354 char topt[32];
1355
1356 if ((sd == NULL) || (sd->sd_dev == NULL))
1357 return (default_scsi_options);
1358
1359 parent = ddi_get_parent(sd->sd_dev);
1360
1361 if ((tgt = ddi_prop_get_int(DDI_DEV_T_ANY, sd->sd_dev,
1362 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "target", -1)) != -1) {
1363 (void) sprintf(topt, "target%d-scsi-options", tgt);
1364 options = ddi_prop_get_int(DDI_DEV_T_ANY, parent,
1365 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, topt, -1);
1366 }
1367
1368 if (options == -1)
1369 options = scsi_get_device_type_scsi_options(parent, sd, -1);
1370
1371 if (options == -1)
1372 options = ddi_prop_get_int(DDI_DEV_T_ANY, parent,
1373 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "scsi-options", -1);
1374
1375 if (options == -1)
1376 options = default_scsi_options;
1377
1378 return (options);
1379 }
1380
1381 /*
1382 * Use scsi-options to return the maximum number of LUNs.
1383 */
1384 int
1385 scsi_get_scsi_maxluns(struct scsi_device *sd)
1386 {
1387 int options;
1388 int maxluns;
1389
1390 ASSERT(sd && sd->sd_inq);
1391 options = scsi_get_scsi_options(sd, SCSI_OPTIONS_NLUNS_DEFAULT);
1392
1393 switch (SCSI_OPTIONS_NLUNS(options)) {
1394 default:
1395 case SCSI_OPTIONS_NLUNS_DEFAULT:
1396 /* based on scsi version of target */
1397 if (sd->sd_inq->inq_ansi < SCSI_VERSION_3)
1398 maxluns = SCSI_8LUN_PER_TARGET; /* 8 */
1399 else
1400 maxluns = SCSI_16LUNS_PER_TARGET; /* 16 */
1401 break;
1402 case SCSI_OPTIONS_NLUNS_1:
1403 maxluns = SCSI_1LUN_PER_TARGET; /* 1 */
1404 break;
1405 case SCSI_OPTIONS_NLUNS_8:
1406 maxluns = SCSI_8LUN_PER_TARGET; /* 8 */
1407 break;
1408 case SCSI_OPTIONS_NLUNS_16:
1409 maxluns = SCSI_16LUNS_PER_TARGET; /* 16 */
1410 break;
1411 case SCSI_OPTIONS_NLUNS_32:
1412 maxluns = SCSI_32LUNS_PER_TARGET; /* 32 */
1413 break;
1414 }
1415
1416 /* For SCSI-1 we never support > 8 LUNs */
1417 if ((sd->sd_inq->inq_ansi <= SCSI_VERSION_1) &&
1418 (maxluns > SCSI_8LUN_PER_TARGET))
1419 maxluns = SCSI_8LUN_PER_TARGET;
1420
1421 return (maxluns);
1422 }
1423
1424 /*
1425 * Functions for format-neutral sense data functions
1426 */
1427 int
1428 scsi_validate_sense(uint8_t *sense_buffer, int sense_buf_len, int *flags)
1429 {
1430 int result;
1431 struct scsi_extended_sense *es =
1432 (struct scsi_extended_sense *)sense_buffer;
1433
1434 /*
1435 * Init flags if present
1436 */
1437 if (flags != NULL) {
1438 *flags = 0;
1439 }
1440
1441 /*
1442 * Check response code (Solaris breaks this into a 3-bit class
1443 * and 4-bit code field.
1444 */
1445 if ((es->es_class != CLASS_EXTENDED_SENSE) ||
1446 ((es->es_code != CODE_FMT_FIXED_CURRENT) &&
1447 (es->es_code != CODE_FMT_FIXED_DEFERRED) &&
1448 (es->es_code != CODE_FMT_DESCR_CURRENT) &&
1449 (es->es_code != CODE_FMT_DESCR_DEFERRED))) {
1450 /*
1451 * Sense data (if there's actually anything here) is not
1452 * in a format we can handle).
1453 */
1454 return (SENSE_UNUSABLE);
1455 }
1456
1457 /*
1458 * Check if this is deferred sense
1459 */
1460 if ((flags != NULL) &&
1461 ((es->es_code == CODE_FMT_FIXED_DEFERRED) ||
1462 (es->es_code == CODE_FMT_DESCR_DEFERRED))) {
1463 *flags |= SNS_BUF_DEFERRED;
1464 }
1465
1466 /*
1467 * Make sure length is OK
1468 */
1469 if (es->es_code == CODE_FMT_FIXED_CURRENT ||
1470 es->es_code == CODE_FMT_FIXED_DEFERRED) {
1471 /*
1472 * We can get by with a buffer that only includes the key,
1473 * asc, and ascq. In reality the minimum length we should
1474 * ever see is 18 bytes.
1475 */
1476 if ((sense_buf_len < MIN_FIXED_SENSE_LEN) ||
1477 ((es->es_add_len + ADDL_SENSE_ADJUST) <
1478 MIN_FIXED_SENSE_LEN)) {
1479 result = SENSE_UNUSABLE;
1480 } else {
1481 /*
1482 * The es_add_len field contains the number of sense
1483 * data bytes that follow the es_add_len field.
1484 */
1485 if ((flags != NULL) &&
1486 (sense_buf_len <
1487 (es->es_add_len + ADDL_SENSE_ADJUST))) {
1488 *flags |= SNS_BUF_OVERFLOW;
1489 }
1490
1491 result = SENSE_FIXED_FORMAT;
1492 }
1493 } else {
1494 struct scsi_descr_sense_hdr *ds =
1495 (struct scsi_descr_sense_hdr *)sense_buffer;
1496
1497 /*
1498 * For descriptor format we need at least the descriptor
1499 * header
1500 */
1501 if (sense_buf_len < sizeof (struct scsi_descr_sense_hdr)) {
1502 result = SENSE_UNUSABLE;
1503 } else {
1504 /*
1505 * Check for overflow
1506 */
1507 if ((flags != NULL) &&
1508 (sense_buf_len <
1509 (ds->ds_addl_sense_length + sizeof (*ds)))) {
1510 *flags |= SNS_BUF_OVERFLOW;
1511 }
1512
1513 result = SENSE_DESCR_FORMAT;
1514 }
1515 }
1516
1517 return (result);
1518 }
1519
1520
1521 uint8_t
1522 scsi_sense_key(uint8_t *sense_buffer)
1523 {
1524 uint8_t skey;
1525 if (SCSI_IS_DESCR_SENSE(sense_buffer)) {
1526 struct scsi_descr_sense_hdr *sdsp =
1527 (struct scsi_descr_sense_hdr *)sense_buffer;
1528 skey = sdsp->ds_key;
1529 } else {
1530 struct scsi_extended_sense *ext_sensep =
1531 (struct scsi_extended_sense *)sense_buffer;
1532 skey = ext_sensep->es_key;
1533 }
1534 return (skey);
1535 }
1536
1537 uint8_t
1538 scsi_sense_asc(uint8_t *sense_buffer)
1539 {
1540 uint8_t asc;
1541 if (SCSI_IS_DESCR_SENSE(sense_buffer)) {
1542 struct scsi_descr_sense_hdr *sdsp =
1543 (struct scsi_descr_sense_hdr *)sense_buffer;
1544 asc = sdsp->ds_add_code;
1545 } else {
1546 struct scsi_extended_sense *ext_sensep =
1547 (struct scsi_extended_sense *)sense_buffer;
1548 asc = ext_sensep->es_add_code;
1549 }
1550 return (asc);
1551 }
1552
1553 uint8_t
1554 scsi_sense_ascq(uint8_t *sense_buffer)
1555 {
1556 uint8_t ascq;
1557 if (SCSI_IS_DESCR_SENSE(sense_buffer)) {
1558 struct scsi_descr_sense_hdr *sdsp =
1559 (struct scsi_descr_sense_hdr *)sense_buffer;
1560 ascq = sdsp->ds_qual_code;
1561 } else {
1562 struct scsi_extended_sense *ext_sensep =
1563 (struct scsi_extended_sense *)sense_buffer;
1564 ascq = ext_sensep->es_qual_code;
1565 }
1566 return (ascq);
1567 }
1568
1569 void scsi_ext_sense_fields(uint8_t *sense_buffer, int sense_buf_len,
1570 uint8_t **information, uint8_t **cmd_spec_info, uint8_t **fru_code,
1571 uint8_t **sk_specific, uint8_t **stream_flags)
1572 {
1573 int sense_fmt;
1574
1575 /*
1576 * Sanity check sense data and determine the format
1577 */
1578 sense_fmt = scsi_validate_sense(sense_buffer, sense_buf_len, NULL);
1579
1580 /*
1581 * Initialize any requested data to 0
1582 */
1583 if (information) {
1584 *information = NULL;
1585 }
1586 if (cmd_spec_info) {
1587 *cmd_spec_info = NULL;
1588 }
1589 if (fru_code) {
1590 *fru_code = NULL;
1591 }
1592 if (sk_specific) {
1593 *sk_specific = NULL;
1594 }
1595 if (stream_flags) {
1596 *stream_flags = NULL;
1597 }
1598
1599 if (sense_fmt == SENSE_DESCR_FORMAT) {
1600 struct scsi_descr_template *sdt = NULL;
1601
1602 while (scsi_get_next_descr(sense_buffer,
1603 sense_buf_len, &sdt) != -1) {
1604 switch (sdt->sdt_descr_type) {
1605 case DESCR_INFORMATION: {
1606 struct scsi_information_sense_descr *isd =
1607 (struct scsi_information_sense_descr *)
1608 sdt;
1609 if (information) {
1610 *information =
1611 &isd->isd_information[0];
1612 }
1613 break;
1614 }
1615 case DESCR_COMMAND_SPECIFIC: {
1616 struct scsi_cmd_specific_sense_descr *csd =
1617 (struct scsi_cmd_specific_sense_descr *)
1618 sdt;
1619 if (cmd_spec_info) {
1620 *cmd_spec_info =
1621 &csd->css_cmd_specific_info[0];
1622 }
1623 break;
1624 }
1625 case DESCR_SENSE_KEY_SPECIFIC: {
1626 struct scsi_sk_specific_sense_descr *ssd =
1627 (struct scsi_sk_specific_sense_descr *)
1628 sdt;
1629 if (sk_specific) {
1630 *sk_specific =
1631 (uint8_t *)&ssd->sss_data;
1632 }
1633 break;
1634 }
1635 case DESCR_FRU: {
1636 struct scsi_fru_sense_descr *fsd =
1637 (struct scsi_fru_sense_descr *)
1638 sdt;
1639 if (fru_code) {
1640 *fru_code = &fsd->fs_fru_code;
1641 }
1642 break;
1643 }
1644 case DESCR_STREAM_COMMANDS: {
1645 struct scsi_stream_cmd_sense_descr *strsd =
1646 (struct scsi_stream_cmd_sense_descr *)
1647 sdt;
1648 if (stream_flags) {
1649 *stream_flags =
1650 (uint8_t *)&strsd->scs_data;
1651 }
1652 break;
1653 }
1654 case DESCR_BLOCK_COMMANDS: {
1655 struct scsi_block_cmd_sense_descr *bsd =
1656 (struct scsi_block_cmd_sense_descr *)
1657 sdt;
1658 /*
1659 * The "Block Command" sense descriptor
1660 * contains an ili bit that we can store
1661 * in the stream specific data if it is
1662 * available. We shouldn't see both
1663 * a block command and a stream command
1664 * descriptor in the same collection
1665 * of sense data.
1666 */
1667 if (stream_flags) {
1668 /*
1669 * Can't take an address of a bitfield,
1670 * but the flags are just after the
1671 * bcs_reserved field.
1672 */
1673 *stream_flags =
1674 (uint8_t *)&bsd->bcs_reserved + 1;
1675 }
1676 break;
1677 }
1678 }
1679 }
1680 } else {
1681 struct scsi_extended_sense *es =
1682 (struct scsi_extended_sense *)sense_buffer;
1683
1684 /* Get data from fixed sense buffer */
1685 if (information && es->es_valid) {
1686 *information = &es->es_info_1;
1687 }
1688 if (cmd_spec_info && es->es_valid) {
1689 *cmd_spec_info = &es->es_cmd_info[0];
1690 }
1691 if (fru_code) {
1692 *fru_code = &es->es_fru_code;
1693 }
1694 if (sk_specific) {
1695 *sk_specific = &es->es_skey_specific[0];
1696 }
1697 if (stream_flags) {
1698 /*
1699 * Can't take the address of a bit field,
1700 * but the stream flags are located just after
1701 * the es_segnum field;
1702 */
1703 *stream_flags = &es->es_segnum + 1;
1704 }
1705 }
1706 }
1707
1708 boolean_t
1709 scsi_sense_info_uint64(uint8_t *sense_buffer, int sense_buf_len,
1710 uint64_t *information)
1711 {
1712 boolean_t valid;
1713 int sense_fmt;
1714
1715 ASSERT(sense_buffer != NULL);
1716 ASSERT(information != NULL);
1717
1718 /* Validate sense data and get format */
1719 sense_fmt = scsi_validate_sense(sense_buffer, sense_buf_len, NULL);
1720
1721 if (sense_fmt == SENSE_UNUSABLE) {
1722 /* Information is not valid */
1723 valid = 0;
1724 } else if (sense_fmt == SENSE_FIXED_FORMAT) {
1725 struct scsi_extended_sense *es =
1726 (struct scsi_extended_sense *)sense_buffer;
1727
1728 *information = (uint64_t)SCSI_READ32(&es->es_info_1);
1729
1730 valid = es->es_valid;
1731 } else {
1732 /* Sense data is descriptor format */
1733 struct scsi_information_sense_descr *isd;
1734
1735 isd = (struct scsi_information_sense_descr *)
1736 scsi_find_sense_descr(sense_buffer, sense_buf_len,
1737 DESCR_INFORMATION);
1738
1739 if (isd) {
1740 *information = SCSI_READ64(isd->isd_information);
1741 valid = 1;
1742 } else {
1743 valid = 0;
1744 }
1745 }
1746
1747 return (valid);
1748 }
1749
1750 boolean_t
1751 scsi_sense_cmdspecific_uint64(uint8_t *sense_buffer, int sense_buf_len,
1752 uint64_t *cmd_specific_info)
1753 {
1754 boolean_t valid;
1755 int sense_fmt;
1756
1757 ASSERT(sense_buffer != NULL);
1758 ASSERT(cmd_specific_info != NULL);
1759
1760 /* Validate sense data and get format */
1761 sense_fmt = scsi_validate_sense(sense_buffer, sense_buf_len, NULL);
1762
1763 if (sense_fmt == SENSE_UNUSABLE) {
1764 /* Command specific info is not valid */
1765 valid = 0;
1766 } else if (sense_fmt == SENSE_FIXED_FORMAT) {
1767 struct scsi_extended_sense *es =
1768 (struct scsi_extended_sense *)sense_buffer;
1769
1770 *cmd_specific_info = (uint64_t)SCSI_READ32(es->es_cmd_info);
1771
1772 valid = es->es_valid;
1773 } else {
1774 /* Sense data is descriptor format */
1775 struct scsi_cmd_specific_sense_descr *c;
1776
1777 c = (struct scsi_cmd_specific_sense_descr *)
1778 scsi_find_sense_descr(sense_buffer, sense_buf_len,
1779 DESCR_COMMAND_SPECIFIC);
1780
1781 if (c) {
1782 valid = 1;
1783 *cmd_specific_info =
1784 SCSI_READ64(c->css_cmd_specific_info);
1785 } else {
1786 valid = 0;
1787 }
1788 }
1789
1790 return (valid);
1791 }
1792
1793 uint8_t *
1794 scsi_find_sense_descr(uint8_t *sdsp, int sense_buf_len, int req_descr_type)
1795 {
1796 struct scsi_descr_template *sdt = NULL;
1797
1798 while (scsi_get_next_descr(sdsp, sense_buf_len, &sdt) != -1) {
1799 ASSERT(sdt != NULL);
1800 if (sdt->sdt_descr_type == req_descr_type) {
1801 /* Found requested descriptor type */
1802 break;
1803 }
1804 }
1805
1806 return ((uint8_t *)sdt);
1807 }
1808
1809 /*
1810 * Sense Descriptor format is:
1811 *
1812 * <Descriptor type> <Descriptor length> <Descriptor data> ...
1813 *
1814 * 2 must be added to the descriptor length value to get the
1815 * total descriptor length sense the stored length does not
1816 * include the "type" and "additional length" fields.
1817 */
1818
1819 #define NEXT_DESCR_PTR(ndp_descr) \
1820 ((struct scsi_descr_template *)(((uint8_t *)(ndp_descr)) + \
1821 ((ndp_descr)->sdt_addl_length + \
1822 sizeof (struct scsi_descr_template))))
1823
1824 static int
1825 scsi_get_next_descr(uint8_t *sense_buffer,
1826 int sense_buf_len, struct scsi_descr_template **descrpp)
1827 {
1828 struct scsi_descr_sense_hdr *sdsp =
1829 (struct scsi_descr_sense_hdr *)sense_buffer;
1830 struct scsi_descr_template *cur_descr;
1831 boolean_t find_first;
1832 int valid_sense_length;
1833
1834 ASSERT(descrpp != NULL);
1835 find_first = (*descrpp == NULL);
1836
1837 /*
1838 * If no descriptor is passed in then return the first
1839 * descriptor
1840 */
1841 if (find_first) {
1842 /*
1843 * The first descriptor will immediately follow the header
1844 * (Pointer arithmetic)
1845 */
1846 cur_descr = (struct scsi_descr_template *)(sdsp+1);
1847 } else {
1848 cur_descr = *descrpp;
1849 ASSERT(cur_descr > (struct scsi_descr_template *)sdsp);
1850 }
1851
1852 /* Assume no more descriptors are available */
1853 *descrpp = NULL;
1854
1855 /*
1856 * Calculate the amount of valid sense data -- make sure the length
1857 * byte in this descriptor lies within the valid sense data.
1858 */
1859 valid_sense_length =
1860 min((sizeof (struct scsi_descr_sense_hdr) +
1861 sdsp->ds_addl_sense_length),
1862 sense_buf_len);
1863
1864 /*
1865 * Make sure this descriptor is complete (either the first
1866 * descriptor or the descriptor passed in)
1867 */
1868 if (scsi_validate_descr(sdsp, valid_sense_length, cur_descr) !=
1869 DESCR_GOOD) {
1870 return (-1);
1871 }
1872
1873 /*
1874 * If we were looking for the first descriptor go ahead and return it
1875 */
1876 if (find_first) {
1877 *descrpp = cur_descr;
1878 return ((*descrpp)->sdt_descr_type);
1879 }
1880
1881 /*
1882 * Get pointer to next descriptor
1883 */
1884 cur_descr = NEXT_DESCR_PTR(cur_descr);
1885
1886 /*
1887 * Make sure this descriptor is also complete.
1888 */
1889 if (scsi_validate_descr(sdsp, valid_sense_length, cur_descr) !=
1890 DESCR_GOOD) {
1891 return (-1);
1892 }
1893
1894 *descrpp = (struct scsi_descr_template *)cur_descr;
1895 return ((*descrpp)->sdt_descr_type);
1896 }
1897
1898 static int
1899 scsi_validate_descr(struct scsi_descr_sense_hdr *sdsp,
1900 int valid_sense_length, struct scsi_descr_template *descrp)
1901 {
1902 int descr_offset, next_descr_offset;
1903
1904 /*
1905 * Make sure length is present
1906 */
1907 descr_offset = (uint8_t *)descrp - (uint8_t *)sdsp;
1908 if (descr_offset + sizeof (struct scsi_descr_template) >
1909 valid_sense_length) {
1910 return (DESCR_PARTIAL);
1911 }
1912
1913 /*
1914 * Check if length is 0 (no more descriptors)
1915 */
1916 if (descrp->sdt_addl_length == 0) {
1917 return (DESCR_END);
1918 }
1919
1920 /*
1921 * Make sure the rest of the descriptor is present
1922 */
1923 next_descr_offset =
1924 (uint8_t *)NEXT_DESCR_PTR(descrp) - (uint8_t *)sdsp;
1925 if (next_descr_offset > valid_sense_length) {
1926 return (DESCR_PARTIAL);
1927 }
1928
1929 return (DESCR_GOOD);
1930 }
1931
1932 /*
1933 * Internal data structure for handling uscsi command.
1934 */
1935 typedef struct uscsi_i_cmd {
1936 struct uscsi_cmd uic_cmd;
1937 caddr_t uic_rqbuf;
1938 uchar_t uic_rqlen;
1939 caddr_t uic_cdb;
1940 int uic_flag;
1941 struct scsi_address *uic_ap;
1942 } uscsi_i_cmd_t;
1943
1944 #if !defined(lint)
1945 _NOTE(SCHEME_PROTECTS_DATA("unshared data", uscsi_i_cmd))
1946 #endif
1947
1948 /*ARGSUSED*/
1949 static void
1950 scsi_uscsi_mincnt(struct buf *bp)
1951 {
1952 /*
1953 * Do not break up because the CDB count would then be
1954 * incorrect and create spurious data underrun errors.
1955 */
1956 }
1957
1958 /*
1959 * Function: scsi_uscsi_alloc_and_copyin
1960 *
1961 * Description: Target drivers call this function to allocate memeory,
1962 * copy in, and convert ILP32/LP64 to make preparations for handling
1963 * uscsi commands.
1964 *
1965 * Arguments:
1966 * arg - pointer to the caller's uscsi command struct
1967 * flag - mode, corresponds to ioctl(9e) 'mode'
1968 * ap - SCSI address structure
1969 * uscmdp - pointer to the converted uscsi command
1970 *
1971 * Return code: 0
1972 * EFAULT
1973 * EINVAL
1974 *
1975 * Context: Never called at interrupt context.
1976 */
1977
1978 int
1979 scsi_uscsi_alloc_and_copyin(intptr_t arg, int flag, struct scsi_address *ap,
1980 struct uscsi_cmd **uscmdp)
1981 {
1982 int rval = 0;
1983 struct uscsi_cmd *uscmd;
1984
1985 /*
1986 * In order to not worry about where the uscsi structure came
1987 * from (or where the cdb it points to came from) we're going
1988 * to make kmem_alloc'd copies of them here. This will also
1989 * allow reference to the data they contain long after this
1990 * process has gone to sleep and its kernel stack has been
1991 * unmapped, etc. First get some memory for the uscsi_cmd
1992 * struct and copy the contents of the given uscsi_cmd struct
1993 * into it. We also save infos of the uscsi command by using
1994 * uicmd to supply referrence for the copyout operation.
1995 */
1996 uscmd = scsi_uscsi_alloc();
1997
1998 if ((rval = scsi_uscsi_copyin(arg, flag, ap, &uscmd)) != 0) {
1999 scsi_uscsi_free(uscmd);
2000 *uscmdp = NULL;
2001 rval = EFAULT;
2002 } else {
2003 *uscmdp = uscmd;
2004 }
2005
2006 return (rval);
2007 }
2008
2009 struct uscsi_cmd *
2010 scsi_uscsi_alloc()
2011 {
2012 struct uscsi_i_cmd *uicmd;
2013
2014 uicmd = (struct uscsi_i_cmd *)
2015 kmem_zalloc(sizeof (struct uscsi_i_cmd), KM_SLEEP);
2016
2017 /*
2018 * It is supposed that the uscsi_cmd has been alloced correctly,
2019 * we need to check is it NULL or mis-created.
2020 */
2021 ASSERT(uicmd && (offsetof(struct uscsi_i_cmd, uic_cmd) == 0));
2022
2023 return (&uicmd->uic_cmd);
2024 }
2025
2026 int
2027 scsi_uscsi_copyin(intptr_t arg, int flag, struct scsi_address *ap,
2028 struct uscsi_cmd **uscmdp)
2029 {
2030 #ifdef _MULTI_DATAMODEL
2031 /*
2032 * For use when a 32 bit app makes a call into a
2033 * 64 bit ioctl
2034 */
2035 struct uscsi_cmd32 uscsi_cmd_32_for_64;
2036 struct uscsi_cmd32 *ucmd32 = &uscsi_cmd_32_for_64;
2037 #endif /* _MULTI_DATAMODEL */
2038 struct uscsi_cmd *uscmd = *uscmdp;
2039 struct uscsi_i_cmd *uicmd = (struct uscsi_i_cmd *)(uscmd);
2040 int max_hba_cdb;
2041 int rval;
2042 extern dev_info_t *scsi_vhci_dip;
2043
2044 ASSERT(uscmd != NULL);
2045 ASSERT(uicmd != NULL);
2046
2047 /*
2048 * To be able to issue multiple commands off a single uscmdp
2049 * We need to free the original cdb, rqbuf and bzero the uscmdp
2050 * if the cdb, rqbuf and uscmdp is not NULL
2051 */
2052 if (uscmd->uscsi_rqbuf != NULL)
2053 kmem_free(uscmd->uscsi_rqbuf, uscmd->uscsi_rqlen);
2054 if (uscmd->uscsi_cdb != NULL)
2055 kmem_free(uscmd->uscsi_cdb, uscmd->uscsi_cdblen);
2056 bzero(uscmd, sizeof (struct uscsi_cmd));
2057
2058
2059 #ifdef _MULTI_DATAMODEL
2060 switch (ddi_model_convert_from(flag & FMODELS)) {
2061 case DDI_MODEL_ILP32:
2062 if (ddi_copyin((void *)arg, ucmd32, sizeof (*ucmd32), flag)) {
2063 rval = EFAULT;
2064 goto scsi_uscsi_copyin_failed;
2065 }
2066 /*
2067 * Convert the ILP32 uscsi data from the
2068 * application to LP64 for internal use.
2069 */
2070 uscsi_cmd32touscsi_cmd(ucmd32, uscmd);
2071 break;
2072 case DDI_MODEL_NONE:
2073 if (ddi_copyin((void *)arg, uscmd, sizeof (*uscmd), flag)) {
2074 rval = EFAULT;
2075 goto scsi_uscsi_copyin_failed;
2076 }
2077 break;
2078 default:
2079 rval = EFAULT;
2080 goto scsi_uscsi_copyin_failed;
2081 }
2082 #else /* ! _MULTI_DATAMODEL */
2083 if (ddi_copyin((void *)arg, uscmd, sizeof (*uscmd), flag)) {
2084 rval = EFAULT;
2085 goto scsi_uscsi_copyin_failed;
2086 }
2087 #endif /* _MULTI_DATAMODEL */
2088
2089 /*
2090 * We are going to allocate kernel virtual addresses for
2091 * uscsi_rqbuf and uscsi_cdb pointers, so save off the
2092 * original, possibly user virtual, uscsi_addresses
2093 * in uic_fields
2094 */
2095 uicmd->uic_rqbuf = uscmd->uscsi_rqbuf;
2096 uicmd->uic_rqlen = uscmd->uscsi_rqlen;
2097 uicmd->uic_cdb = uscmd->uscsi_cdb;
2098 uicmd->uic_flag = flag;
2099 uicmd->uic_ap = ap;
2100
2101 /*
2102 * Skip the following steps if we meet RESET commands.
2103 */
2104 if (uscmd->uscsi_flags &
2105 (USCSI_RESET_LUN | USCSI_RESET_TARGET | USCSI_RESET_ALL)) {
2106 uscmd->uscsi_rqbuf = NULL;
2107 uscmd->uscsi_cdb = NULL;
2108 return (0);
2109 }
2110
2111 /*
2112 * Currently, USCSI_PATH_INSTANCE is only valid when directed
2113 * to scsi_vhci.
2114 */
2115 if ((uscmd->uscsi_flags & USCSI_PATH_INSTANCE) &&
2116 (A_TO_TRAN(ap)->tran_hba_dip != scsi_vhci_dip)) {
2117 rval = EFAULT;
2118 goto scsi_uscsi_copyin_failed;
2119 }
2120
2121 /*
2122 * Perfunctory sanity checks. Get the maximum hba supported
2123 * cdb length first.
2124 */
2125 max_hba_cdb = scsi_ifgetcap(ap, "max-cdb-length", 1);
2126 if (max_hba_cdb < CDB_GROUP0) {
2127 max_hba_cdb = CDB_GROUP4;
2128 }
2129 if (uscmd->uscsi_cdblen < CDB_GROUP0 ||
2130 uscmd->uscsi_cdblen > max_hba_cdb) {
2131 rval = EINVAL;
2132 goto scsi_uscsi_copyin_failed;
2133 }
2134 if ((uscmd->uscsi_flags & USCSI_RQENABLE) &&
2135 (uscmd->uscsi_rqlen == 0 || uscmd->uscsi_rqbuf == NULL)) {
2136 rval = EINVAL;
2137 goto scsi_uscsi_copyin_failed;
2138 }
2139
2140 /*
2141 * To extend uscsi_cmd in the future, we need to ensure current
2142 * reserved bits remain unused (zero).
2143 */
2144 if (uscmd->uscsi_flags & USCSI_RESERVED) {
2145 rval = EINVAL;
2146 goto scsi_uscsi_copyin_failed;
2147 }
2148
2149 /*
2150 * Now we get some space for the CDB, and copy the given CDB into
2151 * it. Use ddi_copyin() in case the data is in user space.
2152 */
2153 uscmd->uscsi_cdb = kmem_zalloc((size_t)uscmd->uscsi_cdblen, KM_SLEEP);
2154 if (ddi_copyin(uicmd->uic_cdb, uscmd->uscsi_cdb,
2155 (uint_t)uscmd->uscsi_cdblen, flag) != 0) {
2156 kmem_free(uscmd->uscsi_cdb, (size_t)uscmd->uscsi_cdblen);
2157 rval = EFAULT;
2158 goto scsi_uscsi_copyin_failed;
2159 }
2160
2161 if (uscmd->uscsi_cdb[0] != SCMD_VAR_LEN) {
2162 if (uscmd->uscsi_cdblen > SCSI_CDB_SIZE ||
2163 scsi_cdb_size[CDB_GROUPID(uscmd->uscsi_cdb[0])] >
2164 uscmd->uscsi_cdblen) {
2165 kmem_free(uscmd->uscsi_cdb,
2166 (size_t)uscmd->uscsi_cdblen);
2167 rval = EINVAL;
2168 goto scsi_uscsi_copyin_failed;
2169 }
2170 } else {
2171 if ((uscmd->uscsi_cdblen % 4) != 0) {
2172 kmem_free(uscmd->uscsi_cdb,
2173 (size_t)uscmd->uscsi_cdblen);
2174 rval = EINVAL;
2175 goto scsi_uscsi_copyin_failed;
2176 }
2177 }
2178
2179 /*
2180 * Initialize Request Sense buffering, if requested.
2181 */
2182 if (uscmd->uscsi_flags & USCSI_RQENABLE) {
2183 /*
2184 * Here uscmd->uscsi_rqbuf currently points to the caller's
2185 * buffer, but we replace this with a kernel buffer that
2186 * we allocate to use with the sense data. The sense data
2187 * (if present) gets copied into this new buffer before the
2188 * command is completed. Then we copy the sense data from
2189 * our allocated buf into the caller's buffer below. Note
2190 * that uscmd->uscsi_rqbuf and uscmd->uscsi_rqlen are used
2191 * below to perform the copy back to the caller's buf.
2192 */
2193 if (uicmd->uic_rqlen <= SENSE_LENGTH) {
2194 uscmd->uscsi_rqlen = SENSE_LENGTH;
2195 uscmd->uscsi_rqbuf = kmem_zalloc(SENSE_LENGTH,
2196 KM_SLEEP);
2197 } else {
2198 uscmd->uscsi_rqlen = MAX_SENSE_LENGTH;
2199 uscmd->uscsi_rqbuf = kmem_zalloc(MAX_SENSE_LENGTH,
2200 KM_SLEEP);
2201 }
2202 uscmd->uscsi_rqresid = uscmd->uscsi_rqlen;
2203 } else {
2204 uscmd->uscsi_rqbuf = NULL;
2205 uscmd->uscsi_rqlen = 0;
2206 uscmd->uscsi_rqresid = 0;
2207 }
2208 return (0);
2209
2210 scsi_uscsi_copyin_failed:
2211 /*
2212 * The uscsi_rqbuf and uscsi_cdb is refering to user-land
2213 * address now, no need to free them.
2214 */
2215 uscmd->uscsi_rqbuf = NULL;
2216 uscmd->uscsi_cdb = NULL;
2217
2218 return (rval);
2219 }
2220
2221 /*
2222 * Function: scsi_uscsi_handle_cmd
2223 *
2224 * Description: Target drivers call this function to handle uscsi commands.
2225 *
2226 * Arguments:
2227 * dev - device number
2228 * dataspace - UIO_USERSPACE or UIO_SYSSPACE
2229 * uscmd - pointer to the converted uscsi command
2230 * strat - pointer to the driver's strategy routine
2231 * bp - buf struct ptr
2232 * private_data - pointer to bp->b_private
2233 *
2234 * Return code: 0
2235 * EIO - scsi_reset() failed, or see biowait()/physio() codes.
2236 * EINVAL
2237 * return code of biowait(9F) or physio(9F):
2238 * EIO - IO error
2239 * ENXIO
2240 * EACCES - reservation conflict
2241 *
2242 * Context: Never called at interrupt context.
2243 */
2244
2245 int
2246 scsi_uscsi_handle_cmd(dev_t dev, enum uio_seg dataspace,
2247 struct uscsi_cmd *uscmd, int (*strat)(struct buf *),
2248 struct buf *bp, void *private_data)
2249 {
2250 struct uscsi_i_cmd *uicmd = (struct uscsi_i_cmd *)uscmd;
2251 int bp_alloc_flag = 0;
2252 int rval;
2253
2254 /*
2255 * Perform resets directly; no need to generate a command to do it.
2256 */
2257 if (uscmd->uscsi_flags &
2258 (USCSI_RESET_LUN | USCSI_RESET_TARGET | USCSI_RESET_ALL)) {
2259 int flags = (uscmd->uscsi_flags & USCSI_RESET_ALL) ?
2260 RESET_ALL : ((uscmd->uscsi_flags & USCSI_RESET_TARGET) ?
2261 RESET_TARGET : RESET_LUN);
2262 if (scsi_reset(uicmd->uic_ap, flags) == 0) {
2263 /* Reset attempt was unsuccessful */
2264 return (EIO);
2265 }
2266 return (0);
2267 }
2268
2269 /*
2270 * Force asynchronous mode, if necessary. Doing this here
2271 * has the unfortunate effect of running other queued
2272 * commands async also, but since the main purpose of this
2273 * capability is downloading new drive firmware, we can
2274 * probably live with it.
2275 */
2276 if (uscmd->uscsi_flags & USCSI_ASYNC) {
2277 if (scsi_ifgetcap(uicmd->uic_ap, "synchronous", 1) == 1) {
2278 if (scsi_ifsetcap(uicmd->uic_ap, "synchronous",
2279 0, 1) != 1) {
2280 return (EINVAL);
2281 }
2282 }
2283 }
2284
2285 /*
2286 * Re-enable synchronous mode, if requested.
2287 */
2288 if (uscmd->uscsi_flags & USCSI_SYNC) {
2289 if (scsi_ifgetcap(uicmd->uic_ap, "synchronous", 1) == 0) {
2290 rval = scsi_ifsetcap(uicmd->uic_ap, "synchronous",
2291 1, 1);
2292 }
2293 }
2294
2295 /*
2296 * If bp is NULL, allocate space here.
2297 */
2298 if (bp == NULL) {
2299 bp = getrbuf(KM_SLEEP);
2300 bp->b_private = private_data;
2301 bp_alloc_flag = 1;
2302 }
2303
2304 /*
2305 * If we're going to do actual I/O, let physio do all the right things.
2306 */
2307 if (uscmd->uscsi_buflen != 0) {
2308 struct iovec aiov;
2309 struct uio auio;
2310 struct uio *uio = &auio;
2311
2312 bzero(&auio, sizeof (struct uio));
2313 bzero(&aiov, sizeof (struct iovec));
2314 aiov.iov_base = uscmd->uscsi_bufaddr;
2315 aiov.iov_len = uscmd->uscsi_buflen;
2316 uio->uio_iov = &aiov;
2317
2318 uio->uio_iovcnt = 1;
2319 uio->uio_resid = uscmd->uscsi_buflen;
2320 uio->uio_segflg = dataspace;
2321
2322 /*
2323 * physio() will block here until the command completes....
2324 */
2325 rval = physio(strat, bp, dev,
2326 ((uscmd->uscsi_flags & USCSI_READ) ? B_READ : B_WRITE),
2327 scsi_uscsi_mincnt, uio);
2328 } else {
2329 /*
2330 * We have to mimic that physio would do here! Argh!
2331 */
2332 bp->b_flags = B_BUSY |
2333 ((uscmd->uscsi_flags & USCSI_READ) ? B_READ : B_WRITE);
2334 bp->b_edev = dev;
2335 bp->b_dev = cmpdev(dev); /* maybe unnecessary? */
2336 bp->b_bcount = 0;
2337 bp->b_blkno = 0;
2338 bp->b_resid = 0;
2339
2340 (void) (*strat)(bp);
2341 rval = biowait(bp);
2342 }
2343 uscmd->uscsi_resid = bp->b_resid;
2344
2345 if (bp_alloc_flag == 1) {
2346 bp_mapout(bp);
2347 freerbuf(bp);
2348 }
2349
2350 return (rval);
2351 }
2352
2353 /*
2354 * Function: scsi_uscsi_pktinit
2355 *
2356 * Description: Target drivers call this function to transfer uscsi_cmd
2357 * information into a scsi_pkt before sending the scsi_pkt.
2358 *
2359 * NB: At this point the implementation is limited to path_instance.
2360 * At some point more code could be removed from the target driver by
2361 * enhancing this function - with the added benifit of making the uscsi
2362 * implementation more consistent accross all drivers.
2363 *
2364 * Arguments:
2365 * uscmd - pointer to the uscsi command
2366 * pkt - pointer to the scsi_pkt
2367 *
2368 * Return code: 1 on successfull transfer, 0 on failure.
2369 */
2370 int
2371 scsi_uscsi_pktinit(struct uscsi_cmd *uscmd, struct scsi_pkt *pkt)
2372 {
2373
2374 /*
2375 * Check if the NACA flag is set. If one initiator sets it
2376 * but does not clear it, other initiators would end up
2377 * waiting indefinitely for the first to clear NACA. If the
2378 * the system allows NACA to be set, then warn the user but
2379 * still pass the command down, otherwise, clear the flag.
2380 */
2381 if (uscmd->uscsi_cdb[uscmd->uscsi_cdblen - 1] & CDB_FLAG_NACA) {
2382 if (scsi_pkt_allow_naca) {
2383 cmn_err(CE_WARN, "scsi_uscsi_pktinit: "
2384 "NACA flag is set");
2385 } else {
2386 uscmd->uscsi_cdb[uscmd->uscsi_cdblen - 1] &=
2387 ~CDB_FLAG_NACA;
2388 cmn_err(CE_WARN, "scsi_uscsi_pktinit: "
2389 "NACA flag is cleared");
2390 }
2391 }
2392
2393 /*
2394 * See if path_instance was requested in uscsi_cmd.
2395 */
2396 if ((uscmd->uscsi_flags & USCSI_PATH_INSTANCE) &&
2397 (uscmd->uscsi_path_instance != 0)) {
2398 /*
2399 * Check to make sure the scsi_pkt was allocated correctly
2400 * before transferring uscsi(7i) path_instance to scsi_pkt(9S).
2401 */
2402 if (scsi_pkt_allocated_correctly(pkt)) {
2403 /* set pkt_path_instance and flag. */
2404 pkt->pkt_flags |= FLAG_PKT_PATH_INSTANCE;
2405 pkt->pkt_path_instance = uscmd->uscsi_path_instance;
2406 } else {
2407 return (0); /* failure */
2408 }
2409 } else {
2410 /*
2411 * Can only use pkt_path_instance if the packet
2412 * was correctly allocated.
2413 */
2414 if (scsi_pkt_allocated_correctly(pkt)) {
2415 pkt->pkt_path_instance = 0;
2416 }
2417 pkt->pkt_flags &= ~FLAG_PKT_PATH_INSTANCE;
2418 }
2419
2420 return (1); /* success */
2421 }
2422
2423 /*
2424 * Function: scsi_uscsi_pktfini
2425 *
2426 * Description: Target drivers call this function to transfer completed
2427 * scsi_pkt information back into uscsi_cmd.
2428 *
2429 * NB: At this point the implementation is limited to path_instance.
2430 * At some point more code could be removed from the target driver by
2431 * enhancing this function - with the added benifit of making the uscsi
2432 * implementation more consistent accross all drivers.
2433 *
2434 * Arguments:
2435 * pkt - pointer to the scsi_pkt
2436 * uscmd - pointer to the uscsi command
2437 *
2438 * Return code: 1 on successfull transfer, 0 on failure.
2439 */
2440 int
2441 scsi_uscsi_pktfini(struct scsi_pkt *pkt, struct uscsi_cmd *uscmd)
2442 {
2443 /*
2444 * Check to make sure the scsi_pkt was allocated correctly before
2445 * transferring scsi_pkt(9S) path_instance to uscsi(7i).
2446 */
2447 if (!scsi_pkt_allocated_correctly(pkt)) {
2448 uscmd->uscsi_path_instance = 0;
2449 return (0); /* failure */
2450 }
2451
2452 uscmd->uscsi_path_instance = pkt->pkt_path_instance;
2453 /* reset path_instance */
2454 pkt->pkt_flags &= ~FLAG_PKT_PATH_INSTANCE;
2455 pkt->pkt_path_instance = 0;
2456 return (1); /* success */
2457 }
2458
2459 /*
2460 * Function: scsi_uscsi_copyout_and_free
2461 *
2462 * Description: Target drivers call this function to undo what was done by
2463 * scsi_uscsi_alloc_and_copyin.
2464 *
2465 * Arguments: arg - pointer to the uscsi command to be returned
2466 * uscmd - pointer to the converted uscsi command
2467 *
2468 * Return code: 0
2469 * EFAULT
2470 *
2471 * Context: Never called at interrupt context.
2472 */
2473 int
2474 scsi_uscsi_copyout_and_free(intptr_t arg, struct uscsi_cmd *uscmd)
2475 {
2476 int rval = 0;
2477
2478 rval = scsi_uscsi_copyout(arg, uscmd);
2479
2480 scsi_uscsi_free(uscmd);
2481
2482 return (rval);
2483 }
2484
2485 int
2486 scsi_uscsi_copyout(intptr_t arg, struct uscsi_cmd *uscmd)
2487 {
2488 #ifdef _MULTI_DATAMODEL
2489 /*
2490 * For use when a 32 bit app makes a call into a
2491 * 64 bit ioctl.
2492 */
2493 struct uscsi_cmd32 uscsi_cmd_32_for_64;
2494 struct uscsi_cmd32 *ucmd32 = &uscsi_cmd_32_for_64;
2495 #endif /* _MULTI_DATAMODEL */
2496 struct uscsi_i_cmd *uicmd = (struct uscsi_i_cmd *)uscmd;
2497 caddr_t k_rqbuf;
2498 int k_rqlen;
2499 caddr_t k_cdb;
2500 int rval = 0;
2501
2502 /*
2503 * If the caller wants sense data, copy back whatever sense data
2504 * we may have gotten, and update the relevant rqsense info.
2505 */
2506 if ((uscmd->uscsi_flags & USCSI_RQENABLE) &&
2507 (uscmd->uscsi_rqbuf != NULL)) {
2508 int rqlen = uscmd->uscsi_rqlen - uscmd->uscsi_rqresid;
2509 rqlen = min(((int)uicmd->uic_rqlen), rqlen);
2510 uscmd->uscsi_rqresid = uicmd->uic_rqlen - rqlen;
2511 /*
2512 * Copy out the sense data for user process.
2513 */
2514 if ((uicmd->uic_rqbuf != NULL) && (rqlen != 0)) {
2515 if (ddi_copyout(uscmd->uscsi_rqbuf,
2516 uicmd->uic_rqbuf, rqlen, uicmd->uic_flag) != 0) {
2517 rval = EFAULT;
2518 }
2519 }
2520 }
2521
2522 /*
2523 * Restore original uscsi_values, saved in uic_fields for
2524 * copyout (so caller does not experience a change in these
2525 * fields)
2526 */
2527 k_rqbuf = uscmd->uscsi_rqbuf;
2528 k_rqlen = uscmd->uscsi_rqlen;
2529 k_cdb = uscmd->uscsi_cdb;
2530 uscmd->uscsi_rqbuf = uicmd->uic_rqbuf;
2531 uscmd->uscsi_rqlen = uicmd->uic_rqlen;
2532 uscmd->uscsi_cdb = uicmd->uic_cdb;
2533
2534 #ifdef _MULTI_DATAMODEL
2535 switch (ddi_model_convert_from(uicmd->uic_flag & FMODELS)) {
2536 case DDI_MODEL_ILP32:
2537 /*
2538 * Convert back to ILP32 before copyout to the
2539 * application
2540 */
2541 uscsi_cmdtouscsi_cmd32(uscmd, ucmd32);
2542 if (ddi_copyout(ucmd32, (void *)arg, sizeof (*ucmd32),
2543 uicmd->uic_flag)) {
2544 rval = EFAULT;
2545 }
2546 break;
2547 case DDI_MODEL_NONE:
2548 if (ddi_copyout(uscmd, (void *)arg, sizeof (*uscmd),
2549 uicmd->uic_flag)) {
2550 rval = EFAULT;
2551 }
2552 break;
2553 default:
2554 rval = EFAULT;
2555 }
2556 #else /* _MULTI_DATAMODE */
2557 if (ddi_copyout(uscmd, (void *)arg, sizeof (*uscmd), uicmd->uic_flag)) {
2558 rval = EFAULT;
2559 }
2560 #endif /* _MULTI_DATAMODE */
2561
2562 /*
2563 * Copyout done, restore kernel virtual addresses for further
2564 * scsi_uscsi_free().
2565 */
2566 uscmd->uscsi_rqbuf = k_rqbuf;
2567 uscmd->uscsi_rqlen = k_rqlen;
2568 uscmd->uscsi_cdb = k_cdb;
2569
2570 return (rval);
2571 }
2572
2573 void
2574 scsi_uscsi_free(struct uscsi_cmd *uscmd)
2575 {
2576 struct uscsi_i_cmd *uicmd = (struct uscsi_i_cmd *)uscmd;
2577
2578 ASSERT(uicmd != NULL);
2579
2580 if ((uscmd->uscsi_rqbuf != NULL) && (uscmd->uscsi_rqlen != 0)) {
2581 kmem_free(uscmd->uscsi_rqbuf, (size_t)uscmd->uscsi_rqlen);
2582 uscmd->uscsi_rqbuf = NULL;
2583 }
2584
2585 if ((uscmd->uscsi_cdb != NULL) && (uscmd->uscsi_cdblen != 0)) {
2586 kmem_free(uscmd->uscsi_cdb, (size_t)uscmd->uscsi_cdblen);
2587 uscmd->uscsi_cdb = NULL;
2588 }
2589
2590 kmem_free(uicmd, sizeof (struct uscsi_i_cmd));
2591 }