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