1 /* $OpenBSD: scsi_base.c,v 1.29 2001/06/22 14:35:42 deraadt Exp $ */ 2 /* $NetBSD: scsi_base.c,v 1.43 1997/04/02 02:29:36 mycroft Exp $ */ 3 4 /* 5 * Copyright (c) 1994, 1995, 1997 Charles M. Hannum. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Charles M. Hannum. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * Originally written by Julian Elischer (julian@dialix.oz.au) 35 * Detailed SCSI error printing Copyright 1997 by Matthew Jacob. 36 */ 37 38 #include <sys/types.h> 39 #include <sys/param.h> 40 #include <sys/systm.h> 41 #include <sys/kernel.h> 42 #include <sys/buf.h> 43 #include <sys/uio.h> 44 #include <sys/malloc.h> 45 #include <sys/errno.h> 46 #include <sys/device.h> 47 #include <sys/proc.h> 48 49 #include <scsi/scsi_all.h> 50 #include <scsi/scsi_disk.h> 51 #include <scsi/scsiconf.h> 52 53 LIST_HEAD(xs_free_list, scsi_xfer) xs_free_list; 54 55 static __inline struct scsi_xfer *scsi_make_xs __P((struct scsi_link *, 56 struct scsi_generic *, int cmdlen, u_char *data_addr, 57 int datalen, int retries, int timeout, struct buf *, int flags)); 58 static __inline void asc2ascii __P((u_char asc, u_char ascq, char *result)); 59 int sc_err1 __P((struct scsi_xfer *, int)); 60 int scsi_interpret_sense __P((struct scsi_xfer *)); 61 char *scsi_decode_sense __P((void *, int)); 62 63 /* 64 * Get a scsi transfer structure for the caller. Charge the structure 65 * to the device that is referenced by the sc_link structure. If the 66 * sc_link structure has no 'credits' then the device already has the 67 * maximum number or outstanding operations under way. In this stage, 68 * wait on the structure so that when one is freed, we are awoken again 69 * If the SCSI_NOSLEEP flag is set, then do not wait, but rather, return 70 * a NULL pointer, signifying that no slots were available 71 * Note in the link structure, that we are waiting on it. 72 */ 73 74 struct scsi_xfer * 75 scsi_get_xs(sc_link, flags) 76 struct scsi_link *sc_link; /* who to charge the xs to */ 77 int flags; /* if this call can sleep */ 78 { 79 struct scsi_xfer *xs; 80 int s; 81 82 SC_DEBUG(sc_link, SDEV_DB3, ("scsi_get_xs\n")); 83 s = splbio(); 84 while (sc_link->openings <= 0) { 85 SC_DEBUG(sc_link, SDEV_DB3, ("sleeping\n")); 86 if ((flags & SCSI_NOSLEEP) != 0) { 87 splx(s); 88 return 0; 89 } 90 sc_link->flags |= SDEV_WAITING; 91 (void) tsleep(sc_link, PRIBIO, "getxs", 0); 92 } 93 sc_link->openings--; 94 if ((xs = xs_free_list.lh_first) != NULL) { 95 LIST_REMOVE(xs, free_list); 96 splx(s); 97 } else { 98 splx(s); 99 SC_DEBUG(sc_link, SDEV_DB3, ("making\n")); 100 xs = malloc(sizeof(*xs), M_DEVBUF, 101 ((flags & SCSI_NOSLEEP) != 0 ? M_NOWAIT : M_WAITOK)); 102 if (!xs) { 103 sc_print_addr(sc_link); 104 printf("cannot allocate scsi xs\n"); 105 return 0; 106 } 107 } 108 109 SC_DEBUG(sc_link, SDEV_DB3, ("returning\n")); 110 xs->flags = INUSE | flags; 111 return xs; 112 } 113 114 /* 115 * Given a scsi_xfer struct, and a device (referenced through sc_link) 116 * return the struct to the free pool and credit the device with it 117 * If another process is waiting for an xs, do a wakeup, let it proceed 118 */ 119 void 120 scsi_free_xs(xs, flags) 121 struct scsi_xfer *xs; 122 int flags; 123 { 124 struct scsi_link *sc_link = xs->sc_link; 125 126 xs->flags &= ~INUSE; 127 LIST_INSERT_HEAD(&xs_free_list, xs, free_list); 128 129 SC_DEBUG(sc_link, SDEV_DB3, ("scsi_free_xs\n")); 130 /* if was 0 and someone waits, wake them up */ 131 sc_link->openings++; 132 if ((sc_link->flags & SDEV_WAITING) != 0) { 133 sc_link->flags &= ~SDEV_WAITING; 134 wakeup(sc_link); 135 } else { 136 if (sc_link->device->start) { 137 SC_DEBUG(sc_link, SDEV_DB2, ("calling private start()\n")); 138 (*(sc_link->device->start)) (sc_link->device_softc); 139 } 140 } 141 } 142 143 /* 144 * Make a scsi_xfer, and return a pointer to it. 145 */ 146 static __inline struct scsi_xfer * 147 scsi_make_xs(sc_link, scsi_cmd, cmdlen, data_addr, datalen, 148 retries, timeout, bp, flags) 149 struct scsi_link *sc_link; 150 struct scsi_generic *scsi_cmd; 151 int cmdlen; 152 u_char *data_addr; 153 int datalen; 154 int retries; 155 int timeout; 156 struct buf *bp; 157 int flags; 158 { 159 struct scsi_xfer *xs; 160 161 if ((xs = scsi_get_xs(sc_link, flags)) == NULL) 162 return NULL; 163 164 /* 165 * Fill out the scsi_xfer structure. We don't know whose context 166 * the cmd is in, so copy it. 167 */ 168 xs->sc_link = sc_link; 169 bcopy(scsi_cmd, &xs->cmdstore, cmdlen); 170 xs->cmd = &xs->cmdstore; 171 xs->cmdlen = cmdlen; 172 xs->data = data_addr; 173 xs->datalen = datalen; 174 xs->retries = retries; 175 xs->timeout = timeout; 176 xs->bp = bp; 177 xs->req_sense_length = 0; /* XXX - not used by scsi internals */ 178 179 /* 180 * Set the LUN in the CDB. This may only be needed if we have an 181 * older device. However, we also set it for more modern SCSI 182 * devices "just in case". The old code assumed everything newer 183 * than SCSI-2 would not need it, but why risk it? This was the 184 * old conditional: 185 * 186 * if ((sc_link->scsi_version & SID_ANSII) <= 2) 187 */ 188 xs->cmd->bytes[0] &= ~SCSI_CMD_LUN_MASK; 189 xs->cmd->bytes[0] |= 190 ((sc_link->lun << SCSI_CMD_LUN_SHIFT) & SCSI_CMD_LUN_MASK); 191 192 return xs; 193 } 194 195 /* 196 * Find out from the device what its capacity is. 197 */ 198 u_long 199 scsi_size(sc_link, flags) 200 struct scsi_link *sc_link; 201 int flags; 202 { 203 struct scsi_read_cap_data rdcap; 204 struct scsi_read_capacity scsi_cmd; 205 206 /* 207 * make up a scsi command and ask the scsi driver to do 208 * it for you. 209 */ 210 bzero(&scsi_cmd, sizeof(scsi_cmd)); 211 scsi_cmd.opcode = READ_CAPACITY; 212 213 /* 214 * If the command works, interpret the result as a 4 byte 215 * number of blocks 216 */ 217 if (scsi_scsi_cmd(sc_link, (struct scsi_generic *)&scsi_cmd, 218 sizeof(scsi_cmd), (u_char *)&rdcap, sizeof(rdcap), 219 2, 20000, NULL, flags | SCSI_DATA_IN) != 0) { 220 sc_print_addr(sc_link); 221 printf("could not get size\n"); 222 return 0; 223 } 224 225 return _4btol(rdcap.addr) + 1; 226 } 227 228 /* 229 * Get scsi driver to send a "are you ready?" command 230 */ 231 int 232 scsi_test_unit_ready(sc_link, flags) 233 struct scsi_link *sc_link; 234 int flags; 235 { 236 struct scsi_test_unit_ready scsi_cmd; 237 238 bzero(&scsi_cmd, sizeof(scsi_cmd)); 239 scsi_cmd.opcode = TEST_UNIT_READY; 240 241 return scsi_scsi_cmd(sc_link, (struct scsi_generic *) &scsi_cmd, 242 sizeof(scsi_cmd), 0, 0, 5, 10000, NULL, flags); 243 } 244 245 /* 246 * Do a scsi operation, asking a device to run as SCSI-II if it can. 247 */ 248 int 249 scsi_change_def(sc_link, flags) 250 struct scsi_link *sc_link; 251 int flags; 252 { 253 struct scsi_changedef scsi_cmd; 254 255 bzero(&scsi_cmd, sizeof(scsi_cmd)); 256 scsi_cmd.opcode = CHANGE_DEFINITION; 257 scsi_cmd.how = SC_SCSI_2; 258 259 return scsi_scsi_cmd(sc_link, (struct scsi_generic *) &scsi_cmd, 260 sizeof(scsi_cmd), 0, 0, 2, 100000, NULL, flags); 261 } 262 263 /* 264 * Do a scsi operation asking a device what it is 265 * Use the scsi_cmd routine in the switch table. 266 */ 267 int 268 scsi_inquire(sc_link, inqbuf, flags) 269 struct scsi_link *sc_link; 270 struct scsi_inquiry_data *inqbuf; 271 int flags; 272 { 273 struct scsi_inquiry scsi_cmd; 274 275 bzero(&scsi_cmd, sizeof(scsi_cmd)); 276 scsi_cmd.opcode = INQUIRY; 277 scsi_cmd.length = sizeof(struct scsi_inquiry_data); 278 279 return scsi_scsi_cmd(sc_link, (struct scsi_generic *) &scsi_cmd, 280 sizeof(scsi_cmd), (u_char *) inqbuf, 281 sizeof(struct scsi_inquiry_data), 2, 10000, NULL, 282 SCSI_DATA_IN | flags); 283 } 284 285 /* 286 * Prevent or allow the user to remove the media 287 */ 288 int 289 scsi_prevent(sc_link, type, flags) 290 struct scsi_link *sc_link; 291 int type, flags; 292 { 293 struct scsi_prevent scsi_cmd; 294 295 bzero(&scsi_cmd, sizeof(scsi_cmd)); 296 scsi_cmd.opcode = PREVENT_ALLOW; 297 scsi_cmd.how = type; 298 return scsi_scsi_cmd(sc_link, (struct scsi_generic *) &scsi_cmd, 299 sizeof(scsi_cmd), 0, 0, 2, 5000, NULL, flags); 300 } 301 302 /* 303 * Get scsi driver to send a "start up" command 304 */ 305 int 306 scsi_start(sc_link, type, flags) 307 struct scsi_link *sc_link; 308 int type, flags; 309 { 310 struct scsi_start_stop scsi_cmd; 311 312 if ((sc_link->quirks & SDEV_NOSTARTUNIT) == SDEV_NOSTARTUNIT) 313 return 0; 314 315 bzero(&scsi_cmd, sizeof(scsi_cmd)); 316 scsi_cmd.opcode = START_STOP; 317 scsi_cmd.byte2 = 0x00; 318 scsi_cmd.how = type; 319 return scsi_scsi_cmd(sc_link, (struct scsi_generic *) &scsi_cmd, 320 sizeof(scsi_cmd), 0, 0, 2, 321 type == SSS_START ? 30000 : 10000, NULL, flags); 322 } 323 324 /* 325 * This routine is called by the scsi interrupt when the transfer is complete. 326 */ 327 void 328 scsi_done(xs) 329 struct scsi_xfer *xs; 330 { 331 struct scsi_link *sc_link = xs->sc_link; 332 struct buf *bp; 333 int error; 334 335 SC_DEBUG(sc_link, SDEV_DB2, ("scsi_done\n")); 336 #ifdef SCSIDEBUG 337 if ((sc_link->flags & SDEV_DB1) != 0) 338 show_scsi_cmd(xs); 339 #endif /* SCSIDEBUG */ 340 341 /* 342 * If it's a user level request, bypass all usual completion processing, 343 * let the user work it out.. We take reponsibility for freeing the 344 * xs when the user returns. (and restarting the device's queue). 345 */ 346 if ((xs->flags & SCSI_USER) != 0) { 347 SC_DEBUG(sc_link, SDEV_DB3, ("calling user done()\n")); 348 scsi_user_done(xs); /* to take a copy of the sense etc. */ 349 SC_DEBUG(sc_link, SDEV_DB3, ("returned from user done()\n ")); 350 351 scsi_free_xs(xs, SCSI_NOSLEEP); /* restarts queue too */ 352 SC_DEBUG(sc_link, SDEV_DB3, ("returning to adapter\n")); 353 return; 354 } 355 356 if (!((xs->flags & (SCSI_NOSLEEP | SCSI_POLL)) == SCSI_NOSLEEP)) { 357 /* 358 * if it's a normal upper level request, then ask 359 * the upper level code to handle error checking 360 * rather than doing it here at interrupt time 361 */ 362 wakeup(xs); 363 return; 364 } 365 366 /* 367 * Go and handle errors now. 368 * If it returns ERESTART then we should RETRY 369 */ 370 retry: 371 error = sc_err1(xs, 1); 372 if (error == ERESTART) { 373 switch ((*(sc_link->adapter->scsi_cmd)) (xs)) { 374 case SUCCESSFULLY_QUEUED: 375 return; 376 377 case TRY_AGAIN_LATER: 378 xs->error = XS_BUSY; 379 case COMPLETE: 380 goto retry; 381 } 382 } 383 384 bp = xs->bp; 385 if (bp) { 386 if (error) { 387 bp->b_error = error; 388 bp->b_flags |= B_ERROR; 389 bp->b_resid = bp->b_bcount; 390 } else { 391 bp->b_error = 0; 392 bp->b_resid = xs->resid; 393 } 394 } 395 if (sc_link->device->done) { 396 /* 397 * Tell the device the operation is actually complete. 398 * No more will happen with this xfer. This for 399 * notification of the upper-level driver only; they 400 * won't be returning any meaningful information to us. 401 */ 402 (*sc_link->device->done)(xs); 403 } 404 scsi_free_xs(xs, SCSI_NOSLEEP); 405 if (bp) 406 biodone(bp); 407 } 408 409 int 410 scsi_execute_xs(xs) 411 struct scsi_xfer *xs; 412 { 413 int error; 414 int s; 415 416 xs->flags &= ~ITSDONE; 417 xs->error = XS_NOERROR; 418 xs->resid = xs->datalen; 419 xs->status = 0; 420 421 retry: 422 /* 423 * Do the transfer. If we are polling we will return: 424 * COMPLETE, Was poll, and scsi_done has been called 425 * TRY_AGAIN_LATER, Adapter short resources, try again 426 * 427 * if under full steam (interrupts) it will return: 428 * SUCCESSFULLY_QUEUED, will do a wakeup when complete 429 * TRY_AGAIN_LATER, (as for polling) 430 * After the wakeup, we must still check if it succeeded 431 * 432 * If we have a SCSI_NOSLEEP (typically because we have a buf) 433 * we just return. All the error proccessing and the buffer 434 * code both expect us to return straight to them, so as soon 435 * as the command is queued, return. 436 */ 437 switch ((*(xs->sc_link->adapter->scsi_cmd)) (xs)) { 438 case SUCCESSFULLY_QUEUED: 439 if ((xs->flags & (SCSI_NOSLEEP | SCSI_POLL)) == SCSI_NOSLEEP) 440 return EJUSTRETURN; 441 #ifdef DIAGNOSTIC 442 if (xs->flags & SCSI_NOSLEEP) 443 panic("scsi_execute_xs: NOSLEEP and POLL"); 444 #endif 445 s = splbio(); 446 while ((xs->flags & ITSDONE) == 0) 447 tsleep(xs, PRIBIO + 1, "scsi_scsi_cmd", 0); 448 splx(s); 449 case COMPLETE: /* Polling command completed ok */ 450 if (xs->bp) 451 return EJUSTRETURN; 452 doit: 453 SC_DEBUG(xs->sc_link, SDEV_DB3, ("back in cmd()\n")); 454 if ((error = sc_err1(xs, 0)) != ERESTART) 455 return error; 456 goto retry; 457 458 case TRY_AGAIN_LATER: /* adapter resource shortage */ 459 xs->error = XS_BUSY; 460 goto doit; 461 462 default: 463 panic("scsi_execute_xs: invalid return code"); 464 } 465 466 #ifdef DIAGNOSTIC 467 panic("scsi_execute_xs: impossible"); 468 #endif 469 return EINVAL; 470 } 471 472 /* 473 * ask the scsi driver to perform a command for us. 474 * tell it where to read/write the data, and how 475 * long the data is supposed to be. If we have a buf 476 * to associate with the transfer, we need that too. 477 */ 478 int 479 scsi_scsi_cmd(sc_link, scsi_cmd, cmdlen, data_addr, datalen, 480 retries, timeout, bp, flags) 481 struct scsi_link *sc_link; 482 struct scsi_generic *scsi_cmd; 483 int cmdlen; 484 u_char *data_addr; 485 int datalen; 486 int retries; 487 int timeout; 488 struct buf *bp; 489 int flags; 490 { 491 struct scsi_xfer *xs; 492 int error; 493 494 SC_DEBUG(sc_link, SDEV_DB2, ("scsi_cmd\n")); 495 496 #ifdef DIAGNOSTIC 497 if (bp != 0 && (flags & SCSI_NOSLEEP) == 0) 498 panic("scsi_scsi_cmd: buffer without nosleep"); 499 #endif 500 501 if ((xs = scsi_make_xs(sc_link, scsi_cmd, cmdlen, data_addr, datalen, 502 retries, timeout, bp, flags)) == NULL) 503 return ENOMEM; 504 505 if ((error = scsi_execute_xs(xs)) == EJUSTRETURN) 506 return 0; 507 508 /* 509 * we have finished with the xfer stuct, free it and 510 * check if anyone else needs to be started up. 511 */ 512 scsi_free_xs(xs, flags); 513 return error; 514 } 515 516 int 517 sc_err1(xs, async) 518 struct scsi_xfer *xs; 519 int async; 520 { 521 int error; 522 523 SC_DEBUG(xs->sc_link, SDEV_DB3, ("sc_err1,err = 0x%x \n", xs->error)); 524 525 /* 526 * If it has a buf, we might be working with 527 * a request from the buffer cache or some other 528 * piece of code that requires us to process 529 * errors at interrupt time. We have probably 530 * been called by scsi_done() 531 */ 532 switch (xs->error) { 533 case XS_NOERROR: /* nearly always hit this one */ 534 error = 0; 535 break; 536 537 case XS_SENSE: 538 case XS_SHORTSENSE: 539 if ((error = scsi_interpret_sense(xs)) == ERESTART) { 540 if (xs->error == XS_BUSY) { 541 xs->error = XS_SENSE; 542 goto sense_retry; 543 } 544 goto retry; 545 } 546 SC_DEBUG(xs->sc_link, SDEV_DB3, 547 ("scsi_interpret_sense returned %d\n", error)); 548 break; 549 550 case XS_BUSY: 551 sense_retry: 552 if (xs->retries) { 553 if ((xs->flags & SCSI_POLL) != 0) 554 delay(1000000); 555 else if ((xs->flags & SCSI_NOSLEEP) == 0) { 556 tsleep(&lbolt, PRIBIO, "scbusy", 0); 557 } else 558 #if 0 559 timeout(scsi_requeue, xs, hz); 560 #else 561 goto lose; 562 #endif 563 } 564 case XS_TIMEOUT: 565 retry: 566 if (xs->retries--) { 567 xs->error = XS_NOERROR; 568 xs->flags &= ~ITSDONE; 569 return ERESTART; 570 } 571 case XS_DRIVER_STUFFUP: 572 lose: 573 error = EIO; 574 break; 575 576 case XS_SELTIMEOUT: 577 /* XXX Disable device? */ 578 error = EIO; 579 break; 580 581 case XS_RESET: 582 if (xs->retries) { 583 SC_DEBUG(xs->sc_link, SDEV_DB3, 584 ("restarting command destroyed by reset\n")); 585 goto retry; 586 } 587 error = EIO; 588 break; 589 590 default: 591 sc_print_addr(xs->sc_link); 592 printf("unknown error category from scsi driver\n"); 593 error = EIO; 594 break; 595 } 596 597 return error; 598 } 599 600 /* 601 * Look at the returned sense and act on the error, determining 602 * the unix error number to pass back. (0 = report no error) 603 * 604 * THIS IS THE DEFAULT ERROR HANDLER 605 */ 606 int 607 scsi_interpret_sense(xs) 608 struct scsi_xfer *xs; 609 { 610 struct scsi_sense_data *sense; 611 struct scsi_link *sc_link = xs->sc_link; 612 u_int8_t key; 613 u_int32_t info; 614 int error; 615 616 sense = &xs->sense; 617 #ifdef SCSIDEBUG 618 if ((sc_link->flags & SDEV_DB1) != 0) { 619 int count; 620 printf("code%x valid%x ", 621 sense->error_code & SSD_ERRCODE, 622 sense->error_code & SSD_ERRCODE_VALID ? 1 : 0); 623 printf("seg%x key%x ili%x eom%x fmark%x\n", 624 sense->segment, 625 sense->flags & SSD_KEY, 626 sense->flags & SSD_ILI ? 1 : 0, 627 sense->flags & SSD_EOM ? 1 : 0, 628 sense->flags & SSD_FILEMARK ? 1 : 0); 629 printf("info: %x %x %x %x followed by %d extra bytes\n", 630 sense->info[0], 631 sense->info[1], 632 sense->info[2], 633 sense->info[3], 634 sense->extra_len); 635 printf("extra: "); 636 for (count = 0; count < sense->extra_len; count++) 637 printf("%x ", sense->cmd_spec_info[count]); 638 printf("\n"); 639 } 640 #endif /* SCSIDEBUG */ 641 /* 642 * If the device has it's own error handler, call it first. 643 * If it returns a legit error value, return that, otherwise 644 * it wants us to continue with normal error processing. 645 */ 646 if (sc_link->device->err_handler) { 647 SC_DEBUG(sc_link, SDEV_DB2, ("calling private err_handler()\n")); 648 error = (*sc_link->device->err_handler) (xs); 649 if (error != SCSIRET_CONTINUE) 650 return error; /* error >= 0 better ? */ 651 } 652 /* otherwise use the default */ 653 switch (sense->error_code & SSD_ERRCODE) { 654 /* 655 * If it's code 70, use the extended stuff and interpret the key 656 */ 657 case 0x71: /* delayed error */ 658 sc_print_addr(sc_link); 659 key = sense->flags & SSD_KEY; 660 printf(" DEFERRED ERROR, key = 0x%x\n", key); 661 /* FALLTHROUGH */ 662 case 0x70: 663 if ((sense->error_code & SSD_ERRCODE_VALID) != 0) 664 info = _4btol(sense->info); 665 else 666 info = 0; 667 key = sense->flags & SSD_KEY; 668 669 switch (key) { 670 case SKEY_NO_SENSE: 671 case SKEY_RECOVERED_ERROR: 672 if (xs->resid == xs->datalen) 673 xs->resid = 0; /* not short read */ 674 case SKEY_EQUAL: 675 error = 0; 676 break; 677 case SKEY_NOT_READY: 678 if ((sc_link->flags & SDEV_REMOVABLE) != 0) 679 sc_link->flags &= ~SDEV_MEDIA_LOADED; 680 if ((xs->flags & SCSI_IGNORE_NOT_READY) != 0) 681 return 0; 682 if (xs->retries && sense->add_sense_code == 0x04 && 683 sense->add_sense_code_qual == 0x01) { 684 xs->error = XS_BUSY; /* ie. sense_retry */ 685 return ERESTART; 686 } 687 if (xs->retries && !(sc_link->flags & SDEV_REMOVABLE)) { 688 delay(1000000); 689 return ERESTART; 690 } 691 if ((xs->flags & SCSI_SILENT) != 0) 692 return EIO; 693 error = EIO; 694 break; 695 case SKEY_ILLEGAL_REQUEST: 696 if ((xs->flags & SCSI_IGNORE_ILLEGAL_REQUEST) != 0) 697 return 0; 698 if ((xs->flags & SCSI_SILENT) != 0) 699 return EIO; 700 error = EINVAL; 701 break; 702 case SKEY_UNIT_ATTENTION: 703 if (sense->add_sense_code == 0x29 && 704 sense->add_sense_code_qual == 0x00) 705 return (ERESTART); /* device or bus reset */ 706 if ((sc_link->flags & SDEV_REMOVABLE) != 0) 707 sc_link->flags &= ~SDEV_MEDIA_LOADED; 708 if ((xs->flags & SCSI_IGNORE_MEDIA_CHANGE) != 0 || 709 /* XXX Should reupload any transient state. */ 710 (sc_link->flags & SDEV_REMOVABLE) == 0) 711 return ERESTART; 712 if ((xs->flags & SCSI_SILENT) != 0) 713 return EIO; 714 error = EIO; 715 break; 716 case SKEY_WRITE_PROTECT: 717 error = EROFS; 718 break; 719 case SKEY_BLANK_CHECK: 720 error = 0; 721 break; 722 case SKEY_ABORTED_COMMAND: 723 error = ERESTART; 724 break; 725 case SKEY_VOLUME_OVERFLOW: 726 error = ENOSPC; 727 break; 728 default: 729 error = EIO; 730 break; 731 } 732 733 if ((xs->flags & SCSI_SILENT) == 0) 734 scsi_print_sense(xs, 0); 735 736 return error; 737 738 /* 739 * Not code 70, just report it 740 */ 741 default: 742 sc_print_addr(sc_link); 743 printf("Sense Error Code %d", 744 sense->error_code & SSD_ERRCODE); 745 if ((sense->error_code & SSD_ERRCODE_VALID) != 0) { 746 struct scsi_sense_data_unextended *usense = 747 (struct scsi_sense_data_unextended *)sense; 748 printf(" at block no. %d (decimal)", 749 _3btol(usense->block)); 750 } 751 printf("\n"); 752 return EIO; 753 } 754 } 755 756 /* 757 * Utility routines often used in SCSI stuff 758 */ 759 760 761 /* 762 * Print out the scsi_link structure's address info. 763 */ 764 void 765 sc_print_addr(sc_link) 766 struct scsi_link *sc_link; 767 { 768 769 printf("%s(%s:%d:%d): ", 770 sc_link->device_softc ? 771 ((struct device *)sc_link->device_softc)->dv_xname : "probe", 772 ((struct device *)sc_link->adapter_softc)->dv_xname, 773 sc_link->target, sc_link->lun); 774 } 775 776 static const char *sense_keys[16] = { 777 "No Additional Sense", 778 "Soft Error", 779 "Not Ready", 780 "Media Error", 781 "Hardware Error", 782 "Illegal Request", 783 "Unit Attention", 784 "Write Protected", 785 "Blank Check", 786 "Vendor Unique", 787 "Copy Aborted", 788 "Aborted Command", 789 "Equal Error", 790 "Volume Overflow", 791 "Miscompare Error", 792 "Reserved" 793 }; 794 #ifndef SCSITERSE 795 static const struct { 796 u_char asc, ascq; 797 char *description; 798 } adesc[] = { 799 { 0x00, 0x00, "No Additional Sense Information" }, 800 { 0x00, 0x01, "Filemark Detected" }, 801 { 0x00, 0x02, "End-Of-Partition/Medium Detected" }, 802 { 0x00, 0x03, "Setmark Detected" }, 803 { 0x00, 0x04, "Beginning-Of-Partition/Medium Detected" }, 804 { 0x00, 0x05, "End-Of-Data Detected" }, 805 { 0x00, 0x06, "I/O Process Terminated" }, 806 { 0x00, 0x11, "Audio Play Operation In Progress" }, 807 { 0x00, 0x12, "Audio Play Operation Paused" }, 808 { 0x00, 0x13, "Audio Play Operation Successfully Completed" }, 809 { 0x00, 0x14, "Audio Play Operation Stopped Due to Error" }, 810 { 0x00, 0x15, "No Current Audio Status To Return" }, 811 { 0x01, 0x00, "No Index/Sector Signal" }, 812 { 0x02, 0x00, "No Seek Complete" }, 813 { 0x03, 0x00, "Peripheral Device Write Fault" }, 814 { 0x03, 0x01, "No Write Current" }, 815 { 0x03, 0x02, "Excessive Write Errors" }, 816 { 0x04, 0x00, "Logical Unit Not Ready, Cause Not Reportable" }, 817 { 0x04, 0x01, "Logical Unit Is in Process Of Becoming Ready" }, 818 { 0x04, 0x02, "Logical Unit Not Ready, Initialization Command Required" }, 819 { 0x04, 0x03, "Logical Unit Not Ready, Manual Intervention Required" }, 820 { 0x04, 0x04, "Logical Unit Not Ready, Format In Progress" }, 821 { 0x05, 0x00, "Logical Unit Does Not Respond To Selection" }, 822 { 0x06, 0x00, "No Reference Position Found" }, 823 { 0x07, 0x00, "Multiple Peripheral Devices Selected" }, 824 { 0x08, 0x00, "Logical Unit Communication Failure" }, 825 { 0x08, 0x01, "Logical Unit Communication Timeout" }, 826 { 0x08, 0x02, "Logical Unit Communication Parity Error" }, 827 { 0x09, 0x00, "Track Following Error" }, 828 { 0x09, 0x01, "Tracking Servo Failure" }, 829 { 0x09, 0x02, "Focus Servo Failure" }, 830 { 0x09, 0x03, "Spindle Servo Failure" }, 831 { 0x0A, 0x00, "Error Log Overflow" }, 832 { 0x0C, 0x00, "Write Error" }, 833 { 0x0C, 0x01, "Write Error Recovered with Auto Reallocation" }, 834 { 0x0C, 0x02, "Write Error - Auto Reallocate Failed" }, 835 { 0x10, 0x00, "ID CRC Or ECC Error" }, 836 { 0x11, 0x00, "Unrecovered Read Error" }, 837 { 0x11, 0x01, "Read Retried Exhausted" }, 838 { 0x11, 0x02, "Error Too Long To Correct" }, 839 { 0x11, 0x03, "Multiple Read Errors" }, 840 { 0x11, 0x04, "Unrecovered Read Error - Auto Reallocate Failed" }, 841 { 0x11, 0x05, "L-EC Uncorrectable Error" }, 842 { 0x11, 0x06, "CIRC Unrecovered Error" }, 843 { 0x11, 0x07, "Data Resynchronization Error" }, 844 { 0x11, 0x08, "Incomplete Block Found" }, 845 { 0x11, 0x09, "No Gap Found" }, 846 { 0x11, 0x0A, "Miscorrected Error" }, 847 { 0x11, 0x0B, "Uncorrected Read Error - Recommend Reassignment" }, 848 { 0x11, 0x0C, "Uncorrected Read Error - Recommend Rewrite the Data" }, 849 { 0x12, 0x00, "Address Mark Not Found for ID Field" }, 850 { 0x13, 0x00, "Address Mark Not Found for Data Field" }, 851 { 0x14, 0x00, "Recorded Entity Not Found" }, 852 { 0x14, 0x01, "Record Not Found" }, 853 { 0x14, 0x02, "Filemark or Setmark Not Found" }, 854 { 0x14, 0x03, "End-Of-Data Not Found" }, 855 { 0x14, 0x04, "Block Sequence Error" }, 856 { 0x15, 0x00, "Random Positioning Error" }, 857 { 0x15, 0x01, "Mechanical Positioning Error" }, 858 { 0x15, 0x02, "Positioning Error Detected By Read of Medium" }, 859 { 0x16, 0x00, "Data Synchronization Mark Error" }, 860 { 0x17, 0x00, "Recovered Data With No Error Correction Applied" }, 861 { 0x17, 0x01, "Recovered Data With Retries" }, 862 { 0x17, 0x02, "Recovered Data With Positive Head Offset" }, 863 { 0x17, 0x03, "Recovered Data With Negative Head Offset" }, 864 { 0x17, 0x04, "Recovered Data With Retries and/or CIRC Applied" }, 865 { 0x17, 0x05, "Recovered Data Using Previous Sector ID" }, 866 { 0x17, 0x06, "Recovered Data Without ECC - Data Auto-Reallocated" }, 867 { 0x17, 0x07, "Recovered Data Without ECC - Recommend Reassignment" }, 868 { 0x17, 0x08, "Recovered Data Without ECC - Recommend Rewrite" }, 869 { 0x18, 0x00, "Recovered Data With Error Correction Applied" }, 870 { 0x18, 0x01, "Recovered Data With Error Correction & Retries Applied" }, 871 { 0x18, 0x02, "Recovered Data - Data Auto-Reallocated" }, 872 { 0x18, 0x03, "Recovered Data With CIRC" }, 873 { 0x18, 0x04, "Recovered Data With LEC" }, 874 { 0x18, 0x05, "Recovered Data - Recommend Reassignment" }, 875 { 0x18, 0x06, "Recovered Data - Recommend Rewrite" }, 876 { 0x19, 0x00, "Defect List Error" }, 877 { 0x19, 0x01, "Defect List Not Available" }, 878 { 0x19, 0x02, "Defect List Error in Primary List" }, 879 { 0x19, 0x03, "Defect List Error in Grown List" }, 880 { 0x1A, 0x00, "Parameter List Length Error" }, 881 { 0x1B, 0x00, "Synchronous Data Transfer Error" }, 882 { 0x1C, 0x00, "Defect List Not Found" }, 883 { 0x1C, 0x01, "Primary Defect List Not Found" }, 884 { 0x1C, 0x02, "Grown Defect List Not Found" }, 885 { 0x1D, 0x00, "Miscompare During Verify Operation" }, 886 { 0x1E, 0x00, "Recovered ID with ECC" }, 887 { 0x20, 0x00, "Invalid Command Operation Code" }, 888 { 0x21, 0x00, "Logical Block Address Out of Range" }, 889 { 0x21, 0x01, "Invalid Element Address" }, 890 { 0x22, 0x00, "Illegal Function (Should 20 00, 24 00, or 26 00)" }, 891 { 0x24, 0x00, "Illegal Field in CDB" }, 892 { 0x25, 0x00, "Logical Unit Not Supported" }, 893 { 0x26, 0x00, "Invalid Field In Parameter List" }, 894 { 0x26, 0x01, "Parameter Not Supported" }, 895 { 0x26, 0x02, "Parameter Value Invalid" }, 896 { 0x26, 0x03, "Threshold Parameters Not Supported" }, 897 { 0x27, 0x00, "Write Protected" }, 898 { 0x28, 0x00, "Not Ready To Ready Transition (Medium May Have Changed)" }, 899 { 0x28, 0x01, "Import Or Export Element Accessed" }, 900 { 0x29, 0x00, "Power On, Reset, or Bus Device Reset Occurred" }, 901 { 0x2A, 0x00, "Parameters Changed" }, 902 { 0x2A, 0x01, "Mode Parameters Changed" }, 903 { 0x2A, 0x02, "Log Parameters Changed" }, 904 { 0x2B, 0x00, "Copy Cannot Execute Since Host Cannot Disconnect" }, 905 { 0x2C, 0x00, "Command Sequence Error" }, 906 { 0x2C, 0x01, "Too Many Windows Specified" }, 907 { 0x2C, 0x02, "Invalid Combination of Windows Specified" }, 908 { 0x2D, 0x00, "Overwrite Error On Update In Place" }, 909 { 0x2F, 0x00, "Commands Cleared By Another Initiator" }, 910 { 0x30, 0x00, "Incompatible Medium Installed" }, 911 { 0x30, 0x01, "Cannot Read Medium - Unknown Format" }, 912 { 0x30, 0x02, "Cannot Read Medium - Incompatible Format" }, 913 { 0x30, 0x03, "Cleaning Cartridge Installed" }, 914 { 0x31, 0x00, "Medium Format Corrupted" }, 915 { 0x31, 0x01, "Format Command Failed" }, 916 { 0x32, 0x00, "No Defect Spare Location Available" }, 917 { 0x32, 0x01, "Defect List Update Failure" }, 918 { 0x33, 0x00, "Tape Length Error" }, 919 { 0x36, 0x00, "Ribbon, Ink, or Toner Failure" }, 920 { 0x37, 0x00, "Rounded Parameter" }, 921 { 0x39, 0x00, "Saving Parameters Not Supported" }, 922 { 0x3A, 0x00, "Medium Not Present" }, 923 { 0x3B, 0x00, "Positioning Error" }, 924 { 0x3B, 0x01, "Tape Position Error At Beginning-of-Medium" }, 925 { 0x3B, 0x02, "Tape Position Error At End-of-Medium" }, 926 { 0x3B, 0x03, "Tape or Electronic Vertical Forms Unit Not Ready" }, 927 { 0x3B, 0x04, "Slew Failure" }, 928 { 0x3B, 0x05, "Paper Jam" }, 929 { 0x3B, 0x06, "Failed To Sense Top-Of-Form" }, 930 { 0x3B, 0x07, "Failed To Sense Bottom-Of-Form" }, 931 { 0x3B, 0x08, "Reposition Error" }, 932 { 0x3B, 0x09, "Read Past End Of Medium" }, 933 { 0x3B, 0x0A, "Read Past Begining Of Medium" }, 934 { 0x3B, 0x0B, "Position Past End Of Medium" }, 935 { 0x3B, 0x0C, "Position Past Beginning Of Medium" }, 936 { 0x3B, 0x0D, "Medium Destination Element Full" }, 937 { 0x3B, 0x0E, "Medium Source Element Empty" }, 938 { 0x3D, 0x00, "Invalid Bits In IDENTFY Message" }, 939 { 0x3E, 0x00, "Logical Unit Has Not Self-Configured Yet" }, 940 { 0x3F, 0x00, "Target Operating Conditions Have Changed" }, 941 { 0x3F, 0x01, "Microcode Has Changed" }, 942 { 0x3F, 0x02, "Changed Operating Definition" }, 943 { 0x3F, 0x03, "INQUIRY Data Has Changed" }, 944 { 0x40, 0x00, "RAM FAILURE (Should Use 40 NN)" }, 945 { 0x41, 0x00, "Data Path FAILURE (Should Use 40 NN)" }, 946 { 0x42, 0x00, "Power-On or Self-Test FAILURE (Should Use 40 NN)" }, 947 { 0x43, 0x00, "Message Error" }, 948 { 0x44, 0x00, "Internal Target Failure" }, 949 { 0x45, 0x00, "Select Or Reselect Failure" }, 950 { 0x46, 0x00, "Unsuccessful Soft Reset" }, 951 { 0x47, 0x00, "SCSI Parity Error" }, 952 { 0x48, 0x00, "INITIATOR DETECTED ERROR Message Received" }, 953 { 0x49, 0x00, "Invalid Message Error" }, 954 { 0x4A, 0x00, "Command Phase Error" }, 955 { 0x4B, 0x00, "Data Phase Error" }, 956 { 0x4C, 0x00, "Logical Unit Failed Self-Configuration" }, 957 { 0x4E, 0x00, "Overlapped Commands Attempted" }, 958 { 0x50, 0x00, "Write Append Error" }, 959 { 0x50, 0x01, "Write Append Position Error" }, 960 { 0x50, 0x02, "Position Error Related To Timing" }, 961 { 0x51, 0x00, "Erase Failure" }, 962 { 0x52, 0x00, "Cartridge Fault" }, 963 { 0x53, 0x00, "Media Load or Eject Failed" }, 964 { 0x53, 0x01, "Unload Tape Failure" }, 965 { 0x53, 0x02, "Medium Removal Prevented" }, 966 { 0x54, 0x00, "SCSI To Host System Interface Failure" }, 967 { 0x55, 0x00, "System Resource Failure" }, 968 { 0x57, 0x00, "Unable To Recover Table-Of-Contents" }, 969 { 0x58, 0x00, "Generation Does Not Exist" }, 970 { 0x59, 0x00, "Updated Block Read" }, 971 { 0x5A, 0x00, "Operator Request or State Change Input (Unspecified)" }, 972 { 0x5A, 0x01, "Operator Medium Removal Requested" }, 973 { 0x5A, 0x02, "Operator Selected Write Protect" }, 974 { 0x5A, 0x03, "Operator Selected Write Permit" }, 975 { 0x5B, 0x00, "Log Exception" }, 976 { 0x5B, 0x01, "Threshold Condition Met" }, 977 { 0x5B, 0x02, "Log Counter At Maximum" }, 978 { 0x5B, 0x03, "Log List Codes Exhausted" }, 979 { 0x5C, 0x00, "RPL Status Change" }, 980 { 0x5C, 0x01, "Spindles Synchronized" }, 981 { 0x5C, 0x02, "Spindles Not Synchronized" }, 982 { 0x60, 0x00, "Lamp Failure" }, 983 { 0x61, 0x00, "Video Acquisition Error" }, 984 { 0x61, 0x01, "Unable To Acquire Video" }, 985 { 0x61, 0x02, "Out Of Focus" }, 986 { 0x62, 0x00, "Scan Head Positioning Error" }, 987 { 0x63, 0x00, "End Of User Area Encountered On This Track" }, 988 { 0x64, 0x00, "Illegal Mode For This Track" }, 989 { 0x00, 0x00, NULL } 990 }; 991 992 static __inline void 993 asc2ascii(asc, ascq, result) 994 u_char asc, ascq; 995 char *result; 996 { 997 register int i = 0; 998 999 while (adesc[i].description != NULL) { 1000 if (adesc[i].asc == asc && adesc[i].ascq == ascq) 1001 break; 1002 i++; 1003 } 1004 if (adesc[i].description == NULL) { 1005 if (asc == 0x40 && ascq != 0) { 1006 (void) sprintf(result, 1007 "Diagnostic Failure on Component 0x%02x", 1008 ascq & 0xff); 1009 } else { 1010 (void) sprintf(result, "ASC 0x%02x ASCQ 0x%02x", 1011 asc & 0xff, ascq & 0xff); 1012 } 1013 } else { 1014 (void) strcpy(result, adesc[i].description); 1015 } 1016 } 1017 1018 #else 1019 1020 static __inline void 1021 asc2ascii(asc, ascq, result) 1022 u_char asc, ascq; 1023 char *result; 1024 { 1025 (void) sprintf(result, "ASC 0x%02x ASCQ 0x%02x", asc & 0xff, 1026 ascq & 0xff); 1027 } 1028 #endif /* SCSITERSE */ 1029 1030 void 1031 scsi_print_sense(xs, verbosity) 1032 struct scsi_xfer *xs; 1033 int verbosity; 1034 { 1035 int32_t info; 1036 register int i, j, k; 1037 char *sbs, *s; 1038 1039 sc_print_addr(xs->sc_link); 1040 s = (char *) &xs->sense; 1041 printf("Check Condition on opcode 0x%x\n", xs->cmd->opcode); 1042 1043 /* 1044 * Basics- print out SENSE KEY 1045 */ 1046 printf(" SENSE KEY: %s\n", scsi_decode_sense(s, 0)); 1047 1048 /* 1049 * Print out, unqualified but aligned, FMK, EOM and ILI status. 1050 */ 1051 if (s[2] & 0xe0) { 1052 char pad = ' '; 1053 1054 printf(" "); 1055 if (s[2] & SSD_FILEMARK) { 1056 printf("%c Filemark Detected", pad); 1057 pad = ','; 1058 } 1059 if (s[2] & SSD_EOM) { 1060 printf("%c EOM Detected", pad); 1061 pad = ','; 1062 } 1063 if (s[2] & SSD_ILI) 1064 printf("%c Incorrect Length Indicator Set", pad); 1065 printf("\n"); 1066 } 1067 /* 1068 * Now we should figure out, based upon device type, how 1069 * to format the information field. Unfortunately, that's 1070 * not convenient here, so we'll print it as a signed 1071 * 32 bit integer. 1072 */ 1073 info = _4btol(&s[3]); 1074 if (info) 1075 printf(" INFO FIELD: %u\n", info); 1076 1077 /* 1078 * Now we check additional length to see whether there is 1079 * more information to extract. 1080 */ 1081 1082 /* enough for command specific information? */ 1083 if (s[7] < 4) 1084 return; 1085 info = _4btol(&s[8]); 1086 if (info) 1087 printf(" COMMAND INFO: %d (0x%x)\n", info, info); 1088 1089 /* 1090 * Decode ASC && ASCQ info, plus FRU, plus the rest... 1091 */ 1092 1093 sbs = scsi_decode_sense(s, 1); 1094 if (sbs) 1095 printf(" ASC/ASCQ: %s\n", sbs); 1096 if (s[14] != 0) 1097 printf(" FRU CODE: 0x%x\n", s[14] & 0xff); 1098 sbs = scsi_decode_sense(s, 3); 1099 if (sbs) 1100 printf(" SKSV: %s\n", sbs); 1101 if (verbosity == 0) 1102 return; 1103 1104 /* 1105 * Now figure whether we should print any additional informtion. 1106 * 1107 * Where should we start from? If we had SKSV data, 1108 * start from offset 18, else from offset 15. 1109 * 1110 * From that point until the end of the buffer, check for any 1111 * nonzero data. If we have some, go back and print the lot, 1112 * otherwise we're done. 1113 */ 1114 if (sbs) 1115 i = 18; 1116 else 1117 i = 15; 1118 1119 for (j = i; j < sizeof (xs->sense); j++) 1120 if (s[j]) 1121 break; 1122 if (j == sizeof (xs->sense)) 1123 return; 1124 1125 printf(" Additional Sense Information (byte %d out...):\n", i); 1126 if (i == 15) { 1127 printf(" %2d:", i); 1128 k = 7; 1129 } else { 1130 printf(" %2d:", i); 1131 k = 2; 1132 j -= 2; 1133 } 1134 while (j > 0) { 1135 if (i >= sizeof (xs->sense)) 1136 break; 1137 if (k == 8) { 1138 k = 0; 1139 printf("\n %2d:", i); 1140 } 1141 printf(" 0x%02x", s[i] & 0xff); 1142 k++; 1143 j--; 1144 i++; 1145 } 1146 printf("\n"); 1147 } 1148 1149 char * 1150 scsi_decode_sense(sinfo, flag) 1151 void *sinfo; 1152 int flag; 1153 { 1154 u_char *snsbuf, skey; 1155 static char rqsbuf[132]; 1156 1157 skey = 0; 1158 1159 snsbuf = (u_char *) sinfo; 1160 if (flag == 0 || flag == 2 || flag == 3) { 1161 skey = snsbuf[2] & 0xf; 1162 } 1163 if (flag == 0) { /* Sense Key Only */ 1164 (void) strcpy(rqsbuf, sense_keys[skey]); 1165 return (rqsbuf); 1166 } else if (flag == 1) { /* ASC/ASCQ Only */ 1167 asc2ascii(snsbuf[12], snsbuf[13], rqsbuf); 1168 return (rqsbuf); 1169 } else if (flag == 2) { /* Sense Key && ASC/ASCQ */ 1170 asc2ascii(snsbuf[12], snsbuf[13], 1171 rqsbuf + sprintf(rqsbuf, "%s, ", sense_keys[skey])); 1172 return (rqsbuf); 1173 } else if (flag == 3 && snsbuf[7] >= 9 && (snsbuf[15] & 0x80)) { 1174 /* 1175 * SKSV Data 1176 */ 1177 switch (skey) { 1178 case 0x5: /* Illegal Request */ 1179 if (snsbuf[15] & 0x8) { 1180 (void) sprintf(rqsbuf, 1181 "Error in %s, Offset %d, bit %d", 1182 (snsbuf[15] & 0x40)? "CDB" : "Parameters", 1183 (snsbuf[16] & 0xff) << 8 | 1184 (snsbuf[17] & 0xff), snsbuf[15] & 0xf); 1185 } else { 1186 (void) sprintf(rqsbuf, 1187 "Error in %s, Offset %d", 1188 (snsbuf[15] & 0x40)? "CDB" : "Parameters", 1189 (snsbuf[16] & 0xff) << 8 | 1190 (snsbuf[17] & 0xff)); 1191 } 1192 return (rqsbuf); 1193 case 0x1: 1194 case 0x3: 1195 case 0x4: 1196 (void) sprintf(rqsbuf, "Actual Retry Count: %d", 1197 (snsbuf[16] & 0xff) << 8 | (snsbuf[17] & 0xff)); 1198 return (rqsbuf); 1199 case 0x2: 1200 (void) sprintf(rqsbuf, "Progress Indicator: %d", 1201 (snsbuf[16] & 0xff) << 8 | (snsbuf[17] & 0xff)); 1202 return (rqsbuf); 1203 default: 1204 break; 1205 } 1206 } 1207 return (NULL); 1208 } 1209 1210 #ifdef SCSIDEBUG 1211 /* 1212 * Given a scsi_xfer, dump the request, in all it's glory 1213 */ 1214 void 1215 show_scsi_xs(xs) 1216 struct scsi_xfer *xs; 1217 { 1218 printf("xs(%p): ", xs); 1219 printf("flg(0x%x)", xs->flags); 1220 printf("sc_link(%p)", xs->sc_link); 1221 printf("retr(0x%x)", xs->retries); 1222 printf("timo(0x%x)", xs->timeout); 1223 printf("cmd(%p)", xs->cmd); 1224 printf("len(0x%x)", xs->cmdlen); 1225 printf("data(%p)", xs->data); 1226 printf("len(0x%x)", xs->datalen); 1227 printf("res(0x%x)", xs->resid); 1228 printf("err(0x%x)", xs->error); 1229 printf("bp(%p)", xs->bp); 1230 show_scsi_cmd(xs); 1231 } 1232 1233 void 1234 show_scsi_cmd(xs) 1235 struct scsi_xfer *xs; 1236 { 1237 u_char *b = (u_char *) xs->cmd; 1238 int i = 0; 1239 1240 sc_print_addr(xs->sc_link); 1241 printf("command: "); 1242 1243 if ((xs->flags & SCSI_RESET) == 0) { 1244 while (i < xs->cmdlen) { 1245 if (i) 1246 printf(","); 1247 printf("%x", b[i++]); 1248 } 1249 printf("-[%d bytes]\n", xs->datalen); 1250 if (xs->datalen) 1251 show_mem(xs->data, min(64, xs->datalen)); 1252 } else 1253 printf("-RESET-\n"); 1254 } 1255 1256 void 1257 show_mem(address, num) 1258 u_char *address; 1259 int num; 1260 { 1261 int x; 1262 1263 printf("------------------------------"); 1264 for (x = 0; x < num; x++) { 1265 if ((x % 16) == 0) 1266 printf("\n%03d: ", x); 1267 printf("%02x ", *address++); 1268 } 1269 printf("\n------------------------------\n"); 1270 } 1271 #endif /* SCSIDEBUG */ 1272