Annotation of sys/scsi/scsi_base.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: scsi_base.c,v 1.122 2007/06/23 19:19:49 krw 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: #include <sys/pool.h>
! 49:
! 50: #include <scsi/scsi_all.h>
! 51: #include <scsi/scsi_disk.h>
! 52: #include <scsi/scsiconf.h>
! 53:
! 54: static __inline struct scsi_xfer *scsi_make_xs(struct scsi_link *,
! 55: struct scsi_generic *, int cmdlen, u_char *data_addr,
! 56: int datalen, int retries, int timeout, struct buf *, int flags);
! 57: static __inline void asc2ascii(u_int8_t, u_int8_t ascq, char *result,
! 58: size_t len);
! 59: int sc_err1(struct scsi_xfer *);
! 60: int scsi_interpret_sense(struct scsi_xfer *);
! 61: char *scsi_decode_sense(struct scsi_sense_data *, int);
! 62:
! 63: /* Values for flag parameter to scsi_decode_sense. */
! 64: #define DECODE_SENSE_KEY 1
! 65: #define DECODE_ASC_ASCQ 2
! 66: #define DECODE_SKSV 3
! 67:
! 68: int scsi_running = 0;
! 69: struct pool scsi_xfer_pool;
! 70:
! 71: /*
! 72: * Called when a scsibus is attached to initialize global data.
! 73: */
! 74: void
! 75: scsi_init()
! 76: {
! 77: if (scsi_running++)
! 78: return;
! 79:
! 80: #if defined(SCSI_DELAY) && SCSI_DELAY > 0
! 81: /* Historical. Older buses may need a moment to stabilize. */
! 82: delay(1000000 * SCSI_DELAY);
! 83: #endif
! 84:
! 85: /* Initialize the scsi_xfer pool. */
! 86: pool_init(&scsi_xfer_pool, sizeof(struct scsi_xfer), 0,
! 87: 0, 0, "scxspl", NULL);
! 88: }
! 89:
! 90: void
! 91: scsi_deinit()
! 92: {
! 93: if (--scsi_running)
! 94: return;
! 95: }
! 96:
! 97: /*
! 98: * Get a scsi transfer structure for the caller. Charge the structure
! 99: * to the device that is referenced by the sc_link structure. If the
! 100: * sc_link structure has no 'credits' then the device already has the
! 101: * maximum number or outstanding operations under way. In this stage,
! 102: * wait on the structure so that when one is freed, we are awoken again
! 103: * If the SCSI_NOSLEEP flag is set, then do not wait, but rather, return
! 104: * a NULL pointer, signifying that no slots were available
! 105: * Note in the link structure, that we are waiting on it.
! 106: */
! 107:
! 108: struct scsi_xfer *
! 109: scsi_get_xs(struct scsi_link *sc_link, int flags)
! 110: {
! 111: struct scsi_xfer *xs;
! 112: int s;
! 113:
! 114: SC_DEBUG(sc_link, SDEV_DB3, ("scsi_get_xs\n"));
! 115:
! 116: s = splbio();
! 117: while (sc_link->openings == 0) {
! 118: SC_DEBUG(sc_link, SDEV_DB3, ("sleeping\n"));
! 119: if ((flags & SCSI_NOSLEEP) != 0) {
! 120: splx(s);
! 121: return (NULL);
! 122: }
! 123: sc_link->flags |= SDEV_WAITING;
! 124: if (tsleep(sc_link, PRIBIO|PCATCH, "getxs", 0)) {
! 125: /* Bail out on getting a signal. */
! 126: sc_link->flags &= ~SDEV_WAITING;
! 127: splx(s);
! 128: return (NULL);
! 129: }
! 130: }
! 131: SC_DEBUG(sc_link, SDEV_DB3, ("calling pool_get\n"));
! 132: xs = pool_get(&scsi_xfer_pool,
! 133: ((flags & SCSI_NOSLEEP) != 0 ? PR_NOWAIT : PR_WAITOK));
! 134: if (xs != NULL) {
! 135: bzero(xs, sizeof(*xs));
! 136: sc_link->openings--;
! 137: xs->flags = flags;
! 138: } else {
! 139: sc_print_addr(sc_link);
! 140: printf("cannot allocate scsi xs\n");
! 141: }
! 142: splx(s);
! 143:
! 144: SC_DEBUG(sc_link, SDEV_DB3, ("returning\n"));
! 145:
! 146: return (xs);
! 147: }
! 148:
! 149: /*
! 150: * Given a scsi_xfer struct, and a device (referenced through sc_link)
! 151: * return the struct to the free pool and credit the device with it
! 152: * If another process is waiting for an xs, do a wakeup, let it proceed
! 153: */
! 154: void
! 155: scsi_free_xs(struct scsi_xfer *xs, int start)
! 156: {
! 157: struct scsi_link *sc_link = xs->sc_link;
! 158:
! 159: splassert(IPL_BIO);
! 160:
! 161: SC_DEBUG(sc_link, SDEV_DB3, ("scsi_free_xs\n"));
! 162:
! 163: pool_put(&scsi_xfer_pool, xs);
! 164: sc_link->openings++;
! 165:
! 166: /* If someone is waiting for scsi_xfer, wake them up. */
! 167: if ((sc_link->flags & SDEV_WAITING) != 0) {
! 168: sc_link->flags &= ~SDEV_WAITING;
! 169: wakeup(sc_link);
! 170: } else if (start && sc_link->device->start) {
! 171: SC_DEBUG(sc_link, SDEV_DB2,
! 172: ("calling private start()\n"));
! 173: (*(sc_link->device->start)) (sc_link->device_softc);
! 174: }
! 175: }
! 176:
! 177: /*
! 178: * Make a scsi_xfer, and return a pointer to it.
! 179: */
! 180: static __inline struct scsi_xfer *
! 181: scsi_make_xs(struct scsi_link *sc_link, struct scsi_generic *scsi_cmd,
! 182: int cmdlen, u_char *data_addr, int datalen, int retries, int timeout,
! 183: struct buf *bp, int flags)
! 184: {
! 185: struct scsi_xfer *xs;
! 186:
! 187: if ((xs = scsi_get_xs(sc_link, flags)) == NULL)
! 188: return (NULL);
! 189:
! 190: /*
! 191: * Fill out the scsi_xfer structure. We don't know whose context
! 192: * the cmd is in, so copy it.
! 193: */
! 194: xs->sc_link = sc_link;
! 195: bcopy(scsi_cmd, &xs->cmdstore, cmdlen);
! 196: xs->cmd = &xs->cmdstore;
! 197: xs->cmdlen = cmdlen;
! 198: xs->data = data_addr;
! 199: xs->datalen = datalen;
! 200: xs->retries = retries;
! 201: xs->timeout = timeout;
! 202: xs->bp = bp;
! 203:
! 204: /*
! 205: * Set the LUN in the CDB if it fits in the three bits available. This
! 206: * may only be needed if we have an older device. However, we also set
! 207: * it for more modern SCSI devices "just in case". The old code
! 208: * assumed everything newer than SCSI-2 would not need it, but why risk
! 209: * it? This was the old conditional:
! 210: *
! 211: * if ((SCSISPC(sc_link->inqdata.version) <= 2))
! 212: */
! 213: xs->cmd->bytes[0] &= ~SCSI_CMD_LUN_MASK;
! 214: if (sc_link->lun < 8)
! 215: xs->cmd->bytes[0] |= ((sc_link->lun << SCSI_CMD_LUN_SHIFT) &
! 216: SCSI_CMD_LUN_MASK);
! 217:
! 218: return (xs);
! 219: }
! 220:
! 221: /*
! 222: * Find out from the device what its capacity is.
! 223: */
! 224: daddr64_t
! 225: scsi_size(struct scsi_link *sc_link, int flags, u_int32_t *blksize)
! 226: {
! 227: struct scsi_read_cap_data_16 rdcap16;
! 228: struct scsi_read_capacity_16 rc16;
! 229: struct scsi_read_cap_data rdcap;
! 230: struct scsi_read_capacity rc;
! 231: daddr64_t max_addr;
! 232: int error;
! 233:
! 234: if (blksize != NULL)
! 235: *blksize = 0;
! 236:
! 237: /*
! 238: * make up a scsi command and ask the scsi driver to do it for you.
! 239: */
! 240: bzero(&rc, sizeof(rc));
! 241: bzero(&rdcap, sizeof(rdcap));
! 242: rc.opcode = READ_CAPACITY;
! 243:
! 244: /*
! 245: * If the command works, interpret the result as a 4 byte
! 246: * number of blocks
! 247: */
! 248: error = scsi_scsi_cmd(sc_link, (struct scsi_generic *)&rc, sizeof(rc),
! 249: (u_char *)&rdcap, sizeof(rdcap), 2, 20000, NULL,
! 250: flags | SCSI_DATA_IN);
! 251: if (error) {
! 252: SC_DEBUG(sc_link, SDEV_DB1, ("READ CAPACITY error (%#x)\n",
! 253: error));
! 254: return (0);
! 255: }
! 256:
! 257: max_addr = _4btol(rdcap.addr);
! 258: if (blksize != NULL)
! 259: *blksize = _4btol(rdcap.length);
! 260:
! 261: if (max_addr != 0xffffffff)
! 262: return (max_addr + 1);
! 263:
! 264: /*
! 265: * The device has more than 2^32-1 sectors. Use 16-byte READ CAPACITY.
! 266: */
! 267: bzero(&rc16, sizeof(rc16));
! 268: bzero(&rdcap16, sizeof(rdcap16));
! 269: rc16.opcode = READ_CAPACITY_16;
! 270: rc16.byte2 = SRC16_SERVICE_ACTION;
! 271: _lto4b(sizeof(rdcap16), rc16.length);
! 272:
! 273: error = scsi_scsi_cmd(sc_link, (struct scsi_generic *)&rc16,
! 274: sizeof(rc16), (u_char *)&rdcap16, sizeof(rdcap16), 2, 20000, NULL,
! 275: flags | SCSI_DATA_IN);
! 276: if (error) {
! 277: SC_DEBUG(sc_link, SDEV_DB1, ("READ CAPACITY 16 error (%#x)\n",
! 278: error));
! 279: return (0);
! 280: }
! 281:
! 282: max_addr = _8btol(rdcap16.addr);
! 283: if (blksize != NULL)
! 284: *blksize = _4btol(rdcap16.length);
! 285:
! 286: return (max_addr + 1);
! 287: }
! 288:
! 289: /*
! 290: * Get scsi driver to send a "are you ready?" command
! 291: */
! 292: int
! 293: scsi_test_unit_ready(struct scsi_link *sc_link, int retries, int flags)
! 294: {
! 295: struct scsi_test_unit_ready scsi_cmd;
! 296:
! 297: if (sc_link->quirks & ADEV_NOTUR)
! 298: return (0);
! 299:
! 300: bzero(&scsi_cmd, sizeof(scsi_cmd));
! 301: scsi_cmd.opcode = TEST_UNIT_READY;
! 302:
! 303: return (scsi_scsi_cmd(sc_link, (struct scsi_generic *) &scsi_cmd,
! 304: sizeof(scsi_cmd), 0, 0, retries, 10000, NULL, flags));
! 305: }
! 306:
! 307: /*
! 308: * Do a scsi operation asking a device what it is.
! 309: * Use the scsi_cmd routine in the switch table.
! 310: */
! 311: int
! 312: scsi_inquire(struct scsi_link *sc_link, struct scsi_inquiry_data *inqbuf,
! 313: int flags)
! 314: {
! 315: struct scsi_inquiry scsi_cmd;
! 316: int length;
! 317: int error;
! 318:
! 319: bzero(&scsi_cmd, sizeof(scsi_cmd));
! 320: scsi_cmd.opcode = INQUIRY;
! 321:
! 322: bzero(inqbuf, sizeof(*inqbuf));
! 323:
! 324: memset(&inqbuf->vendor, ' ', sizeof inqbuf->vendor);
! 325: memset(&inqbuf->product, ' ', sizeof inqbuf->product);
! 326: memset(&inqbuf->revision, ' ', sizeof inqbuf->revision);
! 327: memset(&inqbuf->extra, ' ', sizeof inqbuf->extra);
! 328:
! 329: /*
! 330: * Ask for only the basic 36 bytes of SCSI2 inquiry information. This
! 331: * avoids problems with devices that choke trying to supply more.
! 332: */
! 333: length = SID_INQUIRY_HDR + SID_SCSI2_ALEN;
! 334: _lto2b(length, scsi_cmd.length);
! 335: error = scsi_scsi_cmd(sc_link, (struct scsi_generic *)&scsi_cmd,
! 336: sizeof(scsi_cmd), (u_char *)inqbuf, length, 2, 10000, NULL,
! 337: SCSI_DATA_IN | flags);
! 338:
! 339: return (error);
! 340: }
! 341:
! 342: /*
! 343: * Query a VPD inquiry page
! 344: */
! 345: int
! 346: scsi_inquire_vpd(struct scsi_link *sc_link, void *buf, u_int buflen,
! 347: u_int8_t page, int flags)
! 348: {
! 349: struct scsi_inquiry scsi_cmd;
! 350: int error;
! 351:
! 352: bzero(&scsi_cmd, sizeof(scsi_cmd));
! 353: scsi_cmd.opcode = INQUIRY;
! 354: scsi_cmd.flags = SI_EVPD;
! 355: scsi_cmd.pagecode = page;
! 356: _lto2b(buflen, scsi_cmd.length);
! 357:
! 358: bzero(buf, buflen);
! 359:
! 360: error = scsi_scsi_cmd(sc_link, (struct scsi_generic *)&scsi_cmd,
! 361: sizeof(scsi_cmd), buf, buflen, 2, 10000, NULL,
! 362: SCSI_DATA_IN | flags);
! 363:
! 364: return (error);
! 365: }
! 366:
! 367: /*
! 368: * Prevent or allow the user to remove the media
! 369: */
! 370: int
! 371: scsi_prevent(struct scsi_link *sc_link, int type, int flags)
! 372: {
! 373: struct scsi_prevent scsi_cmd;
! 374:
! 375: if (sc_link->quirks & ADEV_NODOORLOCK)
! 376: return (0);
! 377:
! 378: bzero(&scsi_cmd, sizeof(scsi_cmd));
! 379: scsi_cmd.opcode = PREVENT_ALLOW;
! 380: scsi_cmd.how = type;
! 381:
! 382: return (scsi_scsi_cmd(sc_link, (struct scsi_generic *)&scsi_cmd,
! 383: sizeof(scsi_cmd), 0, 0, 2, 5000, NULL, flags));
! 384: }
! 385:
! 386: /*
! 387: * Get scsi driver to send a "start up" command
! 388: */
! 389: int
! 390: scsi_start(struct scsi_link *sc_link, int type, int flags)
! 391: {
! 392: struct scsi_start_stop scsi_cmd;
! 393:
! 394: bzero(&scsi_cmd, sizeof(scsi_cmd));
! 395: scsi_cmd.opcode = START_STOP;
! 396: scsi_cmd.byte2 = 0x00;
! 397: scsi_cmd.how = type;
! 398:
! 399: return (scsi_scsi_cmd(sc_link, (struct scsi_generic *)&scsi_cmd,
! 400: sizeof(scsi_cmd), 0, 0, 2,
! 401: type == SSS_START ? 30000 : 10000, NULL, flags));
! 402: }
! 403:
! 404: int
! 405: scsi_mode_sense(struct scsi_link *sc_link, int byte2, int page,
! 406: struct scsi_mode_header *data, size_t len, int flags, int timeout)
! 407: {
! 408: struct scsi_mode_sense scsi_cmd;
! 409: int error;
! 410:
! 411: /*
! 412: * Make sure the sense buffer is clean before we do the mode sense, so
! 413: * that checks for bogus values of 0 will work in case the mode sense
! 414: * fails.
! 415: */
! 416: bzero(data, len);
! 417:
! 418: bzero(&scsi_cmd, sizeof(scsi_cmd));
! 419: scsi_cmd.opcode = MODE_SENSE;
! 420: scsi_cmd.byte2 = byte2;
! 421: scsi_cmd.page = page;
! 422:
! 423: if (len > 0xff)
! 424: len = 0xff;
! 425: scsi_cmd.length = len;
! 426:
! 427: error = scsi_scsi_cmd(sc_link, (struct scsi_generic *)&scsi_cmd,
! 428: sizeof(scsi_cmd), (u_char *)data, len, 4, timeout, NULL,
! 429: flags | SCSI_DATA_IN);
! 430:
! 431: SC_DEBUG(sc_link, SDEV_DB2, ("scsi_mode_sense: page %#x, error = %d\n",
! 432: page, error));
! 433:
! 434: return (error);
! 435: }
! 436:
! 437: int
! 438: scsi_mode_sense_big(struct scsi_link *sc_link, int byte2, int page,
! 439: struct scsi_mode_header_big *data, size_t len, int flags, int timeout)
! 440: {
! 441: struct scsi_mode_sense_big scsi_cmd;
! 442: int error;
! 443:
! 444: /*
! 445: * Make sure the sense buffer is clean before we do the mode sense, so
! 446: * that checks for bogus values of 0 will work in case the mode sense
! 447: * fails.
! 448: */
! 449: bzero(data, len);
! 450:
! 451: bzero(&scsi_cmd, sizeof(scsi_cmd));
! 452: scsi_cmd.opcode = MODE_SENSE_BIG;
! 453: scsi_cmd.byte2 = byte2;
! 454: scsi_cmd.page = page;
! 455:
! 456: if (len > 0xffff)
! 457: len = 0xffff;
! 458: _lto2b(len, scsi_cmd.length);
! 459:
! 460: error = scsi_scsi_cmd(sc_link, (struct scsi_generic *)&scsi_cmd,
! 461: sizeof(scsi_cmd), (u_char *)data, len, 4, timeout, NULL,
! 462: flags | SCSI_DATA_IN);
! 463:
! 464: SC_DEBUG(sc_link, SDEV_DB2,
! 465: ("scsi_mode_sense_big: page %#x, error = %d\n", page, error));
! 466:
! 467: return (error);
! 468: }
! 469:
! 470: void *
! 471: scsi_mode_sense_page(struct scsi_mode_header *hdr, const int page_len)
! 472: {
! 473: int total_length, header_length;
! 474:
! 475: total_length = hdr->data_length + sizeof(hdr->data_length);
! 476: header_length = sizeof(*hdr) + hdr->blk_desc_len;
! 477:
! 478: if ((total_length - header_length) < page_len)
! 479: return (NULL);
! 480:
! 481: return ((u_char *)hdr + header_length);
! 482: }
! 483:
! 484: void *
! 485: scsi_mode_sense_big_page(struct scsi_mode_header_big *hdr, const int page_len)
! 486: {
! 487: int total_length, header_length;
! 488:
! 489: total_length = _2btol(hdr->data_length) + sizeof(hdr->data_length);
! 490: header_length = sizeof(*hdr) + _2btol(hdr->blk_desc_len);
! 491:
! 492: if ((total_length - header_length) < page_len)
! 493: return (NULL);
! 494:
! 495: return ((u_char *)hdr + header_length);
! 496: }
! 497:
! 498: int
! 499: scsi_do_mode_sense(struct scsi_link *sc_link, int page,
! 500: union scsi_mode_sense_buf *buf, void **page_data, u_int32_t *density,
! 501: u_int64_t *block_count, u_int32_t *block_size, int page_len, int flags,
! 502: int *big)
! 503: {
! 504: struct scsi_direct_blk_desc *direct;
! 505: struct scsi_blk_desc *general;
! 506: int error, blk_desc_len, offset;
! 507:
! 508: *page_data = NULL;
! 509:
! 510: if (density != NULL)
! 511: *density = 0;
! 512: if (block_count != NULL)
! 513: *block_count = 0;
! 514: if (block_size != NULL)
! 515: *block_size = 0;
! 516: if (big != NULL)
! 517: *big = 0;
! 518:
! 519: if ((sc_link->flags & SDEV_ATAPI) == 0 ||
! 520: (sc_link->inqdata.device & SID_TYPE) == T_SEQUENTIAL) {
! 521: /*
! 522: * Try 6 byte mode sense request first. Some devices don't
! 523: * distinguish between 6 and 10 byte MODE SENSE commands,
! 524: * returning 6 byte data for 10 byte requests. ATAPI tape
! 525: * drives use MODE SENSE (6) even though ATAPI uses 10 byte
! 526: * everything else. Don't bother with SMS_DBD. Check returned
! 527: * data length to ensure that at least a header (3 additional
! 528: * bytes) is returned.
! 529: */
! 530: error = scsi_mode_sense(sc_link, 0, page, &buf->hdr,
! 531: sizeof(*buf), flags, 20000);
! 532: if (error == 0) {
! 533: *page_data = scsi_mode_sense_page(&buf->hdr, page_len);
! 534: if (*page_data == NULL) {
! 535: /*
! 536: * XXX
! 537: * Page data may be invalid (e.g. all zeros)
! 538: * but we accept the device's word that this is
! 539: * the best it can do. Some devices will freak
! 540: * out if their word is not accepted and
! 541: * MODE_SENSE_BIG is attempted.
! 542: */
! 543: return (0);
! 544: }
! 545: offset = sizeof(struct scsi_mode_header);
! 546: blk_desc_len = buf->hdr.blk_desc_len;
! 547: goto blk_desc;
! 548: }
! 549: }
! 550:
! 551: /*
! 552: * Try 10 byte mode sense request. Don't bother with SMS_DBD or
! 553: * SMS_LLBAA. Bail out if the returned information is less than
! 554: * a big header in size (6 additional bytes).
! 555: */
! 556: error = scsi_mode_sense_big(sc_link, 0, page, &buf->hdr_big,
! 557: sizeof(*buf), flags, 20000);
! 558: if (error != 0)
! 559: return (error);
! 560: if (_2btol(buf->hdr_big.data_length) < 6)
! 561: return (EIO);
! 562:
! 563: if (big != NULL)
! 564: *big = 1;
! 565: offset = sizeof(struct scsi_mode_header_big);
! 566: *page_data = scsi_mode_sense_big_page(&buf->hdr_big, page_len);
! 567: blk_desc_len = _2btol(buf->hdr_big.blk_desc_len);
! 568:
! 569: blk_desc:
! 570: /* Both scsi_blk_desc and scsi_direct_blk_desc are 8 bytes. */
! 571: if (blk_desc_len == 0 || (blk_desc_len % 8 != 0))
! 572: return (0);
! 573:
! 574: switch (sc_link->inqdata.device & SID_TYPE) {
! 575: case T_SEQUENTIAL:
! 576: /*
! 577: * XXX What other device types return general block descriptors?
! 578: */
! 579: general = (struct scsi_blk_desc *)&buf->buf[offset];
! 580: if (density != NULL)
! 581: *density = general->density;
! 582: if (block_size != NULL)
! 583: *block_size = _3btol(general->blklen);
! 584: if (block_count != NULL)
! 585: *block_count = (u_int64_t)_3btol(general->nblocks);
! 586: break;
! 587:
! 588: default:
! 589: direct = (struct scsi_direct_blk_desc *)&buf->buf[offset];
! 590: if (density != NULL)
! 591: *density = direct->density;
! 592: if (block_size != NULL)
! 593: *block_size = _3btol(direct->blklen);
! 594: if (block_count != NULL)
! 595: *block_count = (u_int64_t)_4btol(direct->nblocks);
! 596: break;
! 597: }
! 598:
! 599: return (0);
! 600: }
! 601:
! 602: int
! 603: scsi_mode_select(struct scsi_link *sc_link, int byte2,
! 604: struct scsi_mode_header *data, int flags, int timeout)
! 605: {
! 606: struct scsi_mode_select scsi_cmd;
! 607: int error;
! 608:
! 609: bzero(&scsi_cmd, sizeof(scsi_cmd));
! 610: scsi_cmd.opcode = MODE_SELECT;
! 611: scsi_cmd.byte2 = byte2;
! 612: scsi_cmd.length = data->data_length + 1; /* 1 == sizeof(data_length) */
! 613:
! 614: /* Length is reserved when doing mode select so zero it. */
! 615: data->data_length = 0;
! 616:
! 617: error = scsi_scsi_cmd(sc_link, (struct scsi_generic *)&scsi_cmd,
! 618: sizeof(scsi_cmd), (u_char *)data, scsi_cmd.length, 4, timeout, NULL,
! 619: flags | SCSI_DATA_OUT);
! 620:
! 621: SC_DEBUG(sc_link, SDEV_DB2, ("scsi_mode_select: error = %d\n", error));
! 622:
! 623: return (error);
! 624: }
! 625:
! 626: int
! 627: scsi_mode_select_big(struct scsi_link *sc_link, int byte2,
! 628: struct scsi_mode_header_big *data, int flags, int timeout)
! 629: {
! 630: struct scsi_mode_select_big scsi_cmd;
! 631: u_int32_t len;
! 632: int error;
! 633:
! 634: len = _2btol(data->data_length) + 2; /* 2 == sizeof data->data_length */
! 635:
! 636: bzero(&scsi_cmd, sizeof(scsi_cmd));
! 637: scsi_cmd.opcode = MODE_SELECT_BIG;
! 638: scsi_cmd.byte2 = byte2;
! 639: _lto2b(len, scsi_cmd.length);
! 640:
! 641: /* Length is reserved when doing mode select so zero it. */
! 642: _lto2b(0, data->data_length);
! 643:
! 644: error = scsi_scsi_cmd(sc_link, (struct scsi_generic *)&scsi_cmd,
! 645: sizeof(scsi_cmd), (u_char *)data, len, 4, timeout, NULL,
! 646: flags | SCSI_DATA_OUT);
! 647:
! 648: SC_DEBUG(sc_link, SDEV_DB2, ("scsi_mode_select_big: error = %d\n",
! 649: error));
! 650:
! 651: return (error);
! 652: }
! 653:
! 654: int
! 655: scsi_report_luns(struct scsi_link *sc_link, int selectreport,
! 656: struct scsi_report_luns_data *data, u_int32_t datalen, int flags,
! 657: int timeout)
! 658: {
! 659: struct scsi_report_luns scsi_cmd;
! 660: int error;
! 661:
! 662: bzero(&scsi_cmd, sizeof(scsi_cmd));
! 663: bzero(data, datalen);
! 664:
! 665: scsi_cmd.opcode = REPORT_LUNS;
! 666: scsi_cmd.selectreport = selectreport;
! 667: _lto4b(datalen, scsi_cmd.length);
! 668:
! 669: error = scsi_scsi_cmd(sc_link, (struct scsi_generic *)&scsi_cmd,
! 670: sizeof(scsi_cmd), (u_char *)data, datalen, 4, timeout, NULL,
! 671: flags | SCSI_DATA_IN);
! 672:
! 673: SC_DEBUG(sc_link, SDEV_DB2, ("scsi_report_luns: error = %d\n", error));
! 674:
! 675: return (error);
! 676: }
! 677:
! 678: /*
! 679: * This routine is called by the scsi interrupt when the transfer is complete.
! 680: */
! 681: void
! 682: scsi_done(struct scsi_xfer *xs)
! 683: {
! 684: struct scsi_link *sc_link = xs->sc_link;
! 685: struct buf *bp;
! 686: int error;
! 687:
! 688: splassert(IPL_BIO);
! 689:
! 690: SC_DEBUG(sc_link, SDEV_DB2, ("scsi_done\n"));
! 691: #ifdef SCSIDEBUG
! 692: if ((sc_link->flags & SDEV_DB1) != 0)
! 693: show_scsi_cmd(xs);
! 694: #endif /* SCSIDEBUG */
! 695:
! 696: /*
! 697: * If it's a user level request, bypass all usual completion processing,
! 698: * let the user work it out.. We take reponsibility for freeing the
! 699: * xs when the user returns (and restarting the device's queue).
! 700: */
! 701: if ((xs->flags & SCSI_USER) != 0) {
! 702: SC_DEBUG(sc_link, SDEV_DB3, ("calling user done()\n"));
! 703: scsi_user_done(xs); /* to take a copy of the sense etc. */
! 704: SC_DEBUG(sc_link, SDEV_DB3, ("returned from user done()\n"));
! 705:
! 706: scsi_free_xs(xs, 1); /* restarts queue too */
! 707: SC_DEBUG(sc_link, SDEV_DB3, ("returning to adapter\n"));
! 708: return;
! 709: }
! 710:
! 711: if (!((xs->flags & (SCSI_NOSLEEP | SCSI_POLL)) == SCSI_NOSLEEP)) {
! 712: /*
! 713: * if it's a normal upper level request, then ask
! 714: * the upper level code to handle error checking
! 715: * rather than doing it here at interrupt time
! 716: */
! 717: wakeup(xs);
! 718: return;
! 719: }
! 720:
! 721: /*
! 722: * Go and handle errors now.
! 723: * If it returns ERESTART then we should RETRY
! 724: */
! 725: retry:
! 726: error = sc_err1(xs);
! 727: if (error == ERESTART) {
! 728: switch ((*(sc_link->adapter->scsi_cmd)) (xs)) {
! 729: case SUCCESSFULLY_QUEUED:
! 730: return;
! 731:
! 732: case TRY_AGAIN_LATER:
! 733: xs->error = XS_BUSY;
! 734: /* FALLTHROUGH */
! 735: case COMPLETE:
! 736: goto retry;
! 737: }
! 738: }
! 739:
! 740: bp = xs->bp;
! 741: if (bp != NULL) {
! 742: if (error) {
! 743: bp->b_error = error;
! 744: bp->b_flags |= B_ERROR;
! 745: bp->b_resid = bp->b_bcount;
! 746: } else {
! 747: bp->b_error = 0;
! 748: bp->b_resid = xs->resid;
! 749: }
! 750: }
! 751:
! 752: if (sc_link->device->done) {
! 753: /*
! 754: * Tell the device the operation is actually complete.
! 755: * No more will happen with this xfer. This for
! 756: * notification of the upper-level driver only; they
! 757: * won't be returning any meaningful information to us.
! 758: */
! 759: (*sc_link->device->done)(xs);
! 760: }
! 761: scsi_free_xs(xs, 1);
! 762: if (bp != NULL)
! 763: biodone(bp);
! 764: }
! 765:
! 766: int
! 767: scsi_execute_xs(struct scsi_xfer *xs)
! 768: {
! 769: int error, flags, rslt, s;
! 770:
! 771: xs->flags &= ~ITSDONE;
! 772: xs->error = XS_NOERROR;
! 773: xs->resid = xs->datalen;
! 774: xs->status = 0;
! 775:
! 776: /*
! 777: * Do the transfer. If we are polling we will return:
! 778: * COMPLETE, Was poll, and scsi_done has been called
! 779: * TRY_AGAIN_LATER, Adapter short resources, try again
! 780: *
! 781: * if under full steam (interrupts) it will return:
! 782: * SUCCESSFULLY_QUEUED, will do a wakeup when complete
! 783: * TRY_AGAIN_LATER, (as for polling)
! 784: * After the wakeup, we must still check if it succeeded
! 785: *
! 786: * If we have a SCSI_NOSLEEP (typically because we have a buf)
! 787: * we just return. All the error processing and the buffer
! 788: * code both expect us to return straight to them, so as soon
! 789: * as the command is queued, return.
! 790: */
! 791:
! 792: /*
! 793: * We save the flags here because the xs structure may already
! 794: * be freed by scsi_done by the time adapter->scsi_cmd returns.
! 795: *
! 796: * scsi_done is responsible for freeing the xs if either
! 797: * (flags & (SCSI_NOSLEEP | SCSI_POLL)) == SCSI_NOSLEEP
! 798: * -or-
! 799: * (flags & SCSI_USER) != 0
! 800: *
! 801: * Note: SCSI_USER must always be called with SCSI_NOSLEEP
! 802: * and never with SCSI_POLL, so the second expression should be
! 803: * is equivalent to the first.
! 804: */
! 805:
! 806: flags = xs->flags;
! 807: #ifdef DIAGNOSTIC
! 808: if ((flags & (SCSI_USER | SCSI_NOSLEEP)) == SCSI_USER)
! 809: panic("scsi_execute_xs: USER without NOSLEEP");
! 810: if ((flags & (SCSI_USER | SCSI_POLL)) == (SCSI_USER | SCSI_POLL))
! 811: panic("scsi_execute_xs: USER with POLL");
! 812: #endif
! 813: retry:
! 814: rslt = (*(xs->sc_link->adapter->scsi_cmd))(xs);
! 815: switch (rslt) {
! 816: case SUCCESSFULLY_QUEUED:
! 817: if ((flags & (SCSI_NOSLEEP | SCSI_POLL)) == SCSI_NOSLEEP)
! 818: return (EJUSTRETURN);
! 819: #ifdef DIAGNOSTIC
! 820: if (flags & SCSI_NOSLEEP)
! 821: panic("scsi_execute_xs: NOSLEEP and POLL");
! 822: #endif
! 823: s = splbio();
! 824: /* Since the xs is active we can't bail out on a signal. */
! 825: while ((xs->flags & ITSDONE) == 0)
! 826: tsleep(xs, PRIBIO + 1, "scsicmd", 0);
! 827: splx(s);
! 828: /* FALLTHROUGH */
! 829: case COMPLETE: /* Polling command completed ok */
! 830: if ((flags & (SCSI_NOSLEEP | SCSI_POLL)) == SCSI_NOSLEEP)
! 831: return (EJUSTRETURN);
! 832: if (xs->bp)
! 833: return (EJUSTRETURN);
! 834: doit:
! 835: SC_DEBUG(xs->sc_link, SDEV_DB3, ("back in cmd()\n"));
! 836: if ((error = sc_err1(xs)) != ERESTART)
! 837: return (error);
! 838: goto retry;
! 839:
! 840: case TRY_AGAIN_LATER: /* adapter resource shortage */
! 841: xs->error = XS_BUSY;
! 842: goto doit;
! 843:
! 844: case NO_CCB:
! 845: return (EAGAIN);
! 846:
! 847: default:
! 848: panic("scsi_execute_xs: invalid return code (%#x)", rslt);
! 849: }
! 850:
! 851: #ifdef DIAGNOSTIC
! 852: panic("scsi_execute_xs: impossible");
! 853: #endif
! 854: return (EINVAL);
! 855: }
! 856:
! 857: /*
! 858: * ask the scsi driver to perform a command for us.
! 859: * tell it where to read/write the data, and how
! 860: * long the data is supposed to be. If we have a buf
! 861: * to associate with the transfer, we need that too.
! 862: */
! 863: int
! 864: scsi_scsi_cmd(struct scsi_link *sc_link, struct scsi_generic *scsi_cmd,
! 865: int cmdlen, u_char *data_addr, int datalen, int retries, int timeout,
! 866: struct buf *bp, int flags)
! 867: {
! 868: struct scsi_xfer *xs;
! 869: int error;
! 870: int s;
! 871:
! 872: SC_DEBUG(sc_link, SDEV_DB2, ("scsi_cmd\n"));
! 873:
! 874: #ifdef DIAGNOSTIC
! 875: if (bp != NULL && (flags & SCSI_NOSLEEP) == 0)
! 876: panic("scsi_scsi_cmd: buffer without nosleep");
! 877: #endif
! 878:
! 879: if ((xs = scsi_make_xs(sc_link, scsi_cmd, cmdlen, data_addr, datalen,
! 880: retries, timeout, bp, flags)) == NULL)
! 881: return (ENOMEM);
! 882:
! 883: if ((error = scsi_execute_xs(xs)) == EJUSTRETURN)
! 884: return (0);
! 885:
! 886: s = splbio();
! 887:
! 888: if (error == EAGAIN)
! 889: scsi_free_xs(xs, 0); /* Don't restart queue. */
! 890: else
! 891: scsi_free_xs(xs, 1);
! 892:
! 893: splx(s);
! 894:
! 895: return (error);
! 896: }
! 897:
! 898: int
! 899: sc_err1(struct scsi_xfer *xs)
! 900: {
! 901: int error;
! 902:
! 903: SC_DEBUG(xs->sc_link, SDEV_DB3, ("sc_err1,err = 0x%x\n", xs->error));
! 904:
! 905: /*
! 906: * If it has a buf, we might be working with
! 907: * a request from the buffer cache or some other
! 908: * piece of code that requires us to process
! 909: * errors at interrupt time. We have probably
! 910: * been called by scsi_done()
! 911: */
! 912: switch (xs->error) {
! 913: case XS_NOERROR: /* nearly always hit this one */
! 914: error = 0;
! 915: break;
! 916:
! 917: case XS_SENSE:
! 918: case XS_SHORTSENSE:
! 919: if ((error = scsi_interpret_sense(xs)) == ERESTART)
! 920: goto retry;
! 921: SC_DEBUG(xs->sc_link, SDEV_DB3,
! 922: ("scsi_interpret_sense returned %#x\n", error));
! 923: break;
! 924:
! 925: case XS_BUSY:
! 926: if (xs->retries) {
! 927: if ((error = scsi_delay(xs, 1)) == EIO)
! 928: goto lose;
! 929: }
! 930: /* FALLTHROUGH */
! 931: case XS_TIMEOUT:
! 932: retry:
! 933: if (xs->retries--) {
! 934: xs->error = XS_NOERROR;
! 935: xs->flags &= ~ITSDONE;
! 936: return ERESTART;
! 937: }
! 938: /* FALLTHROUGH */
! 939: case XS_DRIVER_STUFFUP:
! 940: lose:
! 941: error = EIO;
! 942: break;
! 943:
! 944: case XS_SELTIMEOUT:
! 945: /* XXX Disable device? */
! 946: error = EIO;
! 947: break;
! 948:
! 949: case XS_RESET:
! 950: if (xs->retries) {
! 951: SC_DEBUG(xs->sc_link, SDEV_DB3,
! 952: ("restarting command destroyed by reset\n"));
! 953: goto retry;
! 954: }
! 955: error = EIO;
! 956: break;
! 957:
! 958: default:
! 959: sc_print_addr(xs->sc_link);
! 960: printf("unknown error category (0x%x) from scsi driver\n",
! 961: xs->error);
! 962: error = EIO;
! 963: break;
! 964: }
! 965:
! 966: return (error);
! 967: }
! 968:
! 969: int
! 970: scsi_delay(struct scsi_xfer *xs, int seconds)
! 971: {
! 972: switch (xs->flags & (SCSI_POLL | SCSI_NOSLEEP)) {
! 973: case SCSI_POLL:
! 974: delay(1000000 * seconds);
! 975: return (ERESTART);
! 976: case SCSI_NOSLEEP:
! 977: /* Retry the command immediately since we can't delay. */
! 978: return (ERESTART);
! 979: case (SCSI_POLL | SCSI_NOSLEEP):
! 980: /* Invalid combination! */
! 981: return (EIO);
! 982: }
! 983:
! 984: while (seconds-- > 0) {
! 985: if (tsleep(&lbolt, PRIBIO|PCATCH, "scbusy", 0)) {
! 986: /* Signal == abort xs. */
! 987: return (EIO);
! 988: }
! 989: }
! 990:
! 991: return (ERESTART);
! 992: }
! 993:
! 994: /*
! 995: * Look at the returned sense and act on the error, determining
! 996: * the unix error number to pass back. (0 = report no error)
! 997: *
! 998: * THIS IS THE DEFAULT ERROR HANDLER
! 999: */
! 1000: int
! 1001: scsi_interpret_sense(struct scsi_xfer *xs)
! 1002: {
! 1003: struct scsi_sense_data *sense = &xs->sense;
! 1004: struct scsi_link *sc_link = xs->sc_link;
! 1005: u_int8_t serr, skey;
! 1006: int error;
! 1007:
! 1008: SC_DEBUG(sc_link, SDEV_DB1,
! 1009: ("code:%#x valid:%d key:%#x ili:%d eom:%d fmark:%d extra:%d\n",
! 1010: sense->error_code & SSD_ERRCODE,
! 1011: sense->error_code & SSD_ERRCODE_VALID ? 1 : 0,
! 1012: sense->flags & SSD_KEY,
! 1013: sense->flags & SSD_ILI ? 1 : 0,
! 1014: sense->flags & SSD_EOM ? 1 : 0,
! 1015: sense->flags & SSD_FILEMARK ? 1 : 0,
! 1016: sense->extra_len));
! 1017: #ifdef SCSIDEBUG
! 1018: if ((sc_link->flags & SDEV_DB1) != 0)
! 1019: show_mem((u_char *)&xs->sense, sizeof xs->sense);
! 1020: #endif /* SCSIDEBUG */
! 1021:
! 1022: /*
! 1023: * If the device has its own error handler, call it first.
! 1024: * If it returns a legit error value, return that, otherwise
! 1025: * it wants us to continue with normal error processing.
! 1026: */
! 1027: if (sc_link->device->err_handler) {
! 1028: SC_DEBUG(sc_link, SDEV_DB2,
! 1029: ("calling private err_handler()\n"));
! 1030: error = (*sc_link->device->err_handler) (xs);
! 1031: if (error != EJUSTRETURN)
! 1032: return (error); /* error >= 0 better ? */
! 1033: }
! 1034:
! 1035: /* Default sense interpretation. */
! 1036: serr = sense->error_code & SSD_ERRCODE;
! 1037: if (serr != SSD_ERRCODE_CURRENT && serr != SSD_ERRCODE_DEFERRED)
! 1038: skey = 0xff; /* Invalid value, since key is 4 bit value. */
! 1039: else
! 1040: skey = sense->flags & SSD_KEY;
! 1041:
! 1042: /*
! 1043: * Interpret the key/asc/ascq information where appropriate.
! 1044: */
! 1045: error = 0;
! 1046: switch (skey) {
! 1047: case SKEY_NO_SENSE:
! 1048: case SKEY_RECOVERED_ERROR:
! 1049: if (xs->resid == xs->datalen)
! 1050: xs->resid = 0; /* not short read */
! 1051: break;
! 1052: case SKEY_BLANK_CHECK:
! 1053: case SKEY_EQUAL:
! 1054: break;
! 1055: case SKEY_NOT_READY:
! 1056: if ((xs->flags & SCSI_IGNORE_NOT_READY) != 0)
! 1057: return (0);
! 1058: error = EIO;
! 1059: if (xs->retries) {
! 1060: switch (ASC_ASCQ(sense)) {
! 1061: case SENSE_NOT_READY_BECOMING_READY:
! 1062: case SENSE_NOT_READY_FORMAT:
! 1063: case SENSE_NOT_READY_REBUILD:
! 1064: case SENSE_NOT_READY_RECALC:
! 1065: case SENSE_NOT_READY_INPROGRESS:
! 1066: case SENSE_NOT_READY_LONGWRITE:
! 1067: case SENSE_NOT_READY_SELFTEST:
! 1068: SC_DEBUG(sc_link, SDEV_DB1,
! 1069: ("not ready: busy (%#x)\n",
! 1070: sense->add_sense_code_qual));
! 1071: return (scsi_delay(xs, 1));
! 1072: case SENSE_NOMEDIUM:
! 1073: case SENSE_NOMEDIUM_TCLOSED:
! 1074: case SENSE_NOMEDIUM_TOPEN:
! 1075: case SENSE_NOMEDIUM_LOADABLE:
! 1076: case SENSE_NOMEDIUM_AUXMEM:
! 1077: sc_link->flags &= ~SDEV_MEDIA_LOADED;
! 1078: error = ENOMEDIUM;
! 1079: break;
! 1080: default:
! 1081: break;
! 1082: }
! 1083: }
! 1084: break;
! 1085: case SKEY_MEDIUM_ERROR:
! 1086: switch (ASC_ASCQ(sense)) {
! 1087: case SENSE_NOMEDIUM:
! 1088: case SENSE_NOMEDIUM_TCLOSED:
! 1089: case SENSE_NOMEDIUM_TOPEN:
! 1090: case SENSE_NOMEDIUM_LOADABLE:
! 1091: case SENSE_NOMEDIUM_AUXMEM:
! 1092: sc_link->flags &= ~SDEV_MEDIA_LOADED;
! 1093: error = ENOMEDIUM;
! 1094: break;
! 1095: case SENSE_BAD_MEDIUM:
! 1096: case SENSE_NR_MEDIUM_UNKNOWN_FORMAT:
! 1097: case SENSE_NR_MEDIUM_INCOMPATIBLE_FORMAT:
! 1098: case SENSE_NW_MEDIUM_UNKNOWN_FORMAT:
! 1099: case SENSE_NW_MEDIUM_INCOMPATIBLE_FORMAT:
! 1100: case SENSE_NF_MEDIUM_INCOMPATIBLE_FORMAT:
! 1101: case SENSE_NW_MEDIUM_AC_MISMATCH:
! 1102: error = EMEDIUMTYPE;
! 1103: break;
! 1104: default:
! 1105: error = EIO;
! 1106: break;
! 1107: }
! 1108: break;
! 1109: case SKEY_ILLEGAL_REQUEST:
! 1110: if ((xs->flags & SCSI_IGNORE_ILLEGAL_REQUEST) != 0)
! 1111: return (0);
! 1112: if (ASC_ASCQ(sense) == SENSE_MEDIUM_REMOVAL_PREVENTED)
! 1113: return(EBUSY);
! 1114: error = EINVAL;
! 1115: break;
! 1116: case SKEY_UNIT_ATTENTION:
! 1117: switch (ASC_ASCQ(sense)) {
! 1118: case SENSE_POWER_RESET_OR_BUS:
! 1119: case SENSE_POWER_ON:
! 1120: case SENSE_BUS_RESET:
! 1121: case SENSE_BUS_DEVICE_RESET:
! 1122: case SENSE_DEVICE_INTERNAL_RESET:
! 1123: case SENSE_TSC_CHANGE_SE:
! 1124: case SENSE_TSC_CHANGE_LVD:
! 1125: case SENSE_IT_NEXUS_LOSS:
! 1126: return (scsi_delay(xs, 1));
! 1127: default:
! 1128: break;
! 1129: }
! 1130: if ((sc_link->flags & SDEV_REMOVABLE) != 0)
! 1131: sc_link->flags &= ~SDEV_MEDIA_LOADED;
! 1132: if ((xs->flags & SCSI_IGNORE_MEDIA_CHANGE) != 0 ||
! 1133: /* XXX Should reupload any transient state. */
! 1134: (sc_link->flags & SDEV_REMOVABLE) == 0) {
! 1135: return (scsi_delay(xs, 1));
! 1136: }
! 1137: error = EIO;
! 1138: break;
! 1139: case SKEY_WRITE_PROTECT:
! 1140: error = EROFS;
! 1141: break;
! 1142: case SKEY_ABORTED_COMMAND:
! 1143: error = ERESTART;
! 1144: break;
! 1145: case SKEY_VOLUME_OVERFLOW:
! 1146: error = ENOSPC;
! 1147: break;
! 1148: case SKEY_HARDWARE_ERROR:
! 1149: if (ASC_ASCQ(sense) == SENSE_CARTRIDGE_FAULT)
! 1150: return(EMEDIUMTYPE);
! 1151: error = EIO;
! 1152: break;
! 1153: default:
! 1154: error = EIO;
! 1155: break;
! 1156: }
! 1157:
! 1158: if (skey && (xs->flags & SCSI_SILENT) == 0)
! 1159: scsi_print_sense(xs);
! 1160:
! 1161: return (error);
! 1162: }
! 1163:
! 1164: /*
! 1165: * Utility routines often used in SCSI stuff
! 1166: */
! 1167:
! 1168:
! 1169: /*
! 1170: * Print out the scsi_link structure's address info.
! 1171: */
! 1172: void
! 1173: sc_print_addr(struct scsi_link *sc_link)
! 1174: {
! 1175: printf("%s(%s:%d:%d): ",
! 1176: sc_link->device_softc ?
! 1177: ((struct device *)sc_link->device_softc)->dv_xname : "probe",
! 1178: ((struct device *)sc_link->adapter_softc)->dv_xname,
! 1179: sc_link->target, sc_link->lun);
! 1180: }
! 1181:
! 1182: static const char *sense_keys[16] = {
! 1183: "No Additional Sense",
! 1184: "Soft Error",
! 1185: "Not Ready",
! 1186: "Media Error",
! 1187: "Hardware Error",
! 1188: "Illegal Request",
! 1189: "Unit Attention",
! 1190: "Write Protected",
! 1191: "Blank Check",
! 1192: "Vendor Unique",
! 1193: "Copy Aborted",
! 1194: "Aborted Command",
! 1195: "Equal Error",
! 1196: "Volume Overflow",
! 1197: "Miscompare Error",
! 1198: "Reserved"
! 1199: };
! 1200:
! 1201: #ifdef SCSITERSE
! 1202: static __inline void
! 1203: asc2ascii(u_int8_t asc, u_int8_t ascq, char *result, size_t len)
! 1204: {
! 1205: snprintf(result, len, "ASC 0x%02x ASCQ 0x%02x", asc, ascq);
! 1206: }
! 1207: #else
! 1208: static const struct {
! 1209: u_int8_t asc, ascq;
! 1210: char *description;
! 1211: } adesc[] = {
! 1212: { 0x00, 0x00, "No Additional Sense Information" },
! 1213: { 0x00, 0x01, "Filemark Detected" },
! 1214: { 0x00, 0x02, "End-Of-Partition/Medium Detected" },
! 1215: { 0x00, 0x03, "Setmark Detected" },
! 1216: { 0x00, 0x04, "Beginning-Of-Partition/Medium Detected" },
! 1217: { 0x00, 0x05, "End-Of-Data Detected" },
! 1218: { 0x00, 0x06, "I/O Process Terminated" },
! 1219: { 0x00, 0x11, "Audio Play Operation In Progress" },
! 1220: { 0x00, 0x12, "Audio Play Operation Paused" },
! 1221: { 0x00, 0x13, "Audio Play Operation Successfully Completed" },
! 1222: { 0x00, 0x14, "Audio Play Operation Stopped Due to Error" },
! 1223: { 0x00, 0x15, "No Current Audio Status To Return" },
! 1224: { 0x00, 0x16, "Operation In Progress" },
! 1225: { 0x00, 0x17, "Cleaning Requested" },
! 1226: { 0x00, 0x18, "Erase Operation In Progress" },
! 1227: { 0x00, 0x19, "Locate Operation In Progress" },
! 1228: { 0x00, 0x1A, "Rewind Operation In Progress" },
! 1229: { 0x00, 0x1B, "Set Capacity Operation In Progress" },
! 1230: { 0x00, 0x1C, "Verify Operation In Progress" },
! 1231: { 0x01, 0x00, "No Index/Sector Signal" },
! 1232: { 0x02, 0x00, "No Seek Complete" },
! 1233: { 0x03, 0x00, "Peripheral Device Write Fault" },
! 1234: { 0x03, 0x01, "No Write Current" },
! 1235: { 0x03, 0x02, "Excessive Write Errors" },
! 1236: { 0x04, 0x00, "Logical Unit Not Ready, Cause Not Reportable" },
! 1237: { 0x04, 0x01, "Logical Unit Is in Process Of Becoming Ready" },
! 1238: { 0x04, 0x02, "Logical Unit Not Ready, Initialization Command Required" },
! 1239: { 0x04, 0x03, "Logical Unit Not Ready, Manual Intervention Required" },
! 1240: { 0x04, 0x04, "Logical Unit Not Ready, Format In Progress" },
! 1241: { 0x04, 0x05, "Logical Unit Not Ready, Rebuild In Progress" },
! 1242: { 0x04, 0x06, "Logical Unit Not Ready, Recalculation In Progress" },
! 1243: { 0x04, 0x07, "Logical Unit Not Ready, Operation In Progress" },
! 1244: { 0x04, 0x08, "Logical Unit Not Ready, Long Write In Progress" },
! 1245: { 0x04, 0x09, "Logical Unit Not Ready, Self-Test In Progress" },
! 1246: { 0x04, 0x0A, "Logical Unit Not Accessible, Asymmetric Access State Transition" },
! 1247: { 0x04, 0x0B, "Logical Unit Not Accessible, Target Port In Standby State" },
! 1248: { 0x04, 0x0C, "Logical Unit Not Accessible, Target Port In Unavailable State" },
! 1249: { 0x04, 0x10, "Logical Unit Not Ready, Auxiliary Memory Not Accessible" },
! 1250: { 0x04, 0x11, "Logical Unit Not Ready, Notify (Enable Spinup) Required" },
! 1251: { 0x05, 0x00, "Logical Unit Does Not Respond To Selection" },
! 1252: { 0x06, 0x00, "No Reference Position Found" },
! 1253: { 0x07, 0x00, "Multiple Peripheral Devices Selected" },
! 1254: { 0x08, 0x00, "Logical Unit Communication Failure" },
! 1255: { 0x08, 0x01, "Logical Unit Communication Timeout" },
! 1256: { 0x08, 0x02, "Logical Unit Communication Parity Error" },
! 1257: { 0x08, 0x03, "Logical Unit Communication CRC Error (ULTRA-DMA/32)" },
! 1258: { 0x08, 0x04, "Unreachable Copy Target" },
! 1259: { 0x09, 0x00, "Track Following Error" },
! 1260: { 0x09, 0x01, "Tracking Servo Failure" },
! 1261: { 0x09, 0x02, "Focus Servo Failure" },
! 1262: { 0x09, 0x03, "Spindle Servo Failure" },
! 1263: { 0x09, 0x04, "Head Select Fault" },
! 1264: { 0x0A, 0x00, "Error Log Overflow" },
! 1265: { 0x0B, 0x00, "Warning" },
! 1266: { 0x0B, 0x01, "Warning - Specified Temperature Exceeded" },
! 1267: { 0x0B, 0x02, "Warning - Enclosure Degraded" },
! 1268: { 0x0C, 0x00, "Write Error" },
! 1269: { 0x0C, 0x01, "Write Error Recovered with Auto Reallocation" },
! 1270: { 0x0C, 0x02, "Write Error - Auto Reallocate Failed" },
! 1271: { 0x0C, 0x03, "Write Error - Recommend Reassignment" },
! 1272: { 0x0C, 0x04, "Compression Check Miscompare Error" },
! 1273: { 0x0C, 0x05, "Data Expansion Occurred During Compression" },
! 1274: { 0x0C, 0x06, "Block Not Compressible" },
! 1275: { 0x0C, 0x07, "Write Error - Recovery Needed" },
! 1276: { 0x0C, 0x08, "Write Error - Recovery Failed" },
! 1277: { 0x0C, 0x09, "Write Error - Loss Of Streaming" },
! 1278: { 0x0C, 0x0A, "Write Error - Padding Blocks Added" },
! 1279: { 0x0C, 0x0B, "Auxiliary Memory Write Error" },
! 1280: { 0x0C, 0x0C, "Write Error - Unexpected Unsolicited Data" },
! 1281: { 0x0C, 0x0D, "Write Error - Not Enough Unsolicited Data" },
! 1282: { 0x0D, 0x00, "Error Detected By Third Party Temporary Initiator" },
! 1283: { 0x0D, 0x01, "Third Party Device Failure" },
! 1284: { 0x0D, 0x02, "Copy Target Device Not Reachable" },
! 1285: { 0x0D, 0x03, "Incorrect Copy Target Device Type" },
! 1286: { 0x0D, 0x04, "Copy Target Device Data Underrun" },
! 1287: { 0x0D, 0x05, "Copy Target Device Data Overrun" },
! 1288: { 0x0E, 0x00, "Invalid Information Unit" },
! 1289: { 0x0E, 0x01, "Information Unit Too Short" },
! 1290: { 0x0E, 0x02, "Information Unit Too Long" },
! 1291: { 0x10, 0x00, "ID CRC Or ECC Error" },
! 1292: { 0x11, 0x00, "Unrecovered Read Error" },
! 1293: { 0x11, 0x01, "Read Retries Exhausted" },
! 1294: { 0x11, 0x02, "Error Too Long To Correct" },
! 1295: { 0x11, 0x03, "Multiple Read Errors" },
! 1296: { 0x11, 0x04, "Unrecovered Read Error - Auto Reallocate Failed" },
! 1297: { 0x11, 0x05, "L-EC Uncorrectable Error" },
! 1298: { 0x11, 0x06, "CIRC Unrecovered Error" },
! 1299: { 0x11, 0x07, "Data Resynchronization Error" },
! 1300: { 0x11, 0x08, "Incomplete Block Read" },
! 1301: { 0x11, 0x09, "No Gap Found" },
! 1302: { 0x11, 0x0A, "Miscorrected Error" },
! 1303: { 0x11, 0x0B, "Uncorrected Read Error - Recommend Reassignment" },
! 1304: { 0x11, 0x0C, "Uncorrected Read Error - Recommend Rewrite The Data" },
! 1305: { 0x11, 0x0D, "De-Compression CRC Error" },
! 1306: { 0x11, 0x0E, "Cannot Decompress Using Declared Algorithm" },
! 1307: { 0x11, 0x0F, "Error Reading UPC/EAN Number" },
! 1308: { 0x11, 0x10, "Error Reading ISRC Number" },
! 1309: { 0x11, 0x11, "Read Error - Loss Of Streaming" },
! 1310: { 0x11, 0x12, "Auxiliary Memory Read Error" },
! 1311: { 0x11, 0x13, "Read Error - Failed Retransmission Request" },
! 1312: { 0x12, 0x00, "Address Mark Not Found for ID Field" },
! 1313: { 0x13, 0x00, "Address Mark Not Found for Data Field" },
! 1314: { 0x14, 0x00, "Recorded Entity Not Found" },
! 1315: { 0x14, 0x01, "Record Not Found" },
! 1316: { 0x14, 0x02, "Filemark or Setmark Not Found" },
! 1317: { 0x14, 0x03, "End-Of-Data Not Found" },
! 1318: { 0x14, 0x04, "Block Sequence Error" },
! 1319: { 0x14, 0x05, "Record Not Found - Recommend Reassignment" },
! 1320: { 0x14, 0x06, "Record Not Found - Data Auto-Reallocated" },
! 1321: { 0x14, 0x07, "Locate Operation Failure" },
! 1322: { 0x15, 0x00, "Random Positioning Error" },
! 1323: { 0x15, 0x01, "Mechanical Positioning Error" },
! 1324: { 0x15, 0x02, "Positioning Error Detected By Read of Medium" },
! 1325: { 0x16, 0x00, "Data Synchronization Mark Error" },
! 1326: { 0x16, 0x01, "Data Sync Error - Data Rewritten" },
! 1327: { 0x16, 0x02, "Data Sync Error - Recommend Rewrite" },
! 1328: { 0x16, 0x03, "Data Sync Error - Data Auto-Reallocated" },
! 1329: { 0x16, 0x04, "Data Sync Error - Recommend Reassignment" },
! 1330: { 0x17, 0x00, "Recovered Data With No Error Correction Applied" },
! 1331: { 0x17, 0x01, "Recovered Data With Retries" },
! 1332: { 0x17, 0x02, "Recovered Data With Positive Head Offset" },
! 1333: { 0x17, 0x03, "Recovered Data With Negative Head Offset" },
! 1334: { 0x17, 0x04, "Recovered Data With Retries and/or CIRC Applied" },
! 1335: { 0x17, 0x05, "Recovered Data Using Previous Sector ID" },
! 1336: { 0x17, 0x06, "Recovered Data Without ECC - Data Auto-Reallocated" },
! 1337: { 0x17, 0x07, "Recovered Data Without ECC - Recommend Reassignment" },
! 1338: { 0x17, 0x08, "Recovered Data Without ECC - Recommend Rewrite" },
! 1339: { 0x17, 0x09, "Recovered Data Without ECC - Data Rewritten" },
! 1340: { 0x18, 0x00, "Recovered Data With Error Correction Applied" },
! 1341: { 0x18, 0x01, "Recovered Data With Error Correction & Retries Applied" },
! 1342: { 0x18, 0x02, "Recovered Data - Data Auto-Reallocated" },
! 1343: { 0x18, 0x03, "Recovered Data With CIRC" },
! 1344: { 0x18, 0x04, "Recovered Data With L-EC" },
! 1345: { 0x18, 0x05, "Recovered Data - Recommend Reassignment" },
! 1346: { 0x18, 0x06, "Recovered Data - Recommend Rewrite" },
! 1347: { 0x18, 0x07, "Recovered Data With ECC - Data Rewritten" },
! 1348: { 0x18, 0x08, "Recovered Data With Linking" },
! 1349: { 0x19, 0x00, "Defect List Error" },
! 1350: { 0x19, 0x01, "Defect List Not Available" },
! 1351: { 0x19, 0x02, "Defect List Error in Primary List" },
! 1352: { 0x19, 0x03, "Defect List Error in Grown List" },
! 1353: { 0x1A, 0x00, "Parameter List Length Error" },
! 1354: { 0x1B, 0x00, "Synchronous Data Transfer Error" },
! 1355: { 0x1C, 0x00, "Defect List Not Found" },
! 1356: { 0x1C, 0x01, "Primary Defect List Not Found" },
! 1357: { 0x1C, 0x02, "Grown Defect List Not Found" },
! 1358: { 0x1D, 0x00, "Miscompare During Verify Operation" },
! 1359: { 0x1E, 0x00, "Recovered ID with ECC" },
! 1360: { 0x1F, 0x00, "Partial Defect List Transfer" },
! 1361: { 0x20, 0x00, "Invalid Command Operation Code" },
! 1362: { 0x20, 0x01, "Access Denied - Initiator Pending-Enrolled" },
! 1363: { 0x20, 0x02, "Access Denied - No Access rights" },
! 1364: { 0x20, 0x03, "Access Denied - Invalid Mgmt ID Key" },
! 1365: { 0x20, 0x04, "Illegal Command While In Write Capable State" },
! 1366: { 0x20, 0x05, "Obsolete" },
! 1367: { 0x20, 0x06, "Illegal Command While In Explicit Address Mode" },
! 1368: { 0x20, 0x07, "Illegal Command While In Implicit Address Mode" },
! 1369: { 0x20, 0x08, "Access Denied - Enrollment Conflict" },
! 1370: { 0x20, 0x09, "Access Denied - Invalid LU Identifier" },
! 1371: { 0x20, 0x0A, "Access Denied - Invalid Proxy Token" },
! 1372: { 0x20, 0x0B, "Access Denied - ACL LUN Conflict" },
! 1373: { 0x21, 0x00, "Logical Block Address Out of Range" },
! 1374: { 0x21, 0x01, "Invalid Element Address" },
! 1375: { 0x21, 0x02, "Invalid Address For Write" },
! 1376: { 0x22, 0x00, "Illegal Function (Should 20 00, 24 00, or 26 00)" },
! 1377: { 0x24, 0x00, "Illegal Field in CDB" },
! 1378: { 0x24, 0x01, "CDB Decryption Error" },
! 1379: { 0x24, 0x02, "Obsolete" },
! 1380: { 0x24, 0x03, "Obsolete" },
! 1381: { 0x24, 0x04, "Security Audit Value Frozen" },
! 1382: { 0x24, 0x05, "Security Working Key Frozen" },
! 1383: { 0x24, 0x06, "Nonce Not Unique" },
! 1384: { 0x24, 0x07, "Nonce Timestamp Out Of Range" },
! 1385: { 0x25, 0x00, "Logical Unit Not Supported" },
! 1386: { 0x26, 0x00, "Invalid Field In Parameter List" },
! 1387: { 0x26, 0x01, "Parameter Not Supported" },
! 1388: { 0x26, 0x02, "Parameter Value Invalid" },
! 1389: { 0x26, 0x03, "Threshold Parameters Not Supported" },
! 1390: { 0x26, 0x04, "Invalid Release Of Persistent Reservation" },
! 1391: { 0x26, 0x05, "Data Decryption Error" },
! 1392: { 0x26, 0x06, "Too Many Target Descriptors" },
! 1393: { 0x26, 0x07, "Unsupported Target Descriptor Type Code" },
! 1394: { 0x26, 0x08, "Too Many Segment Descriptors" },
! 1395: { 0x26, 0x09, "Unsupported Segment Descriptor Type Code" },
! 1396: { 0x26, 0x0A, "Unexpected Inexact Segment" },
! 1397: { 0x26, 0x0B, "Inline Data Length Exceeded" },
! 1398: { 0x26, 0x0C, "Invalid Operation For Copy Source Or Destination" },
! 1399: { 0x26, 0x0D, "Copy Segment Granularity Violation" },
! 1400: { 0x26, 0x0E, "Invalid Parameter While Port Is Enabled" },
! 1401: { 0x27, 0x00, "Write Protected" },
! 1402: { 0x27, 0x01, "Hardware Write Protected" },
! 1403: { 0x27, 0x02, "Logical Unit Software Write Protected" },
! 1404: { 0x27, 0x03, "Associated Write Protect" },
! 1405: { 0x27, 0x04, "Persistent Write Protect" },
! 1406: { 0x27, 0x05, "Permanent Write Protect" },
! 1407: { 0x27, 0x06, "Conditional Write Protect" },
! 1408: { 0x28, 0x00, "Not Ready To Ready Transition (Medium May Have Changed)" },
! 1409: { 0x28, 0x01, "Import Or Export Element Accessed" },
! 1410: { 0x29, 0x00, "Power On, Reset, or Bus Device Reset Occurred" },
! 1411: { 0x29, 0x01, "Power On Occurred" },
! 1412: { 0x29, 0x02, "SCSI Bus Reset Occurred" },
! 1413: { 0x29, 0x03, "Bus Device Reset Function Occurred" },
! 1414: { 0x29, 0x04, "Device Internal Reset" },
! 1415: { 0x29, 0x05, "Transceiver Mode Changed to Single Ended" },
! 1416: { 0x29, 0x06, "Transceiver Mode Changed to LVD" },
! 1417: { 0x29, 0x07, "I_T Nexus Loss Occurred" },
! 1418: { 0x2A, 0x00, "Parameters Changed" },
! 1419: { 0x2A, 0x01, "Mode Parameters Changed" },
! 1420: { 0x2A, 0x02, "Log Parameters Changed" },
! 1421: { 0x2A, 0x03, "Reservations Preempted" },
! 1422: { 0x2A, 0x04, "Reservations Released" },
! 1423: { 0x2A, 0x05, "Registrations Preempted" },
! 1424: { 0x2A, 0x06, "Asymmetric Access State Changed" },
! 1425: { 0x2A, 0x07, "Implicit Asymmetric Access State Transition Failed" },
! 1426: { 0x2B, 0x00, "Copy Cannot Execute Since Host Cannot Disconnect" },
! 1427: { 0x2C, 0x00, "Command Sequence Error" },
! 1428: { 0x2C, 0x01, "Too Many Windows Specified" },
! 1429: { 0x2C, 0x02, "Invalid Combination of Windows Specified" },
! 1430: { 0x2C, 0x03, "Current Program Area Is Not Empty" },
! 1431: { 0x2C, 0x04, "Current Program Area Is Empty" },
! 1432: { 0x2C, 0x05, "Illegal Power Condition Request" },
! 1433: { 0x2C, 0x06, "Persistent Prevent Conflict" },
! 1434: { 0x2C, 0x07, "Previous Busy Status" },
! 1435: { 0x2C, 0x08, "Previous Task Set Full Status" },
! 1436: { 0x2C, 0x09, "Previous Reservation Conflict Status" },
! 1437: { 0x2C, 0x0A, "Partition Or Collection Contains User Objects" },
! 1438: { 0x2D, 0x00, "Overwrite Error On Update In Place" },
! 1439: { 0x2E, 0x00, "Insufficient Time For Operation" },
! 1440: { 0x2F, 0x00, "Commands Cleared By Another Initiator" },
! 1441: { 0x30, 0x00, "Incompatible Medium Installed" },
! 1442: { 0x30, 0x01, "Cannot Read Medium - Unknown Format" },
! 1443: { 0x30, 0x02, "Cannot Read Medium - Incompatible Format" },
! 1444: { 0x30, 0x03, "Cleaning Cartridge Installed" },
! 1445: { 0x30, 0x04, "Cannot Write Medium - Unknown Format" },
! 1446: { 0x30, 0x05, "Cannot Write Medium - Incompatible Format" },
! 1447: { 0x30, 0x06, "Cannot Format Medium - Incompatible Medium" },
! 1448: { 0x30, 0x07, "Cleaning Failure" },
! 1449: { 0x30, 0x08, "Cannot Write - Application Code Mismatch" },
! 1450: { 0x30, 0x09, "Current Session Not Fixated For Append" },
! 1451: { 0x30, 0x0A, "Cleaning Request Rejected" },
! 1452: { 0x30, 0x10, "Medium Not Formatted" },
! 1453: { 0x31, 0x00, "Medium Format Corrupted" },
! 1454: { 0x31, 0x01, "Format Command Failed" },
! 1455: { 0x32, 0x00, "No Defect Spare Location Available" },
! 1456: { 0x32, 0x01, "Defect List Update Failure" },
! 1457: { 0x33, 0x00, "Tape Length Error" },
! 1458: { 0x34, 0x00, "Enclosure Failure" },
! 1459: { 0x35, 0x00, "Enclosure Services Failure" },
! 1460: { 0x35, 0x01, "Unsupported Enclosure Function" },
! 1461: { 0x35, 0x02, "Enclosure Services Unavailable" },
! 1462: { 0x35, 0x03, "Enclosure Services Transfer Failure" },
! 1463: { 0x35, 0x04, "Enclosure Services Transfer Refused" },
! 1464: { 0x36, 0x00, "Ribbon, Ink, or Toner Failure" },
! 1465: { 0x37, 0x00, "Rounded Parameter" },
! 1466: { 0x38, 0x00, "Event Status Notification" },
! 1467: { 0x38, 0x02, "ESN - Power Management Class Event" },
! 1468: { 0x38, 0x04, "ESN - Media Class Event" },
! 1469: { 0x38, 0x06, "ESN - Device Busy Class Event" },
! 1470: { 0x39, 0x00, "Saving Parameters Not Supported" },
! 1471: { 0x3A, 0x00, "Medium Not Present" },
! 1472: { 0x3A, 0x01, "Medium Not Present - Tray Closed" },
! 1473: { 0x3A, 0x02, "Medium Not Present - Tray Open" },
! 1474: { 0x3A, 0x03, "Medium Not Present - Loadable" },
! 1475: { 0x3A, 0x04, "Medium Not Present - Medium Auxiliary Memory Accessible" },
! 1476: { 0x3B, 0x00, "Sequential Positioning Error" },
! 1477: { 0x3B, 0x01, "Tape Position Error At Beginning-of-Medium" },
! 1478: { 0x3B, 0x02, "Tape Position Error At End-of-Medium" },
! 1479: { 0x3B, 0x03, "Tape or Electronic Vertical Forms Unit Not Ready" },
! 1480: { 0x3B, 0x04, "Slew Failure" },
! 1481: { 0x3B, 0x05, "Paper Jam" },
! 1482: { 0x3B, 0x06, "Failed To Sense Top-Of-Form" },
! 1483: { 0x3B, 0x07, "Failed To Sense Bottom-Of-Form" },
! 1484: { 0x3B, 0x08, "Reposition Error" },
! 1485: { 0x3B, 0x09, "Read Past End Of Medium" },
! 1486: { 0x3B, 0x0A, "Read Past Beginning Of Medium" },
! 1487: { 0x3B, 0x0B, "Position Past End Of Medium" },
! 1488: { 0x3B, 0x0C, "Position Past Beginning Of Medium" },
! 1489: { 0x3B, 0x0D, "Medium Destination Element Full" },
! 1490: { 0x3B, 0x0E, "Medium Source Element Empty" },
! 1491: { 0x3B, 0x0F, "End Of Medium Reached" },
! 1492: { 0x3B, 0x11, "Medium Magazine Not Accessible" },
! 1493: { 0x3B, 0x12, "Medium Magazine Removed" },
! 1494: { 0x3B, 0x13, "Medium Magazine Inserted" },
! 1495: { 0x3B, 0x14, "Medium Magazine Locked" },
! 1496: { 0x3B, 0x15, "Medium Magazine Unlocked" },
! 1497: { 0x3B, 0x16, "Mechanical Positioning Or Changer Error" },
! 1498: { 0x3D, 0x00, "Invalid Bits In IDENTIFY Message" },
! 1499: { 0x3E, 0x00, "Logical Unit Has Not Self-Configured Yet" },
! 1500: { 0x3E, 0x01, "Logical Unit Failure" },
! 1501: { 0x3E, 0x02, "Timeout On Logical Unit" },
! 1502: { 0x3E, 0x03, "Logical Unit Failed Self-Test" },
! 1503: { 0x3E, 0x04, "Logical Unit Unable To Update Self-Test Log" },
! 1504: { 0x3F, 0x00, "Target Operating Conditions Have Changed" },
! 1505: { 0x3F, 0x01, "Microcode Has Changed" },
! 1506: { 0x3F, 0x02, "Changed Operating Definition" },
! 1507: { 0x3F, 0x03, "INQUIRY Data Has Changed" },
! 1508: { 0x3F, 0x04, "component Device Attached" },
! 1509: { 0x3F, 0x05, "Device Identifier Changed" },
! 1510: { 0x3F, 0x06, "Redundancy Group Created Or Modified" },
! 1511: { 0x3F, 0x07, "Redundancy Group Deleted" },
! 1512: { 0x3F, 0x08, "Spare Created Or Modified" },
! 1513: { 0x3F, 0x09, "Spare Deleted" },
! 1514: { 0x3F, 0x0A, "Volume Set Created Or Modified" },
! 1515: { 0x3F, 0x0B, "Volume Set Deleted" },
! 1516: { 0x3F, 0x0C, "Volume Set Deassigned" },
! 1517: { 0x3F, 0x0D, "Volume Set Reassigned" },
! 1518: { 0x3F, 0x0E, "Reported LUNs Data Has Changed" },
! 1519: { 0x3F, 0x0F, "Echo Buffer Overwritten" },
! 1520: { 0x3F, 0x10, "Medium Loadable" },
! 1521: { 0x3F, 0x11, "Medium Auxiliary Memory Accessible" },
! 1522: { 0x40, 0x00, "RAM FAILURE (Should Use 40 NN)" },
! 1523: /*
! 1524: * ASC 0x40 also has an ASCQ range from 0x80 to 0xFF.
! 1525: * 0x40 0xNN DIAGNOSTIC FAILURE ON COMPONENT NN
! 1526: */
! 1527: { 0x41, 0x00, "Data Path FAILURE (Should Use 40 NN)" },
! 1528: { 0x42, 0x00, "Power-On or Self-Test FAILURE (Should Use 40 NN)" },
! 1529: { 0x43, 0x00, "Message Error" },
! 1530: { 0x44, 0x00, "Internal Target Failure" },
! 1531: { 0x45, 0x00, "Select Or Reselect Failure" },
! 1532: { 0x46, 0x00, "Unsuccessful Soft Reset" },
! 1533: { 0x47, 0x00, "SCSI Parity Error" },
! 1534: { 0x47, 0x01, "Data Phase CRC Error Detected" },
! 1535: { 0x47, 0x02, "SCSI Parity Error Detected During ST Data Phase" },
! 1536: { 0x47, 0x03, "Information Unit iuCRC Error Detected" },
! 1537: { 0x47, 0x04, "Asynchronous Information Protection Error Detected" },
! 1538: { 0x47, 0x05, "Protocol Service CRC Error" },
! 1539: { 0x47, 0x7F, "Some Commands Cleared By iSCSI Protocol Event" },
! 1540: { 0x48, 0x00, "Initiator Detected Error Message Received" },
! 1541: { 0x49, 0x00, "Invalid Message Error" },
! 1542: { 0x4A, 0x00, "Command Phase Error" },
! 1543: { 0x4B, 0x00, "Data Phase Error" },
! 1544: { 0x4B, 0x01, "Invalid Target Port Transfer Tag Received" },
! 1545: { 0x4B, 0x02, "Too Much Write Data" },
! 1546: { 0x4B, 0x03, "ACK/NAK Timeout" },
! 1547: { 0x4B, 0x04, "NAK Received" },
! 1548: { 0x4B, 0x05, "Data Offset Error" },
! 1549: { 0x4B, 0x06, "Initiator Response Timeout" },
! 1550: { 0x4C, 0x00, "Logical Unit Failed Self-Configuration" },
! 1551: /*
! 1552: * ASC 0x4D has an ASCQ range from 0x00 to 0xFF.
! 1553: * 0x4D 0xNN TAGGED OVERLAPPED COMMANDS (NN = TASK TAG)
! 1554: */
! 1555: { 0x4E, 0x00, "Overlapped Commands Attempted" },
! 1556: { 0x50, 0x00, "Write Append Error" },
! 1557: { 0x50, 0x01, "Write Append Position Error" },
! 1558: { 0x50, 0x02, "Position Error Related To Timing" },
! 1559: { 0x51, 0x00, "Erase Failure" },
! 1560: { 0x51, 0x01, "Erase Failure - Incomplete Erase Operation Detected" },
! 1561: { 0x52, 0x00, "Cartridge Fault" },
! 1562: { 0x53, 0x00, "Media Load or Eject Failed" },
! 1563: { 0x53, 0x01, "Unload Tape Failure" },
! 1564: { 0x53, 0x02, "Medium Removal Prevented" },
! 1565: { 0x54, 0x00, "SCSI To Host System Interface Failure" },
! 1566: { 0x55, 0x00, "System Resource Failure" },
! 1567: { 0x55, 0x01, "System Buffer Full" },
! 1568: { 0x55, 0x02, "Insufficient Reservation Resources" },
! 1569: { 0x55, 0x03, "Insufficient Resources" },
! 1570: { 0x55, 0x04, "Insufficient Registration Resources" },
! 1571: { 0x55, 0x05, "Insufficient Access Control Resources" },
! 1572: { 0x55, 0x06, "Auxiliary Memory Out Of Space" },
! 1573: { 0x57, 0x00, "Unable To Recover Table-Of-Contents" },
! 1574: { 0x58, 0x00, "Generation Does Not Exist" },
! 1575: { 0x59, 0x00, "Updated Block Read" },
! 1576: { 0x5A, 0x00, "Operator Request or State Change Input" },
! 1577: { 0x5A, 0x01, "Operator Medium Removal Requested" },
! 1578: { 0x5A, 0x02, "Operator Selected Write Protect" },
! 1579: { 0x5A, 0x03, "Operator Selected Write Permit" },
! 1580: { 0x5B, 0x00, "Log Exception" },
! 1581: { 0x5B, 0x01, "Threshold Condition Met" },
! 1582: { 0x5B, 0x02, "Log Counter At Maximum" },
! 1583: { 0x5B, 0x03, "Log List Codes Exhausted" },
! 1584: { 0x5C, 0x00, "RPL Status Change" },
! 1585: { 0x5C, 0x01, "Spindles Synchronized" },
! 1586: { 0x5C, 0x02, "Spindles Not Synchronized" },
! 1587: { 0x5D, 0x00, "Failure Prediction Threshold Exceeded" },
! 1588: { 0x5D, 0x01, "Media Failure Prediction Threshold Exceeded" },
! 1589: { 0x5D, 0x02, "Logical Unit Failure Prediction Threshold Exceeded" },
! 1590: { 0x5D, 0x03, "Spare Area Exhaustion Prediction Threshold Exceeded" },
! 1591: { 0x5D, 0x10, "Hardware Impending Failure General Hard Drive Failure" },
! 1592: { 0x5D, 0x11, "Hardware Impending Failure Drive Error Rate Too High" },
! 1593: { 0x5D, 0x12, "Hardware Impending Failure Data Error Rate Too High" },
! 1594: { 0x5D, 0x13, "Hardware Impending Failure Seek Error Rate Too High" },
! 1595: { 0x5D, 0x14, "Hardware Impending Failure Too Many Block Reassigns" },
! 1596: { 0x5D, 0x15, "Hardware Impending Failure Access Times Too High" },
! 1597: { 0x5D, 0x16, "Hardware Impending Failure Start Unit Times Too High" },
! 1598: { 0x5D, 0x17, "Hardware Impending Failure Channel Parametrics" },
! 1599: { 0x5D, 0x18, "Hardware Impending Failure Controller Detected" },
! 1600: { 0x5D, 0x19, "Hardware Impending Failure Throughput Performance" },
! 1601: { 0x5D, 0x1A, "Hardware Impending Failure Seek Time Performance" },
! 1602: { 0x5D, 0x1B, "Hardware Impending Failure Spin-Up Retry Count" },
! 1603: { 0x5D, 0x1C, "Hardware Impending Failure Drive Calibration Retry Count" },
! 1604: { 0x5D, 0x20, "Controller Impending Failure General Hard Drive Failure" },
! 1605: { 0x5D, 0x21, "Controller Impending Failure Drive Error Rate Too High" },
! 1606: { 0x5D, 0x22, "Controller Impending Failure Data Error Rate Too High" },
! 1607: { 0x5D, 0x23, "Controller Impending Failure Seek Error Rate Too High" },
! 1608: { 0x5D, 0x24, "Controller Impending Failure Too Many Block Reassigns" },
! 1609: { 0x5D, 0x25, "Controller Impending Failure Access Times Too High" },
! 1610: { 0x5D, 0x26, "Controller Impending Failure Start Unit Times Too High" },
! 1611: { 0x5D, 0x27, "Controller Impending Failure Channel Parametrics" },
! 1612: { 0x5D, 0x28, "Controller Impending Failure Controller Detected" },
! 1613: { 0x5D, 0x29, "Controller Impending Failure Throughput Performance" },
! 1614: { 0x5D, 0x2A, "Controller Impending Failure Seek Time Performance" },
! 1615: { 0x5D, 0x2B, "Controller Impending Failure Spin-Up Retry Count" },
! 1616: { 0x5D, 0x2C, "Controller Impending Failure Drive Calibration Retry Count" },
! 1617: { 0x5D, 0x30, "Data Channel Impending Failure General Hard Drive Failure" },
! 1618: { 0x5D, 0x31, "Data Channel Impending Failure Drive Error Rate Too High" },
! 1619: { 0x5D, 0x32, "Data Channel Impending Failure Data Error Rate Too High" },
! 1620: { 0x5D, 0x33, "Data Channel Impending Failure Seek Error Rate Too High" },
! 1621: { 0x5D, 0x34, "Data Channel Impending Failure Too Many Block Reassigns" },
! 1622: { 0x5D, 0x35, "Data Channel Impending Failure Access Times Too High" },
! 1623: { 0x5D, 0x36, "Data Channel Impending Failure Start Unit Times Too High" },
! 1624: { 0x5D, 0x37, "Data Channel Impending Failure Channel Parametrics" },
! 1625: { 0x5D, 0x38, "Data Channel Impending Failure Controller Detected" },
! 1626: { 0x5D, 0x39, "Data Channel Impending Failure Throughput Performance" },
! 1627: { 0x5D, 0x3A, "Data Channel Impending Failure Seek Time Performance" },
! 1628: { 0x5D, 0x3B, "Data Channel Impending Failure Spin-Up Retry Count" },
! 1629: { 0x5D, 0x3C, "Data Channel Impending Failure Drive Calibration Retry Count" },
! 1630: { 0x5D, 0x40, "Servo Impending Failure General Hard Drive Failure" },
! 1631: { 0x5D, 0x41, "Servo Impending Failure Drive Error Rate Too High" },
! 1632: { 0x5D, 0x42, "Servo Impending Failure Data Error Rate Too High" },
! 1633: { 0x5D, 0x43, "Servo Impending Failure Seek Error Rate Too High" },
! 1634: { 0x5D, 0x44, "Servo Impending Failure Too Many Block Reassigns" },
! 1635: { 0x5D, 0x45, "Servo Impending Failure Access Times Too High" },
! 1636: { 0x5D, 0x46, "Servo Impending Failure Start Unit Times Too High" },
! 1637: { 0x5D, 0x47, "Servo Impending Failure Channel Parametrics" },
! 1638: { 0x5D, 0x48, "Servo Impending Failure Controller Detected" },
! 1639: { 0x5D, 0x49, "Servo Impending Failure Throughput Performance" },
! 1640: { 0x5D, 0x4A, "Servo Impending Failure Seek Time Performance" },
! 1641: { 0x5D, 0x4B, "Servo Impending Failure Spin-Up Retry Count" },
! 1642: { 0x5D, 0x4C, "Servo Impending Failure Drive Calibration Retry Count" },
! 1643: { 0x5D, 0x50, "Spindle Impending Failure General Hard Drive Failure" },
! 1644: { 0x5D, 0x51, "Spindle Impending Failure Drive Error Rate Too High" },
! 1645: { 0x5D, 0x52, "Spindle Impending Failure Data Error Rate Too High" },
! 1646: { 0x5D, 0x53, "Spindle Impending Failure Seek Error Rate Too High" },
! 1647: { 0x5D, 0x54, "Spindle Impending Failure Too Many Block Reassigns" },
! 1648: { 0x5D, 0x55, "Spindle Impending Failure Access Times Too High" },
! 1649: { 0x5D, 0x56, "Spindle Impending Failure Start Unit Times Too High" },
! 1650: { 0x5D, 0x57, "Spindle Impending Failure Channel Parametrics" },
! 1651: { 0x5D, 0x58, "Spindle Impending Failure Controller Detected" },
! 1652: { 0x5D, 0x59, "Spindle Impending Failure Throughput Performance" },
! 1653: { 0x5D, 0x5A, "Spindle Impending Failure Seek Time Performance" },
! 1654: { 0x5D, 0x5B, "Spindle Impending Failure Spin-Up Retry Count" },
! 1655: { 0x5D, 0x5C, "Spindle Impending Failure Drive Calibration Retry Count" },
! 1656: { 0x5D, 0x60, "Firmware Impending Failure General Hard Drive Failure" },
! 1657: { 0x5D, 0x61, "Firmware Impending Failure Drive Error Rate Too High" },
! 1658: { 0x5D, 0x62, "Firmware Impending Failure Data Error Rate Too High" },
! 1659: { 0x5D, 0x63, "Firmware Impending Failure Seek Error Rate Too High" },
! 1660: { 0x5D, 0x64, "Firmware Impending Failure Too Many Block Reassigns" },
! 1661: { 0x5D, 0x65, "Firmware Impending Failure Access Times Too High" },
! 1662: { 0x5D, 0x66, "Firmware Impending Failure Start Unit Times Too High" },
! 1663: { 0x5D, 0x67, "Firmware Impending Failure Channel Parametrics" },
! 1664: { 0x5D, 0x68, "Firmware Impending Failure Controller Detected" },
! 1665: { 0x5D, 0x69, "Firmware Impending Failure Throughput Performance" },
! 1666: { 0x5D, 0x6A, "Firmware Impending Failure Seek Time Performance" },
! 1667: { 0x5D, 0x6B, "Firmware Impending Failure Spin-Up Retry Count" },
! 1668: { 0x5D, 0x6C, "Firmware Impending Failure Drive Calibration Retry Count" },
! 1669: { 0x5D, 0xFF, "Failure Prediction Threshold Exceeded (false)" },
! 1670: { 0x5E, 0x00, "Low Power Condition On" },
! 1671: { 0x5E, 0x01, "Idle Condition Activated By Timer" },
! 1672: { 0x5E, 0x02, "Standby Condition Activated By Timer" },
! 1673: { 0x5E, 0x03, "Idle Condition Activated By Command" },
! 1674: { 0x5E, 0x04, "Standby Condition Activated By Command" },
! 1675: { 0x5E, 0x41, "Power State Change To Active" },
! 1676: { 0x5E, 0x42, "Power State Change To Idle" },
! 1677: { 0x5E, 0x43, "Power State Change To Standby" },
! 1678: { 0x5E, 0x45, "Power State Change To Sleep" },
! 1679: { 0x5E, 0x47, "Power State Change To Device Control" },
! 1680: { 0x60, 0x00, "Lamp Failure" },
! 1681: { 0x61, 0x00, "Video Acquisition Error" },
! 1682: { 0x61, 0x01, "Unable To Acquire Video" },
! 1683: { 0x61, 0x02, "Out Of Focus" },
! 1684: { 0x62, 0x00, "Scan Head Positioning Error" },
! 1685: { 0x63, 0x00, "End Of User Area Encountered On This Track" },
! 1686: { 0x63, 0x01, "Packet Does Not Fit In Available Space" },
! 1687: { 0x64, 0x00, "Illegal Mode For This Track" },
! 1688: { 0x64, 0x01, "Invalid Packet Size" },
! 1689: { 0x65, 0x00, "Voltage Fault" },
! 1690: { 0x66, 0x00, "Automatic Document Feeder Cover Up" },
! 1691: { 0x66, 0x01, "Automatic Document Feeder Lift Up" },
! 1692: { 0x66, 0x02, "Document Jam In Automatic Document Feeder" },
! 1693: { 0x66, 0x03, "Document Miss Feed Automatic In Document Feeder" },
! 1694: { 0x67, 0x00, "Configuration Failure" },
! 1695: { 0x67, 0x01, "Configuration Of Incapable Logical Units Failed" },
! 1696: { 0x67, 0x02, "Add Logical Unit Failed" },
! 1697: { 0x67, 0x03, "Modification Of Logical Unit Failed" },
! 1698: { 0x67, 0x04, "Exchange Of Logical Unit Failed" },
! 1699: { 0x67, 0x05, "Remove Of Logical Unit Failed" },
! 1700: { 0x67, 0x06, "Attachment Of Logical Unit Failed" },
! 1701: { 0x67, 0x07, "Creation Of Logical Unit Failed" },
! 1702: { 0x67, 0x08, "Assign Failure Occurred" },
! 1703: { 0x67, 0x09, "Multiply Assigned Logical Unit" },
! 1704: { 0x67, 0x0A, "Set Target Port Groups Command Failed" },
! 1705: { 0x68, 0x00, "Logical Unit Not Configured" },
! 1706: { 0x69, 0x00, "Data Loss On Logical Unit" },
! 1707: { 0x69, 0x01, "Multiple Logical Unit Failures" },
! 1708: { 0x69, 0x02, "Parity/Data Mismatch" },
! 1709: { 0x6A, 0x00, "Informational, Refer To Log" },
! 1710: { 0x6B, 0x00, "State Change Has Occurred" },
! 1711: { 0x6B, 0x01, "Redundancy Level Got Better" },
! 1712: { 0x6B, 0x02, "Redundancy Level Got Worse" },
! 1713: { 0x6C, 0x00, "Rebuild Failure Occurred" },
! 1714: { 0x6D, 0x00, "Recalculate Failure Occurred" },
! 1715: { 0x6E, 0x00, "Command To Logical Unit Failed" },
! 1716: { 0x6F, 0x00, "Copy Protection Key Exchange Failure - Authentication Failure" },
! 1717: { 0x6F, 0x01, "Copy Protection Key Exchange Failure - Key Not Present" },
! 1718: { 0x6F, 0x02, "Copy Protection Key Exchange Failure - Key Not Established" },
! 1719: { 0x6F, 0x03, "Read Of Scrambled Sector Without Authentication" },
! 1720: { 0x6F, 0x04, "Media Region Code Is Mismatched To Logical Unit Region" },
! 1721: { 0x6F, 0x05, "Drive Region Must Be Permanent/Region Reset Count Error" },
! 1722: /*
! 1723: * ASC 0x70 has an ASCQ range from 0x00 to 0xFF.
! 1724: * 0x70 0xNN DECOMPRESSION EXCEPTION SHORT ALGORITHM ID Of NN
! 1725: */
! 1726: { 0x71, 0x00, "Decompression Exception Long Algorithm ID" },
! 1727: { 0x72, 0x00, "Session Fixation Error" },
! 1728: { 0x72, 0x01, "Session Fixation Error Writing Lead-In" },
! 1729: { 0x72, 0x02, "Session Fixation Error Writing Lead-Out" },
! 1730: { 0x72, 0x03, "Session Fixation Error - Incomplete Track In Session" },
! 1731: { 0x72, 0x04, "Empty Or Partially Written Reserved Track" },
! 1732: { 0x72, 0x05, "No More Track Reservations Allowed" },
! 1733: { 0x73, 0x00, "CD Control Error" },
! 1734: { 0x73, 0x01, "Power Calibration Area Almost Full" },
! 1735: { 0x73, 0x02, "Power Calibration Area Is Full" },
! 1736: { 0x73, 0x03, "Power Calibration Area Error" },
! 1737: { 0x73, 0x04, "Program Memory Area Update Failure" },
! 1738: { 0x73, 0x05, "Program Memory Area Is Full" },
! 1739: { 0x73, 0x06, "RMA/PMA Is Almost Full" },
! 1740: { 0x00, 0x00, NULL }
! 1741: };
! 1742:
! 1743: static __inline void
! 1744: asc2ascii(u_int8_t asc, u_int8_t ascq, char *result, size_t len)
! 1745: {
! 1746: int i;
! 1747:
! 1748: /* Check for a dynamically built description. */
! 1749: switch (asc) {
! 1750: case 0x40:
! 1751: if (ascq >= 0x80) {
! 1752: snprintf(result, len,
! 1753: "Diagnostic Failure on Component 0x%02x", ascq);
! 1754: return;
! 1755: }
! 1756: break;
! 1757: case 0x4d:
! 1758: snprintf(result, len,
! 1759: "Tagged Overlapped Commands (0x%02x = TASK TAG)", ascq);
! 1760: return;
! 1761: case 0x70:
! 1762: snprintf(result, len,
! 1763: "Decompression Exception Short Algorithm ID OF 0x%02x",
! 1764: ascq);
! 1765: return;
! 1766: default:
! 1767: break;
! 1768: }
! 1769:
! 1770: /* Check for a fixed description. */
! 1771: for (i = 0; adesc[i].description != NULL; i++) {
! 1772: if (adesc[i].asc == asc && adesc[i].ascq == ascq) {
! 1773: strlcpy(result, adesc[i].description, len);
! 1774: return;
! 1775: }
! 1776: }
! 1777:
! 1778: /* Just print out the ASC and ASCQ values as a description. */
! 1779: snprintf(result, len, "ASC 0x%02x ASCQ 0x%02x", asc, ascq);
! 1780: }
! 1781: #endif /* SCSITERSE */
! 1782:
! 1783: void
! 1784: scsi_print_sense(struct scsi_xfer *xs)
! 1785: {
! 1786: struct scsi_sense_data *sense = &xs->sense;
! 1787: u_int8_t serr = sense->error_code &
! 1788: SSD_ERRCODE;
! 1789: int32_t info;
! 1790: char *sbs;
! 1791:
! 1792: sc_print_addr(xs->sc_link);
! 1793:
! 1794: /* XXX For error 0x71, current opcode is not the relevant one. */
! 1795: printf("%sCheck Condition (error %#x) on opcode 0x%x\n",
! 1796: (serr == SSD_ERRCODE_DEFERRED) ? "DEFERRED " : "", serr,
! 1797: xs->cmd->opcode);
! 1798:
! 1799: if (serr != SSD_ERRCODE_CURRENT && serr != SSD_ERRCODE_DEFERRED) {
! 1800: if ((sense->error_code & SSD_ERRCODE_VALID) != 0) {
! 1801: struct scsi_sense_data_unextended *usense =
! 1802: (struct scsi_sense_data_unextended *)sense;
! 1803: printf(" AT BLOCK #: %d (decimal)",
! 1804: _3btol(usense->block));
! 1805: }
! 1806: return;
! 1807: }
! 1808:
! 1809: printf(" SENSE KEY: %s\n", scsi_decode_sense(sense,
! 1810: DECODE_SENSE_KEY));
! 1811:
! 1812: if (sense->flags & (SSD_FILEMARK | SSD_EOM | SSD_ILI)) {
! 1813: char pad = ' ';
! 1814:
! 1815: printf(" ");
! 1816: if (sense->flags & SSD_FILEMARK) {
! 1817: printf("%c Filemark Detected", pad);
! 1818: pad = ',';
! 1819: }
! 1820: if (sense->flags & SSD_EOM) {
! 1821: printf("%c EOM Detected", pad);
! 1822: pad = ',';
! 1823: }
! 1824: if (sense->flags & SSD_ILI)
! 1825: printf("%c Incorrect Length Indicator Set", pad);
! 1826: printf("\n");
! 1827: }
! 1828:
! 1829: /*
! 1830: * It is inconvenient to use device type to figure out how to
! 1831: * format the info fields. So print them as 32 bit integers.
! 1832: */
! 1833: info = _4btol(&sense->info[0]);
! 1834: if (info)
! 1835: printf(" INFO: 0x%x (VALID flag %s)\n", info,
! 1836: sense->error_code & SSD_ERRCODE_VALID ? "on" : "off");
! 1837:
! 1838: if (sense->extra_len < 4)
! 1839: return;
! 1840:
! 1841: info = _4btol(&sense->cmd_spec_info[0]);
! 1842: if (info)
! 1843: printf(" COMMAND INFO: 0x%x\n", info);
! 1844: sbs = scsi_decode_sense(sense, DECODE_ASC_ASCQ);
! 1845: if (strlen(sbs) > 0)
! 1846: printf(" ASC/ASCQ: %s\n", sbs);
! 1847: if (sense->fru != 0)
! 1848: printf(" FRU CODE: 0x%x\n", sense->fru);
! 1849: sbs = scsi_decode_sense(sense, DECODE_SKSV);
! 1850: if (strlen(sbs) > 0)
! 1851: printf(" SKSV: %s\n", sbs);
! 1852: }
! 1853:
! 1854: char *
! 1855: scsi_decode_sense(struct scsi_sense_data *sense, int flag)
! 1856: {
! 1857: static char rqsbuf[132];
! 1858: u_int16_t count;
! 1859: u_int8_t skey, spec_1;
! 1860: int len;
! 1861:
! 1862: bzero(rqsbuf, sizeof(rqsbuf));
! 1863:
! 1864: skey = sense->flags & SSD_KEY;
! 1865: spec_1 = sense->sense_key_spec_1;
! 1866: count = _2btol(&sense->sense_key_spec_2);
! 1867:
! 1868: switch (flag) {
! 1869: case DECODE_SENSE_KEY:
! 1870: strlcpy(rqsbuf, sense_keys[skey], sizeof(rqsbuf));
! 1871: break;
! 1872: case DECODE_ASC_ASCQ:
! 1873: asc2ascii(sense->add_sense_code, sense->add_sense_code_qual,
! 1874: rqsbuf, sizeof(rqsbuf));
! 1875: break;
! 1876: case DECODE_SKSV:
! 1877: if (sense->extra_len < 9 || ((spec_1 & SSD_SCS_VALID) == 0))
! 1878: break;
! 1879: switch (skey) {
! 1880: case SKEY_ILLEGAL_REQUEST:
! 1881: len = snprintf(rqsbuf, sizeof rqsbuf,
! 1882: "Error in %s, Offset %d",
! 1883: (spec_1 & SSD_SCS_CDB_ERROR) ? "CDB" : "Parameters",
! 1884: count);
! 1885: if ((len != -1 && len < sizeof rqsbuf) &&
! 1886: (spec_1 & SSD_SCS_VALID_BIT_INDEX))
! 1887: snprintf(rqsbuf+len, sizeof rqsbuf - len,
! 1888: ", bit %d", spec_1 & SSD_SCS_BIT_INDEX);
! 1889: break;
! 1890: case SKEY_RECOVERED_ERROR:
! 1891: case SKEY_MEDIUM_ERROR:
! 1892: case SKEY_HARDWARE_ERROR:
! 1893: snprintf(rqsbuf, sizeof rqsbuf,
! 1894: "Actual Retry Count: %d", count);
! 1895: break;
! 1896: case SKEY_NOT_READY:
! 1897: snprintf(rqsbuf, sizeof rqsbuf,
! 1898: "Progress Indicator: %d", count);
! 1899: break;
! 1900: default:
! 1901: break;
! 1902: }
! 1903: break;
! 1904: default:
! 1905: break;
! 1906: }
! 1907:
! 1908: return (rqsbuf);
! 1909: }
! 1910:
! 1911: #ifdef SCSIDEBUG
! 1912: /*
! 1913: * Given a scsi_xfer, dump the request, in all its glory
! 1914: */
! 1915: void
! 1916: show_scsi_xs(struct scsi_xfer *xs)
! 1917: {
! 1918: printf("xs(%p): ", xs);
! 1919: printf("flg(0x%x)", xs->flags);
! 1920: printf("sc_link(%p)", xs->sc_link);
! 1921: printf("retr(0x%x)", xs->retries);
! 1922: printf("timo(0x%x)", xs->timeout);
! 1923: printf("cmd(%p)", xs->cmd);
! 1924: printf("len(0x%x)", xs->cmdlen);
! 1925: printf("data(%p)", xs->data);
! 1926: printf("len(0x%x)", xs->datalen);
! 1927: printf("res(0x%x)", xs->resid);
! 1928: printf("err(0x%x)", xs->error);
! 1929: printf("bp(%p)", xs->bp);
! 1930: show_scsi_cmd(xs);
! 1931: }
! 1932:
! 1933: void
! 1934: show_scsi_cmd(struct scsi_xfer *xs)
! 1935: {
! 1936: u_char *b = (u_char *) xs->cmd;
! 1937: int i = 0;
! 1938:
! 1939: sc_print_addr(xs->sc_link);
! 1940: printf("command: ");
! 1941:
! 1942: if ((xs->flags & SCSI_RESET) == 0) {
! 1943: while (i < xs->cmdlen) {
! 1944: if (i)
! 1945: printf(",");
! 1946: printf("%x", b[i++]);
! 1947: }
! 1948: printf("-[%d bytes]\n", xs->datalen);
! 1949: if (xs->datalen)
! 1950: show_mem(xs->data, min(64, xs->datalen));
! 1951: } else
! 1952: printf("-RESET-\n");
! 1953: }
! 1954:
! 1955: void
! 1956: show_mem(u_char *address, int num)
! 1957: {
! 1958: int x;
! 1959:
! 1960: printf("------------------------------");
! 1961: for (x = 0; x < num; x++) {
! 1962: if ((x % 16) == 0)
! 1963: printf("\n%03d: ", x);
! 1964: printf("%02x ", *address++);
! 1965: }
! 1966: printf("\n------------------------------\n");
! 1967: }
! 1968: #endif /* SCSIDEBUG */
CVSweb