1139743Simp/*- 239213Sgibbs * Implementation of Utility functions for all SCSI device types. 339213Sgibbs * 474840Sken * Copyright (c) 1997, 1998, 1999 Justin T. Gibbs. 5114261Sken * Copyright (c) 1997, 1998, 2003 Kenneth D. Merry. 639213Sgibbs * All rights reserved. 739213Sgibbs * 839213Sgibbs * Redistribution and use in source and binary forms, with or without 939213Sgibbs * modification, are permitted provided that the following conditions 1039213Sgibbs * are met: 1139213Sgibbs * 1. Redistributions of source code must retain the above copyright 1239213Sgibbs * notice, this list of conditions, and the following disclaimer, 1339213Sgibbs * without modification, immediately at the beginning of the file. 1439213Sgibbs * 2. The name of the author may not be used to endorse or promote products 1539213Sgibbs * derived from this software without specific prior written permission. 1639213Sgibbs * 1739213Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1839213Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1939213Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2039213Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 2139213Sgibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2239213Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2339213Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2439213Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2539213Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2639213Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2739213Sgibbs * SUCH DAMAGE. 2839213Sgibbs */ 2939213Sgibbs 30116162Sobrien#include <sys/cdefs.h> 31116162Sobrien__FBSDID("$FreeBSD$"); 32116162Sobrien 3339213Sgibbs#include <sys/param.h> 34225950Sken#include <sys/types.h> 35225950Sken#include <sys/stdint.h> 3639213Sgibbs 3755205Speter#ifdef _KERNEL 3839213Sgibbs#include <opt_scsi.h> 3939213Sgibbs 4039213Sgibbs#include <sys/systm.h> 4174840Sken#include <sys/libkern.h> 42102862Sbrooks#include <sys/kernel.h> 43249937Ssmh#include <sys/lock.h> 44249937Ssmh#include <sys/malloc.h> 45249937Ssmh#include <sys/mutex.h> 46102862Sbrooks#include <sys/sysctl.h> 47268700Smav#include <sys/ctype.h> 4839213Sgibbs#else 4939213Sgibbs#include <errno.h> 5039213Sgibbs#include <stdio.h> 5174840Sken#include <stdlib.h> 5239213Sgibbs#include <string.h> 53268700Smav#include <ctype.h> 5439213Sgibbs#endif 5539213Sgibbs 5639213Sgibbs#include <cam/cam.h> 5739213Sgibbs#include <cam/cam_ccb.h> 58195534Sscottl#include <cam/cam_queue.h> 5939213Sgibbs#include <cam/cam_xpt.h> 6039213Sgibbs#include <cam/scsi/scsi_all.h> 61248992Ssmh#include <sys/ata.h> 6274840Sken#include <sys/sbuf.h> 63249937Ssmh 64249937Ssmh#ifdef _KERNEL 65249937Ssmh#include <cam/cam_periph.h> 66249937Ssmh#include <cam/cam_xpt_sim.h> 67249937Ssmh#include <cam/cam_xpt_periph.h> 68249937Ssmh#include <cam/cam_xpt_internal.h> 69249937Ssmh#else 7039213Sgibbs#include <camlib.h> 71225950Sken#include <stddef.h> 7239213Sgibbs 7339213Sgibbs#ifndef FALSE 7439213Sgibbs#define FALSE 0 7539213Sgibbs#endif /* FALSE */ 7639213Sgibbs#ifndef TRUE 7739213Sgibbs#define TRUE 1 7839213Sgibbs#endif /* TRUE */ 7939213Sgibbs#define ERESTART -1 /* restart syscall */ 8039213Sgibbs#define EJUSTRETURN -2 /* don't modify regs, just return */ 8155205Speter#endif /* !_KERNEL */ 8239213Sgibbs 83102862Sbrooks/* 84181791Sken * This is the default number of milliseconds we wait for devices to settle 85102862Sbrooks * after a SCSI bus reset. 86102862Sbrooks */ 87102862Sbrooks#ifndef SCSI_DELAY 88102862Sbrooks#define SCSI_DELAY 2000 89102862Sbrooks#endif 90102862Sbrooks/* 91102862Sbrooks * All devices need _some_ sort of bus settle delay, so we'll set it to 92103818Smjacob * a minimum value of 100ms. Note that this is pertinent only for SPI- 93103818Smjacob * not transport like Fibre Channel or iSCSI where 'delay' is completely 94103818Smjacob * meaningless. 95102862Sbrooks */ 96102862Sbrooks#ifndef SCSI_MIN_DELAY 97102862Sbrooks#define SCSI_MIN_DELAY 100 98102862Sbrooks#endif 99102862Sbrooks/* 100102862Sbrooks * Make sure the user isn't using seconds instead of milliseconds. 101102862Sbrooks */ 102103818Smjacob#if (SCSI_DELAY < SCSI_MIN_DELAY && SCSI_DELAY != 0) 103102862Sbrooks#error "SCSI_DELAY is in milliseconds, not seconds! Please use a larger value" 104102862Sbrooks#endif 105102862Sbrooks 106102862Sbrooksint scsi_delay; 107102862Sbrooks 10874840Skenstatic int ascentrycomp(const void *key, const void *member); 10974840Skenstatic int senseentrycomp(const void *key, const void *member); 11074840Skenstatic void fetchtableentries(int sense_key, int asc, int ascq, 11174840Sken struct scsi_inquiry_data *, 11274840Sken const struct sense_key_table_entry **, 11374840Sken const struct asc_table_entry **); 114102862Sbrooks#ifdef _KERNEL 115102862Sbrooksstatic void init_scsi_delay(void); 116102862Sbrooksstatic int sysctl_scsi_delay(SYSCTL_HANDLER_ARGS); 117102862Sbrooksstatic int set_scsi_delay(int delay); 118102862Sbrooks#endif 11939213Sgibbs 12039213Sgibbs#if !defined(SCSI_NO_OP_STRINGS) 12139213Sgibbs 122181381Sjkim#define D (1 << T_DIRECT) 123181381Sjkim#define T (1 << T_SEQUENTIAL) 124181381Sjkim#define L (1 << T_PRINTER) 125181381Sjkim#define P (1 << T_PROCESSOR) 126181381Sjkim#define W (1 << T_WORM) 127181381Sjkim#define R (1 << T_CDROM) 128181381Sjkim#define O (1 << T_OPTICAL) 129181381Sjkim#define M (1 << T_CHANGER) 130181381Sjkim#define A (1 << T_STORARRAY) 131181381Sjkim#define E (1 << T_ENCLOSURE) 132181381Sjkim#define B (1 << T_RBC) 133181381Sjkim#define K (1 << T_OCRW) 134181381Sjkim#define V (1 << T_ADC) 135181381Sjkim#define F (1 << T_OSD) 136181381Sjkim#define S (1 << T_SCANNER) 137181381Sjkim#define C (1 << T_COMM) 13839213Sgibbs 139181381Sjkim#define ALL (D | T | L | P | W | R | O | M | A | E | B | K | V | F | S | C) 14039213Sgibbs 14139213Sgibbsstatic struct op_table_entry plextor_cd_ops[] = { 142181381Sjkim { 0xD8, R, "CD-DA READ" } 14339213Sgibbs}; 14439213Sgibbs 14539213Sgibbsstatic struct scsi_op_quirk_entry scsi_op_quirk_table[] = { 14639213Sgibbs { 14739213Sgibbs /* 14839213Sgibbs * I believe that 0xD8 is the Plextor proprietary command 14939213Sgibbs * to read CD-DA data. I'm not sure which Plextor CDROM 15039213Sgibbs * models support the command, though. I know for sure 15139213Sgibbs * that the 4X, 8X, and 12X models do, and presumably the 15239213Sgibbs * 12-20X does. I don't know about any earlier models, 15339213Sgibbs * though. If anyone has any more complete information, 15439213Sgibbs * feel free to change this quirk entry. 15539213Sgibbs */ 15639213Sgibbs {T_CDROM, SIP_MEDIA_REMOVABLE, "PLEXTOR", "CD-ROM PX*", "*"}, 15774840Sken sizeof(plextor_cd_ops)/sizeof(struct op_table_entry), 15839213Sgibbs plextor_cd_ops 15939213Sgibbs } 16039213Sgibbs}; 16139213Sgibbs 16239213Sgibbsstatic struct op_table_entry scsi_op_codes[] = { 163181381Sjkim /* 164181381Sjkim * From: http://www.t10.org/lists/op-num.txt 165181381Sjkim * Modifications by Kenneth Merry (ken@FreeBSD.ORG) 166181381Sjkim * and Jung-uk Kim (jkim@FreeBSD.org) 167181381Sjkim * 168181381Sjkim * Note: order is important in this table, scsi_op_desc() currently 169181381Sjkim * depends on the opcodes in the table being in order to save 170181381Sjkim * search time. 171181381Sjkim * Note: scanner and comm. devices are carried over from the previous 172181381Sjkim * version because they were removed in the latest spec. 173181381Sjkim */ 174181381Sjkim /* File: OP-NUM.TXT 175181381Sjkim * 176181381Sjkim * SCSI Operation Codes 177181381Sjkim * Numeric Sorted Listing 178181381Sjkim * as of 3/11/08 179181381Sjkim * 180181381Sjkim * D - DIRECT ACCESS DEVICE (SBC-2) device column key 181181381Sjkim * .T - SEQUENTIAL ACCESS DEVICE (SSC-2) ----------------- 182181381Sjkim * . L - PRINTER DEVICE (SSC) M = Mandatory 183181381Sjkim * . P - PROCESSOR DEVICE (SPC) O = Optional 184181381Sjkim * . .W - WRITE ONCE READ MULTIPLE DEVICE (SBC-2) V = Vendor spec. 185181381Sjkim * . . R - CD/DVE DEVICE (MMC-3) Z = Obsolete 186181381Sjkim * . . O - OPTICAL MEMORY DEVICE (SBC-2) 187181381Sjkim * . . .M - MEDIA CHANGER DEVICE (SMC-2) 188181381Sjkim * . . . A - STORAGE ARRAY DEVICE (SCC-2) 189181381Sjkim * . . . .E - ENCLOSURE SERVICES DEVICE (SES) 190181381Sjkim * . . . .B - SIMPLIFIED DIRECT-ACCESS DEVICE (RBC) 191181381Sjkim * . . . . K - OPTICAL CARD READER/WRITER DEVICE (OCRW) 192181381Sjkim * . . . . V - AUTOMATION/DRIVE INTERFACE (ADC) 193181381Sjkim * . . . . .F - OBJECT-BASED STORAGE (OSD) 194181381Sjkim * OP DTLPWROMAEBKVF Description 195181381Sjkim * -- -------------- ---------------------------------------------- */ 196181381Sjkim /* 00 MMMMMMMMMMMMMM TEST UNIT READY */ 197181381Sjkim { 0x00, ALL, "TEST UNIT READY" }, 198181381Sjkim /* 01 M REWIND */ 199181381Sjkim { 0x01, T, "REWIND" }, 200181381Sjkim /* 01 Z V ZZZZ REZERO UNIT */ 201181381Sjkim { 0x01, D | W | R | O | M, "REZERO UNIT" }, 202181381Sjkim /* 02 VVVVVV V */ 203181381Sjkim /* 03 MMMMMMMMMMOMMM REQUEST SENSE */ 204181381Sjkim { 0x03, ALL, "REQUEST SENSE" }, 205181381Sjkim /* 04 M OO FORMAT UNIT */ 206181381Sjkim { 0x04, D | R | O, "FORMAT UNIT" }, 207181381Sjkim /* 04 O FORMAT MEDIUM */ 208181381Sjkim { 0x04, T, "FORMAT MEDIUM" }, 209181381Sjkim /* 04 O FORMAT */ 210181381Sjkim { 0x04, L, "FORMAT" }, 211181381Sjkim /* 05 VMVVVV V READ BLOCK LIMITS */ 212181381Sjkim { 0x05, T, "READ BLOCK LIMITS" }, 213181381Sjkim /* 06 VVVVVV V */ 214181381Sjkim /* 07 OVV O OV REASSIGN BLOCKS */ 215181381Sjkim { 0x07, D | W | O, "REASSIGN BLOCKS" }, 216181381Sjkim /* 07 O INITIALIZE ELEMENT STATUS */ 217181381Sjkim { 0x07, M, "INITIALIZE ELEMENT STATUS" }, 218181381Sjkim /* 08 MOV O OV READ(6) */ 219181381Sjkim { 0x08, D | T | W | O, "READ(6)" }, 220181381Sjkim /* 08 O RECEIVE */ 221181381Sjkim { 0x08, P, "RECEIVE" }, 222181381Sjkim /* 08 GET MESSAGE(6) */ 223181381Sjkim { 0x08, C, "GET MESSAGE(6)" }, 224181381Sjkim /* 09 VVVVVV V */ 225181381Sjkim /* 0A OO O OV WRITE(6) */ 226181381Sjkim { 0x0A, D | T | W | O, "WRITE(6)" }, 227181381Sjkim /* 0A M SEND(6) */ 228181381Sjkim { 0x0A, P, "SEND(6)" }, 229181381Sjkim /* 0A SEND MESSAGE(6) */ 230181381Sjkim { 0x0A, C, "SEND MESSAGE(6)" }, 231181381Sjkim /* 0A M PRINT */ 232181381Sjkim { 0x0A, L, "PRINT" }, 233181381Sjkim /* 0B Z ZOZV SEEK(6) */ 234181381Sjkim { 0x0B, D | W | R | O, "SEEK(6)" }, 235181381Sjkim /* 0B O SET CAPACITY */ 236181381Sjkim { 0x0B, T, "SET CAPACITY" }, 237181381Sjkim /* 0B O SLEW AND PRINT */ 238181381Sjkim { 0x0B, L, "SLEW AND PRINT" }, 239181381Sjkim /* 0C VVVVVV V */ 240181381Sjkim /* 0D VVVVVV V */ 241181381Sjkim /* 0E VVVVVV V */ 242181381Sjkim /* 0F VOVVVV V READ REVERSE(6) */ 243181381Sjkim { 0x0F, T, "READ REVERSE(6)" }, 244181381Sjkim /* 10 VM VVV WRITE FILEMARKS(6) */ 245181381Sjkim { 0x10, T, "WRITE FILEMARKS(6)" }, 246181381Sjkim /* 10 O SYNCHRONIZE BUFFER */ 247181381Sjkim { 0x10, L, "SYNCHRONIZE BUFFER" }, 248181381Sjkim /* 11 VMVVVV SPACE(6) */ 249181381Sjkim { 0x11, T, "SPACE(6)" }, 250181381Sjkim /* 12 MMMMMMMMMMMMMM INQUIRY */ 251181381Sjkim { 0x12, ALL, "INQUIRY" }, 252181381Sjkim /* 13 V VVVV */ 253181381Sjkim /* 13 O VERIFY(6) */ 254181381Sjkim { 0x13, T, "VERIFY(6)" }, 255181381Sjkim /* 14 VOOVVV RECOVER BUFFERED DATA */ 256181381Sjkim { 0x14, T | L, "RECOVER BUFFERED DATA" }, 257181381Sjkim /* 15 OMO O OOOO OO MODE SELECT(6) */ 258181381Sjkim { 0x15, ALL & ~(P | R | B | F), "MODE SELECT(6)" }, 259181381Sjkim /* 16 ZZMZO OOOZ O RESERVE(6) */ 260181381Sjkim { 0x16, ALL & ~(R | B | V | F | C), "RESERVE(6)" }, 261181381Sjkim /* 16 Z RESERVE ELEMENT(6) */ 262181381Sjkim { 0x16, M, "RESERVE ELEMENT(6)" }, 263181381Sjkim /* 17 ZZMZO OOOZ O RELEASE(6) */ 264181381Sjkim { 0x17, ALL & ~(R | B | V | F | C), "RELEASE(6)" }, 265181381Sjkim /* 17 Z RELEASE ELEMENT(6) */ 266181381Sjkim { 0x17, M, "RELEASE ELEMENT(6)" }, 267181381Sjkim /* 18 ZZZZOZO Z COPY */ 268181381Sjkim { 0x18, D | T | L | P | W | R | O | K | S, "COPY" }, 269181381Sjkim /* 19 VMVVVV ERASE(6) */ 270181381Sjkim { 0x19, T, "ERASE(6)" }, 271181381Sjkim /* 1A OMO O OOOO OO MODE SENSE(6) */ 272181381Sjkim { 0x1A, ALL & ~(P | R | B | F), "MODE SENSE(6)" }, 273181381Sjkim /* 1B O OOO O MO O START STOP UNIT */ 274181381Sjkim { 0x1B, D | W | R | O | A | B | K | F, "START STOP UNIT" }, 275181381Sjkim /* 1B O M LOAD UNLOAD */ 276181381Sjkim { 0x1B, T | V, "LOAD UNLOAD" }, 277181381Sjkim /* 1B SCAN */ 278181381Sjkim { 0x1B, S, "SCAN" }, 279181381Sjkim /* 1B O STOP PRINT */ 280181381Sjkim { 0x1B, L, "STOP PRINT" }, 281181381Sjkim /* 1B O OPEN/CLOSE IMPORT/EXPORT ELEMENT */ 282181381Sjkim { 0x1B, M, "OPEN/CLOSE IMPORT/EXPORT ELEMENT" }, 283181381Sjkim /* 1C OOOOO OOOM OOO RECEIVE DIAGNOSTIC RESULTS */ 284181381Sjkim { 0x1C, ALL & ~(R | B), "RECEIVE DIAGNOSTIC RESULTS" }, 285181381Sjkim /* 1D MMMMM MMOM MMM SEND DIAGNOSTIC */ 286181381Sjkim { 0x1D, ALL & ~(R | B), "SEND DIAGNOSTIC" }, 287181381Sjkim /* 1E OO OOOO O O PREVENT ALLOW MEDIUM REMOVAL */ 288181381Sjkim { 0x1E, D | T | W | R | O | M | K | F, "PREVENT ALLOW MEDIUM REMOVAL" }, 289181381Sjkim /* 1F */ 290181381Sjkim /* 20 V VVV V */ 291181381Sjkim /* 21 V VVV V */ 292181381Sjkim /* 22 V VVV V */ 293181381Sjkim /* 23 V V V V */ 294181381Sjkim /* 23 O READ FORMAT CAPACITIES */ 295181381Sjkim { 0x23, R, "READ FORMAT CAPACITIES" }, 296181381Sjkim /* 24 V VV SET WINDOW */ 297181381Sjkim { 0x24, S, "SET WINDOW" }, 298181381Sjkim /* 25 M M M M READ CAPACITY(10) */ 299181381Sjkim { 0x25, D | W | O | B, "READ CAPACITY(10)" }, 300181381Sjkim /* 25 O READ CAPACITY */ 301181381Sjkim { 0x25, R, "READ CAPACITY" }, 302181381Sjkim /* 25 M READ CARD CAPACITY */ 303181381Sjkim { 0x25, K, "READ CARD CAPACITY" }, 304181381Sjkim /* 25 GET WINDOW */ 305181381Sjkim { 0x25, S, "GET WINDOW" }, 306181381Sjkim /* 26 V VV */ 307181381Sjkim /* 27 V VV */ 308181381Sjkim /* 28 M MOM MM READ(10) */ 309181381Sjkim { 0x28, D | W | R | O | B | K | S, "READ(10)" }, 310181381Sjkim /* 28 GET MESSAGE(10) */ 311181381Sjkim { 0x28, C, "GET MESSAGE(10)" }, 312181381Sjkim /* 29 V VVO READ GENERATION */ 313181381Sjkim { 0x29, O, "READ GENERATION" }, 314181381Sjkim /* 2A O MOM MO WRITE(10) */ 315181381Sjkim { 0x2A, D | W | R | O | B | K, "WRITE(10)" }, 316181381Sjkim /* 2A SEND(10) */ 317181381Sjkim { 0x2A, S, "SEND(10)" }, 318181381Sjkim /* 2A SEND MESSAGE(10) */ 319181381Sjkim { 0x2A, C, "SEND MESSAGE(10)" }, 320181381Sjkim /* 2B Z OOO O SEEK(10) */ 321181381Sjkim { 0x2B, D | W | R | O | K, "SEEK(10)" }, 322181381Sjkim /* 2B O LOCATE(10) */ 323181381Sjkim { 0x2B, T, "LOCATE(10)" }, 324181381Sjkim /* 2B O POSITION TO ELEMENT */ 325181381Sjkim { 0x2B, M, "POSITION TO ELEMENT" }, 326181381Sjkim /* 2C V OO ERASE(10) */ 327181381Sjkim { 0x2C, R | O, "ERASE(10)" }, 328181381Sjkim /* 2D O READ UPDATED BLOCK */ 329181381Sjkim { 0x2D, O, "READ UPDATED BLOCK" }, 330181381Sjkim /* 2D V */ 331181381Sjkim /* 2E O OOO MO WRITE AND VERIFY(10) */ 332181381Sjkim { 0x2E, D | W | R | O | B | K, "WRITE AND VERIFY(10)" }, 333181381Sjkim /* 2F O OOO VERIFY(10) */ 334181381Sjkim { 0x2F, D | W | R | O, "VERIFY(10)" }, 335181381Sjkim /* 30 Z ZZZ SEARCH DATA HIGH(10) */ 336181381Sjkim { 0x30, D | W | R | O, "SEARCH DATA HIGH(10)" }, 337181381Sjkim /* 31 Z ZZZ SEARCH DATA EQUAL(10) */ 338181381Sjkim { 0x31, D | W | R | O, "SEARCH DATA EQUAL(10)" }, 339181381Sjkim /* 31 OBJECT POSITION */ 340181381Sjkim { 0x31, S, "OBJECT POSITION" }, 341181381Sjkim /* 32 Z ZZZ SEARCH DATA LOW(10) */ 342181381Sjkim { 0x32, D | W | R | O, "SEARCH DATA LOW(10)" }, 343181381Sjkim /* 33 Z OZO SET LIMITS(10) */ 344181381Sjkim { 0x33, D | W | R | O, "SET LIMITS(10)" }, 345181381Sjkim /* 34 O O O O PRE-FETCH(10) */ 346181381Sjkim { 0x34, D | W | O | K, "PRE-FETCH(10)" }, 347181381Sjkim /* 34 M READ POSITION */ 348181381Sjkim { 0x34, T, "READ POSITION" }, 349181381Sjkim /* 34 GET DATA BUFFER STATUS */ 350181381Sjkim { 0x34, S, "GET DATA BUFFER STATUS" }, 351181381Sjkim /* 35 O OOO MO SYNCHRONIZE CACHE(10) */ 352181381Sjkim { 0x35, D | W | R | O | B | K, "SYNCHRONIZE CACHE(10)" }, 353181381Sjkim /* 36 Z O O O LOCK UNLOCK CACHE(10) */ 354181381Sjkim { 0x36, D | W | O | K, "LOCK UNLOCK CACHE(10)" }, 355181381Sjkim /* 37 O O READ DEFECT DATA(10) */ 356181381Sjkim { 0x37, D | O, "READ DEFECT DATA(10)" }, 357181381Sjkim /* 37 O INITIALIZE ELEMENT STATUS WITH RANGE */ 358181381Sjkim { 0x37, M, "INITIALIZE ELEMENT STATUS WITH RANGE" }, 359181381Sjkim /* 38 O O O MEDIUM SCAN */ 360181381Sjkim { 0x38, W | O | K, "MEDIUM SCAN" }, 361181381Sjkim /* 39 ZZZZOZO Z COMPARE */ 362181381Sjkim { 0x39, D | T | L | P | W | R | O | K | S, "COMPARE" }, 363181381Sjkim /* 3A ZZZZOZO Z COPY AND VERIFY */ 364181381Sjkim { 0x3A, D | T | L | P | W | R | O | K | S, "COPY AND VERIFY" }, 365181381Sjkim /* 3B OOOOOOOOOOMOOO WRITE BUFFER */ 366181381Sjkim { 0x3B, ALL, "WRITE BUFFER" }, 367181381Sjkim /* 3C OOOOOOOOOO OOO READ BUFFER */ 368181381Sjkim { 0x3C, ALL & ~(B), "READ BUFFER" }, 369181381Sjkim /* 3D O UPDATE BLOCK */ 370181381Sjkim { 0x3D, O, "UPDATE BLOCK" }, 371181381Sjkim /* 3E O O O READ LONG(10) */ 372181381Sjkim { 0x3E, D | W | O, "READ LONG(10)" }, 373181381Sjkim /* 3F O O O WRITE LONG(10) */ 374181381Sjkim { 0x3F, D | W | O, "WRITE LONG(10)" }, 375181381Sjkim /* 40 ZZZZOZOZ CHANGE DEFINITION */ 376181381Sjkim { 0x40, D | T | L | P | W | R | O | M | S | C, "CHANGE DEFINITION" }, 377181381Sjkim /* 41 O WRITE SAME(10) */ 378181381Sjkim { 0x41, D, "WRITE SAME(10)" }, 379230053Smav /* 42 O UNMAP */ 380230053Smav { 0x42, D, "UNMAP" }, 381181381Sjkim /* 42 O READ SUB-CHANNEL */ 382181381Sjkim { 0x42, R, "READ SUB-CHANNEL" }, 383181381Sjkim /* 43 O READ TOC/PMA/ATIP */ 384181381Sjkim { 0x43, R, "READ TOC/PMA/ATIP" }, 385181381Sjkim /* 44 M M REPORT DENSITY SUPPORT */ 386181381Sjkim { 0x44, T | V, "REPORT DENSITY SUPPORT" }, 387181381Sjkim /* 44 READ HEADER */ 388181381Sjkim /* 45 O PLAY AUDIO(10) */ 389181381Sjkim { 0x45, R, "PLAY AUDIO(10)" }, 390181381Sjkim /* 46 M GET CONFIGURATION */ 391181381Sjkim { 0x46, R, "GET CONFIGURATION" }, 392181381Sjkim /* 47 O PLAY AUDIO MSF */ 393181381Sjkim { 0x47, R, "PLAY AUDIO MSF" }, 394181381Sjkim /* 48 */ 395181381Sjkim /* 49 */ 396181381Sjkim /* 4A M GET EVENT STATUS NOTIFICATION */ 397181381Sjkim { 0x4A, R, "GET EVENT STATUS NOTIFICATION" }, 398181381Sjkim /* 4B O PAUSE/RESUME */ 399181381Sjkim { 0x4B, R, "PAUSE/RESUME" }, 400181381Sjkim /* 4C OOOOO OOOO OOO LOG SELECT */ 401181381Sjkim { 0x4C, ALL & ~(R | B), "LOG SELECT" }, 402181381Sjkim /* 4D OOOOO OOOO OMO LOG SENSE */ 403181381Sjkim { 0x4D, ALL & ~(R | B), "LOG SENSE" }, 404181381Sjkim /* 4E O STOP PLAY/SCAN */ 405181381Sjkim { 0x4E, R, "STOP PLAY/SCAN" }, 406181381Sjkim /* 4F */ 407181381Sjkim /* 50 O XDWRITE(10) */ 408181381Sjkim { 0x50, D, "XDWRITE(10)" }, 409181381Sjkim /* 51 O XPWRITE(10) */ 410181381Sjkim { 0x51, D, "XPWRITE(10)" }, 411181381Sjkim /* 51 O READ DISC INFORMATION */ 412181381Sjkim { 0x51, R, "READ DISC INFORMATION" }, 413181381Sjkim /* 52 O XDREAD(10) */ 414181381Sjkim { 0x52, D, "XDREAD(10)" }, 415181381Sjkim /* 52 O READ TRACK INFORMATION */ 416181381Sjkim { 0x52, R, "READ TRACK INFORMATION" }, 417181381Sjkim /* 53 O RESERVE TRACK */ 418181381Sjkim { 0x53, R, "RESERVE TRACK" }, 419181381Sjkim /* 54 O SEND OPC INFORMATION */ 420181381Sjkim { 0x54, R, "SEND OPC INFORMATION" }, 421181381Sjkim /* 55 OOO OMOOOOMOMO MODE SELECT(10) */ 422181381Sjkim { 0x55, ALL & ~(P), "MODE SELECT(10)" }, 423181381Sjkim /* 56 ZZMZO OOOZ RESERVE(10) */ 424181381Sjkim { 0x56, ALL & ~(R | B | K | V | F | C), "RESERVE(10)" }, 425181381Sjkim /* 56 Z RESERVE ELEMENT(10) */ 426181381Sjkim { 0x56, M, "RESERVE ELEMENT(10)" }, 427181381Sjkim /* 57 ZZMZO OOOZ RELEASE(10) */ 428181381Sjkim { 0x57, ALL & ~(R | B | K | V | F | C), "RELEASE(10)" }, 429181381Sjkim /* 57 Z RELEASE ELEMENT(10) */ 430181381Sjkim { 0x57, M, "RELEASE ELEMENT(10)" }, 431181381Sjkim /* 58 O REPAIR TRACK */ 432181381Sjkim { 0x58, R, "REPAIR TRACK" }, 433181381Sjkim /* 59 */ 434181381Sjkim /* 5A OOO OMOOOOMOMO MODE SENSE(10) */ 435181381Sjkim { 0x5A, ALL & ~(P), "MODE SENSE(10)" }, 436181381Sjkim /* 5B O CLOSE TRACK/SESSION */ 437181381Sjkim { 0x5B, R, "CLOSE TRACK/SESSION" }, 438181381Sjkim /* 5C O READ BUFFER CAPACITY */ 439181381Sjkim { 0x5C, R, "READ BUFFER CAPACITY" }, 440181381Sjkim /* 5D O SEND CUE SHEET */ 441181381Sjkim { 0x5D, R, "SEND CUE SHEET" }, 442181381Sjkim /* 5E OOOOO OOOO M PERSISTENT RESERVE IN */ 443181381Sjkim { 0x5E, ALL & ~(R | B | K | V | C), "PERSISTENT RESERVE IN" }, 444181381Sjkim /* 5F OOOOO OOOO M PERSISTENT RESERVE OUT */ 445181381Sjkim { 0x5F, ALL & ~(R | B | K | V | C), "PERSISTENT RESERVE OUT" }, 446181381Sjkim /* 7E OO O OOOO O extended CDB */ 447181381Sjkim { 0x7E, D | T | R | M | A | E | B | V, "extended CDB" }, 448181381Sjkim /* 7F O M variable length CDB (more than 16 bytes) */ 449181381Sjkim { 0x7F, D | F, "variable length CDB (more than 16 bytes)" }, 450181381Sjkim /* 80 Z XDWRITE EXTENDED(16) */ 451181381Sjkim { 0x80, D, "XDWRITE EXTENDED(16)" }, 452181381Sjkim /* 80 M WRITE FILEMARKS(16) */ 453181381Sjkim { 0x80, T, "WRITE FILEMARKS(16)" }, 454181381Sjkim /* 81 Z REBUILD(16) */ 455181381Sjkim { 0x81, D, "REBUILD(16)" }, 456181381Sjkim /* 81 O READ REVERSE(16) */ 457181381Sjkim { 0x81, T, "READ REVERSE(16)" }, 458181381Sjkim /* 82 Z REGENERATE(16) */ 459181381Sjkim { 0x82, D, "REGENERATE(16)" }, 460181381Sjkim /* 83 OOOOO O OO EXTENDED COPY */ 461181381Sjkim { 0x83, D | T | L | P | W | O | K | V, "EXTENDED COPY" }, 462181381Sjkim /* 84 OOOOO O OO RECEIVE COPY RESULTS */ 463181381Sjkim { 0x84, D | T | L | P | W | O | K | V, "RECEIVE COPY RESULTS" }, 464181381Sjkim /* 85 O O O ATA COMMAND PASS THROUGH(16) */ 465181381Sjkim { 0x85, D | R | B, "ATA COMMAND PASS THROUGH(16)" }, 466181381Sjkim /* 86 OO OO OOOOOOO ACCESS CONTROL IN */ 467181381Sjkim { 0x86, ALL & ~(L | R | F), "ACCESS CONTROL IN" }, 468181381Sjkim /* 87 OO OO OOOOOOO ACCESS CONTROL OUT */ 469181381Sjkim { 0x87, ALL & ~(L | R | F), "ACCESS CONTROL OUT" }, 470181381Sjkim /* 471181381Sjkim * XXX READ(16)/WRITE(16) were not listed for CD/DVE in op-num.txt 472181381Sjkim * but we had it since r1.40. Do we really want them? 473181381Sjkim */ 474181381Sjkim /* 88 MM O O O READ(16) */ 475181381Sjkim { 0x88, D | T | W | O | B, "READ(16)" }, 476268151Smav /* 89 O COMPARE AND WRITE*/ 477268151Smav { 0x89, D, "COMPARE AND WRITE" }, 478181381Sjkim /* 8A OM O O O WRITE(16) */ 479181381Sjkim { 0x8A, D | T | W | O | B, "WRITE(16)" }, 480181381Sjkim /* 8B O ORWRITE */ 481181381Sjkim { 0x8B, D, "ORWRITE" }, 482181381Sjkim /* 8C OO O OO O M READ ATTRIBUTE */ 483181381Sjkim { 0x8C, D | T | W | O | M | B | V, "READ ATTRIBUTE" }, 484181381Sjkim /* 8D OO O OO O O WRITE ATTRIBUTE */ 485181381Sjkim { 0x8D, D | T | W | O | M | B | V, "WRITE ATTRIBUTE" }, 486181381Sjkim /* 8E O O O O WRITE AND VERIFY(16) */ 487181381Sjkim { 0x8E, D | W | O | B, "WRITE AND VERIFY(16)" }, 488181381Sjkim /* 8F OO O O O VERIFY(16) */ 489181381Sjkim { 0x8F, D | T | W | O | B, "VERIFY(16)" }, 490181381Sjkim /* 90 O O O O PRE-FETCH(16) */ 491181381Sjkim { 0x90, D | W | O | B, "PRE-FETCH(16)" }, 492181381Sjkim /* 91 O O O O SYNCHRONIZE CACHE(16) */ 493181381Sjkim { 0x91, D | W | O | B, "SYNCHRONIZE CACHE(16)" }, 494181381Sjkim /* 91 O SPACE(16) */ 495181381Sjkim { 0x91, T, "SPACE(16)" }, 496181381Sjkim /* 92 Z O O LOCK UNLOCK CACHE(16) */ 497181381Sjkim { 0x92, D | W | O, "LOCK UNLOCK CACHE(16)" }, 498181381Sjkim /* 92 O LOCATE(16) */ 499181381Sjkim { 0x92, T, "LOCATE(16)" }, 500181381Sjkim /* 93 O WRITE SAME(16) */ 501181381Sjkim { 0x93, D, "WRITE SAME(16)" }, 502181381Sjkim /* 93 M ERASE(16) */ 503181381Sjkim { 0x93, T, "ERASE(16)" }, 504181381Sjkim /* 94 [usage proposed by SCSI Socket Services project] */ 505181381Sjkim /* 95 [usage proposed by SCSI Socket Services project] */ 506181381Sjkim /* 96 [usage proposed by SCSI Socket Services project] */ 507181381Sjkim /* 97 [usage proposed by SCSI Socket Services project] */ 508181381Sjkim /* 98 */ 509181381Sjkim /* 99 */ 510181381Sjkim /* 9A */ 511181381Sjkim /* 9B */ 512181381Sjkim /* 9C */ 513181381Sjkim /* 9D */ 514181381Sjkim /* XXX KDM ALL for this? op-num.txt defines it for none.. */ 515181381Sjkim /* 9E SERVICE ACTION IN(16) */ 516181381Sjkim { 0x9E, ALL, "SERVICE ACTION IN(16)" }, 517181381Sjkim /* XXX KDM ALL for this? op-num.txt defines it for ADC.. */ 518181381Sjkim /* 9F M SERVICE ACTION OUT(16) */ 519181381Sjkim { 0x9F, ALL, "SERVICE ACTION OUT(16)" }, 520181381Sjkim /* A0 MMOOO OMMM OMO REPORT LUNS */ 521181381Sjkim { 0xA0, ALL & ~(R | B), "REPORT LUNS" }, 522181381Sjkim /* A1 O BLANK */ 523181381Sjkim { 0xA1, R, "BLANK" }, 524181381Sjkim /* A1 O O ATA COMMAND PASS THROUGH(12) */ 525181381Sjkim { 0xA1, D | B, "ATA COMMAND PASS THROUGH(12)" }, 526181381Sjkim /* A2 OO O O SECURITY PROTOCOL IN */ 527181381Sjkim { 0xA2, D | T | R | V, "SECURITY PROTOCOL IN" }, 528181381Sjkim /* A3 OOO O OOMOOOM MAINTENANCE (IN) */ 529181381Sjkim { 0xA3, ALL & ~(P | R | F), "MAINTENANCE (IN)" }, 530181381Sjkim /* A3 O SEND KEY */ 531181381Sjkim { 0xA3, R, "SEND KEY" }, 532181381Sjkim /* A4 OOO O OOOOOOO MAINTENANCE (OUT) */ 533181381Sjkim { 0xA4, ALL & ~(P | R | F), "MAINTENANCE (OUT)" }, 534181381Sjkim /* A4 O REPORT KEY */ 535181381Sjkim { 0xA4, R, "REPORT KEY" }, 536181381Sjkim /* A5 O O OM MOVE MEDIUM */ 537181381Sjkim { 0xA5, T | W | O | M, "MOVE MEDIUM" }, 538181381Sjkim /* A5 O PLAY AUDIO(12) */ 539181381Sjkim { 0xA5, R, "PLAY AUDIO(12)" }, 540181381Sjkim /* A6 O EXCHANGE MEDIUM */ 541181381Sjkim { 0xA6, M, "EXCHANGE MEDIUM" }, 542181381Sjkim /* A6 O LOAD/UNLOAD C/DVD */ 543181381Sjkim { 0xA6, R, "LOAD/UNLOAD C/DVD" }, 544181381Sjkim /* A7 ZZ O O MOVE MEDIUM ATTACHED */ 545181381Sjkim { 0xA7, D | T | W | O, "MOVE MEDIUM ATTACHED" }, 546181381Sjkim /* A7 O SET READ AHEAD */ 547181381Sjkim { 0xA7, R, "SET READ AHEAD" }, 548181381Sjkim /* A8 O OOO READ(12) */ 549181381Sjkim { 0xA8, D | W | R | O, "READ(12)" }, 550181381Sjkim /* A8 GET MESSAGE(12) */ 551181381Sjkim { 0xA8, C, "GET MESSAGE(12)" }, 552181381Sjkim /* A9 O SERVICE ACTION OUT(12) */ 553181381Sjkim { 0xA9, V, "SERVICE ACTION OUT(12)" }, 554181381Sjkim /* AA O OOO WRITE(12) */ 555181381Sjkim { 0xAA, D | W | R | O, "WRITE(12)" }, 556181381Sjkim /* AA SEND MESSAGE(12) */ 557181381Sjkim { 0xAA, C, "SEND MESSAGE(12)" }, 558181381Sjkim /* AB O O SERVICE ACTION IN(12) */ 559181381Sjkim { 0xAB, R | V, "SERVICE ACTION IN(12)" }, 560181381Sjkim /* AC O ERASE(12) */ 561181381Sjkim { 0xAC, O, "ERASE(12)" }, 562181381Sjkim /* AC O GET PERFORMANCE */ 563181381Sjkim { 0xAC, R, "GET PERFORMANCE" }, 564181381Sjkim /* AD O READ DVD STRUCTURE */ 565181381Sjkim { 0xAD, R, "READ DVD STRUCTURE" }, 566181381Sjkim /* AE O O O WRITE AND VERIFY(12) */ 567181381Sjkim { 0xAE, D | W | O, "WRITE AND VERIFY(12)" }, 568181381Sjkim /* AF O OZO VERIFY(12) */ 569181381Sjkim { 0xAF, D | W | R | O, "VERIFY(12)" }, 570181381Sjkim /* B0 ZZZ SEARCH DATA HIGH(12) */ 571181381Sjkim { 0xB0, W | R | O, "SEARCH DATA HIGH(12)" }, 572181381Sjkim /* B1 ZZZ SEARCH DATA EQUAL(12) */ 573181381Sjkim { 0xB1, W | R | O, "SEARCH DATA EQUAL(12)" }, 574181381Sjkim /* B2 ZZZ SEARCH DATA LOW(12) */ 575181381Sjkim { 0xB2, W | R | O, "SEARCH DATA LOW(12)" }, 576181381Sjkim /* B3 Z OZO SET LIMITS(12) */ 577181381Sjkim { 0xB3, D | W | R | O, "SET LIMITS(12)" }, 578181381Sjkim /* B4 ZZ OZO READ ELEMENT STATUS ATTACHED */ 579181381Sjkim { 0xB4, D | T | W | R | O, "READ ELEMENT STATUS ATTACHED" }, 580181381Sjkim /* B5 OO O O SECURITY PROTOCOL OUT */ 581181381Sjkim { 0xB5, D | T | R | V, "SECURITY PROTOCOL OUT" }, 582181381Sjkim /* B5 O REQUEST VOLUME ELEMENT ADDRESS */ 583181381Sjkim { 0xB5, M, "REQUEST VOLUME ELEMENT ADDRESS" }, 584181381Sjkim /* B6 O SEND VOLUME TAG */ 585181381Sjkim { 0xB6, M, "SEND VOLUME TAG" }, 586181381Sjkim /* B6 O SET STREAMING */ 587181381Sjkim { 0xB6, R, "SET STREAMING" }, 588181381Sjkim /* B7 O O READ DEFECT DATA(12) */ 589181381Sjkim { 0xB7, D | O, "READ DEFECT DATA(12)" }, 590181381Sjkim /* B8 O OZOM READ ELEMENT STATUS */ 591181381Sjkim { 0xB8, T | W | R | O | M, "READ ELEMENT STATUS" }, 592181381Sjkim /* B9 O READ CD MSF */ 593181381Sjkim { 0xB9, R, "READ CD MSF" }, 594181381Sjkim /* BA O O OOMO REDUNDANCY GROUP (IN) */ 595181381Sjkim { 0xBA, D | W | O | M | A | E, "REDUNDANCY GROUP (IN)" }, 596181381Sjkim /* BA O SCAN */ 597181381Sjkim { 0xBA, R, "SCAN" }, 598181381Sjkim /* BB O O OOOO REDUNDANCY GROUP (OUT) */ 599181381Sjkim { 0xBB, D | W | O | M | A | E, "REDUNDANCY GROUP (OUT)" }, 600181381Sjkim /* BB O SET CD SPEED */ 601181381Sjkim { 0xBB, R, "SET CD SPEED" }, 602181381Sjkim /* BC O O OOMO SPARE (IN) */ 603181381Sjkim { 0xBC, D | W | O | M | A | E, "SPARE (IN)" }, 604181381Sjkim /* BD O O OOOO SPARE (OUT) */ 605181381Sjkim { 0xBD, D | W | O | M | A | E, "SPARE (OUT)" }, 606181381Sjkim /* BD O MECHANISM STATUS */ 607181381Sjkim { 0xBD, R, "MECHANISM STATUS" }, 608181381Sjkim /* BE O O OOMO VOLUME SET (IN) */ 609181381Sjkim { 0xBE, D | W | O | M | A | E, "VOLUME SET (IN)" }, 610181381Sjkim /* BE O READ CD */ 611181381Sjkim { 0xBE, R, "READ CD" }, 612181381Sjkim /* BF O O OOOO VOLUME SET (OUT) */ 613181381Sjkim { 0xBF, D | W | O | M | A | E, "VOLUME SET (OUT)" }, 614181381Sjkim /* BF O SEND DVD STRUCTURE */ 615181381Sjkim { 0xBF, R, "SEND DVD STRUCTURE" } 61639213Sgibbs}; 61739213Sgibbs 61839213Sgibbsconst char * 61939213Sgibbsscsi_op_desc(u_int16_t opcode, struct scsi_inquiry_data *inq_data) 62039213Sgibbs{ 62139213Sgibbs caddr_t match; 62239213Sgibbs int i, j; 623181381Sjkim u_int32_t opmask; 62439213Sgibbs u_int16_t pd_type; 62539213Sgibbs int num_ops[2]; 62639213Sgibbs struct op_table_entry *table[2]; 62739213Sgibbs int num_tables; 62839213Sgibbs 629225950Sken /* 630225950Sken * If we've got inquiry data, use it to determine what type of 631225950Sken * device we're dealing with here. Otherwise, assume direct 632225950Sken * access. 633225950Sken */ 634225950Sken if (inq_data == NULL) { 635225950Sken pd_type = T_DIRECT; 636225950Sken match = NULL; 637225950Sken } else { 638225950Sken pd_type = SID_TYPE(inq_data); 63939213Sgibbs 640225950Sken match = cam_quirkmatch((caddr_t)inq_data, 641225950Sken (caddr_t)scsi_op_quirk_table, 642225950Sken sizeof(scsi_op_quirk_table)/ 643225950Sken sizeof(*scsi_op_quirk_table), 644225950Sken sizeof(*scsi_op_quirk_table), 645225950Sken scsi_inquiry_match); 646225950Sken } 64739213Sgibbs 64839213Sgibbs if (match != NULL) { 64939213Sgibbs table[0] = ((struct scsi_op_quirk_entry *)match)->op_table; 65039213Sgibbs num_ops[0] = ((struct scsi_op_quirk_entry *)match)->num_ops; 65139213Sgibbs table[1] = scsi_op_codes; 65239213Sgibbs num_ops[1] = sizeof(scsi_op_codes)/sizeof(scsi_op_codes[0]); 65339213Sgibbs num_tables = 2; 65439213Sgibbs } else { 65539213Sgibbs /* 65639213Sgibbs * If this is true, we have a vendor specific opcode that 65739213Sgibbs * wasn't covered in the quirk table. 65839213Sgibbs */ 65939213Sgibbs if ((opcode > 0xBF) || ((opcode > 0x5F) && (opcode < 0x80))) 66039213Sgibbs return("Vendor Specific Command"); 66139213Sgibbs 66239213Sgibbs table[0] = scsi_op_codes; 66339213Sgibbs num_ops[0] = sizeof(scsi_op_codes)/sizeof(scsi_op_codes[0]); 66439213Sgibbs num_tables = 1; 66539213Sgibbs } 66639213Sgibbs 66792052Ssimokawa /* RBC is 'Simplified' Direct Access Device */ 66892052Ssimokawa if (pd_type == T_RBC) 66992052Ssimokawa pd_type = T_DIRECT; 67092052Ssimokawa 671253323Smav /* Map NODEVICE to Direct Access Device to handle REPORT LUNS, etc. */ 672253323Smav if (pd_type == T_NODEVICE) 673253323Smav pd_type = T_DIRECT; 674253323Smav 67539213Sgibbs opmask = 1 << pd_type; 67639213Sgibbs 67739213Sgibbs for (j = 0; j < num_tables; j++) { 67839213Sgibbs for (i = 0;i < num_ops[j] && table[j][i].opcode <= opcode; i++){ 67939213Sgibbs if ((table[j][i].opcode == opcode) 68039213Sgibbs && ((table[j][i].opmask & opmask) != 0)) 68139213Sgibbs return(table[j][i].desc); 68239213Sgibbs } 68339213Sgibbs } 68439213Sgibbs 68539213Sgibbs /* 68639213Sgibbs * If we can't find a match for the command in the table, we just 68739213Sgibbs * assume it's a vendor specifc command. 68839213Sgibbs */ 68939213Sgibbs return("Vendor Specific Command"); 69039213Sgibbs 69139213Sgibbs} 69239213Sgibbs 69339213Sgibbs#else /* SCSI_NO_OP_STRINGS */ 69439213Sgibbs 69539213Sgibbsconst char * 69639213Sgibbsscsi_op_desc(u_int16_t opcode, struct scsi_inquiry_data *inq_data) 69739213Sgibbs{ 69839213Sgibbs return(""); 69939213Sgibbs} 70039213Sgibbs 70139213Sgibbs#endif 70239213Sgibbs 70339213Sgibbs 70439213Sgibbs#if !defined(SCSI_NO_SENSE_STRINGS) 70539213Sgibbs#define SST(asc, ascq, action, desc) \ 70639213Sgibbs asc, ascq, action, desc 70739213Sgibbs#else 70874840Skenconst char empty_string[] = ""; 70974840Sken 71039213Sgibbs#define SST(asc, ascq, action, desc) \ 71174840Sken asc, ascq, action, empty_string 71239213Sgibbs#endif 71339213Sgibbs 71474840Skenconst struct sense_key_table_entry sense_key_table[] = 71574840Sken{ 71674840Sken { SSD_KEY_NO_SENSE, SS_NOP, "NO SENSE" }, 71774840Sken { SSD_KEY_RECOVERED_ERROR, SS_NOP|SSQ_PRINT_SENSE, "RECOVERED ERROR" }, 718249352Smav { SSD_KEY_NOT_READY, SS_RDEF, "NOT READY" }, 71974840Sken { SSD_KEY_MEDIUM_ERROR, SS_RDEF, "MEDIUM ERROR" }, 72074840Sken { SSD_KEY_HARDWARE_ERROR, SS_RDEF, "HARDWARE FAILURE" }, 72174840Sken { SSD_KEY_ILLEGAL_REQUEST, SS_FATAL|EINVAL, "ILLEGAL REQUEST" }, 72274840Sken { SSD_KEY_UNIT_ATTENTION, SS_FATAL|ENXIO, "UNIT ATTENTION" }, 72376162Sken { SSD_KEY_DATA_PROTECT, SS_FATAL|EACCES, "DATA PROTECT" }, 72476162Sken { SSD_KEY_BLANK_CHECK, SS_FATAL|ENOSPC, "BLANK CHECK" }, 72574840Sken { SSD_KEY_Vendor_Specific, SS_FATAL|EIO, "Vendor Specific" }, 72674840Sken { SSD_KEY_COPY_ABORTED, SS_FATAL|EIO, "COPY ABORTED" }, 72774840Sken { SSD_KEY_ABORTED_COMMAND, SS_RDEF, "ABORTED COMMAND" }, 72874840Sken { SSD_KEY_EQUAL, SS_NOP, "EQUAL" }, 72974840Sken { SSD_KEY_VOLUME_OVERFLOW, SS_FATAL|EIO, "VOLUME OVERFLOW" }, 73074840Sken { SSD_KEY_MISCOMPARE, SS_NOP, "MISCOMPARE" }, 731225950Sken { SSD_KEY_COMPLETED, SS_NOP, "COMPLETED" } 73274840Sken}; 73374840Sken 73474840Skenconst int sense_key_table_size = 73574840Sken sizeof(sense_key_table)/sizeof(sense_key_table[0]); 73674840Sken 73739213Sgibbsstatic struct asc_table_entry quantum_fireball_entries[] = { 738181381Sjkim { SST(0x04, 0x0b, SS_START | SSQ_DECREMENT_COUNT | ENXIO, 739181381Sjkim "Logical unit not ready, initializing cmd. required") } 74039213Sgibbs}; 74139213Sgibbs 74276293Sjoergstatic struct asc_table_entry sony_mo_entries[] = { 743181381Sjkim { SST(0x04, 0x00, SS_START | SSQ_DECREMENT_COUNT | ENXIO, 744181381Sjkim "Logical unit not ready, cause not reportable") } 74576293Sjoerg}; 74676293Sjoerg 747252204Smavstatic struct asc_table_entry hgst_entries[] = { 748252204Smav { SST(0x04, 0xF0, SS_RDEF, 749252204Smav "Vendor Unique - Logical Unit Not Ready") }, 750252204Smav { SST(0x0A, 0x01, SS_RDEF, 751252204Smav "Unrecovered Super Certification Log Write Error") }, 752252204Smav { SST(0x0A, 0x02, SS_RDEF, 753252204Smav "Unrecovered Super Certification Log Read Error") }, 754252204Smav { SST(0x15, 0x03, SS_RDEF, 755252204Smav "Unrecovered Sector Error") }, 756252204Smav { SST(0x3E, 0x04, SS_RDEF, 757252204Smav "Unrecovered Self-Test Hard-Cache Test Fail") }, 758252204Smav { SST(0x3E, 0x05, SS_RDEF, 759252204Smav "Unrecovered Self-Test OTF-Cache Fail") }, 760252204Smav { SST(0x40, 0x00, SS_RDEF, 761252204Smav "Unrecovered SAT No Buffer Overflow Error") }, 762252204Smav { SST(0x40, 0x01, SS_RDEF, 763252204Smav "Unrecovered SAT Buffer Overflow Error") }, 764252204Smav { SST(0x40, 0x02, SS_RDEF, 765252204Smav "Unrecovered SAT No Buffer Overflow With ECS Fault") }, 766252204Smav { SST(0x40, 0x03, SS_RDEF, 767252204Smav "Unrecovered SAT Buffer Overflow With ECS Fault") }, 768252204Smav { SST(0x40, 0x81, SS_RDEF, 769252204Smav "DRAM Failure") }, 770252204Smav { SST(0x44, 0x0B, SS_RDEF, 771252204Smav "Vendor Unique - Internal Target Failure") }, 772252204Smav { SST(0x44, 0xF2, SS_RDEF, 773252204Smav "Vendor Unique - Internal Target Failure") }, 774252204Smav { SST(0x44, 0xF6, SS_RDEF, 775252204Smav "Vendor Unique - Internal Target Failure") }, 776252204Smav { SST(0x44, 0xF9, SS_RDEF, 777252204Smav "Vendor Unique - Internal Target Failure") }, 778252204Smav { SST(0x44, 0xFA, SS_RDEF, 779252204Smav "Vendor Unique - Internal Target Failure") }, 780252204Smav { SST(0x5D, 0x22, SS_RDEF, 781252204Smav "Extreme Over-Temperature Warning") }, 782252204Smav { SST(0x5D, 0x50, SS_RDEF, 783252204Smav "Load/Unload cycle Count Warning") }, 784252204Smav { SST(0x81, 0x00, SS_RDEF, 785252204Smav "Vendor Unique - Internal Logic Error") }, 786252204Smav { SST(0x85, 0x00, SS_RDEF, 787252204Smav "Vendor Unique - Internal Key Seed Error") }, 788252204Smav}; 789252204Smav 790252204Smavstatic struct asc_table_entry seagate_entries[] = { 791252204Smav { SST(0x04, 0xF0, SS_RDEF, 792252204Smav "Logical Unit Not Ready, super certify in Progress") }, 793252204Smav { SST(0x08, 0x86, SS_RDEF, 794252204Smav "Write Fault Data Corruption") }, 795252204Smav { SST(0x09, 0x0D, SS_RDEF, 796252204Smav "Tracking Failure") }, 797252204Smav { SST(0x09, 0x0E, SS_RDEF, 798252204Smav "ETF Failure") }, 799252204Smav { SST(0x0B, 0x5D, SS_RDEF, 800252204Smav "Pre-SMART Warning") }, 801252204Smav { SST(0x0B, 0x85, SS_RDEF, 802252204Smav "5V Voltage Warning") }, 803252204Smav { SST(0x0B, 0x8C, SS_RDEF, 804252204Smav "12V Voltage Warning") }, 805252204Smav { SST(0x0C, 0xFF, SS_RDEF, 806252250Smav "Write Error - Too many error recovery revs") }, 807252204Smav { SST(0x11, 0xFF, SS_RDEF, 808252250Smav "Unrecovered Read Error - Too many error recovery revs") }, 809252204Smav { SST(0x19, 0x0E, SS_RDEF, 810252204Smav "Fewer than 1/2 defect list copies") }, 811252204Smav { SST(0x20, 0xF3, SS_RDEF, 812252204Smav "Illegal CDB linked to skip mask cmd") }, 813252204Smav { SST(0x24, 0xF0, SS_RDEF, 814252204Smav "Illegal byte in CDB, LBA not matching") }, 815252204Smav { SST(0x24, 0xF1, SS_RDEF, 816252204Smav "Illegal byte in CDB, LEN not matching") }, 817252204Smav { SST(0x24, 0xF2, SS_RDEF, 818252204Smav "Mask not matching transfer length") }, 819252204Smav { SST(0x24, 0xF3, SS_RDEF, 820252204Smav "Drive formatted without plist") }, 821252204Smav { SST(0x26, 0x95, SS_RDEF, 822252250Smav "Invalid Field Parameter - CAP File") }, 823252204Smav { SST(0x26, 0x96, SS_RDEF, 824252250Smav "Invalid Field Parameter - RAP File") }, 825252204Smav { SST(0x26, 0x97, SS_RDEF, 826252250Smav "Invalid Field Parameter - TMS Firmware Tag") }, 827252204Smav { SST(0x26, 0x98, SS_RDEF, 828252250Smav "Invalid Field Parameter - Check Sum") }, 829252204Smav { SST(0x26, 0x99, SS_RDEF, 830252250Smav "Invalid Field Parameter - Firmware Tag") }, 831252204Smav { SST(0x29, 0x08, SS_RDEF, 832252204Smav "Write Log Dump data") }, 833252204Smav { SST(0x29, 0x09, SS_RDEF, 834252204Smav "Write Log Dump data") }, 835252204Smav { SST(0x29, 0x0A, SS_RDEF, 836252204Smav "Reserved disk space") }, 837252204Smav { SST(0x29, 0x0B, SS_RDEF, 838252204Smav "SDBP") }, 839252204Smav { SST(0x29, 0x0C, SS_RDEF, 840252204Smav "SDBP") }, 841252204Smav { SST(0x31, 0x91, SS_RDEF, 842252204Smav "Format Corrupted World Wide Name (WWN) is Invalid") }, 843252204Smav { SST(0x32, 0x03, SS_RDEF, 844252250Smav "Defect List - Length exceeds Command Allocated Length") }, 845252204Smav { SST(0x33, 0x00, SS_RDEF, 846252204Smav "Flash not ready for access") }, 847252204Smav { SST(0x3F, 0x70, SS_RDEF, 848252204Smav "Invalid RAP block") }, 849252204Smav { SST(0x3F, 0x71, SS_RDEF, 850252204Smav "RAP/ETF mismatch") }, 851252204Smav { SST(0x3F, 0x90, SS_RDEF, 852252204Smav "Invalid CAP block") }, 853252204Smav { SST(0x3F, 0x91, SS_RDEF, 854252204Smav "World Wide Name (WWN) Mismatch") }, 855252204Smav { SST(0x40, 0x01, SS_RDEF, 856252204Smav "DRAM Parity Error") }, 857252204Smav { SST(0x40, 0x02, SS_RDEF, 858252204Smav "DRAM Parity Error") }, 859252204Smav { SST(0x42, 0x0A, SS_RDEF, 860252204Smav "Loopback Test") }, 861252204Smav { SST(0x42, 0x0B, SS_RDEF, 862252204Smav "Loopback Test") }, 863252204Smav { SST(0x44, 0xF2, SS_RDEF, 864252204Smav "Compare error during data integrity check") }, 865252204Smav { SST(0x44, 0xF6, SS_RDEF, 866252204Smav "Unrecoverable error during data integrity check") }, 867252204Smav { SST(0x47, 0x80, SS_RDEF, 868252204Smav "Fibre Channel Sequence Error") }, 869252204Smav { SST(0x4E, 0x01, SS_RDEF, 870252204Smav "Information Unit Too Short") }, 871252204Smav { SST(0x80, 0x00, SS_RDEF, 872252204Smav "General Firmware Error / Command Timeout") }, 873252204Smav { SST(0x80, 0x01, SS_RDEF, 874252204Smav "Command Timeout") }, 875252204Smav { SST(0x80, 0x02, SS_RDEF, 876252204Smav "Command Timeout") }, 877252204Smav { SST(0x80, 0x80, SS_RDEF, 878252204Smav "FC FIFO Error During Read Transfer") }, 879252204Smav { SST(0x80, 0x81, SS_RDEF, 880252204Smav "FC FIFO Error During Write Transfer") }, 881252204Smav { SST(0x80, 0x82, SS_RDEF, 882252204Smav "DISC FIFO Error During Read Transfer") }, 883252204Smav { SST(0x80, 0x83, SS_RDEF, 884252204Smav "DISC FIFO Error During Write Transfer") }, 885252204Smav { SST(0x80, 0x84, SS_RDEF, 886252204Smav "LBA Seeded LRC Error on Read") }, 887252204Smav { SST(0x80, 0x85, SS_RDEF, 888252204Smav "LBA Seeded LRC Error on Write") }, 889252204Smav { SST(0x80, 0x86, SS_RDEF, 890252204Smav "IOEDC Error on Read") }, 891252204Smav { SST(0x80, 0x87, SS_RDEF, 892252204Smav "IOEDC Error on Write") }, 893252204Smav { SST(0x80, 0x88, SS_RDEF, 894252204Smav "Host Parity Check Failed") }, 895252204Smav { SST(0x80, 0x89, SS_RDEF, 896252204Smav "IOEDC error on read detected by formatter") }, 897252204Smav { SST(0x80, 0x8A, SS_RDEF, 898252204Smav "Host Parity Errors / Host FIFO Initialization Failed") }, 899252204Smav { SST(0x80, 0x8B, SS_RDEF, 900252204Smav "Host Parity Errors") }, 901252204Smav { SST(0x80, 0x8C, SS_RDEF, 902252204Smav "Host Parity Errors") }, 903252204Smav { SST(0x80, 0x8D, SS_RDEF, 904252204Smav "Host Parity Errors") }, 905252204Smav { SST(0x81, 0x00, SS_RDEF, 906252204Smav "LA Check Failed") }, 907252204Smav { SST(0x82, 0x00, SS_RDEF, 908252204Smav "Internal client detected insufficient buffer") }, 909252204Smav { SST(0x84, 0x00, SS_RDEF, 910252204Smav "Scheduled Diagnostic And Repair") }, 911252204Smav}; 912252204Smav 91374840Skenstatic struct scsi_sense_quirk_entry sense_quirk_table[] = { 91439213Sgibbs { 91539213Sgibbs /* 916181381Sjkim * XXX The Quantum Fireball ST and SE like to return 0x04 0x0b 917181381Sjkim * when they really should return 0x04 0x02. 91839213Sgibbs */ 91939213Sgibbs {T_DIRECT, SIP_MEDIA_FIXED, "QUANTUM", "FIREBALL S*", "*"}, 92074840Sken /*num_sense_keys*/0, 92174840Sken sizeof(quantum_fireball_entries)/sizeof(struct asc_table_entry), 92274840Sken /*sense key entries*/NULL, 92339213Sgibbs quantum_fireball_entries 92476293Sjoerg }, 92576293Sjoerg { 92676293Sjoerg /* 92776293Sjoerg * This Sony MO drive likes to return 0x04, 0x00 when it 92876293Sjoerg * isn't spun up. 92976293Sjoerg */ 93076293Sjoerg {T_DIRECT, SIP_MEDIA_REMOVABLE, "SONY", "SMO-*", "*"}, 93176293Sjoerg /*num_sense_keys*/0, 93276293Sjoerg sizeof(sony_mo_entries)/sizeof(struct asc_table_entry), 93376293Sjoerg /*sense key entries*/NULL, 93476293Sjoerg sony_mo_entries 935252204Smav }, 936252204Smav { 937252204Smav /* 938252204Smav * HGST vendor-specific error codes 939252204Smav */ 940252204Smav {T_DIRECT, SIP_MEDIA_FIXED, "HGST", "*", "*"}, 941252204Smav /*num_sense_keys*/0, 942252204Smav sizeof(hgst_entries)/sizeof(struct asc_table_entry), 943252204Smav /*sense key entries*/NULL, 944252204Smav hgst_entries 945252204Smav }, 946252204Smav { 947252204Smav /* 948252204Smav * SEAGATE vendor-specific error codes 949252204Smav */ 950252204Smav {T_DIRECT, SIP_MEDIA_FIXED, "SEAGATE", "*", "*"}, 951252204Smav /*num_sense_keys*/0, 952252204Smav sizeof(seagate_entries)/sizeof(struct asc_table_entry), 953252204Smav /*sense key entries*/NULL, 954252204Smav seagate_entries 95539213Sgibbs } 95639213Sgibbs}; 95739213Sgibbs 95874840Skenconst int sense_quirk_table_size = 95974840Sken sizeof(sense_quirk_table)/sizeof(sense_quirk_table[0]); 96074840Sken 96174840Skenstatic struct asc_table_entry asc_table[] = { 962181381Sjkim /* 963181381Sjkim * From: http://www.t10.org/lists/asc-num.txt 964181381Sjkim * Modifications by Jung-uk Kim (jkim@FreeBSD.org) 965181381Sjkim */ 966181381Sjkim /* 967181381Sjkim * File: ASC-NUM.TXT 968181381Sjkim * 969181381Sjkim * SCSI ASC/ASCQ Assignments 970181381Sjkim * Numeric Sorted Listing 971238595Smav * as of 5/20/12 972181381Sjkim * 973181381Sjkim * D - DIRECT ACCESS DEVICE (SBC-2) device column key 974181381Sjkim * .T - SEQUENTIAL ACCESS DEVICE (SSC) ------------------- 975181381Sjkim * . L - PRINTER DEVICE (SSC) blank = reserved 976181381Sjkim * . P - PROCESSOR DEVICE (SPC) not blank = allowed 977181381Sjkim * . .W - WRITE ONCE READ MULTIPLE DEVICE (SBC-2) 978181381Sjkim * . . R - CD DEVICE (MMC) 979181381Sjkim * . . O - OPTICAL MEMORY DEVICE (SBC-2) 980181381Sjkim * . . .M - MEDIA CHANGER DEVICE (SMC) 981181381Sjkim * . . . A - STORAGE ARRAY DEVICE (SCC) 982181381Sjkim * . . . E - ENCLOSURE SERVICES DEVICE (SES) 983181381Sjkim * . . . .B - SIMPLIFIED DIRECT-ACCESS DEVICE (RBC) 984181381Sjkim * . . . . K - OPTICAL CARD READER/WRITER DEVICE (OCRW) 985181381Sjkim * . . . . V - AUTOMATION/DRIVE INTERFACE (ADC) 986181381Sjkim * . . . . .F - OBJECT-BASED STORAGE (OSD) 987181381Sjkim * DTLPWROMAEBKVF 988181381Sjkim * ASC ASCQ Action 989181381Sjkim * Description 990181381Sjkim */ 991181381Sjkim /* DTLPWROMAEBKVF */ 992181381Sjkim { SST(0x00, 0x00, SS_NOP, 993181381Sjkim "No additional sense information") }, 994181381Sjkim /* T */ 995181381Sjkim { SST(0x00, 0x01, SS_RDEF, 996181381Sjkim "Filemark detected") }, 997181381Sjkim /* T */ 998181381Sjkim { SST(0x00, 0x02, SS_RDEF, 999181381Sjkim "End-of-partition/medium detected") }, 1000181381Sjkim /* T */ 1001181381Sjkim { SST(0x00, 0x03, SS_RDEF, 1002181381Sjkim "Setmark detected") }, 1003181381Sjkim /* T */ 1004181381Sjkim { SST(0x00, 0x04, SS_RDEF, 1005181381Sjkim "Beginning-of-partition/medium detected") }, 1006181381Sjkim /* TL */ 1007181381Sjkim { SST(0x00, 0x05, SS_RDEF, 1008181381Sjkim "End-of-data detected") }, 1009181381Sjkim /* DTLPWROMAEBKVF */ 1010181381Sjkim { SST(0x00, 0x06, SS_RDEF, 1011181381Sjkim "I/O process terminated") }, 1012181381Sjkim /* T */ 1013181381Sjkim { SST(0x00, 0x07, SS_RDEF, /* XXX TBD */ 1014181381Sjkim "Programmable early warning detected") }, 1015181381Sjkim /* R */ 1016181381Sjkim { SST(0x00, 0x11, SS_FATAL | EBUSY, 1017181381Sjkim "Audio play operation in progress") }, 1018181381Sjkim /* R */ 1019181381Sjkim { SST(0x00, 0x12, SS_NOP, 1020181381Sjkim "Audio play operation paused") }, 1021181381Sjkim /* R */ 1022181381Sjkim { SST(0x00, 0x13, SS_NOP, 1023181381Sjkim "Audio play operation successfully completed") }, 1024181381Sjkim /* R */ 1025181381Sjkim { SST(0x00, 0x14, SS_RDEF, 1026181381Sjkim "Audio play operation stopped due to error") }, 1027181381Sjkim /* R */ 1028181381Sjkim { SST(0x00, 0x15, SS_NOP, 1029181381Sjkim "No current audio status to return") }, 1030181381Sjkim /* DTLPWROMAEBKVF */ 1031181381Sjkim { SST(0x00, 0x16, SS_FATAL | EBUSY, 1032181381Sjkim "Operation in progress") }, 1033181381Sjkim /* DTL WROMAEBKVF */ 1034181381Sjkim { SST(0x00, 0x17, SS_RDEF, 1035181381Sjkim "Cleaning requested") }, 1036181381Sjkim /* T */ 1037181381Sjkim { SST(0x00, 0x18, SS_RDEF, /* XXX TBD */ 1038181381Sjkim "Erase operation in progress") }, 1039181381Sjkim /* T */ 1040181381Sjkim { SST(0x00, 0x19, SS_RDEF, /* XXX TBD */ 1041181381Sjkim "Locate operation in progress") }, 1042181381Sjkim /* T */ 1043181381Sjkim { SST(0x00, 0x1A, SS_RDEF, /* XXX TBD */ 1044181381Sjkim "Rewind operation in progress") }, 1045181381Sjkim /* T */ 1046181381Sjkim { SST(0x00, 0x1B, SS_RDEF, /* XXX TBD */ 1047181381Sjkim "Set capacity operation in progress") }, 1048181381Sjkim /* T */ 1049181381Sjkim { SST(0x00, 0x1C, SS_RDEF, /* XXX TBD */ 1050181381Sjkim "Verify operation in progress") }, 1051181381Sjkim /* DT B */ 1052181381Sjkim { SST(0x00, 0x1D, SS_RDEF, /* XXX TBD */ 1053181381Sjkim "ATA pass through information available") }, 1054181381Sjkim /* DT R MAEBKV */ 1055181381Sjkim { SST(0x00, 0x1E, SS_RDEF, /* XXX TBD */ 1056181381Sjkim "Conflicting SA creation request") }, 1057238595Smav /* DT B */ 1058238595Smav { SST(0x00, 0x1F, SS_RDEF, /* XXX TBD */ 1059238595Smav "Logical unit transitioning to another power condition") }, 1060238595Smav /* DT P B */ 1061238595Smav { SST(0x00, 0x20, SS_RDEF, /* XXX TBD */ 1062238595Smav "Extended copy information available") }, 1063181381Sjkim /* D W O BK */ 1064181381Sjkim { SST(0x01, 0x00, SS_RDEF, 1065181381Sjkim "No index/sector signal") }, 1066181381Sjkim /* D WRO BK */ 1067181381Sjkim { SST(0x02, 0x00, SS_RDEF, 1068181381Sjkim "No seek complete") }, 1069181381Sjkim /* DTL W O BK */ 1070181381Sjkim { SST(0x03, 0x00, SS_RDEF, 1071181381Sjkim "Peripheral device write fault") }, 1072181381Sjkim /* T */ 1073181381Sjkim { SST(0x03, 0x01, SS_RDEF, 1074181381Sjkim "No write current") }, 1075181381Sjkim /* T */ 1076181381Sjkim { SST(0x03, 0x02, SS_RDEF, 1077181381Sjkim "Excessive write errors") }, 1078181381Sjkim /* DTLPWROMAEBKVF */ 1079249352Smav { SST(0x04, 0x00, SS_RDEF, 1080181381Sjkim "Logical unit not ready, cause not reportable") }, 1081181381Sjkim /* DTLPWROMAEBKVF */ 1082181381Sjkim { SST(0x04, 0x01, SS_TUR | SSQ_MANY | SSQ_DECREMENT_COUNT | EBUSY, 1083181381Sjkim "Logical unit is in process of becoming ready") }, 1084181381Sjkim /* DTLPWROMAEBKVF */ 1085181381Sjkim { SST(0x04, 0x02, SS_START | SSQ_DECREMENT_COUNT | ENXIO, 1086181381Sjkim "Logical unit not ready, initializing command required") }, 1087181381Sjkim /* DTLPWROMAEBKVF */ 1088181381Sjkim { SST(0x04, 0x03, SS_FATAL | ENXIO, 1089181381Sjkim "Logical unit not ready, manual intervention required") }, 1090181381Sjkim /* DTL RO B */ 1091181381Sjkim { SST(0x04, 0x04, SS_FATAL | EBUSY, 1092181381Sjkim "Logical unit not ready, format in progress") }, 1093181381Sjkim /* DT W O A BK F */ 1094181381Sjkim { SST(0x04, 0x05, SS_FATAL | EBUSY, 1095181381Sjkim "Logical unit not ready, rebuild in progress") }, 1096181381Sjkim /* DT W O A BK */ 1097181381Sjkim { SST(0x04, 0x06, SS_FATAL | EBUSY, 1098181381Sjkim "Logical unit not ready, recalculation in progress") }, 1099181381Sjkim /* DTLPWROMAEBKVF */ 1100181381Sjkim { SST(0x04, 0x07, SS_FATAL | EBUSY, 1101181381Sjkim "Logical unit not ready, operation in progress") }, 1102181381Sjkim /* R */ 1103181381Sjkim { SST(0x04, 0x08, SS_FATAL | EBUSY, 1104181381Sjkim "Logical unit not ready, long write in progress") }, 1105181381Sjkim /* DTLPWROMAEBKVF */ 1106181381Sjkim { SST(0x04, 0x09, SS_RDEF, /* XXX TBD */ 1107181381Sjkim "Logical unit not ready, self-test in progress") }, 1108181381Sjkim /* DTLPWROMAEBKVF */ 1109181381Sjkim { SST(0x04, 0x0A, SS_RDEF, /* XXX TBD */ 1110181381Sjkim "Logical unit not accessible, asymmetric access state transition")}, 1111181381Sjkim /* DTLPWROMAEBKVF */ 1112181381Sjkim { SST(0x04, 0x0B, SS_RDEF, /* XXX TBD */ 1113181381Sjkim "Logical unit not accessible, target port in standby state") }, 1114181381Sjkim /* DTLPWROMAEBKVF */ 1115181381Sjkim { SST(0x04, 0x0C, SS_RDEF, /* XXX TBD */ 1116181381Sjkim "Logical unit not accessible, target port in unavailable state") }, 1117181381Sjkim /* F */ 1118181381Sjkim { SST(0x04, 0x0D, SS_RDEF, /* XXX TBD */ 1119181381Sjkim "Logical unit not ready, structure check required") }, 1120181381Sjkim /* DT WROM B */ 1121181381Sjkim { SST(0x04, 0x10, SS_RDEF, /* XXX TBD */ 1122181381Sjkim "Logical unit not ready, auxiliary memory not accessible") }, 1123181381Sjkim /* DT WRO AEB VF */ 1124254970Sken { SST(0x04, 0x11, SS_TUR | SSQ_MANY | SSQ_DECREMENT_COUNT | EBUSY, 1125181381Sjkim "Logical unit not ready, notify (enable spinup) required") }, 1126181381Sjkim /* M V */ 1127181381Sjkim { SST(0x04, 0x12, SS_RDEF, /* XXX TBD */ 1128181381Sjkim "Logical unit not ready, offline") }, 1129181381Sjkim /* DT R MAEBKV */ 1130181381Sjkim { SST(0x04, 0x13, SS_RDEF, /* XXX TBD */ 1131181381Sjkim "Logical unit not ready, SA creation in progress") }, 1132238595Smav /* D B */ 1133238595Smav { SST(0x04, 0x14, SS_RDEF, /* XXX TBD */ 1134238595Smav "Logical unit not ready, space allocation in progress") }, 1135238595Smav /* M */ 1136238595Smav { SST(0x04, 0x15, SS_RDEF, /* XXX TBD */ 1137238595Smav "Logical unit not ready, robotics disabled") }, 1138238595Smav /* M */ 1139238595Smav { SST(0x04, 0x16, SS_RDEF, /* XXX TBD */ 1140238595Smav "Logical unit not ready, configuration required") }, 1141238595Smav /* M */ 1142238595Smav { SST(0x04, 0x17, SS_RDEF, /* XXX TBD */ 1143238595Smav "Logical unit not ready, calibration required") }, 1144238595Smav /* M */ 1145238595Smav { SST(0x04, 0x18, SS_RDEF, /* XXX TBD */ 1146238595Smav "Logical unit not ready, a door is open") }, 1147238595Smav /* M */ 1148238595Smav { SST(0x04, 0x19, SS_RDEF, /* XXX TBD */ 1149238595Smav "Logical unit not ready, operating in sequential mode") }, 1150238595Smav /* DT B */ 1151238595Smav { SST(0x04, 0x1A, SS_RDEF, /* XXX TBD */ 1152238595Smav "Logical unit not ready, START/STOP UNIT command in progress") }, 1153238595Smav /* D B */ 1154238595Smav { SST(0x04, 0x1B, SS_RDEF, /* XXX TBD */ 1155238595Smav "Logical unit not ready, sanitize in progress") }, 1156238595Smav /* DT MAEB */ 1157238595Smav { SST(0x04, 0x1C, SS_RDEF, /* XXX TBD */ 1158238595Smav "Logical unit not ready, additional power use not yet granted") }, 1159181381Sjkim /* DTL WROMAEBKVF */ 1160181381Sjkim { SST(0x05, 0x00, SS_RDEF, 1161181381Sjkim "Logical unit does not respond to selection") }, 1162181381Sjkim /* D WROM BK */ 1163181381Sjkim { SST(0x06, 0x00, SS_RDEF, 1164181381Sjkim "No reference position found") }, 1165181381Sjkim /* DTL WROM BK */ 1166181381Sjkim { SST(0x07, 0x00, SS_RDEF, 1167181381Sjkim "Multiple peripheral devices selected") }, 1168181381Sjkim /* DTL WROMAEBKVF */ 1169181381Sjkim { SST(0x08, 0x00, SS_RDEF, 1170181381Sjkim "Logical unit communication failure") }, 1171181381Sjkim /* DTL WROMAEBKVF */ 1172181381Sjkim { SST(0x08, 0x01, SS_RDEF, 1173181381Sjkim "Logical unit communication time-out") }, 1174181381Sjkim /* DTL WROMAEBKVF */ 1175181381Sjkim { SST(0x08, 0x02, SS_RDEF, 1176181381Sjkim "Logical unit communication parity error") }, 1177181381Sjkim /* DT ROM BK */ 1178181381Sjkim { SST(0x08, 0x03, SS_RDEF, 1179181381Sjkim "Logical unit communication CRC error (Ultra-DMA/32)") }, 1180181381Sjkim /* DTLPWRO K */ 1181181381Sjkim { SST(0x08, 0x04, SS_RDEF, /* XXX TBD */ 1182181381Sjkim "Unreachable copy target") }, 1183181381Sjkim /* DT WRO B */ 1184181381Sjkim { SST(0x09, 0x00, SS_RDEF, 1185181381Sjkim "Track following error") }, 1186181381Sjkim /* WRO K */ 1187181381Sjkim { SST(0x09, 0x01, SS_RDEF, 1188181381Sjkim "Tracking servo failure") }, 1189181381Sjkim /* WRO K */ 1190181381Sjkim { SST(0x09, 0x02, SS_RDEF, 1191181381Sjkim "Focus servo failure") }, 1192181381Sjkim /* WRO */ 1193181381Sjkim { SST(0x09, 0x03, SS_RDEF, 1194181381Sjkim "Spindle servo failure") }, 1195181381Sjkim /* DT WRO B */ 1196181381Sjkim { SST(0x09, 0x04, SS_RDEF, 1197181381Sjkim "Head select fault") }, 1198181381Sjkim /* DTLPWROMAEBKVF */ 1199181381Sjkim { SST(0x0A, 0x00, SS_FATAL | ENOSPC, 1200181381Sjkim "Error log overflow") }, 1201181381Sjkim /* DTLPWROMAEBKVF */ 1202181381Sjkim { SST(0x0B, 0x00, SS_RDEF, 1203181381Sjkim "Warning") }, 1204181381Sjkim /* DTLPWROMAEBKVF */ 1205181381Sjkim { SST(0x0B, 0x01, SS_RDEF, 1206181381Sjkim "Warning - specified temperature exceeded") }, 1207181381Sjkim /* DTLPWROMAEBKVF */ 1208181381Sjkim { SST(0x0B, 0x02, SS_RDEF, 1209181381Sjkim "Warning - enclosure degraded") }, 1210181381Sjkim /* DTLPWROMAEBKVF */ 1211181381Sjkim { SST(0x0B, 0x03, SS_RDEF, /* XXX TBD */ 1212181381Sjkim "Warning - background self-test failed") }, 1213181381Sjkim /* DTLPWRO AEBKVF */ 1214181381Sjkim { SST(0x0B, 0x04, SS_RDEF, /* XXX TBD */ 1215181381Sjkim "Warning - background pre-scan detected medium error") }, 1216181381Sjkim /* DTLPWRO AEBKVF */ 1217181381Sjkim { SST(0x0B, 0x05, SS_RDEF, /* XXX TBD */ 1218181381Sjkim "Warning - background medium scan detected medium error") }, 1219181381Sjkim /* DTLPWROMAEBKVF */ 1220181381Sjkim { SST(0x0B, 0x06, SS_RDEF, /* XXX TBD */ 1221181381Sjkim "Warning - non-volatile cache now volatile") }, 1222181381Sjkim /* DTLPWROMAEBKVF */ 1223181381Sjkim { SST(0x0B, 0x07, SS_RDEF, /* XXX TBD */ 1224181381Sjkim "Warning - degraded power to non-volatile cache") }, 1225238595Smav /* DTLPWROMAEBKVF */ 1226238595Smav { SST(0x0B, 0x08, SS_RDEF, /* XXX TBD */ 1227238595Smav "Warning - power loss expected") }, 1228238595Smav /* D */ 1229238595Smav { SST(0x0B, 0x09, SS_RDEF, /* XXX TBD */ 1230238595Smav "Warning - device statistics notification available") }, 1231181381Sjkim /* T R */ 1232181381Sjkim { SST(0x0C, 0x00, SS_RDEF, 1233181381Sjkim "Write error") }, 1234181381Sjkim /* K */ 1235181381Sjkim { SST(0x0C, 0x01, SS_NOP | SSQ_PRINT_SENSE, 1236181381Sjkim "Write error - recovered with auto reallocation") }, 1237181381Sjkim /* D W O BK */ 1238181381Sjkim { SST(0x0C, 0x02, SS_RDEF, 1239181381Sjkim "Write error - auto reallocation failed") }, 1240181381Sjkim /* D W O BK */ 1241181381Sjkim { SST(0x0C, 0x03, SS_RDEF, 1242181381Sjkim "Write error - recommend reassignment") }, 1243181381Sjkim /* DT W O B */ 1244181381Sjkim { SST(0x0C, 0x04, SS_RDEF, 1245181381Sjkim "Compression check miscompare error") }, 1246181381Sjkim /* DT W O B */ 1247181381Sjkim { SST(0x0C, 0x05, SS_RDEF, 1248181381Sjkim "Data expansion occurred during compression") }, 1249181381Sjkim /* DT W O B */ 1250181381Sjkim { SST(0x0C, 0x06, SS_RDEF, 1251181381Sjkim "Block not compressible") }, 1252181381Sjkim /* R */ 1253181381Sjkim { SST(0x0C, 0x07, SS_RDEF, 1254181381Sjkim "Write error - recovery needed") }, 1255181381Sjkim /* R */ 1256181381Sjkim { SST(0x0C, 0x08, SS_RDEF, 1257181381Sjkim "Write error - recovery failed") }, 1258181381Sjkim /* R */ 1259181381Sjkim { SST(0x0C, 0x09, SS_RDEF, 1260181381Sjkim "Write error - loss of streaming") }, 1261181381Sjkim /* R */ 1262181381Sjkim { SST(0x0C, 0x0A, SS_RDEF, 1263181381Sjkim "Write error - padding blocks added") }, 1264181381Sjkim /* DT WROM B */ 1265181381Sjkim { SST(0x0C, 0x0B, SS_RDEF, /* XXX TBD */ 1266181381Sjkim "Auxiliary memory write error") }, 1267181381Sjkim /* DTLPWRO AEBKVF */ 1268181381Sjkim { SST(0x0C, 0x0C, SS_RDEF, /* XXX TBD */ 1269181381Sjkim "Write error - unexpected unsolicited data") }, 1270181381Sjkim /* DTLPWRO AEBKVF */ 1271181381Sjkim { SST(0x0C, 0x0D, SS_RDEF, /* XXX TBD */ 1272181381Sjkim "Write error - not enough unsolicited data") }, 1273238595Smav /* DT W O BK */ 1274238595Smav { SST(0x0C, 0x0E, SS_RDEF, /* XXX TBD */ 1275238595Smav "Multiple write errors") }, 1276181381Sjkim /* R */ 1277181381Sjkim { SST(0x0C, 0x0F, SS_RDEF, /* XXX TBD */ 1278181381Sjkim "Defects in error window") }, 1279181381Sjkim /* DTLPWRO A K */ 1280181381Sjkim { SST(0x0D, 0x00, SS_RDEF, /* XXX TBD */ 1281181381Sjkim "Error detected by third party temporary initiator") }, 1282181381Sjkim /* DTLPWRO A K */ 1283181381Sjkim { SST(0x0D, 0x01, SS_RDEF, /* XXX TBD */ 1284181381Sjkim "Third party device failure") }, 1285181381Sjkim /* DTLPWRO A K */ 1286181381Sjkim { SST(0x0D, 0x02, SS_RDEF, /* XXX TBD */ 1287181381Sjkim "Copy target device not reachable") }, 1288181381Sjkim /* DTLPWRO A K */ 1289181381Sjkim { SST(0x0D, 0x03, SS_RDEF, /* XXX TBD */ 1290181381Sjkim "Incorrect copy target device type") }, 1291181381Sjkim /* DTLPWRO A K */ 1292181381Sjkim { SST(0x0D, 0x04, SS_RDEF, /* XXX TBD */ 1293181381Sjkim "Copy target device data underrun") }, 1294181381Sjkim /* DTLPWRO A K */ 1295181381Sjkim { SST(0x0D, 0x05, SS_RDEF, /* XXX TBD */ 1296181381Sjkim "Copy target device data overrun") }, 1297181381Sjkim /* DT PWROMAEBK F */ 1298181381Sjkim { SST(0x0E, 0x00, SS_RDEF, /* XXX TBD */ 1299181381Sjkim "Invalid information unit") }, 1300181381Sjkim /* DT PWROMAEBK F */ 1301181381Sjkim { SST(0x0E, 0x01, SS_RDEF, /* XXX TBD */ 1302181381Sjkim "Information unit too short") }, 1303181381Sjkim /* DT PWROMAEBK F */ 1304181381Sjkim { SST(0x0E, 0x02, SS_RDEF, /* XXX TBD */ 1305181381Sjkim "Information unit too long") }, 1306181381Sjkim /* DT P R MAEBK F */ 1307181381Sjkim { SST(0x0E, 0x03, SS_RDEF, /* XXX TBD */ 1308181381Sjkim "Invalid field in command information unit") }, 1309181381Sjkim /* D W O BK */ 1310181381Sjkim { SST(0x10, 0x00, SS_RDEF, 1311181381Sjkim "ID CRC or ECC error") }, 1312181381Sjkim /* DT W O */ 1313181381Sjkim { SST(0x10, 0x01, SS_RDEF, /* XXX TBD */ 1314181381Sjkim "Logical block guard check failed") }, 1315181381Sjkim /* DT W O */ 1316181381Sjkim { SST(0x10, 0x02, SS_RDEF, /* XXX TBD */ 1317181381Sjkim "Logical block application tag check failed") }, 1318181381Sjkim /* DT W O */ 1319181381Sjkim { SST(0x10, 0x03, SS_RDEF, /* XXX TBD */ 1320181381Sjkim "Logical block reference tag check failed") }, 1321238595Smav /* T */ 1322238595Smav { SST(0x10, 0x04, SS_RDEF, /* XXX TBD */ 1323238595Smav "Logical block protection error on recovered buffer data") }, 1324238595Smav /* T */ 1325238595Smav { SST(0x10, 0x05, SS_RDEF, /* XXX TBD */ 1326238595Smav "Logical block protection method error") }, 1327181381Sjkim /* DT WRO BK */ 1328225950Sken { SST(0x11, 0x00, SS_FATAL|EIO, 1329181381Sjkim "Unrecovered read error") }, 1330181381Sjkim /* DT WRO BK */ 1331225950Sken { SST(0x11, 0x01, SS_FATAL|EIO, 1332181381Sjkim "Read retries exhausted") }, 1333181381Sjkim /* DT WRO BK */ 1334225950Sken { SST(0x11, 0x02, SS_FATAL|EIO, 1335181381Sjkim "Error too long to correct") }, 1336181381Sjkim /* DT W O BK */ 1337225950Sken { SST(0x11, 0x03, SS_FATAL|EIO, 1338181381Sjkim "Multiple read errors") }, 1339181381Sjkim /* D W O BK */ 1340225950Sken { SST(0x11, 0x04, SS_FATAL|EIO, 1341181381Sjkim "Unrecovered read error - auto reallocate failed") }, 1342181381Sjkim /* WRO B */ 1343225950Sken { SST(0x11, 0x05, SS_FATAL|EIO, 1344181381Sjkim "L-EC uncorrectable error") }, 1345181381Sjkim /* WRO B */ 1346225950Sken { SST(0x11, 0x06, SS_FATAL|EIO, 1347181381Sjkim "CIRC unrecovered error") }, 1348181381Sjkim /* W O B */ 1349181381Sjkim { SST(0x11, 0x07, SS_RDEF, 1350181381Sjkim "Data re-synchronization error") }, 1351181381Sjkim /* T */ 1352181381Sjkim { SST(0x11, 0x08, SS_RDEF, 1353181381Sjkim "Incomplete block read") }, 1354181381Sjkim /* T */ 1355181381Sjkim { SST(0x11, 0x09, SS_RDEF, 1356181381Sjkim "No gap found") }, 1357181381Sjkim /* DT O BK */ 1358181381Sjkim { SST(0x11, 0x0A, SS_RDEF, 1359181381Sjkim "Miscorrected error") }, 1360181381Sjkim /* D W O BK */ 1361225950Sken { SST(0x11, 0x0B, SS_FATAL|EIO, 1362181381Sjkim "Unrecovered read error - recommend reassignment") }, 1363181381Sjkim /* D W O BK */ 1364225950Sken { SST(0x11, 0x0C, SS_FATAL|EIO, 1365181381Sjkim "Unrecovered read error - recommend rewrite the data") }, 1366181381Sjkim /* DT WRO B */ 1367181381Sjkim { SST(0x11, 0x0D, SS_RDEF, 1368181381Sjkim "De-compression CRC error") }, 1369181381Sjkim /* DT WRO B */ 1370181381Sjkim { SST(0x11, 0x0E, SS_RDEF, 1371181381Sjkim "Cannot decompress using declared algorithm") }, 1372181381Sjkim /* R */ 1373181381Sjkim { SST(0x11, 0x0F, SS_RDEF, 1374181381Sjkim "Error reading UPC/EAN number") }, 1375181381Sjkim /* R */ 1376181381Sjkim { SST(0x11, 0x10, SS_RDEF, 1377181381Sjkim "Error reading ISRC number") }, 1378181381Sjkim /* R */ 1379181381Sjkim { SST(0x11, 0x11, SS_RDEF, 1380181381Sjkim "Read error - loss of streaming") }, 1381181381Sjkim /* DT WROM B */ 1382181381Sjkim { SST(0x11, 0x12, SS_RDEF, /* XXX TBD */ 1383181381Sjkim "Auxiliary memory read error") }, 1384181381Sjkim /* DTLPWRO AEBKVF */ 1385181381Sjkim { SST(0x11, 0x13, SS_RDEF, /* XXX TBD */ 1386181381Sjkim "Read error - failed retransmission request") }, 1387181381Sjkim /* D */ 1388181381Sjkim { SST(0x11, 0x14, SS_RDEF, /* XXX TBD */ 1389181381Sjkim "Read error - LBA marked bad by application client") }, 1390181381Sjkim /* D W O BK */ 1391181381Sjkim { SST(0x12, 0x00, SS_RDEF, 1392181381Sjkim "Address mark not found for ID field") }, 1393181381Sjkim /* D W O BK */ 1394181381Sjkim { SST(0x13, 0x00, SS_RDEF, 1395181381Sjkim "Address mark not found for data field") }, 1396181381Sjkim /* DTL WRO BK */ 1397181381Sjkim { SST(0x14, 0x00, SS_RDEF, 1398181381Sjkim "Recorded entity not found") }, 1399181381Sjkim /* DT WRO BK */ 1400181381Sjkim { SST(0x14, 0x01, SS_RDEF, 1401181381Sjkim "Record not found") }, 1402181381Sjkim /* T */ 1403181381Sjkim { SST(0x14, 0x02, SS_RDEF, 1404181381Sjkim "Filemark or setmark not found") }, 1405181381Sjkim /* T */ 1406181381Sjkim { SST(0x14, 0x03, SS_RDEF, 1407181381Sjkim "End-of-data not found") }, 1408181381Sjkim /* T */ 1409181381Sjkim { SST(0x14, 0x04, SS_RDEF, 1410181381Sjkim "Block sequence error") }, 1411181381Sjkim /* DT W O BK */ 1412181381Sjkim { SST(0x14, 0x05, SS_RDEF, 1413181381Sjkim "Record not found - recommend reassignment") }, 1414181381Sjkim /* DT W O BK */ 1415181381Sjkim { SST(0x14, 0x06, SS_RDEF, 1416181381Sjkim "Record not found - data auto-reallocated") }, 1417181381Sjkim /* T */ 1418181381Sjkim { SST(0x14, 0x07, SS_RDEF, /* XXX TBD */ 1419181381Sjkim "Locate operation failure") }, 1420181381Sjkim /* DTL WROM BK */ 1421181381Sjkim { SST(0x15, 0x00, SS_RDEF, 1422181381Sjkim "Random positioning error") }, 1423181381Sjkim /* DTL WROM BK */ 1424181381Sjkim { SST(0x15, 0x01, SS_RDEF, 1425181381Sjkim "Mechanical positioning error") }, 1426181381Sjkim /* DT WRO BK */ 1427181381Sjkim { SST(0x15, 0x02, SS_RDEF, 1428181381Sjkim "Positioning error detected by read of medium") }, 1429181381Sjkim /* D W O BK */ 1430181381Sjkim { SST(0x16, 0x00, SS_RDEF, 1431181381Sjkim "Data synchronization mark error") }, 1432181381Sjkim /* D W O BK */ 1433181381Sjkim { SST(0x16, 0x01, SS_RDEF, 1434181381Sjkim "Data sync error - data rewritten") }, 1435181381Sjkim /* D W O BK */ 1436181381Sjkim { SST(0x16, 0x02, SS_RDEF, 1437181381Sjkim "Data sync error - recommend rewrite") }, 1438181381Sjkim /* D W O BK */ 1439181381Sjkim { SST(0x16, 0x03, SS_NOP | SSQ_PRINT_SENSE, 1440181381Sjkim "Data sync error - data auto-reallocated") }, 1441181381Sjkim /* D W O BK */ 1442181381Sjkim { SST(0x16, 0x04, SS_RDEF, 1443181381Sjkim "Data sync error - recommend reassignment") }, 1444181381Sjkim /* DT WRO BK */ 1445181381Sjkim { SST(0x17, 0x00, SS_NOP | SSQ_PRINT_SENSE, 1446181381Sjkim "Recovered data with no error correction applied") }, 1447181381Sjkim /* DT WRO BK */ 1448181381Sjkim { SST(0x17, 0x01, SS_NOP | SSQ_PRINT_SENSE, 1449181381Sjkim "Recovered data with retries") }, 1450181381Sjkim /* DT WRO BK */ 1451181381Sjkim { SST(0x17, 0x02, SS_NOP | SSQ_PRINT_SENSE, 1452181381Sjkim "Recovered data with positive head offset") }, 1453181381Sjkim /* DT WRO BK */ 1454181381Sjkim { SST(0x17, 0x03, SS_NOP | SSQ_PRINT_SENSE, 1455181381Sjkim "Recovered data with negative head offset") }, 1456181381Sjkim /* WRO B */ 1457181381Sjkim { SST(0x17, 0x04, SS_NOP | SSQ_PRINT_SENSE, 1458181381Sjkim "Recovered data with retries and/or CIRC applied") }, 1459181381Sjkim /* D WRO BK */ 1460181381Sjkim { SST(0x17, 0x05, SS_NOP | SSQ_PRINT_SENSE, 1461181381Sjkim "Recovered data using previous sector ID") }, 1462181381Sjkim /* D W O BK */ 1463181381Sjkim { SST(0x17, 0x06, SS_NOP | SSQ_PRINT_SENSE, 1464181381Sjkim "Recovered data without ECC - data auto-reallocated") }, 1465181381Sjkim /* D WRO BK */ 1466181381Sjkim { SST(0x17, 0x07, SS_NOP | SSQ_PRINT_SENSE, 1467181381Sjkim "Recovered data without ECC - recommend reassignment") }, 1468181381Sjkim /* D WRO BK */ 1469181381Sjkim { SST(0x17, 0x08, SS_NOP | SSQ_PRINT_SENSE, 1470181381Sjkim "Recovered data without ECC - recommend rewrite") }, 1471181381Sjkim /* D WRO BK */ 1472181381Sjkim { SST(0x17, 0x09, SS_NOP | SSQ_PRINT_SENSE, 1473181381Sjkim "Recovered data without ECC - data rewritten") }, 1474181381Sjkim /* DT WRO BK */ 1475181381Sjkim { SST(0x18, 0x00, SS_NOP | SSQ_PRINT_SENSE, 1476181381Sjkim "Recovered data with error correction applied") }, 1477181381Sjkim /* D WRO BK */ 1478181381Sjkim { SST(0x18, 0x01, SS_NOP | SSQ_PRINT_SENSE, 1479181381Sjkim "Recovered data with error corr. & retries applied") }, 1480181381Sjkim /* D WRO BK */ 1481181381Sjkim { SST(0x18, 0x02, SS_NOP | SSQ_PRINT_SENSE, 1482181381Sjkim "Recovered data - data auto-reallocated") }, 1483181381Sjkim /* R */ 1484181381Sjkim { SST(0x18, 0x03, SS_NOP | SSQ_PRINT_SENSE, 1485181381Sjkim "Recovered data with CIRC") }, 1486181381Sjkim /* R */ 1487181381Sjkim { SST(0x18, 0x04, SS_NOP | SSQ_PRINT_SENSE, 1488181381Sjkim "Recovered data with L-EC") }, 1489181381Sjkim /* D WRO BK */ 1490181381Sjkim { SST(0x18, 0x05, SS_NOP | SSQ_PRINT_SENSE, 1491181381Sjkim "Recovered data - recommend reassignment") }, 1492181381Sjkim /* D WRO BK */ 1493181381Sjkim { SST(0x18, 0x06, SS_NOP | SSQ_PRINT_SENSE, 1494181381Sjkim "Recovered data - recommend rewrite") }, 1495181381Sjkim /* D W O BK */ 1496181381Sjkim { SST(0x18, 0x07, SS_NOP | SSQ_PRINT_SENSE, 1497181381Sjkim "Recovered data with ECC - data rewritten") }, 1498181381Sjkim /* R */ 1499181381Sjkim { SST(0x18, 0x08, SS_RDEF, /* XXX TBD */ 1500181381Sjkim "Recovered data with linking") }, 1501181381Sjkim /* D O K */ 1502181381Sjkim { SST(0x19, 0x00, SS_RDEF, 1503181381Sjkim "Defect list error") }, 1504181381Sjkim /* D O K */ 1505181381Sjkim { SST(0x19, 0x01, SS_RDEF, 1506181381Sjkim "Defect list not available") }, 1507181381Sjkim /* D O K */ 1508181381Sjkim { SST(0x19, 0x02, SS_RDEF, 1509181381Sjkim "Defect list error in primary list") }, 1510181381Sjkim /* D O K */ 1511181381Sjkim { SST(0x19, 0x03, SS_RDEF, 1512181381Sjkim "Defect list error in grown list") }, 1513181381Sjkim /* DTLPWROMAEBKVF */ 1514181381Sjkim { SST(0x1A, 0x00, SS_RDEF, 1515181381Sjkim "Parameter list length error") }, 1516181381Sjkim /* DTLPWROMAEBKVF */ 1517181381Sjkim { SST(0x1B, 0x00, SS_RDEF, 1518181381Sjkim "Synchronous data transfer error") }, 1519181381Sjkim /* D O BK */ 1520181381Sjkim { SST(0x1C, 0x00, SS_RDEF, 1521181381Sjkim "Defect list not found") }, 1522181381Sjkim /* D O BK */ 1523181381Sjkim { SST(0x1C, 0x01, SS_RDEF, 1524181381Sjkim "Primary defect list not found") }, 1525181381Sjkim /* D O BK */ 1526181381Sjkim { SST(0x1C, 0x02, SS_RDEF, 1527181381Sjkim "Grown defect list not found") }, 1528181381Sjkim /* DT WRO BK */ 1529181381Sjkim { SST(0x1D, 0x00, SS_FATAL, 1530181381Sjkim "Miscompare during verify operation") }, 1531238595Smav /* D B */ 1532238595Smav { SST(0x1D, 0x01, SS_RDEF, /* XXX TBD */ 1533238595Smav "Miscomparable verify of unmapped LBA") }, 1534181381Sjkim /* D W O BK */ 1535181381Sjkim { SST(0x1E, 0x00, SS_NOP | SSQ_PRINT_SENSE, 1536181381Sjkim "Recovered ID with ECC correction") }, 1537181381Sjkim /* D O K */ 1538181381Sjkim { SST(0x1F, 0x00, SS_RDEF, 1539181381Sjkim "Partial defect list transfer") }, 1540181381Sjkim /* DTLPWROMAEBKVF */ 1541181381Sjkim { SST(0x20, 0x00, SS_FATAL | EINVAL, 1542181381Sjkim "Invalid command operation code") }, 1543181381Sjkim /* DT PWROMAEBK */ 1544181381Sjkim { SST(0x20, 0x01, SS_RDEF, /* XXX TBD */ 1545181381Sjkim "Access denied - initiator pending-enrolled") }, 1546181381Sjkim /* DT PWROMAEBK */ 1547181381Sjkim { SST(0x20, 0x02, SS_RDEF, /* XXX TBD */ 1548181381Sjkim "Access denied - no access rights") }, 1549181381Sjkim /* DT PWROMAEBK */ 1550181381Sjkim { SST(0x20, 0x03, SS_RDEF, /* XXX TBD */ 1551181381Sjkim "Access denied - invalid mgmt ID key") }, 1552181381Sjkim /* T */ 1553181381Sjkim { SST(0x20, 0x04, SS_RDEF, /* XXX TBD */ 1554181381Sjkim "Illegal command while in write capable state") }, 1555181381Sjkim /* T */ 1556181381Sjkim { SST(0x20, 0x05, SS_RDEF, /* XXX TBD */ 1557181381Sjkim "Obsolete") }, 1558181381Sjkim /* T */ 1559181381Sjkim { SST(0x20, 0x06, SS_RDEF, /* XXX TBD */ 1560181381Sjkim "Illegal command while in explicit address mode") }, 1561181381Sjkim /* T */ 1562181381Sjkim { SST(0x20, 0x07, SS_RDEF, /* XXX TBD */ 1563181381Sjkim "Illegal command while in implicit address mode") }, 1564181381Sjkim /* DT PWROMAEBK */ 1565181381Sjkim { SST(0x20, 0x08, SS_RDEF, /* XXX TBD */ 1566181381Sjkim "Access denied - enrollment conflict") }, 1567181381Sjkim /* DT PWROMAEBK */ 1568181381Sjkim { SST(0x20, 0x09, SS_RDEF, /* XXX TBD */ 1569181381Sjkim "Access denied - invalid LU identifier") }, 1570181381Sjkim /* DT PWROMAEBK */ 1571181381Sjkim { SST(0x20, 0x0A, SS_RDEF, /* XXX TBD */ 1572181381Sjkim "Access denied - invalid proxy token") }, 1573181381Sjkim /* DT PWROMAEBK */ 1574181381Sjkim { SST(0x20, 0x0B, SS_RDEF, /* XXX TBD */ 1575181381Sjkim "Access denied - ACL LUN conflict") }, 1576238595Smav /* T */ 1577238595Smav { SST(0x20, 0x0C, SS_FATAL | EINVAL, 1578238595Smav "Illegal command when not in append-only mode") }, 1579181381Sjkim /* DT WRO BK */ 1580181381Sjkim { SST(0x21, 0x00, SS_FATAL | EINVAL, 1581181381Sjkim "Logical block address out of range") }, 1582181381Sjkim /* DT WROM BK */ 1583181381Sjkim { SST(0x21, 0x01, SS_FATAL | EINVAL, 1584181381Sjkim "Invalid element address") }, 1585181381Sjkim /* R */ 1586181381Sjkim { SST(0x21, 0x02, SS_RDEF, /* XXX TBD */ 1587181381Sjkim "Invalid address for write") }, 1588181381Sjkim /* R */ 1589181381Sjkim { SST(0x21, 0x03, SS_RDEF, /* XXX TBD */ 1590181381Sjkim "Invalid write crossing layer jump") }, 1591181381Sjkim /* D */ 1592181381Sjkim { SST(0x22, 0x00, SS_FATAL | EINVAL, 1593181381Sjkim "Illegal function (use 20 00, 24 00, or 26 00)") }, 1594238595Smav /* DT P B */ 1595238595Smav { SST(0x23, 0x00, SS_RDEF, /* XXX TBD */ 1596238595Smav "Invalid token operation, cause not reportable") }, 1597238595Smav /* DT P B */ 1598238595Smav { SST(0x23, 0x01, SS_RDEF, /* XXX TBD */ 1599238595Smav "Invalid token operation, unsupported token type") }, 1600238595Smav /* DT P B */ 1601238595Smav { SST(0x23, 0x02, SS_RDEF, /* XXX TBD */ 1602238595Smav "Invalid token operation, remote token usage not supported") }, 1603238595Smav /* DT P B */ 1604238595Smav { SST(0x23, 0x03, SS_RDEF, /* XXX TBD */ 1605238595Smav "Invalid token operation, remote ROD token creation not supported") }, 1606238595Smav /* DT P B */ 1607238595Smav { SST(0x23, 0x04, SS_RDEF, /* XXX TBD */ 1608238595Smav "Invalid token operation, token unknown") }, 1609238595Smav /* DT P B */ 1610238595Smav { SST(0x23, 0x05, SS_RDEF, /* XXX TBD */ 1611238595Smav "Invalid token operation, token corrupt") }, 1612238595Smav /* DT P B */ 1613238595Smav { SST(0x23, 0x06, SS_RDEF, /* XXX TBD */ 1614238595Smav "Invalid token operation, token revoked") }, 1615238595Smav /* DT P B */ 1616238595Smav { SST(0x23, 0x07, SS_RDEF, /* XXX TBD */ 1617238595Smav "Invalid token operation, token expired") }, 1618238595Smav /* DT P B */ 1619238595Smav { SST(0x23, 0x08, SS_RDEF, /* XXX TBD */ 1620238595Smav "Invalid token operation, token cancelled") }, 1621238595Smav /* DT P B */ 1622238595Smav { SST(0x23, 0x09, SS_RDEF, /* XXX TBD */ 1623238595Smav "Invalid token operation, token deleted") }, 1624238595Smav /* DT P B */ 1625238595Smav { SST(0x23, 0x0A, SS_RDEF, /* XXX TBD */ 1626238595Smav "Invalid token operation, invalid token length") }, 1627181381Sjkim /* DTLPWROMAEBKVF */ 1628181381Sjkim { SST(0x24, 0x00, SS_FATAL | EINVAL, 1629181381Sjkim "Invalid field in CDB") }, 1630181381Sjkim /* DTLPWRO AEBKVF */ 1631181381Sjkim { SST(0x24, 0x01, SS_RDEF, /* XXX TBD */ 1632181381Sjkim "CDB decryption error") }, 1633181381Sjkim /* T */ 1634181381Sjkim { SST(0x24, 0x02, SS_RDEF, /* XXX TBD */ 1635181381Sjkim "Obsolete") }, 1636181381Sjkim /* T */ 1637181381Sjkim { SST(0x24, 0x03, SS_RDEF, /* XXX TBD */ 1638181381Sjkim "Obsolete") }, 1639181381Sjkim /* F */ 1640181381Sjkim { SST(0x24, 0x04, SS_RDEF, /* XXX TBD */ 1641181381Sjkim "Security audit value frozen") }, 1642181381Sjkim /* F */ 1643181381Sjkim { SST(0x24, 0x05, SS_RDEF, /* XXX TBD */ 1644181381Sjkim "Security working key frozen") }, 1645181381Sjkim /* F */ 1646181381Sjkim { SST(0x24, 0x06, SS_RDEF, /* XXX TBD */ 1647181381Sjkim "NONCE not unique") }, 1648181381Sjkim /* F */ 1649181381Sjkim { SST(0x24, 0x07, SS_RDEF, /* XXX TBD */ 1650181381Sjkim "NONCE timestamp out of range") }, 1651181381Sjkim /* DT R MAEBKV */ 1652181381Sjkim { SST(0x24, 0x08, SS_RDEF, /* XXX TBD */ 1653181381Sjkim "Invalid XCDB") }, 1654181381Sjkim /* DTLPWROMAEBKVF */ 1655253322Smav { SST(0x25, 0x00, SS_FATAL | ENXIO | SSQ_LOST, 1656181381Sjkim "Logical unit not supported") }, 1657181381Sjkim /* DTLPWROMAEBKVF */ 1658181381Sjkim { SST(0x26, 0x00, SS_FATAL | EINVAL, 1659181381Sjkim "Invalid field in parameter list") }, 1660181381Sjkim /* DTLPWROMAEBKVF */ 1661181381Sjkim { SST(0x26, 0x01, SS_FATAL | EINVAL, 1662181381Sjkim "Parameter not supported") }, 1663181381Sjkim /* DTLPWROMAEBKVF */ 1664181381Sjkim { SST(0x26, 0x02, SS_FATAL | EINVAL, 1665181381Sjkim "Parameter value invalid") }, 1666181381Sjkim /* DTLPWROMAE K */ 1667181381Sjkim { SST(0x26, 0x03, SS_FATAL | EINVAL, 1668181381Sjkim "Threshold parameters not supported") }, 1669181381Sjkim /* DTLPWROMAEBKVF */ 1670181381Sjkim { SST(0x26, 0x04, SS_FATAL | EINVAL, 1671181381Sjkim "Invalid release of persistent reservation") }, 1672181381Sjkim /* DTLPWRO A BK */ 1673181381Sjkim { SST(0x26, 0x05, SS_RDEF, /* XXX TBD */ 1674181381Sjkim "Data decryption error") }, 1675181381Sjkim /* DTLPWRO K */ 1676181381Sjkim { SST(0x26, 0x06, SS_RDEF, /* XXX TBD */ 1677181381Sjkim "Too many target descriptors") }, 1678181381Sjkim /* DTLPWRO K */ 1679181381Sjkim { SST(0x26, 0x07, SS_RDEF, /* XXX TBD */ 1680181381Sjkim "Unsupported target descriptor type code") }, 1681181381Sjkim /* DTLPWRO K */ 1682181381Sjkim { SST(0x26, 0x08, SS_RDEF, /* XXX TBD */ 1683181381Sjkim "Too many segment descriptors") }, 1684181381Sjkim /* DTLPWRO K */ 1685181381Sjkim { SST(0x26, 0x09, SS_RDEF, /* XXX TBD */ 1686181381Sjkim "Unsupported segment descriptor type code") }, 1687181381Sjkim /* DTLPWRO K */ 1688181381Sjkim { SST(0x26, 0x0A, SS_RDEF, /* XXX TBD */ 1689181381Sjkim "Unexpected inexact segment") }, 1690181381Sjkim /* DTLPWRO K */ 1691181381Sjkim { SST(0x26, 0x0B, SS_RDEF, /* XXX TBD */ 1692181381Sjkim "Inline data length exceeded") }, 1693181381Sjkim /* DTLPWRO K */ 1694181381Sjkim { SST(0x26, 0x0C, SS_RDEF, /* XXX TBD */ 1695181381Sjkim "Invalid operation for copy source or destination") }, 1696181381Sjkim /* DTLPWRO K */ 1697181381Sjkim { SST(0x26, 0x0D, SS_RDEF, /* XXX TBD */ 1698181381Sjkim "Copy segment granularity violation") }, 1699181381Sjkim /* DT PWROMAEBK */ 1700181381Sjkim { SST(0x26, 0x0E, SS_RDEF, /* XXX TBD */ 1701181381Sjkim "Invalid parameter while port is enabled") }, 1702181381Sjkim /* F */ 1703181381Sjkim { SST(0x26, 0x0F, SS_RDEF, /* XXX TBD */ 1704181381Sjkim "Invalid data-out buffer integrity check value") }, 1705181381Sjkim /* T */ 1706181381Sjkim { SST(0x26, 0x10, SS_RDEF, /* XXX TBD */ 1707181381Sjkim "Data decryption key fail limit reached") }, 1708181381Sjkim /* T */ 1709181381Sjkim { SST(0x26, 0x11, SS_RDEF, /* XXX TBD */ 1710181381Sjkim "Incomplete key-associated data set") }, 1711181381Sjkim /* T */ 1712181381Sjkim { SST(0x26, 0x12, SS_RDEF, /* XXX TBD */ 1713181381Sjkim "Vendor specific key reference not found") }, 1714181381Sjkim /* DT WRO BK */ 1715181381Sjkim { SST(0x27, 0x00, SS_FATAL | EACCES, 1716181381Sjkim "Write protected") }, 1717181381Sjkim /* DT WRO BK */ 1718181381Sjkim { SST(0x27, 0x01, SS_FATAL | EACCES, 1719181381Sjkim "Hardware write protected") }, 1720181381Sjkim /* DT WRO BK */ 1721181381Sjkim { SST(0x27, 0x02, SS_FATAL | EACCES, 1722181381Sjkim "Logical unit software write protected") }, 1723181381Sjkim /* T R */ 1724181381Sjkim { SST(0x27, 0x03, SS_FATAL | EACCES, 1725181381Sjkim "Associated write protect") }, 1726181381Sjkim /* T R */ 1727181381Sjkim { SST(0x27, 0x04, SS_FATAL | EACCES, 1728181381Sjkim "Persistent write protect") }, 1729181381Sjkim /* T R */ 1730181381Sjkim { SST(0x27, 0x05, SS_FATAL | EACCES, 1731181381Sjkim "Permanent write protect") }, 1732181381Sjkim /* R F */ 1733181381Sjkim { SST(0x27, 0x06, SS_RDEF, /* XXX TBD */ 1734181381Sjkim "Conditional write protect") }, 1735238595Smav /* D B */ 1736238595Smav { SST(0x27, 0x07, SS_RDEF, /* XXX TBD */ 1737238595Smav "Space allocation failed write protect") }, 1738181381Sjkim /* DTLPWROMAEBKVF */ 1739181381Sjkim { SST(0x28, 0x00, SS_FATAL | ENXIO, 1740181381Sjkim "Not ready to ready change, medium may have changed") }, 1741181381Sjkim /* DT WROM B */ 1742181381Sjkim { SST(0x28, 0x01, SS_FATAL | ENXIO, 1743181381Sjkim "Import or export element accessed") }, 1744181381Sjkim /* R */ 1745181381Sjkim { SST(0x28, 0x02, SS_RDEF, /* XXX TBD */ 1746181381Sjkim "Format-layer may have changed") }, 1747181381Sjkim /* M */ 1748181381Sjkim { SST(0x28, 0x03, SS_RDEF, /* XXX TBD */ 1749181381Sjkim "Import/export element accessed, medium changed") }, 1750181381Sjkim /* 1751181381Sjkim * XXX JGibbs - All of these should use the same errno, but I don't 1752181381Sjkim * think ENXIO is the correct choice. Should we borrow from 1753181381Sjkim * the networking errnos? ECONNRESET anyone? 1754181381Sjkim */ 1755181381Sjkim /* DTLPWROMAEBKVF */ 1756181381Sjkim { SST(0x29, 0x00, SS_FATAL | ENXIO, 1757181381Sjkim "Power on, reset, or bus device reset occurred") }, 1758181381Sjkim /* DTLPWROMAEBKVF */ 1759181381Sjkim { SST(0x29, 0x01, SS_RDEF, 1760181381Sjkim "Power on occurred") }, 1761181381Sjkim /* DTLPWROMAEBKVF */ 1762181381Sjkim { SST(0x29, 0x02, SS_RDEF, 1763181381Sjkim "SCSI bus reset occurred") }, 1764181381Sjkim /* DTLPWROMAEBKVF */ 1765181381Sjkim { SST(0x29, 0x03, SS_RDEF, 1766181381Sjkim "Bus device reset function occurred") }, 1767181381Sjkim /* DTLPWROMAEBKVF */ 1768181381Sjkim { SST(0x29, 0x04, SS_RDEF, 1769181381Sjkim "Device internal reset") }, 1770181381Sjkim /* DTLPWROMAEBKVF */ 1771181381Sjkim { SST(0x29, 0x05, SS_RDEF, 1772181381Sjkim "Transceiver mode changed to single-ended") }, 1773181381Sjkim /* DTLPWROMAEBKVF */ 1774181381Sjkim { SST(0x29, 0x06, SS_RDEF, 1775181381Sjkim "Transceiver mode changed to LVD") }, 1776181381Sjkim /* DTLPWROMAEBKVF */ 1777181381Sjkim { SST(0x29, 0x07, SS_RDEF, /* XXX TBD */ 1778181381Sjkim "I_T nexus loss occurred") }, 1779181381Sjkim /* DTL WROMAEBKVF */ 1780181381Sjkim { SST(0x2A, 0x00, SS_RDEF, 1781181381Sjkim "Parameters changed") }, 1782181381Sjkim /* DTL WROMAEBKVF */ 1783181381Sjkim { SST(0x2A, 0x01, SS_RDEF, 1784181381Sjkim "Mode parameters changed") }, 1785181381Sjkim /* DTL WROMAE K */ 1786181381Sjkim { SST(0x2A, 0x02, SS_RDEF, 1787181381Sjkim "Log parameters changed") }, 1788181381Sjkim /* DTLPWROMAE K */ 1789181381Sjkim { SST(0x2A, 0x03, SS_RDEF, 1790181381Sjkim "Reservations preempted") }, 1791181381Sjkim /* DTLPWROMAE */ 1792181381Sjkim { SST(0x2A, 0x04, SS_RDEF, /* XXX TBD */ 1793181381Sjkim "Reservations released") }, 1794181381Sjkim /* DTLPWROMAE */ 1795181381Sjkim { SST(0x2A, 0x05, SS_RDEF, /* XXX TBD */ 1796181381Sjkim "Registrations preempted") }, 1797181381Sjkim /* DTLPWROMAEBKVF */ 1798181381Sjkim { SST(0x2A, 0x06, SS_RDEF, /* XXX TBD */ 1799181381Sjkim "Asymmetric access state changed") }, 1800181381Sjkim /* DTLPWROMAEBKVF */ 1801181381Sjkim { SST(0x2A, 0x07, SS_RDEF, /* XXX TBD */ 1802181381Sjkim "Implicit asymmetric access state transition failed") }, 1803181381Sjkim /* DT WROMAEBKVF */ 1804181381Sjkim { SST(0x2A, 0x08, SS_RDEF, /* XXX TBD */ 1805181381Sjkim "Priority changed") }, 1806181381Sjkim /* D */ 1807181381Sjkim { SST(0x2A, 0x09, SS_RDEF, /* XXX TBD */ 1808181381Sjkim "Capacity data has changed") }, 1809181381Sjkim /* DT */ 1810181381Sjkim { SST(0x2A, 0x0A, SS_RDEF, /* XXX TBD */ 1811181381Sjkim "Error history I_T nexus cleared") }, 1812181381Sjkim /* DT */ 1813181381Sjkim { SST(0x2A, 0x0B, SS_RDEF, /* XXX TBD */ 1814181381Sjkim "Error history snapshot released") }, 1815181381Sjkim /* F */ 1816181381Sjkim { SST(0x2A, 0x0C, SS_RDEF, /* XXX TBD */ 1817181381Sjkim "Error recovery attributes have changed") }, 1818181381Sjkim /* T */ 1819181381Sjkim { SST(0x2A, 0x0D, SS_RDEF, /* XXX TBD */ 1820181381Sjkim "Data encryption capabilities changed") }, 1821181381Sjkim /* DT M E V */ 1822181381Sjkim { SST(0x2A, 0x10, SS_RDEF, /* XXX TBD */ 1823181381Sjkim "Timestamp changed") }, 1824181381Sjkim /* T */ 1825181381Sjkim { SST(0x2A, 0x11, SS_RDEF, /* XXX TBD */ 1826181381Sjkim "Data encryption parameters changed by another I_T nexus") }, 1827181381Sjkim /* T */ 1828181381Sjkim { SST(0x2A, 0x12, SS_RDEF, /* XXX TBD */ 1829181381Sjkim "Data encryption parameters changed by vendor specific event") }, 1830181381Sjkim /* T */ 1831181381Sjkim { SST(0x2A, 0x13, SS_RDEF, /* XXX TBD */ 1832181381Sjkim "Data encryption key instance counter has changed") }, 1833181381Sjkim /* DT R MAEBKV */ 1834181381Sjkim { SST(0x2A, 0x14, SS_RDEF, /* XXX TBD */ 1835181381Sjkim "SA creation capabilities data has changed") }, 1836238595Smav /* T M V */ 1837238595Smav { SST(0x2A, 0x15, SS_RDEF, /* XXX TBD */ 1838238595Smav "Medium removal prevention preempted") }, 1839181381Sjkim /* DTLPWRO K */ 1840181381Sjkim { SST(0x2B, 0x00, SS_RDEF, 1841181381Sjkim "Copy cannot execute since host cannot disconnect") }, 1842181381Sjkim /* DTLPWROMAEBKVF */ 1843181381Sjkim { SST(0x2C, 0x00, SS_RDEF, 1844181381Sjkim "Command sequence error") }, 1845181381Sjkim /* */ 1846181381Sjkim { SST(0x2C, 0x01, SS_RDEF, 1847181381Sjkim "Too many windows specified") }, 1848181381Sjkim /* */ 1849181381Sjkim { SST(0x2C, 0x02, SS_RDEF, 1850181381Sjkim "Invalid combination of windows specified") }, 1851181381Sjkim /* R */ 1852181381Sjkim { SST(0x2C, 0x03, SS_RDEF, 1853181381Sjkim "Current program area is not empty") }, 1854181381Sjkim /* R */ 1855181381Sjkim { SST(0x2C, 0x04, SS_RDEF, 1856181381Sjkim "Current program area is empty") }, 1857181381Sjkim /* B */ 1858181381Sjkim { SST(0x2C, 0x05, SS_RDEF, /* XXX TBD */ 1859181381Sjkim "Illegal power condition request") }, 1860181381Sjkim /* R */ 1861181381Sjkim { SST(0x2C, 0x06, SS_RDEF, /* XXX TBD */ 1862181381Sjkim "Persistent prevent conflict") }, 1863181381Sjkim /* DTLPWROMAEBKVF */ 1864181381Sjkim { SST(0x2C, 0x07, SS_RDEF, /* XXX TBD */ 1865181381Sjkim "Previous busy status") }, 1866181381Sjkim /* DTLPWROMAEBKVF */ 1867181381Sjkim { SST(0x2C, 0x08, SS_RDEF, /* XXX TBD */ 1868181381Sjkim "Previous task set full status") }, 1869181381Sjkim /* DTLPWROM EBKVF */ 1870181381Sjkim { SST(0x2C, 0x09, SS_RDEF, /* XXX TBD */ 1871181381Sjkim "Previous reservation conflict status") }, 1872181381Sjkim /* F */ 1873181381Sjkim { SST(0x2C, 0x0A, SS_RDEF, /* XXX TBD */ 1874181381Sjkim "Partition or collection contains user objects") }, 1875181381Sjkim /* T */ 1876181381Sjkim { SST(0x2C, 0x0B, SS_RDEF, /* XXX TBD */ 1877181381Sjkim "Not reserved") }, 1878238595Smav /* D */ 1879238595Smav { SST(0x2C, 0x0C, SS_RDEF, /* XXX TBD */ 1880238595Smav "ORWRITE generation does not match") }, 1881181381Sjkim /* T */ 1882181381Sjkim { SST(0x2D, 0x00, SS_RDEF, 1883181381Sjkim "Overwrite error on update in place") }, 1884181381Sjkim /* R */ 1885181381Sjkim { SST(0x2E, 0x00, SS_RDEF, /* XXX TBD */ 1886181381Sjkim "Insufficient time for operation") }, 1887181381Sjkim /* DTLPWROMAEBKVF */ 1888181381Sjkim { SST(0x2F, 0x00, SS_RDEF, 1889181381Sjkim "Commands cleared by another initiator") }, 1890181381Sjkim /* D */ 1891181381Sjkim { SST(0x2F, 0x01, SS_RDEF, /* XXX TBD */ 1892181381Sjkim "Commands cleared by power loss notification") }, 1893181381Sjkim /* DTLPWROMAEBKVF */ 1894181381Sjkim { SST(0x2F, 0x02, SS_RDEF, /* XXX TBD */ 1895181381Sjkim "Commands cleared by device server") }, 1896181381Sjkim /* DT WROM BK */ 1897181381Sjkim { SST(0x30, 0x00, SS_RDEF, 1898181381Sjkim "Incompatible medium installed") }, 1899181381Sjkim /* DT WRO BK */ 1900181381Sjkim { SST(0x30, 0x01, SS_RDEF, 1901181381Sjkim "Cannot read medium - unknown format") }, 1902181381Sjkim /* DT WRO BK */ 1903181381Sjkim { SST(0x30, 0x02, SS_RDEF, 1904181381Sjkim "Cannot read medium - incompatible format") }, 1905181381Sjkim /* DT R K */ 1906181381Sjkim { SST(0x30, 0x03, SS_RDEF, 1907181381Sjkim "Cleaning cartridge installed") }, 1908181381Sjkim /* DT WRO BK */ 1909181381Sjkim { SST(0x30, 0x04, SS_RDEF, 1910181381Sjkim "Cannot write medium - unknown format") }, 1911181381Sjkim /* DT WRO BK */ 1912181381Sjkim { SST(0x30, 0x05, SS_RDEF, 1913181381Sjkim "Cannot write medium - incompatible format") }, 1914181381Sjkim /* DT WRO B */ 1915181381Sjkim { SST(0x30, 0x06, SS_RDEF, 1916181381Sjkim "Cannot format medium - incompatible medium") }, 1917181381Sjkim /* DTL WROMAEBKVF */ 1918181381Sjkim { SST(0x30, 0x07, SS_RDEF, 1919181381Sjkim "Cleaning failure") }, 1920181381Sjkim /* R */ 1921181381Sjkim { SST(0x30, 0x08, SS_RDEF, 1922181381Sjkim "Cannot write - application code mismatch") }, 1923181381Sjkim /* R */ 1924181381Sjkim { SST(0x30, 0x09, SS_RDEF, 1925181381Sjkim "Current session not fixated for append") }, 1926181381Sjkim /* DT WRO AEBK */ 1927181381Sjkim { SST(0x30, 0x0A, SS_RDEF, /* XXX TBD */ 1928181381Sjkim "Cleaning request rejected") }, 1929181381Sjkim /* T */ 1930181381Sjkim { SST(0x30, 0x0C, SS_RDEF, /* XXX TBD */ 1931181381Sjkim "WORM medium - overwrite attempted") }, 1932181381Sjkim /* T */ 1933181381Sjkim { SST(0x30, 0x0D, SS_RDEF, /* XXX TBD */ 1934181381Sjkim "WORM medium - integrity check") }, 1935181381Sjkim /* R */ 1936181381Sjkim { SST(0x30, 0x10, SS_RDEF, /* XXX TBD */ 1937181381Sjkim "Medium not formatted") }, 1938181381Sjkim /* M */ 1939181381Sjkim { SST(0x30, 0x11, SS_RDEF, /* XXX TBD */ 1940181381Sjkim "Incompatible volume type") }, 1941181381Sjkim /* M */ 1942181381Sjkim { SST(0x30, 0x12, SS_RDEF, /* XXX TBD */ 1943181381Sjkim "Incompatible volume qualifier") }, 1944238595Smav /* M */ 1945238595Smav { SST(0x30, 0x13, SS_RDEF, /* XXX TBD */ 1946238595Smav "Cleaning volume expired") }, 1947181381Sjkim /* DT WRO BK */ 1948181381Sjkim { SST(0x31, 0x00, SS_RDEF, 1949181381Sjkim "Medium format corrupted") }, 1950181381Sjkim /* D L RO B */ 1951181381Sjkim { SST(0x31, 0x01, SS_RDEF, 1952181381Sjkim "Format command failed") }, 1953181381Sjkim /* R */ 1954181381Sjkim { SST(0x31, 0x02, SS_RDEF, /* XXX TBD */ 1955181381Sjkim "Zoned formatting failed due to spare linking") }, 1956238595Smav /* D B */ 1957238595Smav { SST(0x31, 0x03, SS_RDEF, /* XXX TBD */ 1958238595Smav "SANITIZE command failed") }, 1959181381Sjkim /* D W O BK */ 1960181381Sjkim { SST(0x32, 0x00, SS_RDEF, 1961181381Sjkim "No defect spare location available") }, 1962181381Sjkim /* D W O BK */ 1963181381Sjkim { SST(0x32, 0x01, SS_RDEF, 1964181381Sjkim "Defect list update failure") }, 1965181381Sjkim /* T */ 1966181381Sjkim { SST(0x33, 0x00, SS_RDEF, 1967181381Sjkim "Tape length error") }, 1968181381Sjkim /* DTLPWROMAEBKVF */ 1969181381Sjkim { SST(0x34, 0x00, SS_RDEF, 1970181381Sjkim "Enclosure failure") }, 1971181381Sjkim /* DTLPWROMAEBKVF */ 1972181381Sjkim { SST(0x35, 0x00, SS_RDEF, 1973181381Sjkim "Enclosure services failure") }, 1974181381Sjkim /* DTLPWROMAEBKVF */ 1975181381Sjkim { SST(0x35, 0x01, SS_RDEF, 1976181381Sjkim "Unsupported enclosure function") }, 1977181381Sjkim /* DTLPWROMAEBKVF */ 1978181381Sjkim { SST(0x35, 0x02, SS_RDEF, 1979181381Sjkim "Enclosure services unavailable") }, 1980181381Sjkim /* DTLPWROMAEBKVF */ 1981181381Sjkim { SST(0x35, 0x03, SS_RDEF, 1982181381Sjkim "Enclosure services transfer failure") }, 1983181381Sjkim /* DTLPWROMAEBKVF */ 1984181381Sjkim { SST(0x35, 0x04, SS_RDEF, 1985181381Sjkim "Enclosure services transfer refused") }, 1986181381Sjkim /* DTL WROMAEBKVF */ 1987181381Sjkim { SST(0x35, 0x05, SS_RDEF, /* XXX TBD */ 1988181381Sjkim "Enclosure services checksum error") }, 1989181381Sjkim /* L */ 1990181381Sjkim { SST(0x36, 0x00, SS_RDEF, 1991181381Sjkim "Ribbon, ink, or toner failure") }, 1992181381Sjkim /* DTL WROMAEBKVF */ 1993181381Sjkim { SST(0x37, 0x00, SS_RDEF, 1994181381Sjkim "Rounded parameter") }, 1995181381Sjkim /* B */ 1996181381Sjkim { SST(0x38, 0x00, SS_RDEF, /* XXX TBD */ 1997181381Sjkim "Event status notification") }, 1998181381Sjkim /* B */ 1999181381Sjkim { SST(0x38, 0x02, SS_RDEF, /* XXX TBD */ 2000181381Sjkim "ESN - power management class event") }, 2001181381Sjkim /* B */ 2002181381Sjkim { SST(0x38, 0x04, SS_RDEF, /* XXX TBD */ 2003181381Sjkim "ESN - media class event") }, 2004181381Sjkim /* B */ 2005181381Sjkim { SST(0x38, 0x06, SS_RDEF, /* XXX TBD */ 2006181381Sjkim "ESN - device busy class event") }, 2007238595Smav /* D */ 2008238595Smav { SST(0x38, 0x07, SS_RDEF, /* XXX TBD */ 2009238595Smav "Thin provisioning soft threshold reached") }, 2010181381Sjkim /* DTL WROMAE K */ 2011181381Sjkim { SST(0x39, 0x00, SS_RDEF, 2012181381Sjkim "Saving parameters not supported") }, 2013181381Sjkim /* DTL WROM BK */ 2014181381Sjkim { SST(0x3A, 0x00, SS_FATAL | ENXIO, 2015181381Sjkim "Medium not present") }, 2016181381Sjkim /* DT WROM BK */ 2017181381Sjkim { SST(0x3A, 0x01, SS_FATAL | ENXIO, 2018181381Sjkim "Medium not present - tray closed") }, 2019181381Sjkim /* DT WROM BK */ 2020181381Sjkim { SST(0x3A, 0x02, SS_FATAL | ENXIO, 2021181381Sjkim "Medium not present - tray open") }, 2022181381Sjkim /* DT WROM B */ 2023181381Sjkim { SST(0x3A, 0x03, SS_RDEF, /* XXX TBD */ 2024181381Sjkim "Medium not present - loadable") }, 2025181381Sjkim /* DT WRO B */ 2026181381Sjkim { SST(0x3A, 0x04, SS_RDEF, /* XXX TBD */ 2027181381Sjkim "Medium not present - medium auxiliary memory accessible") }, 2028181381Sjkim /* TL */ 2029181381Sjkim { SST(0x3B, 0x00, SS_RDEF, 2030181381Sjkim "Sequential positioning error") }, 2031181381Sjkim /* T */ 2032181381Sjkim { SST(0x3B, 0x01, SS_RDEF, 2033181381Sjkim "Tape position error at beginning-of-medium") }, 2034181381Sjkim /* T */ 2035181381Sjkim { SST(0x3B, 0x02, SS_RDEF, 2036181381Sjkim "Tape position error at end-of-medium") }, 2037181381Sjkim /* L */ 2038181381Sjkim { SST(0x3B, 0x03, SS_RDEF, 2039181381Sjkim "Tape or electronic vertical forms unit not ready") }, 2040181381Sjkim /* L */ 2041181381Sjkim { SST(0x3B, 0x04, SS_RDEF, 2042181381Sjkim "Slew failure") }, 2043181381Sjkim /* L */ 2044181381Sjkim { SST(0x3B, 0x05, SS_RDEF, 2045181381Sjkim "Paper jam") }, 2046181381Sjkim /* L */ 2047181381Sjkim { SST(0x3B, 0x06, SS_RDEF, 2048181381Sjkim "Failed to sense top-of-form") }, 2049181381Sjkim /* L */ 2050181381Sjkim { SST(0x3B, 0x07, SS_RDEF, 2051181381Sjkim "Failed to sense bottom-of-form") }, 2052181381Sjkim /* T */ 2053181381Sjkim { SST(0x3B, 0x08, SS_RDEF, 2054181381Sjkim "Reposition error") }, 2055181381Sjkim /* */ 2056181381Sjkim { SST(0x3B, 0x09, SS_RDEF, 2057181381Sjkim "Read past end of medium") }, 2058181381Sjkim /* */ 2059181381Sjkim { SST(0x3B, 0x0A, SS_RDEF, 2060181381Sjkim "Read past beginning of medium") }, 2061181381Sjkim /* */ 2062181381Sjkim { SST(0x3B, 0x0B, SS_RDEF, 2063181381Sjkim "Position past end of medium") }, 2064181381Sjkim /* T */ 2065181381Sjkim { SST(0x3B, 0x0C, SS_RDEF, 2066181381Sjkim "Position past beginning of medium") }, 2067181381Sjkim /* DT WROM BK */ 2068181381Sjkim { SST(0x3B, 0x0D, SS_FATAL | ENOSPC, 2069181381Sjkim "Medium destination element full") }, 2070181381Sjkim /* DT WROM BK */ 2071181381Sjkim { SST(0x3B, 0x0E, SS_RDEF, 2072181381Sjkim "Medium source element empty") }, 2073181381Sjkim /* R */ 2074181381Sjkim { SST(0x3B, 0x0F, SS_RDEF, 2075181381Sjkim "End of medium reached") }, 2076181381Sjkim /* DT WROM BK */ 2077181381Sjkim { SST(0x3B, 0x11, SS_RDEF, 2078181381Sjkim "Medium magazine not accessible") }, 2079181381Sjkim /* DT WROM BK */ 2080181381Sjkim { SST(0x3B, 0x12, SS_RDEF, 2081181381Sjkim "Medium magazine removed") }, 2082181381Sjkim /* DT WROM BK */ 2083181381Sjkim { SST(0x3B, 0x13, SS_RDEF, 2084181381Sjkim "Medium magazine inserted") }, 2085181381Sjkim /* DT WROM BK */ 2086181381Sjkim { SST(0x3B, 0x14, SS_RDEF, 2087181381Sjkim "Medium magazine locked") }, 2088181381Sjkim /* DT WROM BK */ 2089181381Sjkim { SST(0x3B, 0x15, SS_RDEF, 2090181381Sjkim "Medium magazine unlocked") }, 2091181381Sjkim /* R */ 2092181381Sjkim { SST(0x3B, 0x16, SS_RDEF, /* XXX TBD */ 2093181381Sjkim "Mechanical positioning or changer error") }, 2094181381Sjkim /* F */ 2095181381Sjkim { SST(0x3B, 0x17, SS_RDEF, /* XXX TBD */ 2096181381Sjkim "Read past end of user object") }, 2097181381Sjkim /* M */ 2098181381Sjkim { SST(0x3B, 0x18, SS_RDEF, /* XXX TBD */ 2099181381Sjkim "Element disabled") }, 2100181381Sjkim /* M */ 2101181381Sjkim { SST(0x3B, 0x19, SS_RDEF, /* XXX TBD */ 2102181381Sjkim "Element enabled") }, 2103181381Sjkim /* M */ 2104181381Sjkim { SST(0x3B, 0x1A, SS_RDEF, /* XXX TBD */ 2105181381Sjkim "Data transfer device removed") }, 2106181381Sjkim /* M */ 2107181381Sjkim { SST(0x3B, 0x1B, SS_RDEF, /* XXX TBD */ 2108181381Sjkim "Data transfer device inserted") }, 2109238595Smav /* T */ 2110238595Smav { SST(0x3B, 0x1C, SS_RDEF, /* XXX TBD */ 2111238595Smav "Too many logical objects on partition to support operation") }, 2112181381Sjkim /* DTLPWROMAE K */ 2113181381Sjkim { SST(0x3D, 0x00, SS_RDEF, 2114181381Sjkim "Invalid bits in IDENTIFY message") }, 2115181381Sjkim /* DTLPWROMAEBKVF */ 2116181381Sjkim { SST(0x3E, 0x00, SS_RDEF, 2117181381Sjkim "Logical unit has not self-configured yet") }, 2118181381Sjkim /* DTLPWROMAEBKVF */ 2119181381Sjkim { SST(0x3E, 0x01, SS_RDEF, 2120181381Sjkim "Logical unit failure") }, 2121181381Sjkim /* DTLPWROMAEBKVF */ 2122181381Sjkim { SST(0x3E, 0x02, SS_RDEF, 2123181381Sjkim "Timeout on logical unit") }, 2124181381Sjkim /* DTLPWROMAEBKVF */ 2125181381Sjkim { SST(0x3E, 0x03, SS_RDEF, /* XXX TBD */ 2126181381Sjkim "Logical unit failed self-test") }, 2127181381Sjkim /* DTLPWROMAEBKVF */ 2128181381Sjkim { SST(0x3E, 0x04, SS_RDEF, /* XXX TBD */ 2129181381Sjkim "Logical unit unable to update self-test log") }, 2130181381Sjkim /* DTLPWROMAEBKVF */ 2131181381Sjkim { SST(0x3F, 0x00, SS_RDEF, 2132181381Sjkim "Target operating conditions have changed") }, 2133181381Sjkim /* DTLPWROMAEBKVF */ 2134181381Sjkim { SST(0x3F, 0x01, SS_RDEF, 2135181381Sjkim "Microcode has been changed") }, 2136181381Sjkim /* DTLPWROM BK */ 2137181381Sjkim { SST(0x3F, 0x02, SS_RDEF, 2138181381Sjkim "Changed operating definition") }, 2139181381Sjkim /* DTLPWROMAEBKVF */ 2140181381Sjkim { SST(0x3F, 0x03, SS_RDEF, 2141181381Sjkim "INQUIRY data has changed") }, 2142181381Sjkim /* DT WROMAEBK */ 2143181381Sjkim { SST(0x3F, 0x04, SS_RDEF, 2144181381Sjkim "Component device attached") }, 2145181381Sjkim /* DT WROMAEBK */ 2146181381Sjkim { SST(0x3F, 0x05, SS_RDEF, 2147181381Sjkim "Device identifier changed") }, 2148181381Sjkim /* DT WROMAEB */ 2149181381Sjkim { SST(0x3F, 0x06, SS_RDEF, 2150181381Sjkim "Redundancy group created or modified") }, 2151181381Sjkim /* DT WROMAEB */ 2152181381Sjkim { SST(0x3F, 0x07, SS_RDEF, 2153181381Sjkim "Redundancy group deleted") }, 2154181381Sjkim /* DT WROMAEB */ 2155181381Sjkim { SST(0x3F, 0x08, SS_RDEF, 2156181381Sjkim "Spare created or modified") }, 2157181381Sjkim /* DT WROMAEB */ 2158181381Sjkim { SST(0x3F, 0x09, SS_RDEF, 2159181381Sjkim "Spare deleted") }, 2160181381Sjkim /* DT WROMAEBK */ 2161181381Sjkim { SST(0x3F, 0x0A, SS_RDEF, 2162181381Sjkim "Volume set created or modified") }, 2163181381Sjkim /* DT WROMAEBK */ 2164181381Sjkim { SST(0x3F, 0x0B, SS_RDEF, 2165181381Sjkim "Volume set deleted") }, 2166181381Sjkim /* DT WROMAEBK */ 2167181381Sjkim { SST(0x3F, 0x0C, SS_RDEF, 2168181381Sjkim "Volume set deassigned") }, 2169181381Sjkim /* DT WROMAEBK */ 2170181381Sjkim { SST(0x3F, 0x0D, SS_RDEF, 2171181381Sjkim "Volume set reassigned") }, 2172181381Sjkim /* DTLPWROMAE */ 2173253322Smav { SST(0x3F, 0x0E, SS_RDEF | SSQ_RESCAN , 2174181381Sjkim "Reported LUNs data has changed") }, 2175181381Sjkim /* DTLPWROMAEBKVF */ 2176181381Sjkim { SST(0x3F, 0x0F, SS_RDEF, /* XXX TBD */ 2177181381Sjkim "Echo buffer overwritten") }, 2178181381Sjkim /* DT WROM B */ 2179181381Sjkim { SST(0x3F, 0x10, SS_RDEF, /* XXX TBD */ 2180181381Sjkim "Medium loadable") }, 2181181381Sjkim /* DT WROM B */ 2182181381Sjkim { SST(0x3F, 0x11, SS_RDEF, /* XXX TBD */ 2183181381Sjkim "Medium auxiliary memory accessible") }, 2184181381Sjkim /* DTLPWR MAEBK F */ 2185181381Sjkim { SST(0x3F, 0x12, SS_RDEF, /* XXX TBD */ 2186181381Sjkim "iSCSI IP address added") }, 2187181381Sjkim /* DTLPWR MAEBK F */ 2188181381Sjkim { SST(0x3F, 0x13, SS_RDEF, /* XXX TBD */ 2189181381Sjkim "iSCSI IP address removed") }, 2190181381Sjkim /* DTLPWR MAEBK F */ 2191181381Sjkim { SST(0x3F, 0x14, SS_RDEF, /* XXX TBD */ 2192181381Sjkim "iSCSI IP address changed") }, 2193181381Sjkim /* D */ 2194181381Sjkim { SST(0x40, 0x00, SS_RDEF, 2195181381Sjkim "RAM failure") }, /* deprecated - use 40 NN instead */ 2196181381Sjkim /* DTLPWROMAEBKVF */ 2197181381Sjkim { SST(0x40, 0x80, SS_RDEF, 2198181381Sjkim "Diagnostic failure: ASCQ = Component ID") }, 2199181381Sjkim /* DTLPWROMAEBKVF */ 2200181381Sjkim { SST(0x40, 0xFF, SS_RDEF | SSQ_RANGE, 2201181381Sjkim NULL) }, /* Range 0x80->0xFF */ 2202181381Sjkim /* D */ 2203181381Sjkim { SST(0x41, 0x00, SS_RDEF, 2204181381Sjkim "Data path failure") }, /* deprecated - use 40 NN instead */ 2205181381Sjkim /* D */ 2206181381Sjkim { SST(0x42, 0x00, SS_RDEF, 2207181381Sjkim "Power-on or self-test failure") }, 2208181381Sjkim /* deprecated - use 40 NN instead */ 2209181381Sjkim /* DTLPWROMAEBKVF */ 2210181381Sjkim { SST(0x43, 0x00, SS_RDEF, 2211181381Sjkim "Message error") }, 2212181381Sjkim /* DTLPWROMAEBKVF */ 2213181381Sjkim { SST(0x44, 0x00, SS_RDEF, 2214181381Sjkim "Internal target failure") }, 2215238595Smav /* DT P MAEBKVF */ 2216238595Smav { SST(0x44, 0x01, SS_RDEF, /* XXX TBD */ 2217238595Smav "Persistent reservation information lost") }, 2218181381Sjkim /* DT B */ 2219181381Sjkim { SST(0x44, 0x71, SS_RDEF, /* XXX TBD */ 2220181381Sjkim "ATA device failed set features") }, 2221181381Sjkim /* DTLPWROMAEBKVF */ 2222181381Sjkim { SST(0x45, 0x00, SS_RDEF, 2223181381Sjkim "Select or reselect failure") }, 2224181381Sjkim /* DTLPWROM BK */ 2225181381Sjkim { SST(0x46, 0x00, SS_RDEF, 2226181381Sjkim "Unsuccessful soft reset") }, 2227181381Sjkim /* DTLPWROMAEBKVF */ 2228181381Sjkim { SST(0x47, 0x00, SS_RDEF, 2229181381Sjkim "SCSI parity error") }, 2230181381Sjkim /* DTLPWROMAEBKVF */ 2231181381Sjkim { SST(0x47, 0x01, SS_RDEF, /* XXX TBD */ 2232181381Sjkim "Data phase CRC error detected") }, 2233181381Sjkim /* DTLPWROMAEBKVF */ 2234181381Sjkim { SST(0x47, 0x02, SS_RDEF, /* XXX TBD */ 2235181381Sjkim "SCSI parity error detected during ST data phase") }, 2236181381Sjkim /* DTLPWROMAEBKVF */ 2237181381Sjkim { SST(0x47, 0x03, SS_RDEF, /* XXX TBD */ 2238181381Sjkim "Information unit iuCRC error detected") }, 2239181381Sjkim /* DTLPWROMAEBKVF */ 2240181381Sjkim { SST(0x47, 0x04, SS_RDEF, /* XXX TBD */ 2241181381Sjkim "Asynchronous information protection error detected") }, 2242181381Sjkim /* DTLPWROMAEBKVF */ 2243181381Sjkim { SST(0x47, 0x05, SS_RDEF, /* XXX TBD */ 2244181381Sjkim "Protocol service CRC error") }, 2245181381Sjkim /* DT MAEBKVF */ 2246181381Sjkim { SST(0x47, 0x06, SS_RDEF, /* XXX TBD */ 2247181381Sjkim "PHY test function in progress") }, 2248181381Sjkim /* DT PWROMAEBK */ 2249181381Sjkim { SST(0x47, 0x7F, SS_RDEF, /* XXX TBD */ 2250181381Sjkim "Some commands cleared by iSCSI protocol event") }, 2251181381Sjkim /* DTLPWROMAEBKVF */ 2252181381Sjkim { SST(0x48, 0x00, SS_RDEF, 2253181381Sjkim "Initiator detected error message received") }, 2254181381Sjkim /* DTLPWROMAEBKVF */ 2255181381Sjkim { SST(0x49, 0x00, SS_RDEF, 2256181381Sjkim "Invalid message error") }, 2257181381Sjkim /* DTLPWROMAEBKVF */ 2258181381Sjkim { SST(0x4A, 0x00, SS_RDEF, 2259181381Sjkim "Command phase error") }, 2260181381Sjkim /* DTLPWROMAEBKVF */ 2261181381Sjkim { SST(0x4B, 0x00, SS_RDEF, 2262181381Sjkim "Data phase error") }, 2263181381Sjkim /* DT PWROMAEBK */ 2264181381Sjkim { SST(0x4B, 0x01, SS_RDEF, /* XXX TBD */ 2265181381Sjkim "Invalid target port transfer tag received") }, 2266181381Sjkim /* DT PWROMAEBK */ 2267181381Sjkim { SST(0x4B, 0x02, SS_RDEF, /* XXX TBD */ 2268181381Sjkim "Too much write data") }, 2269181381Sjkim /* DT PWROMAEBK */ 2270181381Sjkim { SST(0x4B, 0x03, SS_RDEF, /* XXX TBD */ 2271181381Sjkim "ACK/NAK timeout") }, 2272181381Sjkim /* DT PWROMAEBK */ 2273181381Sjkim { SST(0x4B, 0x04, SS_RDEF, /* XXX TBD */ 2274181381Sjkim "NAK received") }, 2275181381Sjkim /* DT PWROMAEBK */ 2276181381Sjkim { SST(0x4B, 0x05, SS_RDEF, /* XXX TBD */ 2277181381Sjkim "Data offset error") }, 2278181381Sjkim /* DT PWROMAEBK */ 2279181381Sjkim { SST(0x4B, 0x06, SS_RDEF, /* XXX TBD */ 2280181381Sjkim "Initiator response timeout") }, 2281238595Smav /* DT PWROMAEBK F */ 2282238595Smav { SST(0x4B, 0x07, SS_RDEF, /* XXX TBD */ 2283238595Smav "Connection lost") }, 2284238595Smav /* DT PWROMAEBK F */ 2285238595Smav { SST(0x4B, 0x08, SS_RDEF, /* XXX TBD */ 2286238595Smav "Data-in buffer overflow - data buffer size") }, 2287238595Smav /* DT PWROMAEBK F */ 2288238595Smav { SST(0x4B, 0x09, SS_RDEF, /* XXX TBD */ 2289238595Smav "Data-in buffer overflow - data buffer descriptor area") }, 2290238595Smav /* DT PWROMAEBK F */ 2291238595Smav { SST(0x4B, 0x0A, SS_RDEF, /* XXX TBD */ 2292238595Smav "Data-in buffer error") }, 2293238595Smav /* DT PWROMAEBK F */ 2294238595Smav { SST(0x4B, 0x0B, SS_RDEF, /* XXX TBD */ 2295238595Smav "Data-out buffer overflow - data buffer size") }, 2296238595Smav /* DT PWROMAEBK F */ 2297238595Smav { SST(0x4B, 0x0C, SS_RDEF, /* XXX TBD */ 2298238595Smav "Data-out buffer overflow - data buffer descriptor area") }, 2299238595Smav /* DT PWROMAEBK F */ 2300238595Smav { SST(0x4B, 0x0D, SS_RDEF, /* XXX TBD */ 2301238595Smav "Data-out buffer error") }, 2302181381Sjkim /* DTLPWROMAEBKVF */ 2303181381Sjkim { SST(0x4C, 0x00, SS_RDEF, 2304181381Sjkim "Logical unit failed self-configuration") }, 2305181381Sjkim /* DTLPWROMAEBKVF */ 2306181381Sjkim { SST(0x4D, 0x00, SS_RDEF, 2307181381Sjkim "Tagged overlapped commands: ASCQ = Queue tag ID") }, 2308181381Sjkim /* DTLPWROMAEBKVF */ 2309181381Sjkim { SST(0x4D, 0xFF, SS_RDEF | SSQ_RANGE, 2310181381Sjkim NULL) }, /* Range 0x00->0xFF */ 2311181381Sjkim /* DTLPWROMAEBKVF */ 2312181381Sjkim { SST(0x4E, 0x00, SS_RDEF, 2313181381Sjkim "Overlapped commands attempted") }, 2314181381Sjkim /* T */ 2315181381Sjkim { SST(0x50, 0x00, SS_RDEF, 2316181381Sjkim "Write append error") }, 2317181381Sjkim /* T */ 2318181381Sjkim { SST(0x50, 0x01, SS_RDEF, 2319181381Sjkim "Write append position error") }, 2320181381Sjkim /* T */ 2321181381Sjkim { SST(0x50, 0x02, SS_RDEF, 2322181381Sjkim "Position error related to timing") }, 2323181381Sjkim /* T RO */ 2324181381Sjkim { SST(0x51, 0x00, SS_RDEF, 2325181381Sjkim "Erase failure") }, 2326181381Sjkim /* R */ 2327181381Sjkim { SST(0x51, 0x01, SS_RDEF, /* XXX TBD */ 2328181381Sjkim "Erase failure - incomplete erase operation detected") }, 2329181381Sjkim /* T */ 2330181381Sjkim { SST(0x52, 0x00, SS_RDEF, 2331181381Sjkim "Cartridge fault") }, 2332181381Sjkim /* DTL WROM BK */ 2333181381Sjkim { SST(0x53, 0x00, SS_RDEF, 2334181381Sjkim "Media load or eject failed") }, 2335181381Sjkim /* T */ 2336181381Sjkim { SST(0x53, 0x01, SS_RDEF, 2337181381Sjkim "Unload tape failure") }, 2338181381Sjkim /* DT WROM BK */ 2339181381Sjkim { SST(0x53, 0x02, SS_RDEF, 2340181381Sjkim "Medium removal prevented") }, 2341181381Sjkim /* M */ 2342181381Sjkim { SST(0x53, 0x03, SS_RDEF, /* XXX TBD */ 2343181381Sjkim "Medium removal prevented by data transfer element") }, 2344181381Sjkim /* T */ 2345181381Sjkim { SST(0x53, 0x04, SS_RDEF, /* XXX TBD */ 2346181381Sjkim "Medium thread or unthread failure") }, 2347238595Smav /* M */ 2348238595Smav { SST(0x53, 0x05, SS_RDEF, /* XXX TBD */ 2349238595Smav "Volume identifier invalid") }, 2350238595Smav /* T */ 2351238595Smav { SST(0x53, 0x06, SS_RDEF, /* XXX TBD */ 2352238595Smav "Volume identifier missing") }, 2353238595Smav /* M */ 2354238595Smav { SST(0x53, 0x07, SS_RDEF, /* XXX TBD */ 2355238595Smav "Duplicate volume identifier") }, 2356238595Smav /* M */ 2357238595Smav { SST(0x53, 0x08, SS_RDEF, /* XXX TBD */ 2358238595Smav "Element status unknown") }, 2359181381Sjkim /* P */ 2360181381Sjkim { SST(0x54, 0x00, SS_RDEF, 2361181381Sjkim "SCSI to host system interface failure") }, 2362181381Sjkim /* P */ 2363181381Sjkim { SST(0x55, 0x00, SS_RDEF, 2364181381Sjkim "System resource failure") }, 2365181381Sjkim /* D O BK */ 2366181381Sjkim { SST(0x55, 0x01, SS_FATAL | ENOSPC, 2367181381Sjkim "System buffer full") }, 2368181381Sjkim /* DTLPWROMAE K */ 2369181381Sjkim { SST(0x55, 0x02, SS_RDEF, /* XXX TBD */ 2370181381Sjkim "Insufficient reservation resources") }, 2371181381Sjkim /* DTLPWROMAE K */ 2372181381Sjkim { SST(0x55, 0x03, SS_RDEF, /* XXX TBD */ 2373181381Sjkim "Insufficient resources") }, 2374181381Sjkim /* DTLPWROMAE K */ 2375181381Sjkim { SST(0x55, 0x04, SS_RDEF, /* XXX TBD */ 2376181381Sjkim "Insufficient registration resources") }, 2377181381Sjkim /* DT PWROMAEBK */ 2378181381Sjkim { SST(0x55, 0x05, SS_RDEF, /* XXX TBD */ 2379181381Sjkim "Insufficient access control resources") }, 2380181381Sjkim /* DT WROM B */ 2381181381Sjkim { SST(0x55, 0x06, SS_RDEF, /* XXX TBD */ 2382181381Sjkim "Auxiliary memory out of space") }, 2383181381Sjkim /* F */ 2384181381Sjkim { SST(0x55, 0x07, SS_RDEF, /* XXX TBD */ 2385181381Sjkim "Quota error") }, 2386181381Sjkim /* T */ 2387181381Sjkim { SST(0x55, 0x08, SS_RDEF, /* XXX TBD */ 2388181381Sjkim "Maximum number of supplemental decryption keys exceeded") }, 2389181381Sjkim /* M */ 2390181381Sjkim { SST(0x55, 0x09, SS_RDEF, /* XXX TBD */ 2391181381Sjkim "Medium auxiliary memory not accessible") }, 2392181381Sjkim /* M */ 2393181381Sjkim { SST(0x55, 0x0A, SS_RDEF, /* XXX TBD */ 2394181381Sjkim "Data currently unavailable") }, 2395238595Smav /* DTLPWROMAEBKVF */ 2396238595Smav { SST(0x55, 0x0B, SS_RDEF, /* XXX TBD */ 2397238595Smav "Insufficient power for operation") }, 2398238595Smav /* DT P B */ 2399238595Smav { SST(0x55, 0x0C, SS_RDEF, /* XXX TBD */ 2400238596Smav "Insufficient resources to create ROD") }, 2401238595Smav /* DT P B */ 2402238595Smav { SST(0x55, 0x0D, SS_RDEF, /* XXX TBD */ 2403238596Smav "Insufficient resources to create ROD token") }, 2404181381Sjkim /* R */ 2405181381Sjkim { SST(0x57, 0x00, SS_RDEF, 2406181381Sjkim "Unable to recover table-of-contents") }, 2407181381Sjkim /* O */ 2408181381Sjkim { SST(0x58, 0x00, SS_RDEF, 2409181381Sjkim "Generation does not exist") }, 2410181381Sjkim /* O */ 2411181381Sjkim { SST(0x59, 0x00, SS_RDEF, 2412181381Sjkim "Updated block read") }, 2413181381Sjkim /* DTLPWRO BK */ 2414181381Sjkim { SST(0x5A, 0x00, SS_RDEF, 2415181381Sjkim "Operator request or state change input") }, 2416181381Sjkim /* DT WROM BK */ 2417181381Sjkim { SST(0x5A, 0x01, SS_RDEF, 2418181381Sjkim "Operator medium removal request") }, 2419181381Sjkim /* DT WRO A BK */ 2420181381Sjkim { SST(0x5A, 0x02, SS_RDEF, 2421181381Sjkim "Operator selected write protect") }, 2422181381Sjkim /* DT WRO A BK */ 2423181381Sjkim { SST(0x5A, 0x03, SS_RDEF, 2424181381Sjkim "Operator selected write permit") }, 2425181381Sjkim /* DTLPWROM K */ 2426181381Sjkim { SST(0x5B, 0x00, SS_RDEF, 2427181381Sjkim "Log exception") }, 2428181381Sjkim /* DTLPWROM K */ 2429181381Sjkim { SST(0x5B, 0x01, SS_RDEF, 2430181381Sjkim "Threshold condition met") }, 2431181381Sjkim /* DTLPWROM K */ 2432181381Sjkim { SST(0x5B, 0x02, SS_RDEF, 2433181381Sjkim "Log counter at maximum") }, 2434181381Sjkim /* DTLPWROM K */ 2435181381Sjkim { SST(0x5B, 0x03, SS_RDEF, 2436181381Sjkim "Log list codes exhausted") }, 2437181381Sjkim /* D O */ 2438181381Sjkim { SST(0x5C, 0x00, SS_RDEF, 2439181381Sjkim "RPL status change") }, 2440181381Sjkim /* D O */ 2441181381Sjkim { SST(0x5C, 0x01, SS_NOP | SSQ_PRINT_SENSE, 2442181381Sjkim "Spindles synchronized") }, 2443181381Sjkim /* D O */ 2444181381Sjkim { SST(0x5C, 0x02, SS_RDEF, 2445181381Sjkim "Spindles not synchronized") }, 2446181381Sjkim /* DTLPWROMAEBKVF */ 2447181381Sjkim { SST(0x5D, 0x00, SS_RDEF, 2448181381Sjkim "Failure prediction threshold exceeded") }, 2449181381Sjkim /* R B */ 2450181381Sjkim { SST(0x5D, 0x01, SS_RDEF, /* XXX TBD */ 2451181381Sjkim "Media failure prediction threshold exceeded") }, 2452181381Sjkim /* R */ 2453181381Sjkim { SST(0x5D, 0x02, SS_RDEF, /* XXX TBD */ 2454181381Sjkim "Logical unit failure prediction threshold exceeded") }, 2455181381Sjkim /* R */ 2456181381Sjkim { SST(0x5D, 0x03, SS_RDEF, /* XXX TBD */ 2457181381Sjkim "Spare area exhaustion prediction threshold exceeded") }, 2458181381Sjkim /* D B */ 2459181381Sjkim { SST(0x5D, 0x10, SS_RDEF, /* XXX TBD */ 2460181381Sjkim "Hardware impending failure general hard drive failure") }, 2461181381Sjkim /* D B */ 2462181381Sjkim { SST(0x5D, 0x11, SS_RDEF, /* XXX TBD */ 2463181381Sjkim "Hardware impending failure drive error rate too high") }, 2464181381Sjkim /* D B */ 2465181381Sjkim { SST(0x5D, 0x12, SS_RDEF, /* XXX TBD */ 2466181381Sjkim "Hardware impending failure data error rate too high") }, 2467181381Sjkim /* D B */ 2468181381Sjkim { SST(0x5D, 0x13, SS_RDEF, /* XXX TBD */ 2469181381Sjkim "Hardware impending failure seek error rate too high") }, 2470181381Sjkim /* D B */ 2471181381Sjkim { SST(0x5D, 0x14, SS_RDEF, /* XXX TBD */ 2472181381Sjkim "Hardware impending failure too many block reassigns") }, 2473181381Sjkim /* D B */ 2474181381Sjkim { SST(0x5D, 0x15, SS_RDEF, /* XXX TBD */ 2475181381Sjkim "Hardware impending failure access times too high") }, 2476181381Sjkim /* D B */ 2477181381Sjkim { SST(0x5D, 0x16, SS_RDEF, /* XXX TBD */ 2478181381Sjkim "Hardware impending failure start unit times too high") }, 2479181381Sjkim /* D B */ 2480181381Sjkim { SST(0x5D, 0x17, SS_RDEF, /* XXX TBD */ 2481181381Sjkim "Hardware impending failure channel parametrics") }, 2482181381Sjkim /* D B */ 2483181381Sjkim { SST(0x5D, 0x18, SS_RDEF, /* XXX TBD */ 2484181381Sjkim "Hardware impending failure controller detected") }, 2485181381Sjkim /* D B */ 2486181381Sjkim { SST(0x5D, 0x19, SS_RDEF, /* XXX TBD */ 2487181381Sjkim "Hardware impending failure throughput performance") }, 2488181381Sjkim /* D B */ 2489181381Sjkim { SST(0x5D, 0x1A, SS_RDEF, /* XXX TBD */ 2490181381Sjkim "Hardware impending failure seek time performance") }, 2491181381Sjkim /* D B */ 2492181381Sjkim { SST(0x5D, 0x1B, SS_RDEF, /* XXX TBD */ 2493181381Sjkim "Hardware impending failure spin-up retry count") }, 2494181381Sjkim /* D B */ 2495181381Sjkim { SST(0x5D, 0x1C, SS_RDEF, /* XXX TBD */ 2496181381Sjkim "Hardware impending failure drive calibration retry count") }, 2497181381Sjkim /* D B */ 2498181381Sjkim { SST(0x5D, 0x20, SS_RDEF, /* XXX TBD */ 2499181381Sjkim "Controller impending failure general hard drive failure") }, 2500181381Sjkim /* D B */ 2501181381Sjkim { SST(0x5D, 0x21, SS_RDEF, /* XXX TBD */ 2502181381Sjkim "Controller impending failure drive error rate too high") }, 2503181381Sjkim /* D B */ 2504181381Sjkim { SST(0x5D, 0x22, SS_RDEF, /* XXX TBD */ 2505181381Sjkim "Controller impending failure data error rate too high") }, 2506181381Sjkim /* D B */ 2507181381Sjkim { SST(0x5D, 0x23, SS_RDEF, /* XXX TBD */ 2508181381Sjkim "Controller impending failure seek error rate too high") }, 2509181381Sjkim /* D B */ 2510181381Sjkim { SST(0x5D, 0x24, SS_RDEF, /* XXX TBD */ 2511181381Sjkim "Controller impending failure too many block reassigns") }, 2512181381Sjkim /* D B */ 2513181381Sjkim { SST(0x5D, 0x25, SS_RDEF, /* XXX TBD */ 2514181381Sjkim "Controller impending failure access times too high") }, 2515181381Sjkim /* D B */ 2516181381Sjkim { SST(0x5D, 0x26, SS_RDEF, /* XXX TBD */ 2517181381Sjkim "Controller impending failure start unit times too high") }, 2518181381Sjkim /* D B */ 2519181381Sjkim { SST(0x5D, 0x27, SS_RDEF, /* XXX TBD */ 2520181381Sjkim "Controller impending failure channel parametrics") }, 2521181381Sjkim /* D B */ 2522181381Sjkim { SST(0x5D, 0x28, SS_RDEF, /* XXX TBD */ 2523181381Sjkim "Controller impending failure controller detected") }, 2524181381Sjkim /* D B */ 2525181381Sjkim { SST(0x5D, 0x29, SS_RDEF, /* XXX TBD */ 2526181381Sjkim "Controller impending failure throughput performance") }, 2527181381Sjkim /* D B */ 2528181381Sjkim { SST(0x5D, 0x2A, SS_RDEF, /* XXX TBD */ 2529181381Sjkim "Controller impending failure seek time performance") }, 2530181381Sjkim /* D B */ 2531181381Sjkim { SST(0x5D, 0x2B, SS_RDEF, /* XXX TBD */ 2532181381Sjkim "Controller impending failure spin-up retry count") }, 2533181381Sjkim /* D B */ 2534181381Sjkim { SST(0x5D, 0x2C, SS_RDEF, /* XXX TBD */ 2535181381Sjkim "Controller impending failure drive calibration retry count") }, 2536181381Sjkim /* D B */ 2537181381Sjkim { SST(0x5D, 0x30, SS_RDEF, /* XXX TBD */ 2538181381Sjkim "Data channel impending failure general hard drive failure") }, 2539181381Sjkim /* D B */ 2540181381Sjkim { SST(0x5D, 0x31, SS_RDEF, /* XXX TBD */ 2541181381Sjkim "Data channel impending failure drive error rate too high") }, 2542181381Sjkim /* D B */ 2543181381Sjkim { SST(0x5D, 0x32, SS_RDEF, /* XXX TBD */ 2544181381Sjkim "Data channel impending failure data error rate too high") }, 2545181381Sjkim /* D B */ 2546181381Sjkim { SST(0x5D, 0x33, SS_RDEF, /* XXX TBD */ 2547181381Sjkim "Data channel impending failure seek error rate too high") }, 2548181381Sjkim /* D B */ 2549181381Sjkim { SST(0x5D, 0x34, SS_RDEF, /* XXX TBD */ 2550181381Sjkim "Data channel impending failure too many block reassigns") }, 2551181381Sjkim /* D B */ 2552181381Sjkim { SST(0x5D, 0x35, SS_RDEF, /* XXX TBD */ 2553181381Sjkim "Data channel impending failure access times too high") }, 2554181381Sjkim /* D B */ 2555181381Sjkim { SST(0x5D, 0x36, SS_RDEF, /* XXX TBD */ 2556181381Sjkim "Data channel impending failure start unit times too high") }, 2557181381Sjkim /* D B */ 2558181381Sjkim { SST(0x5D, 0x37, SS_RDEF, /* XXX TBD */ 2559181381Sjkim "Data channel impending failure channel parametrics") }, 2560181381Sjkim /* D B */ 2561181381Sjkim { SST(0x5D, 0x38, SS_RDEF, /* XXX TBD */ 2562181381Sjkim "Data channel impending failure controller detected") }, 2563181381Sjkim /* D B */ 2564181381Sjkim { SST(0x5D, 0x39, SS_RDEF, /* XXX TBD */ 2565181381Sjkim "Data channel impending failure throughput performance") }, 2566181381Sjkim /* D B */ 2567181381Sjkim { SST(0x5D, 0x3A, SS_RDEF, /* XXX TBD */ 2568181381Sjkim "Data channel impending failure seek time performance") }, 2569181381Sjkim /* D B */ 2570181381Sjkim { SST(0x5D, 0x3B, SS_RDEF, /* XXX TBD */ 2571181381Sjkim "Data channel impending failure spin-up retry count") }, 2572181381Sjkim /* D B */ 2573181381Sjkim { SST(0x5D, 0x3C, SS_RDEF, /* XXX TBD */ 2574181381Sjkim "Data channel impending failure drive calibration retry count") }, 2575181381Sjkim /* D B */ 2576181381Sjkim { SST(0x5D, 0x40, SS_RDEF, /* XXX TBD */ 2577181381Sjkim "Servo impending failure general hard drive failure") }, 2578181381Sjkim /* D B */ 2579181381Sjkim { SST(0x5D, 0x41, SS_RDEF, /* XXX TBD */ 2580181381Sjkim "Servo impending failure drive error rate too high") }, 2581181381Sjkim /* D B */ 2582181381Sjkim { SST(0x5D, 0x42, SS_RDEF, /* XXX TBD */ 2583181381Sjkim "Servo impending failure data error rate too high") }, 2584181381Sjkim /* D B */ 2585181381Sjkim { SST(0x5D, 0x43, SS_RDEF, /* XXX TBD */ 2586181381Sjkim "Servo impending failure seek error rate too high") }, 2587181381Sjkim /* D B */ 2588181381Sjkim { SST(0x5D, 0x44, SS_RDEF, /* XXX TBD */ 2589181381Sjkim "Servo impending failure too many block reassigns") }, 2590181381Sjkim /* D B */ 2591181381Sjkim { SST(0x5D, 0x45, SS_RDEF, /* XXX TBD */ 2592181381Sjkim "Servo impending failure access times too high") }, 2593181381Sjkim /* D B */ 2594181381Sjkim { SST(0x5D, 0x46, SS_RDEF, /* XXX TBD */ 2595181381Sjkim "Servo impending failure start unit times too high") }, 2596181381Sjkim /* D B */ 2597181381Sjkim { SST(0x5D, 0x47, SS_RDEF, /* XXX TBD */ 2598181381Sjkim "Servo impending failure channel parametrics") }, 2599181381Sjkim /* D B */ 2600181381Sjkim { SST(0x5D, 0x48, SS_RDEF, /* XXX TBD */ 2601181381Sjkim "Servo impending failure controller detected") }, 2602181381Sjkim /* D B */ 2603181381Sjkim { SST(0x5D, 0x49, SS_RDEF, /* XXX TBD */ 2604181381Sjkim "Servo impending failure throughput performance") }, 2605181381Sjkim /* D B */ 2606181381Sjkim { SST(0x5D, 0x4A, SS_RDEF, /* XXX TBD */ 2607181381Sjkim "Servo impending failure seek time performance") }, 2608181381Sjkim /* D B */ 2609181381Sjkim { SST(0x5D, 0x4B, SS_RDEF, /* XXX TBD */ 2610181381Sjkim "Servo impending failure spin-up retry count") }, 2611181381Sjkim /* D B */ 2612181381Sjkim { SST(0x5D, 0x4C, SS_RDEF, /* XXX TBD */ 2613181381Sjkim "Servo impending failure drive calibration retry count") }, 2614181381Sjkim /* D B */ 2615181381Sjkim { SST(0x5D, 0x50, SS_RDEF, /* XXX TBD */ 2616181381Sjkim "Spindle impending failure general hard drive failure") }, 2617181381Sjkim /* D B */ 2618181381Sjkim { SST(0x5D, 0x51, SS_RDEF, /* XXX TBD */ 2619181381Sjkim "Spindle impending failure drive error rate too high") }, 2620181381Sjkim /* D B */ 2621181381Sjkim { SST(0x5D, 0x52, SS_RDEF, /* XXX TBD */ 2622181381Sjkim "Spindle impending failure data error rate too high") }, 2623181381Sjkim /* D B */ 2624181381Sjkim { SST(0x5D, 0x53, SS_RDEF, /* XXX TBD */ 2625181381Sjkim "Spindle impending failure seek error rate too high") }, 2626181381Sjkim /* D B */ 2627181381Sjkim { SST(0x5D, 0x54, SS_RDEF, /* XXX TBD */ 2628181381Sjkim "Spindle impending failure too many block reassigns") }, 2629181381Sjkim /* D B */ 2630181381Sjkim { SST(0x5D, 0x55, SS_RDEF, /* XXX TBD */ 2631181381Sjkim "Spindle impending failure access times too high") }, 2632181381Sjkim /* D B */ 2633181381Sjkim { SST(0x5D, 0x56, SS_RDEF, /* XXX TBD */ 2634181381Sjkim "Spindle impending failure start unit times too high") }, 2635181381Sjkim /* D B */ 2636181381Sjkim { SST(0x5D, 0x57, SS_RDEF, /* XXX TBD */ 2637181381Sjkim "Spindle impending failure channel parametrics") }, 2638181381Sjkim /* D B */ 2639181381Sjkim { SST(0x5D, 0x58, SS_RDEF, /* XXX TBD */ 2640181381Sjkim "Spindle impending failure controller detected") }, 2641181381Sjkim /* D B */ 2642181381Sjkim { SST(0x5D, 0x59, SS_RDEF, /* XXX TBD */ 2643181381Sjkim "Spindle impending failure throughput performance") }, 2644181381Sjkim /* D B */ 2645181381Sjkim { SST(0x5D, 0x5A, SS_RDEF, /* XXX TBD */ 2646181381Sjkim "Spindle impending failure seek time performance") }, 2647181381Sjkim /* D B */ 2648181381Sjkim { SST(0x5D, 0x5B, SS_RDEF, /* XXX TBD */ 2649181381Sjkim "Spindle impending failure spin-up retry count") }, 2650181381Sjkim /* D B */ 2651181381Sjkim { SST(0x5D, 0x5C, SS_RDEF, /* XXX TBD */ 2652181381Sjkim "Spindle impending failure drive calibration retry count") }, 2653181381Sjkim /* D B */ 2654181381Sjkim { SST(0x5D, 0x60, SS_RDEF, /* XXX TBD */ 2655181381Sjkim "Firmware impending failure general hard drive failure") }, 2656181381Sjkim /* D B */ 2657181381Sjkim { SST(0x5D, 0x61, SS_RDEF, /* XXX TBD */ 2658181381Sjkim "Firmware impending failure drive error rate too high") }, 2659181381Sjkim /* D B */ 2660181381Sjkim { SST(0x5D, 0x62, SS_RDEF, /* XXX TBD */ 2661181381Sjkim "Firmware impending failure data error rate too high") }, 2662181381Sjkim /* D B */ 2663181381Sjkim { SST(0x5D, 0x63, SS_RDEF, /* XXX TBD */ 2664181381Sjkim "Firmware impending failure seek error rate too high") }, 2665181381Sjkim /* D B */ 2666181381Sjkim { SST(0x5D, 0x64, SS_RDEF, /* XXX TBD */ 2667181381Sjkim "Firmware impending failure too many block reassigns") }, 2668181381Sjkim /* D B */ 2669181381Sjkim { SST(0x5D, 0x65, SS_RDEF, /* XXX TBD */ 2670181381Sjkim "Firmware impending failure access times too high") }, 2671181381Sjkim /* D B */ 2672181381Sjkim { SST(0x5D, 0x66, SS_RDEF, /* XXX TBD */ 2673181381Sjkim "Firmware impending failure start unit times too high") }, 2674181381Sjkim /* D B */ 2675181381Sjkim { SST(0x5D, 0x67, SS_RDEF, /* XXX TBD */ 2676181381Sjkim "Firmware impending failure channel parametrics") }, 2677181381Sjkim /* D B */ 2678181381Sjkim { SST(0x5D, 0x68, SS_RDEF, /* XXX TBD */ 2679181381Sjkim "Firmware impending failure controller detected") }, 2680181381Sjkim /* D B */ 2681181381Sjkim { SST(0x5D, 0x69, SS_RDEF, /* XXX TBD */ 2682181381Sjkim "Firmware impending failure throughput performance") }, 2683181381Sjkim /* D B */ 2684181381Sjkim { SST(0x5D, 0x6A, SS_RDEF, /* XXX TBD */ 2685181381Sjkim "Firmware impending failure seek time performance") }, 2686181381Sjkim /* D B */ 2687181381Sjkim { SST(0x5D, 0x6B, SS_RDEF, /* XXX TBD */ 2688181381Sjkim "Firmware impending failure spin-up retry count") }, 2689181381Sjkim /* D B */ 2690181381Sjkim { SST(0x5D, 0x6C, SS_RDEF, /* XXX TBD */ 2691181381Sjkim "Firmware impending failure drive calibration retry count") }, 2692181381Sjkim /* DTLPWROMAEBKVF */ 2693181381Sjkim { SST(0x5D, 0xFF, SS_RDEF, 2694181381Sjkim "Failure prediction threshold exceeded (false)") }, 2695181381Sjkim /* DTLPWRO A K */ 2696181381Sjkim { SST(0x5E, 0x00, SS_RDEF, 2697181381Sjkim "Low power condition on") }, 2698181381Sjkim /* DTLPWRO A K */ 2699181381Sjkim { SST(0x5E, 0x01, SS_RDEF, 2700181381Sjkim "Idle condition activated by timer") }, 2701181381Sjkim /* DTLPWRO A K */ 2702181381Sjkim { SST(0x5E, 0x02, SS_RDEF, 2703181381Sjkim "Standby condition activated by timer") }, 2704181381Sjkim /* DTLPWRO A K */ 2705181381Sjkim { SST(0x5E, 0x03, SS_RDEF, 2706181381Sjkim "Idle condition activated by command") }, 2707181381Sjkim /* DTLPWRO A K */ 2708181381Sjkim { SST(0x5E, 0x04, SS_RDEF, 2709181381Sjkim "Standby condition activated by command") }, 2710238595Smav /* DTLPWRO A K */ 2711238595Smav { SST(0x5E, 0x05, SS_RDEF, 2712238595Smav "Idle-B condition activated by timer") }, 2713238595Smav /* DTLPWRO A K */ 2714238595Smav { SST(0x5E, 0x06, SS_RDEF, 2715238595Smav "Idle-B condition activated by command") }, 2716238595Smav /* DTLPWRO A K */ 2717238595Smav { SST(0x5E, 0x07, SS_RDEF, 2718238595Smav "Idle-C condition activated by timer") }, 2719238595Smav /* DTLPWRO A K */ 2720238595Smav { SST(0x5E, 0x08, SS_RDEF, 2721238595Smav "Idle-C condition activated by command") }, 2722238595Smav /* DTLPWRO A K */ 2723238595Smav { SST(0x5E, 0x09, SS_RDEF, 2724238596Smav "Standby-Y condition activated by timer") }, 2725238595Smav /* DTLPWRO A K */ 2726238595Smav { SST(0x5E, 0x0A, SS_RDEF, 2727238595Smav "Standby-Y condition activated by command") }, 2728181381Sjkim /* B */ 2729181381Sjkim { SST(0x5E, 0x41, SS_RDEF, /* XXX TBD */ 2730181381Sjkim "Power state change to active") }, 2731181381Sjkim /* B */ 2732181381Sjkim { SST(0x5E, 0x42, SS_RDEF, /* XXX TBD */ 2733181381Sjkim "Power state change to idle") }, 2734181381Sjkim /* B */ 2735181381Sjkim { SST(0x5E, 0x43, SS_RDEF, /* XXX TBD */ 2736181381Sjkim "Power state change to standby") }, 2737181381Sjkim /* B */ 2738181381Sjkim { SST(0x5E, 0x45, SS_RDEF, /* XXX TBD */ 2739181381Sjkim "Power state change to sleep") }, 2740181381Sjkim /* BK */ 2741181381Sjkim { SST(0x5E, 0x47, SS_RDEF, /* XXX TBD */ 2742181381Sjkim "Power state change to device control") }, 2743181381Sjkim /* */ 2744181381Sjkim { SST(0x60, 0x00, SS_RDEF, 2745181381Sjkim "Lamp failure") }, 2746181381Sjkim /* */ 2747181381Sjkim { SST(0x61, 0x00, SS_RDEF, 2748181381Sjkim "Video acquisition error") }, 2749181381Sjkim /* */ 2750181381Sjkim { SST(0x61, 0x01, SS_RDEF, 2751181381Sjkim "Unable to acquire video") }, 2752181381Sjkim /* */ 2753181381Sjkim { SST(0x61, 0x02, SS_RDEF, 2754181381Sjkim "Out of focus") }, 2755181381Sjkim /* */ 2756181381Sjkim { SST(0x62, 0x00, SS_RDEF, 2757181381Sjkim "Scan head positioning error") }, 2758181381Sjkim /* R */ 2759181381Sjkim { SST(0x63, 0x00, SS_RDEF, 2760181381Sjkim "End of user area encountered on this track") }, 2761181381Sjkim /* R */ 2762181381Sjkim { SST(0x63, 0x01, SS_FATAL | ENOSPC, 2763181381Sjkim "Packet does not fit in available space") }, 2764181381Sjkim /* R */ 2765181381Sjkim { SST(0x64, 0x00, SS_FATAL | ENXIO, 2766181381Sjkim "Illegal mode for this track") }, 2767181381Sjkim /* R */ 2768181381Sjkim { SST(0x64, 0x01, SS_RDEF, 2769181381Sjkim "Invalid packet size") }, 2770181381Sjkim /* DTLPWROMAEBKVF */ 2771181381Sjkim { SST(0x65, 0x00, SS_RDEF, 2772181381Sjkim "Voltage fault") }, 2773181381Sjkim /* */ 2774181381Sjkim { SST(0x66, 0x00, SS_RDEF, 2775181381Sjkim "Automatic document feeder cover up") }, 2776181381Sjkim /* */ 2777181381Sjkim { SST(0x66, 0x01, SS_RDEF, 2778181381Sjkim "Automatic document feeder lift up") }, 2779181381Sjkim /* */ 2780181381Sjkim { SST(0x66, 0x02, SS_RDEF, 2781181381Sjkim "Document jam in automatic document feeder") }, 2782181381Sjkim /* */ 2783181381Sjkim { SST(0x66, 0x03, SS_RDEF, 2784181381Sjkim "Document miss feed automatic in document feeder") }, 2785181381Sjkim /* A */ 2786181381Sjkim { SST(0x67, 0x00, SS_RDEF, 2787181381Sjkim "Configuration failure") }, 2788181381Sjkim /* A */ 2789181381Sjkim { SST(0x67, 0x01, SS_RDEF, 2790181381Sjkim "Configuration of incapable logical units failed") }, 2791181381Sjkim /* A */ 2792181381Sjkim { SST(0x67, 0x02, SS_RDEF, 2793181381Sjkim "Add logical unit failed") }, 2794181381Sjkim /* A */ 2795181381Sjkim { SST(0x67, 0x03, SS_RDEF, 2796181381Sjkim "Modification of logical unit failed") }, 2797181381Sjkim /* A */ 2798181381Sjkim { SST(0x67, 0x04, SS_RDEF, 2799181381Sjkim "Exchange of logical unit failed") }, 2800181381Sjkim /* A */ 2801181381Sjkim { SST(0x67, 0x05, SS_RDEF, 2802181381Sjkim "Remove of logical unit failed") }, 2803181381Sjkim /* A */ 2804181381Sjkim { SST(0x67, 0x06, SS_RDEF, 2805181381Sjkim "Attachment of logical unit failed") }, 2806181381Sjkim /* A */ 2807181381Sjkim { SST(0x67, 0x07, SS_RDEF, 2808181381Sjkim "Creation of logical unit failed") }, 2809181381Sjkim /* A */ 2810181381Sjkim { SST(0x67, 0x08, SS_RDEF, /* XXX TBD */ 2811181381Sjkim "Assign failure occurred") }, 2812181381Sjkim /* A */ 2813181381Sjkim { SST(0x67, 0x09, SS_RDEF, /* XXX TBD */ 2814181381Sjkim "Multiply assigned logical unit") }, 2815181381Sjkim /* DTLPWROMAEBKVF */ 2816181381Sjkim { SST(0x67, 0x0A, SS_RDEF, /* XXX TBD */ 2817181381Sjkim "Set target port groups command failed") }, 2818181381Sjkim /* DT B */ 2819181381Sjkim { SST(0x67, 0x0B, SS_RDEF, /* XXX TBD */ 2820181381Sjkim "ATA device feature not enabled") }, 2821181381Sjkim /* A */ 2822181381Sjkim { SST(0x68, 0x00, SS_RDEF, 2823181381Sjkim "Logical unit not configured") }, 2824181381Sjkim /* A */ 2825181381Sjkim { SST(0x69, 0x00, SS_RDEF, 2826181381Sjkim "Data loss on logical unit") }, 2827181381Sjkim /* A */ 2828181381Sjkim { SST(0x69, 0x01, SS_RDEF, 2829181381Sjkim "Multiple logical unit failures") }, 2830181381Sjkim /* A */ 2831181381Sjkim { SST(0x69, 0x02, SS_RDEF, 2832181381Sjkim "Parity/data mismatch") }, 2833181381Sjkim /* A */ 2834181381Sjkim { SST(0x6A, 0x00, SS_RDEF, 2835181381Sjkim "Informational, refer to log") }, 2836181381Sjkim /* A */ 2837181381Sjkim { SST(0x6B, 0x00, SS_RDEF, 2838181381Sjkim "State change has occurred") }, 2839181381Sjkim /* A */ 2840181381Sjkim { SST(0x6B, 0x01, SS_RDEF, 2841181381Sjkim "Redundancy level got better") }, 2842181381Sjkim /* A */ 2843181381Sjkim { SST(0x6B, 0x02, SS_RDEF, 2844181381Sjkim "Redundancy level got worse") }, 2845181381Sjkim /* A */ 2846181381Sjkim { SST(0x6C, 0x00, SS_RDEF, 2847181381Sjkim "Rebuild failure occurred") }, 2848181381Sjkim /* A */ 2849181381Sjkim { SST(0x6D, 0x00, SS_RDEF, 2850181381Sjkim "Recalculate failure occurred") }, 2851181381Sjkim /* A */ 2852181381Sjkim { SST(0x6E, 0x00, SS_RDEF, 2853181381Sjkim "Command to logical unit failed") }, 2854181381Sjkim /* R */ 2855181381Sjkim { SST(0x6F, 0x00, SS_RDEF, /* XXX TBD */ 2856181381Sjkim "Copy protection key exchange failure - authentication failure") }, 2857181381Sjkim /* R */ 2858181381Sjkim { SST(0x6F, 0x01, SS_RDEF, /* XXX TBD */ 2859181381Sjkim "Copy protection key exchange failure - key not present") }, 2860181381Sjkim /* R */ 2861181381Sjkim { SST(0x6F, 0x02, SS_RDEF, /* XXX TBD */ 2862181381Sjkim "Copy protection key exchange failure - key not established") }, 2863181381Sjkim /* R */ 2864181381Sjkim { SST(0x6F, 0x03, SS_RDEF, /* XXX TBD */ 2865181381Sjkim "Read of scrambled sector without authentication") }, 2866181381Sjkim /* R */ 2867181381Sjkim { SST(0x6F, 0x04, SS_RDEF, /* XXX TBD */ 2868181381Sjkim "Media region code is mismatched to logical unit region") }, 2869181381Sjkim /* R */ 2870181381Sjkim { SST(0x6F, 0x05, SS_RDEF, /* XXX TBD */ 2871181381Sjkim "Drive region must be permanent/region reset count error") }, 2872181381Sjkim /* R */ 2873181381Sjkim { SST(0x6F, 0x06, SS_RDEF, /* XXX TBD */ 2874181381Sjkim "Insufficient block count for binding NONCE recording") }, 2875181381Sjkim /* R */ 2876181381Sjkim { SST(0x6F, 0x07, SS_RDEF, /* XXX TBD */ 2877181381Sjkim "Conflict in binding NONCE recording") }, 2878181381Sjkim /* T */ 2879181381Sjkim { SST(0x70, 0x00, SS_RDEF, 2880181381Sjkim "Decompression exception short: ASCQ = Algorithm ID") }, 2881181381Sjkim /* T */ 2882181381Sjkim { SST(0x70, 0xFF, SS_RDEF | SSQ_RANGE, 2883181381Sjkim NULL) }, /* Range 0x00 -> 0xFF */ 2884181381Sjkim /* T */ 2885181381Sjkim { SST(0x71, 0x00, SS_RDEF, 2886181381Sjkim "Decompression exception long: ASCQ = Algorithm ID") }, 2887181381Sjkim /* T */ 2888181381Sjkim { SST(0x71, 0xFF, SS_RDEF | SSQ_RANGE, 2889181381Sjkim NULL) }, /* Range 0x00 -> 0xFF */ 2890181381Sjkim /* R */ 2891181381Sjkim { SST(0x72, 0x00, SS_RDEF, 2892181381Sjkim "Session fixation error") }, 2893181381Sjkim /* R */ 2894181381Sjkim { SST(0x72, 0x01, SS_RDEF, 2895181381Sjkim "Session fixation error writing lead-in") }, 2896181381Sjkim /* R */ 2897181381Sjkim { SST(0x72, 0x02, SS_RDEF, 2898181381Sjkim "Session fixation error writing lead-out") }, 2899181381Sjkim /* R */ 2900181381Sjkim { SST(0x72, 0x03, SS_RDEF, 2901181381Sjkim "Session fixation error - incomplete track in session") }, 2902181381Sjkim /* R */ 2903181381Sjkim { SST(0x72, 0x04, SS_RDEF, 2904181381Sjkim "Empty or partially written reserved track") }, 2905181381Sjkim /* R */ 2906181381Sjkim { SST(0x72, 0x05, SS_RDEF, /* XXX TBD */ 2907181381Sjkim "No more track reservations allowed") }, 2908181381Sjkim /* R */ 2909181381Sjkim { SST(0x72, 0x06, SS_RDEF, /* XXX TBD */ 2910181381Sjkim "RMZ extension is not allowed") }, 2911181381Sjkim /* R */ 2912181381Sjkim { SST(0x72, 0x07, SS_RDEF, /* XXX TBD */ 2913181381Sjkim "No more test zone extensions are allowed") }, 2914181381Sjkim /* R */ 2915181381Sjkim { SST(0x73, 0x00, SS_RDEF, 2916181381Sjkim "CD control error") }, 2917181381Sjkim /* R */ 2918181381Sjkim { SST(0x73, 0x01, SS_RDEF, 2919181381Sjkim "Power calibration area almost full") }, 2920181381Sjkim /* R */ 2921181381Sjkim { SST(0x73, 0x02, SS_FATAL | ENOSPC, 2922181381Sjkim "Power calibration area is full") }, 2923181381Sjkim /* R */ 2924181381Sjkim { SST(0x73, 0x03, SS_RDEF, 2925181381Sjkim "Power calibration area error") }, 2926181381Sjkim /* R */ 2927181381Sjkim { SST(0x73, 0x04, SS_RDEF, 2928181381Sjkim "Program memory area update failure") }, 2929181381Sjkim /* R */ 2930181381Sjkim { SST(0x73, 0x05, SS_RDEF, 2931181381Sjkim "Program memory area is full") }, 2932181381Sjkim /* R */ 2933181381Sjkim { SST(0x73, 0x06, SS_RDEF, /* XXX TBD */ 2934181381Sjkim "RMA/PMA is almost full") }, 2935181381Sjkim /* R */ 2936181381Sjkim { SST(0x73, 0x10, SS_RDEF, /* XXX TBD */ 2937181381Sjkim "Current power calibration area almost full") }, 2938181381Sjkim /* R */ 2939181381Sjkim { SST(0x73, 0x11, SS_RDEF, /* XXX TBD */ 2940181381Sjkim "Current power calibration area is full") }, 2941181381Sjkim /* R */ 2942181381Sjkim { SST(0x73, 0x17, SS_RDEF, /* XXX TBD */ 2943181381Sjkim "RDZ is full") }, 2944181381Sjkim /* T */ 2945181381Sjkim { SST(0x74, 0x00, SS_RDEF, /* XXX TBD */ 2946181381Sjkim "Security error") }, 2947181381Sjkim /* T */ 2948181381Sjkim { SST(0x74, 0x01, SS_RDEF, /* XXX TBD */ 2949181381Sjkim "Unable to decrypt data") }, 2950181381Sjkim /* T */ 2951181381Sjkim { SST(0x74, 0x02, SS_RDEF, /* XXX TBD */ 2952181381Sjkim "Unencrypted data encountered while decrypting") }, 2953181381Sjkim /* T */ 2954181381Sjkim { SST(0x74, 0x03, SS_RDEF, /* XXX TBD */ 2955181381Sjkim "Incorrect data encryption key") }, 2956181381Sjkim /* T */ 2957181381Sjkim { SST(0x74, 0x04, SS_RDEF, /* XXX TBD */ 2958181381Sjkim "Cryptographic integrity validation failed") }, 2959181381Sjkim /* T */ 2960181381Sjkim { SST(0x74, 0x05, SS_RDEF, /* XXX TBD */ 2961181381Sjkim "Error decrypting data") }, 2962181381Sjkim /* T */ 2963181381Sjkim { SST(0x74, 0x06, SS_RDEF, /* XXX TBD */ 2964181381Sjkim "Unknown signature verification key") }, 2965181381Sjkim /* T */ 2966181381Sjkim { SST(0x74, 0x07, SS_RDEF, /* XXX TBD */ 2967181381Sjkim "Encryption parameters not useable") }, 2968181381Sjkim /* DT R M E VF */ 2969181381Sjkim { SST(0x74, 0x08, SS_RDEF, /* XXX TBD */ 2970181381Sjkim "Digital signature validation failure") }, 2971181381Sjkim /* T */ 2972181381Sjkim { SST(0x74, 0x09, SS_RDEF, /* XXX TBD */ 2973181381Sjkim "Encryption mode mismatch on read") }, 2974181381Sjkim /* T */ 2975181381Sjkim { SST(0x74, 0x0A, SS_RDEF, /* XXX TBD */ 2976181381Sjkim "Encrypted block not raw read enabled") }, 2977181381Sjkim /* T */ 2978181381Sjkim { SST(0x74, 0x0B, SS_RDEF, /* XXX TBD */ 2979181381Sjkim "Incorrect encryption parameters") }, 2980181381Sjkim /* DT R MAEBKV */ 2981181381Sjkim { SST(0x74, 0x0C, SS_RDEF, /* XXX TBD */ 2982181381Sjkim "Unable to decrypt parameter list") }, 2983181381Sjkim /* T */ 2984181381Sjkim { SST(0x74, 0x0D, SS_RDEF, /* XXX TBD */ 2985181381Sjkim "Encryption algorithm disabled") }, 2986181381Sjkim /* DT R MAEBKV */ 2987181381Sjkim { SST(0x74, 0x10, SS_RDEF, /* XXX TBD */ 2988181381Sjkim "SA creation parameter value invalid") }, 2989181381Sjkim /* DT R MAEBKV */ 2990181381Sjkim { SST(0x74, 0x11, SS_RDEF, /* XXX TBD */ 2991181381Sjkim "SA creation parameter value rejected") }, 2992181381Sjkim /* DT R MAEBKV */ 2993181381Sjkim { SST(0x74, 0x12, SS_RDEF, /* XXX TBD */ 2994181381Sjkim "Invalid SA usage") }, 2995181381Sjkim /* T */ 2996181381Sjkim { SST(0x74, 0x21, SS_RDEF, /* XXX TBD */ 2997181381Sjkim "Data encryption configuration prevented") }, 2998181381Sjkim /* DT R MAEBKV */ 2999181381Sjkim { SST(0x74, 0x30, SS_RDEF, /* XXX TBD */ 3000181381Sjkim "SA creation parameter not supported") }, 3001181381Sjkim /* DT R MAEBKV */ 3002181381Sjkim { SST(0x74, 0x40, SS_RDEF, /* XXX TBD */ 3003181381Sjkim "Authentication failed") }, 3004181381Sjkim /* V */ 3005181381Sjkim { SST(0x74, 0x61, SS_RDEF, /* XXX TBD */ 3006181381Sjkim "External data encryption key manager access error") }, 3007181381Sjkim /* V */ 3008181381Sjkim { SST(0x74, 0x62, SS_RDEF, /* XXX TBD */ 3009181381Sjkim "External data encryption key manager error") }, 3010181381Sjkim /* V */ 3011181381Sjkim { SST(0x74, 0x63, SS_RDEF, /* XXX TBD */ 3012181381Sjkim "External data encryption key not found") }, 3013181381Sjkim /* V */ 3014181381Sjkim { SST(0x74, 0x64, SS_RDEF, /* XXX TBD */ 3015181381Sjkim "External data encryption request not authorized") }, 3016181381Sjkim /* T */ 3017181381Sjkim { SST(0x74, 0x6E, SS_RDEF, /* XXX TBD */ 3018181381Sjkim "External data encryption control timeout") }, 3019181381Sjkim /* T */ 3020181381Sjkim { SST(0x74, 0x6F, SS_RDEF, /* XXX TBD */ 3021181381Sjkim "External data encryption control error") }, 3022181381Sjkim /* DT R M E V */ 3023181381Sjkim { SST(0x74, 0x71, SS_RDEF, /* XXX TBD */ 3024181381Sjkim "Logical unit access not authorized") }, 3025181381Sjkim /* D */ 3026181381Sjkim { SST(0x74, 0x79, SS_RDEF, /* XXX TBD */ 3027181381Sjkim "Security conflict in translated device") } 302839213Sgibbs}; 302939213Sgibbs 303074840Skenconst int asc_table_size = sizeof(asc_table)/sizeof(asc_table[0]); 303174840Sken 303274840Skenstruct asc_key 303339213Sgibbs{ 303474840Sken int asc; 303574840Sken int ascq; 303674840Sken}; 303774840Sken 303874840Skenstatic int 303974840Skenascentrycomp(const void *key, const void *member) 304074840Sken{ 304174840Sken int asc; 304274840Sken int ascq; 304374840Sken const struct asc_table_entry *table_entry; 304474840Sken 304574840Sken asc = ((const struct asc_key *)key)->asc; 304674840Sken ascq = ((const struct asc_key *)key)->ascq; 304774840Sken table_entry = (const struct asc_table_entry *)member; 304874840Sken 304974840Sken if (asc >= table_entry->asc) { 305074840Sken 305174840Sken if (asc > table_entry->asc) 305274840Sken return (1); 305374840Sken 305474840Sken if (ascq <= table_entry->ascq) { 305574840Sken /* Check for ranges */ 305674840Sken if (ascq == table_entry->ascq 305774840Sken || ((table_entry->action & SSQ_RANGE) != 0 305874840Sken && ascq >= (table_entry - 1)->ascq)) 305974840Sken return (0); 306074840Sken return (-1); 306174840Sken } 306274840Sken return (1); 306374840Sken } 306474840Sken return (-1); 306574840Sken} 306674840Sken 306774840Skenstatic int 306874840Skensenseentrycomp(const void *key, const void *member) 306974840Sken{ 307074840Sken int sense_key; 307174840Sken const struct sense_key_table_entry *table_entry; 307274840Sken 307374840Sken sense_key = *((const int *)key); 307474840Sken table_entry = (const struct sense_key_table_entry *)member; 307574840Sken 307674840Sken if (sense_key >= table_entry->sense_key) { 307774840Sken if (sense_key == table_entry->sense_key) 307874840Sken return (0); 307974840Sken return (1); 308074840Sken } 308174840Sken return (-1); 308274840Sken} 308374840Sken 308474840Skenstatic void 308574840Skenfetchtableentries(int sense_key, int asc, int ascq, 308674840Sken struct scsi_inquiry_data *inq_data, 308774840Sken const struct sense_key_table_entry **sense_entry, 308874840Sken const struct asc_table_entry **asc_entry) 308974840Sken{ 309039213Sgibbs caddr_t match; 309174840Sken const struct asc_table_entry *asc_tables[2]; 309274840Sken const struct sense_key_table_entry *sense_tables[2]; 309374840Sken struct asc_key asc_ascq; 309474840Sken size_t asc_tables_size[2]; 309574840Sken size_t sense_tables_size[2]; 309674840Sken int num_asc_tables; 309774840Sken int num_sense_tables; 309874840Sken int i; 309939213Sgibbs 310074840Sken /* Default to failure */ 310174840Sken *sense_entry = NULL; 310274840Sken *asc_entry = NULL; 310374840Sken match = NULL; 310474840Sken if (inq_data != NULL) 310574840Sken match = cam_quirkmatch((caddr_t)inq_data, 310674840Sken (caddr_t)sense_quirk_table, 310774840Sken sense_quirk_table_size, 310874840Sken sizeof(*sense_quirk_table), 310974840Sken scsi_inquiry_match); 311039213Sgibbs 311174840Sken if (match != NULL) { 311274840Sken struct scsi_sense_quirk_entry *quirk; 311339213Sgibbs 311474840Sken quirk = (struct scsi_sense_quirk_entry *)match; 311574840Sken asc_tables[0] = quirk->asc_info; 311674840Sken asc_tables_size[0] = quirk->num_ascs; 311774840Sken asc_tables[1] = asc_table; 311874840Sken asc_tables_size[1] = asc_table_size; 311974840Sken num_asc_tables = 2; 312074840Sken sense_tables[0] = quirk->sense_key_info; 312174840Sken sense_tables_size[0] = quirk->num_sense_keys; 312274840Sken sense_tables[1] = sense_key_table; 312374840Sken sense_tables_size[1] = sense_key_table_size; 312474840Sken num_sense_tables = 2; 312539213Sgibbs } else { 312674840Sken asc_tables[0] = asc_table; 312774840Sken asc_tables_size[0] = asc_table_size; 312874840Sken num_asc_tables = 1; 312974840Sken sense_tables[0] = sense_key_table; 313074840Sken sense_tables_size[0] = sense_key_table_size; 313174840Sken num_sense_tables = 1; 313239213Sgibbs } 313339213Sgibbs 313474840Sken asc_ascq.asc = asc; 313574840Sken asc_ascq.ascq = ascq; 313674840Sken for (i = 0; i < num_asc_tables; i++) { 313774840Sken void *found_entry; 313839213Sgibbs 313974840Sken found_entry = bsearch(&asc_ascq, asc_tables[i], 314074840Sken asc_tables_size[i], 314174840Sken sizeof(**asc_tables), 314274840Sken ascentrycomp); 314339213Sgibbs 314474840Sken if (found_entry) { 314574840Sken *asc_entry = (struct asc_table_entry *)found_entry; 314674840Sken break; 314739213Sgibbs } 314839213Sgibbs } 314939213Sgibbs 315074840Sken for (i = 0; i < num_sense_tables; i++) { 315174840Sken void *found_entry; 315239213Sgibbs 315374840Sken found_entry = bsearch(&sense_key, sense_tables[i], 315474840Sken sense_tables_size[i], 315574840Sken sizeof(**sense_tables), 315674840Sken senseentrycomp); 315739213Sgibbs 315874840Sken if (found_entry) { 315974840Sken *sense_entry = 316074840Sken (struct sense_key_table_entry *)found_entry; 316174840Sken break; 316274840Sken } 316374840Sken } 316439213Sgibbs} 316539213Sgibbs 316674840Skenvoid 316774840Skenscsi_sense_desc(int sense_key, int asc, int ascq, 316874840Sken struct scsi_inquiry_data *inq_data, 316974840Sken const char **sense_key_desc, const char **asc_desc) 317039213Sgibbs{ 317174840Sken const struct asc_table_entry *asc_entry; 317274840Sken const struct sense_key_table_entry *sense_entry; 317374840Sken 317474840Sken fetchtableentries(sense_key, asc, ascq, 317574840Sken inq_data, 317674840Sken &sense_entry, 317774840Sken &asc_entry); 317874840Sken 3179225950Sken if (sense_entry != NULL) 3180225950Sken *sense_key_desc = sense_entry->desc; 3181225950Sken else 3182225950Sken *sense_key_desc = "Invalid Sense Key"; 318374840Sken 318474840Sken if (asc_entry != NULL) 318574840Sken *asc_desc = asc_entry->desc; 318674840Sken else if (asc >= 0x80 && asc <= 0xff) 318774840Sken *asc_desc = "Vendor Specific ASC"; 318874840Sken else if (ascq >= 0x80 && ascq <= 0xff) 318974840Sken *asc_desc = "Vendor Specific ASCQ"; 319074840Sken else 319174840Sken *asc_desc = "Reserved ASC/ASCQ pair"; 319239213Sgibbs} 319339213Sgibbs 319439213Sgibbs/* 319574840Sken * Given sense and device type information, return the appropriate action. 319674840Sken * If we do not understand the specific error as identified by the ASC/ASCQ 319774840Sken * pair, fall back on the more generic actions derived from the sense key. 319839213Sgibbs */ 319939213Sgibbsscsi_sense_action 320074840Skenscsi_error_action(struct ccb_scsiio *csio, struct scsi_inquiry_data *inq_data, 320174840Sken u_int32_t sense_flags) 320239213Sgibbs{ 320374840Sken const struct asc_table_entry *asc_entry; 320474840Sken const struct sense_key_table_entry *sense_entry; 320574840Sken int error_code, sense_key, asc, ascq; 320674840Sken scsi_sense_action action; 320739213Sgibbs 3208237478Smav if (!scsi_extract_sense_ccb((union ccb *)csio, 3209237478Smav &error_code, &sense_key, &asc, &ascq)) { 3210237478Smav action = SS_RETRY | SSQ_DECREMENT_COUNT | SSQ_PRINT_SENSE | EIO; 3211237478Smav } else if ((error_code == SSD_DEFERRED_ERROR) 3212225950Sken || (error_code == SSD_DESC_DEFERRED_ERROR)) { 321374840Sken /* 321474840Sken * XXX dufault@FreeBSD.org 321574840Sken * This error doesn't relate to the command associated 321674840Sken * with this request sense. A deferred error is an error 321774840Sken * for a command that has already returned GOOD status 321874840Sken * (see SCSI2 8.2.14.2). 321974840Sken * 322074840Sken * By my reading of that section, it looks like the current 322174840Sken * command has been cancelled, we should now clean things up 322274840Sken * (hopefully recovering any lost data) and then retry the 322374840Sken * current command. There are two easy choices, both wrong: 322474840Sken * 322574840Sken * 1. Drop through (like we had been doing), thus treating 322674840Sken * this as if the error were for the current command and 322774840Sken * return and stop the current command. 322874840Sken * 322974840Sken * 2. Issue a retry (like I made it do) thus hopefully 323074840Sken * recovering the current transfer, and ignoring the 323174840Sken * fact that we've dropped a command. 323274840Sken * 323374840Sken * These should probably be handled in a device specific 323474840Sken * sense handler or punted back up to a user mode daemon 323574840Sken */ 323674840Sken action = SS_RETRY|SSQ_DECREMENT_COUNT|SSQ_PRINT_SENSE; 323739213Sgibbs } else { 323874840Sken fetchtableentries(sense_key, asc, ascq, 323974840Sken inq_data, 324074840Sken &sense_entry, 324174840Sken &asc_entry); 324239213Sgibbs 324374840Sken /* 324474840Sken * Override the 'No additional Sense' entry (0,0) 324574840Sken * with the error action of the sense key. 324674840Sken */ 324774840Sken if (asc_entry != NULL 324874840Sken && (asc != 0 || ascq != 0)) 324974840Sken action = asc_entry->action; 3250225950Sken else if (sense_entry != NULL) 3251225950Sken action = sense_entry->action; 325274840Sken else 3253225950Sken action = SS_RETRY|SSQ_DECREMENT_COUNT|SSQ_PRINT_SENSE; 325439213Sgibbs 325574840Sken if (sense_key == SSD_KEY_RECOVERED_ERROR) { 325674840Sken /* 325774840Sken * The action succeeded but the device wants 325874840Sken * the user to know that some recovery action 325974840Sken * was required. 326074840Sken */ 326174840Sken action &= ~(SS_MASK|SSQ_MASK|SS_ERRMASK); 326274840Sken action |= SS_NOP|SSQ_PRINT_SENSE; 326374840Sken } else if (sense_key == SSD_KEY_ILLEGAL_REQUEST) { 326474840Sken if ((sense_flags & SF_QUIET_IR) != 0) 326574840Sken action &= ~SSQ_PRINT_SENSE; 326674840Sken } else if (sense_key == SSD_KEY_UNIT_ATTENTION) { 326774840Sken if ((sense_flags & SF_RETRY_UA) != 0 326874840Sken && (action & SS_MASK) == SS_FAIL) { 326974840Sken action &= ~(SS_MASK|SSQ_MASK); 327074840Sken action |= SS_RETRY|SSQ_DECREMENT_COUNT| 327174840Sken SSQ_PRINT_SENSE; 327239213Sgibbs } 3273253322Smav action |= SSQ_UA; 327439213Sgibbs } 327539213Sgibbs } 3276245647Skan if ((action & SS_MASK) >= SS_START && 3277245647Skan (sense_flags & SF_NO_RECOVERY)) { 3278245647Skan action &= ~SS_MASK; 3279245647Skan action |= SS_FAIL; 3280245647Skan } else if ((action & SS_MASK) == SS_RETRY && 3281245647Skan (sense_flags & SF_NO_RETRY)) { 3282245647Skan action &= ~SS_MASK; 3283245647Skan action |= SS_FAIL; 3284245647Skan } 328574840Sken if ((sense_flags & SF_PRINT_ALWAYS) != 0) 328674840Sken action |= SSQ_PRINT_SENSE; 328774840Sken else if ((sense_flags & SF_NO_PRINT) != 0) 328874840Sken action &= ~SSQ_PRINT_SENSE; 328974840Sken 329074840Sken return (action); 329139213Sgibbs} 329239213Sgibbs 329339213Sgibbschar * 329440401Skenscsi_cdb_string(u_int8_t *cdb_ptr, char *cdb_string, size_t len) 329539213Sgibbs{ 329639213Sgibbs u_int8_t cdb_len; 329739213Sgibbs int i; 329839213Sgibbs 329939213Sgibbs if (cdb_ptr == NULL) 330039213Sgibbs return(""); 330139213Sgibbs 330239213Sgibbs /* Silence warnings */ 330339213Sgibbs cdb_len = 0; 330439213Sgibbs 330539213Sgibbs /* 330639213Sgibbs * This is taken from the SCSI-3 draft spec. 330739213Sgibbs * (T10/1157D revision 0.3) 330839213Sgibbs * The top 3 bits of an opcode are the group code. The next 5 bits 330939213Sgibbs * are the command code. 331039213Sgibbs * Group 0: six byte commands 331139213Sgibbs * Group 1: ten byte commands 331239213Sgibbs * Group 2: ten byte commands 331339213Sgibbs * Group 3: reserved 331439213Sgibbs * Group 4: sixteen byte commands 331539213Sgibbs * Group 5: twelve byte commands 331639213Sgibbs * Group 6: vendor specific 331739213Sgibbs * Group 7: vendor specific 331839213Sgibbs */ 331939213Sgibbs switch((*cdb_ptr >> 5) & 0x7) { 332039213Sgibbs case 0: 332139213Sgibbs cdb_len = 6; 332239213Sgibbs break; 332339213Sgibbs case 1: 332439213Sgibbs case 2: 332539213Sgibbs cdb_len = 10; 332639213Sgibbs break; 332739213Sgibbs case 3: 332839213Sgibbs case 6: 332939213Sgibbs case 7: 333039213Sgibbs /* in this case, just print out the opcode */ 333139213Sgibbs cdb_len = 1; 333239213Sgibbs break; 333339213Sgibbs case 4: 333439213Sgibbs cdb_len = 16; 333539213Sgibbs break; 333639213Sgibbs case 5: 333739213Sgibbs cdb_len = 12; 333839213Sgibbs break; 333939213Sgibbs } 334039213Sgibbs *cdb_string = '\0'; 334141514Sarchie for (i = 0; i < cdb_len; i++) 334241514Sarchie snprintf(cdb_string + strlen(cdb_string), 3343246146Ssmh len - strlen(cdb_string), "%02hhx ", cdb_ptr[i]); 334440401Sken 334539213Sgibbs return(cdb_string); 334639213Sgibbs} 334774840Sken 334874840Skenconst char * 334974840Skenscsi_status_string(struct ccb_scsiio *csio) 335074840Sken{ 335174840Sken switch(csio->scsi_status) { 335274840Sken case SCSI_STATUS_OK: 335374840Sken return("OK"); 335474840Sken case SCSI_STATUS_CHECK_COND: 335574840Sken return("Check Condition"); 335674840Sken case SCSI_STATUS_BUSY: 335774840Sken return("Busy"); 335874840Sken case SCSI_STATUS_INTERMED: 335974840Sken return("Intermediate"); 336074840Sken case SCSI_STATUS_INTERMED_COND_MET: 336174840Sken return("Intermediate-Condition Met"); 336274840Sken case SCSI_STATUS_RESERV_CONFLICT: 336374840Sken return("Reservation Conflict"); 336474840Sken case SCSI_STATUS_CMD_TERMINATED: 336574840Sken return("Command Terminated"); 336674840Sken case SCSI_STATUS_QUEUE_FULL: 336774840Sken return("Queue Full"); 336874840Sken case SCSI_STATUS_ACA_ACTIVE: 336974840Sken return("ACA Active"); 337074840Sken case SCSI_STATUS_TASK_ABORTED: 337174840Sken return("Task Aborted"); 337274840Sken default: { 337374840Sken static char unkstr[64]; 337474840Sken snprintf(unkstr, sizeof(unkstr), "Unknown %#x", 337574840Sken csio->scsi_status); 337674840Sken return(unkstr); 337774840Sken } 337874840Sken } 337974840Sken} 338074840Sken 338139213Sgibbs/* 338274840Sken * scsi_command_string() returns 0 for success and -1 for failure. 338339213Sgibbs */ 338455205Speter#ifdef _KERNEL 338574840Skenint 338674840Skenscsi_command_string(struct ccb_scsiio *csio, struct sbuf *sb) 338774840Sken#else /* !_KERNEL */ 338874840Skenint 338974840Skenscsi_command_string(struct cam_device *device, struct ccb_scsiio *csio, 339074840Sken struct sbuf *sb) 339174840Sken#endif /* _KERNEL/!_KERNEL */ 339239213Sgibbs{ 339374840Sken struct scsi_inquiry_data *inq_data; 339474840Sken char cdb_str[(SCSI_MAX_CDBLEN * 3) + 1]; 339574840Sken#ifdef _KERNEL 3396203108Smav struct ccb_getdev *cgd; 339774840Sken#endif /* _KERNEL */ 339839213Sgibbs 339974840Sken#ifdef _KERNEL 3400203108Smav if ((cgd = (struct ccb_getdev*)xpt_alloc_ccb_nowait()) == NULL) 3401203108Smav return(-1); 340239213Sgibbs /* 340339213Sgibbs * Get the device information. 340439213Sgibbs */ 3405203108Smav xpt_setup_ccb(&cgd->ccb_h, 340639213Sgibbs csio->ccb_h.path, 3407198382Smav CAM_PRIORITY_NORMAL); 3408203108Smav cgd->ccb_h.func_code = XPT_GDEV_TYPE; 3409203108Smav xpt_action((union ccb *)cgd); 341039213Sgibbs 341139213Sgibbs /* 341239213Sgibbs * If the device is unconfigured, just pretend that it is a hard 341339213Sgibbs * drive. scsi_op_desc() needs this. 341439213Sgibbs */ 3415203108Smav if (cgd->ccb_h.status == CAM_DEV_NOT_THERE) 3416203108Smav cgd->inq_data.device = T_DIRECT; 341739213Sgibbs 3418203108Smav inq_data = &cgd->inq_data; 341939213Sgibbs 342074840Sken#else /* !_KERNEL */ 342139213Sgibbs 342274840Sken inq_data = &device->inq_data; 342339213Sgibbs 342474840Sken#endif /* _KERNEL/!_KERNEL */ 342574840Sken 342674840Sken if ((csio->ccb_h.flags & CAM_CDB_POINTER) != 0) { 342774840Sken sbuf_printf(sb, "%s. CDB: %s", 342874840Sken scsi_op_desc(csio->cdb_io.cdb_ptr[0], inq_data), 342974840Sken scsi_cdb_string(csio->cdb_io.cdb_ptr, cdb_str, 343074840Sken sizeof(cdb_str))); 343139213Sgibbs } else { 343274840Sken sbuf_printf(sb, "%s. CDB: %s", 343374840Sken scsi_op_desc(csio->cdb_io.cdb_bytes[0], inq_data), 343474840Sken scsi_cdb_string(csio->cdb_io.cdb_bytes, cdb_str, 343574840Sken sizeof(cdb_str))); 343639213Sgibbs } 343739213Sgibbs 3438236689Sken#ifdef _KERNEL 3439236689Sken xpt_free_ccb((union ccb *)cgd); 3440236689Sken#endif 3441236689Sken 344274840Sken return(0); 344374840Sken} 344439213Sgibbs 3445225950Sken/* 3446225950Sken * Iterate over sense descriptors. Each descriptor is passed into iter_func(). 3447225950Sken * If iter_func() returns 0, list traversal continues. If iter_func() 3448225950Sken * returns non-zero, list traversal is stopped. 3449225950Sken */ 3450225950Skenvoid 3451225950Skenscsi_desc_iterate(struct scsi_sense_data_desc *sense, u_int sense_len, 3452225950Sken int (*iter_func)(struct scsi_sense_data_desc *sense, 3453225950Sken u_int, struct scsi_sense_desc_header *, 3454225950Sken void *), void *arg) 3455225950Sken{ 3456225950Sken int cur_pos; 3457225950Sken int desc_len; 345839213Sgibbs 3459225950Sken /* 3460225950Sken * First make sure the extra length field is present. 3461225950Sken */ 3462225950Sken if (SSD_DESC_IS_PRESENT(sense, sense_len, extra_len) == 0) 3463225950Sken return; 3464225950Sken 3465225950Sken /* 3466225950Sken * The length of data actually returned may be different than the 3467225950Sken * extra_len recorded in the sturcture. 3468225950Sken */ 3469225950Sken desc_len = sense_len -offsetof(struct scsi_sense_data_desc, sense_desc); 3470225950Sken 3471225950Sken /* 3472225950Sken * Limit this further by the extra length reported, and the maximum 3473225950Sken * allowed extra length. 3474225950Sken */ 3475225950Sken desc_len = MIN(desc_len, MIN(sense->extra_len, SSD_EXTRA_MAX)); 3476225950Sken 3477225950Sken /* 3478225950Sken * Subtract the size of the header from the descriptor length. 3479225950Sken * This is to ensure that we have at least the header left, so we 3480225950Sken * don't have to check that inside the loop. This can wind up 3481225950Sken * being a negative value. 3482225950Sken */ 3483225950Sken desc_len -= sizeof(struct scsi_sense_desc_header); 3484225950Sken 3485225950Sken for (cur_pos = 0; cur_pos < desc_len;) { 3486225950Sken struct scsi_sense_desc_header *header; 3487225950Sken 3488225950Sken header = (struct scsi_sense_desc_header *) 3489225950Sken &sense->sense_desc[cur_pos]; 3490225950Sken 3491225950Sken /* 3492225950Sken * Check to make sure we have the entire descriptor. We 3493225950Sken * don't call iter_func() unless we do. 3494225950Sken * 3495225950Sken * Note that although cur_pos is at the beginning of the 3496225950Sken * descriptor, desc_len already has the header length 3497225950Sken * subtracted. So the comparison of the length in the 3498225950Sken * header (which does not include the header itself) to 3499225950Sken * desc_len - cur_pos is correct. 3500225950Sken */ 3501225950Sken if (header->length > (desc_len - cur_pos)) 3502225950Sken break; 3503225950Sken 3504225950Sken if (iter_func(sense, sense_len, header, arg) != 0) 3505225950Sken break; 3506225950Sken 3507225950Sken cur_pos += sizeof(*header) + header->length; 3508225950Sken } 3509225950Sken} 3510225950Sken 3511225950Skenstruct scsi_find_desc_info { 3512225950Sken uint8_t desc_type; 3513225950Sken struct scsi_sense_desc_header *header; 3514225950Sken}; 3515225950Sken 3516225950Skenstatic int 3517225950Skenscsi_find_desc_func(struct scsi_sense_data_desc *sense, u_int sense_len, 3518225950Sken struct scsi_sense_desc_header *header, void *arg) 3519225950Sken{ 3520225950Sken struct scsi_find_desc_info *desc_info; 3521225950Sken 3522225950Sken desc_info = (struct scsi_find_desc_info *)arg; 3523225950Sken 3524225950Sken if (header->desc_type == desc_info->desc_type) { 3525225950Sken desc_info->header = header; 3526225950Sken 3527225950Sken /* We found the descriptor, tell the iterator to stop. */ 3528225950Sken return (1); 3529225950Sken } else 3530225950Sken return (0); 3531225950Sken} 3532225950Sken 353374840Sken/* 3534225950Sken * Given a descriptor type, return a pointer to it if it is in the sense 3535225950Sken * data and not truncated. Avoiding truncating sense data will simplify 3536225950Sken * things significantly for the caller. 3537225950Sken */ 3538225950Skenuint8_t * 3539225950Skenscsi_find_desc(struct scsi_sense_data_desc *sense, u_int sense_len, 3540225950Sken uint8_t desc_type) 3541225950Sken{ 3542225950Sken struct scsi_find_desc_info desc_info; 3543225950Sken 3544225950Sken desc_info.desc_type = desc_type; 3545225950Sken desc_info.header = NULL; 3546225950Sken 3547225950Sken scsi_desc_iterate(sense, sense_len, scsi_find_desc_func, &desc_info); 3548225950Sken 3549225950Sken return ((uint8_t *)desc_info.header); 3550225950Sken} 3551225950Sken 3552225950Sken/* 3553225950Sken * Fill in SCSI sense data with the specified parameters. This routine can 3554225950Sken * fill in either fixed or descriptor type sense data. 3555225950Sken */ 3556225950Skenvoid 3557225950Skenscsi_set_sense_data_va(struct scsi_sense_data *sense_data, 3558225950Sken scsi_sense_data_type sense_format, int current_error, 3559225950Sken int sense_key, int asc, int ascq, va_list ap) 3560225950Sken{ 3561225950Sken int descriptor_sense; 3562225950Sken scsi_sense_elem_type elem_type; 3563225950Sken 3564225950Sken /* 3565225950Sken * Determine whether to return fixed or descriptor format sense 3566225950Sken * data. If the user specifies SSD_TYPE_NONE for some reason, 3567225950Sken * they'll just get fixed sense data. 3568225950Sken */ 3569225950Sken if (sense_format == SSD_TYPE_DESC) 3570225950Sken descriptor_sense = 1; 3571225950Sken else 3572225950Sken descriptor_sense = 0; 3573225950Sken 3574225950Sken /* 3575225950Sken * Zero the sense data, so that we don't pass back any garbage data 3576225950Sken * to the user. 3577225950Sken */ 3578225950Sken memset(sense_data, 0, sizeof(*sense_data)); 3579225950Sken 3580225950Sken if (descriptor_sense != 0) { 3581225950Sken struct scsi_sense_data_desc *sense; 3582225950Sken 3583225950Sken sense = (struct scsi_sense_data_desc *)sense_data; 3584225950Sken /* 3585225950Sken * The descriptor sense format eliminates the use of the 3586225950Sken * valid bit. 3587225950Sken */ 3588225950Sken if (current_error != 0) 3589225950Sken sense->error_code = SSD_DESC_CURRENT_ERROR; 3590225950Sken else 3591225950Sken sense->error_code = SSD_DESC_DEFERRED_ERROR; 3592225950Sken sense->sense_key = sense_key; 3593225950Sken sense->add_sense_code = asc; 3594225950Sken sense->add_sense_code_qual = ascq; 3595225950Sken /* 3596225950Sken * Start off with no extra length, since the above data 3597225950Sken * fits in the standard descriptor sense information. 3598225950Sken */ 3599225950Sken sense->extra_len = 0; 3600225950Sken while ((elem_type = (scsi_sense_elem_type)va_arg(ap, 3601225950Sken scsi_sense_elem_type)) != SSD_ELEM_NONE) { 3602225950Sken int sense_len, len_to_copy; 3603225950Sken uint8_t *data; 3604225950Sken 3605225950Sken if (elem_type >= SSD_ELEM_MAX) { 3606225950Sken printf("%s: invalid sense type %d\n", __func__, 3607225950Sken elem_type); 3608225950Sken break; 3609225950Sken } 3610225950Sken 3611225950Sken sense_len = (int)va_arg(ap, int); 3612225950Sken len_to_copy = MIN(sense_len, SSD_EXTRA_MAX - 3613225950Sken sense->extra_len); 3614225950Sken data = (uint8_t *)va_arg(ap, uint8_t *); 3615225950Sken 3616225950Sken /* 3617225950Sken * We've already consumed the arguments for this one. 3618225950Sken */ 3619225950Sken if (elem_type == SSD_ELEM_SKIP) 3620225950Sken continue; 3621225950Sken 3622225950Sken switch (elem_type) { 3623225950Sken case SSD_ELEM_DESC: { 3624225950Sken 3625225950Sken /* 3626225950Sken * This is a straight descriptor. All we 3627225950Sken * need to do is copy the data in. 3628225950Sken */ 3629225950Sken bcopy(data, &sense->sense_desc[ 3630225950Sken sense->extra_len], len_to_copy); 3631225950Sken sense->extra_len += len_to_copy; 3632225950Sken break; 3633225950Sken } 3634225950Sken case SSD_ELEM_SKS: { 3635225950Sken struct scsi_sense_sks sks; 3636225950Sken 3637225950Sken bzero(&sks, sizeof(sks)); 3638225950Sken 3639225950Sken /* 3640225950Sken * This is already-formatted sense key 3641225950Sken * specific data. We just need to fill out 3642225950Sken * the header and copy everything in. 3643225950Sken */ 3644225950Sken bcopy(data, &sks.sense_key_spec, 3645225950Sken MIN(len_to_copy, 3646225950Sken sizeof(sks.sense_key_spec))); 3647225950Sken 3648225950Sken sks.desc_type = SSD_DESC_SKS; 3649225950Sken sks.length = sizeof(sks) - 3650225950Sken offsetof(struct scsi_sense_sks, reserved1); 3651225950Sken bcopy(&sks,&sense->sense_desc[sense->extra_len], 3652225950Sken sizeof(sks)); 3653225950Sken sense->extra_len += sizeof(sks); 3654225950Sken break; 3655225950Sken } 3656225950Sken case SSD_ELEM_INFO: 3657225950Sken case SSD_ELEM_COMMAND: { 3658225950Sken struct scsi_sense_command cmd; 3659225950Sken struct scsi_sense_info info; 3660225950Sken uint8_t *data_dest; 3661225950Sken uint8_t *descriptor; 3662225950Sken int descriptor_size, i, copy_len; 3663225950Sken 3664225950Sken bzero(&cmd, sizeof(cmd)); 3665225950Sken bzero(&info, sizeof(info)); 3666225950Sken 3667225950Sken /* 3668225950Sken * Command or information data. The 3669225950Sken * operate in pretty much the same way. 3670225950Sken */ 3671225950Sken if (elem_type == SSD_ELEM_COMMAND) { 3672225950Sken len_to_copy = MIN(len_to_copy, 3673225950Sken sizeof(cmd.command_info)); 3674225950Sken descriptor = (uint8_t *)&cmd; 3675225950Sken descriptor_size = sizeof(cmd); 3676225950Sken data_dest =(uint8_t *)&cmd.command_info; 3677225950Sken cmd.desc_type = SSD_DESC_COMMAND; 3678225950Sken cmd.length = sizeof(cmd) - 3679225950Sken offsetof(struct scsi_sense_command, 3680225950Sken reserved); 3681225950Sken } else { 3682225950Sken len_to_copy = MIN(len_to_copy, 3683225950Sken sizeof(info.info)); 3684225950Sken descriptor = (uint8_t *)&info; 3685225950Sken descriptor_size = sizeof(cmd); 3686225950Sken data_dest = (uint8_t *)&info.info; 3687225950Sken info.desc_type = SSD_DESC_INFO; 3688225950Sken info.byte2 = SSD_INFO_VALID; 3689225950Sken info.length = sizeof(info) - 3690225950Sken offsetof(struct scsi_sense_info, 3691225950Sken byte2); 3692225950Sken } 3693225950Sken 3694225950Sken /* 3695225950Sken * Copy this in reverse because the spec 3696225950Sken * (SPC-4) says that when 4 byte quantities 3697225950Sken * are stored in this 8 byte field, the 3698225950Sken * first four bytes shall be 0. 3699225950Sken * 3700225950Sken * So we fill the bytes in from the end, and 3701225950Sken * if we have less than 8 bytes to copy, 3702225950Sken * the initial, most significant bytes will 3703225950Sken * be 0. 3704225950Sken */ 3705225950Sken for (i = sense_len - 1; i >= 0 && 3706225950Sken len_to_copy > 0; i--, len_to_copy--) 3707225950Sken data_dest[len_to_copy - 1] = data[i]; 3708225950Sken 3709225950Sken /* 3710225950Sken * This calculation looks much like the 3711225950Sken * initial len_to_copy calculation, but 3712225950Sken * we have to do it again here, because 3713225950Sken * we're looking at a larger amount that 3714225950Sken * may or may not fit. It's not only the 3715225950Sken * data the user passed in, but also the 3716225950Sken * rest of the descriptor. 3717225950Sken */ 3718225950Sken copy_len = MIN(descriptor_size, 3719225950Sken SSD_EXTRA_MAX - sense->extra_len); 3720225950Sken bcopy(descriptor, &sense->sense_desc[ 3721225950Sken sense->extra_len], copy_len); 3722225950Sken sense->extra_len += copy_len; 3723225950Sken break; 3724225950Sken } 3725225950Sken case SSD_ELEM_FRU: { 3726225950Sken struct scsi_sense_fru fru; 3727225950Sken int copy_len; 3728225950Sken 3729225950Sken bzero(&fru, sizeof(fru)); 3730225950Sken 3731225950Sken fru.desc_type = SSD_DESC_FRU; 3732225950Sken fru.length = sizeof(fru) - 3733225950Sken offsetof(struct scsi_sense_fru, reserved); 3734225950Sken fru.fru = *data; 3735225950Sken 3736225950Sken copy_len = MIN(sizeof(fru), SSD_EXTRA_MAX - 3737225950Sken sense->extra_len); 3738225950Sken bcopy(&fru, &sense->sense_desc[ 3739225950Sken sense->extra_len], copy_len); 3740225950Sken sense->extra_len += copy_len; 3741225950Sken break; 3742225950Sken } 3743225950Sken case SSD_ELEM_STREAM: { 3744225950Sken struct scsi_sense_stream stream_sense; 3745225950Sken int copy_len; 3746225950Sken 3747225950Sken bzero(&stream_sense, sizeof(stream_sense)); 3748225950Sken stream_sense.desc_type = SSD_DESC_STREAM; 3749225950Sken stream_sense.length = sizeof(stream_sense) - 3750225950Sken offsetof(struct scsi_sense_stream, reserved); 3751225950Sken stream_sense.byte3 = *data; 3752225950Sken 3753225950Sken copy_len = MIN(sizeof(stream_sense), 3754225950Sken SSD_EXTRA_MAX - sense->extra_len); 3755225950Sken bcopy(&stream_sense, &sense->sense_desc[ 3756225950Sken sense->extra_len], copy_len); 3757225950Sken sense->extra_len += copy_len; 3758225950Sken break; 3759225950Sken } 3760225950Sken default: 3761225950Sken /* 3762225950Sken * We shouldn't get here, but if we do, do 3763225950Sken * nothing. We've already consumed the 3764225950Sken * arguments above. 3765225950Sken */ 3766225950Sken break; 3767225950Sken } 3768225950Sken } 3769225950Sken } else { 3770225950Sken struct scsi_sense_data_fixed *sense; 3771225950Sken 3772225950Sken sense = (struct scsi_sense_data_fixed *)sense_data; 3773225950Sken 3774225950Sken if (current_error != 0) 3775225950Sken sense->error_code = SSD_CURRENT_ERROR; 3776225950Sken else 3777225950Sken sense->error_code = SSD_DEFERRED_ERROR; 3778225950Sken 3779225950Sken sense->flags = sense_key; 3780225950Sken sense->add_sense_code = asc; 3781225950Sken sense->add_sense_code_qual = ascq; 3782225950Sken /* 3783225950Sken * We've set the ASC and ASCQ, so we have 6 more bytes of 3784225950Sken * valid data. If we wind up setting any of the other 3785225950Sken * fields, we'll bump this to 10 extra bytes. 3786225950Sken */ 3787225950Sken sense->extra_len = 6; 3788225950Sken 3789225950Sken while ((elem_type = (scsi_sense_elem_type)va_arg(ap, 3790225950Sken scsi_sense_elem_type)) != SSD_ELEM_NONE) { 3791225950Sken int sense_len, len_to_copy; 3792225950Sken uint8_t *data; 3793225950Sken 3794225950Sken if (elem_type >= SSD_ELEM_MAX) { 3795225950Sken printf("%s: invalid sense type %d\n", __func__, 3796225950Sken elem_type); 3797225950Sken break; 3798225950Sken } 3799225950Sken /* 3800225950Sken * If we get in here, just bump the extra length to 3801225950Sken * 10 bytes. That will encompass anything we're 3802225950Sken * going to set here. 3803225950Sken */ 3804225950Sken sense->extra_len = 10; 3805225950Sken sense_len = (int)va_arg(ap, int); 3806225950Sken len_to_copy = MIN(sense_len, SSD_EXTRA_MAX - 3807225950Sken sense->extra_len); 3808225950Sken data = (uint8_t *)va_arg(ap, uint8_t *); 3809225950Sken 3810225950Sken switch (elem_type) { 3811225950Sken case SSD_ELEM_SKS: 3812225950Sken /* 3813225950Sken * The user passed in pre-formatted sense 3814225950Sken * key specific data. 3815225950Sken */ 3816225950Sken bcopy(data, &sense->sense_key_spec[0], 3817225950Sken MIN(sizeof(sense->sense_key_spec), 3818225950Sken sense_len)); 3819225950Sken break; 3820225950Sken case SSD_ELEM_INFO: 3821225950Sken case SSD_ELEM_COMMAND: { 3822225950Sken uint8_t *data_dest; 3823225950Sken int i; 3824225950Sken 3825225950Sken if (elem_type == SSD_ELEM_COMMAND) 3826225950Sken data_dest = &sense->cmd_spec_info[0]; 3827225950Sken else { 3828225950Sken data_dest = &sense->info[0]; 3829225950Sken /* 3830225950Sken * We're setting the info field, so 3831225950Sken * set the valid bit. 3832225950Sken */ 3833225950Sken sense->error_code |= SSD_ERRCODE_VALID; 3834225950Sken } 3835225950Sken 3836225950Sken /* 3837225950Sken * Copy this in reverse so that if we have 3838225950Sken * less than 4 bytes to fill, the least 3839225950Sken * significant bytes will be at the end. 3840225950Sken * If we have more than 4 bytes, only the 3841225950Sken * least significant bytes will be included. 3842225950Sken */ 3843225950Sken for (i = sense_len - 1; i >= 0 && 3844225950Sken len_to_copy > 0; i--, len_to_copy--) 3845225950Sken data_dest[len_to_copy - 1] = data[i]; 3846225950Sken 3847225950Sken break; 3848225950Sken } 3849225950Sken case SSD_ELEM_FRU: 3850225950Sken sense->fru = *data; 3851225950Sken break; 3852225950Sken case SSD_ELEM_STREAM: 3853225950Sken sense->flags |= *data; 3854225950Sken break; 3855225950Sken case SSD_ELEM_DESC: 3856225950Sken default: 3857225950Sken 3858225950Sken /* 3859225950Sken * If the user passes in descriptor sense, 3860225950Sken * we can't handle that in fixed format. 3861225950Sken * So just skip it, and any unknown argument 3862225950Sken * types. 3863225950Sken */ 3864225950Sken break; 3865225950Sken } 3866225950Sken } 3867225950Sken } 3868225950Sken} 3869225950Sken 3870225950Skenvoid 3871225950Skenscsi_set_sense_data(struct scsi_sense_data *sense_data, 3872225950Sken scsi_sense_data_type sense_format, int current_error, 3873225950Sken int sense_key, int asc, int ascq, ...) 3874225950Sken{ 3875225950Sken va_list ap; 3876225950Sken 3877225950Sken va_start(ap, ascq); 3878225950Sken scsi_set_sense_data_va(sense_data, sense_format, current_error, 3879225950Sken sense_key, asc, ascq, ap); 3880225950Sken va_end(ap); 3881225950Sken} 3882225950Sken 3883225950Sken/* 3884225950Sken * Get sense information for three similar sense data types. 3885225950Sken */ 3886225950Skenint 3887225950Skenscsi_get_sense_info(struct scsi_sense_data *sense_data, u_int sense_len, 3888225950Sken uint8_t info_type, uint64_t *info, int64_t *signed_info) 3889225950Sken{ 3890225950Sken scsi_sense_data_type sense_type; 3891225950Sken 3892225950Sken if (sense_len == 0) 3893225950Sken goto bailout; 3894225950Sken 3895225950Sken sense_type = scsi_sense_type(sense_data); 3896225950Sken 3897225950Sken switch (sense_type) { 3898225950Sken case SSD_TYPE_DESC: { 3899225950Sken struct scsi_sense_data_desc *sense; 3900225950Sken uint8_t *desc; 3901225950Sken 3902225950Sken sense = (struct scsi_sense_data_desc *)sense_data; 3903225950Sken 3904225950Sken desc = scsi_find_desc(sense, sense_len, info_type); 3905225950Sken if (desc == NULL) 3906225950Sken goto bailout; 3907225950Sken 3908225950Sken switch (info_type) { 3909225950Sken case SSD_DESC_INFO: { 3910225950Sken struct scsi_sense_info *info_desc; 3911225950Sken 3912225950Sken info_desc = (struct scsi_sense_info *)desc; 3913225950Sken *info = scsi_8btou64(info_desc->info); 3914225950Sken if (signed_info != NULL) 3915225950Sken *signed_info = *info; 3916225950Sken break; 3917225950Sken } 3918225950Sken case SSD_DESC_COMMAND: { 3919225950Sken struct scsi_sense_command *cmd_desc; 3920225950Sken 3921225950Sken cmd_desc = (struct scsi_sense_command *)desc; 3922225950Sken 3923225950Sken *info = scsi_8btou64(cmd_desc->command_info); 3924225950Sken if (signed_info != NULL) 3925225950Sken *signed_info = *info; 3926225950Sken break; 3927225950Sken } 3928225950Sken case SSD_DESC_FRU: { 3929225950Sken struct scsi_sense_fru *fru_desc; 3930225950Sken 3931225950Sken fru_desc = (struct scsi_sense_fru *)desc; 3932225950Sken 3933225950Sken *info = fru_desc->fru; 3934225950Sken if (signed_info != NULL) 3935225950Sken *signed_info = (int8_t)fru_desc->fru; 3936225950Sken break; 3937225950Sken } 3938225950Sken default: 3939225950Sken goto bailout; 3940225950Sken break; 3941225950Sken } 3942225950Sken break; 3943225950Sken } 3944225950Sken case SSD_TYPE_FIXED: { 3945225950Sken struct scsi_sense_data_fixed *sense; 3946225950Sken 3947225950Sken sense = (struct scsi_sense_data_fixed *)sense_data; 3948225950Sken 3949225950Sken switch (info_type) { 3950225950Sken case SSD_DESC_INFO: { 3951225950Sken uint32_t info_val; 3952225950Sken 3953225950Sken if ((sense->error_code & SSD_ERRCODE_VALID) == 0) 3954225950Sken goto bailout; 3955225950Sken 3956225950Sken if (SSD_FIXED_IS_PRESENT(sense, sense_len, info) == 0) 3957225950Sken goto bailout; 3958225950Sken 3959225950Sken info_val = scsi_4btoul(sense->info); 3960225950Sken 3961225950Sken *info = info_val; 3962225950Sken if (signed_info != NULL) 3963225950Sken *signed_info = (int32_t)info_val; 3964225950Sken break; 3965225950Sken } 3966225950Sken case SSD_DESC_COMMAND: { 3967225950Sken uint32_t cmd_val; 3968225950Sken 3969225950Sken if ((SSD_FIXED_IS_PRESENT(sense, sense_len, 3970225950Sken cmd_spec_info) == 0) 3971225950Sken || (SSD_FIXED_IS_FILLED(sense, cmd_spec_info) == 0)) 3972225950Sken goto bailout; 3973225950Sken 3974225950Sken cmd_val = scsi_4btoul(sense->cmd_spec_info); 3975225950Sken if (cmd_val == 0) 3976225950Sken goto bailout; 3977225950Sken 3978225950Sken *info = cmd_val; 3979225950Sken if (signed_info != NULL) 3980225950Sken *signed_info = (int32_t)cmd_val; 3981225950Sken break; 3982225950Sken } 3983225950Sken case SSD_DESC_FRU: 3984225950Sken if ((SSD_FIXED_IS_PRESENT(sense, sense_len, fru) == 0) 3985225950Sken || (SSD_FIXED_IS_FILLED(sense, fru) == 0)) 3986225950Sken goto bailout; 3987225950Sken 3988225950Sken if (sense->fru == 0) 3989225950Sken goto bailout; 3990225950Sken 3991225950Sken *info = sense->fru; 3992225950Sken if (signed_info != NULL) 3993225950Sken *signed_info = (int8_t)sense->fru; 3994225950Sken break; 3995225950Sken default: 3996225950Sken goto bailout; 3997225950Sken break; 3998225950Sken } 3999225950Sken break; 4000225950Sken } 4001225950Sken default: 4002225950Sken goto bailout; 4003225950Sken break; 4004225950Sken } 4005225950Sken 4006225950Sken return (0); 4007225950Skenbailout: 4008225950Sken return (1); 4009225950Sken} 4010225950Sken 4011225950Skenint 4012225950Skenscsi_get_sks(struct scsi_sense_data *sense_data, u_int sense_len, uint8_t *sks) 4013225950Sken{ 4014225950Sken scsi_sense_data_type sense_type; 4015225950Sken 4016225950Sken if (sense_len == 0) 4017225950Sken goto bailout; 4018225950Sken 4019225950Sken sense_type = scsi_sense_type(sense_data); 4020225950Sken 4021225950Sken switch (sense_type) { 4022225950Sken case SSD_TYPE_DESC: { 4023225950Sken struct scsi_sense_data_desc *sense; 4024225950Sken struct scsi_sense_sks *desc; 4025225950Sken 4026225950Sken sense = (struct scsi_sense_data_desc *)sense_data; 4027225950Sken 4028225950Sken desc = (struct scsi_sense_sks *)scsi_find_desc(sense, sense_len, 4029225950Sken SSD_DESC_SKS); 4030225950Sken if (desc == NULL) 4031225950Sken goto bailout; 4032225950Sken 4033225950Sken /* 4034225950Sken * No need to check the SKS valid bit for descriptor sense. 4035225950Sken * If the descriptor is present, it is valid. 4036225950Sken */ 4037225950Sken bcopy(desc->sense_key_spec, sks, sizeof(desc->sense_key_spec)); 4038225950Sken break; 4039225950Sken } 4040225950Sken case SSD_TYPE_FIXED: { 4041225950Sken struct scsi_sense_data_fixed *sense; 4042225950Sken 4043225950Sken sense = (struct scsi_sense_data_fixed *)sense_data; 4044225950Sken 4045225950Sken if ((SSD_FIXED_IS_PRESENT(sense, sense_len, sense_key_spec)== 0) 4046225950Sken || (SSD_FIXED_IS_FILLED(sense, sense_key_spec) == 0)) 4047225950Sken goto bailout; 4048225950Sken 4049225950Sken if ((sense->sense_key_spec[0] & SSD_SCS_VALID) == 0) 4050225950Sken goto bailout; 4051225950Sken 4052225950Sken bcopy(sense->sense_key_spec, sks,sizeof(sense->sense_key_spec)); 4053225950Sken break; 4054225950Sken } 4055225950Sken default: 4056225950Sken goto bailout; 4057225950Sken break; 4058225950Sken } 4059225950Sken return (0); 4060225950Skenbailout: 4061225950Sken return (1); 4062225950Sken} 4063225950Sken 4064225950Sken/* 4065225950Sken * Provide a common interface for fixed and descriptor sense to detect 4066225950Sken * whether we have block-specific sense information. It is clear by the 4067225950Sken * presence of the block descriptor in descriptor mode, but we have to 4068225950Sken * infer from the inquiry data and ILI bit in fixed mode. 4069225950Sken */ 4070225950Skenint 4071225950Skenscsi_get_block_info(struct scsi_sense_data *sense_data, u_int sense_len, 4072225950Sken struct scsi_inquiry_data *inq_data, uint8_t *block_bits) 4073225950Sken{ 4074225950Sken scsi_sense_data_type sense_type; 4075225950Sken 4076225950Sken if (inq_data != NULL) { 4077225950Sken switch (SID_TYPE(inq_data)) { 4078225950Sken case T_DIRECT: 4079225950Sken case T_RBC: 4080225950Sken break; 4081225950Sken default: 4082225950Sken goto bailout; 4083225950Sken break; 4084225950Sken } 4085225950Sken } 4086225950Sken 4087225950Sken sense_type = scsi_sense_type(sense_data); 4088225950Sken 4089225950Sken switch (sense_type) { 4090225950Sken case SSD_TYPE_DESC: { 4091225950Sken struct scsi_sense_data_desc *sense; 4092225950Sken struct scsi_sense_block *block; 4093225950Sken 4094225950Sken sense = (struct scsi_sense_data_desc *)sense_data; 4095225950Sken 4096225950Sken block = (struct scsi_sense_block *)scsi_find_desc(sense, 4097225950Sken sense_len, SSD_DESC_BLOCK); 4098225950Sken if (block == NULL) 4099225950Sken goto bailout; 4100225950Sken 4101225950Sken *block_bits = block->byte3; 4102225950Sken break; 4103225950Sken } 4104225950Sken case SSD_TYPE_FIXED: { 4105225950Sken struct scsi_sense_data_fixed *sense; 4106225950Sken 4107225950Sken sense = (struct scsi_sense_data_fixed *)sense_data; 4108225950Sken 4109225950Sken if (SSD_FIXED_IS_PRESENT(sense, sense_len, flags) == 0) 4110225950Sken goto bailout; 4111225950Sken 4112225950Sken if ((sense->flags & SSD_ILI) == 0) 4113225950Sken goto bailout; 4114225950Sken 4115225950Sken *block_bits = sense->flags & SSD_ILI; 4116225950Sken break; 4117225950Sken } 4118225950Sken default: 4119225950Sken goto bailout; 4120225950Sken break; 4121225950Sken } 4122225950Sken return (0); 4123225950Skenbailout: 4124225950Sken return (1); 4125225950Sken} 4126225950Sken 4127225950Skenint 4128225950Skenscsi_get_stream_info(struct scsi_sense_data *sense_data, u_int sense_len, 4129225950Sken struct scsi_inquiry_data *inq_data, uint8_t *stream_bits) 4130225950Sken{ 4131225950Sken scsi_sense_data_type sense_type; 4132225950Sken 4133225950Sken if (inq_data != NULL) { 4134225950Sken switch (SID_TYPE(inq_data)) { 4135225950Sken case T_SEQUENTIAL: 4136225950Sken break; 4137225950Sken default: 4138225950Sken goto bailout; 4139225950Sken break; 4140225950Sken } 4141225950Sken } 4142225950Sken 4143225950Sken sense_type = scsi_sense_type(sense_data); 4144225950Sken 4145225950Sken switch (sense_type) { 4146225950Sken case SSD_TYPE_DESC: { 4147225950Sken struct scsi_sense_data_desc *sense; 4148225950Sken struct scsi_sense_stream *stream; 4149225950Sken 4150225950Sken sense = (struct scsi_sense_data_desc *)sense_data; 4151225950Sken 4152225950Sken stream = (struct scsi_sense_stream *)scsi_find_desc(sense, 4153225950Sken sense_len, SSD_DESC_STREAM); 4154225950Sken if (stream == NULL) 4155225950Sken goto bailout; 4156225950Sken 4157225950Sken *stream_bits = stream->byte3; 4158225950Sken break; 4159225950Sken } 4160225950Sken case SSD_TYPE_FIXED: { 4161225950Sken struct scsi_sense_data_fixed *sense; 4162225950Sken 4163225950Sken sense = (struct scsi_sense_data_fixed *)sense_data; 4164225950Sken 4165225950Sken if (SSD_FIXED_IS_PRESENT(sense, sense_len, flags) == 0) 4166225950Sken goto bailout; 4167225950Sken 4168225950Sken if ((sense->flags & (SSD_ILI|SSD_EOM|SSD_FILEMARK)) == 0) 4169225950Sken goto bailout; 4170225950Sken 4171225950Sken *stream_bits = sense->flags & (SSD_ILI|SSD_EOM|SSD_FILEMARK); 4172225950Sken break; 4173225950Sken } 4174225950Sken default: 4175225950Sken goto bailout; 4176225950Sken break; 4177225950Sken } 4178225950Sken return (0); 4179225950Skenbailout: 4180225950Sken return (1); 4181225950Sken} 4182225950Sken 4183225950Skenvoid 4184225950Skenscsi_info_sbuf(struct sbuf *sb, uint8_t *cdb, int cdb_len, 4185225950Sken struct scsi_inquiry_data *inq_data, uint64_t info) 4186225950Sken{ 4187225950Sken sbuf_printf(sb, "Info: %#jx", info); 4188225950Sken} 4189225950Sken 4190225950Skenvoid 4191225950Skenscsi_command_sbuf(struct sbuf *sb, uint8_t *cdb, int cdb_len, 4192225950Sken struct scsi_inquiry_data *inq_data, uint64_t csi) 4193225950Sken{ 4194225950Sken sbuf_printf(sb, "Command Specific Info: %#jx", csi); 4195225950Sken} 4196225950Sken 4197225950Sken 4198225950Skenvoid 4199225950Skenscsi_progress_sbuf(struct sbuf *sb, uint16_t progress) 4200225950Sken{ 4201225950Sken sbuf_printf(sb, "Progress: %d%% (%d/%d) complete", 4202225950Sken (progress * 100) / SSD_SKS_PROGRESS_DENOM, 4203225950Sken progress, SSD_SKS_PROGRESS_DENOM); 4204225950Sken} 4205225950Sken 4206225950Sken/* 4207225950Sken * Returns 1 for failure (i.e. SKS isn't valid) and 0 for success. 4208225950Sken */ 4209225950Skenint 4210225950Skenscsi_sks_sbuf(struct sbuf *sb, int sense_key, uint8_t *sks) 4211225950Sken{ 4212225950Sken if ((sks[0] & SSD_SKS_VALID) == 0) 4213225950Sken return (1); 4214225950Sken 4215225950Sken switch (sense_key) { 4216225950Sken case SSD_KEY_ILLEGAL_REQUEST: { 4217225950Sken struct scsi_sense_sks_field *field; 4218225950Sken int bad_command; 4219225950Sken char tmpstr[40]; 4220225950Sken 4221225950Sken /*Field Pointer*/ 4222225950Sken field = (struct scsi_sense_sks_field *)sks; 4223225950Sken 4224225950Sken if (field->byte0 & SSD_SKS_FIELD_CMD) 4225225950Sken bad_command = 1; 4226225950Sken else 4227225950Sken bad_command = 0; 4228225950Sken 4229225950Sken tmpstr[0] = '\0'; 4230225950Sken 4231225950Sken /* Bit pointer is valid */ 4232225950Sken if (field->byte0 & SSD_SKS_BPV) 4233225950Sken snprintf(tmpstr, sizeof(tmpstr), "bit %d ", 4234225950Sken field->byte0 & SSD_SKS_BIT_VALUE); 4235225950Sken 4236225950Sken sbuf_printf(sb, "%s byte %d %sis invalid", 4237225950Sken bad_command ? "Command" : "Data", 4238225950Sken scsi_2btoul(field->field), tmpstr); 4239225950Sken break; 4240225950Sken } 4241225950Sken case SSD_KEY_UNIT_ATTENTION: { 4242225950Sken struct scsi_sense_sks_overflow *overflow; 4243225950Sken 4244225950Sken overflow = (struct scsi_sense_sks_overflow *)sks; 4245225950Sken 4246225950Sken /*UA Condition Queue Overflow*/ 4247225950Sken sbuf_printf(sb, "Unit Attention Condition Queue %s", 4248225950Sken (overflow->byte0 & SSD_SKS_OVERFLOW_SET) ? 4249225950Sken "Overflowed" : "Did Not Overflow??"); 4250225950Sken break; 4251225950Sken } 4252225950Sken case SSD_KEY_RECOVERED_ERROR: 4253225950Sken case SSD_KEY_HARDWARE_ERROR: 4254225950Sken case SSD_KEY_MEDIUM_ERROR: { 4255225950Sken struct scsi_sense_sks_retry *retry; 4256225950Sken 4257225950Sken /*Actual Retry Count*/ 4258225950Sken retry = (struct scsi_sense_sks_retry *)sks; 4259225950Sken 4260225950Sken sbuf_printf(sb, "Actual Retry Count: %d", 4261225950Sken scsi_2btoul(retry->actual_retry_count)); 4262225950Sken break; 4263225950Sken } 4264225950Sken case SSD_KEY_NO_SENSE: 4265225950Sken case SSD_KEY_NOT_READY: { 4266225950Sken struct scsi_sense_sks_progress *progress; 4267225950Sken int progress_val; 4268225950Sken 4269225950Sken /*Progress Indication*/ 4270225950Sken progress = (struct scsi_sense_sks_progress *)sks; 4271225950Sken progress_val = scsi_2btoul(progress->progress); 4272225950Sken 4273225950Sken scsi_progress_sbuf(sb, progress_val); 4274225950Sken break; 4275225950Sken } 4276225950Sken case SSD_KEY_COPY_ABORTED: { 4277225950Sken struct scsi_sense_sks_segment *segment; 4278225950Sken char tmpstr[40]; 4279225950Sken 4280225950Sken /*Segment Pointer*/ 4281225950Sken segment = (struct scsi_sense_sks_segment *)sks; 4282225950Sken 4283225950Sken tmpstr[0] = '\0'; 4284225950Sken 4285225950Sken if (segment->byte0 & SSD_SKS_SEGMENT_BPV) 4286225950Sken snprintf(tmpstr, sizeof(tmpstr), "bit %d ", 4287225950Sken segment->byte0 & SSD_SKS_SEGMENT_BITPTR); 4288225950Sken 4289225950Sken sbuf_printf(sb, "%s byte %d %sis invalid", (segment->byte0 & 4290225950Sken SSD_SKS_SEGMENT_SD) ? "Segment" : "Data", 4291225950Sken scsi_2btoul(segment->field), tmpstr); 4292225950Sken break; 4293225950Sken } 4294225950Sken default: 4295225950Sken sbuf_printf(sb, "Sense Key Specific: %#x,%#x", sks[0], 4296225950Sken scsi_2btoul(&sks[1])); 4297225950Sken break; 4298225950Sken } 4299225950Sken 4300225950Sken return (0); 4301225950Sken} 4302225950Sken 4303225950Skenvoid 4304225950Skenscsi_fru_sbuf(struct sbuf *sb, uint64_t fru) 4305225950Sken{ 4306225950Sken sbuf_printf(sb, "Field Replaceable Unit: %d", (int)fru); 4307225950Sken} 4308225950Sken 4309225950Skenvoid 4310225950Skenscsi_stream_sbuf(struct sbuf *sb, uint8_t stream_bits, uint64_t info) 4311225950Sken{ 4312225950Sken int need_comma; 4313225950Sken 4314225950Sken need_comma = 0; 4315225950Sken /* 4316225950Sken * XXX KDM this needs more descriptive decoding. 4317225950Sken */ 4318225950Sken if (stream_bits & SSD_DESC_STREAM_FM) { 4319225950Sken sbuf_printf(sb, "Filemark"); 4320225950Sken need_comma = 1; 4321225950Sken } 4322225950Sken 4323225950Sken if (stream_bits & SSD_DESC_STREAM_EOM) { 4324225950Sken sbuf_printf(sb, "%sEOM", (need_comma) ? "," : ""); 4325225950Sken need_comma = 1; 4326225950Sken } 4327225950Sken 4328225950Sken if (stream_bits & SSD_DESC_STREAM_ILI) 4329225950Sken sbuf_printf(sb, "%sILI", (need_comma) ? "," : ""); 4330225950Sken 4331225950Sken sbuf_printf(sb, ": Info: %#jx", (uintmax_t) info); 4332225950Sken} 4333225950Sken 4334225950Skenvoid 4335225950Skenscsi_block_sbuf(struct sbuf *sb, uint8_t block_bits, uint64_t info) 4336225950Sken{ 4337225950Sken if (block_bits & SSD_DESC_BLOCK_ILI) 4338225950Sken sbuf_printf(sb, "ILI: residue %#jx", (uintmax_t) info); 4339225950Sken} 4340225950Sken 4341225950Skenvoid 4342225950Skenscsi_sense_info_sbuf(struct sbuf *sb, struct scsi_sense_data *sense, 4343225950Sken u_int sense_len, uint8_t *cdb, int cdb_len, 4344225950Sken struct scsi_inquiry_data *inq_data, 4345225950Sken struct scsi_sense_desc_header *header) 4346225950Sken{ 4347225950Sken struct scsi_sense_info *info; 4348225950Sken 4349225950Sken info = (struct scsi_sense_info *)header; 4350225950Sken 4351225950Sken scsi_info_sbuf(sb, cdb, cdb_len, inq_data, scsi_8btou64(info->info)); 4352225950Sken} 4353225950Sken 4354225950Skenvoid 4355225950Skenscsi_sense_command_sbuf(struct sbuf *sb, struct scsi_sense_data *sense, 4356225950Sken u_int sense_len, uint8_t *cdb, int cdb_len, 4357225950Sken struct scsi_inquiry_data *inq_data, 4358225950Sken struct scsi_sense_desc_header *header) 4359225950Sken{ 4360225950Sken struct scsi_sense_command *command; 4361225950Sken 4362225950Sken command = (struct scsi_sense_command *)header; 4363225950Sken 4364225950Sken scsi_command_sbuf(sb, cdb, cdb_len, inq_data, 4365225950Sken scsi_8btou64(command->command_info)); 4366225950Sken} 4367225950Sken 4368225950Skenvoid 4369225950Skenscsi_sense_sks_sbuf(struct sbuf *sb, struct scsi_sense_data *sense, 4370225950Sken u_int sense_len, uint8_t *cdb, int cdb_len, 4371225950Sken struct scsi_inquiry_data *inq_data, 4372225950Sken struct scsi_sense_desc_header *header) 4373225950Sken{ 4374225950Sken struct scsi_sense_sks *sks; 4375225950Sken int error_code, sense_key, asc, ascq; 4376225950Sken 4377225950Sken sks = (struct scsi_sense_sks *)header; 4378225950Sken 4379225950Sken scsi_extract_sense_len(sense, sense_len, &error_code, &sense_key, 4380225950Sken &asc, &ascq, /*show_errors*/ 1); 4381225950Sken 4382225950Sken scsi_sks_sbuf(sb, sense_key, sks->sense_key_spec); 4383225950Sken} 4384225950Sken 4385225950Skenvoid 4386225950Skenscsi_sense_fru_sbuf(struct sbuf *sb, struct scsi_sense_data *sense, 4387225950Sken u_int sense_len, uint8_t *cdb, int cdb_len, 4388225950Sken struct scsi_inquiry_data *inq_data, 4389225950Sken struct scsi_sense_desc_header *header) 4390225950Sken{ 4391225950Sken struct scsi_sense_fru *fru; 4392225950Sken 4393225950Sken fru = (struct scsi_sense_fru *)header; 4394225950Sken 4395225950Sken scsi_fru_sbuf(sb, (uint64_t)fru->fru); 4396225950Sken} 4397225950Sken 4398225950Skenvoid 4399225950Skenscsi_sense_stream_sbuf(struct sbuf *sb, struct scsi_sense_data *sense, 4400225950Sken u_int sense_len, uint8_t *cdb, int cdb_len, 4401225950Sken struct scsi_inquiry_data *inq_data, 4402225950Sken struct scsi_sense_desc_header *header) 4403225950Sken{ 4404225950Sken struct scsi_sense_stream *stream; 4405225950Sken uint64_t info; 4406225950Sken 4407225950Sken stream = (struct scsi_sense_stream *)header; 4408225950Sken info = 0; 4409225950Sken 4410225950Sken scsi_get_sense_info(sense, sense_len, SSD_DESC_INFO, &info, NULL); 4411225950Sken 4412225950Sken scsi_stream_sbuf(sb, stream->byte3, info); 4413225950Sken} 4414225950Sken 4415225950Skenvoid 4416225950Skenscsi_sense_block_sbuf(struct sbuf *sb, struct scsi_sense_data *sense, 4417225950Sken u_int sense_len, uint8_t *cdb, int cdb_len, 4418225950Sken struct scsi_inquiry_data *inq_data, 4419225950Sken struct scsi_sense_desc_header *header) 4420225950Sken{ 4421225950Sken struct scsi_sense_block *block; 4422225950Sken uint64_t info; 4423225950Sken 4424225950Sken block = (struct scsi_sense_block *)header; 4425225950Sken info = 0; 4426225950Sken 4427225950Sken scsi_get_sense_info(sense, sense_len, SSD_DESC_INFO, &info, NULL); 4428225950Sken 4429225950Sken scsi_block_sbuf(sb, block->byte3, info); 4430225950Sken} 4431225950Sken 4432225950Skenvoid 4433225950Skenscsi_sense_progress_sbuf(struct sbuf *sb, struct scsi_sense_data *sense, 4434225950Sken u_int sense_len, uint8_t *cdb, int cdb_len, 4435225950Sken struct scsi_inquiry_data *inq_data, 4436225950Sken struct scsi_sense_desc_header *header) 4437225950Sken{ 4438225950Sken struct scsi_sense_progress *progress; 4439225950Sken const char *sense_key_desc; 4440225950Sken const char *asc_desc; 4441225950Sken int progress_val; 4442225950Sken 4443225950Sken progress = (struct scsi_sense_progress *)header; 4444225950Sken 4445225950Sken /* 4446225950Sken * Get descriptions for the sense key, ASC, and ASCQ in the 4447225950Sken * progress descriptor. These could be different than the values 4448225950Sken * in the overall sense data. 4449225950Sken */ 4450225950Sken scsi_sense_desc(progress->sense_key, progress->add_sense_code, 4451225950Sken progress->add_sense_code_qual, inq_data, 4452225950Sken &sense_key_desc, &asc_desc); 4453225950Sken 4454225950Sken progress_val = scsi_2btoul(progress->progress); 4455225950Sken 4456225950Sken /* 4457225950Sken * The progress indicator is for the operation described by the 4458225950Sken * sense key, ASC, and ASCQ in the descriptor. 4459225950Sken */ 4460225950Sken sbuf_cat(sb, sense_key_desc); 4461225950Sken sbuf_printf(sb, " asc:%x,%x (%s): ", progress->add_sense_code, 4462225950Sken progress->add_sense_code_qual, asc_desc); 4463225950Sken scsi_progress_sbuf(sb, progress_val); 4464225950Sken} 4465225950Sken 4466225950Sken/* 4467225950Sken * Generic sense descriptor printing routine. This is used when we have 4468225950Sken * not yet implemented a specific printing routine for this descriptor. 4469225950Sken */ 4470225950Skenvoid 4471225950Skenscsi_sense_generic_sbuf(struct sbuf *sb, struct scsi_sense_data *sense, 4472225950Sken u_int sense_len, uint8_t *cdb, int cdb_len, 4473225950Sken struct scsi_inquiry_data *inq_data, 4474225950Sken struct scsi_sense_desc_header *header) 4475225950Sken{ 4476225950Sken int i; 4477225950Sken uint8_t *buf_ptr; 4478225950Sken 4479225950Sken sbuf_printf(sb, "Descriptor %#x:", header->desc_type); 4480225950Sken 4481225950Sken buf_ptr = (uint8_t *)&header[1]; 4482225950Sken 4483225950Sken for (i = 0; i < header->length; i++, buf_ptr++) 4484225950Sken sbuf_printf(sb, " %02x", *buf_ptr); 4485225950Sken} 4486225950Sken 4487225950Sken/* 4488225950Sken * Keep this list in numeric order. This speeds the array traversal. 4489225950Sken */ 4490225950Skenstruct scsi_sense_desc_printer { 4491225950Sken uint8_t desc_type; 4492225950Sken /* 4493225950Sken * The function arguments here are the superset of what is needed 4494225950Sken * to print out various different descriptors. Command and 4495225950Sken * information descriptors need inquiry data and command type. 4496225950Sken * Sense key specific descriptors need the sense key. 4497225950Sken * 4498225950Sken * The sense, cdb, and inquiry data arguments may be NULL, but the 4499225950Sken * information printed may not be fully decoded as a result. 4500225950Sken */ 4501225950Sken void (*print_func)(struct sbuf *sb, struct scsi_sense_data *sense, 4502225950Sken u_int sense_len, uint8_t *cdb, int cdb_len, 4503225950Sken struct scsi_inquiry_data *inq_data, 4504225950Sken struct scsi_sense_desc_header *header); 4505225950Sken} scsi_sense_printers[] = { 4506225950Sken {SSD_DESC_INFO, scsi_sense_info_sbuf}, 4507225950Sken {SSD_DESC_COMMAND, scsi_sense_command_sbuf}, 4508225950Sken {SSD_DESC_SKS, scsi_sense_sks_sbuf}, 4509225950Sken {SSD_DESC_FRU, scsi_sense_fru_sbuf}, 4510225950Sken {SSD_DESC_STREAM, scsi_sense_stream_sbuf}, 4511225950Sken {SSD_DESC_BLOCK, scsi_sense_block_sbuf}, 4512225950Sken {SSD_DESC_PROGRESS, scsi_sense_progress_sbuf} 4513225950Sken}; 4514225950Sken 4515225950Skenvoid 4516225950Skenscsi_sense_desc_sbuf(struct sbuf *sb, struct scsi_sense_data *sense, 4517225950Sken u_int sense_len, uint8_t *cdb, int cdb_len, 4518225950Sken struct scsi_inquiry_data *inq_data, 4519225950Sken struct scsi_sense_desc_header *header) 4520225950Sken{ 4521238200Seadler int i; 4522225950Sken 4523238200Seadler for (i = 0; i < (sizeof(scsi_sense_printers) / 4524225950Sken sizeof(scsi_sense_printers[0])); i++) { 4525225950Sken struct scsi_sense_desc_printer *printer; 4526225950Sken 4527225950Sken printer = &scsi_sense_printers[i]; 4528225950Sken 4529225950Sken /* 4530225950Sken * The list is sorted, so quit if we've passed our 4531225950Sken * descriptor number. 4532225950Sken */ 4533225950Sken if (printer->desc_type > header->desc_type) 4534225950Sken break; 4535225950Sken 4536225950Sken if (printer->desc_type != header->desc_type) 4537225950Sken continue; 4538225950Sken 4539225950Sken printer->print_func(sb, sense, sense_len, cdb, cdb_len, 4540225950Sken inq_data, header); 4541225950Sken 4542225950Sken return; 4543225950Sken } 4544225950Sken 4545225950Sken /* 4546225950Sken * No specific printing routine, so use the generic routine. 4547225950Sken */ 4548225950Sken scsi_sense_generic_sbuf(sb, sense, sense_len, cdb, cdb_len, 4549225950Sken inq_data, header); 4550225950Sken} 4551225950Sken 4552225950Skenscsi_sense_data_type 4553225950Skenscsi_sense_type(struct scsi_sense_data *sense_data) 4554225950Sken{ 4555225950Sken switch (sense_data->error_code & SSD_ERRCODE) { 4556225950Sken case SSD_DESC_CURRENT_ERROR: 4557225950Sken case SSD_DESC_DEFERRED_ERROR: 4558225950Sken return (SSD_TYPE_DESC); 4559225950Sken break; 4560225950Sken case SSD_CURRENT_ERROR: 4561225950Sken case SSD_DEFERRED_ERROR: 4562225950Sken return (SSD_TYPE_FIXED); 4563225950Sken break; 4564225950Sken default: 4565225950Sken break; 4566225950Sken } 4567225950Sken 4568225950Sken return (SSD_TYPE_NONE); 4569225950Sken} 4570225950Sken 4571225950Skenstruct scsi_print_sense_info { 4572225950Sken struct sbuf *sb; 4573225950Sken char *path_str; 4574225950Sken uint8_t *cdb; 4575225950Sken int cdb_len; 4576225950Sken struct scsi_inquiry_data *inq_data; 4577225950Sken}; 4578225950Sken 4579225950Skenstatic int 4580225950Skenscsi_print_desc_func(struct scsi_sense_data_desc *sense, u_int sense_len, 4581225950Sken struct scsi_sense_desc_header *header, void *arg) 4582225950Sken{ 4583225950Sken struct scsi_print_sense_info *print_info; 4584225950Sken 4585225950Sken print_info = (struct scsi_print_sense_info *)arg; 4586225950Sken 4587225950Sken switch (header->desc_type) { 4588225950Sken case SSD_DESC_INFO: 4589225950Sken case SSD_DESC_FRU: 4590225950Sken case SSD_DESC_COMMAND: 4591225950Sken case SSD_DESC_SKS: 4592225950Sken case SSD_DESC_BLOCK: 4593225950Sken case SSD_DESC_STREAM: 4594225950Sken /* 4595225950Sken * We have already printed these descriptors, if they are 4596225950Sken * present. 4597225950Sken */ 4598225950Sken break; 4599225950Sken default: { 4600225950Sken sbuf_printf(print_info->sb, "%s", print_info->path_str); 4601225950Sken scsi_sense_desc_sbuf(print_info->sb, 4602225950Sken (struct scsi_sense_data *)sense, sense_len, 4603225950Sken print_info->cdb, print_info->cdb_len, 4604225950Sken print_info->inq_data, header); 4605225950Sken sbuf_printf(print_info->sb, "\n"); 4606225950Sken break; 4607225950Sken } 4608225950Sken } 4609225950Sken 4610225950Sken /* 4611225950Sken * Tell the iterator that we want to see more descriptors if they 4612225950Sken * are present. 4613225950Sken */ 4614225950Sken return (0); 4615225950Sken} 4616225950Sken 4617225950Skenvoid 4618225950Skenscsi_sense_only_sbuf(struct scsi_sense_data *sense, u_int sense_len, 4619225950Sken struct sbuf *sb, char *path_str, 4620225950Sken struct scsi_inquiry_data *inq_data, uint8_t *cdb, 4621225950Sken int cdb_len) 4622225950Sken{ 4623225950Sken int error_code, sense_key, asc, ascq; 4624225950Sken 4625225950Sken sbuf_cat(sb, path_str); 4626225950Sken 4627225950Sken scsi_extract_sense_len(sense, sense_len, &error_code, &sense_key, 4628225950Sken &asc, &ascq, /*show_errors*/ 1); 4629225950Sken 4630225950Sken sbuf_printf(sb, "SCSI sense: "); 4631225950Sken switch (error_code) { 4632225950Sken case SSD_DEFERRED_ERROR: 4633225950Sken case SSD_DESC_DEFERRED_ERROR: 4634225950Sken sbuf_printf(sb, "Deferred error: "); 4635225950Sken 4636225950Sken /* FALLTHROUGH */ 4637225950Sken case SSD_CURRENT_ERROR: 4638225950Sken case SSD_DESC_CURRENT_ERROR: 4639225950Sken { 4640225950Sken struct scsi_sense_data_desc *desc_sense; 4641225950Sken struct scsi_print_sense_info print_info; 4642225950Sken const char *sense_key_desc; 4643225950Sken const char *asc_desc; 4644225950Sken uint8_t sks[3]; 4645225950Sken uint64_t val; 4646225950Sken int info_valid; 4647225950Sken 4648225950Sken /* 4649225950Sken * Get descriptions for the sense key, ASC, and ASCQ. If 4650225950Sken * these aren't present in the sense data (i.e. the sense 4651225950Sken * data isn't long enough), the -1 values that 4652225950Sken * scsi_extract_sense_len() returns will yield default 4653225950Sken * or error descriptions. 4654225950Sken */ 4655225950Sken scsi_sense_desc(sense_key, asc, ascq, inq_data, 4656225950Sken &sense_key_desc, &asc_desc); 4657225950Sken 4658225950Sken /* 4659225950Sken * We first print the sense key and ASC/ASCQ. 4660225950Sken */ 4661225950Sken sbuf_cat(sb, sense_key_desc); 4662225950Sken sbuf_printf(sb, " asc:%x,%x (%s)\n", asc, ascq, asc_desc); 4663225950Sken 4664225950Sken /* 4665225950Sken * Get the info field if it is valid. 4666225950Sken */ 4667225950Sken if (scsi_get_sense_info(sense, sense_len, SSD_DESC_INFO, 4668225950Sken &val, NULL) == 0) 4669225950Sken info_valid = 1; 4670225950Sken else 4671225950Sken info_valid = 0; 4672225950Sken 4673225950Sken if (info_valid != 0) { 4674225950Sken uint8_t bits; 4675225950Sken 4676225950Sken /* 4677225950Sken * Determine whether we have any block or stream 4678225950Sken * device-specific information. 4679225950Sken */ 4680225950Sken if (scsi_get_block_info(sense, sense_len, inq_data, 4681225950Sken &bits) == 0) { 4682225950Sken sbuf_cat(sb, path_str); 4683225950Sken scsi_block_sbuf(sb, bits, val); 4684225950Sken sbuf_printf(sb, "\n"); 4685225950Sken } else if (scsi_get_stream_info(sense, sense_len, 4686225950Sken inq_data, &bits) == 0) { 4687225950Sken sbuf_cat(sb, path_str); 4688225950Sken scsi_stream_sbuf(sb, bits, val); 4689225950Sken sbuf_printf(sb, "\n"); 4690225950Sken } else if (val != 0) { 4691225950Sken /* 4692225950Sken * The information field can be valid but 0. 4693225950Sken * If the block or stream bits aren't set, 4694225950Sken * and this is 0, it isn't terribly useful 4695225950Sken * to print it out. 4696225950Sken */ 4697225950Sken sbuf_cat(sb, path_str); 4698225950Sken scsi_info_sbuf(sb, cdb, cdb_len, inq_data, val); 4699225950Sken sbuf_printf(sb, "\n"); 4700225950Sken } 4701225950Sken } 4702225950Sken 4703225950Sken /* 4704225950Sken * Print the FRU. 4705225950Sken */ 4706225950Sken if (scsi_get_sense_info(sense, sense_len, SSD_DESC_FRU, 4707225950Sken &val, NULL) == 0) { 4708225950Sken sbuf_cat(sb, path_str); 4709225950Sken scsi_fru_sbuf(sb, val); 4710225950Sken sbuf_printf(sb, "\n"); 4711225950Sken } 4712225950Sken 4713225950Sken /* 4714225950Sken * Print any command-specific information. 4715225950Sken */ 4716225950Sken if (scsi_get_sense_info(sense, sense_len, SSD_DESC_COMMAND, 4717225950Sken &val, NULL) == 0) { 4718225950Sken sbuf_cat(sb, path_str); 4719225950Sken scsi_command_sbuf(sb, cdb, cdb_len, inq_data, val); 4720225950Sken sbuf_printf(sb, "\n"); 4721225950Sken } 4722225950Sken 4723225950Sken /* 4724225950Sken * Print out any sense-key-specific information. 4725225950Sken */ 4726225950Sken if (scsi_get_sks(sense, sense_len, sks) == 0) { 4727225950Sken sbuf_cat(sb, path_str); 4728225950Sken scsi_sks_sbuf(sb, sense_key, sks); 4729225950Sken sbuf_printf(sb, "\n"); 4730225950Sken } 4731225950Sken 4732225950Sken /* 4733225950Sken * If this is fixed sense, we're done. If we have 4734225950Sken * descriptor sense, we might have more information 4735225950Sken * available. 4736225950Sken */ 4737225950Sken if (scsi_sense_type(sense) != SSD_TYPE_DESC) 4738225950Sken break; 4739225950Sken 4740225950Sken desc_sense = (struct scsi_sense_data_desc *)sense; 4741225950Sken 4742225950Sken print_info.sb = sb; 4743225950Sken print_info.path_str = path_str; 4744225950Sken print_info.cdb = cdb; 4745225950Sken print_info.cdb_len = cdb_len; 4746225950Sken print_info.inq_data = inq_data; 4747225950Sken 4748225950Sken /* 4749225950Sken * Print any sense descriptors that we have not already printed. 4750225950Sken */ 4751225950Sken scsi_desc_iterate(desc_sense, sense_len, scsi_print_desc_func, 4752225950Sken &print_info); 4753225950Sken break; 4754225950Sken 4755225950Sken } 4756225950Sken case -1: 4757225950Sken /* 4758225950Sken * scsi_extract_sense_len() sets values to -1 if the 4759225950Sken * show_errors flag is set and they aren't present in the 4760225950Sken * sense data. This means that sense_len is 0. 4761225950Sken */ 4762225950Sken sbuf_printf(sb, "No sense data present\n"); 4763225950Sken break; 4764225950Sken default: { 4765225950Sken sbuf_printf(sb, "Error code 0x%x", error_code); 4766225950Sken if (sense->error_code & SSD_ERRCODE_VALID) { 4767225950Sken struct scsi_sense_data_fixed *fixed_sense; 4768225950Sken 4769225950Sken fixed_sense = (struct scsi_sense_data_fixed *)sense; 4770225950Sken 4771225950Sken if (SSD_FIXED_IS_PRESENT(fixed_sense, sense_len, info)){ 4772225950Sken uint32_t info; 4773225950Sken 4774225950Sken info = scsi_4btoul(fixed_sense->info); 4775225950Sken 4776225950Sken sbuf_printf(sb, " at block no. %d (decimal)", 4777225950Sken info); 4778225950Sken } 4779225950Sken } 4780225950Sken sbuf_printf(sb, "\n"); 4781225950Sken break; 4782225950Sken } 4783225950Sken } 4784225950Sken} 4785225950Sken 4786225950Sken/* 478774840Sken * scsi_sense_sbuf() returns 0 for success and -1 for failure. 478874840Sken */ 478974840Sken#ifdef _KERNEL 479074840Skenint 479174840Skenscsi_sense_sbuf(struct ccb_scsiio *csio, struct sbuf *sb, 479274840Sken scsi_sense_string_flags flags) 479355205Speter#else /* !_KERNEL */ 479474840Skenint 479574840Skenscsi_sense_sbuf(struct cam_device *device, struct ccb_scsiio *csio, 479674840Sken struct sbuf *sb, scsi_sense_string_flags flags) 479774840Sken#endif /* _KERNEL/!_KERNEL */ 479839213Sgibbs{ 479939213Sgibbs struct scsi_sense_data *sense; 480074840Sken struct scsi_inquiry_data *inq_data; 480174840Sken#ifdef _KERNEL 4802203108Smav struct ccb_getdev *cgd; 480374840Sken#endif /* _KERNEL */ 480439213Sgibbs char path_str[64]; 4805225950Sken uint8_t *cdb; 480639213Sgibbs 480774840Sken#ifndef _KERNEL 480874840Sken if (device == NULL) 480974840Sken return(-1); 481074840Sken#endif /* !_KERNEL */ 481174840Sken if ((csio == NULL) || (sb == NULL)) 481274840Sken return(-1); 481339213Sgibbs 481439213Sgibbs /* 481539213Sgibbs * If the CDB is a physical address, we can't deal with it.. 481639213Sgibbs */ 481739213Sgibbs if ((csio->ccb_h.flags & CAM_CDB_PHYS) != 0) 481874840Sken flags &= ~SSS_FLAG_PRINT_COMMAND; 481939213Sgibbs 482074840Sken#ifdef _KERNEL 482174840Sken xpt_path_string(csio->ccb_h.path, path_str, sizeof(path_str)); 482274840Sken#else /* !_KERNEL */ 482374840Sken cam_path_string(device, path_str, sizeof(path_str)); 482474840Sken#endif /* _KERNEL/!_KERNEL */ 482539213Sgibbs 482674840Sken#ifdef _KERNEL 4827203108Smav if ((cgd = (struct ccb_getdev*)xpt_alloc_ccb_nowait()) == NULL) 4828203108Smav return(-1); 482974840Sken /* 483074840Sken * Get the device information. 483174840Sken */ 4832203108Smav xpt_setup_ccb(&cgd->ccb_h, 483374840Sken csio->ccb_h.path, 4834198382Smav CAM_PRIORITY_NORMAL); 4835203108Smav cgd->ccb_h.func_code = XPT_GDEV_TYPE; 4836203108Smav xpt_action((union ccb *)cgd); 483739213Sgibbs 483874840Sken /* 483974840Sken * If the device is unconfigured, just pretend that it is a hard 484074840Sken * drive. scsi_op_desc() needs this. 484174840Sken */ 4842203108Smav if (cgd->ccb_h.status == CAM_DEV_NOT_THERE) 4843203108Smav cgd->inq_data.device = T_DIRECT; 484439213Sgibbs 4845203108Smav inq_data = &cgd->inq_data; 484639213Sgibbs 484774840Sken#else /* !_KERNEL */ 484839213Sgibbs 484974840Sken inq_data = &device->inq_data; 485040401Sken 485174840Sken#endif /* _KERNEL/!_KERNEL */ 485239213Sgibbs 485374840Sken sense = NULL; 485440401Sken 485574840Sken if (flags & SSS_FLAG_PRINT_COMMAND) { 485640401Sken 485774840Sken sbuf_cat(sb, path_str); 485874840Sken 485974840Sken#ifdef _KERNEL 486074840Sken scsi_command_string(csio, sb); 486174840Sken#else /* !_KERNEL */ 486274840Sken scsi_command_string(device, csio, sb); 486374840Sken#endif /* _KERNEL/!_KERNEL */ 4864111206Sken sbuf_printf(sb, "\n"); 486539213Sgibbs } 486639213Sgibbs 486739213Sgibbs /* 486839213Sgibbs * If the sense data is a physical pointer, forget it. 486939213Sgibbs */ 487039213Sgibbs if (csio->ccb_h.flags & CAM_SENSE_PTR) { 4871203108Smav if (csio->ccb_h.flags & CAM_SENSE_PHYS) { 4872203108Smav#ifdef _KERNEL 4873203108Smav xpt_free_ccb((union ccb*)cgd); 4874203108Smav#endif /* _KERNEL/!_KERNEL */ 487574840Sken return(-1); 4876203108Smav } else { 487739213Sgibbs /* 487874840Sken * bcopy the pointer to avoid unaligned access 487974840Sken * errors on finicky architectures. We don't 488074840Sken * ensure that the sense data is pointer aligned. 488139213Sgibbs */ 4882142159Sscottl bcopy(&csio->sense_data, &sense, 488339213Sgibbs sizeof(struct scsi_sense_data *)); 488439213Sgibbs } 488539213Sgibbs } else { 488639213Sgibbs /* 488739213Sgibbs * If the physical sense flag is set, but the sense pointer 488839213Sgibbs * is not also set, we assume that the user is an idiot and 488939213Sgibbs * return. (Well, okay, it could be that somehow, the 489039213Sgibbs * entire csio is physical, but we would have probably core 489139213Sgibbs * dumped on one of the bogus pointer deferences above 489239213Sgibbs * already.) 489339213Sgibbs */ 4894203108Smav if (csio->ccb_h.flags & CAM_SENSE_PHYS) { 4895203108Smav#ifdef _KERNEL 4896203108Smav xpt_free_ccb((union ccb*)cgd); 4897203108Smav#endif /* _KERNEL/!_KERNEL */ 489874840Sken return(-1); 4899203108Smav } else 490039213Sgibbs sense = &csio->sense_data; 490139213Sgibbs } 490239213Sgibbs 4903225950Sken if (csio->ccb_h.flags & CAM_CDB_POINTER) 4904225950Sken cdb = csio->cdb_io.cdb_ptr; 4905225950Sken else 4906225950Sken cdb = csio->cdb_io.cdb_bytes; 490739213Sgibbs 4908225950Sken scsi_sense_only_sbuf(sense, csio->sense_len - csio->sense_resid, sb, 4909225950Sken path_str, inq_data, cdb, csio->cdb_len); 4910225950Sken 4911203108Smav#ifdef _KERNEL 4912203108Smav xpt_free_ccb((union ccb*)cgd); 4913203108Smav#endif /* _KERNEL/!_KERNEL */ 491474840Sken return(0); 491574840Sken} 491640401Sken 491739213Sgibbs 491840401Sken 491974840Sken#ifdef _KERNEL 492074840Skenchar * 492174840Skenscsi_sense_string(struct ccb_scsiio *csio, char *str, int str_len) 492274840Sken#else /* !_KERNEL */ 492374840Skenchar * 492474840Skenscsi_sense_string(struct cam_device *device, struct ccb_scsiio *csio, 492574840Sken char *str, int str_len) 492674840Sken#endif /* _KERNEL/!_KERNEL */ 492739213Sgibbs{ 492874840Sken struct sbuf sb; 492939213Sgibbs 493074840Sken sbuf_new(&sb, str, str_len, 0); 493139213Sgibbs 493274840Sken#ifdef _KERNEL 493374840Sken scsi_sense_sbuf(csio, &sb, SSS_FLAG_PRINT_COMMAND); 493474840Sken#else /* !_KERNEL */ 493574840Sken scsi_sense_sbuf(device, csio, &sb, SSS_FLAG_PRINT_COMMAND); 493674840Sken#endif /* _KERNEL/!_KERNEL */ 493774840Sken 493874840Sken sbuf_finish(&sb); 493974840Sken 494074840Sken return(sbuf_data(&sb)); 494139213Sgibbs} 494239213Sgibbs 494355205Speter#ifdef _KERNEL 494474840Skenvoid 494574840Skenscsi_sense_print(struct ccb_scsiio *csio) 494639213Sgibbs{ 494774840Sken struct sbuf sb; 494874840Sken char str[512]; 494939213Sgibbs 495074840Sken sbuf_new(&sb, str, sizeof(str), 0); 495139213Sgibbs 495274840Sken scsi_sense_sbuf(csio, &sb, SSS_FLAG_PRINT_COMMAND); 495339213Sgibbs 495474840Sken sbuf_finish(&sb); 495539213Sgibbs 495674840Sken printf("%s", sbuf_data(&sb)); 495774840Sken} 495839213Sgibbs 495974840Sken#else /* !_KERNEL */ 496074840Skenvoid 496174840Skenscsi_sense_print(struct cam_device *device, struct ccb_scsiio *csio, 496274840Sken FILE *ofile) 496374840Sken{ 496474840Sken struct sbuf sb; 496574840Sken char str[512]; 496639213Sgibbs 496774840Sken if ((device == NULL) || (csio == NULL) || (ofile == NULL)) 496874840Sken return; 496939213Sgibbs 497074840Sken sbuf_new(&sb, str, sizeof(str), 0); 497139213Sgibbs 497274840Sken scsi_sense_sbuf(device, csio, &sb, SSS_FLAG_PRINT_COMMAND); 497339213Sgibbs 497474840Sken sbuf_finish(&sb); 497539213Sgibbs 497674840Sken fprintf(ofile, "%s", sbuf_data(&sb)); 497739213Sgibbs} 497839213Sgibbs 497974840Sken#endif /* _KERNEL/!_KERNEL */ 498074840Sken 498157349Sken/* 4982225950Sken * Extract basic sense information. This is backward-compatible with the 4983225950Sken * previous implementation. For new implementations, 4984225950Sken * scsi_extract_sense_len() is recommended. 4985225950Sken */ 4986225950Skenvoid 4987225950Skenscsi_extract_sense(struct scsi_sense_data *sense_data, int *error_code, 4988225950Sken int *sense_key, int *asc, int *ascq) 4989225950Sken{ 4990225950Sken scsi_extract_sense_len(sense_data, sizeof(*sense_data), error_code, 4991225950Sken sense_key, asc, ascq, /*show_errors*/ 0); 4992225950Sken} 4993225950Sken 4994225950Sken/* 4995237478Smav * Extract basic sense information from SCSI I/O CCB structure. 4996237478Smav */ 4997237478Smavint 4998237478Smavscsi_extract_sense_ccb(union ccb *ccb, 4999237478Smav int *error_code, int *sense_key, int *asc, int *ascq) 5000237478Smav{ 5001237478Smav struct scsi_sense_data *sense_data; 5002237478Smav 5003237478Smav /* Make sure there are some sense data we can access. */ 5004237478Smav if (ccb->ccb_h.func_code != XPT_SCSI_IO || 5005237478Smav (ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_SCSI_STATUS_ERROR || 5006237478Smav (ccb->csio.scsi_status != SCSI_STATUS_CHECK_COND) || 5007237478Smav (ccb->ccb_h.status & CAM_AUTOSNS_VALID) == 0 || 5008237478Smav (ccb->ccb_h.flags & CAM_SENSE_PHYS)) 5009237478Smav return (0); 5010237478Smav 5011237478Smav if (ccb->ccb_h.flags & CAM_SENSE_PTR) 5012237478Smav bcopy(&ccb->csio.sense_data, &sense_data, 5013237478Smav sizeof(struct scsi_sense_data *)); 5014237478Smav else 5015237478Smav sense_data = &ccb->csio.sense_data; 5016237478Smav scsi_extract_sense_len(sense_data, 5017237478Smav ccb->csio.sense_len - ccb->csio.sense_resid, 5018237478Smav error_code, sense_key, asc, ascq, 1); 5019237478Smav if (*error_code == -1) 5020237478Smav return (0); 5021237478Smav return (1); 5022237478Smav} 5023237478Smav 5024237478Smav/* 5025225950Sken * Extract basic sense information. If show_errors is set, sense values 5026225950Sken * will be set to -1 if they are not present. 5027225950Sken */ 5028225950Skenvoid 5029225950Skenscsi_extract_sense_len(struct scsi_sense_data *sense_data, u_int sense_len, 5030225950Sken int *error_code, int *sense_key, int *asc, int *ascq, 5031225950Sken int show_errors) 5032225950Sken{ 5033225950Sken /* 5034225950Sken * If we have no length, we have no sense. 5035225950Sken */ 5036225950Sken if (sense_len == 0) { 5037225950Sken if (show_errors == 0) { 5038225950Sken *error_code = 0; 5039225950Sken *sense_key = 0; 5040225950Sken *asc = 0; 5041225950Sken *ascq = 0; 5042225950Sken } else { 5043225950Sken *error_code = -1; 5044225950Sken *sense_key = -1; 5045225950Sken *asc = -1; 5046225950Sken *ascq = -1; 5047225950Sken } 5048225950Sken return; 5049225950Sken } 5050225950Sken 5051225950Sken *error_code = sense_data->error_code & SSD_ERRCODE; 5052225950Sken 5053225950Sken switch (*error_code) { 5054225950Sken case SSD_DESC_CURRENT_ERROR: 5055225950Sken case SSD_DESC_DEFERRED_ERROR: { 5056225950Sken struct scsi_sense_data_desc *sense; 5057225950Sken 5058225950Sken sense = (struct scsi_sense_data_desc *)sense_data; 5059225950Sken 5060225950Sken if (SSD_DESC_IS_PRESENT(sense, sense_len, sense_key)) 5061225950Sken *sense_key = sense->sense_key & SSD_KEY; 5062225950Sken else 5063225950Sken *sense_key = (show_errors) ? -1 : 0; 5064225950Sken 5065225950Sken if (SSD_DESC_IS_PRESENT(sense, sense_len, add_sense_code)) 5066225950Sken *asc = sense->add_sense_code; 5067225950Sken else 5068225950Sken *asc = (show_errors) ? -1 : 0; 5069225950Sken 5070225950Sken if (SSD_DESC_IS_PRESENT(sense, sense_len, add_sense_code_qual)) 5071225950Sken *ascq = sense->add_sense_code_qual; 5072225950Sken else 5073225950Sken *ascq = (show_errors) ? -1 : 0; 5074225950Sken break; 5075225950Sken } 5076225950Sken case SSD_CURRENT_ERROR: 5077225950Sken case SSD_DEFERRED_ERROR: 5078225950Sken default: { 5079225950Sken struct scsi_sense_data_fixed *sense; 5080225950Sken 5081225950Sken sense = (struct scsi_sense_data_fixed *)sense_data; 5082225950Sken 5083225950Sken if (SSD_FIXED_IS_PRESENT(sense, sense_len, flags)) 5084225950Sken *sense_key = sense->flags & SSD_KEY; 5085225950Sken else 5086225950Sken *sense_key = (show_errors) ? -1 : 0; 5087225950Sken 5088225950Sken if ((SSD_FIXED_IS_PRESENT(sense, sense_len, add_sense_code)) 5089225950Sken && (SSD_FIXED_IS_FILLED(sense, add_sense_code))) 5090225950Sken *asc = sense->add_sense_code; 5091225950Sken else 5092225950Sken *asc = (show_errors) ? -1 : 0; 5093225950Sken 5094225950Sken if ((SSD_FIXED_IS_PRESENT(sense, sense_len,add_sense_code_qual)) 5095225950Sken && (SSD_FIXED_IS_FILLED(sense, add_sense_code_qual))) 5096225950Sken *ascq = sense->add_sense_code_qual; 5097225950Sken else 5098225950Sken *ascq = (show_errors) ? -1 : 0; 5099225950Sken break; 5100225950Sken } 5101225950Sken } 5102225950Sken} 5103225950Sken 5104225950Skenint 5105225950Skenscsi_get_sense_key(struct scsi_sense_data *sense_data, u_int sense_len, 5106225950Sken int show_errors) 5107225950Sken{ 5108225950Sken int error_code, sense_key, asc, ascq; 5109225950Sken 5110225950Sken scsi_extract_sense_len(sense_data, sense_len, &error_code, 5111225950Sken &sense_key, &asc, &ascq, show_errors); 5112225950Sken 5113225950Sken return (sense_key); 5114225950Sken} 5115225950Sken 5116225950Skenint 5117225950Skenscsi_get_asc(struct scsi_sense_data *sense_data, u_int sense_len, 5118225950Sken int show_errors) 5119225950Sken{ 5120225950Sken int error_code, sense_key, asc, ascq; 5121225950Sken 5122225950Sken scsi_extract_sense_len(sense_data, sense_len, &error_code, 5123225950Sken &sense_key, &asc, &ascq, show_errors); 5124225950Sken 5125225950Sken return (asc); 5126225950Sken} 5127225950Sken 5128225950Skenint 5129225950Skenscsi_get_ascq(struct scsi_sense_data *sense_data, u_int sense_len, 5130225950Sken int show_errors) 5131225950Sken{ 5132225950Sken int error_code, sense_key, asc, ascq; 5133225950Sken 5134225950Sken scsi_extract_sense_len(sense_data, sense_len, &error_code, 5135225950Sken &sense_key, &asc, &ascq, show_errors); 5136225950Sken 5137225950Sken return (ascq); 5138225950Sken} 5139225950Sken 5140225950Sken/* 514157349Sken * This function currently requires at least 36 bytes, or 514257349Sken * SHORT_INQUIRY_LENGTH, worth of data to function properly. If this 514357349Sken * function needs more or less data in the future, another length should be 514457349Sken * defined in scsi_all.h to indicate the minimum amount of data necessary 514557349Sken * for this routine to function properly. 514657349Sken */ 514739213Sgibbsvoid 514839213Sgibbsscsi_print_inquiry(struct scsi_inquiry_data *inq_data) 514939213Sgibbs{ 515039213Sgibbs u_int8_t type; 515139213Sgibbs char *dtype, *qtype; 515241549Smjacob char vendor[16], product[48], revision[16], rstr[4]; 515339213Sgibbs 515439213Sgibbs type = SID_TYPE(inq_data); 515539213Sgibbs 515639213Sgibbs /* 515739213Sgibbs * Figure out basic device type and qualifier. 515839213Sgibbs */ 515939213Sgibbs if (SID_QUAL_IS_VENDOR_UNIQUE(inq_data)) { 516039213Sgibbs qtype = "(vendor-unique qualifier)"; 516139213Sgibbs } else { 516239213Sgibbs switch (SID_QUAL(inq_data)) { 516339213Sgibbs case SID_QUAL_LU_CONNECTED: 516439213Sgibbs qtype = ""; 516539213Sgibbs break; 516639213Sgibbs 516739213Sgibbs case SID_QUAL_LU_OFFLINE: 516839213Sgibbs qtype = "(offline)"; 516939213Sgibbs break; 517039213Sgibbs 517139213Sgibbs case SID_QUAL_RSVD: 517239213Sgibbs qtype = "(reserved qualifier)"; 517339213Sgibbs break; 517439213Sgibbs default: 517539213Sgibbs case SID_QUAL_BAD_LU: 5176181381Sjkim qtype = "(LUN not supported)"; 517739213Sgibbs break; 517839213Sgibbs } 517939213Sgibbs } 518039213Sgibbs 518139213Sgibbs switch (type) { 518239213Sgibbs case T_DIRECT: 518339213Sgibbs dtype = "Direct Access"; 518439213Sgibbs break; 518539213Sgibbs case T_SEQUENTIAL: 518639213Sgibbs dtype = "Sequential Access"; 518739213Sgibbs break; 518839213Sgibbs case T_PRINTER: 518939213Sgibbs dtype = "Printer"; 519039213Sgibbs break; 519139213Sgibbs case T_PROCESSOR: 519239213Sgibbs dtype = "Processor"; 519339213Sgibbs break; 5194181381Sjkim case T_WORM: 5195181381Sjkim dtype = "WORM"; 5196181381Sjkim break; 519739213Sgibbs case T_CDROM: 519839213Sgibbs dtype = "CD-ROM"; 519939213Sgibbs break; 520039213Sgibbs case T_SCANNER: 520139213Sgibbs dtype = "Scanner"; 520239213Sgibbs break; 520339213Sgibbs case T_OPTICAL: 520439213Sgibbs dtype = "Optical"; 520539213Sgibbs break; 520639213Sgibbs case T_CHANGER: 520739213Sgibbs dtype = "Changer"; 520839213Sgibbs break; 520939213Sgibbs case T_COMM: 521039213Sgibbs dtype = "Communication"; 521139213Sgibbs break; 521239213Sgibbs case T_STORARRAY: 521381448Sphk dtype = "Storage Array"; 521439213Sgibbs break; 521539213Sgibbs case T_ENCLOSURE: 521639213Sgibbs dtype = "Enclosure Services"; 521739213Sgibbs break; 521891016Ssimokawa case T_RBC: 521991016Ssimokawa dtype = "Simplified Direct Access"; 522091016Ssimokawa break; 522191016Ssimokawa case T_OCRW: 522291016Ssimokawa dtype = "Optical Card Read/Write"; 522391016Ssimokawa break; 5224181381Sjkim case T_OSD: 5225181381Sjkim dtype = "Object-Based Storage"; 5226181381Sjkim break; 5227181381Sjkim case T_ADC: 5228181381Sjkim dtype = "Automation/Drive Interface"; 5229181381Sjkim break; 523039213Sgibbs case T_NODEVICE: 523139213Sgibbs dtype = "Uninstalled"; 5232187243Strasz break; 523339213Sgibbs default: 523439213Sgibbs dtype = "unknown"; 523539213Sgibbs break; 523639213Sgibbs } 523739213Sgibbs 523839213Sgibbs cam_strvis(vendor, inq_data->vendor, sizeof(inq_data->vendor), 523939213Sgibbs sizeof(vendor)); 524039213Sgibbs cam_strvis(product, inq_data->product, sizeof(inq_data->product), 524139213Sgibbs sizeof(product)); 524239213Sgibbs cam_strvis(revision, inq_data->revision, sizeof(inq_data->revision), 524339213Sgibbs sizeof(revision)); 524439213Sgibbs 524541549Smjacob if (SID_ANSI_REV(inq_data) == SCSI_REV_CCS) 524641549Smjacob bcopy("CCS", rstr, 4); 524741549Smjacob else 524841549Smjacob snprintf(rstr, sizeof (rstr), "%d", SID_ANSI_REV(inq_data)); 524941549Smjacob printf("<%s %s %s> %s %s SCSI-%s device %s\n", 525039213Sgibbs vendor, product, revision, 525139213Sgibbs SID_IS_REMOVABLE(inq_data) ? "Removable" : "Fixed", 525241549Smjacob dtype, rstr, qtype); 525339213Sgibbs} 525439213Sgibbs 5255257049Smavvoid 5256257049Smavscsi_print_inquiry_short(struct scsi_inquiry_data *inq_data) 5257257049Smav{ 5258257049Smav char vendor[16], product[48], revision[16]; 5259257049Smav 5260257049Smav cam_strvis(vendor, inq_data->vendor, sizeof(inq_data->vendor), 5261257049Smav sizeof(vendor)); 5262257049Smav cam_strvis(product, inq_data->product, sizeof(inq_data->product), 5263257049Smav sizeof(product)); 5264257049Smav cam_strvis(revision, inq_data->revision, sizeof(inq_data->revision), 5265257049Smav sizeof(revision)); 5266257049Smav 5267257049Smav printf("<%s %s %s>", vendor, product, revision); 5268257049Smav} 5269257049Smav 527039213Sgibbs/* 527139213Sgibbs * Table of syncrates that don't follow the "divisible by 4" 527239213Sgibbs * rule. This table will be expanded in future SCSI specs. 527339213Sgibbs */ 527439213Sgibbsstatic struct { 527563456Sgibbs u_int period_factor; 527697882Sgibbs u_int period; /* in 100ths of ns */ 527739213Sgibbs} scsi_syncrates[] = { 527897882Sgibbs { 0x08, 625 }, /* FAST-160 */ 527997882Sgibbs { 0x09, 1250 }, /* FAST-80 */ 528097882Sgibbs { 0x0a, 2500 }, /* FAST-40 40MHz */ 528197882Sgibbs { 0x0b, 3030 }, /* FAST-40 33MHz */ 528297882Sgibbs { 0x0c, 5000 } /* FAST-20 */ 528339213Sgibbs}; 528439213Sgibbs 528539213Sgibbs/* 528639213Sgibbs * Return the frequency in kHz corresponding to the given 528739213Sgibbs * sync period factor. 528839213Sgibbs */ 528939213Sgibbsu_int 529039213Sgibbsscsi_calc_syncsrate(u_int period_factor) 529139213Sgibbs{ 529239213Sgibbs int i; 529339213Sgibbs int num_syncrates; 529439213Sgibbs 5295145042Smjacob /* 5296145042Smjacob * It's a bug if period is zero, but if it is anyway, don't 5297145042Smjacob * die with a divide fault- instead return something which 5298145042Smjacob * 'approximates' async 5299145042Smjacob */ 5300145042Smjacob if (period_factor == 0) { 5301145042Smjacob return (3300); 5302145042Smjacob } 5303145042Smjacob 530439213Sgibbs num_syncrates = sizeof(scsi_syncrates) / sizeof(scsi_syncrates[0]); 530539213Sgibbs /* See if the period is in the "exception" table */ 530639213Sgibbs for (i = 0; i < num_syncrates; i++) { 530739213Sgibbs 530839213Sgibbs if (period_factor == scsi_syncrates[i].period_factor) { 530939213Sgibbs /* Period in kHz */ 531097882Sgibbs return (100000000 / scsi_syncrates[i].period); 531139213Sgibbs } 531239213Sgibbs } 531339213Sgibbs 531439213Sgibbs /* 531539213Sgibbs * Wasn't in the table, so use the standard 531639213Sgibbs * 4 times conversion. 531739213Sgibbs */ 531839213Sgibbs return (10000000 / (period_factor * 4 * 10)); 531939213Sgibbs} 532039213Sgibbs 532139213Sgibbs/* 532239213Sgibbs * Return the SCSI sync parameter that corresponsd to 532339213Sgibbs * the passed in period in 10ths of ns. 532439213Sgibbs */ 532539213Sgibbsu_int 532639213Sgibbsscsi_calc_syncparam(u_int period) 532739213Sgibbs{ 532839213Sgibbs int i; 532939213Sgibbs int num_syncrates; 533039213Sgibbs 533139213Sgibbs if (period == 0) 533239213Sgibbs return (~0); /* Async */ 533339213Sgibbs 5334102443Sgibbs /* Adjust for exception table being in 100ths. */ 5335102443Sgibbs period *= 10; 533639213Sgibbs num_syncrates = sizeof(scsi_syncrates) / sizeof(scsi_syncrates[0]); 533739213Sgibbs /* See if the period is in the "exception" table */ 533839213Sgibbs for (i = 0; i < num_syncrates; i++) { 533939213Sgibbs 534039213Sgibbs if (period <= scsi_syncrates[i].period) { 5341102443Sgibbs /* Period in 100ths of ns */ 534239213Sgibbs return (scsi_syncrates[i].period_factor); 534339213Sgibbs } 534439213Sgibbs } 534539213Sgibbs 534639213Sgibbs /* 534739213Sgibbs * Wasn't in the table, so use the standard 534839213Sgibbs * 1/4 period in ns conversion. 534939213Sgibbs */ 5350102443Sgibbs return (period/400); 535139213Sgibbs} 535239213Sgibbs 5353223081Sgibbsint 5354223081Sgibbsscsi_devid_is_naa_ieee_reg(uint8_t *bufp) 5355216088Sken{ 5356216088Sken struct scsi_vpd_id_descriptor *descr; 5357216088Sken struct scsi_vpd_id_naa_basic *naa; 5358216088Sken 5359223081Sgibbs descr = (struct scsi_vpd_id_descriptor *)bufp; 5360223081Sgibbs naa = (struct scsi_vpd_id_naa_basic *)descr->identifier; 5361223081Sgibbs if ((descr->id_type & SVPD_ID_TYPE_MASK) != SVPD_ID_TYPE_NAA) 5362223081Sgibbs return 0; 5363223081Sgibbs if (descr->length < sizeof(struct scsi_vpd_id_naa_ieee_reg)) 5364223081Sgibbs return 0; 5365223081Sgibbs if ((naa->naa >> SVPD_ID_NAA_NAA_SHIFT) != SVPD_ID_NAA_IEEE_REG) 5366223081Sgibbs return 0; 5367223081Sgibbs return 1; 5368223081Sgibbs} 5369223081Sgibbs 5370223081Sgibbsint 5371223081Sgibbsscsi_devid_is_sas_target(uint8_t *bufp) 5372223081Sgibbs{ 5373223081Sgibbs struct scsi_vpd_id_descriptor *descr; 5374223081Sgibbs 5375223081Sgibbs descr = (struct scsi_vpd_id_descriptor *)bufp; 5376223081Sgibbs if (!scsi_devid_is_naa_ieee_reg(bufp)) 5377223081Sgibbs return 0; 5378223081Sgibbs if ((descr->id_type & SVPD_ID_PIV) == 0) /* proto field reserved */ 5379223081Sgibbs return 0; 5380223081Sgibbs if ((descr->proto_codeset >> SVPD_ID_PROTO_SHIFT) != SCSI_PROTO_SAS) 5381223081Sgibbs return 0; 5382223081Sgibbs return 1; 5383223081Sgibbs} 5384223081Sgibbs 5385251654Smavint 5386251654Smavscsi_devid_is_lun_eui64(uint8_t *bufp) 5387251654Smav{ 5388251654Smav struct scsi_vpd_id_descriptor *descr; 5389251654Smav 5390251654Smav descr = (struct scsi_vpd_id_descriptor *)bufp; 5391251654Smav if ((descr->id_type & SVPD_ID_ASSOC_MASK) != SVPD_ID_ASSOC_LUN) 5392251654Smav return 0; 5393251654Smav if ((descr->id_type & SVPD_ID_TYPE_MASK) != SVPD_ID_TYPE_EUI64) 5394251654Smav return 0; 5395251654Smav return 1; 5396251654Smav} 5397251654Smav 5398251654Smavint 5399251654Smavscsi_devid_is_lun_naa(uint8_t *bufp) 5400251654Smav{ 5401251654Smav struct scsi_vpd_id_descriptor *descr; 5402251654Smav 5403251654Smav descr = (struct scsi_vpd_id_descriptor *)bufp; 5404251654Smav if ((descr->id_type & SVPD_ID_ASSOC_MASK) != SVPD_ID_ASSOC_LUN) 5405251654Smav return 0; 5406251654Smav if ((descr->id_type & SVPD_ID_TYPE_MASK) != SVPD_ID_TYPE_NAA) 5407251654Smav return 0; 5408251654Smav return 1; 5409251654Smav} 5410251654Smav 5411251654Smavint 5412251654Smavscsi_devid_is_lun_t10(uint8_t *bufp) 5413251654Smav{ 5414251654Smav struct scsi_vpd_id_descriptor *descr; 5415251654Smav 5416251654Smav descr = (struct scsi_vpd_id_descriptor *)bufp; 5417251654Smav if ((descr->id_type & SVPD_ID_ASSOC_MASK) != SVPD_ID_ASSOC_LUN) 5418251654Smav return 0; 5419251654Smav if ((descr->id_type & SVPD_ID_TYPE_MASK) != SVPD_ID_TYPE_T10) 5420251654Smav return 0; 5421251654Smav return 1; 5422251654Smav} 5423251654Smav 5424251654Smavint 5425251654Smavscsi_devid_is_lun_name(uint8_t *bufp) 5426251654Smav{ 5427251654Smav struct scsi_vpd_id_descriptor *descr; 5428251654Smav 5429251654Smav descr = (struct scsi_vpd_id_descriptor *)bufp; 5430251654Smav if ((descr->id_type & SVPD_ID_ASSOC_MASK) != SVPD_ID_ASSOC_LUN) 5431251654Smav return 0; 5432251654Smav if ((descr->id_type & SVPD_ID_TYPE_MASK) != SVPD_ID_TYPE_SCSI_NAME) 5433251654Smav return 0; 5434251654Smav return 1; 5435251654Smav} 5436251654Smav 5437251654Smavstruct scsi_vpd_id_descriptor * 5438270106Smavscsi_get_devid_desc(struct scsi_vpd_id_descriptor *desc, uint32_t len, 5439223081Sgibbs scsi_devid_checkfn_t ck_fn) 5440223081Sgibbs{ 5441223081Sgibbs uint8_t *desc_buf_end; 5442223081Sgibbs 5443270106Smav desc_buf_end = (uint8_t *)desc + len; 5444223081Sgibbs 5445270106Smav for (; desc->identifier <= desc_buf_end && 5446270106Smav desc->identifier + desc->length <= desc_buf_end; 5447270106Smav desc = (struct scsi_vpd_id_descriptor *)(desc->identifier 5448223081Sgibbs + desc->length)) { 5449223081Sgibbs 5450223081Sgibbs if (ck_fn == NULL || ck_fn((uint8_t *)desc) != 0) 5451251654Smav return (desc); 5452216088Sken } 5453223081Sgibbs return (NULL); 5454216088Sken} 5455216088Sken 5456270106Smavstruct scsi_vpd_id_descriptor * 5457270106Smavscsi_get_devid(struct scsi_vpd_device_id *id, uint32_t page_len, 5458270106Smav scsi_devid_checkfn_t ck_fn) 5459270106Smav{ 5460270106Smav uint32_t len; 5461270106Smav 5462270106Smav if (page_len < sizeof(*id)) 5463270106Smav return (NULL); 5464270106Smav len = MIN(scsi_2btoul(id->length), page_len - sizeof(*id)); 5465270106Smav return (scsi_get_devid_desc((struct scsi_vpd_id_descriptor *) 5466270106Smav id->desc_list, len, ck_fn)); 5467270106Smav} 5468270106Smav 5469268700Smavint 5470268700Smavscsi_transportid_sbuf(struct sbuf *sb, struct scsi_transportid_header *hdr, 5471268700Smav uint32_t valid_len) 5472268700Smav{ 5473268700Smav switch (hdr->format_protocol & SCSI_TRN_PROTO_MASK) { 5474268700Smav case SCSI_PROTO_FC: { 5475268700Smav struct scsi_transportid_fcp *fcp; 5476268700Smav uint64_t n_port_name; 5477268700Smav 5478268700Smav fcp = (struct scsi_transportid_fcp *)hdr; 5479268700Smav 5480268700Smav n_port_name = scsi_8btou64(fcp->n_port_name); 5481268700Smav 5482268700Smav sbuf_printf(sb, "FCP address: 0x%.16jx",(uintmax_t)n_port_name); 5483268700Smav break; 5484268700Smav } 5485268700Smav case SCSI_PROTO_SPI: { 5486268700Smav struct scsi_transportid_spi *spi; 5487268700Smav 5488268700Smav spi = (struct scsi_transportid_spi *)hdr; 5489268700Smav 5490268700Smav sbuf_printf(sb, "SPI address: %u,%u", 5491268700Smav scsi_2btoul(spi->scsi_addr), 5492268700Smav scsi_2btoul(spi->rel_trgt_port_id)); 5493268700Smav break; 5494268700Smav } 5495268700Smav case SCSI_PROTO_SSA: 5496268700Smav /* 5497268700Smav * XXX KDM there is no transport ID defined in SPC-4 for 5498268700Smav * SSA. 5499268700Smav */ 5500268700Smav break; 5501268700Smav case SCSI_PROTO_1394: { 5502268700Smav struct scsi_transportid_1394 *sbp; 5503268700Smav uint64_t eui64; 5504268700Smav 5505268700Smav sbp = (struct scsi_transportid_1394 *)hdr; 5506268700Smav 5507268700Smav eui64 = scsi_8btou64(sbp->eui64); 5508268700Smav sbuf_printf(sb, "SBP address: 0x%.16jx", (uintmax_t)eui64); 5509268700Smav break; 5510268700Smav } 5511268700Smav case SCSI_PROTO_RDMA: { 5512268700Smav struct scsi_transportid_rdma *rdma; 5513268700Smav unsigned int i; 5514268700Smav 5515268700Smav rdma = (struct scsi_transportid_rdma *)hdr; 5516268700Smav 5517268700Smav sbuf_printf(sb, "RDMA address: 0x"); 5518268700Smav for (i = 0; i < sizeof(rdma->initiator_port_id); i++) 5519268700Smav sbuf_printf(sb, "%02x", rdma->initiator_port_id[i]); 5520268700Smav break; 5521268700Smav } 5522268700Smav case SCSI_PROTO_ISCSI: { 5523268700Smav uint32_t add_len, i; 5524268700Smav uint8_t *iscsi_name = NULL; 5525268700Smav int nul_found = 0; 5526268700Smav 5527268700Smav sbuf_printf(sb, "iSCSI address: "); 5528268700Smav if ((hdr->format_protocol & SCSI_TRN_FORMAT_MASK) == 5529268700Smav SCSI_TRN_ISCSI_FORMAT_DEVICE) { 5530268700Smav struct scsi_transportid_iscsi_device *dev; 5531268700Smav 5532268700Smav dev = (struct scsi_transportid_iscsi_device *)hdr; 5533268700Smav 5534268700Smav /* 5535268700Smav * Verify how much additional data we really have. 5536268700Smav */ 5537268700Smav add_len = scsi_2btoul(dev->additional_length); 5538268700Smav add_len = MIN(add_len, valid_len - 5539268700Smav __offsetof(struct scsi_transportid_iscsi_device, 5540268700Smav iscsi_name)); 5541268700Smav iscsi_name = &dev->iscsi_name[0]; 5542268700Smav 5543268700Smav } else if ((hdr->format_protocol & SCSI_TRN_FORMAT_MASK) == 5544268700Smav SCSI_TRN_ISCSI_FORMAT_PORT) { 5545268700Smav struct scsi_transportid_iscsi_port *port; 5546268700Smav 5547268700Smav port = (struct scsi_transportid_iscsi_port *)hdr; 5548268700Smav 5549268700Smav add_len = scsi_2btoul(port->additional_length); 5550268700Smav add_len = MIN(add_len, valid_len - 5551268700Smav __offsetof(struct scsi_transportid_iscsi_port, 5552268700Smav iscsi_name)); 5553268700Smav iscsi_name = &port->iscsi_name[0]; 5554268700Smav } else { 5555268700Smav sbuf_printf(sb, "unknown format %x", 5556268700Smav (hdr->format_protocol & 5557268700Smav SCSI_TRN_FORMAT_MASK) >> 5558268700Smav SCSI_TRN_FORMAT_SHIFT); 5559268700Smav break; 5560268700Smav } 5561268700Smav if (add_len == 0) { 5562268700Smav sbuf_printf(sb, "not enough data"); 5563268700Smav break; 5564268700Smav } 5565268700Smav /* 5566268700Smav * This is supposed to be a NUL-terminated ASCII 5567268700Smav * string, but you never know. So we're going to 5568268700Smav * check. We need to do this because there is no 5569268700Smav * sbuf equivalent of strncat(). 5570268700Smav */ 5571268700Smav for (i = 0; i < add_len; i++) { 5572268700Smav if (iscsi_name[i] == '\0') { 5573268700Smav nul_found = 1; 5574268700Smav break; 5575268700Smav } 5576268700Smav } 5577268700Smav /* 5578268700Smav * If there is a NUL in the name, we can just use 5579268700Smav * sbuf_cat(). Otherwise we need to use sbuf_bcat(). 5580268700Smav */ 5581268700Smav if (nul_found != 0) 5582268700Smav sbuf_cat(sb, iscsi_name); 5583268700Smav else 5584268700Smav sbuf_bcat(sb, iscsi_name, add_len); 5585268700Smav break; 5586268700Smav } 5587268700Smav case SCSI_PROTO_SAS: { 5588268700Smav struct scsi_transportid_sas *sas; 5589268700Smav uint64_t sas_addr; 5590268700Smav 5591268700Smav sas = (struct scsi_transportid_sas *)hdr; 5592268700Smav 5593268700Smav sas_addr = scsi_8btou64(sas->sas_address); 5594268700Smav sbuf_printf(sb, "SAS address: 0x%.16jx", (uintmax_t)sas_addr); 5595268700Smav break; 5596268700Smav } 5597268700Smav case SCSI_PROTO_ADITP: 5598268700Smav case SCSI_PROTO_ATA: 5599268700Smav case SCSI_PROTO_UAS: 5600268700Smav /* 5601268700Smav * No Transport ID format for ADI, ATA or USB is defined in 5602268700Smav * SPC-4. 5603268700Smav */ 5604268700Smav sbuf_printf(sb, "No known Transport ID format for protocol " 5605268700Smav "%#x", hdr->format_protocol & SCSI_TRN_PROTO_MASK); 5606268700Smav break; 5607268700Smav case SCSI_PROTO_SOP: { 5608268700Smav struct scsi_transportid_sop *sop; 5609268700Smav struct scsi_sop_routing_id_norm *rid; 5610268700Smav 5611268700Smav sop = (struct scsi_transportid_sop *)hdr; 5612268700Smav rid = (struct scsi_sop_routing_id_norm *)sop->routing_id; 5613268700Smav 5614268700Smav /* 5615268700Smav * Note that there is no alternate format specified in SPC-4 5616268700Smav * for the PCIe routing ID, so we don't really have a way 5617268700Smav * to know whether the second byte of the routing ID is 5618268700Smav * a device and function or just a function. So we just 5619268700Smav * assume bus,device,function. 5620268700Smav */ 5621268700Smav sbuf_printf(sb, "SOP Routing ID: %u,%u,%u", 5622268700Smav rid->bus, rid->devfunc >> SCSI_TRN_SOP_DEV_SHIFT, 5623268700Smav rid->devfunc & SCSI_TRN_SOP_FUNC_NORM_MAX); 5624268700Smav break; 5625268700Smav } 5626268700Smav case SCSI_PROTO_NONE: 5627268700Smav default: 5628268700Smav sbuf_printf(sb, "Unknown protocol %#x", 5629268700Smav hdr->format_protocol & SCSI_TRN_PROTO_MASK); 5630268700Smav break; 5631268700Smav } 5632268700Smav 5633268700Smav return (0); 5634268700Smav} 5635268700Smav 5636268700Smavstruct scsi_nv scsi_proto_map[] = { 5637268700Smav { "fcp", SCSI_PROTO_FC }, 5638268700Smav { "spi", SCSI_PROTO_SPI }, 5639268700Smav { "ssa", SCSI_PROTO_SSA }, 5640268700Smav { "sbp", SCSI_PROTO_1394 }, 5641268700Smav { "1394", SCSI_PROTO_1394 }, 5642268700Smav { "srp", SCSI_PROTO_RDMA }, 5643268700Smav { "rdma", SCSI_PROTO_RDMA }, 5644268700Smav { "iscsi", SCSI_PROTO_ISCSI }, 5645268700Smav { "iqn", SCSI_PROTO_ISCSI }, 5646268700Smav { "sas", SCSI_PROTO_SAS }, 5647268700Smav { "aditp", SCSI_PROTO_ADITP }, 5648268700Smav { "ata", SCSI_PROTO_ATA }, 5649268700Smav { "uas", SCSI_PROTO_UAS }, 5650268700Smav { "usb", SCSI_PROTO_UAS }, 5651268700Smav { "sop", SCSI_PROTO_SOP } 5652268700Smav}; 5653268700Smav 5654268700Smavconst char * 5655268700Smavscsi_nv_to_str(struct scsi_nv *table, int num_table_entries, uint64_t value) 5656268700Smav{ 5657268700Smav int i; 5658268700Smav 5659268700Smav for (i = 0; i < num_table_entries; i++) { 5660268700Smav if (table[i].value == value) 5661268700Smav return (table[i].name); 5662268700Smav } 5663268700Smav 5664268700Smav return (NULL); 5665268700Smav} 5666268700Smav 5667268700Smav/* 5668268700Smav * Given a name/value table, find a value matching the given name. 5669268700Smav * Return values: 5670268700Smav * SCSI_NV_FOUND - match found 5671268700Smav * SCSI_NV_AMBIGUOUS - more than one match, none of them exact 5672268700Smav * SCSI_NV_NOT_FOUND - no match found 5673268700Smav */ 5674268700Smavscsi_nv_status 5675268700Smavscsi_get_nv(struct scsi_nv *table, int num_table_entries, 5676268700Smav char *name, int *table_entry, scsi_nv_flags flags) 5677268700Smav{ 5678268700Smav int i, num_matches = 0; 5679268700Smav 5680268700Smav for (i = 0; i < num_table_entries; i++) { 5681268700Smav size_t table_len, name_len; 5682268700Smav 5683268700Smav table_len = strlen(table[i].name); 5684268700Smav name_len = strlen(name); 5685268700Smav 5686268700Smav if ((((flags & SCSI_NV_FLAG_IG_CASE) != 0) 5687268700Smav && (strncasecmp(table[i].name, name, name_len) == 0)) 5688268700Smav || (((flags & SCSI_NV_FLAG_IG_CASE) == 0) 5689268700Smav && (strncmp(table[i].name, name, name_len) == 0))) { 5690268700Smav *table_entry = i; 5691268700Smav 5692268700Smav /* 5693268700Smav * Check for an exact match. If we have the same 5694268700Smav * number of characters in the table as the argument, 5695268700Smav * and we already know they're the same, we have 5696268700Smav * an exact match. 5697268700Smav */ 5698268700Smav if (table_len == name_len) 5699268700Smav return (SCSI_NV_FOUND); 5700268700Smav 5701268700Smav /* 5702268700Smav * Otherwise, bump up the number of matches. We'll 5703268700Smav * see later how many we have. 5704268700Smav */ 5705268700Smav num_matches++; 5706268700Smav } 5707268700Smav } 5708268700Smav 5709268700Smav if (num_matches > 1) 5710268700Smav return (SCSI_NV_AMBIGUOUS); 5711268700Smav else if (num_matches == 1) 5712268700Smav return (SCSI_NV_FOUND); 5713268700Smav else 5714268700Smav return (SCSI_NV_NOT_FOUND); 5715268700Smav} 5716268700Smav 5717268700Smav/* 5718268700Smav * Parse transport IDs for Fibre Channel, 1394 and SAS. Since these are 5719268700Smav * all 64-bit numbers, the code is similar. 5720268700Smav */ 5721268700Smavint 5722268700Smavscsi_parse_transportid_64bit(int proto_id, char *id_str, 5723268700Smav struct scsi_transportid_header **hdr, 5724268700Smav unsigned int *alloc_len, 5725268700Smav#ifdef _KERNEL 5726268700Smav struct malloc_type *type, int flags, 5727268700Smav#endif 5728268700Smav char *error_str, int error_str_len) 5729268700Smav{ 5730268700Smav uint64_t value; 5731268700Smav char *endptr; 5732268700Smav int retval; 5733268700Smav size_t alloc_size; 5734268700Smav 5735268700Smav retval = 0; 5736268700Smav 5737268700Smav value = strtouq(id_str, &endptr, 0); 5738268700Smav if (*endptr != '\0') { 5739268700Smav if (error_str != NULL) { 5740268700Smav snprintf(error_str, error_str_len, "%s: error " 5741268700Smav "parsing ID %s, 64-bit number required", 5742268700Smav __func__, id_str); 5743268700Smav } 5744268700Smav retval = 1; 5745268700Smav goto bailout; 5746268700Smav } 5747268700Smav 5748268700Smav switch (proto_id) { 5749268700Smav case SCSI_PROTO_FC: 5750268700Smav alloc_size = sizeof(struct scsi_transportid_fcp); 5751268700Smav break; 5752268700Smav case SCSI_PROTO_1394: 5753268700Smav alloc_size = sizeof(struct scsi_transportid_1394); 5754268700Smav break; 5755268700Smav case SCSI_PROTO_SAS: 5756268700Smav alloc_size = sizeof(struct scsi_transportid_sas); 5757268700Smav break; 5758268700Smav default: 5759268700Smav if (error_str != NULL) { 5760268700Smav snprintf(error_str, error_str_len, "%s: unsupoprted " 5761268700Smav "protocol %d", __func__, proto_id); 5762268700Smav } 5763268700Smav retval = 1; 5764268700Smav goto bailout; 5765268700Smav break; /* NOTREACHED */ 5766268700Smav } 5767268700Smav#ifdef _KERNEL 5768268700Smav *hdr = malloc(alloc_size, type, flags); 5769268700Smav#else /* _KERNEL */ 5770268700Smav *hdr = malloc(alloc_size); 5771268700Smav#endif /*_KERNEL */ 5772268700Smav if (*hdr == NULL) { 5773268700Smav if (error_str != NULL) { 5774268700Smav snprintf(error_str, error_str_len, "%s: unable to " 5775268700Smav "allocate %zu bytes", __func__, alloc_size); 5776268700Smav } 5777268700Smav retval = 1; 5778268700Smav goto bailout; 5779268700Smav } 5780268700Smav 5781268700Smav *alloc_len = alloc_size; 5782268700Smav 5783268700Smav bzero(*hdr, alloc_size); 5784268700Smav 5785268700Smav switch (proto_id) { 5786268700Smav case SCSI_PROTO_FC: { 5787268700Smav struct scsi_transportid_fcp *fcp; 5788268700Smav 5789268700Smav fcp = (struct scsi_transportid_fcp *)(*hdr); 5790268700Smav fcp->format_protocol = SCSI_PROTO_FC | 5791268700Smav SCSI_TRN_FCP_FORMAT_DEFAULT; 5792268700Smav scsi_u64to8b(value, fcp->n_port_name); 5793268700Smav break; 5794268700Smav } 5795268700Smav case SCSI_PROTO_1394: { 5796268700Smav struct scsi_transportid_1394 *sbp; 5797268700Smav 5798268700Smav sbp = (struct scsi_transportid_1394 *)(*hdr); 5799268700Smav sbp->format_protocol = SCSI_PROTO_1394 | 5800268700Smav SCSI_TRN_1394_FORMAT_DEFAULT; 5801268700Smav scsi_u64to8b(value, sbp->eui64); 5802268700Smav break; 5803268700Smav } 5804268700Smav case SCSI_PROTO_SAS: { 5805268700Smav struct scsi_transportid_sas *sas; 5806268700Smav 5807268700Smav sas = (struct scsi_transportid_sas *)(*hdr); 5808268700Smav sas->format_protocol = SCSI_PROTO_SAS | 5809268700Smav SCSI_TRN_SAS_FORMAT_DEFAULT; 5810268700Smav scsi_u64to8b(value, sas->sas_address); 5811268700Smav break; 5812268700Smav } 5813268700Smav default: 5814268700Smav break; 5815268700Smav } 5816268700Smavbailout: 5817268700Smav return (retval); 5818268700Smav} 5819268700Smav 5820268700Smav/* 5821268700Smav * Parse a SPI (Parallel SCSI) address of the form: id,rel_tgt_port 5822268700Smav */ 5823268700Smavint 5824268700Smavscsi_parse_transportid_spi(char *id_str, struct scsi_transportid_header **hdr, 5825268700Smav unsigned int *alloc_len, 5826268700Smav#ifdef _KERNEL 5827268700Smav struct malloc_type *type, int flags, 5828268700Smav#endif 5829268700Smav char *error_str, int error_str_len) 5830268700Smav{ 5831268700Smav unsigned long scsi_addr, target_port; 5832268700Smav struct scsi_transportid_spi *spi; 5833268700Smav char *tmpstr, *endptr; 5834268700Smav int retval; 5835268700Smav 5836268700Smav retval = 0; 5837268700Smav 5838268700Smav tmpstr = strsep(&id_str, ","); 5839268700Smav if (tmpstr == NULL) { 5840268700Smav if (error_str != NULL) { 5841268700Smav snprintf(error_str, error_str_len, 5842268700Smav "%s: no ID found", __func__); 5843268700Smav } 5844268700Smav retval = 1; 5845268700Smav goto bailout; 5846268700Smav } 5847268700Smav scsi_addr = strtoul(tmpstr, &endptr, 0); 5848268700Smav if (*endptr != '\0') { 5849268700Smav if (error_str != NULL) { 5850268700Smav snprintf(error_str, error_str_len, "%s: error " 5851268700Smav "parsing SCSI ID %s, number required", 5852268700Smav __func__, tmpstr); 5853268700Smav } 5854268700Smav retval = 1; 5855268700Smav goto bailout; 5856268700Smav } 5857268700Smav 5858268700Smav if (id_str == NULL) { 5859268700Smav if (error_str != NULL) { 5860268700Smav snprintf(error_str, error_str_len, "%s: no relative " 5861268700Smav "target port found", __func__); 5862268700Smav } 5863268700Smav retval = 1; 5864268700Smav goto bailout; 5865268700Smav } 5866268700Smav 5867268700Smav target_port = strtoul(id_str, &endptr, 0); 5868268700Smav if (*endptr != '\0') { 5869268700Smav if (error_str != NULL) { 5870268700Smav snprintf(error_str, error_str_len, "%s: error " 5871268700Smav "parsing relative target port %s, number " 5872268700Smav "required", __func__, id_str); 5873268700Smav } 5874268700Smav retval = 1; 5875268700Smav goto bailout; 5876268700Smav } 5877268700Smav#ifdef _KERNEL 5878268700Smav spi = malloc(sizeof(*spi), type, flags); 5879268700Smav#else 5880268700Smav spi = malloc(sizeof(*spi)); 5881268700Smav#endif 5882268700Smav if (spi == NULL) { 5883268700Smav if (error_str != NULL) { 5884268700Smav snprintf(error_str, error_str_len, "%s: unable to " 5885268700Smav "allocate %zu bytes", __func__, 5886268700Smav sizeof(*spi)); 5887268700Smav } 5888268700Smav retval = 1; 5889268700Smav goto bailout; 5890268700Smav } 5891268700Smav *alloc_len = sizeof(*spi); 5892268700Smav bzero(spi, sizeof(*spi)); 5893268700Smav 5894268700Smav spi->format_protocol = SCSI_PROTO_SPI | SCSI_TRN_SPI_FORMAT_DEFAULT; 5895268700Smav scsi_ulto2b(scsi_addr, spi->scsi_addr); 5896268700Smav scsi_ulto2b(target_port, spi->rel_trgt_port_id); 5897268700Smav 5898268700Smav *hdr = (struct scsi_transportid_header *)spi; 5899268700Smavbailout: 5900268700Smav return (retval); 5901268700Smav} 5902268700Smav 5903268700Smav/* 5904268700Smav * Parse an RDMA/SRP Initiator Port ID string. This is 32 hexadecimal digits, 5905268700Smav * optionally prefixed by "0x" or "0X". 5906268700Smav */ 5907268700Smavint 5908268700Smavscsi_parse_transportid_rdma(char *id_str, struct scsi_transportid_header **hdr, 5909268700Smav unsigned int *alloc_len, 5910268700Smav#ifdef _KERNEL 5911268700Smav struct malloc_type *type, int flags, 5912268700Smav#endif 5913268700Smav char *error_str, int error_str_len) 5914268700Smav{ 5915268700Smav struct scsi_transportid_rdma *rdma; 5916268700Smav int retval; 5917268700Smav size_t id_len, rdma_id_size; 5918268700Smav uint8_t rdma_id[SCSI_TRN_RDMA_PORT_LEN]; 5919268700Smav char *tmpstr; 5920268700Smav unsigned int i, j; 5921268700Smav 5922268700Smav retval = 0; 5923268700Smav id_len = strlen(id_str); 5924268700Smav rdma_id_size = SCSI_TRN_RDMA_PORT_LEN; 5925268700Smav 5926268700Smav /* 5927268700Smav * Check the size. It needs to be either 32 or 34 characters long. 5928268700Smav */ 5929268700Smav if ((id_len != (rdma_id_size * 2)) 5930268700Smav && (id_len != ((rdma_id_size * 2) + 2))) { 5931268700Smav if (error_str != NULL) { 5932268700Smav snprintf(error_str, error_str_len, "%s: RDMA ID " 5933268700Smav "must be 32 hex digits (0x prefix " 5934268700Smav "optional), only %zu seen", __func__, id_len); 5935268700Smav } 5936268700Smav retval = 1; 5937268700Smav goto bailout; 5938268700Smav } 5939268700Smav 5940268700Smav tmpstr = id_str; 5941268700Smav /* 5942268700Smav * If the user gave us 34 characters, the string needs to start 5943268700Smav * with '0x'. 5944268700Smav */ 5945268700Smav if (id_len == ((rdma_id_size * 2) + 2)) { 5946268700Smav if ((tmpstr[0] == '0') 5947268700Smav && ((tmpstr[1] == 'x') || (tmpstr[1] == 'X'))) { 5948268700Smav tmpstr += 2; 5949268700Smav } else { 5950268700Smav if (error_str != NULL) { 5951268700Smav snprintf(error_str, error_str_len, "%s: RDMA " 5952268700Smav "ID prefix, if used, must be \"0x\", " 5953268700Smav "got %s", __func__, tmpstr); 5954268700Smav } 5955268700Smav retval = 1; 5956268700Smav goto bailout; 5957268700Smav } 5958268700Smav } 5959268700Smav bzero(rdma_id, sizeof(rdma_id)); 5960268700Smav 5961268700Smav /* 5962268700Smav * Convert ASCII hex into binary bytes. There is no standard 5963268700Smav * 128-bit integer type, and so no strtou128t() routine to convert 5964268700Smav * from hex into a large integer. In the end, we're not going to 5965268700Smav * an integer, but rather to a byte array, so that and the fact 5966268700Smav * that we require the user to give us 32 hex digits simplifies the 5967268700Smav * logic. 5968268700Smav */ 5969268700Smav for (i = 0; i < (rdma_id_size * 2); i++) { 5970268700Smav int cur_shift; 5971268700Smav unsigned char c; 5972268700Smav 5973268700Smav /* Increment the byte array one for every 2 hex digits */ 5974268700Smav j = i >> 1; 5975268700Smav 5976268700Smav /* 5977268700Smav * The first digit in every pair is the most significant 5978268700Smav * 4 bits. The second is the least significant 4 bits. 5979268700Smav */ 5980268700Smav if ((i % 2) == 0) 5981268700Smav cur_shift = 4; 5982268700Smav else 5983268700Smav cur_shift = 0; 5984268700Smav 5985268700Smav c = tmpstr[i]; 5986268700Smav /* Convert the ASCII hex character into a number */ 5987268700Smav if (isdigit(c)) 5988268700Smav c -= '0'; 5989268700Smav else if (isalpha(c)) 5990268700Smav c -= isupper(c) ? 'A' - 10 : 'a' - 10; 5991268700Smav else { 5992268700Smav if (error_str != NULL) { 5993268700Smav snprintf(error_str, error_str_len, "%s: " 5994268700Smav "RDMA ID must be hex digits, got " 5995268700Smav "invalid character %c", __func__, 5996268700Smav tmpstr[i]); 5997268700Smav } 5998268700Smav retval = 1; 5999268700Smav goto bailout; 6000268700Smav } 6001268700Smav /* 6002268700Smav * The converted number can't be less than 0; the type is 6003268700Smav * unsigned, and the subtraction logic will not give us 6004268700Smav * a negative number. So we only need to make sure that 6005268700Smav * the value is not greater than 0xf. (i.e. make sure the 6006268700Smav * user didn't give us a value like "0x12jklmno"). 6007268700Smav */ 6008268700Smav if (c > 0xf) { 6009268700Smav if (error_str != NULL) { 6010268700Smav snprintf(error_str, error_str_len, "%s: " 6011268700Smav "RDMA ID must be hex digits, got " 6012268700Smav "invalid character %c", __func__, 6013268700Smav tmpstr[i]); 6014268700Smav } 6015268700Smav retval = 1; 6016268700Smav goto bailout; 6017268700Smav } 6018268700Smav 6019268700Smav rdma_id[j] |= c << cur_shift; 6020268700Smav } 6021268700Smav 6022268700Smav#ifdef _KERNEL 6023268700Smav rdma = malloc(sizeof(*rdma), type, flags); 6024268700Smav#else 6025268700Smav rdma = malloc(sizeof(*rdma)); 6026268700Smav#endif 6027268700Smav if (rdma == NULL) { 6028268700Smav if (error_str != NULL) { 6029268700Smav snprintf(error_str, error_str_len, "%s: unable to " 6030268700Smav "allocate %zu bytes", __func__, 6031268700Smav sizeof(*rdma)); 6032268700Smav } 6033268700Smav retval = 1; 6034268700Smav goto bailout; 6035268700Smav } 6036268700Smav *alloc_len = sizeof(*rdma); 6037268700Smav bzero(rdma, sizeof(rdma)); 6038268700Smav 6039268700Smav rdma->format_protocol = SCSI_PROTO_RDMA | SCSI_TRN_RDMA_FORMAT_DEFAULT; 6040268700Smav bcopy(rdma_id, rdma->initiator_port_id, SCSI_TRN_RDMA_PORT_LEN); 6041268700Smav 6042268700Smav *hdr = (struct scsi_transportid_header *)rdma; 6043268700Smav 6044268700Smavbailout: 6045268700Smav return (retval); 6046268700Smav} 6047268700Smav 6048268700Smav/* 6049268700Smav * Parse an iSCSI name. The format is either just the name: 6050268700Smav * 6051268700Smav * iqn.2012-06.com.example:target0 6052268700Smav * or the name, separator and initiator session ID: 6053268700Smav * 6054268700Smav * iqn.2012-06.com.example:target0,i,0x123 6055268700Smav * 6056268700Smav * The separator format is exact. 6057268700Smav */ 6058268700Smavint 6059268700Smavscsi_parse_transportid_iscsi(char *id_str, struct scsi_transportid_header **hdr, 6060268700Smav unsigned int *alloc_len, 6061268700Smav#ifdef _KERNEL 6062268700Smav struct malloc_type *type, int flags, 6063268700Smav#endif 6064268700Smav char *error_str, int error_str_len) 6065268700Smav{ 6066268700Smav size_t id_len, sep_len, id_size, name_len; 6067268700Smav int is_full_id, retval; 6068268700Smav unsigned int i, sep_pos, sep_found; 6069268700Smav const char *sep_template = ",i,0x"; 6070268700Smav const char *iqn_prefix = "iqn."; 6071268700Smav struct scsi_transportid_iscsi_device *iscsi; 6072268700Smav 6073268700Smav is_full_id = 0; 6074268700Smav retval = 0; 6075268700Smav sep_found = 0; 6076268700Smav 6077268700Smav id_len = strlen(id_str); 6078268700Smav sep_len = strlen(sep_template); 6079268700Smav 6080268700Smav /* 6081268700Smav * The separator is defined as exactly ',i,0x'. Any other commas, 6082268700Smav * or any other form, is an error. So look for a comma, and once 6083268700Smav * we find that, the next few characters must match the separator 6084268700Smav * exactly. Once we get through the separator, there should be at 6085268700Smav * least one character. 6086268700Smav */ 6087268700Smav for (i = 0, sep_pos = 0; i < id_len; i++) { 6088268700Smav if (sep_pos == 0) { 6089268700Smav if (id_str[i] == sep_template[sep_pos]) 6090268700Smav sep_pos++; 6091268700Smav 6092268700Smav continue; 6093268700Smav } 6094268700Smav if (sep_pos < sep_len) { 6095268700Smav if (id_str[i] == sep_template[sep_pos]) { 6096268700Smav sep_pos++; 6097268700Smav continue; 6098268700Smav } 6099268700Smav if (error_str != NULL) { 6100268700Smav snprintf(error_str, error_str_len, "%s: " 6101268700Smav "invalid separator in iSCSI name " 6102268700Smav "\"%s\"", 6103268700Smav __func__, id_str); 6104268700Smav } 6105268700Smav retval = 1; 6106268700Smav goto bailout; 6107268700Smav } else { 6108268700Smav sep_found = 1; 6109268700Smav break; 6110268700Smav } 6111268700Smav } 6112268700Smav 6113268700Smav /* 6114268700Smav * Check to see whether we have a separator but no digits after it. 6115268700Smav */ 6116268700Smav if ((sep_pos != 0) 6117268700Smav && (sep_found == 0)) { 6118268700Smav if (error_str != NULL) { 6119268700Smav snprintf(error_str, error_str_len, "%s: no digits " 6120268700Smav "found after separator in iSCSI name \"%s\"", 6121268700Smav __func__, id_str); 6122268700Smav } 6123268700Smav retval = 1; 6124268700Smav goto bailout; 6125268700Smav } 6126268700Smav 6127268700Smav /* 6128268700Smav * The incoming ID string has the "iqn." prefix stripped off. We 6129268700Smav * need enough space for the base structure (the structures are the 6130268700Smav * same for the two iSCSI forms), the prefix, the ID string and a 6131268700Smav * terminating NUL. 6132268700Smav */ 6133268700Smav id_size = sizeof(*iscsi) + strlen(iqn_prefix) + id_len + 1; 6134268700Smav 6135268700Smav#ifdef _KERNEL 6136268700Smav iscsi = malloc(id_size, type, flags); 6137268700Smav#else 6138268700Smav iscsi = malloc(id_size); 6139268700Smav#endif 6140268700Smav if (iscsi == NULL) { 6141268700Smav if (error_str != NULL) { 6142268700Smav snprintf(error_str, error_str_len, "%s: unable to " 6143268700Smav "allocate %zu bytes", __func__, id_size); 6144268700Smav } 6145268700Smav retval = 1; 6146268700Smav goto bailout; 6147268700Smav } 6148268700Smav *alloc_len = id_size; 6149268700Smav bzero(iscsi, id_size); 6150268700Smav 6151268700Smav iscsi->format_protocol = SCSI_PROTO_ISCSI; 6152268700Smav if (sep_found == 0) 6153268700Smav iscsi->format_protocol |= SCSI_TRN_ISCSI_FORMAT_DEVICE; 6154268700Smav else 6155268700Smav iscsi->format_protocol |= SCSI_TRN_ISCSI_FORMAT_PORT; 6156268700Smav name_len = id_size - sizeof(*iscsi); 6157268700Smav scsi_ulto2b(name_len, iscsi->additional_length); 6158268700Smav snprintf(iscsi->iscsi_name, name_len, "%s%s", iqn_prefix, id_str); 6159268700Smav 6160268700Smav *hdr = (struct scsi_transportid_header *)iscsi; 6161268700Smav 6162268700Smavbailout: 6163268700Smav return (retval); 6164268700Smav} 6165268700Smav 6166268700Smav/* 6167268700Smav * Parse a SCSI over PCIe (SOP) identifier. The Routing ID can either be 6168268700Smav * of the form 'bus,device,function' or 'bus,function'. 6169268700Smav */ 6170268700Smavint 6171268700Smavscsi_parse_transportid_sop(char *id_str, struct scsi_transportid_header **hdr, 6172268700Smav unsigned int *alloc_len, 6173268700Smav#ifdef _KERNEL 6174268700Smav struct malloc_type *type, int flags, 6175268700Smav#endif 6176268700Smav char *error_str, int error_str_len) 6177268700Smav{ 6178268700Smav struct scsi_transportid_sop *sop; 6179268700Smav unsigned long bus, device, function; 6180268700Smav char *tmpstr, *endptr; 6181268700Smav int retval, device_spec; 6182268700Smav 6183268700Smav retval = 0; 6184268700Smav device_spec = 0; 6185268700Smav device = 0; 6186268700Smav 6187268700Smav tmpstr = strsep(&id_str, ","); 6188268700Smav if ((tmpstr == NULL) 6189268700Smav || (*tmpstr == '\0')) { 6190268700Smav if (error_str != NULL) { 6191268700Smav snprintf(error_str, error_str_len, "%s: no ID found", 6192268700Smav __func__); 6193268700Smav } 6194268700Smav retval = 1; 6195268700Smav goto bailout; 6196268700Smav } 6197268700Smav bus = strtoul(tmpstr, &endptr, 0); 6198268700Smav if (*endptr != '\0') { 6199268700Smav if (error_str != NULL) { 6200268700Smav snprintf(error_str, error_str_len, "%s: error " 6201268700Smav "parsing PCIe bus %s, number required", 6202268700Smav __func__, tmpstr); 6203268700Smav } 6204268700Smav retval = 1; 6205268700Smav goto bailout; 6206268700Smav } 6207268700Smav if ((id_str == NULL) 6208268700Smav || (*id_str == '\0')) { 6209268700Smav if (error_str != NULL) { 6210268700Smav snprintf(error_str, error_str_len, "%s: no PCIe " 6211268700Smav "device or function found", __func__); 6212268700Smav } 6213268700Smav retval = 1; 6214268700Smav goto bailout; 6215268700Smav } 6216268700Smav tmpstr = strsep(&id_str, ","); 6217268700Smav function = strtoul(tmpstr, &endptr, 0); 6218268700Smav if (*endptr != '\0') { 6219268700Smav if (error_str != NULL) { 6220268700Smav snprintf(error_str, error_str_len, "%s: error " 6221268700Smav "parsing PCIe device/function %s, number " 6222268700Smav "required", __func__, tmpstr); 6223268700Smav } 6224268700Smav retval = 1; 6225268700Smav goto bailout; 6226268700Smav } 6227268700Smav /* 6228268700Smav * Check to see whether the user specified a third value. If so, 6229268700Smav * the second is the device. 6230268700Smav */ 6231268700Smav if (id_str != NULL) { 6232268700Smav if (*id_str == '\0') { 6233268700Smav if (error_str != NULL) { 6234268700Smav snprintf(error_str, error_str_len, "%s: " 6235268700Smav "no PCIe function found", __func__); 6236268700Smav } 6237268700Smav retval = 1; 6238268700Smav goto bailout; 6239268700Smav } 6240268700Smav device = function; 6241268700Smav device_spec = 1; 6242268700Smav function = strtoul(id_str, &endptr, 0); 6243268700Smav if (*endptr != '\0') { 6244268700Smav if (error_str != NULL) { 6245268700Smav snprintf(error_str, error_str_len, "%s: " 6246268700Smav "error parsing PCIe function %s, " 6247268700Smav "number required", __func__, id_str); 6248268700Smav } 6249268700Smav retval = 1; 6250268700Smav goto bailout; 6251268700Smav } 6252268700Smav } 6253268700Smav if (bus > SCSI_TRN_SOP_BUS_MAX) { 6254268700Smav if (error_str != NULL) { 6255268700Smav snprintf(error_str, error_str_len, "%s: bus value " 6256268700Smav "%lu greater than maximum %u", __func__, 6257268700Smav bus, SCSI_TRN_SOP_BUS_MAX); 6258268700Smav } 6259268700Smav retval = 1; 6260268700Smav goto bailout; 6261268700Smav } 6262268700Smav 6263268700Smav if ((device_spec != 0) 6264268700Smav && (device > SCSI_TRN_SOP_DEV_MASK)) { 6265268700Smav if (error_str != NULL) { 6266268700Smav snprintf(error_str, error_str_len, "%s: device value " 6267268700Smav "%lu greater than maximum %u", __func__, 6268268700Smav device, SCSI_TRN_SOP_DEV_MAX); 6269268700Smav } 6270268700Smav retval = 1; 6271268700Smav goto bailout; 6272268700Smav } 6273268700Smav 6274268700Smav if (((device_spec != 0) 6275268700Smav && (function > SCSI_TRN_SOP_FUNC_NORM_MAX)) 6276268700Smav || ((device_spec == 0) 6277268700Smav && (function > SCSI_TRN_SOP_FUNC_ALT_MAX))) { 6278268700Smav if (error_str != NULL) { 6279268700Smav snprintf(error_str, error_str_len, "%s: function value " 6280268700Smav "%lu greater than maximum %u", __func__, 6281268700Smav function, (device_spec == 0) ? 6282268700Smav SCSI_TRN_SOP_FUNC_ALT_MAX : 6283268700Smav SCSI_TRN_SOP_FUNC_NORM_MAX); 6284268700Smav } 6285268700Smav retval = 1; 6286268700Smav goto bailout; 6287268700Smav } 6288268700Smav 6289268700Smav#ifdef _KERNEL 6290268700Smav sop = malloc(sizeof(*sop), type, flags); 6291268700Smav#else 6292268700Smav sop = malloc(sizeof(*sop)); 6293268700Smav#endif 6294268700Smav if (sop == NULL) { 6295268700Smav if (error_str != NULL) { 6296268700Smav snprintf(error_str, error_str_len, "%s: unable to " 6297268700Smav "allocate %zu bytes", __func__, sizeof(*sop)); 6298268700Smav } 6299268700Smav retval = 1; 6300268700Smav goto bailout; 6301268700Smav } 6302268700Smav *alloc_len = sizeof(*sop); 6303268700Smav bzero(sop, sizeof(*sop)); 6304268700Smav sop->format_protocol = SCSI_PROTO_SOP | SCSI_TRN_SOP_FORMAT_DEFAULT; 6305268700Smav if (device_spec != 0) { 6306268700Smav struct scsi_sop_routing_id_norm rid; 6307268700Smav 6308268700Smav rid.bus = bus; 6309268700Smav rid.devfunc = (device << SCSI_TRN_SOP_DEV_SHIFT) | function; 6310268700Smav bcopy(&rid, sop->routing_id, MIN(sizeof(rid), 6311268700Smav sizeof(sop->routing_id))); 6312268700Smav } else { 6313268700Smav struct scsi_sop_routing_id_alt rid; 6314268700Smav 6315268700Smav rid.bus = bus; 6316268700Smav rid.function = function; 6317268700Smav bcopy(&rid, sop->routing_id, MIN(sizeof(rid), 6318268700Smav sizeof(sop->routing_id))); 6319268700Smav } 6320268700Smav 6321268700Smav *hdr = (struct scsi_transportid_header *)sop; 6322268700Smavbailout: 6323268700Smav return (retval); 6324268700Smav} 6325268700Smav 6326268700Smav/* 6327268700Smav * transportid_str: NUL-terminated string with format: protcol,id 6328268700Smav * The ID is protocol specific. 6329268700Smav * hdr: Storage will be allocated for the transport ID. 6330268700Smav * alloc_len: The amount of memory allocated is returned here. 6331268700Smav * type: Malloc bucket (kernel only). 6332268700Smav * flags: Malloc flags (kernel only). 6333268700Smav * error_str: If non-NULL, it will contain error information (without 6334268700Smav * a terminating newline) if an error is returned. 6335268700Smav * error_str_len: Allocated length of the error string. 6336268700Smav * 6337268700Smav * Returns 0 for success, non-zero for failure. 6338268700Smav */ 6339268700Smavint 6340268700Smavscsi_parse_transportid(char *transportid_str, 6341268700Smav struct scsi_transportid_header **hdr, 6342268700Smav unsigned int *alloc_len, 6343268700Smav#ifdef _KERNEL 6344268700Smav struct malloc_type *type, int flags, 6345268700Smav#endif 6346268700Smav char *error_str, int error_str_len) 6347268700Smav{ 6348268700Smav char *tmpstr; 6349268700Smav scsi_nv_status status; 6350268700Smav int retval, num_proto_entries, table_entry; 6351268700Smav 6352268700Smav retval = 0; 6353268700Smav table_entry = 0; 6354268700Smav 6355268700Smav /* 6356268700Smav * We do allow a period as well as a comma to separate the protocol 6357268700Smav * from the ID string. This is to accommodate iSCSI names, which 6358268700Smav * start with "iqn.". 6359268700Smav */ 6360268700Smav tmpstr = strsep(&transportid_str, ",."); 6361268700Smav if (tmpstr == NULL) { 6362268700Smav if (error_str != NULL) { 6363268700Smav snprintf(error_str, error_str_len, 6364268700Smav "%s: transportid_str is NULL", __func__); 6365268700Smav } 6366268700Smav retval = 1; 6367268700Smav goto bailout; 6368268700Smav } 6369268700Smav 6370268700Smav num_proto_entries = sizeof(scsi_proto_map) / 6371268700Smav sizeof(scsi_proto_map[0]); 6372268700Smav status = scsi_get_nv(scsi_proto_map, num_proto_entries, tmpstr, 6373268700Smav &table_entry, SCSI_NV_FLAG_IG_CASE); 6374268700Smav if (status != SCSI_NV_FOUND) { 6375268700Smav if (error_str != NULL) { 6376268700Smav snprintf(error_str, error_str_len, "%s: %s protocol " 6377268700Smav "name %s", __func__, 6378268700Smav (status == SCSI_NV_AMBIGUOUS) ? "ambiguous" : 6379268700Smav "invalid", tmpstr); 6380268700Smav } 6381268700Smav retval = 1; 6382268700Smav goto bailout; 6383268700Smav } 6384268700Smav switch (scsi_proto_map[table_entry].value) { 6385268700Smav case SCSI_PROTO_FC: 6386268700Smav case SCSI_PROTO_1394: 6387268700Smav case SCSI_PROTO_SAS: 6388268700Smav retval = scsi_parse_transportid_64bit( 6389268700Smav scsi_proto_map[table_entry].value, transportid_str, hdr, 6390268700Smav alloc_len, 6391268700Smav#ifdef _KERNEL 6392268700Smav type, flags, 6393268700Smav#endif 6394268700Smav error_str, error_str_len); 6395268700Smav break; 6396268700Smav case SCSI_PROTO_SPI: 6397268700Smav retval = scsi_parse_transportid_spi(transportid_str, hdr, 6398268700Smav alloc_len, 6399268700Smav#ifdef _KERNEL 6400268700Smav type, flags, 6401268700Smav#endif 6402268700Smav error_str, error_str_len); 6403268700Smav break; 6404268700Smav case SCSI_PROTO_RDMA: 6405268700Smav retval = scsi_parse_transportid_rdma(transportid_str, hdr, 6406268700Smav alloc_len, 6407268700Smav#ifdef _KERNEL 6408268700Smav type, flags, 6409268700Smav#endif 6410268700Smav error_str, error_str_len); 6411268700Smav break; 6412268700Smav case SCSI_PROTO_ISCSI: 6413268700Smav retval = scsi_parse_transportid_iscsi(transportid_str, hdr, 6414268700Smav alloc_len, 6415268700Smav#ifdef _KERNEL 6416268700Smav type, flags, 6417268700Smav#endif 6418268700Smav error_str, error_str_len); 6419268700Smav break; 6420268700Smav case SCSI_PROTO_SOP: 6421268700Smav retval = scsi_parse_transportid_sop(transportid_str, hdr, 6422268700Smav alloc_len, 6423268700Smav#ifdef _KERNEL 6424268700Smav type, flags, 6425268700Smav#endif 6426268700Smav error_str, error_str_len); 6427268700Smav break; 6428268700Smav case SCSI_PROTO_SSA: 6429268700Smav case SCSI_PROTO_ADITP: 6430268700Smav case SCSI_PROTO_ATA: 6431268700Smav case SCSI_PROTO_UAS: 6432268700Smav case SCSI_PROTO_NONE: 6433268700Smav default: 6434268700Smav /* 6435268700Smav * There is no format defined for a Transport ID for these 6436268700Smav * protocols. So even if the user gives us something, we 6437268700Smav * have no way to turn it into a standard SCSI Transport ID. 6438268700Smav */ 6439268700Smav retval = 1; 6440268700Smav if (error_str != NULL) { 6441268700Smav snprintf(error_str, error_str_len, "%s: no Transport " 6442268700Smav "ID format exists for protocol %s", 6443268700Smav __func__, tmpstr); 6444268700Smav } 6445268700Smav goto bailout; 6446268700Smav break; /* NOTREACHED */ 6447268700Smav } 6448268700Smavbailout: 6449268700Smav return (retval); 6450268700Smav} 6451268700Smav 645239213Sgibbsvoid 645339213Sgibbsscsi_test_unit_ready(struct ccb_scsiio *csio, u_int32_t retries, 645439213Sgibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 645539213Sgibbs u_int8_t tag_action, u_int8_t sense_len, u_int32_t timeout) 645639213Sgibbs{ 645739213Sgibbs struct scsi_test_unit_ready *scsi_cmd; 645839213Sgibbs 645939213Sgibbs cam_fill_csio(csio, 646039213Sgibbs retries, 646139213Sgibbs cbfcnp, 646239213Sgibbs CAM_DIR_NONE, 646339213Sgibbs tag_action, 646439213Sgibbs /*data_ptr*/NULL, 646539213Sgibbs /*dxfer_len*/0, 646639213Sgibbs sense_len, 646739213Sgibbs sizeof(*scsi_cmd), 646839213Sgibbs timeout); 646939213Sgibbs 647039213Sgibbs scsi_cmd = (struct scsi_test_unit_ready *)&csio->cdb_io.cdb_bytes; 647139213Sgibbs bzero(scsi_cmd, sizeof(*scsi_cmd)); 647239213Sgibbs scsi_cmd->opcode = TEST_UNIT_READY; 647339213Sgibbs} 647439213Sgibbs 647539213Sgibbsvoid 647639213Sgibbsscsi_request_sense(struct ccb_scsiio *csio, u_int32_t retries, 647739213Sgibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 647839213Sgibbs void *data_ptr, u_int8_t dxfer_len, u_int8_t tag_action, 647939213Sgibbs u_int8_t sense_len, u_int32_t timeout) 648039213Sgibbs{ 648139213Sgibbs struct scsi_request_sense *scsi_cmd; 648239213Sgibbs 648339213Sgibbs cam_fill_csio(csio, 648439213Sgibbs retries, 648539213Sgibbs cbfcnp, 648639213Sgibbs CAM_DIR_IN, 648739213Sgibbs tag_action, 648839213Sgibbs data_ptr, 648939213Sgibbs dxfer_len, 649039213Sgibbs sense_len, 649139213Sgibbs sizeof(*scsi_cmd), 649239213Sgibbs timeout); 649339213Sgibbs 649439213Sgibbs scsi_cmd = (struct scsi_request_sense *)&csio->cdb_io.cdb_bytes; 649539213Sgibbs bzero(scsi_cmd, sizeof(*scsi_cmd)); 649639213Sgibbs scsi_cmd->opcode = REQUEST_SENSE; 6497120314Sthomas scsi_cmd->length = dxfer_len; 649839213Sgibbs} 649939213Sgibbs 650039213Sgibbsvoid 650139213Sgibbsscsi_inquiry(struct ccb_scsiio *csio, u_int32_t retries, 650239213Sgibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 650339213Sgibbs u_int8_t tag_action, u_int8_t *inq_buf, u_int32_t inq_len, 650439213Sgibbs int evpd, u_int8_t page_code, u_int8_t sense_len, 650539213Sgibbs u_int32_t timeout) 650639213Sgibbs{ 650739213Sgibbs struct scsi_inquiry *scsi_cmd; 650839213Sgibbs 650939213Sgibbs cam_fill_csio(csio, 651039213Sgibbs retries, 651139213Sgibbs cbfcnp, 651239213Sgibbs /*flags*/CAM_DIR_IN, 651339213Sgibbs tag_action, 651439213Sgibbs /*data_ptr*/inq_buf, 651539213Sgibbs /*dxfer_len*/inq_len, 651639213Sgibbs sense_len, 651739213Sgibbs sizeof(*scsi_cmd), 651839213Sgibbs timeout); 651939213Sgibbs 652039213Sgibbs scsi_cmd = (struct scsi_inquiry *)&csio->cdb_io.cdb_bytes; 652139213Sgibbs bzero(scsi_cmd, sizeof(*scsi_cmd)); 652239213Sgibbs scsi_cmd->opcode = INQUIRY; 652339213Sgibbs if (evpd) { 652439213Sgibbs scsi_cmd->byte2 |= SI_EVPD; 652539213Sgibbs scsi_cmd->page_code = page_code; 652639213Sgibbs } 6527229997Sken scsi_ulto2b(inq_len, scsi_cmd->length); 652839213Sgibbs} 652939213Sgibbs 653039213Sgibbsvoid 653139213Sgibbsscsi_mode_sense(struct ccb_scsiio *csio, u_int32_t retries, 653239213Sgibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 653339213Sgibbs u_int8_t tag_action, int dbd, u_int8_t page_code, 653439213Sgibbs u_int8_t page, u_int8_t *param_buf, u_int32_t param_len, 653539213Sgibbs u_int8_t sense_len, u_int32_t timeout) 653639213Sgibbs{ 6537115454Sphk 6538115454Sphk scsi_mode_sense_len(csio, retries, cbfcnp, tag_action, dbd, 6539115454Sphk page_code, page, param_buf, param_len, 0, 6540115454Sphk sense_len, timeout); 6541111206Sken} 6542115454Sphk 6543111206Skenvoid 6544111206Skenscsi_mode_sense_len(struct ccb_scsiio *csio, u_int32_t retries, 6545111206Sken void (*cbfcnp)(struct cam_periph *, union ccb *), 6546111206Sken u_int8_t tag_action, int dbd, u_int8_t page_code, 6547111206Sken u_int8_t page, u_int8_t *param_buf, u_int32_t param_len, 6548111206Sken int minimum_cmd_size, u_int8_t sense_len, u_int32_t timeout) 6549111206Sken{ 655039213Sgibbs u_int8_t cdb_len; 655139213Sgibbs 655239213Sgibbs /* 655339213Sgibbs * Use the smallest possible command to perform the operation. 655439213Sgibbs */ 6555111206Sken if ((param_len < 256) 6556111206Sken && (minimum_cmd_size < 10)) { 655739213Sgibbs /* 655839213Sgibbs * We can fit in a 6 byte cdb. 655939213Sgibbs */ 656039213Sgibbs struct scsi_mode_sense_6 *scsi_cmd; 656139213Sgibbs 656239213Sgibbs scsi_cmd = (struct scsi_mode_sense_6 *)&csio->cdb_io.cdb_bytes; 656339213Sgibbs bzero(scsi_cmd, sizeof(*scsi_cmd)); 656439213Sgibbs scsi_cmd->opcode = MODE_SENSE_6; 656539213Sgibbs if (dbd != 0) 656639213Sgibbs scsi_cmd->byte2 |= SMS_DBD; 656739213Sgibbs scsi_cmd->page = page_code | page; 656839213Sgibbs scsi_cmd->length = param_len; 656939213Sgibbs cdb_len = sizeof(*scsi_cmd); 657039213Sgibbs } else { 657139213Sgibbs /* 657239213Sgibbs * Need a 10 byte cdb. 657339213Sgibbs */ 657439213Sgibbs struct scsi_mode_sense_10 *scsi_cmd; 657539213Sgibbs 657639213Sgibbs scsi_cmd = (struct scsi_mode_sense_10 *)&csio->cdb_io.cdb_bytes; 657739213Sgibbs bzero(scsi_cmd, sizeof(*scsi_cmd)); 657839213Sgibbs scsi_cmd->opcode = MODE_SENSE_10; 657939213Sgibbs if (dbd != 0) 658039213Sgibbs scsi_cmd->byte2 |= SMS_DBD; 658139213Sgibbs scsi_cmd->page = page_code | page; 658239213Sgibbs scsi_ulto2b(param_len, scsi_cmd->length); 658339213Sgibbs cdb_len = sizeof(*scsi_cmd); 658439213Sgibbs } 658539213Sgibbs cam_fill_csio(csio, 658639213Sgibbs retries, 658739213Sgibbs cbfcnp, 658839213Sgibbs CAM_DIR_IN, 658939213Sgibbs tag_action, 659039213Sgibbs param_buf, 659139213Sgibbs param_len, 659239213Sgibbs sense_len, 659339213Sgibbs cdb_len, 659439213Sgibbs timeout); 659539213Sgibbs} 659639213Sgibbs 659739213Sgibbsvoid 659839213Sgibbsscsi_mode_select(struct ccb_scsiio *csio, u_int32_t retries, 659939213Sgibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 660039213Sgibbs u_int8_t tag_action, int scsi_page_fmt, int save_pages, 660139213Sgibbs u_int8_t *param_buf, u_int32_t param_len, u_int8_t sense_len, 660239213Sgibbs u_int32_t timeout) 660339213Sgibbs{ 6604115454Sphk scsi_mode_select_len(csio, retries, cbfcnp, tag_action, 6605115454Sphk scsi_page_fmt, save_pages, param_buf, 6606115454Sphk param_len, 0, sense_len, timeout); 6607111206Sken} 6608111206Sken 6609111206Skenvoid 6610111206Skenscsi_mode_select_len(struct ccb_scsiio *csio, u_int32_t retries, 6611111206Sken void (*cbfcnp)(struct cam_periph *, union ccb *), 6612111206Sken u_int8_t tag_action, int scsi_page_fmt, int save_pages, 6613111206Sken u_int8_t *param_buf, u_int32_t param_len, 6614111206Sken int minimum_cmd_size, u_int8_t sense_len, 6615111206Sken u_int32_t timeout) 6616111206Sken{ 661739213Sgibbs u_int8_t cdb_len; 661839213Sgibbs 661939213Sgibbs /* 662039213Sgibbs * Use the smallest possible command to perform the operation. 662139213Sgibbs */ 6622111206Sken if ((param_len < 256) 6623111206Sken && (minimum_cmd_size < 10)) { 662439213Sgibbs /* 662539213Sgibbs * We can fit in a 6 byte cdb. 662639213Sgibbs */ 662739213Sgibbs struct scsi_mode_select_6 *scsi_cmd; 662839213Sgibbs 662939213Sgibbs scsi_cmd = (struct scsi_mode_select_6 *)&csio->cdb_io.cdb_bytes; 663039213Sgibbs bzero(scsi_cmd, sizeof(*scsi_cmd)); 663139213Sgibbs scsi_cmd->opcode = MODE_SELECT_6; 663239213Sgibbs if (scsi_page_fmt != 0) 663339213Sgibbs scsi_cmd->byte2 |= SMS_PF; 663439213Sgibbs if (save_pages != 0) 663539213Sgibbs scsi_cmd->byte2 |= SMS_SP; 663639213Sgibbs scsi_cmd->length = param_len; 663739213Sgibbs cdb_len = sizeof(*scsi_cmd); 663839213Sgibbs } else { 663939213Sgibbs /* 664039213Sgibbs * Need a 10 byte cdb. 664139213Sgibbs */ 664239213Sgibbs struct scsi_mode_select_10 *scsi_cmd; 664339213Sgibbs 664439213Sgibbs scsi_cmd = 664539213Sgibbs (struct scsi_mode_select_10 *)&csio->cdb_io.cdb_bytes; 664639213Sgibbs bzero(scsi_cmd, sizeof(*scsi_cmd)); 664739213Sgibbs scsi_cmd->opcode = MODE_SELECT_10; 664839213Sgibbs if (scsi_page_fmt != 0) 664939213Sgibbs scsi_cmd->byte2 |= SMS_PF; 665039213Sgibbs if (save_pages != 0) 665139213Sgibbs scsi_cmd->byte2 |= SMS_SP; 665239213Sgibbs scsi_ulto2b(param_len, scsi_cmd->length); 665339213Sgibbs cdb_len = sizeof(*scsi_cmd); 665439213Sgibbs } 665539213Sgibbs cam_fill_csio(csio, 665639213Sgibbs retries, 665739213Sgibbs cbfcnp, 665839213Sgibbs CAM_DIR_OUT, 665939213Sgibbs tag_action, 666039213Sgibbs param_buf, 666139213Sgibbs param_len, 666239213Sgibbs sense_len, 666339213Sgibbs cdb_len, 666439213Sgibbs timeout); 666539213Sgibbs} 666639213Sgibbs 666782384Skbyancvoid 666882384Skbyancscsi_log_sense(struct ccb_scsiio *csio, u_int32_t retries, 666982384Skbyanc void (*cbfcnp)(struct cam_periph *, union ccb *), 667082384Skbyanc u_int8_t tag_action, u_int8_t page_code, u_int8_t page, 667182384Skbyanc int save_pages, int ppc, u_int32_t paramptr, 667282384Skbyanc u_int8_t *param_buf, u_int32_t param_len, u_int8_t sense_len, 667382384Skbyanc u_int32_t timeout) 667482384Skbyanc{ 667582384Skbyanc struct scsi_log_sense *scsi_cmd; 667682384Skbyanc u_int8_t cdb_len; 667739213Sgibbs 667882384Skbyanc scsi_cmd = (struct scsi_log_sense *)&csio->cdb_io.cdb_bytes; 667982384Skbyanc bzero(scsi_cmd, sizeof(*scsi_cmd)); 668082384Skbyanc scsi_cmd->opcode = LOG_SENSE; 668182384Skbyanc scsi_cmd->page = page_code | page; 668282384Skbyanc if (save_pages != 0) 668382384Skbyanc scsi_cmd->byte2 |= SLS_SP; 668482384Skbyanc if (ppc != 0) 668582384Skbyanc scsi_cmd->byte2 |= SLS_PPC; 668682384Skbyanc scsi_ulto2b(paramptr, scsi_cmd->paramptr); 668782384Skbyanc scsi_ulto2b(param_len, scsi_cmd->length); 668882384Skbyanc cdb_len = sizeof(*scsi_cmd); 668982384Skbyanc 669082384Skbyanc cam_fill_csio(csio, 669182384Skbyanc retries, 669282384Skbyanc cbfcnp, 669382384Skbyanc /*flags*/CAM_DIR_IN, 669482384Skbyanc tag_action, 669582384Skbyanc /*data_ptr*/param_buf, 669682384Skbyanc /*dxfer_len*/param_len, 669782384Skbyanc sense_len, 669882384Skbyanc cdb_len, 669982384Skbyanc timeout); 670082384Skbyanc} 670182384Skbyanc 670282384Skbyancvoid 670382384Skbyancscsi_log_select(struct ccb_scsiio *csio, u_int32_t retries, 670482384Skbyanc void (*cbfcnp)(struct cam_periph *, union ccb *), 670582384Skbyanc u_int8_t tag_action, u_int8_t page_code, int save_pages, 670682384Skbyanc int pc_reset, u_int8_t *param_buf, u_int32_t param_len, 670782384Skbyanc u_int8_t sense_len, u_int32_t timeout) 670882384Skbyanc{ 670982384Skbyanc struct scsi_log_select *scsi_cmd; 671082384Skbyanc u_int8_t cdb_len; 671182384Skbyanc 671282384Skbyanc scsi_cmd = (struct scsi_log_select *)&csio->cdb_io.cdb_bytes; 671382384Skbyanc bzero(scsi_cmd, sizeof(*scsi_cmd)); 671482384Skbyanc scsi_cmd->opcode = LOG_SELECT; 671582384Skbyanc scsi_cmd->page = page_code & SLS_PAGE_CODE; 671682384Skbyanc if (save_pages != 0) 671782384Skbyanc scsi_cmd->byte2 |= SLS_SP; 671882384Skbyanc if (pc_reset != 0) 671982384Skbyanc scsi_cmd->byte2 |= SLS_PCR; 672082384Skbyanc scsi_ulto2b(param_len, scsi_cmd->length); 672182384Skbyanc cdb_len = sizeof(*scsi_cmd); 672282384Skbyanc 672382384Skbyanc cam_fill_csio(csio, 672482384Skbyanc retries, 672582384Skbyanc cbfcnp, 672682384Skbyanc /*flags*/CAM_DIR_OUT, 672782384Skbyanc tag_action, 672882384Skbyanc /*data_ptr*/param_buf, 672982384Skbyanc /*dxfer_len*/param_len, 673082384Skbyanc sense_len, 673182384Skbyanc cdb_len, 673282384Skbyanc timeout); 673382384Skbyanc} 673482384Skbyanc 673597825Smjacob/* 673697825Smjacob * Prevent or allow the user to remove the media 673797825Smjacob */ 673897825Smjacobvoid 673997825Smjacobscsi_prevent(struct ccb_scsiio *csio, u_int32_t retries, 674097825Smjacob void (*cbfcnp)(struct cam_periph *, union ccb *), 674197825Smjacob u_int8_t tag_action, u_int8_t action, 674297825Smjacob u_int8_t sense_len, u_int32_t timeout) 674397825Smjacob{ 674497825Smjacob struct scsi_prevent *scsi_cmd; 674597825Smjacob 674697825Smjacob cam_fill_csio(csio, 674797825Smjacob retries, 674897825Smjacob cbfcnp, 674997825Smjacob /*flags*/CAM_DIR_NONE, 675097825Smjacob tag_action, 675197825Smjacob /*data_ptr*/NULL, 675297825Smjacob /*dxfer_len*/0, 675397825Smjacob sense_len, 675497825Smjacob sizeof(*scsi_cmd), 675597825Smjacob timeout); 675697825Smjacob 675797825Smjacob scsi_cmd = (struct scsi_prevent *)&csio->cdb_io.cdb_bytes; 675897825Smjacob bzero(scsi_cmd, sizeof(*scsi_cmd)); 675997825Smjacob scsi_cmd->opcode = PREVENT_ALLOW; 676097825Smjacob scsi_cmd->how = action; 676197825Smjacob} 676297825Smjacob 676339213Sgibbs/* XXX allow specification of address and PMI bit and LBA */ 676439213Sgibbsvoid 676539213Sgibbsscsi_read_capacity(struct ccb_scsiio *csio, u_int32_t retries, 676639213Sgibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 676739213Sgibbs u_int8_t tag_action, 676839213Sgibbs struct scsi_read_capacity_data *rcap_buf, 676939213Sgibbs u_int8_t sense_len, u_int32_t timeout) 677039213Sgibbs{ 677139213Sgibbs struct scsi_read_capacity *scsi_cmd; 677239213Sgibbs 677339213Sgibbs cam_fill_csio(csio, 677439213Sgibbs retries, 677539213Sgibbs cbfcnp, 677639213Sgibbs /*flags*/CAM_DIR_IN, 677739213Sgibbs tag_action, 677839213Sgibbs /*data_ptr*/(u_int8_t *)rcap_buf, 677939213Sgibbs /*dxfer_len*/sizeof(*rcap_buf), 678039213Sgibbs sense_len, 678139213Sgibbs sizeof(*scsi_cmd), 678239213Sgibbs timeout); 678339213Sgibbs 678439213Sgibbs scsi_cmd = (struct scsi_read_capacity *)&csio->cdb_io.cdb_bytes; 678539213Sgibbs bzero(scsi_cmd, sizeof(*scsi_cmd)); 678639213Sgibbs scsi_cmd->opcode = READ_CAPACITY; 678739213Sgibbs} 678839213Sgibbs 678939213Sgibbsvoid 6790114261Skenscsi_read_capacity_16(struct ccb_scsiio *csio, uint32_t retries, 6791114261Sken void (*cbfcnp)(struct cam_periph *, union ccb *), 6792114261Sken uint8_t tag_action, uint64_t lba, int reladr, int pmi, 6793230590Sken uint8_t *rcap_buf, int rcap_buf_len, uint8_t sense_len, 6794230590Sken uint32_t timeout) 6795114261Sken{ 6796114261Sken struct scsi_read_capacity_16 *scsi_cmd; 6797114261Sken 6798114261Sken 6799114261Sken cam_fill_csio(csio, 6800114261Sken retries, 6801114261Sken cbfcnp, 6802114261Sken /*flags*/CAM_DIR_IN, 6803114261Sken tag_action, 6804114261Sken /*data_ptr*/(u_int8_t *)rcap_buf, 6805230590Sken /*dxfer_len*/rcap_buf_len, 6806114261Sken sense_len, 6807114261Sken sizeof(*scsi_cmd), 6808114261Sken timeout); 6809114261Sken scsi_cmd = (struct scsi_read_capacity_16 *)&csio->cdb_io.cdb_bytes; 6810114261Sken bzero(scsi_cmd, sizeof(*scsi_cmd)); 6811114261Sken scsi_cmd->opcode = SERVICE_ACTION_IN; 6812114261Sken scsi_cmd->service_action = SRC16_SERVICE_ACTION; 6813114261Sken scsi_u64to8b(lba, scsi_cmd->addr); 6814230590Sken scsi_ulto4b(rcap_buf_len, scsi_cmd->alloc_len); 6815114261Sken if (pmi) 6816114261Sken reladr |= SRC16_PMI; 6817114261Sken if (reladr) 6818114261Sken reladr |= SRC16_RELADR; 6819114261Sken} 6820114261Sken 6821114261Skenvoid 682297825Smjacobscsi_report_luns(struct ccb_scsiio *csio, u_int32_t retries, 682397825Smjacob void (*cbfcnp)(struct cam_periph *, union ccb *), 6824161506Sken u_int8_t tag_action, u_int8_t select_report, 6825161506Sken struct scsi_report_luns_data *rpl_buf, u_int32_t alloc_len, 6826161506Sken u_int8_t sense_len, u_int32_t timeout) 682739213Sgibbs{ 682897825Smjacob struct scsi_report_luns *scsi_cmd; 682939213Sgibbs 683039213Sgibbs cam_fill_csio(csio, 683139213Sgibbs retries, 683239213Sgibbs cbfcnp, 683397825Smjacob /*flags*/CAM_DIR_IN, 683439213Sgibbs tag_action, 683597825Smjacob /*data_ptr*/(u_int8_t *)rpl_buf, 683697825Smjacob /*dxfer_len*/alloc_len, 683739213Sgibbs sense_len, 683839213Sgibbs sizeof(*scsi_cmd), 683939213Sgibbs timeout); 684097825Smjacob scsi_cmd = (struct scsi_report_luns *)&csio->cdb_io.cdb_bytes; 684139213Sgibbs bzero(scsi_cmd, sizeof(*scsi_cmd)); 684297825Smjacob scsi_cmd->opcode = REPORT_LUNS; 6843161506Sken scsi_cmd->select_report = select_report; 6844161506Sken scsi_ulto4b(alloc_len, scsi_cmd->length); 684539213Sgibbs} 684639213Sgibbs 6847208905Smjacobvoid 6848208905Smjacobscsi_report_target_group(struct ccb_scsiio *csio, u_int32_t retries, 6849208905Smjacob void (*cbfcnp)(struct cam_periph *, union ccb *), 6850208905Smjacob u_int8_t tag_action, u_int8_t pdf, 6851208905Smjacob void *buf, u_int32_t alloc_len, 6852208905Smjacob u_int8_t sense_len, u_int32_t timeout) 6853208905Smjacob{ 6854208905Smjacob struct scsi_target_group *scsi_cmd; 6855208905Smjacob 6856208905Smjacob cam_fill_csio(csio, 6857208905Smjacob retries, 6858208905Smjacob cbfcnp, 6859208905Smjacob /*flags*/CAM_DIR_IN, 6860208905Smjacob tag_action, 6861208905Smjacob /*data_ptr*/(u_int8_t *)buf, 6862208905Smjacob /*dxfer_len*/alloc_len, 6863208905Smjacob sense_len, 6864208905Smjacob sizeof(*scsi_cmd), 6865208905Smjacob timeout); 6866208905Smjacob scsi_cmd = (struct scsi_target_group *)&csio->cdb_io.cdb_bytes; 6867208905Smjacob bzero(scsi_cmd, sizeof(*scsi_cmd)); 6868208905Smjacob scsi_cmd->opcode = MAINTENANCE_IN; 6869208905Smjacob scsi_cmd->service_action = REPORT_TARGET_PORT_GROUPS | pdf; 6870208905Smjacob scsi_ulto4b(alloc_len, scsi_cmd->length); 6871208905Smjacob} 6872208905Smjacob 6873208905Smjacobvoid 6874208905Smjacobscsi_set_target_group(struct ccb_scsiio *csio, u_int32_t retries, 6875208905Smjacob void (*cbfcnp)(struct cam_periph *, union ccb *), 6876208905Smjacob u_int8_t tag_action, void *buf, u_int32_t alloc_len, 6877208905Smjacob u_int8_t sense_len, u_int32_t timeout) 6878208905Smjacob{ 6879208905Smjacob struct scsi_target_group *scsi_cmd; 6880208905Smjacob 6881208905Smjacob cam_fill_csio(csio, 6882208905Smjacob retries, 6883208905Smjacob cbfcnp, 6884208905Smjacob /*flags*/CAM_DIR_OUT, 6885208905Smjacob tag_action, 6886208905Smjacob /*data_ptr*/(u_int8_t *)buf, 6887208905Smjacob /*dxfer_len*/alloc_len, 6888208905Smjacob sense_len, 6889208905Smjacob sizeof(*scsi_cmd), 6890208905Smjacob timeout); 6891208905Smjacob scsi_cmd = (struct scsi_target_group *)&csio->cdb_io.cdb_bytes; 6892208905Smjacob bzero(scsi_cmd, sizeof(*scsi_cmd)); 6893208905Smjacob scsi_cmd->opcode = MAINTENANCE_OUT; 6894208905Smjacob scsi_cmd->service_action = SET_TARGET_PORT_GROUPS; 6895208905Smjacob scsi_ulto4b(alloc_len, scsi_cmd->length); 6896208905Smjacob} 6897208905Smjacob 689839213Sgibbs/* 689939213Sgibbs * Syncronize the media to the contents of the cache for 690039213Sgibbs * the given lba/count pair. Specifying 0/0 means sync 690139213Sgibbs * the whole cache. 690239213Sgibbs */ 690339213Sgibbsvoid 690439213Sgibbsscsi_synchronize_cache(struct ccb_scsiio *csio, u_int32_t retries, 690539213Sgibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 690639213Sgibbs u_int8_t tag_action, u_int32_t begin_lba, 690739213Sgibbs u_int16_t lb_count, u_int8_t sense_len, 690839213Sgibbs u_int32_t timeout) 690939213Sgibbs{ 691039213Sgibbs struct scsi_sync_cache *scsi_cmd; 691139213Sgibbs 691239213Sgibbs cam_fill_csio(csio, 691339213Sgibbs retries, 691439213Sgibbs cbfcnp, 691539213Sgibbs /*flags*/CAM_DIR_NONE, 691639213Sgibbs tag_action, 691739213Sgibbs /*data_ptr*/NULL, 691839213Sgibbs /*dxfer_len*/0, 691939213Sgibbs sense_len, 692039213Sgibbs sizeof(*scsi_cmd), 692139213Sgibbs timeout); 692239213Sgibbs 692339213Sgibbs scsi_cmd = (struct scsi_sync_cache *)&csio->cdb_io.cdb_bytes; 692439213Sgibbs bzero(scsi_cmd, sizeof(*scsi_cmd)); 692539213Sgibbs scsi_cmd->opcode = SYNCHRONIZE_CACHE; 692639213Sgibbs scsi_ulto4b(begin_lba, scsi_cmd->begin_lba); 692739213Sgibbs scsi_ulto2b(lb_count, scsi_cmd->lb_count); 692839213Sgibbs} 692939213Sgibbs 693039466Skenvoid 693139466Skenscsi_read_write(struct ccb_scsiio *csio, u_int32_t retries, 693239466Sken void (*cbfcnp)(struct cam_periph *, union ccb *), 693339466Sken u_int8_t tag_action, int readop, u_int8_t byte2, 6934114261Sken int minimum_cmd_size, u_int64_t lba, u_int32_t block_count, 693539466Sken u_int8_t *data_ptr, u_int32_t dxfer_len, u_int8_t sense_len, 693639466Sken u_int32_t timeout) 693739466Sken{ 6938248519Skib int read; 693939466Sken u_int8_t cdb_len; 6940248519Skib 6941248519Skib read = (readop & SCSI_RW_DIRMASK) == SCSI_RW_READ; 6942248519Skib 694339466Sken /* 694439466Sken * Use the smallest possible command to perform the operation 694586161Skbyanc * as some legacy hardware does not support the 10 byte commands. 694686161Skbyanc * If any of the bits in byte2 is set, we have to go with a larger 694786161Skbyanc * command. 694839466Sken */ 694939466Sken if ((minimum_cmd_size < 10) 695039466Sken && ((lba & 0x1fffff) == lba) 695139466Sken && ((block_count & 0xff) == block_count) 695286161Skbyanc && (byte2 == 0)) { 695339466Sken /* 695439466Sken * We can fit in a 6 byte cdb. 695539466Sken */ 695639466Sken struct scsi_rw_6 *scsi_cmd; 695739466Sken 695839466Sken scsi_cmd = (struct scsi_rw_6 *)&csio->cdb_io.cdb_bytes; 6959248519Skib scsi_cmd->opcode = read ? READ_6 : WRITE_6; 696039466Sken scsi_ulto3b(lba, scsi_cmd->addr); 696139466Sken scsi_cmd->length = block_count & 0xff; 696239466Sken scsi_cmd->control = 0; 696339466Sken cdb_len = sizeof(*scsi_cmd); 696439466Sken 696539466Sken CAM_DEBUG(csio->ccb_h.path, CAM_DEBUG_SUBTRACE, 696639466Sken ("6byte: %x%x%x:%d:%d\n", scsi_cmd->addr[0], 696739466Sken scsi_cmd->addr[1], scsi_cmd->addr[2], 696839466Sken scsi_cmd->length, dxfer_len)); 696939466Sken } else if ((minimum_cmd_size < 12) 6970114261Sken && ((block_count & 0xffff) == block_count) 6971114261Sken && ((lba & 0xffffffff) == lba)) { 697239466Sken /* 697339466Sken * Need a 10 byte cdb. 697439466Sken */ 697539466Sken struct scsi_rw_10 *scsi_cmd; 697639466Sken 697739466Sken scsi_cmd = (struct scsi_rw_10 *)&csio->cdb_io.cdb_bytes; 6978248519Skib scsi_cmd->opcode = read ? READ_10 : WRITE_10; 697939466Sken scsi_cmd->byte2 = byte2; 698039466Sken scsi_ulto4b(lba, scsi_cmd->addr); 698139466Sken scsi_cmd->reserved = 0; 698239466Sken scsi_ulto2b(block_count, scsi_cmd->length); 698339466Sken scsi_cmd->control = 0; 698439466Sken cdb_len = sizeof(*scsi_cmd); 698539466Sken 698639466Sken CAM_DEBUG(csio->ccb_h.path, CAM_DEBUG_SUBTRACE, 698739466Sken ("10byte: %x%x%x%x:%x%x: %d\n", scsi_cmd->addr[0], 698839466Sken scsi_cmd->addr[1], scsi_cmd->addr[2], 698939466Sken scsi_cmd->addr[3], scsi_cmd->length[0], 699039466Sken scsi_cmd->length[1], dxfer_len)); 6991114261Sken } else if ((minimum_cmd_size < 16) 6992114261Sken && ((block_count & 0xffffffff) == block_count) 6993114261Sken && ((lba & 0xffffffff) == lba)) { 699439466Sken /* 699539466Sken * The block count is too big for a 10 byte CDB, use a 12 6996114261Sken * byte CDB. 699739466Sken */ 699839466Sken struct scsi_rw_12 *scsi_cmd; 699939466Sken 700039466Sken scsi_cmd = (struct scsi_rw_12 *)&csio->cdb_io.cdb_bytes; 7001248519Skib scsi_cmd->opcode = read ? READ_12 : WRITE_12; 700239466Sken scsi_cmd->byte2 = byte2; 700339466Sken scsi_ulto4b(lba, scsi_cmd->addr); 700439466Sken scsi_cmd->reserved = 0; 700539466Sken scsi_ulto4b(block_count, scsi_cmd->length); 700639466Sken scsi_cmd->control = 0; 700739466Sken cdb_len = sizeof(*scsi_cmd); 700839466Sken 700939466Sken CAM_DEBUG(csio->ccb_h.path, CAM_DEBUG_SUBTRACE, 701039466Sken ("12byte: %x%x%x%x:%x%x%x%x: %d\n", scsi_cmd->addr[0], 701139466Sken scsi_cmd->addr[1], scsi_cmd->addr[2], 701239466Sken scsi_cmd->addr[3], scsi_cmd->length[0], 701339466Sken scsi_cmd->length[1], scsi_cmd->length[2], 701439466Sken scsi_cmd->length[3], dxfer_len)); 7015114261Sken } else { 7016114261Sken /* 7017114261Sken * 16 byte CDB. We'll only get here if the LBA is larger 7018114261Sken * than 2^32, or if the user asks for a 16 byte command. 7019114261Sken */ 7020114261Sken struct scsi_rw_16 *scsi_cmd; 7021114261Sken 7022114261Sken scsi_cmd = (struct scsi_rw_16 *)&csio->cdb_io.cdb_bytes; 7023248519Skib scsi_cmd->opcode = read ? READ_16 : WRITE_16; 7024114261Sken scsi_cmd->byte2 = byte2; 7025114261Sken scsi_u64to8b(lba, scsi_cmd->addr); 7026114261Sken scsi_cmd->reserved = 0; 7027114261Sken scsi_ulto4b(block_count, scsi_cmd->length); 7028114261Sken scsi_cmd->control = 0; 7029114261Sken cdb_len = sizeof(*scsi_cmd); 703039466Sken } 703139466Sken cam_fill_csio(csio, 703239466Sken retries, 703339466Sken cbfcnp, 7034248519Skib (read ? CAM_DIR_IN : CAM_DIR_OUT) | 7035248519Skib ((readop & SCSI_RW_BIO) != 0 ? CAM_DATA_BIO : 0), 703639466Sken tag_action, 703739466Sken data_ptr, 703839466Sken dxfer_len, 703939466Sken sense_len, 704039466Sken cdb_len, 704139466Sken timeout); 704239466Sken} 704339466Sken 7044223081Sgibbsvoid 7045230053Smavscsi_write_same(struct ccb_scsiio *csio, u_int32_t retries, 7046230053Smav void (*cbfcnp)(struct cam_periph *, union ccb *), 7047230053Smav u_int8_t tag_action, u_int8_t byte2, 7048230053Smav int minimum_cmd_size, u_int64_t lba, u_int32_t block_count, 7049230053Smav u_int8_t *data_ptr, u_int32_t dxfer_len, u_int8_t sense_len, 7050230053Smav u_int32_t timeout) 7051230053Smav{ 7052230053Smav u_int8_t cdb_len; 7053230053Smav if ((minimum_cmd_size < 16) && 7054230053Smav ((block_count & 0xffff) == block_count) && 7055230053Smav ((lba & 0xffffffff) == lba)) { 7056230053Smav /* 7057230053Smav * Need a 10 byte cdb. 7058230053Smav */ 7059230053Smav struct scsi_write_same_10 *scsi_cmd; 7060230053Smav 7061230053Smav scsi_cmd = (struct scsi_write_same_10 *)&csio->cdb_io.cdb_bytes; 7062230053Smav scsi_cmd->opcode = WRITE_SAME_10; 7063230053Smav scsi_cmd->byte2 = byte2; 7064230053Smav scsi_ulto4b(lba, scsi_cmd->addr); 7065230053Smav scsi_cmd->group = 0; 7066230053Smav scsi_ulto2b(block_count, scsi_cmd->length); 7067230053Smav scsi_cmd->control = 0; 7068230053Smav cdb_len = sizeof(*scsi_cmd); 7069230053Smav 7070230053Smav CAM_DEBUG(csio->ccb_h.path, CAM_DEBUG_SUBTRACE, 7071230053Smav ("10byte: %x%x%x%x:%x%x: %d\n", scsi_cmd->addr[0], 7072230053Smav scsi_cmd->addr[1], scsi_cmd->addr[2], 7073230053Smav scsi_cmd->addr[3], scsi_cmd->length[0], 7074230053Smav scsi_cmd->length[1], dxfer_len)); 7075230053Smav } else { 7076230053Smav /* 7077230053Smav * 16 byte CDB. We'll only get here if the LBA is larger 7078230053Smav * than 2^32, or if the user asks for a 16 byte command. 7079230053Smav */ 7080230053Smav struct scsi_write_same_16 *scsi_cmd; 7081230053Smav 7082230053Smav scsi_cmd = (struct scsi_write_same_16 *)&csio->cdb_io.cdb_bytes; 7083230053Smav scsi_cmd->opcode = WRITE_SAME_16; 7084230053Smav scsi_cmd->byte2 = byte2; 7085230053Smav scsi_u64to8b(lba, scsi_cmd->addr); 7086230053Smav scsi_ulto4b(block_count, scsi_cmd->length); 7087230053Smav scsi_cmd->group = 0; 7088230053Smav scsi_cmd->control = 0; 7089230053Smav cdb_len = sizeof(*scsi_cmd); 7090230053Smav 7091230053Smav CAM_DEBUG(csio->ccb_h.path, CAM_DEBUG_SUBTRACE, 7092230053Smav ("16byte: %x%x%x%x%x%x%x%x:%x%x%x%x: %d\n", 7093230053Smav scsi_cmd->addr[0], scsi_cmd->addr[1], 7094230053Smav scsi_cmd->addr[2], scsi_cmd->addr[3], 7095230053Smav scsi_cmd->addr[4], scsi_cmd->addr[5], 7096230053Smav scsi_cmd->addr[6], scsi_cmd->addr[7], 7097230053Smav scsi_cmd->length[0], scsi_cmd->length[1], 7098230053Smav scsi_cmd->length[2], scsi_cmd->length[3], 7099230053Smav dxfer_len)); 7100230053Smav } 7101230053Smav cam_fill_csio(csio, 7102230053Smav retries, 7103230053Smav cbfcnp, 7104230053Smav /*flags*/CAM_DIR_OUT, 7105230053Smav tag_action, 7106230053Smav data_ptr, 7107230053Smav dxfer_len, 7108230053Smav sense_len, 7109230053Smav cdb_len, 7110230053Smav timeout); 7111230053Smav} 7112230053Smav 7113230053Smavvoid 7114249933Ssmhscsi_ata_identify(struct ccb_scsiio *csio, u_int32_t retries, 7115249933Ssmh void (*cbfcnp)(struct cam_periph *, union ccb *), 7116249933Ssmh u_int8_t tag_action, u_int8_t *data_ptr, 7117249933Ssmh u_int16_t dxfer_len, u_int8_t sense_len, 7118249933Ssmh u_int32_t timeout) 7119249933Ssmh{ 7120249933Ssmh scsi_ata_pass_16(csio, 7121249933Ssmh retries, 7122249933Ssmh cbfcnp, 7123249933Ssmh /*flags*/CAM_DIR_IN, 7124249933Ssmh tag_action, 7125249933Ssmh /*protocol*/AP_PROTO_PIO_IN, 7126249933Ssmh /*ata_flags*/AP_FLAG_TDIR_FROM_DEV| 7127249933Ssmh AP_FLAG_BYT_BLOK_BYTES|AP_FLAG_TLEN_SECT_CNT, 7128249933Ssmh /*features*/0, 7129249933Ssmh /*sector_count*/dxfer_len, 7130249933Ssmh /*lba*/0, 7131249933Ssmh /*command*/ATA_ATA_IDENTIFY, 7132249933Ssmh /*control*/0, 7133249933Ssmh data_ptr, 7134249933Ssmh dxfer_len, 7135249933Ssmh sense_len, 7136249933Ssmh timeout); 7137249933Ssmh} 7138249933Ssmh 7139249933Ssmhvoid 7140249933Ssmhscsi_ata_trim(struct ccb_scsiio *csio, u_int32_t retries, 7141249933Ssmh void (*cbfcnp)(struct cam_periph *, union ccb *), 7142249933Ssmh u_int8_t tag_action, u_int16_t block_count, 7143249933Ssmh u_int8_t *data_ptr, u_int16_t dxfer_len, u_int8_t sense_len, 7144249933Ssmh u_int32_t timeout) 7145249933Ssmh{ 7146249933Ssmh scsi_ata_pass_16(csio, 7147249933Ssmh retries, 7148249933Ssmh cbfcnp, 7149249933Ssmh /*flags*/CAM_DIR_OUT, 7150249933Ssmh tag_action, 7151249933Ssmh /*protocol*/AP_EXTEND|AP_PROTO_DMA, 7152249933Ssmh /*ata_flags*/AP_FLAG_TLEN_SECT_CNT|AP_FLAG_BYT_BLOK_BLOCKS, 7153249933Ssmh /*features*/ATA_DSM_TRIM, 7154249933Ssmh /*sector_count*/block_count, 7155249933Ssmh /*lba*/0, 7156249933Ssmh /*command*/ATA_DATA_SET_MANAGEMENT, 7157249933Ssmh /*control*/0, 7158249933Ssmh data_ptr, 7159249933Ssmh dxfer_len, 7160249933Ssmh sense_len, 7161249933Ssmh timeout); 7162249933Ssmh} 7163249933Ssmh 7164249933Ssmhvoid 7165248992Ssmhscsi_ata_pass_16(struct ccb_scsiio *csio, u_int32_t retries, 7166248992Ssmh void (*cbfcnp)(struct cam_periph *, union ccb *), 7167248992Ssmh u_int32_t flags, u_int8_t tag_action, 7168248992Ssmh u_int8_t protocol, u_int8_t ata_flags, u_int16_t features, 7169248992Ssmh u_int16_t sector_count, uint64_t lba, u_int8_t command, 7170248992Ssmh u_int8_t control, u_int8_t *data_ptr, u_int16_t dxfer_len, 7171248992Ssmh u_int8_t sense_len, u_int32_t timeout) 7172248992Ssmh{ 7173248992Ssmh struct ata_pass_16 *ata_cmd; 7174248992Ssmh 7175248992Ssmh ata_cmd = (struct ata_pass_16 *)&csio->cdb_io.cdb_bytes; 7176248992Ssmh ata_cmd->opcode = ATA_PASS_16; 7177248992Ssmh ata_cmd->protocol = protocol; 7178248992Ssmh ata_cmd->flags = ata_flags; 7179248992Ssmh ata_cmd->features_ext = features >> 8; 7180248992Ssmh ata_cmd->features = features; 7181248992Ssmh ata_cmd->sector_count_ext = sector_count >> 8; 7182248992Ssmh ata_cmd->sector_count = sector_count; 7183248992Ssmh ata_cmd->lba_low = lba; 7184248992Ssmh ata_cmd->lba_mid = lba >> 8; 7185248992Ssmh ata_cmd->lba_high = lba >> 16; 7186248992Ssmh ata_cmd->device = ATA_DEV_LBA; 7187248992Ssmh if (protocol & AP_EXTEND) { 7188248992Ssmh ata_cmd->lba_low_ext = lba >> 24; 7189248992Ssmh ata_cmd->lba_mid_ext = lba >> 32; 7190248992Ssmh ata_cmd->lba_high_ext = lba >> 40; 7191248992Ssmh } else 7192248992Ssmh ata_cmd->device |= (lba >> 24) & 0x0f; 7193248992Ssmh ata_cmd->command = command; 7194248992Ssmh ata_cmd->control = control; 7195248992Ssmh 7196248992Ssmh cam_fill_csio(csio, 7197248992Ssmh retries, 7198248992Ssmh cbfcnp, 7199248992Ssmh flags, 7200248992Ssmh tag_action, 7201248992Ssmh data_ptr, 7202248992Ssmh dxfer_len, 7203248992Ssmh sense_len, 7204248992Ssmh sizeof(*ata_cmd), 7205248992Ssmh timeout); 7206248992Ssmh} 7207248992Ssmh 7208248992Ssmhvoid 7209230053Smavscsi_unmap(struct ccb_scsiio *csio, u_int32_t retries, 7210230053Smav void (*cbfcnp)(struct cam_periph *, union ccb *), 7211230053Smav u_int8_t tag_action, u_int8_t byte2, 7212230053Smav u_int8_t *data_ptr, u_int16_t dxfer_len, u_int8_t sense_len, 7213230053Smav u_int32_t timeout) 7214230053Smav{ 7215230053Smav struct scsi_unmap *scsi_cmd; 7216230053Smav 7217230053Smav scsi_cmd = (struct scsi_unmap *)&csio->cdb_io.cdb_bytes; 7218230053Smav scsi_cmd->opcode = UNMAP; 7219230053Smav scsi_cmd->byte2 = byte2; 7220230053Smav scsi_ulto4b(0, scsi_cmd->reserved); 7221230053Smav scsi_cmd->group = 0; 7222230053Smav scsi_ulto2b(dxfer_len, scsi_cmd->length); 7223230053Smav scsi_cmd->control = 0; 7224230053Smav 7225230053Smav cam_fill_csio(csio, 7226230053Smav retries, 7227230053Smav cbfcnp, 7228230053Smav /*flags*/CAM_DIR_OUT, 7229230053Smav tag_action, 7230230053Smav data_ptr, 7231230053Smav dxfer_len, 7232230053Smav sense_len, 7233230053Smav sizeof(*scsi_cmd), 7234230053Smav timeout); 7235230053Smav} 7236230053Smav 7237230053Smavvoid 7238223081Sgibbsscsi_receive_diagnostic_results(struct ccb_scsiio *csio, u_int32_t retries, 7239223081Sgibbs void (*cbfcnp)(struct cam_periph *, union ccb*), 7240223081Sgibbs uint8_t tag_action, int pcv, uint8_t page_code, 7241223081Sgibbs uint8_t *data_ptr, uint16_t allocation_length, 7242223081Sgibbs uint8_t sense_len, uint32_t timeout) 7243223081Sgibbs{ 7244223081Sgibbs struct scsi_receive_diag *scsi_cmd; 7245223081Sgibbs 7246223081Sgibbs scsi_cmd = (struct scsi_receive_diag *)&csio->cdb_io.cdb_bytes; 7247223081Sgibbs memset(scsi_cmd, 0, sizeof(*scsi_cmd)); 7248223081Sgibbs scsi_cmd->opcode = RECEIVE_DIAGNOSTIC; 7249223081Sgibbs if (pcv) { 7250223081Sgibbs scsi_cmd->byte2 |= SRD_PCV; 7251223081Sgibbs scsi_cmd->page_code = page_code; 7252223081Sgibbs } 7253223081Sgibbs scsi_ulto2b(allocation_length, scsi_cmd->length); 7254223081Sgibbs 7255223081Sgibbs cam_fill_csio(csio, 7256223081Sgibbs retries, 7257223081Sgibbs cbfcnp, 7258223081Sgibbs /*flags*/CAM_DIR_IN, 7259223081Sgibbs tag_action, 7260223081Sgibbs data_ptr, 7261223081Sgibbs allocation_length, 7262223081Sgibbs sense_len, 7263223081Sgibbs sizeof(*scsi_cmd), 7264223081Sgibbs timeout); 7265223081Sgibbs} 7266223081Sgibbs 7267223081Sgibbsvoid 7268223081Sgibbsscsi_send_diagnostic(struct ccb_scsiio *csio, u_int32_t retries, 7269223081Sgibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 7270223081Sgibbs uint8_t tag_action, int unit_offline, int device_offline, 7271223081Sgibbs int self_test, int page_format, int self_test_code, 7272223081Sgibbs uint8_t *data_ptr, uint16_t param_list_length, 7273223081Sgibbs uint8_t sense_len, uint32_t timeout) 7274223081Sgibbs{ 7275223081Sgibbs struct scsi_send_diag *scsi_cmd; 7276223081Sgibbs 7277223081Sgibbs scsi_cmd = (struct scsi_send_diag *)&csio->cdb_io.cdb_bytes; 7278223081Sgibbs memset(scsi_cmd, 0, sizeof(*scsi_cmd)); 7279223081Sgibbs scsi_cmd->opcode = SEND_DIAGNOSTIC; 7280223081Sgibbs 7281223081Sgibbs /* 7282223081Sgibbs * The default self-test mode control and specific test 7283223081Sgibbs * control are mutually exclusive. 7284223081Sgibbs */ 7285223081Sgibbs if (self_test) 7286223081Sgibbs self_test_code = SSD_SELF_TEST_CODE_NONE; 7287223081Sgibbs 7288223081Sgibbs scsi_cmd->byte2 = ((self_test_code << SSD_SELF_TEST_CODE_SHIFT) 7289223081Sgibbs & SSD_SELF_TEST_CODE_MASK) 7290223081Sgibbs | (unit_offline ? SSD_UNITOFFL : 0) 7291223081Sgibbs | (device_offline ? SSD_DEVOFFL : 0) 7292223081Sgibbs | (self_test ? SSD_SELFTEST : 0) 7293223081Sgibbs | (page_format ? SSD_PF : 0); 7294223081Sgibbs scsi_ulto2b(param_list_length, scsi_cmd->length); 7295223081Sgibbs 7296223081Sgibbs cam_fill_csio(csio, 7297223081Sgibbs retries, 7298223081Sgibbs cbfcnp, 7299223081Sgibbs /*flags*/param_list_length ? CAM_DIR_OUT : CAM_DIR_NONE, 7300223081Sgibbs tag_action, 7301223081Sgibbs data_ptr, 7302223081Sgibbs param_list_length, 7303223081Sgibbs sense_len, 7304223081Sgibbs sizeof(*scsi_cmd), 7305223081Sgibbs timeout); 7306223081Sgibbs} 7307223081Sgibbs 7308235897Smavvoid 7309235897Smavscsi_read_buffer(struct ccb_scsiio *csio, u_int32_t retries, 7310235897Smav void (*cbfcnp)(struct cam_periph *, union ccb*), 7311235897Smav uint8_t tag_action, int mode, 7312235897Smav uint8_t buffer_id, u_int32_t offset, 7313235897Smav uint8_t *data_ptr, uint32_t allocation_length, 7314235897Smav uint8_t sense_len, uint32_t timeout) 7315235897Smav{ 7316235897Smav struct scsi_read_buffer *scsi_cmd; 7317235897Smav 7318235897Smav scsi_cmd = (struct scsi_read_buffer *)&csio->cdb_io.cdb_bytes; 7319235897Smav memset(scsi_cmd, 0, sizeof(*scsi_cmd)); 7320235897Smav scsi_cmd->opcode = READ_BUFFER; 7321235897Smav scsi_cmd->byte2 = mode; 7322235897Smav scsi_cmd->buffer_id = buffer_id; 7323235897Smav scsi_ulto3b(offset, scsi_cmd->offset); 7324235897Smav scsi_ulto3b(allocation_length, scsi_cmd->length); 7325235897Smav 7326235897Smav cam_fill_csio(csio, 7327235897Smav retries, 7328235897Smav cbfcnp, 7329235897Smav /*flags*/CAM_DIR_IN, 7330235897Smav tag_action, 7331235897Smav data_ptr, 7332235897Smav allocation_length, 7333235897Smav sense_len, 7334235897Smav sizeof(*scsi_cmd), 7335235897Smav timeout); 7336235897Smav} 7337235897Smav 7338235897Smavvoid 7339235897Smavscsi_write_buffer(struct ccb_scsiio *csio, u_int32_t retries, 7340235897Smav void (*cbfcnp)(struct cam_periph *, union ccb *), 7341235897Smav uint8_t tag_action, int mode, 7342235897Smav uint8_t buffer_id, u_int32_t offset, 7343235897Smav uint8_t *data_ptr, uint32_t param_list_length, 7344235897Smav uint8_t sense_len, uint32_t timeout) 7345235897Smav{ 7346235897Smav struct scsi_write_buffer *scsi_cmd; 7347235897Smav 7348235897Smav scsi_cmd = (struct scsi_write_buffer *)&csio->cdb_io.cdb_bytes; 7349235897Smav memset(scsi_cmd, 0, sizeof(*scsi_cmd)); 7350235897Smav scsi_cmd->opcode = WRITE_BUFFER; 7351235897Smav scsi_cmd->byte2 = mode; 7352235897Smav scsi_cmd->buffer_id = buffer_id; 7353235897Smav scsi_ulto3b(offset, scsi_cmd->offset); 7354235897Smav scsi_ulto3b(param_list_length, scsi_cmd->length); 7355235897Smav 7356235897Smav cam_fill_csio(csio, 7357235897Smav retries, 7358235897Smav cbfcnp, 7359235897Smav /*flags*/param_list_length ? CAM_DIR_OUT : CAM_DIR_NONE, 7360235897Smav tag_action, 7361235897Smav data_ptr, 7362235897Smav param_list_length, 7363235897Smav sense_len, 7364235897Smav sizeof(*scsi_cmd), 7365235897Smav timeout); 7366235897Smav} 7367235897Smav 736839466Skenvoid 736939466Skenscsi_start_stop(struct ccb_scsiio *csio, u_int32_t retries, 737039466Sken void (*cbfcnp)(struct cam_periph *, union ccb *), 737139466Sken u_int8_t tag_action, int start, int load_eject, 737239466Sken int immediate, u_int8_t sense_len, u_int32_t timeout) 737339466Sken{ 737439466Sken struct scsi_start_stop_unit *scsi_cmd; 737539466Sken int extra_flags = 0; 737639466Sken 737739466Sken scsi_cmd = (struct scsi_start_stop_unit *)&csio->cdb_io.cdb_bytes; 737839466Sken bzero(scsi_cmd, sizeof(*scsi_cmd)); 737939466Sken scsi_cmd->opcode = START_STOP_UNIT; 738039466Sken if (start != 0) { 738176153Sken scsi_cmd->how |= SSS_START; 738239466Sken /* it takes a lot of power to start a drive */ 738339466Sken extra_flags |= CAM_HIGH_POWER; 738439466Sken } 738539466Sken if (load_eject != 0) 738639466Sken scsi_cmd->how |= SSS_LOEJ; 738739466Sken if (immediate != 0) 738839466Sken scsi_cmd->byte2 |= SSS_IMMED; 738939466Sken 739039466Sken cam_fill_csio(csio, 739139466Sken retries, 739239466Sken cbfcnp, 739339466Sken /*flags*/CAM_DIR_NONE | extra_flags, 739439466Sken tag_action, 739539466Sken /*data_ptr*/NULL, 739639466Sken /*dxfer_len*/0, 739739466Sken sense_len, 739839466Sken sizeof(*scsi_cmd), 739939466Sken timeout); 740039466Sken} 740139466Sken 740239466Sken 7403268700Smavvoid 7404268700Smavscsi_persistent_reserve_in(struct ccb_scsiio *csio, uint32_t retries, 7405268700Smav void (*cbfcnp)(struct cam_periph *, union ccb *), 7406268700Smav uint8_t tag_action, int service_action, 7407268700Smav uint8_t *data_ptr, uint32_t dxfer_len, int sense_len, 7408268700Smav int timeout) 7409268700Smav{ 7410268700Smav struct scsi_per_res_in *scsi_cmd; 7411268700Smav 7412268700Smav scsi_cmd = (struct scsi_per_res_in *)&csio->cdb_io.cdb_bytes; 7413268700Smav bzero(scsi_cmd, sizeof(*scsi_cmd)); 7414268700Smav 7415268700Smav scsi_cmd->opcode = PERSISTENT_RES_IN; 7416268700Smav scsi_cmd->action = service_action; 7417268700Smav scsi_ulto2b(dxfer_len, scsi_cmd->length); 7418268700Smav 7419268700Smav cam_fill_csio(csio, 7420268700Smav retries, 7421268700Smav cbfcnp, 7422268700Smav /*flags*/CAM_DIR_IN, 7423268700Smav tag_action, 7424268700Smav data_ptr, 7425268700Smav dxfer_len, 7426268700Smav sense_len, 7427268700Smav sizeof(*scsi_cmd), 7428268700Smav timeout); 7429268700Smav} 7430268700Smav 7431268700Smavvoid 7432268700Smavscsi_persistent_reserve_out(struct ccb_scsiio *csio, uint32_t retries, 7433268700Smav void (*cbfcnp)(struct cam_periph *, union ccb *), 7434268700Smav uint8_t tag_action, int service_action, 7435268700Smav int scope, int res_type, uint8_t *data_ptr, 7436268700Smav uint32_t dxfer_len, int sense_len, int timeout) 7437268700Smav{ 7438268700Smav struct scsi_per_res_out *scsi_cmd; 7439268700Smav 7440268700Smav scsi_cmd = (struct scsi_per_res_out *)&csio->cdb_io.cdb_bytes; 7441268700Smav bzero(scsi_cmd, sizeof(*scsi_cmd)); 7442268700Smav 7443268700Smav scsi_cmd->opcode = PERSISTENT_RES_OUT; 7444268700Smav scsi_cmd->action = service_action; 7445268700Smav scsi_cmd->scope_type = scope | res_type; 7446268700Smav scsi_ulto4b(dxfer_len, scsi_cmd->length); 7447268700Smav 7448268700Smav cam_fill_csio(csio, 7449268700Smav retries, 7450268700Smav cbfcnp, 7451268700Smav /*flags*/CAM_DIR_OUT, 7452268700Smav tag_action, 7453268700Smav data_ptr, 7454268700Smav dxfer_len, 7455268700Smav sense_len, 7456268700Smav sizeof(*scsi_cmd), 7457268700Smav timeout); 7458268700Smav} 7459268700Smav 746039213Sgibbs/* 746139213Sgibbs * Try make as good a match as possible with 746239213Sgibbs * available sub drivers 746339213Sgibbs */ 746439213Sgibbsint 746539213Sgibbsscsi_inquiry_match(caddr_t inqbuffer, caddr_t table_entry) 746639213Sgibbs{ 746739213Sgibbs struct scsi_inquiry_pattern *entry; 746839213Sgibbs struct scsi_inquiry_data *inq; 746939213Sgibbs 747039213Sgibbs entry = (struct scsi_inquiry_pattern *)table_entry; 747139213Sgibbs inq = (struct scsi_inquiry_data *)inqbuffer; 747239213Sgibbs 747339213Sgibbs if (((SID_TYPE(inq) == entry->type) 747439213Sgibbs || (entry->type == T_ANY)) 747539213Sgibbs && (SID_IS_REMOVABLE(inq) ? entry->media_type & SIP_MEDIA_REMOVABLE 747639213Sgibbs : entry->media_type & SIP_MEDIA_FIXED) 747739213Sgibbs && (cam_strmatch(inq->vendor, entry->vendor, sizeof(inq->vendor)) == 0) 747839466Sken && (cam_strmatch(inq->product, entry->product, 747939466Sken sizeof(inq->product)) == 0) 748039466Sken && (cam_strmatch(inq->revision, entry->revision, 748139466Sken sizeof(inq->revision)) == 0)) { 748239213Sgibbs return (0); 748339213Sgibbs } 748439213Sgibbs return (-1); 748539213Sgibbs} 748639213Sgibbs 748739213Sgibbs/* 748839213Sgibbs * Try make as good a match as possible with 748939213Sgibbs * available sub drivers 749039213Sgibbs */ 749139213Sgibbsint 749239213Sgibbsscsi_static_inquiry_match(caddr_t inqbuffer, caddr_t table_entry) 749339213Sgibbs{ 749439213Sgibbs struct scsi_static_inquiry_pattern *entry; 749539213Sgibbs struct scsi_inquiry_data *inq; 749639213Sgibbs 749739213Sgibbs entry = (struct scsi_static_inquiry_pattern *)table_entry; 749839213Sgibbs inq = (struct scsi_inquiry_data *)inqbuffer; 749939213Sgibbs 750039213Sgibbs if (((SID_TYPE(inq) == entry->type) 750139213Sgibbs || (entry->type == T_ANY)) 750239213Sgibbs && (SID_IS_REMOVABLE(inq) ? entry->media_type & SIP_MEDIA_REMOVABLE 750339213Sgibbs : entry->media_type & SIP_MEDIA_FIXED) 750439213Sgibbs && (cam_strmatch(inq->vendor, entry->vendor, sizeof(inq->vendor)) == 0) 750539466Sken && (cam_strmatch(inq->product, entry->product, 750639466Sken sizeof(inq->product)) == 0) 750739466Sken && (cam_strmatch(inq->revision, entry->revision, 750839466Sken sizeof(inq->revision)) == 0)) { 750939213Sgibbs return (0); 751039213Sgibbs } 751139213Sgibbs return (-1); 751239213Sgibbs} 7513102862Sbrooks 7514223081Sgibbs/** 7515223081Sgibbs * Compare two buffers of vpd device descriptors for a match. 7516223081Sgibbs * 7517223081Sgibbs * \param lhs Pointer to first buffer of descriptors to compare. 7518223081Sgibbs * \param lhs_len The length of the first buffer. 7519223081Sgibbs * \param rhs Pointer to second buffer of descriptors to compare. 7520223081Sgibbs * \param rhs_len The length of the second buffer. 7521223081Sgibbs * 7522223081Sgibbs * \return 0 on a match, -1 otherwise. 7523223081Sgibbs * 7524223081Sgibbs * Treat rhs and lhs as arrays of vpd device id descriptors. Walk lhs matching 7525223081Sgibbs * agains each element in rhs until all data are exhausted or we have found 7526223081Sgibbs * a match. 7527223081Sgibbs */ 7528223081Sgibbsint 7529223081Sgibbsscsi_devid_match(uint8_t *lhs, size_t lhs_len, uint8_t *rhs, size_t rhs_len) 7530223081Sgibbs{ 7531223081Sgibbs struct scsi_vpd_id_descriptor *lhs_id; 7532223081Sgibbs struct scsi_vpd_id_descriptor *lhs_last; 7533223081Sgibbs struct scsi_vpd_id_descriptor *rhs_last; 7534223081Sgibbs uint8_t *lhs_end; 7535223081Sgibbs uint8_t *rhs_end; 7536223081Sgibbs 7537223081Sgibbs lhs_end = lhs + lhs_len; 7538223081Sgibbs rhs_end = rhs + rhs_len; 7539223081Sgibbs 7540223081Sgibbs /* 7541223081Sgibbs * rhs_last and lhs_last are the last posible position of a valid 7542223081Sgibbs * descriptor assuming it had a zero length identifier. We use 7543223081Sgibbs * these variables to insure we can safely dereference the length 7544223081Sgibbs * field in our loop termination tests. 7545223081Sgibbs */ 7546223081Sgibbs lhs_last = (struct scsi_vpd_id_descriptor *) 7547223081Sgibbs (lhs_end - __offsetof(struct scsi_vpd_id_descriptor, identifier)); 7548223081Sgibbs rhs_last = (struct scsi_vpd_id_descriptor *) 7549223081Sgibbs (rhs_end - __offsetof(struct scsi_vpd_id_descriptor, identifier)); 7550223081Sgibbs 7551223081Sgibbs lhs_id = (struct scsi_vpd_id_descriptor *)lhs; 7552223081Sgibbs while (lhs_id <= lhs_last 7553223081Sgibbs && (lhs_id->identifier + lhs_id->length) <= lhs_end) { 7554223081Sgibbs struct scsi_vpd_id_descriptor *rhs_id; 7555223081Sgibbs 7556223081Sgibbs rhs_id = (struct scsi_vpd_id_descriptor *)rhs; 7557223081Sgibbs while (rhs_id <= rhs_last 7558223081Sgibbs && (rhs_id->identifier + rhs_id->length) <= rhs_end) { 7559223081Sgibbs 7560259721Smav if ((rhs_id->id_type & 7561259721Smav (SVPD_ID_ASSOC_MASK | SVPD_ID_TYPE_MASK)) == 7562259721Smav (lhs_id->id_type & 7563259721Smav (SVPD_ID_ASSOC_MASK | SVPD_ID_TYPE_MASK)) 7564259721Smav && rhs_id->length == lhs_id->length 7565223081Sgibbs && memcmp(rhs_id->identifier, lhs_id->identifier, 7566223081Sgibbs rhs_id->length) == 0) 7567223081Sgibbs return (0); 7568223081Sgibbs 7569223081Sgibbs rhs_id = (struct scsi_vpd_id_descriptor *) 7570223081Sgibbs (rhs_id->identifier + rhs_id->length); 7571223081Sgibbs } 7572223081Sgibbs lhs_id = (struct scsi_vpd_id_descriptor *) 7573223081Sgibbs (lhs_id->identifier + lhs_id->length); 7574223081Sgibbs } 7575223081Sgibbs return (-1); 7576223081Sgibbs} 7577223081Sgibbs 7578102862Sbrooks#ifdef _KERNEL 7579249937Ssmhint 7580249937Ssmhscsi_vpd_supported_page(struct cam_periph *periph, uint8_t page_id) 7581249937Ssmh{ 7582249937Ssmh struct cam_ed *device; 7583249937Ssmh struct scsi_vpd_supported_pages *vpds; 7584249937Ssmh int i, num_pages; 7585249937Ssmh 7586249937Ssmh device = periph->path->device; 7587249937Ssmh vpds = (struct scsi_vpd_supported_pages *)device->supported_vpds; 7588249937Ssmh 7589249937Ssmh if (vpds != NULL) { 7590249937Ssmh num_pages = device->supported_vpds_len - 7591249937Ssmh SVPD_SUPPORTED_PAGES_HDR_LEN; 7592249937Ssmh for (i = 0; i < num_pages; i++) { 7593249937Ssmh if (vpds->page_list[i] == page_id) 7594249937Ssmh return (1); 7595249937Ssmh } 7596249937Ssmh } 7597249937Ssmh 7598249937Ssmh return (0); 7599249937Ssmh} 7600249937Ssmh 7601102862Sbrooksstatic void 7602102862Sbrooksinit_scsi_delay(void) 7603102862Sbrooks{ 7604102862Sbrooks int delay; 7605102862Sbrooks 7606102862Sbrooks delay = SCSI_DELAY; 7607102862Sbrooks TUNABLE_INT_FETCH("kern.cam.scsi_delay", &delay); 7608102862Sbrooks 7609102862Sbrooks if (set_scsi_delay(delay) != 0) { 7610102862Sbrooks printf("cam: invalid value for tunable kern.cam.scsi_delay\n"); 7611102862Sbrooks set_scsi_delay(SCSI_DELAY); 7612102862Sbrooks } 7613102862Sbrooks} 7614102862SbrooksSYSINIT(scsi_delay, SI_SUB_TUNABLES, SI_ORDER_ANY, init_scsi_delay, NULL); 7615102862Sbrooks 7616102862Sbrooksstatic int 7617102862Sbrookssysctl_scsi_delay(SYSCTL_HANDLER_ARGS) 7618102862Sbrooks{ 7619102862Sbrooks int error, delay; 7620102862Sbrooks 7621102862Sbrooks delay = scsi_delay; 7622170289Sdwmalone error = sysctl_handle_int(oidp, &delay, 0, req); 7623102862Sbrooks if (error != 0 || req->newptr == NULL) 7624102862Sbrooks return (error); 7625102862Sbrooks return (set_scsi_delay(delay)); 7626102862Sbrooks} 7627102862SbrooksSYSCTL_PROC(_kern_cam, OID_AUTO, scsi_delay, CTLTYPE_INT|CTLFLAG_RW, 7628102862Sbrooks 0, 0, sysctl_scsi_delay, "I", 7629102862Sbrooks "Delay to allow devices to settle after a SCSI bus reset (ms)"); 7630102862Sbrooks 7631102862Sbrooksstatic int 7632102862Sbrooksset_scsi_delay(int delay) 7633102862Sbrooks{ 7634102862Sbrooks /* 7635102862Sbrooks * If someone sets this to 0, we assume that they want the 7636102862Sbrooks * minimum allowable bus settle delay. 7637102862Sbrooks */ 7638102862Sbrooks if (delay == 0) { 7639102862Sbrooks printf("cam: using minimum scsi_delay (%dms)\n", 7640102862Sbrooks SCSI_MIN_DELAY); 7641102862Sbrooks delay = SCSI_MIN_DELAY; 7642102862Sbrooks } 7643102862Sbrooks if (delay < SCSI_MIN_DELAY) 7644102862Sbrooks return (EINVAL); 7645102862Sbrooks scsi_delay = delay; 7646102862Sbrooks return (0); 7647102862Sbrooks} 7648102862Sbrooks#endif /* _KERNEL */ 7649