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