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