scsi_all.c revision 39466
1/* 2 * Implementation of Utility functions for all SCSI device types. 3 * 4 * Copyright (c) 1997, 1998 Justin T. Gibbs. 5 * Copyright (c) 1997, 1998 Kenneth D. Merry. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions, and the following disclaimer, 13 * without modification, immediately at the beginning of the file. 14 * 2. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 21 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * $Id: scsi_all.c,v 1.1 1998/09/15 06:36:33 gibbs Exp $ 30 */ 31 32#include <sys/param.h> 33 34#ifdef KERNEL 35#include <opt_scsi.h> 36 37#include <sys/systm.h> 38#else 39#include <errno.h> 40#include <stdio.h> 41#include <string.h> 42#endif 43 44#include <cam/cam.h> 45#include <cam/cam_ccb.h> 46#include <cam/cam_xpt.h> 47#include <cam/cam_xpt_periph.h> 48#include <cam/scsi/scsi_all.h> 49#ifndef KERNEL 50#include <camlib.h> 51 52#ifndef FALSE 53#define FALSE 0 54#endif /* FALSE */ 55#ifndef TRUE 56#define TRUE 1 57#endif /* TRUE */ 58#define ERESTART -1 /* restart syscall */ 59#define EJUSTRETURN -2 /* don't modify regs, just return */ 60#endif /* !KERNEL */ 61 62const char *scsi_sense_key_text[] = 63{ 64 "NO SENSE", 65 "RECOVERED ERROR", 66 "NOT READY", 67 "MEDIUM ERROR", 68 "HARDWARE FAILURE", 69 "ILLEGAL REQUEST", 70 "UNIT ATTENTION", 71 "DATA PROTECT", 72 "BLANK CHECK", 73 "Vendor Specific", 74 "COPY ABORTED", 75 "ABORTED COMMAND", 76 "EQUAL", 77 "VOLUME OVERFLOW", 78 "MISCOMPARE", 79 "RESERVED" 80}; 81 82#if !defined(SCSI_NO_OP_STRINGS) 83 84#define D 0x001 85#define T 0x002 86#define L 0x004 87#define P 0x008 88#define W 0x010 89#define R 0x020 90#define S 0x040 91#define O 0x080 92#define M 0x100 93#define C 0x200 94#define A 0x400 95#define E 0x800 96 97#define ALL 0xFFF 98 99/* 100 * WARNING: You must update the num_ops field below for this quirk table 101 * entry if you add more entries. 102 */ 103static struct op_table_entry plextor_cd_ops[] = { 104 {0xD8, R, "CD-DA READ"} 105}; 106 107static struct scsi_op_quirk_entry scsi_op_quirk_table[] = { 108 { 109 /* 110 * I believe that 0xD8 is the Plextor proprietary command 111 * to read CD-DA data. I'm not sure which Plextor CDROM 112 * models support the command, though. I know for sure 113 * that the 4X, 8X, and 12X models do, and presumably the 114 * 12-20X does. I don't know about any earlier models, 115 * though. If anyone has any more complete information, 116 * feel free to change this quirk entry. 117 */ 118 {T_CDROM, SIP_MEDIA_REMOVABLE, "PLEXTOR", "CD-ROM PX*", "*"}, 119 1, /* number of vendor-specific opcodes for this entry */ 120 plextor_cd_ops 121 } 122}; 123 124static struct op_table_entry scsi_op_codes[] = { 125/* 126 * From: ftp://ftp.symbios.com/pub/standards/io/t10/drafts/spc/op-num.txt 127 * Modifications by Kenneth Merry (ken@plutotech.com) 128 * 129 * Note: order is important in this table, scsi_op_desc() currently 130 * depends on the opcodes in the table being in order to save search time. 131 */ 132/* 133 * File: OP-NUM.TXT 134 * 135 * SCSI Operation Codes 136 * Numeric Sorted Listing 137 * as of 11/13/96 138 * 139 * D - DIRECT ACCESS DEVICE (SBC) device column key 140 * .T - SEQUENTIAL ACCESS DEVICE (SSC) ------------------- 141 * . L - PRINTER DEVICE (SSC) M = Mandatory 142 * . P - PROCESSOR DEVICE (SPC) O = Optional 143 * . .W - WRITE ONCE READ MULTIPLE DEVICE (SBC) V = Vendor specific 144 * . . R - CD DEVICE (MMC) R = Reserved 145 * . . S - SCANNER DEVICE (SGC) Z = Obsolete 146 * . . .O - OPTICAL MEMORY DEVICE (SBC) 147 * . . . M - MEDIA CHANGER DEVICE (SMC) 148 * . . . C - COMMUNICATION DEVICE (SSC) 149 * . . . .A - STORAGE ARRAY DEVICE (SCC) 150 * . . . . E - ENCLOSURE SERVICES DEVICE (SES) 151 * OP DTLPWRSOMCAE Description 152 * -- ------------ ---------------------------------------------------- */ 153/* 00 MMMMMMMMMMMM TEST UNIT READY */ 154{0x00, ALL, "TEST UNIT READY"}, 155 156/* 01 M REWIND */ 157{0x01, T, "REWIND"}, 158/* 01 Z V ZO ZO REZERO UNIT */ 159{0x01, D|L|W|O|M, "REZERO UNIT"}, 160 161/* 02 VVVVVV V */ 162 163/* 03 MMMMMMMMMMMM REQUEST SENSE */ 164{0x03, ALL, "REQUEST SENSE"}, 165 166/* 04 M O O FORMAT UNIT */ 167{0x04, D|R|O, "FORMAT UNIT"}, 168/* 04 O FORMAT MEDIUM */ 169{0x04, T, "FORMAT MEDIUM"}, 170/* 04 O FORMAT */ 171{0x04, L, "FORMAT"}, 172 173/* 05 VMVVVV V READ BLOCK LIMITS */ 174{0x05, T, "READ BLOCK LIMITS"}, 175 176/* 06 VVVVVV V */ 177 178/* 07 OVV O OV REASSIGN BLOCKS */ 179{0x07, D|W|O, "REASSIGN BLOCKS"}, 180/* 07 O INITIALIZE ELEMENT STATUS */ 181{0x07, M, "INITIALIZE ELEMENT STATUS"}, 182 183/* 08 OMV OO OV READ(06) */ 184{0x08, D|T|W|R|O, "READ(06)"}, 185/* 08 O RECEIVE */ 186{0x08, P, "RECEIVE"}, 187/* 08 M GET MESSAGE(06) */ 188{0x08, C, "GET MESSAGE(06)"}, 189 190/* 09 VVVVVV V */ 191 192/* 0A OM O OV WRITE(06) */ 193{0x0A, D|T|W|O, "WRITE(06)"}, 194/* 0A M SEND(06) */ 195{0x0A, P, "SEND(06)"}, 196/* 0A M SEND MESSAGE(06) */ 197{0x0A, C, "SEND MESSAGE(06)"}, 198/* 0A M PRINT */ 199{0x0A, L, "PRINT"}, 200 201/* 0B Z ZO ZV SEEK(06) */ 202{0x0B, D|W|R|O, "SEEK(06)"}, 203/* 0B O SLEW AND PRINT */ 204{0x0B, L, "SLEW AND PRINT"}, 205 206/* 0C VVVVVV V */ 207/* 0D VVVVVV V */ 208/* 0E VVVVVV V */ 209/* 0F VOVVVV V READ REVERSE */ 210{0x0F, T, "READ REVERSE"}, 211 212/* 10 VM VVV WRITE FILEMARKS */ 213{0x10, T, "WRITE FILEMARKS"}, 214/* 10 O O SYNCHRONIZE BUFFER */ 215{0x10, L|W, "SYNCHRONIZE BUFFER"}, 216 217/* 11 VMVVVV SPACE */ 218{0x11, T, "SPACE"}, 219 220/* 12 MMMMMMMMMMMM INQUIRY */ 221{0x12, ALL, "INQUIRY"}, 222 223/* 13 VOVVVV VERIFY(06) */ 224{0x13, T, "VERIFY(06)"}, 225 226/* 14 VOOVVV RECOVER BUFFERED DATA */ 227{0x14, T|L, "RECOVER BUFFERED DATA"}, 228 229/* 15 OMO OOOOOOOO MODE SELECT(06) */ 230{0x15, ALL & ~(P), "MODE SELECT(06)"}, 231 232/* 16 MMMOMMMM O RESERVE(06) */ 233{0x16, D|T|L|P|W|R|S|O|E, "RESERVE(06)"}, 234/* 16 M RESERVE ELEMENT(06) */ 235{0x16, M, "RESERVE ELEMENT(06)"}, 236 237/* 17 MMMOMMMM O RELEASE(06) */ 238{0x17, ALL & ~(M|C|A), "RELEASE(06)"}, 239/* 17 M RELEASE ELEMENT(06) */ 240{0x17, M, "RELEASE ELEMENT(06)"}, 241 242/* 18 OOOOOOOO COPY */ 243{0x18, ALL & ~(M|C|A|E), "COPY"}, 244 245/* 19 VMVVVV ERASE */ 246{0x19, T, "ERASE"}, 247 248/* 1A OMO OOOOOOOO MODE SENSE(06) */ 249{0x1A, ALL & ~(P), "MODE SENSE(06)"}, 250 251/* 1B O OM O STOP START UNIT */ 252{0x1B, D|W|R|O, "STOP START UNIT"}, 253/* 1B O LOAD UNLOAD */ 254{0x1B, T, "LOAD UNLOAD"}, 255/* 1B O SCAN */ 256{0x1B, S, "SCAN"}, 257/* 1B O STOP PRINT */ 258{0x1B, L, "STOP PRINT"}, 259 260/* 1C OOOOOOOOOO M RECEIVE DIAGNOSTIC RESULTS */ 261{0x1C, ALL & ~(A), "RECEIVE DIAGNOSTIC RESULTS"}, 262 263/* 1D MMMMMMMMMMMM SEND DIAGNOSTIC */ 264{0x1D, ALL, "SEND DIAGNOSTIC"}, 265 266/* 1E OO OM OO PREVENT ALLOW MEDIUM REMOVAL */ 267{0x1E, D|T|W|R|O|M, "PREVENT ALLOW MEDIUM REMOVAL"}, 268 269/* 1F */ 270/* 20 V VV V */ 271/* 21 V VV V */ 272/* 22 V VV V */ 273/* 23 V VV V */ 274 275/* 24 V VVM SET WINDOW */ 276{0x24, S, "SET WINDOW"}, 277 278/* 25 M M M READ CAPACITY */ 279{0x25, D|W|O, "READ CAPACITY"}, 280/* 25 M READ CD RECORDED CAPACITY */ 281{0x25, R, "READ CD RECORDED CAPACITY"}, 282/* 25 O GET WINDOW */ 283{0x25, S, "GET WINDOW"}, 284 285/* 26 V VV */ 286/* 27 V VV */ 287 288/* 28 M MMMM READ(10) */ 289{0x28, D|W|R|S|O, "READ(10)"}, 290/* 28 O GET MESSAGE(10) */ 291{0x28, C, "GET MESSAGE(10)"}, 292 293/* 29 V VV O READ GENERATION */ 294{0x29, O, "READ GENERATION"}, 295 296/* 2A M MM M WRITE(10) */ 297{0x2A, D|W|R|O, "WRITE(10)"}, 298/* 2A O SEND(10) */ 299{0x2A, S, "SEND(10)"}, 300/* 2A O SEND MESSAGE(10) */ 301{0x2A, C, "SEND MESSAGE(10)"}, 302 303/* 2B O OM O SEEK(10) */ 304{0x2B, D|W|R|O, "SEEK(10)"}, 305/* 2B O LOCATE */ 306{0x2B, T, "LOCATE"}, 307/* 2B O POSITION TO ELEMENT */ 308{0x2B, M, "POSITION TO ELEMENT"}, 309 310/* 2C V O ERASE(10) */ 311{0x2C, O, "ERASE(10)"}, 312 313/* 2D V O O READ UPDATED BLOCK */ 314{0x2D, W|O, "READ UPDATED BLOCK"}, 315 316/* 2E O O O WRITE AND VERIFY(10) */ 317{0x2E, D|W|O, "WRITE AND VERIFY(10)"}, 318 319/* 2F O OO O VERIFY(10) */ 320{0x2F, D|W|R|O, "VERIFY(10)"}, 321 322/* 30 Z ZO Z SEARCH DATA HIGH(10) */ 323{0x30, D|W|R|O, "SEARCH DATA HIGH(10)"}, 324 325/* 31 Z ZO Z SEARCH DATA EQUAL(10) */ 326{0x31, D|W|R|O, "SEARCH DATA EQUAL(10)"}, 327/* 31 O OBJECT POSITION */ 328{0x31, S, "OBJECT POSITION"}, 329 330/* 32 Z ZO Z SEARCH DATA LOW(10) */ 331{0x32, D|W|R|O, "SEARCH DATA LOW(10"}, 332 333/* 33 O OO O SET LIMITS(10) */ 334{0x33, D|W|R|O, "SET LIMITS(10)"}, 335 336/* 34 O OO O PRE-FETCH */ 337{0x34, D|W|R|O, "PRE-FETCH"}, 338/* 34 O READ POSITION */ 339{0x34, T, "READ POSITION"}, 340/* 34 O GET DATA BUFFER STATUS */ 341{0x34, S, "GET DATA BUFFER STATUS"}, 342 343/* 35 O OM O SYNCHRONIZE CACHE */ 344{0x35, D|W|R|O, "SYNCHRONIZE CACHE"}, 345 346/* 36 O OO O LOCK UNLOCK CACHE */ 347{0x36, D|W|R|O, "LOCK UNLOCK CACHE"}, 348 349/* 37 O O READ DEFECT DATA(10) */ 350{0x37, D|O, "READ DEFECT DATA(10)"}, 351 352/* 38 O O MEDIUM SCAN */ 353{0x38, W|O, "MEDIUM SCAN"}, 354 355/* 39 OOOOOOOO COMPARE */ 356{0x39, ALL & ~(M|C|A|E), "COMPARE"}, 357 358/* 3A OOOOOOOO COPY AND VERIFY */ 359{0x3A, ALL & ~(M|C|A|E), "COPY AND VERIFY"}, 360 361/* 3B OOOOOOOOOO O WRITE BUFFER */ 362{0x3B, ALL & ~(A), "WRITE BUFFER"}, 363 364/* 3C OOOOOOOOOO READ BUFFER */ 365{0x3C, ALL & ~(A|E),"READ BUFFER"}, 366 367/* 3D O O UPDATE BLOCK */ 368{0x3D, W|O, "UPDATE BLOCK"}, 369 370/* 3E O OO O READ LONG */ 371{0x3E, D|W|R|O, "READ LONG"}, 372 373/* 3F O O O WRITE LONG */ 374{0x3F, D|W|O, "WRITE LONG"}, 375 376/* 40 OOOOOOOOOO CHANGE DEFINITION */ 377{0x40, ALL & ~(A|E),"CHANGE DEFINITION"}, 378 379/* 41 O WRITE SAME */ 380{0x41, D, "WRITE SAME"}, 381 382/* 42 M READ SUB-CHANNEL */ 383{0x42, R, "READ SUB-CHANNEL"}, 384 385/* 43 M READ TOC/PMA/ATIP {MMC Proposed} */ 386{0x43, R, "READ TOC/PMA/ATIP {MMC Proposed}"}, 387 388/* 44 M REPORT DENSITY SUPPORT */ 389{0x44, T, "REPORT DENSITY SUPPORT"}, 390/* 44 M READ HEADER */ 391{0x44, R, "READ HEADER"}, 392 393/* 45 O PLAY AUDIO(10) */ 394{0x45, R, "PLAY AUDIO(10)"}, 395 396/* 46 */ 397 398/* 47 O PLAY AUDIO MSF */ 399{0x47, R, "PLAY AUDIO MSF"}, 400 401/* 48 O PLAY AUDIO TRACK INDEX */ 402{0x48, R, "PLAY AUDIO TRACK INDEX"}, 403 404/* 49 O PLAY TRACK RELATIVE(10) */ 405{0x49, R, "PLAY TRACK RELATIVE(10)"}, 406 407/* 4A */ 408 409/* 4B O PAUSE/RESUME */ 410{0x4B, R, "PAUSE/RESUME"}, 411 412/* 4C OOOOOOOOOOO LOG SELECT */ 413{0x4C, ALL & ~(E), "LOG SELECT"}, 414 415/* 4D OOOOOOOOOOO LOG SENSE */ 416{0x4D, ALL & ~(E), "LOG SENSE"}, 417 418/* 4E O STOP PLAY/SCAN {MMC Proposed} */ 419{0x4E, R, "STOP PLAY/SCAN {MMC Proposed}"}, 420 421/* 4F */ 422 423/* 50 O XDWRITE(10) */ 424{0x50, D, "XDWRITE(10)"}, 425 426/* 51 O XPWRITE(10) */ 427{0x51, D, "XPWRITE(10)"}, 428/* 51 M READ DISC INFORMATION {MMC Proposed} */ 429{0x51, R, "READ DISC INFORMATION {MMC Proposed}"}, 430 431/* 52 O XDREAD(10) */ 432{0x52, D, "XDREAD(10)"}, 433/* 52 M READ TRACK INFORMATION {MMC Proposed} */ 434{0x52, R, "READ TRACK INFORMATION {MMC Proposed}"}, 435 436/* 53 M RESERVE TRACK {MMC Proposed} */ 437{0x53, R, "RESERVE TRACK {MMC Proposed}"}, 438 439/* 54 O SEND OPC INFORMATION {MMC Proposed} */ 440{0x54, R, "SEND OPC INFORMATION {MMC Proposed}"}, 441 442/* 55 OOO OOOOOOOO MODE SELECT(10) */ 443{0x55, ALL & ~(P), "MODE SELECT(10)"}, 444 445/* 56 MMMOMMMM O RESERVE(10) */ 446{0x56, ALL & ~(M|C|A), "RESERVE(10)"}, 447/* 56 M RESERVE ELEMENT(10) */ 448{0x56, M, "RESERVE ELEMENT(10)"}, 449 450/* 57 MMMOMMMM O RELEASE(10) */ 451{0x57, ALL & ~(M|C|A), "RELEASE(10"}, 452/* 57 M RELEASE ELEMENT(10) */ 453{0x57, M, "RELEASE ELEMENT(10)"}, 454 455/* 58 O REPAIR TRACK {MMC Proposed} */ 456{0x58, R, "REPAIR TRACK {MMC Proposed}"}, 457 458/* 59 O READ MASTER CUE {MMC Proposed} */ 459{0x59, R, "READ MASTER CUE {MMC Proposed}"}, 460 461/* 5A OOO OOOOOOOO MODE SENSE(10) */ 462{0x5A, ALL & ~(P), "MODE SENSE(10)"}, 463 464/* 5B M CLOSE TRACK/SESSION {MMC Proposed} */ 465{0x5B, R, "CLOSE TRACK/SESSION {MMC Proposed}"}, 466 467/* 5C O READ BUFFER CAPACITY {MMC Proposed} */ 468{0x5C, R, "READ BUFFER CAPACITY {MMC Proposed}"}, 469 470/* 5D O SEND CUE SHEET {MMC Proposed} */ 471{0x5D, R, "SEND CUE SHEET {MMC Proposed}"}, 472 473/* 5E OOOOOOOOO O PERSISTENT RESERVE IN */ 474{0x5E, ALL & ~(C|A),"PERSISTENT RESERVE IN"}, 475 476/* 5F OOOOOOOOO O PERSISTENT RESERVE OUT */ 477{0x5F, ALL & ~(C|A),"PERSISTENT RESERVE OUT"}, 478 479/* 80 O XDWRITE EXTENDED(16) */ 480{0x80, D, "XDWRITE EXTENDED(16)"}, 481 482/* 81 O REBUILD(16) */ 483{0x81, D, "REBUILD(16)"}, 484 485/* 82 O REGENERATE(16) */ 486{0x82, D, "REGENERATE(16)"}, 487 488/* 83 */ 489/* 84 */ 490/* 85 */ 491/* 86 */ 492/* 87 */ 493/* 88 */ 494/* 89 */ 495/* 8A */ 496/* 8B */ 497/* 8C */ 498/* 8D */ 499/* 8E */ 500/* 8F */ 501/* 90 */ 502/* 91 */ 503/* 92 */ 504/* 93 */ 505/* 94 */ 506/* 95 */ 507/* 96 */ 508/* 97 */ 509/* 98 */ 510/* 99 */ 511/* 9A */ 512/* 9B */ 513/* 9C */ 514/* 9D */ 515/* 9E */ 516/* 9F */ 517 518/* A0 OOOOOOOOOOO REPORT LUNS */ 519{0xA0, ALL & ~(E), "REPORT LUNS"}, 520 521/* A1 O BLANK {MMC Proposed} */ 522{0xA1, R, "BLANK {MMC Proposed}"}, 523 524/* A2 O WRITE CD MSF {MMC Proposed} */ 525{0xA2, R, "WRITE CD MSF {MMC Proposed}"}, 526 527/* A3 M MAINTENANCE (IN) */ 528{0xA3, A, "MAINTENANCE (IN)"}, 529 530/* A4 O MAINTENANCE (OUT) */ 531{0xA4, A, "MAINTENANCE (OUT)"}, 532 533/* A5 O M MOVE MEDIUM */ 534{0xA5, T|M, "MOVE MEDIUM"}, 535/* A5 O PLAY AUDIO(12) */ 536{0xA5, R, "PLAY AUDIO(12)"}, 537 538/* A6 O EXCHANGE MEDIUM */ 539{0xA6, M, "EXCHANGE MEDIUM"}, 540/* A6 O LOAD/UNLOAD CD {MMC Proposed} */ 541{0xA6, R, "LOAD/UNLOAD CD {MMC Proposed}"}, 542 543/* A7 OO OO OO MOVE MEDIUM ATTACHED */ 544{0xA7, D|T|W|R|O|M, "MOVE MEDIUM ATTACHED"}, 545 546/* A8 OM O READ(12) */ 547{0xA8, W|R|O, "READ(12)"}, 548/* A8 O GET MESSAGE(12) */ 549{0xA8, C, "GET MESSAGE(12)"}, 550 551/* A9 O PLAY TRACK RELATIVE(12) */ 552{0xA9, R, "PLAY TRACK RELATIVE(12)"}, 553 554/* AA O O WRITE(12) */ 555{0xAA, W|O, "WRITE(12)"}, 556/* AA O WRITE CD(12) {MMC Proposed} */ 557{0xAA, R, "WRITE CD(12) {MMC Proposed}"}, 558/* AA O SEND MESSAGE(12) */ 559{0xAA, C, "SEND MESSAGE(12)"}, 560 561/* AB */ 562 563/* AC O ERASE(12) */ 564{0xAC, O, "ERASE(12)"}, 565 566/* AD */ 567 568/* AE O O WRITE AND VERIFY(12) */ 569{0xAE, W|O, "WRITE AND VERIFY(12)"}, 570 571/* AF OO O VERIFY(12) */ 572{0xAF, W|R|O, "VERIFY(12)"}, 573 574/* B0 ZO Z SEARCH DATA HIGH(12) */ 575{0xB0, W|R|O, "SEARCH DATA HIGH(12)"}, 576 577/* B1 ZO Z SEARCH DATA EQUAL(12) */ 578{0xB1, W|R|O, "SEARCH DATA EQUAL(12)"}, 579 580/* B2 ZO Z SEARCH DATA LOW(12) */ 581{0xB2, W|R|O, "SEARCH DATA LOW(12)"}, 582 583/* B3 OO O SET LIMITS(12) */ 584{0xB3, W|R|O, "SET LIMITS(12)"}, 585 586/* B4 OO OO OO READ ELEMENT STATUS ATTACHED */ 587{0xB4, D|T|W|R|O|M, "READ ELEMENT STATUS ATTACHED"}, 588 589/* B5 O REQUEST VOLUME ELEMENT ADDRESS */ 590{0xB5, M, "REQUEST VOLUME ELEMENT ADDRESS"}, 591 592/* B6 O SEND VOLUME TAG */ 593{0xB6, M, "SEND VOLUME TAG"}, 594 595/* B7 O READ DEFECT DATA(12) */ 596{0xB7, O, "READ DEFECT DATA(12)"}, 597 598/* B8 O M READ ELEMENT STATUS */ 599{0xB8, T|M, "READ ELEMENT STATUS"}, 600/* B8 O SET CD SPEED {MMC Proposed} */ 601{0xB8, R, "SET CD SPEED {MMC Proposed}"}, 602 603/* B9 M READ CD MSF {MMC Proposed} */ 604{0xB9, R, "READ CD MSF {MMC Proposed}"}, 605 606/* BA O SCAN {MMC Proposed} */ 607{0xBA, R, "SCAN {MMC Proposed}"}, 608/* BA M REDUNDANCY GROUP (IN) */ 609{0xBA, A, "REDUNDANCY GROUP (IN)"}, 610 611/* BB O SET CD-ROM SPEED {proposed} */ 612{0xBB, R, "SET CD-ROM SPEED {proposed}"}, 613/* BB O REDUNDANCY GROUP (OUT) */ 614{0xBB, A, "REDUNDANCY GROUP (OUT)"}, 615 616/* BC O PLAY CD {MMC Proposed} */ 617{0xBC, R, "PLAY CD {MMC Proposed}"}, 618/* BC M SPARE (IN) */ 619{0xBC, A, "SPARE (IN)"}, 620 621/* BD M MECHANISM STATUS {MMC Proposed} */ 622{0xBD, R, "MECHANISM STATUS {MMC Proposed}"}, 623/* BD O SPARE (OUT) */ 624{0xBD, A, "SPARE (OUT)"}, 625 626/* BE O READ CD {MMC Proposed} */ 627{0xBE, R, "READ CD {MMC Proposed}"}, 628/* BE M VOLUME SET (IN) */ 629{0xBE, A, "VOLUME SET (IN)"}, 630 631/* BF O VOLUME SET (OUT) */ 632{0xBF, A, "VOLUME SET (OUT)"} 633}; 634 635const char * 636scsi_op_desc(u_int16_t opcode, struct scsi_inquiry_data *inq_data) 637{ 638 caddr_t match; 639 int i, j; 640 u_int16_t opmask; 641 u_int16_t pd_type; 642 int num_ops[2]; 643 struct op_table_entry *table[2]; 644 int num_tables; 645 646 pd_type = SID_TYPE(inq_data); 647 648 match = cam_quirkmatch((caddr_t)inq_data, 649 (caddr_t)scsi_op_quirk_table, 650 sizeof(scsi_op_quirk_table)/ 651 sizeof(*scsi_op_quirk_table), 652 sizeof(*scsi_op_quirk_table), 653 scsi_inquiry_match); 654 655 if (match != NULL) { 656 table[0] = ((struct scsi_op_quirk_entry *)match)->op_table; 657 num_ops[0] = ((struct scsi_op_quirk_entry *)match)->num_ops; 658 table[1] = scsi_op_codes; 659 num_ops[1] = sizeof(scsi_op_codes)/sizeof(scsi_op_codes[0]); 660 num_tables = 2; 661 } else { 662 /* 663 * If this is true, we have a vendor specific opcode that 664 * wasn't covered in the quirk table. 665 */ 666 if ((opcode > 0xBF) || ((opcode > 0x5F) && (opcode < 0x80))) 667 return("Vendor Specific Command"); 668 669 table[0] = scsi_op_codes; 670 num_ops[0] = sizeof(scsi_op_codes)/sizeof(scsi_op_codes[0]); 671 num_tables = 1; 672 } 673 674 opmask = 1 << pd_type; 675 676 for (j = 0; j < num_tables; j++) { 677 for (i = 0;i < num_ops[j] && table[j][i].opcode <= opcode; i++){ 678 if ((table[j][i].opcode == opcode) 679 && ((table[j][i].opmask & opmask) != 0)) 680 return(table[j][i].desc); 681 } 682 } 683 684 /* 685 * If we can't find a match for the command in the table, we just 686 * assume it's a vendor specifc command. 687 */ 688 return("Vendor Specific Command"); 689 690} 691 692#else /* SCSI_NO_OP_STRINGS */ 693 694const char * 695scsi_op_desc(u_int16_t opcode, struct scsi_inquiry_data *inq_data) 696{ 697 return(""); 698} 699 700#endif 701 702 703#include <sys/param.h> 704 705 706#if !defined(SCSI_NO_SENSE_STRINGS) 707#define SST(asc, ascq, action, desc) \ 708 asc, ascq, action, desc 709#else 710#define SST(asc, ascq, action, desc) \ 711 asc, asc, action 712#endif 713 714/* 715 * If we're in the kernel, 'quantum' is already defined in cam_xpt.c. 716 * Otherwise, we need to define it. 717 */ 718#ifdef KERNEL 719extern const char quantum[]; 720#else 721static const char quantum[] = "QUANTUM"; 722#endif 723 724/* 725 * WARNING: You must update the num_ascs field below for this quirk table 726 * entry if you add more entries. 727 */ 728static struct asc_table_entry quantum_fireball_entries[] = { 729 {SST(0x04, 0x0b, SS_START|SSQ_DECREMENT_COUNT|ENXIO, 730 "Logical unit not ready, initializing cmd. required")} 731}; 732 733static struct scsi_sense_quirk_entry asc_quirk_table[] = { 734 { 735 /* 736 * The Quantum Fireball ST and SE like to return 0x04 0x0b when 737 * they really should return 0x04 0x02. 0x04,0x0b isn't 738 * defined in any SCSI spec, and it isn't mentioned in the 739 * hardware manual for these drives. 740 */ 741 {T_DIRECT, SIP_MEDIA_FIXED, "QUANTUM", "FIREBALL S*", "*"}, 742 1, /* number of vendor-specific sense codes for this entry */ 743 quantum_fireball_entries 744 } 745}; 746 747static struct asc_table_entry asc_text[] = { 748/* 749 * From File: ASC-NUM.TXT 750 * SCSI ASC/ASCQ Assignments 751 * Numeric Sorted Listing 752 * as of 5/12/97 753 * 754 * D - DIRECT ACCESS DEVICE (SBC) device column key 755 * .T - SEQUENTIAL ACCESS DEVICE (SSC) ------------------- 756 * . L - PRINTER DEVICE (SSC) blank = reserved 757 * . P - PROCESSOR DEVICE (SPC) not blank = allowed 758 * . .W - WRITE ONCE READ MULTIPLE DEVICE (SBC) 759 * . . R - CD DEVICE (MMC) 760 * . . S - SCANNER DEVICE (SGC) 761 * . . .O - OPTICAL MEMORY DEVICE (SBC) 762 * . . . M - MEDIA CHANGER DEVICE (SMC) 763 * . . . C - COMMUNICATION DEVICE (SSC) 764 * . . . .A - STORAGE ARRAY DEVICE (SCC) 765 * . . . . E - ENCLOSURE SERVICES DEVICE (SES) 766 * DTLPWRSOMCAE ASC ASCQ Action Description 767 * ------------ ---- ---- ------ -----------------------------------*/ 768/* DTLPWRSOMCAE */{SST(0x00, 0x00, SS_NEPDEF, 769 "No additional sense information") }, 770/* T S */{SST(0x00, 0x01, SS_DEF, 771 "Filemark detected") }, 772/* T S */{SST(0x00, 0x02, SS_DEF, 773 "End-of-partition/medium detected") }, 774/* T */{SST(0x00, 0x03, SS_DEF, 775 "Setmark detected") }, 776/* T S */{SST(0x00, 0x04, SS_DEF, 777 "Beginning-of-partition/medium detected") }, 778/* T S */{SST(0x00, 0x05, SS_DEF, 779 "End-of-data detected") }, 780/* DTLPWRSOMCAE */{SST(0x00, 0x06, SS_DEF, 781 "I/O process terminated") }, 782/* R */{SST(0x00, 0x11, SS_NEDEF|EBUSY, 783 "Audio play operation in progress") }, 784/* R */{SST(0x00, 0x12, SS_NEDEF, 785 "Audio play operation paused") }, 786/* R */{SST(0x00, 0x13, SS_NEDEF, 787 "Audio play operation successfully completed") }, 788/* R */{SST(0x00, 0x14, SS_DEF, 789 "Audio play operation stopped due to error") }, 790/* R */{SST(0x00, 0x15, SS_DEF, 791 "No current audio status to return") }, 792/* DTLPWRSOMCAE */{SST(0x00, 0x16, SS_NEDEF|EBUSY, 793 "Operation in progress") }, 794/* DTL WRSOM AE */{SST(0x00, 0x17, SS_DEF, 795 "Cleaning requested") }, 796/* D W O */{SST(0x01, 0x00, SS_DEF, 797 "No index/sector signal") }, 798/* D WR OM */{SST(0x02, 0x00, SS_DEF, 799 "No seek complete") }, 800/* DTL W SO */{SST(0x03, 0x00, SS_DEF, 801 "Peripheral device write fault") }, 802/* T */{SST(0x03, 0x01, SS_DEF, 803 "No write current") }, 804/* T */{SST(0x03, 0x02, SS_DEF, 805 "Excessive write errors") }, 806/* DTLPWRSOMCAE */{SST(0x04, 0x00, SS_TUR|SSQ_MANY|SSQ_DECREMENT_COUNT|EIO, 807 "Logical unit not ready, cause not reportable") }, 808/* DTLPWRSOMCAE */{SST(0x04, 0x01, SS_TUR|SSQ_MANY|SSQ_DECREMENT_COUNT|EBUSY, 809 "Logical unit is in process of becoming ready") }, 810/* DTLPWRSOMCAE */{SST(0x04, 0x02, SS_START|SSQ_DECREMENT_COUNT|ENXIO, 811 "Logical unit not ready, initializing cmd. required") }, 812/* DTLPWRSOMCAE */{SST(0x04, 0x03, SS_NEDEF|ENXIO, 813 "Logical unit not ready, manual intervention required")}, 814/* DTL O */{SST(0x04, 0x04, SS_NEDEF|EBUSY, 815 "Logical unit not ready, format in progress") }, 816/* DT W OMCA */{SST(0x04, 0x05, SS_NEDEF|EBUSY, 817 "Logical unit not ready, rebuild in progress") }, 818/* DT W OMCA */{SST(0x04, 0x06, SS_NEDEF|EBUSY, 819 "Logical unit not ready, recalculation in progress") }, 820/* DTLPWRSOMCAE */{SST(0x04, 0x07, SS_NEDEF|EBUSY, 821 "Logical unit not ready, operation in progress") }, 822/* R */{SST(0x04, 0x08, SS_NEDEF|EBUSY, 823 "Logical unit not ready, long write in progress") }, 824/* DTL WRSOMCAE */{SST(0x05, 0x00, SS_DEF, 825 "Logical unit does not respond to selection") }, 826/* D WR OM */{SST(0x06, 0x00, SS_DEF, 827 "No reference position found") }, 828/* DTL WRSOM */{SST(0x07, 0x00, SS_DEF, 829 "Multiple peripheral devices selected") }, 830/* DTL WRSOMCAE */{SST(0x08, 0x00, SS_DEF, 831 "Logical unit communication failure") }, 832/* DTL WRSOMCAE */{SST(0x08, 0x01, SS_DEF, 833 "Logical unit communication time-out") }, 834/* DTL WRSOMCAE */{SST(0x08, 0x02, SS_DEF, 835 "Logical unit communication parity error") }, 836/* DT R OM */{SST(0x08, 0x03, SS_DEF, 837 "Logical unit communication crc error (ultra-dma/32)")}, 838/* DT WR O */{SST(0x09, 0x00, SS_DEF, 839 "Track following error") }, 840/* WR O */{SST(0x09, 0x01, SS_DEF, 841 "Tracking servo failure") }, 842/* WR O */{SST(0x09, 0x02, SS_DEF, 843 "Focus servo failure") }, 844/* WR O */{SST(0x09, 0x03, SS_DEF, 845 "Spindle servo failure") }, 846/* DT WR O */{SST(0x09, 0x04, SS_DEF, 847 "Head select fault") }, 848/* DTLPWRSOMCAE */{SST(0x0A, 0x00, SS_NEDEF|ENOSPC, 849 "Error log overflow") }, 850/* DTLPWRSOMCAE */{SST(0x0B, 0x00, SS_DEF, 851 "Warning") }, 852/* DTLPWRSOMCAE */{SST(0x0B, 0x01, SS_DEF, 853 "Specified temperature exceeded") }, 854/* DTLPWRSOMCAE */{SST(0x0B, 0x02, SS_DEF, 855 "Enclosure degraded") }, 856/* T RS */{SST(0x0C, 0x00, SS_DEF, 857 "Write error") }, 858/* D W O */{SST(0x0C, 0x01, SS_NEDEF, 859 "Write error - recovered with auto reallocation") }, 860/* D W O */{SST(0x0C, 0x02, SS_DEF, 861 "Write error - auto reallocation failed") }, 862/* D W O */{SST(0x0C, 0x03, SS_DEF, 863 "Write error - recommend reassignment") }, 864/* DT W O */{SST(0x0C, 0x04, SS_NEPDEF, 865 "Compression check miscompare error") }, 866/* DT W O */{SST(0x0C, 0x05, SS_DEF, 867 "Data expansion occurred during compression") }, 868/* DT W O */{SST(0x0C, 0x06, SS_DEF, 869 "Block not compressible") }, 870/* R */{SST(0x0C, 0x07, SS_DEF, 871 "Write error - recovery needed") }, 872/* R */{SST(0x0C, 0x08, SS_DEF, 873 "Write error - recovery failed") }, 874/* R */{SST(0x0C, 0x09, SS_DEF, 875 "Write error - loss of streaming") }, 876/* R */{SST(0x0C, 0x0A, SS_DEF, 877 "Write error - padding blocks added") }, 878/* D W O */{SST(0x10, 0x00, SS_DEF, 879 "ID CRC or ECC error") }, 880/* DT WRSO */{SST(0x11, 0x00, SS_DEF, 881 "Unrecovered read error") }, 882/* DT W SO */{SST(0x11, 0x01, SS_DEF, 883 "Read retries exhausted") }, 884/* DT W SO */{SST(0x11, 0x02, SS_DEF, 885 "Error too long to correct") }, 886/* DT W SO */{SST(0x11, 0x03, SS_DEF, 887 "Multiple read errors") }, 888/* D W O */{SST(0x11, 0x04, SS_DEF, 889 "Unrecovered read error - auto reallocate failed") }, 890/* WR O */{SST(0x11, 0x05, SS_DEF, 891 "L-EC uncorrectable error") }, 892/* WR O */{SST(0x11, 0x06, SS_DEF, 893 "CIRC unrecovered error") }, 894/* W O */{SST(0x11, 0x07, SS_DEF, 895 "Data re-synchronization error") }, 896/* T */{SST(0x11, 0x08, SS_DEF, 897 "Incomplete block read") }, 898/* T */{SST(0x11, 0x09, SS_DEF, 899 "No gap found") }, 900/* DT O */{SST(0x11, 0x0A, SS_DEF, 901 "Miscorrected error") }, 902/* D W O */{SST(0x11, 0x0B, SS_DEF, 903 "Unrecovered read error - recommend reassignment") }, 904/* D W O */{SST(0x11, 0x0C, SS_DEF, 905 "Unrecovered read error - recommend rewrite the data")}, 906/* DT WR O */{SST(0x11, 0x0D, SS_DEF, 907 "De-compression CRC error") }, 908/* DT WR O */{SST(0x11, 0x0E, SS_DEF, 909 "Cannot decompress using declared algorithm") }, 910/* R */{SST(0x11, 0x0F, SS_DEF, 911 "Error reading UPC/EAN number") }, 912/* R */{SST(0x11, 0x10, SS_DEF, 913 "Error reading ISRC number") }, 914/* R */{SST(0x11, 0x11, SS_DEF, 915 "Read error - loss of streaming") }, 916/* D W O */{SST(0x12, 0x00, SS_DEF, 917 "Address mark not found for id field") }, 918/* D W O */{SST(0x13, 0x00, SS_DEF, 919 "Address mark not found for data field") }, 920/* DTL WRSO */{SST(0x14, 0x00, SS_DEF, 921 "Recorded entity not found") }, 922/* DT WR O */{SST(0x14, 0x01, SS_DEF, 923 "Record not found") }, 924/* T */{SST(0x14, 0x02, SS_DEF, 925 "Filemark or setmark not found") }, 926/* T */{SST(0x14, 0x03, SS_DEF, 927 "End-of-data not found") }, 928/* T */{SST(0x14, 0x04, SS_DEF, 929 "Block sequence error") }, 930/* DT W O */{SST(0x14, 0x05, SS_DEF, 931 "Record not found - recommend reassignment") }, 932/* DT W O */{SST(0x14, 0x06, SS_DEF, 933 "Record not found - data auto-reallocated") }, 934/* DTL WRSOM */{SST(0x15, 0x00, SS_DEF, 935 "Random positioning error") }, 936/* DTL WRSOM */{SST(0x15, 0x01, SS_DEF, 937 "Mechanical positioning error") }, 938/* DT WR O */{SST(0x15, 0x02, SS_DEF, 939 "Positioning error detected by read of medium") }, 940/* D W O */{SST(0x16, 0x00, SS_DEF, 941 "Data synchronization mark error") }, 942/* D W O */{SST(0x16, 0x01, SS_DEF, 943 "Data sync error - data rewritten") }, 944/* D W O */{SST(0x16, 0x02, SS_DEF, 945 "Data sync error - recommend rewrite") }, 946/* D W O */{SST(0x16, 0x03, SS_NEDEF, 947 "Data sync error - data auto-reallocated") }, 948/* D W O */{SST(0x16, 0x04, SS_DEF, 949 "Data sync error - recommend reassignment") }, 950/* DT WRSO */{SST(0x17, 0x00, SS_NEDEF, 951 "Recovered data with no error correction applied") }, 952/* DT WRSO */{SST(0x17, 0x01, SS_NEDEF, 953 "Recovered data with retries") }, 954/* DT WR O */{SST(0x17, 0x02, SS_NEDEF, 955 "Recovered data with positive head offset") }, 956/* DT WR O */{SST(0x17, 0x03, SS_NEDEF, 957 "Recovered data with negative head offset") }, 958/* WR O */{SST(0x17, 0x04, SS_NEDEF, 959 "Recovered data with retries and/or CIRC applied") }, 960/* D WR O */{SST(0x17, 0x05, SS_NEDEF, 961 "Recovered data using previous sector id") }, 962/* D W O */{SST(0x17, 0x06, SS_NEDEF, 963 "Recovered data without ECC - data auto-reallocated") }, 964/* D W O */{SST(0x17, 0x07, SS_NEDEF, 965 "Recovered data without ECC - recommend reassignment")}, 966/* D W O */{SST(0x17, 0x08, SS_NEDEF, 967 "Recovered data without ECC - recommend rewrite") }, 968/* D W O */{SST(0x17, 0x09, SS_NEDEF, 969 "Recovered data without ECC - data rewritten") }, 970/* D W O */{SST(0x18, 0x00, SS_NEDEF, 971 "Recovered data with error correction applied") }, 972/* D WR O */{SST(0x18, 0x01, SS_NEDEF, 973 "Recovered data with error corr. & retries applied") }, 974/* D WR O */{SST(0x18, 0x02, SS_NEDEF, 975 "Recovered data - data auto-reallocated") }, 976/* R */{SST(0x18, 0x03, SS_NEDEF, 977 "Recovered data with CIRC") }, 978/* R */{SST(0x18, 0x04, SS_NEDEF, 979 "Recovered data with L-EC") }, 980/* D WR O */{SST(0x18, 0x05, SS_NEDEF, 981 "Recovered data - recommend reassignment") }, 982/* D WR O */{SST(0x18, 0x06, SS_NEDEF, 983 "Recovered data - recommend rewrite") }, 984/* D W O */{SST(0x18, 0x07, SS_NEDEF, 985 "Recovered data with ECC - data rewritten") }, 986/* D O */{SST(0x19, 0x00, SS_DEF, 987 "Defect list error") }, 988/* D O */{SST(0x19, 0x01, SS_DEF, 989 "Defect list not available") }, 990/* D O */{SST(0x19, 0x02, SS_DEF, 991 "Defect list error in primary list") }, 992/* D O */{SST(0x19, 0x03, SS_DEF, 993 "Defect list error in grown list") }, 994/* DTLPWRSOMCAE */{SST(0x1A, 0x00, SS_DEF, 995 "Parameter list length error") }, 996/* DTLPWRSOMCAE */{SST(0x1B, 0x00, SS_DEF, 997 "Synchronous data transfer error") }, 998/* D O */{SST(0x1C, 0x00, SS_DEF, 999 "Defect list not found") }, 1000/* D O */{SST(0x1C, 0x01, SS_DEF, 1001 "Primary defect list not found") }, 1002/* D O */{SST(0x1C, 0x02, SS_DEF, 1003 "Grown defect list not found") }, 1004/* D W O */{SST(0x1D, 0x00, SS_NEPDEF, 1005 "Miscompare during verify operation" )}, 1006/* D W O */{SST(0x1E, 0x00, SS_NEDEF, 1007 "Recovered id with ecc correction") }, 1008/* D O */{SST(0x1F, 0x00, SS_DEF, 1009 "Partial defect list transfer") }, 1010/* DTLPWRSOMCAE */{SST(0x20, 0x00, SS_DEF, 1011 "Invalid command operation code") }, 1012/* DT WR OM */{SST(0x21, 0x00, SS_DEF, 1013 "Logical block address out of range" )}, 1014/* DT WR OM */{SST(0x21, 0x01, SS_DEF, 1015 "Invalid element address") }, 1016/* D */{SST(0x22, 0x00, SS_DEF, 1017 "Illegal function") }, /* Deprecated. Use 20 00, 24 00, or 26 00 instead */ 1018/* DTLPWRSOMCAE */{SST(0x24, 0x00, SS_NEDEF|EINVAL, 1019 "Invalid field in CDB") }, 1020/* DTLPWRSOMCAE */{SST(0x25, 0x00, SS_NEDEF|ENXIO, 1021 "Logical unit not supported") }, 1022/* DTLPWRSOMCAE */{SST(0x26, 0x00, SS_NEDEF|EINVAL, 1023 "Invalid field in parameter list") }, 1024/* DTLPWRSOMCAE */{SST(0x26, 0x01, SS_NEDEF|EINVAL, 1025 "Parameter not supported") }, 1026/* DTLPWRSOMCAE */{SST(0x26, 0x02, SS_NEDEF|EINVAL, 1027 "Parameter value invalid") }, 1028/* DTLPWRSOMCAE */{SST(0x26, 0x03, SS_DEF, 1029 "Threshold parameters not supported") }, 1030/* DTLPWRSOMCAE */{SST(0x26, 0x04, SS_DEF, 1031 "Invalid release of active persistent reservation") }, 1032/* DT W O */{SST(0x27, 0x00, SS_NEDEF|EACCES, 1033 "Write protected") }, 1034/* DT W O */{SST(0x27, 0x01, SS_NEDEF|EACCES, 1035 "Hardware write protected") }, 1036/* DT W O */{SST(0x27, 0x02, SS_NEDEF|EACCES, 1037 "Logical unit software write protected") }, 1038/* T */{SST(0x27, 0x03, SS_NEDEF|EACCES, 1039 "Associated write protect") }, 1040/* T */{SST(0x27, 0x04, SS_NEDEF|EACCES, 1041 "Persistent write protect") }, 1042/* T */{SST(0x27, 0x05, SS_NEDEF|EACCES, 1043 "Permanent write protect") }, 1044/* DTLPWRSOMCAE */{SST(0x28, 0x00, SS_NEDEF|ENXIO, 1045 "Not ready to ready change, medium may have changed") }, 1046/* DT WR OM */{SST(0x28, 0x01, SS_DEF, 1047 "Import or export element accessed") }, 1048/* DTLPWRSOMCAE */{SST(0x29, 0x00, SS_NEDEF|ENXIO, 1049 "Power on, reset, or bus device reset occurred") }, 1050/* DTLPWRSOMCAE */{SST(0x29, 0x01, SS_DEF, 1051 "Power on occurred") }, 1052/* DTLPWRSOMCAE */{SST(0x29, 0x02, SS_DEF, 1053 "Scsi bus reset occurred") }, 1054/* DTLPWRSOMCAE */{SST(0x29, 0x03, SS_DEF, 1055 "Bus device reset function occurred") }, 1056/* DTLPWRSOMCAE */{SST(0x29, 0x04, SS_DEF, 1057 "Device internal reset") }, 1058/* DTLPWRSOMCAE */{SST(0x29, 0x05, SS_DEF, 1059 "Transceiver mode changed to single-ended") }, 1060/* DTLPWRSOMCAE */{SST(0x29, 0x06, SS_DEF, 1061 "Transceiver mode changed to LVD") }, 1062/* DTL WRSOMCAE */{SST(0x2A, 0x00, SS_DEF, 1063 "Parameters changed") }, 1064/* DTL WRSOMCAE */{SST(0x2A, 0x01, SS_DEF, 1065 "Mode parameters changed") }, 1066/* DTL WRSOMCAE */{SST(0x2A, 0x02, SS_DEF, 1067 "Log parameters changed") }, 1068/* DTLPWRSOMCAE */{SST(0x2A, 0x03, SS_DEF, 1069 "Reservations preempted") }, 1070/* DTLPWRSO C */{SST(0x2B, 0x00, SS_DEF, 1071 "Copy cannot execute since host cannot disconnect") }, 1072/* DTLPWRSOMCAE */{SST(0x2C, 0x00, SS_DEF, 1073 "Command sequence error") }, 1074/* S */{SST(0x2C, 0x01, SS_DEF, 1075 "Too many windows specified") }, 1076/* S */{SST(0x2C, 0x02, SS_DEF, 1077 "Invalid combination of windows specified") }, 1078/* R */{SST(0x2C, 0x03, SS_DEF, 1079 "Current program area is not empty") }, 1080/* R */{SST(0x2C, 0x04, SS_DEF, 1081 "Current program area is empty") }, 1082/* T */{SST(0x2D, 0x00, SS_DEF, 1083 "Overwrite error on update in place") }, 1084/* DTLPWRSOMCAE */{SST(0x2F, 0x00, SS_DEF, 1085 "Commands cleared by another initiator") }, 1086/* DT WR OM */{SST(0x30, 0x00, SS_DEF, 1087 "Incompatible medium installed") }, 1088/* DT WR O */{SST(0x30, 0x01, SS_DEF, 1089 "Cannot read medium - unknown format") }, 1090/* DT WR O */{SST(0x30, 0x02, SS_DEF, 1091 "Cannot read medium - incompatible format") }, 1092/* DT */{SST(0x30, 0x03, SS_DEF, 1093 "Cleaning cartridge installed") }, 1094/* DT WR O */{SST(0x30, 0x04, SS_DEF, 1095 "Cannot write medium - unknown format") }, 1096/* DT WR O */{SST(0x30, 0x05, SS_DEF, 1097 "Cannot write medium - incompatible format") }, 1098/* DT W O */{SST(0x30, 0x06, SS_DEF, 1099 "Cannot format medium - incompatible medium") }, 1100/* DTL WRSOM AE */{SST(0x30, 0x07, SS_DEF, 1101 "Cleaning failure") }, 1102/* R */{SST(0x30, 0x08, SS_DEF, 1103 "Cannot write - application code mismatch") }, 1104/* R */{SST(0x30, 0x09, SS_DEF, 1105 "Current session not fixated for append") }, 1106/* DT WR O */{SST(0x31, 0x00, SS_DEF, 1107 "Medium format corrupted") }, 1108/* D L R O */{SST(0x31, 0x01, SS_DEF, 1109 "Format command failed") }, 1110/* D W O */{SST(0x32, 0x00, SS_DEF, 1111 "No defect spare location available") }, 1112/* D W O */{SST(0x32, 0x01, SS_DEF, 1113 "Defect list update failure") }, 1114/* T */{SST(0x33, 0x00, SS_DEF, 1115 "Tape length error") }, 1116/* DTLPWRSOMCAE */{SST(0x34, 0x00, SS_DEF, 1117 "Enclosure failure") }, 1118/* DTLPWRSOMCAE */{SST(0x35, 0x00, SS_DEF, 1119 "Enclosure services failure") }, 1120/* DTLPWRSOMCAE */{SST(0x35, 0x01, SS_DEF, 1121 "Unsupported enclosure function") }, 1122/* DTLPWRSOMCAE */{SST(0x35, 0x02, SS_DEF, 1123 "Enclosure services unavailable") }, 1124/* DTLPWRSOMCAE */{SST(0x35, 0x03, SS_DEF, 1125 "Enclosure services transfer failure") }, 1126/* DTLPWRSOMCAE */{SST(0x35, 0x04, SS_DEF, 1127 "Enclosure services transfer refused") }, 1128/* L */{SST(0x36, 0x00, SS_DEF, 1129 "Ribbon, ink, or toner failure") }, 1130/* DTL WRSOMCAE */{SST(0x37, 0x00, SS_DEF, 1131 "Rounded parameter") }, 1132/* DTL WRSOMCAE */{SST(0x39, 0x00, SS_DEF, 1133 "Saving parameters not supported") }, 1134/* DTL WRSOM */{SST(0x3A, 0x00, SS_NEDEF|ENXIO, 1135 "Medium not present") }, 1136/* DT WR OM */{SST(0x3A, 0x01, SS_NEDEF|ENXIO, 1137 "Medium not present - tray closed") }, 1138/* DT WR OM */{SST(0x3A, 0x02, SS_NEDEF|ENXIO, 1139 "Medium not present - tray open") }, 1140/* TL */{SST(0x3B, 0x00, SS_DEF, 1141 "Sequential positioning error") }, 1142/* T */{SST(0x3B, 0x01, SS_DEF, 1143 "Tape position error at beginning-of-medium") }, 1144/* T */{SST(0x3B, 0x02, SS_DEF, 1145 "Tape position error at end-of-medium") }, 1146/* L */{SST(0x3B, 0x03, SS_DEF, 1147 "Tape or electronic vertical forms unit not ready") }, 1148/* L */{SST(0x3B, 0x04, SS_DEF, 1149 "Slew failure") }, 1150/* L */{SST(0x3B, 0x05, SS_DEF, 1151 "Paper jam") }, 1152/* L */{SST(0x3B, 0x06, SS_DEF, 1153 "Failed to sense top-of-form") }, 1154/* L */{SST(0x3B, 0x07, SS_DEF, 1155 "Failed to sense bottom-of-form") }, 1156/* T */{SST(0x3B, 0x08, SS_DEF, 1157 "Reposition error") }, 1158/* S */{SST(0x3B, 0x09, SS_DEF, 1159 "Read past end of medium") }, 1160/* S */{SST(0x3B, 0x0A, SS_DEF, 1161 "Read past beginning of medium") }, 1162/* S */{SST(0x3B, 0x0B, SS_DEF, 1163 "Position past end of medium") }, 1164/* T S */{SST(0x3B, 0x0C, SS_DEF, 1165 "Position past beginning of medium") }, 1166/* DT WR OM */{SST(0x3B, 0x0D, SS_NEDEF|ENOSPC, 1167 "Medium destination element full") }, 1168/* DT WR OM */{SST(0x3B, 0x0E, SS_DEF, 1169 "Medium source element empty") }, 1170/* R */{SST(0x3B, 0x0F, SS_DEF, 1171 "End of medium reached") }, 1172/* DT WR OM */{SST(0x3B, 0x11, SS_DEF, 1173 "Medium magazine not accessible") }, 1174/* DT WR OM */{SST(0x3B, 0x12, SS_DEF, 1175 "Medium magazine removed") }, 1176/* DT WR OM */{SST(0x3B, 0x13, SS_DEF, 1177 "Medium magazine inserted") }, 1178/* DT WR OM */{SST(0x3B, 0x14, SS_DEF, 1179 "Medium magazine locked") }, 1180/* DT WR OM */{SST(0x3B, 0x15, SS_DEF, 1181 "Medium magazine unlocked") }, 1182/* DTLPWRSOMCAE */{SST(0x3D, 0x00, SS_DEF, 1183 "Invalid bits in identify message") }, 1184/* DTLPWRSOMCAE */{SST(0x3E, 0x00, SS_DEF, 1185 "Logical unit has not self-configured yet") }, 1186/* DTLPWRSOMCAE */{SST(0x3E, 0x01, SS_DEF, 1187 "Logical unit failure") }, 1188/* DTLPWRSOMCAE */{SST(0x3E, 0x02, SS_DEF, 1189 "Timeout on logical unit") }, 1190/* DTLPWRSOMCAE */{SST(0x3F, 0x00, SS_DEF, 1191 "Target operating conditions have changed") }, 1192/* DTLPWRSOMCAE */{SST(0x3F, 0x01, SS_DEF, 1193 "Microcode has been changed") }, 1194/* DTLPWRSOMC */{SST(0x3F, 0x02, SS_DEF, 1195 "Changed operating definition") }, 1196/* DTLPWRSOMCAE */{SST(0x3F, 0x03, SS_DEF, 1197 "Inquiry data has changed") }, 1198/* DT WR OMCAE */{SST(0x3F, 0x04, SS_DEF, 1199 "Component device attached") }, 1200/* DT WR OMCAE */{SST(0x3F, 0x05, SS_DEF, 1201 "Device identifier changed") }, 1202/* DT WR OMCAE */{SST(0x3F, 0x06, SS_DEF, 1203 "Redundancy group created or modified") }, 1204/* DT WR OMCAE */{SST(0x3F, 0x07, SS_DEF, 1205 "Redundancy group deleted") }, 1206/* DT WR OMCAE */{SST(0x3F, 0x08, SS_DEF, 1207 "Spare created or modified") }, 1208/* DT WR OMCAE */{SST(0x3F, 0x09, SS_DEF, 1209 "Spare deleted") }, 1210/* DT WR OMCAE */{SST(0x3F, 0x0A, SS_DEF, 1211 "Volume set created or modified") }, 1212/* DT WR OMCAE */{SST(0x3F, 0x0B, SS_DEF, 1213 "Volume set deleted") }, 1214/* DT WR OMCAE */{SST(0x3F, 0x0C, SS_DEF, 1215 "Volume set deassigned") }, 1216/* DT WR OMCAE */{SST(0x3F, 0x0D, SS_DEF, 1217 "Volume set reassigned") }, 1218/* D */{SST(0x40, 0x00, SS_DEF, 1219 "Ram failure") }, /* deprecated - use 40 NN instead */ 1220/* DTLPWRSOMCAE */{SST(0x40, 0x80, SS_DEF, 1221 "Diagnostic failure: ASCQ = Component ID") }, 1222/* DTLPWRSOMCAE */{SST(0x40, 0xFF, SS_DEF|SSQ_RANGE, 1223 NULL) },/* Range 0x80->0xFF */ 1224/* D */{SST(0x41, 0x00, SS_DEF, 1225 "Data path failure") }, /* deprecated - use 40 NN instead */ 1226/* D */{SST(0x42, 0x00, SS_DEF, 1227 "Power-on or self-test failure") }, /* deprecated - use 40 NN instead */ 1228/* DTLPWRSOMCAE */{SST(0x43, 0x00, SS_DEF, 1229 "Message error") }, 1230/* DTLPWRSOMCAE */{SST(0x44, 0x00, SS_DEF, 1231 "Internal target failure") }, 1232/* DTLPWRSOMCAE */{SST(0x45, 0x00, SS_DEF, 1233 "Select or reselect failure") }, 1234/* DTLPWRSOMC */{SST(0x46, 0x00, SS_DEF, 1235 "Unsuccessful soft reset") }, 1236/* DTLPWRSOMCAE */{SST(0x47, 0x00, SS_DEF, 1237 "SCSI parity error") }, 1238/* DTLPWRSOMCAE */{SST(0x48, 0x00, SS_DEF, 1239 "Initiator detected error message received") }, 1240/* DTLPWRSOMCAE */{SST(0x49, 0x00, SS_DEF, 1241 "Invalid message error") }, 1242/* DTLPWRSOMCAE */{SST(0x4A, 0x00, SS_DEF, 1243 "Command phase error") }, 1244/* DTLPWRSOMCAE */{SST(0x4B, 0x00, SS_DEF, 1245 "Data phase error") }, 1246/* DTLPWRSOMCAE */{SST(0x4C, 0x00, SS_DEF, 1247 "Logical unit failed self-configuration") }, 1248/* DTLPWRSOMCAE */{SST(0x4D, 0x00, SS_DEF, 1249 "Tagged overlapped commands: ASCQ = Queue tag ID") }, 1250/* DTLPWRSOMCAE */{SST(0x4D, 0xFF, SS_DEF|SSQ_RANGE, 1251 NULL)}, /* Range 0x00->0xFF */ 1252/* DTLPWRSOMCAE */{SST(0x4E, 0x00, SS_DEF, 1253 "Overlapped commands attempted") }, 1254/* T */{SST(0x50, 0x00, SS_DEF, 1255 "Write append error") }, 1256/* T */{SST(0x50, 0x01, SS_DEF, 1257 "Write append position error") }, 1258/* T */{SST(0x50, 0x02, SS_DEF, 1259 "Position error related to timing") }, 1260/* T O */{SST(0x51, 0x00, SS_DEF, 1261 "Erase failure") }, 1262/* T */{SST(0x52, 0x00, SS_DEF, 1263 "Cartridge fault") }, 1264/* DTL WRSOM */{SST(0x53, 0x00, SS_DEF, 1265 "Media load or eject failed") }, 1266/* T */{SST(0x53, 0x01, SS_DEF, 1267 "Unload tape failure") }, 1268/* DT WR OM */{SST(0x53, 0x02, SS_DEF, 1269 "Medium removal prevented") }, 1270/* P */{SST(0x54, 0x00, SS_DEF, 1271 "Scsi to host system interface failure") }, 1272/* P */{SST(0x55, 0x00, SS_DEF, 1273 "System resource failure") }, 1274/* D O */{SST(0x55, 0x01, SS_NEDEF|ENOSPC, 1275 "System buffer full") }, 1276/* R */{SST(0x57, 0x00, SS_DEF, 1277 "Unable to recover table-of-contents") }, 1278/* O */{SST(0x58, 0x00, SS_DEF, 1279 "Generation does not exist") }, 1280/* O */{SST(0x59, 0x00, SS_DEF, 1281 "Updated block read") }, 1282/* DTLPWRSOM */{SST(0x5A, 0x00, SS_DEF, 1283 "Operator request or state change input") }, 1284/* DT WR OM */{SST(0x5A, 0x01, SS_DEF, 1285 "Operator medium removal request") }, 1286/* DT W O */{SST(0x5A, 0x02, SS_DEF, 1287 "Operator selected write protect") }, 1288/* DT W O */{SST(0x5A, 0x03, SS_DEF, 1289 "Operator selected write permit") }, 1290/* DTLPWRSOM */{SST(0x5B, 0x00, SS_DEF, 1291 "Log exception") }, 1292/* DTLPWRSOM */{SST(0x5B, 0x01, SS_DEF, 1293 "Threshold condition met") }, 1294/* DTLPWRSOM */{SST(0x5B, 0x02, SS_DEF, 1295 "Log counter at maximum") }, 1296/* DTLPWRSOM */{SST(0x5B, 0x03, SS_DEF, 1297 "Log list codes exhausted") }, 1298/* D O */{SST(0x5C, 0x00, SS_DEF, 1299 "RPL status change") }, 1300/* D O */{SST(0x5C, 0x01, SS_NEDEF, 1301 "Spindles synchronized") }, 1302/* D O */{SST(0x5C, 0x02, SS_DEF, 1303 "Spindles not synchronized") }, 1304/* DTLPWRSOMCAE */{SST(0x5D, 0x00, SS_DEF, 1305 "Failure prediction threshold exceeded") }, 1306/* DTLPWRSOMCAE */{SST(0x5D, 0xFF, SS_DEF, 1307 "Failure prediction threshold exceeded (false)") }, 1308/* DTLPWRSO CA */{SST(0x5E, 0x00, SS_DEF, 1309 "Low power condition on") }, 1310/* DTLPWRSO CA */{SST(0x5E, 0x01, SS_DEF, 1311 "Idle condition activated by timer") }, 1312/* DTLPWRSO CA */{SST(0x5E, 0x02, SS_DEF, 1313 "Standby condition activated by timer") }, 1314/* DTLPWRSO CA */{SST(0x5E, 0x03, SS_DEF, 1315 "Idle condition activated by command") }, 1316/* DTLPWRSO CA */{SST(0x5E, 0x04, SS_DEF, 1317 "Standby condition activated by command") }, 1318/* S */{SST(0x60, 0x00, SS_DEF, 1319 "Lamp failure") }, 1320/* S */{SST(0x61, 0x00, SS_DEF, 1321 "Video acquisition error") }, 1322/* S */{SST(0x61, 0x01, SS_DEF, 1323 "Unable to acquire video") }, 1324/* S */{SST(0x61, 0x02, SS_DEF, 1325 "Out of focus") }, 1326/* S */{SST(0x62, 0x00, SS_DEF, 1327 "Scan head positioning error") }, 1328/* R */{SST(0x63, 0x00, SS_DEF, 1329 "End of user area encountered on this track") }, 1330/* R */{SST(0x63, 0x01, SS_NEDEF|ENOSPC, 1331 "Packet does not fit in available space") }, 1332/* R */{SST(0x64, 0x00, SS_DEF, 1333 "Illegal mode for this track") }, 1334/* R */{SST(0x64, 0x01, SS_DEF, 1335 "Invalid packet size") }, 1336/* DTLPWRSOMCAE */{SST(0x65, 0x00, SS_DEF, 1337 "Voltage fault") }, 1338/* S */{SST(0x66, 0x00, SS_DEF, 1339 "Automatic document feeder cover up") }, 1340/* S */{SST(0x66, 0x01, SS_DEF, 1341 "Automatic document feeder lift up") }, 1342/* S */{SST(0x66, 0x02, SS_DEF, 1343 "Document jam in automatic document feeder") }, 1344/* S */{SST(0x66, 0x03, SS_DEF, 1345 "Document miss feed automatic in document feeder") }, 1346/* A */{SST(0x67, 0x00, SS_DEF, 1347 "Configuration failure") }, 1348/* A */{SST(0x67, 0x01, SS_DEF, 1349 "Configuration of incapable logical units failed") }, 1350/* A */{SST(0x67, 0x02, SS_DEF, 1351 "Add logical unit failed") }, 1352/* A */{SST(0x67, 0x03, SS_DEF, 1353 "Modification of logical unit failed") }, 1354/* A */{SST(0x67, 0x04, SS_DEF, 1355 "Exchange of logical unit failed") }, 1356/* A */{SST(0x67, 0x05, SS_DEF, 1357 "Remove of logical unit failed") }, 1358/* A */{SST(0x67, 0x06, SS_DEF, 1359 "Attachment of logical unit failed") }, 1360/* A */{SST(0x67, 0x07, SS_DEF, 1361 "Creation of logical unit failed") }, 1362/* A */{SST(0x68, 0x00, SS_DEF, 1363 "Logical unit not configured") }, 1364/* A */{SST(0x69, 0x00, SS_DEF, 1365 "Data loss on logical unit") }, 1366/* A */{SST(0x69, 0x01, SS_DEF, 1367 "Multiple logical unit failures") }, 1368/* A */{SST(0x69, 0x02, SS_DEF, 1369 "Parity/data mismatch") }, 1370/* A */{SST(0x6A, 0x00, SS_DEF, 1371 "Informational, refer to log") }, 1372/* A */{SST(0x6B, 0x00, SS_DEF, 1373 "State change has occurred") }, 1374/* A */{SST(0x6B, 0x01, SS_DEF, 1375 "Redundancy level got better") }, 1376/* A */{SST(0x6B, 0x02, SS_DEF, 1377 "Redundancy level got worse") }, 1378/* A */{SST(0x6C, 0x00, SS_DEF, 1379 "Rebuild failure occurred") }, 1380/* A */{SST(0x6D, 0x00, SS_DEF, 1381 "Recalculate failure occurred") }, 1382/* A */{SST(0x6E, 0x00, SS_DEF, 1383 "Command to logical unit failed") }, 1384/* T */{SST(0x70, 0x00, SS_DEF, 1385 "Decompression exception short: ASCQ = Algorithm ID") }, 1386/* T */{SST(0x70, 0xFF, SS_DEF|SSQ_RANGE, 1387 NULL) }, /* Range 0x00 -> 0xFF */ 1388/* T */{SST(0x71, 0x00, SS_DEF, 1389 "Decompression exception long: ASCQ = Algorithm ID") }, 1390/* T */{SST(0x71, 0xFF, SS_DEF|SSQ_RANGE, 1391 NULL) }, /* Range 0x00 -> 0xFF */ 1392/* R */{SST(0x72, 0x00, SS_DEF, 1393 "Session fixation error") }, 1394/* R */{SST(0x72, 0x01, SS_DEF, 1395 "Session fixation error writing lead-in") }, 1396/* R */{SST(0x72, 0x02, SS_DEF, 1397 "Session fixation error writing lead-out") }, 1398/* R */{SST(0x72, 0x03, SS_DEF, 1399 "Session fixation error - incomplete track in session") }, 1400/* R */{SST(0x72, 0x04, SS_DEF, 1401 "Empty or partially written reserved track") }, 1402/* R */{SST(0x73, 0x00, SS_DEF, 1403 "CD control error") }, 1404/* R */{SST(0x73, 0x01, SS_DEF, 1405 "Power calibration area almost full") }, 1406/* R */{SST(0x73, 0x02, SS_NEDEF|ENOSPC, 1407 "Power calibration area is full") }, 1408/* R */{SST(0x73, 0x03, SS_DEF, 1409 "Power calibration area error") }, 1410/* R */{SST(0x73, 0x04, SS_DEF, 1411 "Program memory area update failure") }, 1412/* R */{SST(0x73, 0x05, SS_DEF, 1413 "program memory area is full") } 1414}; 1415 1416#if !defined(SCSI_NO_SENSE_STRINGS) 1417const char * 1418scsi_sense_desc(int asc, int ascq, struct scsi_inquiry_data *inq_data) 1419{ 1420 int i, j; 1421 caddr_t match; 1422 struct asc_table_entry *table[2]; 1423 int table_size[2]; 1424 int num_tables; 1425 1426 if (inq_data == NULL) 1427 return(NULL); 1428 1429 match = cam_quirkmatch((caddr_t)inq_data, 1430 (caddr_t)asc_quirk_table, 1431 sizeof(asc_quirk_table)/sizeof(*asc_quirk_table), 1432 sizeof(*asc_quirk_table), scsi_inquiry_match); 1433 1434 if (match != NULL) { 1435 table[0] = ((struct scsi_sense_quirk_entry *)match)->asc_info; 1436 table_size[0] = 1437 ((struct scsi_sense_quirk_entry *)match)->num_ascs; 1438 table[1] = asc_text; 1439 table_size[1] = sizeof(asc_text)/sizeof(asc_text[0]); 1440 num_tables = 2; 1441 } else { 1442 table[0] = asc_text; 1443 table_size[0] = sizeof(asc_text)/sizeof(asc_text[0]); 1444 num_tables = 1; 1445 } 1446 1447 for (j = 0; j < num_tables; j++) { 1448 for (i = 0; i < table_size[j]; i++) { 1449 if (table[j][i].asc == asc) { 1450 1451 /* Check for ranges */ 1452 if ((table[j][i].action & SSQ_RANGE) != 0) { 1453 1454 if (table[j][i].ascq >= ascq 1455 && table[j][i-1].ascq <= ascq) 1456 return table[j][i-1].desc; 1457 1458 continue; 1459 } 1460 1461 if (table[j][i].ascq == ascq) 1462 return table[j][i].desc; 1463 } 1464 } 1465 } 1466 1467 if (asc >= 0x80 && asc <= 0xff) 1468 return "Vendor Specific ASC"; 1469 1470 if (ascq >= 0x80 && ascq <= 0xff) 1471 return "Vendor Specific ASCQ"; 1472 1473 return "Reserved ASC/ASCQ pair"; 1474} 1475 1476#else /* SCSI_NO_SENSE_STRINGS */ 1477const char * 1478scsi_sense_desc(int asc, int ascq, struct scsi_inquiry_data *inq_data) 1479{ 1480 return (""); 1481} 1482#endif 1483 1484/* 1485 * Given a particular failed CCB and its device type information, return 1486 * the appropriate action from either the sense code quirk table or the 1487 * sense code table. 1488 */ 1489scsi_sense_action 1490scsi_error_action(int asc, int ascq, struct scsi_inquiry_data *inq_data) 1491{ 1492 caddr_t match; 1493 struct asc_table_entry *table[2]; 1494 int table_size[2]; 1495 int num_tables; 1496 int i, j; 1497 1498 /* 1499 * If we don't have inquiry data, we can't match against any quirk 1500 * entries. 1501 */ 1502 if (inq_data != NULL) { 1503 match = cam_quirkmatch((caddr_t)inq_data, 1504 (caddr_t)asc_quirk_table, 1505 sizeof(asc_quirk_table) / 1506 sizeof(*asc_quirk_table), 1507 sizeof(*asc_quirk_table), 1508 scsi_inquiry_match); 1509 } else 1510 match = NULL; 1511 1512 if (match != NULL) { 1513 table[0] = ((struct scsi_sense_quirk_entry *)match)->asc_info; 1514 table_size[0] = 1515 ((struct scsi_sense_quirk_entry *)match)->num_ascs; 1516 table[1] = asc_text; 1517 table_size[1] = sizeof(asc_text)/sizeof(asc_text[0]); 1518 num_tables = 2; 1519 } else { 1520 table[0] = asc_text; 1521 table_size[0] = sizeof(asc_text)/sizeof(asc_text[0]); 1522 num_tables = 1; 1523 } 1524 1525 for (j = 0; j < num_tables; j++) { 1526 for (i = 0; i < table_size[j]; i++) { 1527 if (table[j][i].asc == asc) { 1528 1529 /* Check for ranges */ 1530 if ((table[j][i].action & SSQ_RANGE) != 0){ 1531 1532 if (table[j][i].ascq >= ascq 1533 && table[j][i-1].ascq <= ascq) 1534 return table[j][i].action; 1535 1536 continue; 1537 } 1538 1539 /* 1540 * Check to see if we have a match. If the 1541 * current ascq in the table is greater 1542 * than our ascq, and there aren't any more 1543 * tables to search, just return the 1544 * default action. 1545 */ 1546 if (table[j][i].ascq == ascq) 1547 return(table[j][i].action); 1548 else if ((j == (num_tables - 1)) && 1549 (table[j][i].ascq > ascq)) 1550 return(SS_DEF); 1551 } 1552 } 1553 } 1554 /* 1555 * If we get to this point, it's most likely a vendor specific 1556 * ASC and we don't have a quirk entry for it. Oh well, we just 1557 * tell the error handling code to take the default action. 1558 */ 1559 return(SS_DEF); 1560} 1561 1562char * 1563scsi_cdb_string(u_int8_t *cdb_ptr, char *cdb_string) 1564{ 1565 u_int8_t cdb_len; 1566 char holdstr[8]; 1567 int i; 1568 1569 if (cdb_ptr == NULL) 1570 return(""); 1571 1572 /* Silence warnings */ 1573 cdb_len = 0; 1574 1575 /* 1576 * This is taken from the SCSI-3 draft spec. 1577 * (T10/1157D revision 0.3) 1578 * The top 3 bits of an opcode are the group code. The next 5 bits 1579 * are the command code. 1580 * Group 0: six byte commands 1581 * Group 1: ten byte commands 1582 * Group 2: ten byte commands 1583 * Group 3: reserved 1584 * Group 4: sixteen byte commands 1585 * Group 5: twelve byte commands 1586 * Group 6: vendor specific 1587 * Group 7: vendor specific 1588 */ 1589 switch((*cdb_ptr >> 5) & 0x7) { 1590 case 0: 1591 cdb_len = 6; 1592 break; 1593 case 1: 1594 case 2: 1595 cdb_len = 10; 1596 break; 1597 case 3: 1598 case 6: 1599 case 7: 1600 /* in this case, just print out the opcode */ 1601 cdb_len = 1; 1602 break; 1603 case 4: 1604 cdb_len = 16; 1605 break; 1606 case 5: 1607 cdb_len = 12; 1608 break; 1609 } 1610 *cdb_string = '\0'; 1611 for (i = 0; i < cdb_len; i++) { 1612 sprintf(holdstr, "%x ", cdb_ptr[i]); 1613 strcat(cdb_string, holdstr); 1614 } 1615 1616 return(cdb_string); 1617} 1618/* 1619 * scsi_sense_print will decode the sense data into human 1620 * readable form. Sense handlers can use this to generate 1621 * a report. 1622 */ 1623/* 1624 * Because scsi_sense_print() utilizes transport layer functions, it will 1625 * only work in the kernel. 1626 */ 1627#ifdef KERNEL 1628 1629void 1630scsi_sense_print(struct ccb_scsiio *csio) 1631{ 1632 struct scsi_sense_data *sense; 1633 u_int32_t info; 1634 int error_code; 1635 int sense_key; 1636 int asc, ascq; 1637 struct ccb_getdev cgd; 1638 u_int8_t command_print; 1639 1640 sense = &csio->sense_data; 1641 1642 /* 1643 * If the CDB is a physical address, we can't deal with it.. 1644 */ 1645 if ((csio->ccb_h.flags & CAM_CDB_PHYS) != 0) 1646 command_print = 0; 1647 else 1648 command_print = 1; 1649 1650 /* 1651 * Get the device information. 1652 */ 1653 xpt_setup_ccb(&cgd.ccb_h, 1654 csio->ccb_h.path, 1655 /*priority*/ 1); 1656 cgd.ccb_h.func_code = XPT_GDEV_TYPE; 1657 xpt_action((union ccb *)&cgd); 1658 1659 /* 1660 * If the device is unconfigured, just pretend that it is a hard 1661 * drive. scsi_op_desc() needs this. 1662 */ 1663 if (cgd.ccb_h.status == CAM_DEV_NOT_THERE) 1664 cgd.inq_data.device = T_DIRECT; 1665 1666 if (command_print != 0) { 1667 char cdb_str[(SCSI_MAX_CDBLEN * 3) + 1]; 1668 1669 xpt_print_path(csio->ccb_h.path); 1670 1671 if ((csio->ccb_h.flags & CAM_CDB_POINTER) != 0) { 1672 printf("%s. CDB: %s\n", 1673 scsi_op_desc(csio->cdb_io.cdb_ptr[0], 1674 &cgd.inq_data), 1675 scsi_cdb_string(csio->cdb_io.cdb_ptr, cdb_str)); 1676 } else { 1677 printf("%s. CDB: %s\n", 1678 scsi_op_desc(csio->cdb_io.cdb_bytes[0], 1679 &cgd.inq_data), scsi_cdb_string( 1680 (u_int8_t *)&csio->cdb_io.cdb_bytes, cdb_str)); 1681 } 1682 } 1683 1684 /* 1685 * If the sense data is a physical pointer, forget it. 1686 */ 1687 if (csio->ccb_h.flags & CAM_SENSE_PTR) { 1688 if (csio->ccb_h.flags & CAM_SENSE_PHYS) 1689 return; 1690 else { 1691 /* 1692 * XXX KDM this is stupid, but casting the 1693 * structure doesn't work... 1694 */ 1695 bcopy(&csio->sense_data, sense, 1696 sizeof(struct scsi_sense_data *)); 1697 } 1698 } else { 1699 /* 1700 * If the physical sense flag is set, but the sense pointer 1701 * is not also set, we assume that the user is an idiot and 1702 * return. (Well, okay, it could be that somehow, the 1703 * entire csio is physical, but we would have probably core 1704 * dumped on one of the bogus pointer deferences above 1705 * already.) 1706 */ 1707 if (csio->ccb_h.flags & CAM_SENSE_PHYS) 1708 return; 1709 else 1710 sense = &csio->sense_data; 1711 } 1712 1713 xpt_print_path(csio->ccb_h.path); 1714 error_code = sense->error_code & SSD_ERRCODE; 1715 sense_key = sense->flags & SSD_KEY; 1716 1717 switch (error_code) { 1718 case SSD_DEFERRED_ERROR: 1719 printf("Deferred Error: "); 1720 /* FALLTHROUGH */ 1721 case SSD_CURRENT_ERROR: 1722 1723 printf("%s", scsi_sense_key_text[sense_key]); 1724 info = scsi_4btoul(sense->info); 1725 1726 if (sense->error_code & SSD_ERRCODE_VALID) { 1727 1728 switch (sense_key) { 1729 case SSD_KEY_NOT_READY: 1730 case SSD_KEY_ILLEGAL_REQUEST: 1731 case SSD_KEY_UNIT_ATTENTION: 1732 case SSD_KEY_DATA_PROTECT: 1733 break; 1734 case SSD_KEY_BLANK_CHECK: 1735 printf(" req sz: %d (decimal)", 1736 info); 1737 break; 1738 default: 1739 if (info) { 1740 if (sense->flags & SSD_ILI) { 1741 printf(" ILI (length mismatch):" 1742 " %d", info); 1743 } else { 1744 printf(" info:%x", info); 1745 } 1746 } 1747 } 1748 } else if (info) 1749 printf(" info?:%x", info); 1750 1751 if (sense->extra_len >= 4) { 1752 if (bcmp(sense->cmd_spec_info, "\0\0\0\0", 4)) { 1753 printf(" csi:%x,%x,%x,%x", 1754 sense->cmd_spec_info[0], 1755 sense->cmd_spec_info[1], 1756 sense->cmd_spec_info[2], 1757 sense->cmd_spec_info[3]); 1758 } 1759 } 1760 1761 asc = (sense->extra_len >= 5) ? sense->add_sense_code : 0; 1762 ascq = (sense->extra_len >= 6) ? sense->add_sense_code_qual : 0; 1763 1764 if (asc || ascq) { 1765 const char *desc = scsi_sense_desc(asc, ascq, 1766 &cgd.inq_data); 1767 printf(" asc:%x,%x\n", asc, ascq); 1768 1769 xpt_print_path(csio->ccb_h.path); 1770 printf("%s", desc); 1771 } 1772 1773 if (sense->extra_len >= 7 && sense->fru) { 1774 printf(" field replaceable unit: %x", sense->fru); 1775 } 1776 1777 if ((sense->extra_len >= 10) 1778 && (sense->sense_key_spec[0] & SSD_SCS_VALID) != 0) { 1779 printf(" sks:%x,%x", sense->sense_key_spec[0], 1780 scsi_2btoul(&sense->sense_key_spec[1])); 1781 } 1782 break; 1783 1784 default: 1785 printf("error code %d", 1786 sense->error_code & SSD_ERRCODE); 1787 if (sense->error_code & SSD_ERRCODE_VALID) { 1788 printf(" at block no. %d (decimal)", 1789 info = scsi_4btoul(sense->info)); 1790 } 1791 } 1792 1793 printf("\n"); 1794} 1795 1796#else /* !KERNEL */ 1797 1798 1799char * 1800scsi_sense_string(struct cam_device *device, struct ccb_scsiio *csio, 1801 char *str, int str_len) 1802{ 1803 struct scsi_sense_data *sense; 1804 u_int32_t info; 1805 int error_code; 1806 int sense_key; 1807 int asc, ascq; 1808 u_int8_t command_print; 1809 char path_str[64]; 1810 char tmpstr[2048]; 1811 int tmpstrlen = 2048; 1812 int cur_len = 0, retlen; 1813 1814 if ((device == NULL) || (csio == NULL) || (str == NULL)) 1815 return(NULL); 1816 1817 if (str_len <= 0) 1818 return(NULL); 1819 1820 /* 1821 * If the CDB is a physical address, we can't deal with it.. 1822 */ 1823 if ((csio->ccb_h.flags & CAM_CDB_PHYS) != 0) 1824 command_print = 0; 1825 else 1826 command_print = 1; 1827 1828 cam_path_string(device, path_str, 64); 1829 1830 str[0] = '\0'; 1831 1832 sense = NULL; 1833 1834 if (command_print != 0) { 1835 char cdb_str[(SCSI_MAX_CDBLEN * 3) + 1]; 1836 1837 retlen = snprintf(tmpstr, tmpstrlen, "%s", path_str); 1838 1839 strncat(str, tmpstr, str_len - cur_len - 1); 1840 cur_len += retlen; 1841 1842 if ((csio->ccb_h.flags & CAM_CDB_POINTER) != 0) { 1843 retlen = snprintf(tmpstr, tmpstrlen, "%s. CDB: %s\n", 1844 scsi_op_desc(csio->cdb_io.cdb_ptr[0], 1845 &device->inq_data), 1846 scsi_cdb_string(csio->cdb_io.cdb_ptr, 1847 cdb_str)); 1848 } else { 1849 retlen = snprintf(tmpstr, tmpstrlen, "%s. CDB: %s\n", 1850 scsi_op_desc(csio->cdb_io.cdb_bytes[0], 1851 &device->inq_data), scsi_cdb_string( 1852 (u_int8_t *)&csio->cdb_io.cdb_bytes, cdb_str)); 1853 } 1854 strncat(str, tmpstr, str_len - cur_len - 1); 1855 cur_len += retlen; 1856 } 1857 1858 /* 1859 * If the sense data is a physical pointer, forget it. 1860 */ 1861 if (csio->ccb_h.flags & CAM_SENSE_PTR) { 1862 if (csio->ccb_h.flags & CAM_SENSE_PHYS) 1863 return(NULL); 1864 else { 1865 /* 1866 * XXX KDM this is stupid, but casting the 1867 * structure doesn't work... 1868 */ 1869 bcopy(&csio->sense_data, sense, 1870 sizeof(struct scsi_sense_data *)); 1871 } 1872 } else { 1873 /* 1874 * If the physical sense flag is set, but the sense pointer 1875 * is not also set, we assume that the user is an idiot and 1876 * return. (Well, okay, it could be that somehow, the 1877 * entire csio is physical, but we would have probably core 1878 * dumped on one of the bogus pointer deferences above 1879 * already.) 1880 */ 1881 if (csio->ccb_h.flags & CAM_SENSE_PHYS) 1882 return(NULL); 1883 else 1884 sense = &csio->sense_data; 1885 } 1886 1887 1888 retlen = snprintf(tmpstr, tmpstrlen, "%s", path_str); 1889 strncat(str, tmpstr, str_len - cur_len - 1); 1890 cur_len += retlen; 1891 1892 error_code = sense->error_code & SSD_ERRCODE; 1893 sense_key = sense->flags & SSD_KEY; 1894 1895 switch (error_code) { 1896 case SSD_DEFERRED_ERROR: 1897 retlen = snprintf(tmpstr, tmpstrlen, "Deferred Error: "); 1898 strncat(str, tmpstr, str_len - cur_len - 1); 1899 cur_len += retlen; 1900 /* FALLTHROUGH */ 1901 case SSD_CURRENT_ERROR: 1902 1903 retlen = snprintf(tmpstr, tmpstrlen, "%s", 1904 scsi_sense_key_text[sense_key]); 1905 strncat(str, tmpstr, str_len - cur_len - 1); 1906 cur_len += retlen; 1907 1908 info = scsi_4btoul(sense->info); 1909 1910 if (sense->error_code & SSD_ERRCODE_VALID) { 1911 1912 switch (sense_key) { 1913 case SSD_KEY_NOT_READY: 1914 case SSD_KEY_ILLEGAL_REQUEST: 1915 case SSD_KEY_UNIT_ATTENTION: 1916 case SSD_KEY_DATA_PROTECT: 1917 break; 1918 case SSD_KEY_BLANK_CHECK: 1919 retlen = snprintf(tmpstr, tmpstrlen, 1920 " req sz: %d (decimal)", 1921 info); 1922 strncat(str, tmpstr, str_len - cur_len - 1); 1923 cur_len += retlen; 1924 break; 1925 default: 1926 if (info) { 1927 if (sense->flags & SSD_ILI) { 1928 retlen = snprintf (tmpstr, 1929 tmpstrlen, 1930 " ILI (length " 1931 "mismatch): %d", info); 1932 1933 } else { 1934 retlen = snprintf(tmpstr, 1935 tmpstrlen, 1936 " info:%x", 1937 info); 1938 } 1939 strncat(str, tmpstr, 1940 str_len - cur_len - 1); 1941 cur_len += retlen; 1942 } 1943 } 1944 } else if (info) { 1945 retlen = snprintf(tmpstr, tmpstrlen," info?:%x", info); 1946 strncat(str, tmpstr, str_len - cur_len - 1); 1947 cur_len += retlen; 1948 } 1949 1950 if (sense->extra_len >= 4) { 1951 if (bcmp(sense->cmd_spec_info, "\0\0\0\0", 4)) { 1952 retlen = snprintf(tmpstr, tmpstrlen, 1953 " csi:%x,%x,%x,%x", 1954 sense->cmd_spec_info[0], 1955 sense->cmd_spec_info[1], 1956 sense->cmd_spec_info[2], 1957 sense->cmd_spec_info[3]); 1958 strncat(str, tmpstr, str_len - cur_len - 1); 1959 cur_len += retlen; 1960 } 1961 } 1962 1963 asc = (sense->extra_len >= 5) ? sense->add_sense_code : 0; 1964 ascq = (sense->extra_len >= 6) ? sense->add_sense_code_qual : 0; 1965 1966 if (asc || ascq) { 1967 const char *desc = scsi_sense_desc(asc, ascq, 1968 &device->inq_data); 1969 retlen = snprintf(tmpstr, tmpstrlen, 1970 " asc:%x,%x\n%s%s", asc, ascq, 1971 path_str, desc); 1972 strncat(str, tmpstr, str_len - cur_len - 1); 1973 cur_len += retlen; 1974 } 1975 1976 if (sense->extra_len >= 7 && sense->fru) { 1977 retlen = snprintf(tmpstr, tmpstrlen, 1978 " field replaceable unit: %x", 1979 sense->fru); 1980 strncat(str, tmpstr, str_len - cur_len - 1); 1981 cur_len += retlen; 1982 } 1983 1984 if ((sense->extra_len >= 10) 1985 && (sense->sense_key_spec[0] & SSD_SCS_VALID) != 0) { 1986 retlen = snprintf(tmpstr, tmpstrlen, " sks:%x,%x", 1987 sense->sense_key_spec[0], 1988 scsi_2btoul(&sense->sense_key_spec[1])); 1989 strncat(str, tmpstr, str_len - cur_len - 1); 1990 cur_len += retlen; 1991 } 1992 break; 1993 1994 default: 1995 retlen = snprintf(tmpstr, tmpstrlen, "error code %d", 1996 sense->error_code & SSD_ERRCODE); 1997 strncat(str, tmpstr, str_len - cur_len - 1); 1998 cur_len += retlen; 1999 2000 if (sense->error_code & SSD_ERRCODE_VALID) { 2001 retlen = snprintf(tmpstr, tmpstrlen, 2002 " at block no. %d (decimal)", 2003 info = scsi_4btoul(sense->info)); 2004 strncat(str, tmpstr, str_len - cur_len - 1); 2005 cur_len += retlen; 2006 } 2007 } 2008 2009 retlen = snprintf(tmpstr, tmpstrlen, "\n"); 2010 strncat(str, tmpstr, str_len - cur_len - 1); 2011 cur_len += retlen; 2012 2013 return(str); 2014} 2015 2016void 2017scsi_sense_print(struct cam_device *device, struct ccb_scsiio *csio, 2018 FILE *ofile) 2019{ 2020 char str[2048]; 2021 2022 if ((device == NULL) || (csio == NULL) || (ofile == NULL)) 2023 return; 2024 2025 fprintf(ofile, "%s", scsi_sense_string(device, csio, str, 2048)); 2026} 2027 2028#endif /* KERNEL/!KERNEL */ 2029 2030#ifdef KERNEL 2031int 2032scsi_interpret_sense(union ccb *ccb, u_int32_t sense_flags, 2033 u_int32_t *relsim_flags, u_int32_t *openings, 2034 u_int32_t *timeout, scsi_sense_action error_action) 2035#else 2036int 2037scsi_interpret_sense(struct cam_device *device, union ccb *ccb, 2038 u_int32_t sense_flags, u_int32_t *relsim_flags, 2039 u_int32_t *openings, u_int32_t *timeout, 2040 scsi_sense_action error_action) 2041#endif 2042{ 2043 struct scsi_sense_data *sense; 2044 int error_code, sense_key, asc, ascq; 2045 int error; 2046 int print_sense; 2047 struct ccb_scsiio *csio; 2048 int retry; 2049 2050 csio = &ccb->csio; 2051 sense = &csio->sense_data; 2052 scsi_extract_sense(sense, &error_code, &sense_key, &asc, &ascq); 2053 2054#ifdef KERNEL 2055 if ((sense_flags & SF_NO_PRINT) == 0 || bootverbose) 2056#else 2057 if ((sense_flags & SF_NO_PRINT) == 0) 2058#endif 2059 print_sense = TRUE; 2060 else 2061 print_sense = FALSE; 2062 2063 switch (error_code) { 2064 case SSD_DEFERRED_ERROR: 2065 { 2066 /* 2067 * XXX dufault@FreeBSD.org 2068 * This error doesn't relate to the command associated 2069 * with this request sense. A deferred error is an error 2070 * for a command that has already returned GOOD status 2071 * (see 8.2.14.2). 2072 * 2073 * By my reading of that section, it looks like the current 2074 * command has been cancelled, we should now clean things up 2075 * (hopefully recovering any lost data) and then retry the 2076 * current command. There are two easy choices, both wrong: 2077 * 2078 * 1. Drop through (like we had been doing), thus treating 2079 * this as if the error were for the current command and 2080 * return and stop the current command. 2081 * 2082 * 2. Issue a retry (like I made it do) thus hopefully 2083 * recovering the current transfer, and ignoring the 2084 * fact that we've dropped a command. 2085 * 2086 * These should probably be handled in a device specific 2087 * sense handler or punted back up to a user mode daemon 2088 */ 2089 2090 /* decrement the number of retries */ 2091 retry = ccb->ccb_h.retry_count > 0; 2092 if (retry) 2093 ccb->ccb_h.retry_count--; 2094 2095 error = ERESTART; 2096 break; 2097 } 2098 case SSD_CURRENT_ERROR: 2099 { 2100 2101 switch (sense_key) { 2102 case SSD_KEY_NO_SENSE: 2103 /* Why were we called then? Well don't bail now */ 2104 /* FALLTHROUGH */ 2105 case SSD_KEY_EQUAL: 2106 /* These should be filtered by the peripheral drivers */ 2107 /* FALLTHROUGH */ 2108 case SSD_KEY_MISCOMPARE: 2109 print_sense = FALSE; 2110 /* FALLTHROUGH */ 2111 case SSD_KEY_RECOVERED_ERROR: 2112 2113 /* decrement the number of retries */ 2114 retry = ccb->ccb_h.retry_count > 0; 2115 if (retry) 2116 ccb->ccb_h.retry_count--; 2117 2118 error = 0; 2119 break; 2120 case SSD_KEY_ILLEGAL_REQUEST: 2121 if ((sense_flags & SF_QUIET_IR) != 0) 2122 print_sense = FALSE; 2123 2124 /* FALLTHROUGH */ 2125 case SSD_KEY_NOT_READY: 2126 case SSD_KEY_DATA_PROTECT: 2127 case SSD_KEY_VOLUME_OVERFLOW: 2128 case SSD_KEY_BLANK_CHECK: /* should be filtered out by 2129 peripheral drivers */ 2130 retry = ccb->ccb_h.retry_count > 0; 2131 if (retry) 2132 ccb->ccb_h.retry_count--; 2133 2134 if ((error_action & SSQ_PRINT_SENSE) == 0) 2135 print_sense = FALSE; 2136 2137 error = error_action & SS_ERRMASK; 2138 2139 break; 2140 case SSD_KEY_UNIT_ATTENTION: 2141 /* 2142 * This should also be filtered out by 2143 * peripheral drivers since each has a different 2144 * concept of what it means to invalidate the media. 2145 */ 2146 if ((sense_flags & SF_RETRY_UA) != 0) { 2147 /* don't decrement retry count */ 2148 error = ERESTART; 2149 print_sense = FALSE; 2150 } else { 2151 /* decrement the number of retries */ 2152 retry = ccb->ccb_h.retry_count > 0; 2153 if (retry) 2154 ccb->ccb_h.retry_count--; 2155 2156 if ((error_action & SSQ_PRINT_SENSE) == 0) 2157 print_sense = FALSE; 2158 2159 error = error_action & SS_ERRMASK; 2160 } 2161 break; 2162 default: 2163 /* decrement the number of retries */ 2164 retry = ccb->ccb_h.retry_count > 0; 2165 if (retry) 2166 ccb->ccb_h.retry_count--; 2167 2168 if ((error_action & SSQ_PRINT_SENSE) == 0) 2169 print_sense = FALSE; 2170 2171 error = error_action & SS_ERRMASK; 2172 } 2173 break; 2174 } 2175 default: 2176 /* decrement the number of retries */ 2177 retry = ccb->ccb_h.retry_count > 0; 2178 if (retry) 2179 ccb->ccb_h.retry_count--; 2180 error =EIO; 2181 break; 2182 } 2183 2184 if (print_sense) { 2185#ifdef KERNEL 2186 scsi_sense_print(csio); 2187#else 2188 scsi_sense_print(device, csio, stdout); 2189#endif 2190 } 2191 2192 return (error); 2193} 2194 2195void 2196scsi_print_inquiry(struct scsi_inquiry_data *inq_data) 2197{ 2198 u_int8_t type; 2199 char *dtype, *qtype; 2200 char vendor[16], product[48], revision[16]; 2201 2202 type = SID_TYPE(inq_data); 2203 2204 /* 2205 * Figure out basic device type and qualifier. 2206 */ 2207 if (SID_QUAL_IS_VENDOR_UNIQUE(inq_data)) { 2208 qtype = "(vendor-unique qualifier)"; 2209 } else { 2210 switch (SID_QUAL(inq_data)) { 2211 case SID_QUAL_LU_CONNECTED: 2212 qtype = ""; 2213 break; 2214 2215 case SID_QUAL_LU_OFFLINE: 2216 qtype = "(offline)"; 2217 break; 2218 2219 case SID_QUAL_RSVD: 2220 qtype = "(reserved qualifier)"; 2221 break; 2222 default: 2223 case SID_QUAL_BAD_LU: 2224 qtype = "(lun not supported)"; 2225 break; 2226 } 2227 } 2228 2229 switch (type) { 2230 case T_DIRECT: 2231 dtype = "Direct Access"; 2232 break; 2233 case T_SEQUENTIAL: 2234 dtype = "Sequential Access"; 2235 break; 2236 case T_PRINTER: 2237 dtype = "Printer"; 2238 break; 2239 case T_PROCESSOR: 2240 dtype = "Processor"; 2241 break; 2242 case T_CDROM: 2243 dtype = "CD-ROM"; 2244 break; 2245 case T_WORM: 2246 dtype = "Worm"; 2247 break; 2248 case T_SCANNER: 2249 dtype = "Scanner"; 2250 break; 2251 case T_OPTICAL: 2252 dtype = "Optical"; 2253 break; 2254 case T_CHANGER: 2255 dtype = "Changer"; 2256 break; 2257 case T_COMM: 2258 dtype = "Communication"; 2259 break; 2260 case T_STORARRAY: 2261 dtype = "Storage Arrray"; 2262 break; 2263 case T_ENCLOSURE: 2264 dtype = "Enclosure Services"; 2265 break; 2266 case T_NODEVICE: 2267 dtype = "Uninstalled"; 2268 default: 2269 dtype = "unknown"; 2270 break; 2271 } 2272 2273 cam_strvis(vendor, inq_data->vendor, sizeof(inq_data->vendor), 2274 sizeof(vendor)); 2275 cam_strvis(product, inq_data->product, sizeof(inq_data->product), 2276 sizeof(product)); 2277 cam_strvis(revision, inq_data->revision, sizeof(inq_data->revision), 2278 sizeof(revision)); 2279 2280 printf("<%s %s %s> %s %s SCSI%d device %s\n", 2281 vendor, product, revision, 2282 SID_IS_REMOVABLE(inq_data) ? "Removable" : "Fixed", 2283 dtype, SID_ANSI_REV(inq_data), qtype); 2284} 2285 2286/* 2287 * Table of syncrates that don't follow the "divisible by 4" 2288 * rule. This table will be expanded in future SCSI specs. 2289 * I believe that FAST-40 has already been defined... 2290 */ 2291static struct { 2292 u_int period_factor; 2293 u_int period; /* in 10ths of ns */ 2294} scsi_syncrates[] = { 2295 { 0x0a, 250 }, 2296 { 0x0b, 303 }, 2297 { 0x0c, 500 } 2298}; 2299 2300/* 2301 * Return the frequency in kHz corresponding to the given 2302 * sync period factor. 2303 */ 2304u_int 2305scsi_calc_syncsrate(u_int period_factor) 2306{ 2307 int i; 2308 int num_syncrates; 2309 2310 num_syncrates = sizeof(scsi_syncrates) / sizeof(scsi_syncrates[0]); 2311 /* See if the period is in the "exception" table */ 2312 for (i = 0; i < num_syncrates; i++) { 2313 2314 if (period_factor == scsi_syncrates[i].period_factor) { 2315 /* Period in kHz */ 2316 return (10000000 / scsi_syncrates[i].period); 2317 } 2318 } 2319 2320 /* 2321 * Wasn't in the table, so use the standard 2322 * 4 times conversion. 2323 */ 2324 return (10000000 / (period_factor * 4 * 10)); 2325} 2326 2327/* 2328 * Return the SCSI sync parameter that corresponsd to 2329 * the passed in period in 10ths of ns. 2330 */ 2331u_int 2332scsi_calc_syncparam(u_int period) 2333{ 2334 int i; 2335 int num_syncrates; 2336 2337 if (period == 0) 2338 return (~0); /* Async */ 2339 2340 num_syncrates = sizeof(scsi_syncrates) / sizeof(scsi_syncrates[0]); 2341 /* See if the period is in the "exception" table */ 2342 for (i = 0; i < num_syncrates; i++) { 2343 2344 if (period <= scsi_syncrates[i].period) { 2345 /* Period in kHz */ 2346 return (scsi_syncrates[i].period_factor); 2347 } 2348 } 2349 2350 /* 2351 * Wasn't in the table, so use the standard 2352 * 1/4 period in ns conversion. 2353 */ 2354 return (period/40); 2355} 2356 2357void 2358scsi_test_unit_ready(struct ccb_scsiio *csio, u_int32_t retries, 2359 void (*cbfcnp)(struct cam_periph *, union ccb *), 2360 u_int8_t tag_action, u_int8_t sense_len, u_int32_t timeout) 2361{ 2362 struct scsi_test_unit_ready *scsi_cmd; 2363 2364 cam_fill_csio(csio, 2365 retries, 2366 cbfcnp, 2367 CAM_DIR_NONE, 2368 tag_action, 2369 /*data_ptr*/NULL, 2370 /*dxfer_len*/0, 2371 sense_len, 2372 sizeof(*scsi_cmd), 2373 timeout); 2374 2375 scsi_cmd = (struct scsi_test_unit_ready *)&csio->cdb_io.cdb_bytes; 2376 bzero(scsi_cmd, sizeof(*scsi_cmd)); 2377 scsi_cmd->opcode = TEST_UNIT_READY; 2378} 2379 2380void 2381scsi_request_sense(struct ccb_scsiio *csio, u_int32_t retries, 2382 void (*cbfcnp)(struct cam_periph *, union ccb *), 2383 void *data_ptr, u_int8_t dxfer_len, u_int8_t tag_action, 2384 u_int8_t sense_len, u_int32_t timeout) 2385{ 2386 struct scsi_request_sense *scsi_cmd; 2387 2388 cam_fill_csio(csio, 2389 retries, 2390 cbfcnp, 2391 CAM_DIR_IN, 2392 tag_action, 2393 data_ptr, 2394 dxfer_len, 2395 sense_len, 2396 sizeof(*scsi_cmd), 2397 timeout); 2398 2399 scsi_cmd = (struct scsi_request_sense *)&csio->cdb_io.cdb_bytes; 2400 bzero(scsi_cmd, sizeof(*scsi_cmd)); 2401 scsi_cmd->opcode = REQUEST_SENSE; 2402} 2403 2404void 2405scsi_inquiry(struct ccb_scsiio *csio, u_int32_t retries, 2406 void (*cbfcnp)(struct cam_periph *, union ccb *), 2407 u_int8_t tag_action, u_int8_t *inq_buf, u_int32_t inq_len, 2408 int evpd, u_int8_t page_code, u_int8_t sense_len, 2409 u_int32_t timeout) 2410{ 2411 struct scsi_inquiry *scsi_cmd; 2412 2413 cam_fill_csio(csio, 2414 retries, 2415 cbfcnp, 2416 /*flags*/CAM_DIR_IN, 2417 tag_action, 2418 /*data_ptr*/inq_buf, 2419 /*dxfer_len*/inq_len, 2420 sense_len, 2421 sizeof(*scsi_cmd), 2422 timeout); 2423 2424 scsi_cmd = (struct scsi_inquiry *)&csio->cdb_io.cdb_bytes; 2425 bzero(scsi_cmd, sizeof(*scsi_cmd)); 2426 scsi_cmd->opcode = INQUIRY; 2427 if (evpd) { 2428 scsi_cmd->byte2 |= SI_EVPD; 2429 scsi_cmd->page_code = page_code; 2430 } 2431 scsi_cmd->length = inq_len; 2432} 2433 2434void 2435scsi_mode_sense(struct ccb_scsiio *csio, u_int32_t retries, 2436 void (*cbfcnp)(struct cam_periph *, union ccb *), 2437 u_int8_t tag_action, int dbd, u_int8_t page_code, 2438 u_int8_t page, u_int8_t *param_buf, u_int32_t param_len, 2439 u_int8_t sense_len, u_int32_t timeout) 2440{ 2441 u_int8_t cdb_len; 2442 2443 /* 2444 * Use the smallest possible command to perform the operation. 2445 */ 2446 if (param_len < 256) { 2447 /* 2448 * We can fit in a 6 byte cdb. 2449 */ 2450 struct scsi_mode_sense_6 *scsi_cmd; 2451 2452 scsi_cmd = (struct scsi_mode_sense_6 *)&csio->cdb_io.cdb_bytes; 2453 bzero(scsi_cmd, sizeof(*scsi_cmd)); 2454 scsi_cmd->opcode = MODE_SENSE_6; 2455 if (dbd != 0) 2456 scsi_cmd->byte2 |= SMS_DBD; 2457 scsi_cmd->page = page_code | page; 2458 scsi_cmd->length = param_len; 2459 cdb_len = sizeof(*scsi_cmd); 2460 } else { 2461 /* 2462 * Need a 10 byte cdb. 2463 */ 2464 struct scsi_mode_sense_10 *scsi_cmd; 2465 2466 scsi_cmd = (struct scsi_mode_sense_10 *)&csio->cdb_io.cdb_bytes; 2467 bzero(scsi_cmd, sizeof(*scsi_cmd)); 2468 scsi_cmd->opcode = MODE_SENSE_10; 2469 if (dbd != 0) 2470 scsi_cmd->byte2 |= SMS_DBD; 2471 scsi_cmd->page = page_code | page; 2472 scsi_ulto2b(param_len, scsi_cmd->length); 2473 cdb_len = sizeof(*scsi_cmd); 2474 } 2475 cam_fill_csio(csio, 2476 retries, 2477 cbfcnp, 2478 CAM_DIR_IN, 2479 tag_action, 2480 param_buf, 2481 param_len, 2482 sense_len, 2483 cdb_len, 2484 timeout); 2485} 2486 2487void 2488scsi_mode_select(struct ccb_scsiio *csio, u_int32_t retries, 2489 void (*cbfcnp)(struct cam_periph *, union ccb *), 2490 u_int8_t tag_action, int scsi_page_fmt, int save_pages, 2491 u_int8_t *param_buf, u_int32_t param_len, u_int8_t sense_len, 2492 u_int32_t timeout) 2493{ 2494 u_int8_t cdb_len; 2495 2496 /* 2497 * Use the smallest possible command to perform the operation. 2498 */ 2499 if (param_len < 256) { 2500 /* 2501 * We can fit in a 6 byte cdb. 2502 */ 2503 struct scsi_mode_select_6 *scsi_cmd; 2504 2505 scsi_cmd = (struct scsi_mode_select_6 *)&csio->cdb_io.cdb_bytes; 2506 bzero(scsi_cmd, sizeof(*scsi_cmd)); 2507 scsi_cmd->opcode = MODE_SELECT_6; 2508 if (scsi_page_fmt != 0) 2509 scsi_cmd->byte2 |= SMS_PF; 2510 if (save_pages != 0) 2511 scsi_cmd->byte2 |= SMS_SP; 2512 scsi_cmd->length = param_len; 2513 cdb_len = sizeof(*scsi_cmd); 2514 } else { 2515 /* 2516 * Need a 10 byte cdb. 2517 */ 2518 struct scsi_mode_select_10 *scsi_cmd; 2519 2520 scsi_cmd = 2521 (struct scsi_mode_select_10 *)&csio->cdb_io.cdb_bytes; 2522 bzero(scsi_cmd, sizeof(*scsi_cmd)); 2523 scsi_cmd->opcode = MODE_SELECT_10; 2524 if (scsi_page_fmt != 0) 2525 scsi_cmd->byte2 |= SMS_PF; 2526 if (save_pages != 0) 2527 scsi_cmd->byte2 |= SMS_SP; 2528 scsi_ulto2b(param_len, scsi_cmd->length); 2529 cdb_len = sizeof(*scsi_cmd); 2530 } 2531 cam_fill_csio(csio, 2532 retries, 2533 cbfcnp, 2534 CAM_DIR_OUT, 2535 tag_action, 2536 param_buf, 2537 param_len, 2538 sense_len, 2539 cdb_len, 2540 timeout); 2541} 2542 2543 2544/* XXX allow specification of address and PMI bit and LBA */ 2545void 2546scsi_read_capacity(struct ccb_scsiio *csio, u_int32_t retries, 2547 void (*cbfcnp)(struct cam_periph *, union ccb *), 2548 u_int8_t tag_action, 2549 struct scsi_read_capacity_data *rcap_buf, 2550 u_int8_t sense_len, u_int32_t timeout) 2551{ 2552 struct scsi_read_capacity *scsi_cmd; 2553 2554 cam_fill_csio(csio, 2555 retries, 2556 cbfcnp, 2557 /*flags*/CAM_DIR_IN, 2558 tag_action, 2559 /*data_ptr*/(u_int8_t *)rcap_buf, 2560 /*dxfer_len*/sizeof(*rcap_buf), 2561 sense_len, 2562 sizeof(*scsi_cmd), 2563 timeout); 2564 2565 scsi_cmd = (struct scsi_read_capacity *)&csio->cdb_io.cdb_bytes; 2566 bzero(scsi_cmd, sizeof(*scsi_cmd)); 2567 scsi_cmd->opcode = READ_CAPACITY; 2568} 2569 2570/* 2571 * Prevent or allow the user to remove the media 2572 */ 2573void 2574scsi_prevent(struct ccb_scsiio *csio, u_int32_t retries, 2575 void (*cbfcnp)(struct cam_periph *, union ccb *), 2576 u_int8_t tag_action, u_int8_t action, 2577 u_int8_t sense_len, u_int32_t timeout) 2578{ 2579 struct scsi_prevent *scsi_cmd; 2580 2581 cam_fill_csio(csio, 2582 retries, 2583 cbfcnp, 2584 /*flags*/CAM_DIR_NONE, 2585 tag_action, 2586 /*data_ptr*/NULL, 2587 /*dxfer_len*/0, 2588 sense_len, 2589 sizeof(*scsi_cmd), 2590 timeout); 2591 2592 scsi_cmd = (struct scsi_prevent *)&csio->cdb_io.cdb_bytes; 2593 bzero(scsi_cmd, sizeof(*scsi_cmd)); 2594 scsi_cmd->opcode = PREVENT_ALLOW; 2595 scsi_cmd->how = action; 2596} 2597 2598/* 2599 * Syncronize the media to the contents of the cache for 2600 * the given lba/count pair. Specifying 0/0 means sync 2601 * the whole cache. 2602 */ 2603void 2604scsi_synchronize_cache(struct ccb_scsiio *csio, u_int32_t retries, 2605 void (*cbfcnp)(struct cam_periph *, union ccb *), 2606 u_int8_t tag_action, u_int32_t begin_lba, 2607 u_int16_t lb_count, u_int8_t sense_len, 2608 u_int32_t timeout) 2609{ 2610 struct scsi_sync_cache *scsi_cmd; 2611 2612 cam_fill_csio(csio, 2613 retries, 2614 cbfcnp, 2615 /*flags*/CAM_DIR_NONE, 2616 tag_action, 2617 /*data_ptr*/NULL, 2618 /*dxfer_len*/0, 2619 sense_len, 2620 sizeof(*scsi_cmd), 2621 timeout); 2622 2623 scsi_cmd = (struct scsi_sync_cache *)&csio->cdb_io.cdb_bytes; 2624 bzero(scsi_cmd, sizeof(*scsi_cmd)); 2625 scsi_cmd->opcode = SYNCHRONIZE_CACHE; 2626 scsi_ulto4b(begin_lba, scsi_cmd->begin_lba); 2627 scsi_ulto2b(lb_count, scsi_cmd->lb_count); 2628} 2629 2630void 2631scsi_read_write(struct ccb_scsiio *csio, u_int32_t retries, 2632 void (*cbfcnp)(struct cam_periph *, union ccb *), 2633 u_int8_t tag_action, int readop, u_int8_t byte2, 2634 int minimum_cmd_size, u_int32_t lba, u_int32_t block_count, 2635 u_int8_t *data_ptr, u_int32_t dxfer_len, u_int8_t sense_len, 2636 u_int32_t timeout) 2637{ 2638 u_int8_t cdb_len; 2639 /* 2640 * Use the smallest possible command to perform the operation 2641 * as some legacy hardware does not support the 10 byte 2642 * commands. If any of the lower 5 bits in byte2 is set, we have 2643 * to go with a larger command. 2644 * 2645 */ 2646 if ((minimum_cmd_size < 10) 2647 && ((lba & 0x1fffff) == lba) 2648 && ((block_count & 0xff) == block_count) 2649 && ((byte2 & 0xe0) == 0)) { 2650 /* 2651 * We can fit in a 6 byte cdb. 2652 */ 2653 struct scsi_rw_6 *scsi_cmd; 2654 2655 scsi_cmd = (struct scsi_rw_6 *)&csio->cdb_io.cdb_bytes; 2656 scsi_cmd->opcode = readop ? READ_6 : WRITE_6; 2657 scsi_ulto3b(lba, scsi_cmd->addr); 2658 scsi_cmd->length = block_count & 0xff; 2659 scsi_cmd->control = 0; 2660 cdb_len = sizeof(*scsi_cmd); 2661 2662 CAM_DEBUG(csio->ccb_h.path, CAM_DEBUG_SUBTRACE, 2663 ("6byte: %x%x%x:%d:%d\n", scsi_cmd->addr[0], 2664 scsi_cmd->addr[1], scsi_cmd->addr[2], 2665 scsi_cmd->length, dxfer_len)); 2666 } else if ((minimum_cmd_size < 12) 2667 && ((block_count & 0xffff) == block_count)) { 2668 /* 2669 * Need a 10 byte cdb. 2670 */ 2671 struct scsi_rw_10 *scsi_cmd; 2672 2673 scsi_cmd = (struct scsi_rw_10 *)&csio->cdb_io.cdb_bytes; 2674 scsi_cmd->opcode = readop ? READ_10 : WRITE_10; 2675 scsi_cmd->byte2 = byte2; 2676 scsi_ulto4b(lba, scsi_cmd->addr); 2677 scsi_cmd->reserved = 0; 2678 scsi_ulto2b(block_count, scsi_cmd->length); 2679 scsi_cmd->control = 0; 2680 cdb_len = sizeof(*scsi_cmd); 2681 2682 CAM_DEBUG(csio->ccb_h.path, CAM_DEBUG_SUBTRACE, 2683 ("10byte: %x%x%x%x:%x%x: %d\n", scsi_cmd->addr[0], 2684 scsi_cmd->addr[1], scsi_cmd->addr[2], 2685 scsi_cmd->addr[3], scsi_cmd->length[0], 2686 scsi_cmd->length[1], dxfer_len)); 2687 } else { 2688 /* 2689 * The block count is too big for a 10 byte CDB, use a 12 2690 * byte CDB. READ/WRITE(12) are currently only defined for 2691 * optical devices. 2692 */ 2693 struct scsi_rw_12 *scsi_cmd; 2694 2695 scsi_cmd = (struct scsi_rw_12 *)&csio->cdb_io.cdb_bytes; 2696 scsi_cmd->opcode = readop ? READ_12 : WRITE_12; 2697 scsi_cmd->byte2 = byte2; 2698 scsi_ulto4b(lba, scsi_cmd->addr); 2699 scsi_cmd->reserved = 0; 2700 scsi_ulto4b(block_count, scsi_cmd->length); 2701 scsi_cmd->control = 0; 2702 cdb_len = sizeof(*scsi_cmd); 2703 2704 CAM_DEBUG(csio->ccb_h.path, CAM_DEBUG_SUBTRACE, 2705 ("12byte: %x%x%x%x:%x%x%x%x: %d\n", scsi_cmd->addr[0], 2706 scsi_cmd->addr[1], scsi_cmd->addr[2], 2707 scsi_cmd->addr[3], scsi_cmd->length[0], 2708 scsi_cmd->length[1], scsi_cmd->length[2], 2709 scsi_cmd->length[3], dxfer_len)); 2710 } 2711 cam_fill_csio(csio, 2712 retries, 2713 cbfcnp, 2714 /*flags*/readop ? CAM_DIR_IN : CAM_DIR_OUT, 2715 tag_action, 2716 data_ptr, 2717 dxfer_len, 2718 sense_len, 2719 cdb_len, 2720 timeout); 2721} 2722 2723void 2724scsi_start_stop(struct ccb_scsiio *csio, u_int32_t retries, 2725 void (*cbfcnp)(struct cam_periph *, union ccb *), 2726 u_int8_t tag_action, int start, int load_eject, 2727 int immediate, u_int8_t sense_len, u_int32_t timeout) 2728{ 2729 struct scsi_start_stop_unit *scsi_cmd; 2730 int extra_flags = 0; 2731 2732 scsi_cmd = (struct scsi_start_stop_unit *)&csio->cdb_io.cdb_bytes; 2733 bzero(scsi_cmd, sizeof(*scsi_cmd)); 2734 scsi_cmd->opcode = START_STOP_UNIT; 2735 if (start != 0) { 2736 scsi_cmd->how |= SSS_START; 2737 /* it takes a lot of power to start a drive */ 2738 extra_flags |= CAM_HIGH_POWER; 2739 } 2740 if (load_eject != 0) 2741 scsi_cmd->how |= SSS_LOEJ; 2742 if (immediate != 0) 2743 scsi_cmd->byte2 |= SSS_IMMED; 2744 2745 cam_fill_csio(csio, 2746 retries, 2747 cbfcnp, 2748 /*flags*/CAM_DIR_NONE | extra_flags, 2749 tag_action, 2750 /*data_ptr*/NULL, 2751 /*dxfer_len*/0, 2752 sense_len, 2753 sizeof(*scsi_cmd), 2754 timeout); 2755 2756} 2757 2758 2759/* 2760 * Try make as good a match as possible with 2761 * available sub drivers 2762 */ 2763int 2764scsi_inquiry_match(caddr_t inqbuffer, caddr_t table_entry) 2765{ 2766 struct scsi_inquiry_pattern *entry; 2767 struct scsi_inquiry_data *inq; 2768 2769 entry = (struct scsi_inquiry_pattern *)table_entry; 2770 inq = (struct scsi_inquiry_data *)inqbuffer; 2771 2772 if (((SID_TYPE(inq) == entry->type) 2773 || (entry->type == T_ANY)) 2774 && (SID_IS_REMOVABLE(inq) ? entry->media_type & SIP_MEDIA_REMOVABLE 2775 : entry->media_type & SIP_MEDIA_FIXED) 2776 && (cam_strmatch(inq->vendor, entry->vendor, sizeof(inq->vendor)) == 0) 2777 && (cam_strmatch(inq->product, entry->product, 2778 sizeof(inq->product)) == 0) 2779 && (cam_strmatch(inq->revision, entry->revision, 2780 sizeof(inq->revision)) == 0)) { 2781 return (0); 2782 } 2783 return (-1); 2784} 2785 2786/* 2787 * Try make as good a match as possible with 2788 * available sub drivers 2789 */ 2790int 2791scsi_static_inquiry_match(caddr_t inqbuffer, caddr_t table_entry) 2792{ 2793 struct scsi_static_inquiry_pattern *entry; 2794 struct scsi_inquiry_data *inq; 2795 2796 entry = (struct scsi_static_inquiry_pattern *)table_entry; 2797 inq = (struct scsi_inquiry_data *)inqbuffer; 2798 2799 if (((SID_TYPE(inq) == entry->type) 2800 || (entry->type == T_ANY)) 2801 && (SID_IS_REMOVABLE(inq) ? entry->media_type & SIP_MEDIA_REMOVABLE 2802 : entry->media_type & SIP_MEDIA_FIXED) 2803 && (cam_strmatch(inq->vendor, entry->vendor, sizeof(inq->vendor)) == 0) 2804 && (cam_strmatch(inq->product, entry->product, 2805 sizeof(inq->product)) == 0) 2806 && (cam_strmatch(inq->revision, entry->revision, 2807 sizeof(inq->revision)) == 0)) { 2808 return (0); 2809 } 2810 return (-1); 2811} 2812