linux/drivers/scsi/aic7xxx/aiclib.c
<<
>>
Prefs
   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: src/sys/cam/scsi/scsi_all.c,v 1.38 2002/09/23 04:56:35 mjacob Exp $
  30 * $Id$
  31 */
  32
  33#include <linux/blkdev.h>
  34#include <linux/delay.h>
  35#include <linux/version.h>
  36
  37/* Core SCSI definitions */
  38#include "scsi.h"
  39#include <scsi/scsi_host.h>
  40#include "aiclib.h"
  41#include "cam.h"
  42
  43#ifndef FALSE
  44#define FALSE   0
  45#endif /* FALSE */
  46#ifndef TRUE
  47#define TRUE    1
  48#endif /* TRUE */
  49#ifndef ERESTART
  50#define ERESTART        -1              /* restart syscall */
  51#endif
  52#ifndef EJUSTRETURN
  53#define EJUSTRETURN     -2              /* don't modify regs, just return */
  54#endif
  55
  56static int      ascentrycomp(const void *key, const void *member);
  57static int      senseentrycomp(const void *key, const void *member);
  58static void     fetchtableentries(int sense_key, int asc, int ascq,
  59                                  struct scsi_inquiry_data *,
  60                                  const struct sense_key_table_entry **,
  61                                  const struct asc_table_entry **);
  62static void *   scsibsearch(const void *key, const void *base, size_t nmemb,
  63                            size_t size,
  64                            int (*compar)(const void *, const void *));
  65typedef int (cam_quirkmatch_t)(caddr_t, caddr_t);
  66static int      cam_strmatch(const u_int8_t *str, const u_int8_t *pattern,
  67                             int str_len);
  68static caddr_t  cam_quirkmatch(caddr_t target, caddr_t quirk_table,
  69                               int num_entries, int entry_size,
  70                               cam_quirkmatch_t *comp_func);
  71
  72#define SCSI_NO_SENSE_STRINGS 1
  73#if !defined(SCSI_NO_SENSE_STRINGS)
  74#define SST(asc, ascq, action, desc) \
  75        asc, ascq, action, desc
  76#else 
  77static const char empty_string[] = "";
  78
  79#define SST(asc, ascq, action, desc) \
  80        asc, ascq, action, empty_string
  81#endif 
  82
  83static const struct sense_key_table_entry sense_key_table[] = 
  84{
  85        { SSD_KEY_NO_SENSE, SS_NOP, "NO SENSE" },
  86        { SSD_KEY_RECOVERED_ERROR, SS_NOP|SSQ_PRINT_SENSE, "RECOVERED ERROR" },
  87        {
  88          SSD_KEY_NOT_READY, SS_TUR|SSQ_MANY|SSQ_DECREMENT_COUNT|EBUSY,
  89          "NOT READY"
  90        },
  91        { SSD_KEY_MEDIUM_ERROR, SS_RDEF, "MEDIUM ERROR" },
  92        { SSD_KEY_HARDWARE_ERROR, SS_RDEF, "HARDWARE FAILURE" },
  93        { SSD_KEY_ILLEGAL_REQUEST, SS_FATAL|EINVAL, "ILLEGAL REQUEST" },
  94        { SSD_KEY_UNIT_ATTENTION, SS_FATAL|ENXIO, "UNIT ATTENTION" },
  95        { SSD_KEY_DATA_PROTECT, SS_FATAL|EACCES, "DATA PROTECT" },
  96        { SSD_KEY_BLANK_CHECK, SS_FATAL|ENOSPC, "BLANK CHECK" },
  97        { SSD_KEY_Vendor_Specific, SS_FATAL|EIO, "Vendor Specific" },
  98        { SSD_KEY_COPY_ABORTED, SS_FATAL|EIO, "COPY ABORTED" },
  99        { SSD_KEY_ABORTED_COMMAND, SS_RDEF, "ABORTED COMMAND" },
 100        { SSD_KEY_EQUAL, SS_NOP, "EQUAL" },
 101        { SSD_KEY_VOLUME_OVERFLOW, SS_FATAL|EIO, "VOLUME OVERFLOW" },
 102        { SSD_KEY_MISCOMPARE, SS_NOP, "MISCOMPARE" },
 103        { SSD_KEY_RESERVED, SS_FATAL|EIO, "RESERVED" }
 104};
 105
 106static const int sense_key_table_size =
 107    sizeof(sense_key_table)/sizeof(sense_key_table[0]);
 108
 109static struct asc_table_entry quantum_fireball_entries[] = {
 110        {SST(0x04, 0x0b, SS_START|SSQ_DECREMENT_COUNT|ENXIO, 
 111             "Logical unit not ready, initializing cmd. required")}
 112};
 113
 114static struct asc_table_entry sony_mo_entries[] = {
 115        {SST(0x04, 0x00, SS_START|SSQ_DECREMENT_COUNT|ENXIO,
 116             "Logical unit not ready, cause not reportable")}
 117};
 118
 119static struct scsi_sense_quirk_entry sense_quirk_table[] = {
 120        {
 121                /*
 122                 * The Quantum Fireball ST and SE like to return 0x04 0x0b when
 123                 * they really should return 0x04 0x02.  0x04,0x0b isn't
 124                 * defined in any SCSI spec, and it isn't mentioned in the
 125                 * hardware manual for these drives.
 126                 */
 127                {T_DIRECT, SIP_MEDIA_FIXED, "QUANTUM", "FIREBALL S*", "*"},
 128                /*num_sense_keys*/0,
 129                sizeof(quantum_fireball_entries)/sizeof(struct asc_table_entry),
 130                /*sense key entries*/NULL,
 131                quantum_fireball_entries
 132        },
 133        {
 134                /*
 135                 * This Sony MO drive likes to return 0x04, 0x00 when it
 136                 * isn't spun up.
 137                 */
 138                {T_DIRECT, SIP_MEDIA_REMOVABLE, "SONY", "SMO-*", "*"},
 139                /*num_sense_keys*/0,
 140                sizeof(sony_mo_entries)/sizeof(struct asc_table_entry),
 141                /*sense key entries*/NULL,
 142                sony_mo_entries
 143        }
 144};
 145
 146static const int sense_quirk_table_size =
 147    sizeof(sense_quirk_table)/sizeof(sense_quirk_table[0]);
 148
 149static struct asc_table_entry asc_table[] = {
 150/*
 151 * From File: ASC-NUM.TXT
 152 * SCSI ASC/ASCQ Assignments
 153 * Numeric Sorted Listing
 154 * as of  5/12/97
 155 *
 156 * D - DIRECT ACCESS DEVICE (SBC)                     device column key
 157 * .T - SEQUENTIAL ACCESS DEVICE (SSC)               -------------------
 158 * . L - PRINTER DEVICE (SSC)                           blank = reserved
 159 * .  P - PROCESSOR DEVICE (SPC)                     not blank = allowed
 160 * .  .W - WRITE ONCE READ MULTIPLE DEVICE (SBC)
 161 * .  . R - CD DEVICE (MMC)
 162 * .  .  S - SCANNER DEVICE (SGC)
 163 * .  .  .O - OPTICAL MEMORY DEVICE (SBC)
 164 * .  .  . M - MEDIA CHANGER DEVICE (SMC)
 165 * .  .  .  C - COMMUNICATION DEVICE (SSC)
 166 * .  .  .  .A - STORAGE ARRAY DEVICE (SCC)
 167 * .  .  .  . E - ENCLOSURE SERVICES DEVICE (SES)
 168 * DTLPWRSOMCAE        ASC   ASCQ  Action  Description
 169 * ------------        ----  ----  ------  -----------------------------------*/
 170/* DTLPWRSOMCAE */{SST(0x00, 0x00, SS_NOP,
 171                        "No additional sense information") },
 172/*  T    S      */{SST(0x00, 0x01, SS_RDEF,
 173                        "Filemark detected") },
 174/*  T    S      */{SST(0x00, 0x02, SS_RDEF,
 175                        "End-of-partition/medium detected") },
 176/*  T           */{SST(0x00, 0x03, SS_RDEF,
 177                        "Setmark detected") },
 178/*  T    S      */{SST(0x00, 0x04, SS_RDEF,
 179                        "Beginning-of-partition/medium detected") },
 180/*  T    S      */{SST(0x00, 0x05, SS_RDEF,
 181                        "End-of-data detected") },
 182/* DTLPWRSOMCAE */{SST(0x00, 0x06, SS_RDEF,
 183                        "I/O process terminated") },
 184/*      R       */{SST(0x00, 0x11, SS_FATAL|EBUSY,
 185                        "Audio play operation in progress") },
 186/*      R       */{SST(0x00, 0x12, SS_NOP,
 187                        "Audio play operation paused") },
 188/*      R       */{SST(0x00, 0x13, SS_NOP,
 189                        "Audio play operation successfully completed") },
 190/*      R       */{SST(0x00, 0x14, SS_RDEF,
 191                        "Audio play operation stopped due to error") },
 192/*      R       */{SST(0x00, 0x15, SS_NOP,
 193                        "No current audio status to return") },
 194/* DTLPWRSOMCAE */{SST(0x00, 0x16, SS_FATAL|EBUSY,
 195                        "Operation in progress") },
 196/* DTL WRSOM AE */{SST(0x00, 0x17, SS_RDEF,
 197                        "Cleaning requested") },
 198/* D   W  O     */{SST(0x01, 0x00, SS_RDEF,
 199                        "No index/sector signal") },
 200/* D   WR OM    */{SST(0x02, 0x00, SS_RDEF,
 201                        "No seek complete") },
 202/* DTL W SO     */{SST(0x03, 0x00, SS_RDEF,
 203                        "Peripheral device write fault") },
 204/*  T           */{SST(0x03, 0x01, SS_RDEF,
 205                        "No write current") },
 206/*  T           */{SST(0x03, 0x02, SS_RDEF,
 207                        "Excessive write errors") },
 208/* DTLPWRSOMCAE */{SST(0x04, 0x00,
 209                        SS_TUR|SSQ_DELAY|SSQ_MANY|SSQ_DECREMENT_COUNT|EIO,
 210                        "Logical unit not ready, cause not reportable") },
 211/* DTLPWRSOMCAE */{SST(0x04, 0x01,
 212                        SS_TUR|SSQ_DELAY|SSQ_MANY|SSQ_DECREMENT_COUNT|EBUSY,
 213                        "Logical unit is in process of becoming ready") },
 214/* DTLPWRSOMCAE */{SST(0x04, 0x02, SS_START|SSQ_DECREMENT_COUNT|ENXIO,
 215                        "Logical unit not ready, initializing cmd. required") },
 216/* DTLPWRSOMCAE */{SST(0x04, 0x03, SS_FATAL|ENXIO,
 217                        "Logical unit not ready, manual intervention required")},
 218/* DTL    O     */{SST(0x04, 0x04, SS_FATAL|EBUSY,
 219                        "Logical unit not ready, format in progress") },
 220/* DT  W  OMCA  */{SST(0x04, 0x05, SS_FATAL|EBUSY,
 221                        "Logical unit not ready, rebuild in progress") },
 222/* DT  W  OMCA  */{SST(0x04, 0x06, SS_FATAL|EBUSY,
 223                        "Logical unit not ready, recalculation in progress") },
 224/* DTLPWRSOMCAE */{SST(0x04, 0x07, SS_FATAL|EBUSY,
 225                        "Logical unit not ready, operation in progress") },
 226/*      R       */{SST(0x04, 0x08, SS_FATAL|EBUSY,
 227                        "Logical unit not ready, long write in progress") },
 228/* DTL WRSOMCAE */{SST(0x05, 0x00, SS_RDEF,
 229                        "Logical unit does not respond to selection") },
 230/* D   WR OM    */{SST(0x06, 0x00, SS_RDEF,
 231                        "No reference position found") },
 232/* DTL WRSOM    */{SST(0x07, 0x00, SS_RDEF,
 233                        "Multiple peripheral devices selected") },
 234/* DTL WRSOMCAE */{SST(0x08, 0x00, SS_RDEF,
 235                        "Logical unit communication failure") },
 236/* DTL WRSOMCAE */{SST(0x08, 0x01, SS_RDEF,
 237                        "Logical unit communication time-out") },
 238/* DTL WRSOMCAE */{SST(0x08, 0x02, SS_RDEF,
 239                        "Logical unit communication parity error") },
 240/* DT   R OM    */{SST(0x08, 0x03, SS_RDEF,
 241                        "Logical unit communication crc error (ultra-dma/32)")},
 242/* DT  WR O     */{SST(0x09, 0x00, SS_RDEF,
 243                        "Track following error") },
 244/*     WR O     */{SST(0x09, 0x01, SS_RDEF,
 245                        "Tracking servo failure") },
 246/*     WR O     */{SST(0x09, 0x02, SS_RDEF,
 247                        "Focus servo failure") },
 248/*     WR O     */{SST(0x09, 0x03, SS_RDEF,
 249                        "Spindle servo failure") },
 250/* DT  WR O     */{SST(0x09, 0x04, SS_RDEF,
 251                        "Head select fault") },
 252/* DTLPWRSOMCAE */{SST(0x0A, 0x00, SS_FATAL|ENOSPC,
 253                        "Error log overflow") },
 254/* DTLPWRSOMCAE */{SST(0x0B, 0x00, SS_RDEF,
 255                        "Warning") },
 256/* DTLPWRSOMCAE */{SST(0x0B, 0x01, SS_RDEF,
 257                        "Specified temperature exceeded") },
 258/* DTLPWRSOMCAE */{SST(0x0B, 0x02, SS_RDEF,
 259                        "Enclosure degraded") },
 260/*  T   RS      */{SST(0x0C, 0x00, SS_RDEF,
 261                        "Write error") },
 262/* D   W  O     */{SST(0x0C, 0x01, SS_NOP|SSQ_PRINT_SENSE,
 263                        "Write error - recovered with auto reallocation") },
 264/* D   W  O     */{SST(0x0C, 0x02, SS_RDEF,
 265                        "Write error - auto reallocation failed") },
 266/* D   W  O     */{SST(0x0C, 0x03, SS_RDEF,
 267                        "Write error - recommend reassignment") },
 268/* DT  W  O     */{SST(0x0C, 0x04, SS_RDEF,
 269                        "Compression check miscompare error") },
 270/* DT  W  O     */{SST(0x0C, 0x05, SS_RDEF,
 271                        "Data expansion occurred during compression") },
 272/* DT  W  O     */{SST(0x0C, 0x06, SS_RDEF,
 273                        "Block not compressible") },
 274/*      R       */{SST(0x0C, 0x07, SS_RDEF,
 275                        "Write error - recovery needed") },
 276/*      R       */{SST(0x0C, 0x08, SS_RDEF,
 277                        "Write error - recovery failed") },
 278/*      R       */{SST(0x0C, 0x09, SS_RDEF,
 279                        "Write error - loss of streaming") },
 280/*      R       */{SST(0x0C, 0x0A, SS_RDEF,
 281                        "Write error - padding blocks added") },
 282/* D   W  O     */{SST(0x10, 0x00, SS_RDEF,
 283                        "ID CRC or ECC error") },
 284/* DT  WRSO     */{SST(0x11, 0x00, SS_RDEF,
 285                        "Unrecovered read error") },
 286/* DT  W SO     */{SST(0x11, 0x01, SS_RDEF,
 287                        "Read retries exhausted") },
 288/* DT  W SO     */{SST(0x11, 0x02, SS_RDEF,
 289                        "Error too long to correct") },
 290/* DT  W SO     */{SST(0x11, 0x03, SS_RDEF,
 291                        "Multiple read errors") },
 292/* D   W  O     */{SST(0x11, 0x04, SS_RDEF,
 293                        "Unrecovered read error - auto reallocate failed") },
 294/*     WR O     */{SST(0x11, 0x05, SS_RDEF,
 295                        "L-EC uncorrectable error") },
 296/*     WR O     */{SST(0x11, 0x06, SS_RDEF,
 297                        "CIRC unrecovered error") },
 298/*     W  O     */{SST(0x11, 0x07, SS_RDEF,
 299                        "Data re-synchronization error") },
 300/*  T           */{SST(0x11, 0x08, SS_RDEF,
 301                        "Incomplete block read") },
 302/*  T           */{SST(0x11, 0x09, SS_RDEF,
 303                        "No gap found") },
 304/* DT     O     */{SST(0x11, 0x0A, SS_RDEF,
 305                        "Miscorrected error") },
 306/* D   W  O     */{SST(0x11, 0x0B, SS_RDEF,
 307                        "Unrecovered read error - recommend reassignment") },
 308/* D   W  O     */{SST(0x11, 0x0C, SS_RDEF,
 309                        "Unrecovered read error - recommend rewrite the data")},
 310/* DT  WR O     */{SST(0x11, 0x0D, SS_RDEF,
 311                        "De-compression CRC error") },
 312/* DT  WR O     */{SST(0x11, 0x0E, SS_RDEF,
 313                        "Cannot decompress using declared algorithm") },
 314/*      R       */{SST(0x11, 0x0F, SS_RDEF,
 315                        "Error reading UPC/EAN number") },
 316/*      R       */{SST(0x11, 0x10, SS_RDEF,
 317                        "Error reading ISRC number") },
 318/*      R       */{SST(0x11, 0x11, SS_RDEF,
 319                        "Read error - loss of streaming") },
 320/* D   W  O     */{SST(0x12, 0x00, SS_RDEF,
 321                        "Address mark not found for id field") },
 322/* D   W  O     */{SST(0x13, 0x00, SS_RDEF,
 323                        "Address mark not found for data field") },
 324/* DTL WRSO     */{SST(0x14, 0x00, SS_RDEF,
 325                        "Recorded entity not found") },
 326/* DT  WR O     */{SST(0x14, 0x01, SS_RDEF,
 327                        "Record not found") },
 328/*  T           */{SST(0x14, 0x02, SS_RDEF,
 329                        "Filemark or setmark not found") },
 330/*  T           */{SST(0x14, 0x03, SS_RDEF,
 331                        "End-of-data not found") },
 332/*  T           */{SST(0x14, 0x04, SS_RDEF,
 333                        "Block sequence error") },
 334/* DT  W  O     */{SST(0x14, 0x05, SS_RDEF,
 335                        "Record not found - recommend reassignment") },
 336/* DT  W  O     */{SST(0x14, 0x06, SS_RDEF,
 337                        "Record not found - data auto-reallocated") },
 338/* DTL WRSOM    */{SST(0x15, 0x00, SS_RDEF,
 339                        "Random positioning error") },
 340/* DTL WRSOM    */{SST(0x15, 0x01, SS_RDEF,
 341                        "Mechanical positioning error") },
 342/* DT  WR O     */{SST(0x15, 0x02, SS_RDEF,
 343                        "Positioning error detected by read of medium") },
 344/* D   W  O     */{SST(0x16, 0x00, SS_RDEF,
 345                        "Data synchronization mark error") },
 346/* D   W  O     */{SST(0x16, 0x01, SS_RDEF,
 347                        "Data sync error - data rewritten") },
 348/* D   W  O     */{SST(0x16, 0x02, SS_RDEF,
 349                        "Data sync error - recommend rewrite") },
 350/* D   W  O     */{SST(0x16, 0x03, SS_NOP|SSQ_PRINT_SENSE,
 351                        "Data sync error - data auto-reallocated") },
 352/* D   W  O     */{SST(0x16, 0x04, SS_RDEF,
 353                        "Data sync error - recommend reassignment") },
 354/* DT  WRSO     */{SST(0x17, 0x00, SS_NOP|SSQ_PRINT_SENSE,
 355                        "Recovered data with no error correction applied") },
 356/* DT  WRSO     */{SST(0x17, 0x01, SS_NOP|SSQ_PRINT_SENSE,
 357                        "Recovered data with retries") },
 358/* DT  WR O     */{SST(0x17, 0x02, SS_NOP|SSQ_PRINT_SENSE,
 359                        "Recovered data with positive head offset") },
 360/* DT  WR O     */{SST(0x17, 0x03, SS_NOP|SSQ_PRINT_SENSE,
 361                        "Recovered data with negative head offset") },
 362/*     WR O     */{SST(0x17, 0x04, SS_NOP|SSQ_PRINT_SENSE,
 363                        "Recovered data with retries and/or CIRC applied") },
 364/* D   WR O     */{SST(0x17, 0x05, SS_NOP|SSQ_PRINT_SENSE,
 365                        "Recovered data using previous sector id") },
 366/* D   W  O     */{SST(0x17, 0x06, SS_NOP|SSQ_PRINT_SENSE,
 367                        "Recovered data without ECC - data auto-reallocated") },
 368/* D   W  O     */{SST(0x17, 0x07, SS_NOP|SSQ_PRINT_SENSE,
 369                        "Recovered data without ECC - recommend reassignment")},
 370/* D   W  O     */{SST(0x17, 0x08, SS_NOP|SSQ_PRINT_SENSE,
 371                        "Recovered data without ECC - recommend rewrite") },
 372/* D   W  O     */{SST(0x17, 0x09, SS_NOP|SSQ_PRINT_SENSE,
 373                        "Recovered data without ECC - data rewritten") },
 374/* D   W  O     */{SST(0x18, 0x00, SS_NOP|SSQ_PRINT_SENSE,
 375                        "Recovered data with error correction applied") },
 376/* D   WR O     */{SST(0x18, 0x01, SS_NOP|SSQ_PRINT_SENSE,
 377                        "Recovered data with error corr. & retries applied") },
 378/* D   WR O     */{SST(0x18, 0x02, SS_NOP|SSQ_PRINT_SENSE,
 379                        "Recovered data - data auto-reallocated") },
 380/*      R       */{SST(0x18, 0x03, SS_NOP|SSQ_PRINT_SENSE,
 381                        "Recovered data with CIRC") },
 382/*      R       */{SST(0x18, 0x04, SS_NOP|SSQ_PRINT_SENSE,
 383                        "Recovered data with L-EC") },
 384/* D   WR O     */{SST(0x18, 0x05, SS_NOP|SSQ_PRINT_SENSE,
 385                        "Recovered data - recommend reassignment") },
 386/* D   WR O     */{SST(0x18, 0x06, SS_NOP|SSQ_PRINT_SENSE,
 387                        "Recovered data - recommend rewrite") },
 388/* D   W  O     */{SST(0x18, 0x07, SS_NOP|SSQ_PRINT_SENSE,
 389                        "Recovered data with ECC - data rewritten") },
 390/* D      O     */{SST(0x19, 0x00, SS_RDEF,
 391                        "Defect list error") },
 392/* D      O     */{SST(0x19, 0x01, SS_RDEF,
 393                        "Defect list not available") },
 394/* D      O     */{SST(0x19, 0x02, SS_RDEF,
 395                        "Defect list error in primary list") },
 396/* D      O     */{SST(0x19, 0x03, SS_RDEF,
 397                        "Defect list error in grown list") },
 398/* DTLPWRSOMCAE */{SST(0x1A, 0x00, SS_RDEF,
 399                        "Parameter list length error") },
 400/* DTLPWRSOMCAE */{SST(0x1B, 0x00, SS_RDEF,
 401                        "Synchronous data transfer error") },
 402/* D      O     */{SST(0x1C, 0x00, SS_RDEF,
 403                        "Defect list not found") },
 404/* D      O     */{SST(0x1C, 0x01, SS_RDEF,
 405                        "Primary defect list not found") },
 406/* D      O     */{SST(0x1C, 0x02, SS_RDEF,
 407                        "Grown defect list not found") },
 408/* D   W  O     */{SST(0x1D, 0x00, SS_FATAL,
 409                        "Miscompare during verify operation" )},
 410/* D   W  O     */{SST(0x1E, 0x00, SS_NOP|SSQ_PRINT_SENSE,
 411                        "Recovered id with ecc correction") },
 412/* D      O     */{SST(0x1F, 0x00, SS_RDEF,
 413                        "Partial defect list transfer") },
 414/* DTLPWRSOMCAE */{SST(0x20, 0x00, SS_FATAL|EINVAL,
 415                        "Invalid command operation code") },
 416/* DT  WR OM    */{SST(0x21, 0x00, SS_FATAL|EINVAL,
 417                        "Logical block address out of range" )},
 418/* DT  WR OM    */{SST(0x21, 0x01, SS_FATAL|EINVAL,
 419                        "Invalid element address") },
 420/* D            */{SST(0x22, 0x00, SS_FATAL|EINVAL,
 421                        "Illegal function") }, /* Deprecated. Use 20 00, 24 00, or 26 00 instead */
 422/* DTLPWRSOMCAE */{SST(0x24, 0x00, SS_FATAL|EINVAL,
 423                        "Invalid field in CDB") },
 424/* DTLPWRSOMCAE */{SST(0x25, 0x00, SS_FATAL|ENXIO,
 425                        "Logical unit not supported") },
 426/* DTLPWRSOMCAE */{SST(0x26, 0x00, SS_FATAL|EINVAL,
 427                        "Invalid field in parameter list") },
 428/* DTLPWRSOMCAE */{SST(0x26, 0x01, SS_FATAL|EINVAL,
 429                        "Parameter not supported") },
 430/* DTLPWRSOMCAE */{SST(0x26, 0x02, SS_FATAL|EINVAL,
 431                        "Parameter value invalid") },
 432/* DTLPWRSOMCAE */{SST(0x26, 0x03, SS_FATAL|EINVAL,
 433                        "Threshold parameters not supported") },
 434/* DTLPWRSOMCAE */{SST(0x26, 0x04, SS_FATAL|EINVAL,
 435                        "Invalid release of active persistent reservation") },
 436/* DT  W  O     */{SST(0x27, 0x00, SS_FATAL|EACCES,
 437                        "Write protected") },
 438/* DT  W  O     */{SST(0x27, 0x01, SS_FATAL|EACCES,
 439                        "Hardware write protected") },
 440/* DT  W  O     */{SST(0x27, 0x02, SS_FATAL|EACCES,
 441                        "Logical unit software write protected") },
 442/*  T           */{SST(0x27, 0x03, SS_FATAL|EACCES,
 443                        "Associated write protect") },
 444/*  T           */{SST(0x27, 0x04, SS_FATAL|EACCES,
 445                        "Persistent write protect") },
 446/*  T           */{SST(0x27, 0x05, SS_FATAL|EACCES,
 447                        "Permanent write protect") },
 448/* DTLPWRSOMCAE */{SST(0x28, 0x00, SS_RDEF,
 449                        "Not ready to ready change, medium may have changed") },
 450/* DTLPWRSOMCAE */{SST(0x28, 0x01, SS_FATAL|ENXIO,
 451                        "Import or export element accessed") },
 452/*
 453 * XXX JGibbs - All of these should use the same errno, but I don't think
 454 * ENXIO is the correct choice.  Should we borrow from the networking
 455 * errnos?  ECONNRESET anyone?
 456 */
 457/* DTLPWRSOMCAE */{SST(0x29, 0x00, SS_RDEF,
 458                        "Power on, reset, or bus device reset occurred") },
 459/* DTLPWRSOMCAE */{SST(0x29, 0x01, SS_RDEF,
 460                        "Power on occurred") },
 461/* DTLPWRSOMCAE */{SST(0x29, 0x02, SS_RDEF,
 462                        "Scsi bus reset occurred") },
 463/* DTLPWRSOMCAE */{SST(0x29, 0x03, SS_RDEF,
 464                        "Bus device reset function occurred") },
 465/* DTLPWRSOMCAE */{SST(0x29, 0x04, SS_RDEF,
 466                        "Device internal reset") },
 467/* DTLPWRSOMCAE */{SST(0x29, 0x05, SS_RDEF,
 468                        "Transceiver mode changed to single-ended") },
 469/* DTLPWRSOMCAE */{SST(0x29, 0x06, SS_RDEF,
 470                        "Transceiver mode changed to LVD") },
 471/* DTL WRSOMCAE */{SST(0x2A, 0x00, SS_RDEF,
 472                        "Parameters changed") },
 473/* DTL WRSOMCAE */{SST(0x2A, 0x01, SS_RDEF,
 474                        "Mode parameters changed") },
 475/* DTL WRSOMCAE */{SST(0x2A, 0x02, SS_RDEF,
 476                        "Log parameters changed") },
 477/* DTLPWRSOMCAE */{SST(0x2A, 0x03, SS_RDEF,
 478                        "Reservations preempted") },
 479/* DTLPWRSO C   */{SST(0x2B, 0x00, SS_RDEF,
 480                        "Copy cannot execute since host cannot disconnect") },
 481/* DTLPWRSOMCAE */{SST(0x2C, 0x00, SS_RDEF,
 482                        "Command sequence error") },
 483/*       S      */{SST(0x2C, 0x01, SS_RDEF,
 484                        "Too many windows specified") },
 485/*       S      */{SST(0x2C, 0x02, SS_RDEF,
 486                        "Invalid combination of windows specified") },
 487/*      R       */{SST(0x2C, 0x03, SS_RDEF,
 488                        "Current program area is not empty") },
 489/*      R       */{SST(0x2C, 0x04, SS_RDEF,
 490                        "Current program area is empty") },
 491/*  T           */{SST(0x2D, 0x00, SS_RDEF,
 492                        "Overwrite error on update in place") },
 493/* DTLPWRSOMCAE */{SST(0x2F, 0x00, SS_RDEF,
 494                        "Commands cleared by another initiator") },
 495/* DT  WR OM    */{SST(0x30, 0x00, SS_RDEF,
 496                        "Incompatible medium installed") },
 497/* DT  WR O     */{SST(0x30, 0x01, SS_RDEF,
 498                        "Cannot read medium - unknown format") },
 499/* DT  WR O     */{SST(0x30, 0x02, SS_RDEF,
 500                        "Cannot read medium - incompatible format") },
 501/* DT           */{SST(0x30, 0x03, SS_RDEF,
 502                        "Cleaning cartridge installed") },
 503/* DT  WR O     */{SST(0x30, 0x04, SS_RDEF,
 504                        "Cannot write medium - unknown format") },
 505/* DT  WR O     */{SST(0x30, 0x05, SS_RDEF,
 506                        "Cannot write medium - incompatible format") },
 507/* DT  W  O     */{SST(0x30, 0x06, SS_RDEF,
 508                        "Cannot format medium - incompatible medium") },
 509/* DTL WRSOM AE */{SST(0x30, 0x07, SS_RDEF,
 510                        "Cleaning failure") },
 511/*      R       */{SST(0x30, 0x08, SS_RDEF,
 512                        "Cannot write - application code mismatch") },
 513/*      R       */{SST(0x30, 0x09, SS_RDEF,
 514                        "Current session not fixated for append") },
 515/* DT  WR O     */{SST(0x31, 0x00, SS_RDEF,
 516                        "Medium format corrupted") },
 517/* D L  R O     */{SST(0x31, 0x01, SS_RDEF,
 518                        "Format command failed") },
 519/* D   W  O     */{SST(0x32, 0x00, SS_RDEF,
 520                        "No defect spare location available") },
 521/* D   W  O     */{SST(0x32, 0x01, SS_RDEF,
 522                        "Defect list update failure") },
 523/*  T           */{SST(0x33, 0x00, SS_RDEF,
 524                        "Tape length error") },
 525/* DTLPWRSOMCAE */{SST(0x34, 0x00, SS_RDEF,
 526                        "Enclosure failure") },
 527/* DTLPWRSOMCAE */{SST(0x35, 0x00, SS_RDEF,
 528                        "Enclosure services failure") },
 529/* DTLPWRSOMCAE */{SST(0x35, 0x01, SS_RDEF,
 530                        "Unsupported enclosure function") },
 531/* DTLPWRSOMCAE */{SST(0x35, 0x02, SS_RDEF,
 532                        "Enclosure services unavailable") },
 533/* DTLPWRSOMCAE */{SST(0x35, 0x03, SS_RDEF,
 534                        "Enclosure services transfer failure") },
 535/* DTLPWRSOMCAE */{SST(0x35, 0x04, SS_RDEF,
 536                        "Enclosure services transfer refused") },
 537/*   L          */{SST(0x36, 0x00, SS_RDEF,
 538                        "Ribbon, ink, or toner failure") },
 539/* DTL WRSOMCAE */{SST(0x37, 0x00, SS_RDEF,
 540                        "Rounded parameter") },
 541/* DTL WRSOMCAE */{SST(0x39, 0x00, SS_RDEF,
 542                        "Saving parameters not supported") },
 543/* DTL WRSOM    */{SST(0x3A, 0x00, SS_NOP,
 544                        "Medium not present") },
 545/* DT  WR OM    */{SST(0x3A, 0x01, SS_NOP,
 546                        "Medium not present - tray closed") },
 547/* DT  WR OM    */{SST(0x3A, 0x01, SS_NOP,
 548                        "Medium not present - tray open") },
 549/* DT  WR OM    */{SST(0x3A, 0x03, SS_NOP,
 550                        "Medium not present - Loadable") },
 551/* DT  WR OM    */{SST(0x3A, 0x04, SS_NOP,
 552                        "Medium not present - medium auxiliary "
 553                        "memory accessible") },
 554/* DT  WR OM    */{SST(0x3A, 0xFF, SS_NOP, NULL) },/* Range 0x05->0xFF */
 555/*  TL          */{SST(0x3B, 0x00, SS_RDEF,
 556                        "Sequential positioning error") },
 557/*  T           */{SST(0x3B, 0x01, SS_RDEF,
 558                        "Tape position error at beginning-of-medium") },
 559/*  T           */{SST(0x3B, 0x02, SS_RDEF,
 560                        "Tape position error at end-of-medium") },
 561/*   L          */{SST(0x3B, 0x03, SS_RDEF,
 562                        "Tape or electronic vertical forms unit not ready") },
 563/*   L          */{SST(0x3B, 0x04, SS_RDEF,
 564                        "Slew failure") },
 565/*   L          */{SST(0x3B, 0x05, SS_RDEF,
 566                        "Paper jam") },
 567/*   L          */{SST(0x3B, 0x06, SS_RDEF,
 568                        "Failed to sense top-of-form") },
 569/*   L          */{SST(0x3B, 0x07, SS_RDEF,
 570                        "Failed to sense bottom-of-form") },
 571/*  T           */{SST(0x3B, 0x08, SS_RDEF,
 572                        "Reposition error") },
 573/*       S      */{SST(0x3B, 0x09, SS_RDEF,
 574                        "Read past end of medium") },
 575/*       S      */{SST(0x3B, 0x0A, SS_RDEF,
 576                        "Read past beginning of medium") },
 577/*       S      */{SST(0x3B, 0x0B, SS_RDEF,
 578                        "Position past end of medium") },
 579/*  T    S      */{SST(0x3B, 0x0C, SS_RDEF,
 580                        "Position past beginning of medium") },
 581/* DT  WR OM    */{SST(0x3B, 0x0D, SS_FATAL|ENOSPC,
 582                        "Medium destination element full") },
 583/* DT  WR OM    */{SST(0x3B, 0x0E, SS_RDEF,
 584                        "Medium source element empty") },
 585/*      R       */{SST(0x3B, 0x0F, SS_RDEF,
 586                        "End of medium reached") },
 587/* DT  WR OM    */{SST(0x3B, 0x11, SS_RDEF,
 588                        "Medium magazine not accessible") },
 589/* DT  WR OM    */{SST(0x3B, 0x12, SS_RDEF,
 590                        "Medium magazine removed") },
 591/* DT  WR OM    */{SST(0x3B, 0x13, SS_RDEF,
 592                        "Medium magazine inserted") },
 593/* DT  WR OM    */{SST(0x3B, 0x14, SS_RDEF,
 594                        "Medium magazine locked") },
 595/* DT  WR OM    */{SST(0x3B, 0x15, SS_RDEF,
 596                        "Medium magazine unlocked") },
 597/* DTLPWRSOMCAE */{SST(0x3D, 0x00, SS_RDEF,
 598                        "Invalid bits in identify message") },
 599/* DTLPWRSOMCAE */{SST(0x3E, 0x00, SS_RDEF,
 600                        "Logical unit has not self-configured yet") },
 601/* DTLPWRSOMCAE */{SST(0x3E, 0x01, SS_RDEF,
 602                        "Logical unit failure") },
 603/* DTLPWRSOMCAE */{SST(0x3E, 0x02, SS_RDEF,
 604                        "Timeout on logical unit") },
 605/* DTLPWRSOMCAE */{SST(0x3F, 0x00, SS_RDEF,
 606                        "Target operating conditions have changed") },
 607/* DTLPWRSOMCAE */{SST(0x3F, 0x01, SS_RDEF,
 608                        "Microcode has been changed") },
 609/* DTLPWRSOMC   */{SST(0x3F, 0x02, SS_RDEF,
 610                        "Changed operating definition") },
 611/* DTLPWRSOMCAE */{SST(0x3F, 0x03, SS_INQ_REFRESH|SSQ_DECREMENT_COUNT,
 612                        "Inquiry data has changed") },
 613/* DT  WR OMCAE */{SST(0x3F, 0x04, SS_RDEF,
 614                        "Component device attached") },
 615/* DT  WR OMCAE */{SST(0x3F, 0x05, SS_RDEF,
 616                        "Device identifier changed") },
 617/* DT  WR OMCAE */{SST(0x3F, 0x06, SS_RDEF,
 618                        "Redundancy group created or modified") },
 619/* DT  WR OMCAE */{SST(0x3F, 0x07, SS_RDEF,
 620                        "Redundancy group deleted") },
 621/* DT  WR OMCAE */{SST(0x3F, 0x08, SS_RDEF,
 622                        "Spare created or modified") },
 623/* DT  WR OMCAE */{SST(0x3F, 0x09, SS_RDEF,
 624                        "Spare deleted") },
 625/* DT  WR OMCAE */{SST(0x3F, 0x0A, SS_RDEF,
 626                        "Volume set created or modified") },
 627/* DT  WR OMCAE */{SST(0x3F, 0x0B, SS_RDEF,
 628                        "Volume set deleted") },
 629/* DT  WR OMCAE */{SST(0x3F, 0x0C, SS_RDEF,
 630                        "Volume set deassigned") },
 631/* DT  WR OMCAE */{SST(0x3F, 0x0D, SS_RDEF,
 632                        "Volume set reassigned") },
 633/* DTLPWRSOMCAE */{SST(0x3F, 0x0E, SS_RDEF,
 634                        "Reported luns data has changed") },
 635/* DTLPWRSOMCAE */{SST(0x3F, 0x0F, SS_RETRY|SSQ_DECREMENT_COUNT
 636                                 | SSQ_DELAY_RANDOM|EBUSY,
 637                        "Echo buffer overwritten") },
 638/* DT  WR OM   B*/{SST(0x3F, 0x0F, SS_RDEF, "Medium Loadable") },
 639/* DT  WR OM   B*/{SST(0x3F, 0x0F, SS_RDEF,
 640                        "Medium auxiliary memory accessible") },
 641/* D            */{SST(0x40, 0x00, SS_RDEF,
 642                        "Ram failure") }, /* deprecated - use 40 NN instead */
 643/* DTLPWRSOMCAE */{SST(0x40, 0x80, SS_RDEF,
 644                        "Diagnostic failure: ASCQ = Component ID") },
 645/* DTLPWRSOMCAE */{SST(0x40, 0xFF, SS_RDEF|SSQ_RANGE,
 646                        NULL) },/* Range 0x80->0xFF */
 647/* D            */{SST(0x41, 0x00, SS_RDEF,
 648                        "Data path failure") }, /* deprecated - use 40 NN instead */
 649/* D            */{SST(0x42, 0x00, SS_RDEF,
 650                        "Power-on or self-test failure") }, /* deprecated - use 40 NN instead */
 651/* DTLPWRSOMCAE */{SST(0x43, 0x00, SS_RDEF,
 652                        "Message error") },
 653/* DTLPWRSOMCAE */{SST(0x44, 0x00, SS_RDEF,
 654                        "Internal target failure") },
 655/* DTLPWRSOMCAE */{SST(0x45, 0x00, SS_RDEF,
 656                        "Select or reselect failure") },
 657/* DTLPWRSOMC   */{SST(0x46, 0x00, SS_RDEF,
 658                        "Unsuccessful soft reset") },
 659/* DTLPWRSOMCAE */{SST(0x47, 0x00, SS_RDEF|SSQ_FALLBACK,
 660                        "SCSI parity error") },
 661/* DTLPWRSOMCAE */{SST(0x47, 0x01, SS_RDEF|SSQ_FALLBACK,
 662                        "Data Phase CRC error detected") },
 663/* DTLPWRSOMCAE */{SST(0x47, 0x02, SS_RDEF|SSQ_FALLBACK,
 664                        "SCSI parity error detected during ST data phase") },
 665/* DTLPWRSOMCAE */{SST(0x47, 0x03, SS_RDEF|SSQ_FALLBACK,
 666                        "Information Unit iuCRC error") },
 667/* DTLPWRSOMCAE */{SST(0x47, 0x04, SS_RDEF|SSQ_FALLBACK,
 668                        "Asynchronous information protection error detected") },
 669/* DTLPWRSOMCAE */{SST(0x47, 0x05, SS_RDEF|SSQ_FALLBACK,
 670                        "Protocol server CRC error") },
 671/* DTLPWRSOMCAE */{SST(0x48, 0x00, SS_RDEF|SSQ_FALLBACK,
 672                        "Initiator detected error message received") },
 673/* DTLPWRSOMCAE */{SST(0x49, 0x00, SS_RDEF,
 674                        "Invalid message error") },
 675/* DTLPWRSOMCAE */{SST(0x4A, 0x00, SS_RDEF,
 676                        "Command phase error") },
 677/* DTLPWRSOMCAE */{SST(0x4B, 0x00, SS_RDEF,
 678                        "Data phase error") },
 679/* DTLPWRSOMCAE */{SST(0x4C, 0x00, SS_RDEF,
 680                        "Logical unit failed self-configuration") },
 681/* DTLPWRSOMCAE */{SST(0x4D, 0x00, SS_RDEF,
 682                        "Tagged overlapped commands: ASCQ = Queue tag ID") },
 683/* DTLPWRSOMCAE */{SST(0x4D, 0xFF, SS_RDEF|SSQ_RANGE,
 684                        NULL)}, /* Range 0x00->0xFF */
 685/* DTLPWRSOMCAE */{SST(0x4E, 0x00, SS_RDEF,
 686                        "Overlapped commands attempted") },
 687/*  T           */{SST(0x50, 0x00, SS_RDEF,
 688                        "Write append error") },
 689/*  T           */{SST(0x50, 0x01, SS_RDEF,
 690                        "Write append position error") },
 691/*  T           */{SST(0x50, 0x02, SS_RDEF,
 692                        "Position error related to timing") },
 693/*  T     O     */{SST(0x51, 0x00, SS_RDEF,
 694                        "Erase failure") },
 695/*  T           */{SST(0x52, 0x00, SS_RDEF,
 696                        "Cartridge fault") },
 697/* DTL WRSOM    */{SST(0x53, 0x00, SS_RDEF,
 698                        "Media load or eject failed") },
 699/*  T           */{SST(0x53, 0x01, SS_RDEF,
 700                        "Unload tape failure") },
 701/* DT  WR OM    */{SST(0x53, 0x02, SS_RDEF,
 702                        "Medium removal prevented") },
 703/*    P         */{SST(0x54, 0x00, SS_RDEF,
 704                        "Scsi to host system interface failure") },
 705/*    P         */{SST(0x55, 0x00, SS_RDEF,
 706                        "System resource failure") },
 707/* D      O     */{SST(0x55, 0x01, SS_FATAL|ENOSPC,
 708                        "System buffer full") },
 709/*      R       */{SST(0x57, 0x00, SS_RDEF,
 710                        "Unable to recover table-of-contents") },
 711/*        O     */{SST(0x58, 0x00, SS_RDEF,
 712                        "Generation does not exist") },
 713/*        O     */{SST(0x59, 0x00, SS_RDEF,
 714                        "Updated block read") },
 715/* DTLPWRSOM    */{SST(0x5A, 0x00, SS_RDEF,
 716                        "Operator request or state change input") },
 717/* DT  WR OM    */{SST(0x5A, 0x01, SS_RDEF,
 718                        "Operator medium removal request") },
 719/* DT  W  O     */{SST(0x5A, 0x02, SS_RDEF,
 720                        "Operator selected write protect") },
 721/* DT  W  O     */{SST(0x5A, 0x03, SS_RDEF,
 722                        "Operator selected write permit") },
 723/* DTLPWRSOM    */{SST(0x5B, 0x00, SS_RDEF,
 724                        "Log exception") },
 725/* DTLPWRSOM    */{SST(0x5B, 0x01, SS_RDEF,
 726                        "Threshold condition met") },
 727/* DTLPWRSOM    */{SST(0x5B, 0x02, SS_RDEF,
 728                        "Log counter at maximum") },
 729/* DTLPWRSOM    */{SST(0x5B, 0x03, SS_RDEF,
 730                        "Log list codes exhausted") },
 731/* D      O     */{SST(0x5C, 0x00, SS_RDEF,
 732                        "RPL status change") },
 733/* D      O     */{SST(0x5C, 0x01, SS_NOP|SSQ_PRINT_SENSE,
 734                        "Spindles synchronized") },
 735/* D      O     */{SST(0x5C, 0x02, SS_RDEF,
 736                        "Spindles not synchronized") },
 737/* DTLPWRSOMCAE */{SST(0x5D, 0x00, SS_RDEF,
 738                        "Failure prediction threshold exceeded") },
 739/* DTLPWRSOMCAE */{SST(0x5D, 0xFF, SS_RDEF,
 740                        "Failure prediction threshold exceeded (false)") },
 741/* DTLPWRSO CA  */{SST(0x5E, 0x00, SS_RDEF,
 742                        "Low power condition on") },
 743/* DTLPWRSO CA  */{SST(0x5E, 0x01, SS_RDEF,
 744                        "Idle condition activated by timer") },
 745/* DTLPWRSO CA  */{SST(0x5E, 0x02, SS_RDEF,
 746                        "Standby condition activated by timer") },
 747/* DTLPWRSO CA  */{SST(0x5E, 0x03, SS_RDEF,
 748                        "Idle condition activated by command") },
 749/* DTLPWRSO CA  */{SST(0x5E, 0x04, SS_RDEF,
 750                        "Standby condition activated by command") },
 751/*       S      */{SST(0x60, 0x00, SS_RDEF,
 752                        "Lamp failure") },
 753/*       S      */{SST(0x61, 0x00, SS_RDEF,
 754                        "Video acquisition error") },
 755/*       S      */{SST(0x61, 0x01, SS_RDEF,
 756                        "Unable to acquire video") },
 757/*       S      */{SST(0x61, 0x02, SS_RDEF,
 758                        "Out of focus") },
 759/*       S      */{SST(0x62, 0x00, SS_RDEF,
 760                        "Scan head positioning error") },
 761/*      R       */{SST(0x63, 0x00, SS_RDEF,
 762                        "End of user area encountered on this track") },
 763/*      R       */{SST(0x63, 0x01, SS_FATAL|ENOSPC,
 764                        "Packet does not fit in available space") },
 765/*      R       */{SST(0x64, 0x00, SS_RDEF,
 766                        "Illegal mode for this track") },
 767/*      R       */{SST(0x64, 0x01, SS_RDEF,
 768                        "Invalid packet size") },
 769/* DTLPWRSOMCAE */{SST(0x65, 0x00, SS_RDEF,
 770                        "Voltage fault") },
 771/*       S      */{SST(0x66, 0x00, SS_RDEF,
 772                        "Automatic document feeder cover up") },
 773/*       S      */{SST(0x66, 0x01, SS_RDEF,
 774                        "Automatic document feeder lift up") },
 775/*       S      */{SST(0x66, 0x02, SS_RDEF,
 776                        "Document jam in automatic document feeder") },
 777/*       S      */{SST(0x66, 0x03, SS_RDEF,
 778                        "Document miss feed automatic in document feeder") },
 779/*           A  */{SST(0x67, 0x00, SS_RDEF,
 780                        "Configuration failure") },
 781/*           A  */{SST(0x67, 0x01, SS_RDEF,
 782                        "Configuration of incapable logical units failed") },
 783/*           A  */{SST(0x67, 0x02, SS_RDEF,
 784                        "Add logical unit failed") },
 785/*           A  */{SST(0x67, 0x03, SS_RDEF,
 786                        "Modification of logical unit failed") },
 787/*           A  */{SST(0x67, 0x04, SS_RDEF,
 788                        "Exchange of logical unit failed") },
 789/*           A  */{SST(0x67, 0x05, SS_RDEF,
 790                        "Remove of logical unit failed") },
 791/*           A  */{SST(0x67, 0x06, SS_RDEF,
 792                        "Attachment of logical unit failed") },
 793/*           A  */{SST(0x67, 0x07, SS_RDEF,
 794                        "Creation of logical unit failed") },
 795/*           A  */{SST(0x68, 0x00, SS_RDEF,
 796                        "Logical unit not configured") },
 797/*           A  */{SST(0x69, 0x00, SS_RDEF,
 798                        "Data loss on logical unit") },
 799/*           A  */{SST(0x69, 0x01, SS_RDEF,
 800                        "Multiple logical unit failures") },
 801/*           A  */{SST(0x69, 0x02, SS_RDEF,
 802                        "Parity/data mismatch") },
 803/*           A  */{SST(0x6A, 0x00, SS_RDEF,
 804                        "Informational, refer to log") },
 805/*           A  */{SST(0x6B, 0x00, SS_RDEF,
 806                        "State change has occurred") },
 807/*           A  */{SST(0x6B, 0x01, SS_RDEF,
 808                        "Redundancy level got better") },
 809/*           A  */{SST(0x6B, 0x02, SS_RDEF,
 810                        "Redundancy level got worse") },
 811/*           A  */{SST(0x6C, 0x00, SS_RDEF,
 812                        "Rebuild failure occurred") },
 813/*           A  */{SST(0x6D, 0x00, SS_RDEF,
 814                        "Recalculate failure occurred") },
 815/*           A  */{SST(0x6E, 0x00, SS_RDEF,
 816                        "Command to logical unit failed") },
 817/*  T           */{SST(0x70, 0x00, SS_RDEF,
 818                        "Decompression exception short: ASCQ = Algorithm ID") },
 819/*  T           */{SST(0x70, 0xFF, SS_RDEF|SSQ_RANGE,
 820                        NULL) }, /* Range 0x00 -> 0xFF */
 821/*  T           */{SST(0x71, 0x00, SS_RDEF,
 822                        "Decompression exception long: ASCQ = Algorithm ID") },
 823/*  T           */{SST(0x71, 0xFF, SS_RDEF|SSQ_RANGE,
 824                        NULL) }, /* Range 0x00 -> 0xFF */       
 825/*      R       */{SST(0x72, 0x00, SS_RDEF,
 826                        "Session fixation error") },
 827/*      R       */{SST(0x72, 0x01, SS_RDEF,
 828                        "Session fixation error writing lead-in") },
 829/*      R       */{SST(0x72, 0x02, SS_RDEF,
 830                        "Session fixation error writing lead-out") },
 831/*      R       */{SST(0x72, 0x03, SS_RDEF,
 832                        "Session fixation error - incomplete track in session") },
 833/*      R       */{SST(0x72, 0x04, SS_RDEF,
 834                        "Empty or partially written reserved track") },
 835/*      R       */{SST(0x73, 0x00, SS_RDEF,
 836                        "CD control error") },
 837/*      R       */{SST(0x73, 0x01, SS_RDEF,
 838                        "Power calibration area almost full") },
 839/*      R       */{SST(0x73, 0x02, SS_FATAL|ENOSPC,
 840                        "Power calibration area is full") },
 841/*      R       */{SST(0x73, 0x03, SS_RDEF,
 842                        "Power calibration area error") },
 843/*      R       */{SST(0x73, 0x04, SS_RDEF,
 844                        "Program memory area update failure") },
 845/*      R       */{SST(0x73, 0x05, SS_RDEF,
 846                        "program memory area is full") }
 847};
 848
 849static const int asc_table_size = sizeof(asc_table)/sizeof(asc_table[0]);
 850
 851struct asc_key
 852{
 853        int asc;
 854        int ascq;
 855};
 856
 857static int
 858ascentrycomp(const void *key, const void *member)
 859{
 860        int asc;
 861        int ascq;
 862        const struct asc_table_entry *table_entry;
 863
 864        asc = ((const struct asc_key *)key)->asc;
 865        ascq = ((const struct asc_key *)key)->ascq;
 866        table_entry = (const struct asc_table_entry *)member;
 867
 868        if (asc >= table_entry->asc) {
 869
 870                if (asc > table_entry->asc)
 871                        return (1);
 872
 873                if (ascq <= table_entry->ascq) {
 874                        /* Check for ranges */
 875                        if (ascq == table_entry->ascq
 876                         || ((table_entry->action & SSQ_RANGE) != 0
 877                           && ascq >= (table_entry - 1)->ascq))
 878                                return (0);
 879                        return (-1);
 880                }
 881                return (1);
 882        }
 883        return (-1);
 884}
 885
 886static int
 887senseentrycomp(const void *key, const void *member)
 888{
 889        int sense_key;
 890        const struct sense_key_table_entry *table_entry;
 891
 892        sense_key = *((const int *)key);
 893        table_entry = (const struct sense_key_table_entry *)member;
 894
 895        if (sense_key >= table_entry->sense_key) {
 896                if (sense_key == table_entry->sense_key)
 897                        return (0);
 898                return (1);
 899        }
 900        return (-1);
 901}
 902
 903static void
 904fetchtableentries(int sense_key, int asc, int ascq,
 905                  struct scsi_inquiry_data *inq_data,
 906                  const struct sense_key_table_entry **sense_entry,
 907                  const struct asc_table_entry **asc_entry)
 908{
 909        void *match;
 910        const struct asc_table_entry *asc_tables[2];
 911        const struct sense_key_table_entry *sense_tables[2];
 912        struct asc_key asc_ascq;
 913        size_t asc_tables_size[2];
 914        size_t sense_tables_size[2];
 915        int num_asc_tables;
 916        int num_sense_tables;
 917        int i;
 918
 919        /* Default to failure */
 920        *sense_entry = NULL;
 921        *asc_entry = NULL;
 922        match = NULL;
 923        if (inq_data != NULL)
 924                match = cam_quirkmatch((void *)inq_data,
 925                                       (void *)sense_quirk_table,
 926                                       sense_quirk_table_size,
 927                                       sizeof(*sense_quirk_table),
 928                                       aic_inquiry_match);
 929
 930        if (match != NULL) {
 931                struct scsi_sense_quirk_entry *quirk;
 932
 933                quirk = (struct scsi_sense_quirk_entry *)match;
 934                asc_tables[0] = quirk->asc_info;
 935                asc_tables_size[0] = quirk->num_ascs;
 936                asc_tables[1] = asc_table;
 937                asc_tables_size[1] = asc_table_size;
 938                num_asc_tables = 2;
 939                sense_tables[0] = quirk->sense_key_info;
 940                sense_tables_size[0] = quirk->num_sense_keys;
 941                sense_tables[1] = sense_key_table;
 942                sense_tables_size[1] = sense_key_table_size;
 943                num_sense_tables = 2;
 944        } else {
 945                asc_tables[0] = asc_table;
 946                asc_tables_size[0] = asc_table_size;
 947                num_asc_tables = 1;
 948                sense_tables[0] = sense_key_table;
 949                sense_tables_size[0] = sense_key_table_size;
 950                num_sense_tables = 1;
 951        }
 952
 953        asc_ascq.asc = asc;
 954        asc_ascq.ascq = ascq;
 955        for (i = 0; i < num_asc_tables; i++) {
 956                void *found_entry;
 957
 958                found_entry = scsibsearch(&asc_ascq, asc_tables[i],
 959                                          asc_tables_size[i],
 960                                          sizeof(**asc_tables),
 961                                          ascentrycomp);
 962
 963                if (found_entry) {
 964                        *asc_entry = (struct asc_table_entry *)found_entry;
 965                        break;
 966                }
 967        }
 968
 969        for (i = 0; i < num_sense_tables; i++) {
 970                void *found_entry;
 971
 972                found_entry = scsibsearch(&sense_key, sense_tables[i],
 973                                          sense_tables_size[i],
 974                                          sizeof(**sense_tables),
 975                                          senseentrycomp);
 976
 977                if (found_entry) {
 978                        *sense_entry =
 979                            (struct sense_key_table_entry *)found_entry;
 980                        break;
 981                }
 982        }
 983}
 984
 985static void *
 986scsibsearch(const void *key, const void *base, size_t nmemb, size_t size,
 987                 int (*compar)(const void *, const void *))
 988{
 989        const void *entry;
 990        u_int l;
 991        u_int u;
 992        u_int m;
 993
 994        l = -1;
 995        u = nmemb;
 996        while (l + 1 != u) {
 997                m = (l + u) / 2;
 998                entry = base + m * size;
 999                if (compar(key, entry) > 0)
1000                        l = m;
1001                else
1002                        u = m;
1003        }
1004
1005        entry = base + u * size;
1006        if (u == nmemb
1007         || compar(key, entry) != 0)
1008                return (NULL);
1009
1010        return ((void *)entry);
1011}
1012
1013/*
1014 * Compare string with pattern, returning 0 on match.
1015 * Short pattern matches trailing blanks in name,
1016 * wildcard '*' in pattern matches rest of name,
1017 * wildcard '?' matches a single non-space character.
1018 */
1019static int
1020cam_strmatch(const uint8_t *str, const uint8_t *pattern, int str_len)
1021{
1022
1023        while (*pattern != '\0'&& str_len > 0) {  
1024
1025                if (*pattern == '*') {
1026                        return (0);
1027                }
1028                if ((*pattern != *str)
1029                 && (*pattern != '?' || *str == ' ')) {
1030                        return (1);
1031                }
1032                pattern++;
1033                str++;
1034                str_len--;
1035        }
1036        while (str_len > 0 && *str++ == ' ')
1037                str_len--;
1038
1039        return (str_len);
1040}
1041
1042static caddr_t
1043cam_quirkmatch(caddr_t target, caddr_t quirk_table, int num_entries,
1044               int entry_size, cam_quirkmatch_t *comp_func)
1045{
1046        for (; num_entries > 0; num_entries--, quirk_table += entry_size) {
1047                if ((*comp_func)(target, quirk_table) == 0)
1048                        return (quirk_table);
1049        }
1050        return (NULL);
1051}
1052
1053void
1054aic_sense_desc(int sense_key, int asc, int ascq,
1055               struct scsi_inquiry_data *inq_data,
1056               const char **sense_key_desc, const char **asc_desc)
1057{
1058        const struct asc_table_entry *asc_entry;
1059        const struct sense_key_table_entry *sense_entry;
1060
1061        fetchtableentries(sense_key, asc, ascq,
1062                          inq_data,
1063                          &sense_entry,
1064                          &asc_entry);
1065
1066        *sense_key_desc = sense_entry->desc;
1067
1068        if (asc_entry != NULL)
1069                *asc_desc = asc_entry->desc;
1070        else if (asc >= 0x80 && asc <= 0xff)
1071                *asc_desc = "Vendor Specific ASC";
1072        else if (ascq >= 0x80 && ascq <= 0xff)
1073                *asc_desc = "Vendor Specific ASCQ";
1074        else
1075                *asc_desc = "Reserved ASC/ASCQ pair";
1076}
1077
1078/*
1079 * Given sense and device type information, return the appropriate action.
1080 * If we do not understand the specific error as identified by the ASC/ASCQ
1081 * pair, fall back on the more generic actions derived from the sense key.
1082 */
1083aic_sense_action
1084aic_sense_error_action(struct scsi_sense_data *sense_data,
1085                       struct scsi_inquiry_data *inq_data, uint32_t sense_flags)
1086{
1087        const struct asc_table_entry *asc_entry;
1088        const struct sense_key_table_entry *sense_entry;
1089        int error_code, sense_key, asc, ascq;
1090        aic_sense_action action;
1091
1092        scsi_extract_sense(sense_data, &error_code, &sense_key, &asc, &ascq);
1093
1094        if (error_code == SSD_DEFERRED_ERROR) {
1095                /*
1096                 * XXX dufault@FreeBSD.org
1097                 * This error doesn't relate to the command associated
1098                 * with this request sense.  A deferred error is an error
1099                 * for a command that has already returned GOOD status
1100                 * (see SCSI2 8.2.14.2).
1101                 *
1102                 * By my reading of that section, it looks like the current
1103                 * command has been cancelled, we should now clean things up
1104                 * (hopefully recovering any lost data) and then retry the
1105                 * current command.  There are two easy choices, both wrong:
1106                 *
1107                 * 1. Drop through (like we had been doing), thus treating
1108                 *    this as if the error were for the current command and
1109                 *    return and stop the current command.
1110                 * 
1111                 * 2. Issue a retry (like I made it do) thus hopefully
1112                 *    recovering the current transfer, and ignoring the
1113                 *    fact that we've dropped a command.
1114                 *
1115                 * These should probably be handled in a device specific
1116                 * sense handler or punted back up to a user mode daemon
1117                 */
1118                action = SS_RETRY|SSQ_DECREMENT_COUNT|SSQ_PRINT_SENSE;
1119        } else {
1120                fetchtableentries(sense_key, asc, ascq,
1121                                  inq_data,
1122                                  &sense_entry,
1123                                  &asc_entry);
1124
1125                /*
1126                 * Override the 'No additional Sense' entry (0,0)
1127                 * with the error action of the sense key.
1128                 */
1129                if (asc_entry != NULL
1130                 && (asc != 0 || ascq != 0))
1131                        action = asc_entry->action;
1132                else
1133                        action = sense_entry->action;
1134
1135                if (sense_key == SSD_KEY_RECOVERED_ERROR) {
1136                        /*
1137                         * The action succeeded but the device wants
1138                         * the user to know that some recovery action
1139                         * was required.
1140                         */
1141                        action &= ~(SS_MASK|SSQ_MASK|SS_ERRMASK);
1142                        action |= SS_NOP|SSQ_PRINT_SENSE;
1143                } else if (sense_key == SSD_KEY_ILLEGAL_REQUEST) {
1144                        if ((sense_flags & SF_QUIET_IR) != 0)
1145                                action &= ~SSQ_PRINT_SENSE;
1146                } else if (sense_key == SSD_KEY_UNIT_ATTENTION) {
1147                        if ((sense_flags & SF_RETRY_UA) != 0
1148                         && (action & SS_MASK) == SS_FAIL) {
1149                                action &= ~(SS_MASK|SSQ_MASK);
1150                                action |= SS_RETRY|SSQ_DECREMENT_COUNT|
1151                                          SSQ_PRINT_SENSE;
1152                        }
1153                }
1154        }
1155
1156        if ((sense_flags & SF_PRINT_ALWAYS) != 0)
1157                action |= SSQ_PRINT_SENSE;
1158        else if ((sense_flags & SF_NO_PRINT) != 0)
1159                action &= ~SSQ_PRINT_SENSE;
1160
1161        return (action);
1162}
1163
1164/*      
1165 * Try make as good a match as possible with
1166 * available sub drivers
1167 */
1168int
1169aic_inquiry_match(caddr_t inqbuffer, caddr_t table_entry)
1170{
1171        struct scsi_inquiry_pattern *entry;
1172        struct scsi_inquiry_data *inq;
1173 
1174        entry = (struct scsi_inquiry_pattern *)table_entry;
1175        inq = (struct scsi_inquiry_data *)inqbuffer;
1176
1177        if (((SID_TYPE(inq) == entry->type)
1178          || (entry->type == T_ANY))
1179         && (SID_IS_REMOVABLE(inq) ? entry->media_type & SIP_MEDIA_REMOVABLE
1180                                   : entry->media_type & SIP_MEDIA_FIXED)
1181         && (cam_strmatch(inq->vendor, entry->vendor, sizeof(inq->vendor)) == 0)
1182         && (cam_strmatch(inq->product, entry->product,
1183                          sizeof(inq->product)) == 0)
1184         && (cam_strmatch(inq->revision, entry->revision,
1185                          sizeof(inq->revision)) == 0)) {
1186                return (0);
1187        }
1188        return (-1);
1189}
1190
1191/*
1192 * Table of syncrates that don't follow the "divisible by 4"
1193 * rule. This table will be expanded in future SCSI specs.
1194 */
1195static struct {
1196        u_int period_factor;
1197        u_int period;   /* in 100ths of ns */
1198} scsi_syncrates[] = {
1199        { 0x08, 625 },  /* FAST-160 */
1200        { 0x09, 1250 }, /* FAST-80 */
1201        { 0x0a, 2500 }, /* FAST-40 40MHz */
1202        { 0x0b, 3030 }, /* FAST-40 33MHz */
1203        { 0x0c, 5000 }  /* FAST-20 */
1204};
1205
1206/*
1207 * Return the frequency in kHz corresponding to the given
1208 * sync period factor.
1209 */
1210u_int
1211aic_calc_syncsrate(u_int period_factor)
1212{
1213        int i;
1214        int num_syncrates;
1215
1216        num_syncrates = sizeof(scsi_syncrates) / sizeof(scsi_syncrates[0]);
1217        /* See if the period is in the "exception" table */
1218        for (i = 0; i < num_syncrates; i++) {
1219
1220                if (period_factor == scsi_syncrates[i].period_factor) {
1221                        /* Period in kHz */
1222                        return (100000000 / scsi_syncrates[i].period);
1223                }
1224        }
1225
1226        /*
1227         * Wasn't in the table, so use the standard
1228         * 4 times conversion.
1229         */
1230        return (10000000 / (period_factor * 4 * 10));
1231}
1232
1233/*
1234 * Return speed in KB/s.
1235 */
1236u_int
1237aic_calc_speed(u_int width, u_int period, u_int offset, u_int min_rate)
1238{
1239        u_int freq;
1240
1241        if (offset != 0 && period < min_rate)
1242                freq  = aic_calc_syncsrate(period);
1243        else
1244                /* Roughly 3.3MB/s for async */
1245                freq  = 3300;
1246        freq <<= width;
1247        return (freq);
1248}
1249
1250uint32_t
1251aic_error_action(struct scsi_cmnd *cmd, struct scsi_inquiry_data *inq_data,
1252                 cam_status status, u_int scsi_status)
1253{
1254        aic_sense_action  err_action;
1255        int               sense;
1256
1257        sense  = (cmd->result >> 24) == DRIVER_SENSE;
1258
1259        switch (status) {
1260        case CAM_REQ_CMP:
1261                err_action = SS_NOP;
1262                break;
1263        case CAM_AUTOSENSE_FAIL:
1264        case CAM_SCSI_STATUS_ERROR:
1265
1266                switch (scsi_status) {
1267                case SCSI_STATUS_OK:
1268                case SCSI_STATUS_COND_MET:
1269                case SCSI_STATUS_INTERMED:
1270                case SCSI_STATUS_INTERMED_COND_MET:
1271                        err_action = SS_NOP;
1272                        break;
1273                case SCSI_STATUS_CMD_TERMINATED:
1274                case SCSI_STATUS_CHECK_COND:
1275                        if (sense != 0) {
1276                                struct scsi_sense_data *sense;
1277
1278                                sense = (struct scsi_sense_data *)
1279                                    &cmd->sense_buffer;
1280                                err_action =
1281                                    aic_sense_error_action(sense, inq_data, 0);
1282
1283                        } else {
1284                                err_action = SS_RETRY|SSQ_FALLBACK
1285                                           | SSQ_DECREMENT_COUNT|EIO;
1286                        }
1287                        break;
1288                case SCSI_STATUS_QUEUE_FULL:
1289                case SCSI_STATUS_BUSY:
1290                        err_action = SS_RETRY|SSQ_DELAY|SSQ_MANY
1291                                   | SSQ_DECREMENT_COUNT|EBUSY;
1292                        break;
1293                case SCSI_STATUS_RESERV_CONFLICT:
1294                default:
1295                        err_action = SS_FAIL|EBUSY;
1296                        break;
1297                }
1298                break;
1299        case CAM_CMD_TIMEOUT:
1300        case CAM_REQ_CMP_ERR:
1301        case CAM_UNEXP_BUSFREE:
1302        case CAM_UNCOR_PARITY:
1303        case CAM_DATA_RUN_ERR:
1304                err_action = SS_RETRY|SSQ_FALLBACK|EIO;
1305                break;
1306        case CAM_UA_ABORT:
1307        case CAM_UA_TERMIO:
1308        case CAM_MSG_REJECT_REC:
1309        case CAM_SEL_TIMEOUT:
1310                err_action = SS_FAIL|EIO;
1311                break;
1312        case CAM_REQ_INVALID:
1313        case CAM_PATH_INVALID:
1314        case CAM_DEV_NOT_THERE:
1315        case CAM_NO_HBA:
1316        case CAM_PROVIDE_FAIL:
1317        case CAM_REQ_TOO_BIG:           
1318        case CAM_RESRC_UNAVAIL:
1319        case CAM_BUSY:
1320        default:
1321                /* panic??  These should never occur in our application. */
1322                err_action = SS_FAIL|EIO;
1323                break;
1324        case CAM_SCSI_BUS_RESET:
1325        case CAM_BDR_SENT:              
1326        case CAM_REQUEUE_REQ:
1327                /* Unconditional requeue */
1328                err_action = SS_RETRY;
1329                break;
1330        }
1331
1332        return (err_action);
1333}
1334
1335char *
1336aic_parse_brace_option(char *opt_name, char *opt_arg, char *end, int depth,
1337                       aic_option_callback_t *callback, u_long callback_arg)
1338{
1339        char    *tok_end;
1340        char    *tok_end2;
1341        int      i;
1342        int      instance;
1343        int      targ;
1344        int      done;
1345        char     tok_list[] = {'.', ',', '{', '}', '\0'};
1346
1347        /* All options use a ':' name/arg separator */
1348        if (*opt_arg != ':')
1349                return (opt_arg);
1350        opt_arg++;
1351        instance = -1;
1352        targ = -1;
1353        done = FALSE;
1354        /*
1355         * Restore separator that may be in
1356         * the middle of our option argument.
1357         */
1358        tok_end = strchr(opt_arg, '\0');
1359        if (tok_end < end)
1360                *tok_end = ',';
1361        while (!done) {
1362                switch (*opt_arg) {
1363                case '{':
1364                        if (instance == -1) {
1365                                instance = 0;
1366                        } else {
1367                                if (depth > 1) {
1368                                        if (targ == -1)
1369                                                targ = 0;
1370                                } else {
1371                                        printf("Malformed Option %s\n",
1372                                               opt_name);
1373                                        done = TRUE;
1374                                }
1375                        }
1376                        opt_arg++;
1377                        break;
1378                case '}':
1379                        if (targ != -1)
1380                                targ = -1;
1381                        else if (instance != -1)
1382                                instance = -1;
1383                        opt_arg++;
1384                        break;
1385                case ',':
1386                case '.':
1387                        if (instance == -1)
1388                                done = TRUE;
1389                        else if (targ >= 0)
1390                                targ++;
1391                        else if (instance >= 0)
1392                                instance++;
1393                        opt_arg++;
1394                        break;
1395                case '\0':
1396                        done = TRUE;
1397                        break;
1398                default:
1399                        tok_end = end;
1400                        for (i = 0; tok_list[i]; i++) {
1401                                tok_end2 = strchr(opt_arg, tok_list[i]);
1402                                if ((tok_end2) && (tok_end2 < tok_end))
1403                                        tok_end = tok_end2;
1404                        }
1405                        callback(callback_arg, instance, targ,
1406                                 simple_strtol(opt_arg, NULL, 0));
1407                        opt_arg = tok_end;
1408                        break;
1409                }
1410        }
1411        return (opt_arg);
1412}
1413
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.