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