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: stable/10/sys/cam/scsi/scsi_all.c 323987 2017-09-25 18:26:31Z jkim $"); 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 178288772Smav * as of 5/26/15 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 /* 88 MM O O O READ(16) */ 471181381Sjkim { 0x88, D | T | W | O | B, "READ(16)" }, 472268151Smav /* 89 O COMPARE AND WRITE*/ 473268151Smav { 0x89, D, "COMPARE AND WRITE" }, 474181381Sjkim /* 8A OM O O O WRITE(16) */ 475181381Sjkim { 0x8A, D | T | W | O | B, "WRITE(16)" }, 476181381Sjkim /* 8B O ORWRITE */ 477181381Sjkim { 0x8B, D, "ORWRITE" }, 478181381Sjkim /* 8C OO O OO O M READ ATTRIBUTE */ 479181381Sjkim { 0x8C, D | T | W | O | M | B | V, "READ ATTRIBUTE" }, 480181381Sjkim /* 8D OO O OO O O WRITE ATTRIBUTE */ 481181381Sjkim { 0x8D, D | T | W | O | M | B | V, "WRITE ATTRIBUTE" }, 482181381Sjkim /* 8E O O O O WRITE AND VERIFY(16) */ 483181381Sjkim { 0x8E, D | W | O | B, "WRITE AND VERIFY(16)" }, 484181381Sjkim /* 8F OO O O O VERIFY(16) */ 485181381Sjkim { 0x8F, D | T | W | O | B, "VERIFY(16)" }, 486181381Sjkim /* 90 O O O O PRE-FETCH(16) */ 487181381Sjkim { 0x90, D | W | O | B, "PRE-FETCH(16)" }, 488181381Sjkim /* 91 O O O O SYNCHRONIZE CACHE(16) */ 489181381Sjkim { 0x91, D | W | O | B, "SYNCHRONIZE CACHE(16)" }, 490181381Sjkim /* 91 O SPACE(16) */ 491181381Sjkim { 0x91, T, "SPACE(16)" }, 492181381Sjkim /* 92 Z O O LOCK UNLOCK CACHE(16) */ 493181381Sjkim { 0x92, D | W | O, "LOCK UNLOCK CACHE(16)" }, 494181381Sjkim /* 92 O LOCATE(16) */ 495181381Sjkim { 0x92, T, "LOCATE(16)" }, 496181381Sjkim /* 93 O WRITE SAME(16) */ 497181381Sjkim { 0x93, D, "WRITE SAME(16)" }, 498181381Sjkim /* 93 M ERASE(16) */ 499181381Sjkim { 0x93, T, "ERASE(16)" }, 500288772Smav /* 94 O ZBC OUT */ 501288772Smav { 0x94, D, "ZBC OUT" }, 502288772Smav /* 95 O ZBC OUT */ 503288772Smav { 0x95, D, "ZBC OUT" }, 504288772Smav /* 96 */ 505288772Smav /* 97 */ 506181381Sjkim /* 98 */ 507181381Sjkim /* 99 */ 508288772Smav /* 9A O WRITE STREAM(16) */ 509288772Smav { 0x9A, D, "WRITE STREAM(16)" }, 510288772Smav /* 9B OOOOOOOOOO OOO READ BUFFER(16) */ 511288772Smav { 0x9B, ALL & ~(B) , "READ BUFFER(16)" }, 512288741Smav /* 9C O WRITE ATOMIC(16) */ 513288741Smav { 0x9C, D, "WRITE ATOMIC(16)" }, 514288772Smav /* 9D SERVICE ACTION BIDIRECTIONAL */ 515288772Smav { 0x9D, ALL, "SERVICE ACTION BIDIRECTIONAL" }, 516181381Sjkim /* XXX KDM ALL for this? op-num.txt defines it for none.. */ 517181381Sjkim /* 9E SERVICE ACTION IN(16) */ 518181381Sjkim { 0x9E, ALL, "SERVICE ACTION IN(16)" }, 519181381Sjkim /* XXX KDM ALL for this? op-num.txt defines it for ADC.. */ 520181381Sjkim /* 9F M SERVICE ACTION OUT(16) */ 521181381Sjkim { 0x9F, ALL, "SERVICE ACTION OUT(16)" }, 522181381Sjkim /* A0 MMOOO OMMM OMO REPORT LUNS */ 523181381Sjkim { 0xA0, ALL & ~(R | B), "REPORT LUNS" }, 524181381Sjkim /* A1 O BLANK */ 525181381Sjkim { 0xA1, R, "BLANK" }, 526181381Sjkim /* A1 O O ATA COMMAND PASS THROUGH(12) */ 527181381Sjkim { 0xA1, D | B, "ATA COMMAND PASS THROUGH(12)" }, 528181381Sjkim /* A2 OO O O SECURITY PROTOCOL IN */ 529181381Sjkim { 0xA2, D | T | R | V, "SECURITY PROTOCOL IN" }, 530181381Sjkim /* A3 OOO O OOMOOOM MAINTENANCE (IN) */ 531181381Sjkim { 0xA3, ALL & ~(P | R | F), "MAINTENANCE (IN)" }, 532181381Sjkim /* A3 O SEND KEY */ 533181381Sjkim { 0xA3, R, "SEND KEY" }, 534181381Sjkim /* A4 OOO O OOOOOOO MAINTENANCE (OUT) */ 535181381Sjkim { 0xA4, ALL & ~(P | R | F), "MAINTENANCE (OUT)" }, 536181381Sjkim /* A4 O REPORT KEY */ 537181381Sjkim { 0xA4, R, "REPORT KEY" }, 538181381Sjkim /* A5 O O OM MOVE MEDIUM */ 539181381Sjkim { 0xA5, T | W | O | M, "MOVE MEDIUM" }, 540181381Sjkim /* A5 O PLAY AUDIO(12) */ 541181381Sjkim { 0xA5, R, "PLAY AUDIO(12)" }, 542181381Sjkim /* A6 O EXCHANGE MEDIUM */ 543181381Sjkim { 0xA6, M, "EXCHANGE MEDIUM" }, 544181381Sjkim /* A6 O LOAD/UNLOAD C/DVD */ 545181381Sjkim { 0xA6, R, "LOAD/UNLOAD C/DVD" }, 546181381Sjkim /* A7 ZZ O O MOVE MEDIUM ATTACHED */ 547181381Sjkim { 0xA7, D | T | W | O, "MOVE MEDIUM ATTACHED" }, 548181381Sjkim /* A7 O SET READ AHEAD */ 549181381Sjkim { 0xA7, R, "SET READ AHEAD" }, 550181381Sjkim /* A8 O OOO READ(12) */ 551181381Sjkim { 0xA8, D | W | R | O, "READ(12)" }, 552181381Sjkim /* A8 GET MESSAGE(12) */ 553181381Sjkim { 0xA8, C, "GET MESSAGE(12)" }, 554181381Sjkim /* A9 O SERVICE ACTION OUT(12) */ 555181381Sjkim { 0xA9, V, "SERVICE ACTION OUT(12)" }, 556181381Sjkim /* AA O OOO WRITE(12) */ 557181381Sjkim { 0xAA, D | W | R | O, "WRITE(12)" }, 558181381Sjkim /* AA SEND MESSAGE(12) */ 559181381Sjkim { 0xAA, C, "SEND MESSAGE(12)" }, 560181381Sjkim /* AB O O SERVICE ACTION IN(12) */ 561181381Sjkim { 0xAB, R | V, "SERVICE ACTION IN(12)" }, 562181381Sjkim /* AC O ERASE(12) */ 563181381Sjkim { 0xAC, O, "ERASE(12)" }, 564181381Sjkim /* AC O GET PERFORMANCE */ 565181381Sjkim { 0xAC, R, "GET PERFORMANCE" }, 566181381Sjkim /* AD O READ DVD STRUCTURE */ 567181381Sjkim { 0xAD, R, "READ DVD STRUCTURE" }, 568181381Sjkim /* AE O O O WRITE AND VERIFY(12) */ 569181381Sjkim { 0xAE, D | W | O, "WRITE AND VERIFY(12)" }, 570181381Sjkim /* AF O OZO VERIFY(12) */ 571181381Sjkim { 0xAF, D | W | R | O, "VERIFY(12)" }, 572181381Sjkim /* B0 ZZZ SEARCH DATA HIGH(12) */ 573181381Sjkim { 0xB0, W | R | O, "SEARCH DATA HIGH(12)" }, 574181381Sjkim /* B1 ZZZ SEARCH DATA EQUAL(12) */ 575181381Sjkim { 0xB1, W | R | O, "SEARCH DATA EQUAL(12)" }, 576181381Sjkim /* B2 ZZZ SEARCH DATA LOW(12) */ 577181381Sjkim { 0xB2, W | R | O, "SEARCH DATA LOW(12)" }, 578181381Sjkim /* B3 Z OZO SET LIMITS(12) */ 579181381Sjkim { 0xB3, D | W | R | O, "SET LIMITS(12)" }, 580181381Sjkim /* B4 ZZ OZO READ ELEMENT STATUS ATTACHED */ 581181381Sjkim { 0xB4, D | T | W | R | O, "READ ELEMENT STATUS ATTACHED" }, 582181381Sjkim /* B5 OO O O SECURITY PROTOCOL OUT */ 583181381Sjkim { 0xB5, D | T | R | V, "SECURITY PROTOCOL OUT" }, 584181381Sjkim /* B5 O REQUEST VOLUME ELEMENT ADDRESS */ 585181381Sjkim { 0xB5, M, "REQUEST VOLUME ELEMENT ADDRESS" }, 586181381Sjkim /* B6 O SEND VOLUME TAG */ 587181381Sjkim { 0xB6, M, "SEND VOLUME TAG" }, 588181381Sjkim /* B6 O SET STREAMING */ 589181381Sjkim { 0xB6, R, "SET STREAMING" }, 590181381Sjkim /* B7 O O READ DEFECT DATA(12) */ 591181381Sjkim { 0xB7, D | O, "READ DEFECT DATA(12)" }, 592181381Sjkim /* B8 O OZOM READ ELEMENT STATUS */ 593181381Sjkim { 0xB8, T | W | R | O | M, "READ ELEMENT STATUS" }, 594181381Sjkim /* B9 O READ CD MSF */ 595181381Sjkim { 0xB9, R, "READ CD MSF" }, 596181381Sjkim /* BA O O OOMO REDUNDANCY GROUP (IN) */ 597181381Sjkim { 0xBA, D | W | O | M | A | E, "REDUNDANCY GROUP (IN)" }, 598181381Sjkim /* BA O SCAN */ 599181381Sjkim { 0xBA, R, "SCAN" }, 600181381Sjkim /* BB O O OOOO REDUNDANCY GROUP (OUT) */ 601181381Sjkim { 0xBB, D | W | O | M | A | E, "REDUNDANCY GROUP (OUT)" }, 602181381Sjkim /* BB O SET CD SPEED */ 603181381Sjkim { 0xBB, R, "SET CD SPEED" }, 604181381Sjkim /* BC O O OOMO SPARE (IN) */ 605181381Sjkim { 0xBC, D | W | O | M | A | E, "SPARE (IN)" }, 606181381Sjkim /* BD O O OOOO SPARE (OUT) */ 607181381Sjkim { 0xBD, D | W | O | M | A | E, "SPARE (OUT)" }, 608181381Sjkim /* BD O MECHANISM STATUS */ 609181381Sjkim { 0xBD, R, "MECHANISM STATUS" }, 610181381Sjkim /* BE O O OOMO VOLUME SET (IN) */ 611181381Sjkim { 0xBE, D | W | O | M | A | E, "VOLUME SET (IN)" }, 612181381Sjkim /* BE O READ CD */ 613181381Sjkim { 0xBE, R, "READ CD" }, 614181381Sjkim /* BF O O OOOO VOLUME SET (OUT) */ 615181381Sjkim { 0xBF, D | W | O | M | A | E, "VOLUME SET (OUT)" }, 616181381Sjkim /* BF O SEND DVD STRUCTURE */ 617181381Sjkim { 0xBF, R, "SEND DVD STRUCTURE" } 61839213Sgibbs}; 61939213Sgibbs 62039213Sgibbsconst char * 62139213Sgibbsscsi_op_desc(u_int16_t opcode, struct scsi_inquiry_data *inq_data) 62239213Sgibbs{ 62339213Sgibbs caddr_t match; 62439213Sgibbs int i, j; 625181381Sjkim u_int32_t opmask; 62639213Sgibbs u_int16_t pd_type; 62739213Sgibbs int num_ops[2]; 62839213Sgibbs struct op_table_entry *table[2]; 62939213Sgibbs int num_tables; 63039213Sgibbs 631225950Sken /* 632225950Sken * If we've got inquiry data, use it to determine what type of 633225950Sken * device we're dealing with here. Otherwise, assume direct 634225950Sken * access. 635225950Sken */ 636225950Sken if (inq_data == NULL) { 637225950Sken pd_type = T_DIRECT; 638225950Sken match = NULL; 639225950Sken } else { 640225950Sken pd_type = SID_TYPE(inq_data); 64139213Sgibbs 642225950Sken match = cam_quirkmatch((caddr_t)inq_data, 643225950Sken (caddr_t)scsi_op_quirk_table, 644225950Sken sizeof(scsi_op_quirk_table)/ 645225950Sken sizeof(*scsi_op_quirk_table), 646225950Sken sizeof(*scsi_op_quirk_table), 647225950Sken scsi_inquiry_match); 648225950Sken } 64939213Sgibbs 65039213Sgibbs if (match != NULL) { 65139213Sgibbs table[0] = ((struct scsi_op_quirk_entry *)match)->op_table; 65239213Sgibbs num_ops[0] = ((struct scsi_op_quirk_entry *)match)->num_ops; 65339213Sgibbs table[1] = scsi_op_codes; 65439213Sgibbs num_ops[1] = sizeof(scsi_op_codes)/sizeof(scsi_op_codes[0]); 65539213Sgibbs num_tables = 2; 65639213Sgibbs } else { 65739213Sgibbs /* 65839213Sgibbs * If this is true, we have a vendor specific opcode that 65939213Sgibbs * wasn't covered in the quirk table. 66039213Sgibbs */ 66139213Sgibbs if ((opcode > 0xBF) || ((opcode > 0x5F) && (opcode < 0x80))) 66239213Sgibbs return("Vendor Specific Command"); 66339213Sgibbs 66439213Sgibbs table[0] = scsi_op_codes; 66539213Sgibbs num_ops[0] = sizeof(scsi_op_codes)/sizeof(scsi_op_codes[0]); 66639213Sgibbs num_tables = 1; 66739213Sgibbs } 66839213Sgibbs 66992052Ssimokawa /* RBC is 'Simplified' Direct Access Device */ 67092052Ssimokawa if (pd_type == T_RBC) 67192052Ssimokawa pd_type = T_DIRECT; 67292052Ssimokawa 673253323Smav /* Map NODEVICE to Direct Access Device to handle REPORT LUNS, etc. */ 674253323Smav if (pd_type == T_NODEVICE) 675253323Smav pd_type = T_DIRECT; 676253323Smav 67739213Sgibbs opmask = 1 << pd_type; 67839213Sgibbs 67939213Sgibbs for (j = 0; j < num_tables; j++) { 68039213Sgibbs for (i = 0;i < num_ops[j] && table[j][i].opcode <= opcode; i++){ 68139213Sgibbs if ((table[j][i].opcode == opcode) 68239213Sgibbs && ((table[j][i].opmask & opmask) != 0)) 68339213Sgibbs return(table[j][i].desc); 68439213Sgibbs } 68539213Sgibbs } 68639213Sgibbs 68739213Sgibbs /* 68839213Sgibbs * If we can't find a match for the command in the table, we just 68939213Sgibbs * assume it's a vendor specifc command. 69039213Sgibbs */ 69139213Sgibbs return("Vendor Specific Command"); 69239213Sgibbs 69339213Sgibbs} 69439213Sgibbs 69539213Sgibbs#else /* SCSI_NO_OP_STRINGS */ 69639213Sgibbs 69739213Sgibbsconst char * 69839213Sgibbsscsi_op_desc(u_int16_t opcode, struct scsi_inquiry_data *inq_data) 69939213Sgibbs{ 70039213Sgibbs return(""); 70139213Sgibbs} 70239213Sgibbs 70339213Sgibbs#endif 70439213Sgibbs 70539213Sgibbs 70639213Sgibbs#if !defined(SCSI_NO_SENSE_STRINGS) 70739213Sgibbs#define SST(asc, ascq, action, desc) \ 70839213Sgibbs asc, ascq, action, desc 70939213Sgibbs#else 71074840Skenconst char empty_string[] = ""; 71174840Sken 71239213Sgibbs#define SST(asc, ascq, action, desc) \ 71374840Sken asc, ascq, action, empty_string 71439213Sgibbs#endif 71539213Sgibbs 71674840Skenconst struct sense_key_table_entry sense_key_table[] = 71774840Sken{ 71874840Sken { SSD_KEY_NO_SENSE, SS_NOP, "NO SENSE" }, 71974840Sken { SSD_KEY_RECOVERED_ERROR, SS_NOP|SSQ_PRINT_SENSE, "RECOVERED ERROR" }, 720249352Smav { SSD_KEY_NOT_READY, SS_RDEF, "NOT READY" }, 72174840Sken { SSD_KEY_MEDIUM_ERROR, SS_RDEF, "MEDIUM ERROR" }, 72274840Sken { SSD_KEY_HARDWARE_ERROR, SS_RDEF, "HARDWARE FAILURE" }, 72374840Sken { SSD_KEY_ILLEGAL_REQUEST, SS_FATAL|EINVAL, "ILLEGAL REQUEST" }, 72474840Sken { SSD_KEY_UNIT_ATTENTION, SS_FATAL|ENXIO, "UNIT ATTENTION" }, 72576162Sken { SSD_KEY_DATA_PROTECT, SS_FATAL|EACCES, "DATA PROTECT" }, 72676162Sken { SSD_KEY_BLANK_CHECK, SS_FATAL|ENOSPC, "BLANK CHECK" }, 72774840Sken { SSD_KEY_Vendor_Specific, SS_FATAL|EIO, "Vendor Specific" }, 72874840Sken { SSD_KEY_COPY_ABORTED, SS_FATAL|EIO, "COPY ABORTED" }, 72974840Sken { SSD_KEY_ABORTED_COMMAND, SS_RDEF, "ABORTED COMMAND" }, 73074840Sken { SSD_KEY_EQUAL, SS_NOP, "EQUAL" }, 73174840Sken { SSD_KEY_VOLUME_OVERFLOW, SS_FATAL|EIO, "VOLUME OVERFLOW" }, 73274840Sken { SSD_KEY_MISCOMPARE, SS_NOP, "MISCOMPARE" }, 733225950Sken { SSD_KEY_COMPLETED, SS_NOP, "COMPLETED" } 73474840Sken}; 73574840Sken 73674840Skenconst int sense_key_table_size = 73774840Sken sizeof(sense_key_table)/sizeof(sense_key_table[0]); 73874840Sken 73939213Sgibbsstatic struct asc_table_entry quantum_fireball_entries[] = { 740181381Sjkim { SST(0x04, 0x0b, SS_START | SSQ_DECREMENT_COUNT | ENXIO, 741181381Sjkim "Logical unit not ready, initializing cmd. required") } 74239213Sgibbs}; 74339213Sgibbs 74476293Sjoergstatic struct asc_table_entry sony_mo_entries[] = { 745181381Sjkim { SST(0x04, 0x00, SS_START | SSQ_DECREMENT_COUNT | ENXIO, 746181381Sjkim "Logical unit not ready, cause not reportable") } 74776293Sjoerg}; 74876293Sjoerg 749252204Smavstatic struct asc_table_entry hgst_entries[] = { 750252204Smav { SST(0x04, 0xF0, SS_RDEF, 751252204Smav "Vendor Unique - Logical Unit Not Ready") }, 752252204Smav { SST(0x0A, 0x01, SS_RDEF, 753252204Smav "Unrecovered Super Certification Log Write Error") }, 754252204Smav { SST(0x0A, 0x02, SS_RDEF, 755252204Smav "Unrecovered Super Certification Log Read Error") }, 756252204Smav { SST(0x15, 0x03, SS_RDEF, 757252204Smav "Unrecovered Sector Error") }, 758252204Smav { SST(0x3E, 0x04, SS_RDEF, 759252204Smav "Unrecovered Self-Test Hard-Cache Test Fail") }, 760252204Smav { SST(0x3E, 0x05, SS_RDEF, 761252204Smav "Unrecovered Self-Test OTF-Cache Fail") }, 762252204Smav { SST(0x40, 0x00, SS_RDEF, 763252204Smav "Unrecovered SAT No Buffer Overflow Error") }, 764252204Smav { SST(0x40, 0x01, SS_RDEF, 765252204Smav "Unrecovered SAT Buffer Overflow Error") }, 766252204Smav { SST(0x40, 0x02, SS_RDEF, 767252204Smav "Unrecovered SAT No Buffer Overflow With ECS Fault") }, 768252204Smav { SST(0x40, 0x03, SS_RDEF, 769252204Smav "Unrecovered SAT Buffer Overflow With ECS Fault") }, 770252204Smav { SST(0x40, 0x81, SS_RDEF, 771252204Smav "DRAM Failure") }, 772252204Smav { SST(0x44, 0x0B, SS_RDEF, 773252204Smav "Vendor Unique - Internal Target Failure") }, 774252204Smav { SST(0x44, 0xF2, SS_RDEF, 775252204Smav "Vendor Unique - Internal Target Failure") }, 776252204Smav { SST(0x44, 0xF6, SS_RDEF, 777252204Smav "Vendor Unique - Internal Target Failure") }, 778252204Smav { SST(0x44, 0xF9, SS_RDEF, 779252204Smav "Vendor Unique - Internal Target Failure") }, 780252204Smav { SST(0x44, 0xFA, SS_RDEF, 781252204Smav "Vendor Unique - Internal Target Failure") }, 782252204Smav { SST(0x5D, 0x22, SS_RDEF, 783252204Smav "Extreme Over-Temperature Warning") }, 784252204Smav { SST(0x5D, 0x50, SS_RDEF, 785252204Smav "Load/Unload cycle Count Warning") }, 786252204Smav { SST(0x81, 0x00, SS_RDEF, 787252204Smav "Vendor Unique - Internal Logic Error") }, 788252204Smav { SST(0x85, 0x00, SS_RDEF, 789252204Smav "Vendor Unique - Internal Key Seed Error") }, 790252204Smav}; 791252204Smav 792252204Smavstatic struct asc_table_entry seagate_entries[] = { 793252204Smav { SST(0x04, 0xF0, SS_RDEF, 794252204Smav "Logical Unit Not Ready, super certify in Progress") }, 795252204Smav { SST(0x08, 0x86, SS_RDEF, 796252204Smav "Write Fault Data Corruption") }, 797252204Smav { SST(0x09, 0x0D, SS_RDEF, 798252204Smav "Tracking Failure") }, 799252204Smav { SST(0x09, 0x0E, SS_RDEF, 800252204Smav "ETF Failure") }, 801252204Smav { SST(0x0B, 0x5D, SS_RDEF, 802252204Smav "Pre-SMART Warning") }, 803252204Smav { SST(0x0B, 0x85, SS_RDEF, 804252204Smav "5V Voltage Warning") }, 805252204Smav { SST(0x0B, 0x8C, SS_RDEF, 806252204Smav "12V Voltage Warning") }, 807252204Smav { SST(0x0C, 0xFF, SS_RDEF, 808252250Smav "Write Error - Too many error recovery revs") }, 809252204Smav { SST(0x11, 0xFF, SS_RDEF, 810252250Smav "Unrecovered Read Error - Too many error recovery revs") }, 811252204Smav { SST(0x19, 0x0E, SS_RDEF, 812252204Smav "Fewer than 1/2 defect list copies") }, 813252204Smav { SST(0x20, 0xF3, SS_RDEF, 814252204Smav "Illegal CDB linked to skip mask cmd") }, 815252204Smav { SST(0x24, 0xF0, SS_RDEF, 816252204Smav "Illegal byte in CDB, LBA not matching") }, 817252204Smav { SST(0x24, 0xF1, SS_RDEF, 818252204Smav "Illegal byte in CDB, LEN not matching") }, 819252204Smav { SST(0x24, 0xF2, SS_RDEF, 820252204Smav "Mask not matching transfer length") }, 821252204Smav { SST(0x24, 0xF3, SS_RDEF, 822252204Smav "Drive formatted without plist") }, 823252204Smav { SST(0x26, 0x95, SS_RDEF, 824252250Smav "Invalid Field Parameter - CAP File") }, 825252204Smav { SST(0x26, 0x96, SS_RDEF, 826252250Smav "Invalid Field Parameter - RAP File") }, 827252204Smav { SST(0x26, 0x97, SS_RDEF, 828252250Smav "Invalid Field Parameter - TMS Firmware Tag") }, 829252204Smav { SST(0x26, 0x98, SS_RDEF, 830252250Smav "Invalid Field Parameter - Check Sum") }, 831252204Smav { SST(0x26, 0x99, SS_RDEF, 832252250Smav "Invalid Field Parameter - Firmware Tag") }, 833252204Smav { SST(0x29, 0x08, SS_RDEF, 834252204Smav "Write Log Dump data") }, 835252204Smav { SST(0x29, 0x09, SS_RDEF, 836252204Smav "Write Log Dump data") }, 837252204Smav { SST(0x29, 0x0A, SS_RDEF, 838252204Smav "Reserved disk space") }, 839252204Smav { SST(0x29, 0x0B, SS_RDEF, 840252204Smav "SDBP") }, 841252204Smav { SST(0x29, 0x0C, SS_RDEF, 842252204Smav "SDBP") }, 843252204Smav { SST(0x31, 0x91, SS_RDEF, 844252204Smav "Format Corrupted World Wide Name (WWN) is Invalid") }, 845252204Smav { SST(0x32, 0x03, SS_RDEF, 846252250Smav "Defect List - Length exceeds Command Allocated Length") }, 847252204Smav { SST(0x33, 0x00, SS_RDEF, 848252204Smav "Flash not ready for access") }, 849252204Smav { SST(0x3F, 0x70, SS_RDEF, 850252204Smav "Invalid RAP block") }, 851252204Smav { SST(0x3F, 0x71, SS_RDEF, 852252204Smav "RAP/ETF mismatch") }, 853252204Smav { SST(0x3F, 0x90, SS_RDEF, 854252204Smav "Invalid CAP block") }, 855252204Smav { SST(0x3F, 0x91, SS_RDEF, 856252204Smav "World Wide Name (WWN) Mismatch") }, 857252204Smav { SST(0x40, 0x01, SS_RDEF, 858252204Smav "DRAM Parity Error") }, 859252204Smav { SST(0x40, 0x02, SS_RDEF, 860252204Smav "DRAM Parity Error") }, 861252204Smav { SST(0x42, 0x0A, SS_RDEF, 862252204Smav "Loopback Test") }, 863252204Smav { SST(0x42, 0x0B, SS_RDEF, 864252204Smav "Loopback Test") }, 865252204Smav { SST(0x44, 0xF2, SS_RDEF, 866252204Smav "Compare error during data integrity check") }, 867252204Smav { SST(0x44, 0xF6, SS_RDEF, 868252204Smav "Unrecoverable error during data integrity check") }, 869252204Smav { SST(0x47, 0x80, SS_RDEF, 870252204Smav "Fibre Channel Sequence Error") }, 871252204Smav { SST(0x4E, 0x01, SS_RDEF, 872252204Smav "Information Unit Too Short") }, 873252204Smav { SST(0x80, 0x00, SS_RDEF, 874252204Smav "General Firmware Error / Command Timeout") }, 875252204Smav { SST(0x80, 0x01, SS_RDEF, 876252204Smav "Command Timeout") }, 877252204Smav { SST(0x80, 0x02, SS_RDEF, 878252204Smav "Command Timeout") }, 879252204Smav { SST(0x80, 0x80, SS_RDEF, 880252204Smav "FC FIFO Error During Read Transfer") }, 881252204Smav { SST(0x80, 0x81, SS_RDEF, 882252204Smav "FC FIFO Error During Write Transfer") }, 883252204Smav { SST(0x80, 0x82, SS_RDEF, 884252204Smav "DISC FIFO Error During Read Transfer") }, 885252204Smav { SST(0x80, 0x83, SS_RDEF, 886252204Smav "DISC FIFO Error During Write Transfer") }, 887252204Smav { SST(0x80, 0x84, SS_RDEF, 888252204Smav "LBA Seeded LRC Error on Read") }, 889252204Smav { SST(0x80, 0x85, SS_RDEF, 890252204Smav "LBA Seeded LRC Error on Write") }, 891252204Smav { SST(0x80, 0x86, SS_RDEF, 892252204Smav "IOEDC Error on Read") }, 893252204Smav { SST(0x80, 0x87, SS_RDEF, 894252204Smav "IOEDC Error on Write") }, 895252204Smav { SST(0x80, 0x88, SS_RDEF, 896252204Smav "Host Parity Check Failed") }, 897252204Smav { SST(0x80, 0x89, SS_RDEF, 898252204Smav "IOEDC error on read detected by formatter") }, 899252204Smav { SST(0x80, 0x8A, SS_RDEF, 900252204Smav "Host Parity Errors / Host FIFO Initialization Failed") }, 901252204Smav { SST(0x80, 0x8B, SS_RDEF, 902252204Smav "Host Parity Errors") }, 903252204Smav { SST(0x80, 0x8C, SS_RDEF, 904252204Smav "Host Parity Errors") }, 905252204Smav { SST(0x80, 0x8D, SS_RDEF, 906252204Smav "Host Parity Errors") }, 907252204Smav { SST(0x81, 0x00, SS_RDEF, 908252204Smav "LA Check Failed") }, 909252204Smav { SST(0x82, 0x00, SS_RDEF, 910252204Smav "Internal client detected insufficient buffer") }, 911252204Smav { SST(0x84, 0x00, SS_RDEF, 912252204Smav "Scheduled Diagnostic And Repair") }, 913252204Smav}; 914252204Smav 91574840Skenstatic struct scsi_sense_quirk_entry sense_quirk_table[] = { 91639213Sgibbs { 91739213Sgibbs /* 918181381Sjkim * XXX The Quantum Fireball ST and SE like to return 0x04 0x0b 919181381Sjkim * when they really should return 0x04 0x02. 92039213Sgibbs */ 92139213Sgibbs {T_DIRECT, SIP_MEDIA_FIXED, "QUANTUM", "FIREBALL S*", "*"}, 92274840Sken /*num_sense_keys*/0, 92374840Sken sizeof(quantum_fireball_entries)/sizeof(struct asc_table_entry), 92474840Sken /*sense key entries*/NULL, 92539213Sgibbs quantum_fireball_entries 92676293Sjoerg }, 92776293Sjoerg { 92876293Sjoerg /* 92976293Sjoerg * This Sony MO drive likes to return 0x04, 0x00 when it 93076293Sjoerg * isn't spun up. 93176293Sjoerg */ 93276293Sjoerg {T_DIRECT, SIP_MEDIA_REMOVABLE, "SONY", "SMO-*", "*"}, 93376293Sjoerg /*num_sense_keys*/0, 93476293Sjoerg sizeof(sony_mo_entries)/sizeof(struct asc_table_entry), 93576293Sjoerg /*sense key entries*/NULL, 93676293Sjoerg sony_mo_entries 937252204Smav }, 938252204Smav { 939252204Smav /* 940252204Smav * HGST vendor-specific error codes 941252204Smav */ 942252204Smav {T_DIRECT, SIP_MEDIA_FIXED, "HGST", "*", "*"}, 943252204Smav /*num_sense_keys*/0, 944252204Smav sizeof(hgst_entries)/sizeof(struct asc_table_entry), 945252204Smav /*sense key entries*/NULL, 946252204Smav hgst_entries 947252204Smav }, 948252204Smav { 949252204Smav /* 950252204Smav * SEAGATE vendor-specific error codes 951252204Smav */ 952252204Smav {T_DIRECT, SIP_MEDIA_FIXED, "SEAGATE", "*", "*"}, 953252204Smav /*num_sense_keys*/0, 954252204Smav sizeof(seagate_entries)/sizeof(struct asc_table_entry), 955252204Smav /*sense key entries*/NULL, 956252204Smav seagate_entries 95739213Sgibbs } 95839213Sgibbs}; 95939213Sgibbs 96074840Skenconst int sense_quirk_table_size = 96174840Sken sizeof(sense_quirk_table)/sizeof(sense_quirk_table[0]); 96274840Sken 96374840Skenstatic struct asc_table_entry asc_table[] = { 964181381Sjkim /* 965181381Sjkim * From: http://www.t10.org/lists/asc-num.txt 966181381Sjkim * Modifications by Jung-uk Kim (jkim@FreeBSD.org) 967181381Sjkim */ 968181381Sjkim /* 969181381Sjkim * File: ASC-NUM.TXT 970181381Sjkim * 971181381Sjkim * SCSI ASC/ASCQ Assignments 972181381Sjkim * Numeric Sorted Listing 973288771Smav * as of 8/12/15 974181381Sjkim * 975181381Sjkim * D - DIRECT ACCESS DEVICE (SBC-2) device column key 976181381Sjkim * .T - SEQUENTIAL ACCESS DEVICE (SSC) ------------------- 977181381Sjkim * . L - PRINTER DEVICE (SSC) blank = reserved 978181381Sjkim * . P - PROCESSOR DEVICE (SPC) not blank = allowed 979181381Sjkim * . .W - WRITE ONCE READ MULTIPLE DEVICE (SBC-2) 980181381Sjkim * . . R - CD DEVICE (MMC) 981181381Sjkim * . . O - OPTICAL MEMORY DEVICE (SBC-2) 982181381Sjkim * . . .M - MEDIA CHANGER DEVICE (SMC) 983181381Sjkim * . . . A - STORAGE ARRAY DEVICE (SCC) 984181381Sjkim * . . . E - ENCLOSURE SERVICES DEVICE (SES) 985181381Sjkim * . . . .B - SIMPLIFIED DIRECT-ACCESS DEVICE (RBC) 986181381Sjkim * . . . . K - OPTICAL CARD READER/WRITER DEVICE (OCRW) 987181381Sjkim * . . . . V - AUTOMATION/DRIVE INTERFACE (ADC) 988181381Sjkim * . . . . .F - OBJECT-BASED STORAGE (OSD) 989181381Sjkim * DTLPWROMAEBKVF 990181381Sjkim * ASC ASCQ Action 991181381Sjkim * Description 992181381Sjkim */ 993181381Sjkim /* DTLPWROMAEBKVF */ 994181381Sjkim { SST(0x00, 0x00, SS_NOP, 995181381Sjkim "No additional sense information") }, 996181381Sjkim /* T */ 997181381Sjkim { SST(0x00, 0x01, SS_RDEF, 998181381Sjkim "Filemark detected") }, 999181381Sjkim /* T */ 1000181381Sjkim { SST(0x00, 0x02, SS_RDEF, 1001181381Sjkim "End-of-partition/medium detected") }, 1002181381Sjkim /* T */ 1003181381Sjkim { SST(0x00, 0x03, SS_RDEF, 1004181381Sjkim "Setmark detected") }, 1005181381Sjkim /* T */ 1006181381Sjkim { SST(0x00, 0x04, SS_RDEF, 1007181381Sjkim "Beginning-of-partition/medium detected") }, 1008181381Sjkim /* TL */ 1009181381Sjkim { SST(0x00, 0x05, SS_RDEF, 1010181381Sjkim "End-of-data detected") }, 1011181381Sjkim /* DTLPWROMAEBKVF */ 1012181381Sjkim { SST(0x00, 0x06, SS_RDEF, 1013181381Sjkim "I/O process terminated") }, 1014181381Sjkim /* T */ 1015181381Sjkim { SST(0x00, 0x07, SS_RDEF, /* XXX TBD */ 1016181381Sjkim "Programmable early warning detected") }, 1017181381Sjkim /* R */ 1018181381Sjkim { SST(0x00, 0x11, SS_FATAL | EBUSY, 1019181381Sjkim "Audio play operation in progress") }, 1020181381Sjkim /* R */ 1021181381Sjkim { SST(0x00, 0x12, SS_NOP, 1022181381Sjkim "Audio play operation paused") }, 1023181381Sjkim /* R */ 1024181381Sjkim { SST(0x00, 0x13, SS_NOP, 1025181381Sjkim "Audio play operation successfully completed") }, 1026181381Sjkim /* R */ 1027181381Sjkim { SST(0x00, 0x14, SS_RDEF, 1028181381Sjkim "Audio play operation stopped due to error") }, 1029181381Sjkim /* R */ 1030181381Sjkim { SST(0x00, 0x15, SS_NOP, 1031181381Sjkim "No current audio status to return") }, 1032181381Sjkim /* DTLPWROMAEBKVF */ 1033181381Sjkim { SST(0x00, 0x16, SS_FATAL | EBUSY, 1034181381Sjkim "Operation in progress") }, 1035181381Sjkim /* DTL WROMAEBKVF */ 1036181381Sjkim { SST(0x00, 0x17, SS_RDEF, 1037181381Sjkim "Cleaning requested") }, 1038181381Sjkim /* T */ 1039181381Sjkim { SST(0x00, 0x18, SS_RDEF, /* XXX TBD */ 1040181381Sjkim "Erase operation in progress") }, 1041181381Sjkim /* T */ 1042181381Sjkim { SST(0x00, 0x19, SS_RDEF, /* XXX TBD */ 1043181381Sjkim "Locate operation in progress") }, 1044181381Sjkim /* T */ 1045181381Sjkim { SST(0x00, 0x1A, SS_RDEF, /* XXX TBD */ 1046181381Sjkim "Rewind operation in progress") }, 1047181381Sjkim /* T */ 1048181381Sjkim { SST(0x00, 0x1B, SS_RDEF, /* XXX TBD */ 1049181381Sjkim "Set capacity operation in progress") }, 1050181381Sjkim /* T */ 1051181381Sjkim { SST(0x00, 0x1C, SS_RDEF, /* XXX TBD */ 1052181381Sjkim "Verify operation in progress") }, 1053181381Sjkim /* DT B */ 1054306154Smav { SST(0x00, 0x1D, SS_NOP, 1055181381Sjkim "ATA pass through information available") }, 1056181381Sjkim /* DT R MAEBKV */ 1057181381Sjkim { SST(0x00, 0x1E, SS_RDEF, /* XXX TBD */ 1058181381Sjkim "Conflicting SA creation request") }, 1059238595Smav /* DT B */ 1060238595Smav { SST(0x00, 0x1F, SS_RDEF, /* XXX TBD */ 1061238595Smav "Logical unit transitioning to another power condition") }, 1062238595Smav /* DT P B */ 1063306155Smav { SST(0x00, 0x20, SS_NOP, 1064238595Smav "Extended copy information available") }, 1065288771Smav /* D */ 1066288771Smav { SST(0x00, 0x21, SS_RDEF, /* XXX TBD */ 1067288771Smav "Atomic command aborted due to ACA") }, 1068181381Sjkim /* D W O BK */ 1069181381Sjkim { SST(0x01, 0x00, SS_RDEF, 1070181381Sjkim "No index/sector signal") }, 1071181381Sjkim /* D WRO BK */ 1072181381Sjkim { SST(0x02, 0x00, SS_RDEF, 1073181381Sjkim "No seek complete") }, 1074181381Sjkim /* DTL W O BK */ 1075181381Sjkim { SST(0x03, 0x00, SS_RDEF, 1076181381Sjkim "Peripheral device write fault") }, 1077181381Sjkim /* T */ 1078181381Sjkim { SST(0x03, 0x01, SS_RDEF, 1079181381Sjkim "No write current") }, 1080181381Sjkim /* T */ 1081181381Sjkim { SST(0x03, 0x02, SS_RDEF, 1082181381Sjkim "Excessive write errors") }, 1083181381Sjkim /* DTLPWROMAEBKVF */ 1084249352Smav { SST(0x04, 0x00, SS_RDEF, 1085181381Sjkim "Logical unit not ready, cause not reportable") }, 1086181381Sjkim /* DTLPWROMAEBKVF */ 1087288354Smav { SST(0x04, 0x01, SS_WAIT | EBUSY, 1088181381Sjkim "Logical unit is in process of becoming ready") }, 1089181381Sjkim /* DTLPWROMAEBKVF */ 1090181381Sjkim { SST(0x04, 0x02, SS_START | SSQ_DECREMENT_COUNT | ENXIO, 1091181381Sjkim "Logical unit not ready, initializing command required") }, 1092181381Sjkim /* DTLPWROMAEBKVF */ 1093181381Sjkim { SST(0x04, 0x03, SS_FATAL | ENXIO, 1094181381Sjkim "Logical unit not ready, manual intervention required") }, 1095181381Sjkim /* DTL RO B */ 1096181381Sjkim { SST(0x04, 0x04, SS_FATAL | EBUSY, 1097181381Sjkim "Logical unit not ready, format in progress") }, 1098181381Sjkim /* DT W O A BK F */ 1099181381Sjkim { SST(0x04, 0x05, SS_FATAL | EBUSY, 1100181381Sjkim "Logical unit not ready, rebuild in progress") }, 1101181381Sjkim /* DT W O A BK */ 1102181381Sjkim { SST(0x04, 0x06, SS_FATAL | EBUSY, 1103181381Sjkim "Logical unit not ready, recalculation in progress") }, 1104181381Sjkim /* DTLPWROMAEBKVF */ 1105181381Sjkim { SST(0x04, 0x07, SS_FATAL | EBUSY, 1106181381Sjkim "Logical unit not ready, operation in progress") }, 1107181381Sjkim /* R */ 1108181381Sjkim { SST(0x04, 0x08, SS_FATAL | EBUSY, 1109181381Sjkim "Logical unit not ready, long write in progress") }, 1110181381Sjkim /* DTLPWROMAEBKVF */ 1111181381Sjkim { SST(0x04, 0x09, SS_RDEF, /* XXX TBD */ 1112181381Sjkim "Logical unit not ready, self-test in progress") }, 1113181381Sjkim /* DTLPWROMAEBKVF */ 1114288354Smav { SST(0x04, 0x0A, SS_WAIT | ENXIO, 1115181381Sjkim "Logical unit not accessible, asymmetric access state transition")}, 1116181381Sjkim /* DTLPWROMAEBKVF */ 1117275722Smav { SST(0x04, 0x0B, SS_FATAL | ENXIO, 1118181381Sjkim "Logical unit not accessible, target port in standby state") }, 1119181381Sjkim /* DTLPWROMAEBKVF */ 1120275722Smav { SST(0x04, 0x0C, SS_FATAL | ENXIO, 1121181381Sjkim "Logical unit not accessible, target port in unavailable state") }, 1122181381Sjkim /* F */ 1123181381Sjkim { SST(0x04, 0x0D, SS_RDEF, /* XXX TBD */ 1124181381Sjkim "Logical unit not ready, structure check required") }, 1125288771Smav /* DTL WR MAEBKVF */ 1126288771Smav { SST(0x04, 0x0E, SS_RDEF, /* XXX TBD */ 1127288771Smav "Logical unit not ready, security session in progress") }, 1128181381Sjkim /* DT WROM B */ 1129181381Sjkim { SST(0x04, 0x10, SS_RDEF, /* XXX TBD */ 1130181381Sjkim "Logical unit not ready, auxiliary memory not accessible") }, 1131181381Sjkim /* DT WRO AEB VF */ 1132288354Smav { SST(0x04, 0x11, SS_WAIT | EBUSY, 1133181381Sjkim "Logical unit not ready, notify (enable spinup) required") }, 1134181381Sjkim /* M V */ 1135181381Sjkim { SST(0x04, 0x12, SS_RDEF, /* XXX TBD */ 1136181381Sjkim "Logical unit not ready, offline") }, 1137181381Sjkim /* DT R MAEBKV */ 1138181381Sjkim { SST(0x04, 0x13, SS_RDEF, /* XXX TBD */ 1139181381Sjkim "Logical unit not ready, SA creation in progress") }, 1140238595Smav /* D B */ 1141238595Smav { SST(0x04, 0x14, SS_RDEF, /* XXX TBD */ 1142238595Smav "Logical unit not ready, space allocation in progress") }, 1143238595Smav /* M */ 1144238595Smav { SST(0x04, 0x15, SS_RDEF, /* XXX TBD */ 1145238595Smav "Logical unit not ready, robotics disabled") }, 1146238595Smav /* M */ 1147238595Smav { SST(0x04, 0x16, SS_RDEF, /* XXX TBD */ 1148238595Smav "Logical unit not ready, configuration required") }, 1149238595Smav /* M */ 1150238595Smav { SST(0x04, 0x17, SS_RDEF, /* XXX TBD */ 1151238595Smav "Logical unit not ready, calibration required") }, 1152238595Smav /* M */ 1153238595Smav { SST(0x04, 0x18, SS_RDEF, /* XXX TBD */ 1154238595Smav "Logical unit not ready, a door is open") }, 1155238595Smav /* M */ 1156238595Smav { SST(0x04, 0x19, SS_RDEF, /* XXX TBD */ 1157238595Smav "Logical unit not ready, operating in sequential mode") }, 1158238595Smav /* DT B */ 1159238595Smav { SST(0x04, 0x1A, SS_RDEF, /* XXX TBD */ 1160238595Smav "Logical unit not ready, START/STOP UNIT command in progress") }, 1161238595Smav /* D B */ 1162238595Smav { SST(0x04, 0x1B, SS_RDEF, /* XXX TBD */ 1163238595Smav "Logical unit not ready, sanitize in progress") }, 1164238595Smav /* DT MAEB */ 1165238595Smav { SST(0x04, 0x1C, SS_RDEF, /* XXX TBD */ 1166238595Smav "Logical unit not ready, additional power use not yet granted") }, 1167288771Smav /* D */ 1168288771Smav { SST(0x04, 0x1D, SS_RDEF, /* XXX TBD */ 1169288771Smav "Logical unit not ready, configuration in progress") }, 1170288771Smav /* D */ 1171288771Smav { SST(0x04, 0x1E, SS_FATAL | ENXIO, 1172288771Smav "Logical unit not ready, microcode activation required") }, 1173288771Smav /* DTLPWROMAEBKVF */ 1174288771Smav { SST(0x04, 0x1F, SS_FATAL | ENXIO, 1175288771Smav "Logical unit not ready, microcode download required") }, 1176288771Smav /* DTLPWROMAEBKVF */ 1177288771Smav { SST(0x04, 0x20, SS_RDEF, /* XXX TBD */ 1178288771Smav "Logical unit not ready, logical unit reset required") }, 1179288771Smav /* DTLPWROMAEBKVF */ 1180288771Smav { SST(0x04, 0x21, SS_RDEF, /* XXX TBD */ 1181288771Smav "Logical unit not ready, hard reset required") }, 1182288771Smav /* DTLPWROMAEBKVF */ 1183288771Smav { SST(0x04, 0x22, SS_RDEF, /* XXX TBD */ 1184288771Smav "Logical unit not ready, power cycle required") }, 1185181381Sjkim /* DTL WROMAEBKVF */ 1186181381Sjkim { SST(0x05, 0x00, SS_RDEF, 1187181381Sjkim "Logical unit does not respond to selection") }, 1188181381Sjkim /* D WROM BK */ 1189181381Sjkim { SST(0x06, 0x00, SS_RDEF, 1190181381Sjkim "No reference position found") }, 1191181381Sjkim /* DTL WROM BK */ 1192181381Sjkim { SST(0x07, 0x00, SS_RDEF, 1193181381Sjkim "Multiple peripheral devices selected") }, 1194181381Sjkim /* DTL WROMAEBKVF */ 1195181381Sjkim { SST(0x08, 0x00, SS_RDEF, 1196181381Sjkim "Logical unit communication failure") }, 1197181381Sjkim /* DTL WROMAEBKVF */ 1198181381Sjkim { SST(0x08, 0x01, SS_RDEF, 1199181381Sjkim "Logical unit communication time-out") }, 1200181381Sjkim /* DTL WROMAEBKVF */ 1201181381Sjkim { SST(0x08, 0x02, SS_RDEF, 1202181381Sjkim "Logical unit communication parity error") }, 1203181381Sjkim /* DT ROM BK */ 1204181381Sjkim { SST(0x08, 0x03, SS_RDEF, 1205181381Sjkim "Logical unit communication CRC error (Ultra-DMA/32)") }, 1206181381Sjkim /* DTLPWRO K */ 1207181381Sjkim { SST(0x08, 0x04, SS_RDEF, /* XXX TBD */ 1208181381Sjkim "Unreachable copy target") }, 1209181381Sjkim /* DT WRO B */ 1210181381Sjkim { SST(0x09, 0x00, SS_RDEF, 1211181381Sjkim "Track following error") }, 1212181381Sjkim /* WRO K */ 1213181381Sjkim { SST(0x09, 0x01, SS_RDEF, 1214181381Sjkim "Tracking servo failure") }, 1215181381Sjkim /* WRO K */ 1216181381Sjkim { SST(0x09, 0x02, SS_RDEF, 1217181381Sjkim "Focus servo failure") }, 1218181381Sjkim /* WRO */ 1219181381Sjkim { SST(0x09, 0x03, SS_RDEF, 1220181381Sjkim "Spindle servo failure") }, 1221181381Sjkim /* DT WRO B */ 1222181381Sjkim { SST(0x09, 0x04, SS_RDEF, 1223181381Sjkim "Head select fault") }, 1224288771Smav /* DT RO B */ 1225288771Smav { SST(0x09, 0x05, SS_RDEF, 1226288771Smav "Vibration induced tracking error") }, 1227181381Sjkim /* DTLPWROMAEBKVF */ 1228181381Sjkim { SST(0x0A, 0x00, SS_FATAL | ENOSPC, 1229181381Sjkim "Error log overflow") }, 1230181381Sjkim /* DTLPWROMAEBKVF */ 1231311398Smav { SST(0x0B, 0x00, SS_NOP | SSQ_PRINT_SENSE, 1232181381Sjkim "Warning") }, 1233181381Sjkim /* DTLPWROMAEBKVF */ 1234311398Smav { SST(0x0B, 0x01, SS_NOP | SSQ_PRINT_SENSE, 1235181381Sjkim "Warning - specified temperature exceeded") }, 1236181381Sjkim /* DTLPWROMAEBKVF */ 1237311398Smav { SST(0x0B, 0x02, SS_NOP | SSQ_PRINT_SENSE, 1238181381Sjkim "Warning - enclosure degraded") }, 1239181381Sjkim /* DTLPWROMAEBKVF */ 1240311398Smav { SST(0x0B, 0x03, SS_NOP | SSQ_PRINT_SENSE, 1241181381Sjkim "Warning - background self-test failed") }, 1242181381Sjkim /* DTLPWRO AEBKVF */ 1243311398Smav { SST(0x0B, 0x04, SS_NOP | SSQ_PRINT_SENSE, 1244181381Sjkim "Warning - background pre-scan detected medium error") }, 1245181381Sjkim /* DTLPWRO AEBKVF */ 1246311398Smav { SST(0x0B, 0x05, SS_NOP | SSQ_PRINT_SENSE, 1247181381Sjkim "Warning - background medium scan detected medium error") }, 1248181381Sjkim /* DTLPWROMAEBKVF */ 1249311398Smav { SST(0x0B, 0x06, SS_NOP | SSQ_PRINT_SENSE, 1250181381Sjkim "Warning - non-volatile cache now volatile") }, 1251181381Sjkim /* DTLPWROMAEBKVF */ 1252311398Smav { SST(0x0B, 0x07, SS_NOP | SSQ_PRINT_SENSE, 1253181381Sjkim "Warning - degraded power to non-volatile cache") }, 1254238595Smav /* DTLPWROMAEBKVF */ 1255311398Smav { SST(0x0B, 0x08, SS_NOP | SSQ_PRINT_SENSE, 1256238595Smav "Warning - power loss expected") }, 1257238595Smav /* D */ 1258311398Smav { SST(0x0B, 0x09, SS_NOP | SSQ_PRINT_SENSE, 1259238595Smav "Warning - device statistics notification available") }, 1260288771Smav /* DTLPWROMAEBKVF */ 1261311398Smav { SST(0x0B, 0x0A, SS_NOP | SSQ_PRINT_SENSE, 1262288771Smav "Warning - High critical temperature limit exceeded") }, 1263288771Smav /* DTLPWROMAEBKVF */ 1264311398Smav { SST(0x0B, 0x0B, SS_NOP | SSQ_PRINT_SENSE, 1265288771Smav "Warning - Low critical temperature limit exceeded") }, 1266288771Smav /* DTLPWROMAEBKVF */ 1267311398Smav { SST(0x0B, 0x0C, SS_NOP | SSQ_PRINT_SENSE, 1268288771Smav "Warning - High operating temperature limit exceeded") }, 1269288771Smav /* DTLPWROMAEBKVF */ 1270311398Smav { SST(0x0B, 0x0D, SS_NOP | SSQ_PRINT_SENSE, 1271288771Smav "Warning - Low operating temperature limit exceeded") }, 1272288771Smav /* DTLPWROMAEBKVF */ 1273311398Smav { SST(0x0B, 0x0E, SS_NOP | SSQ_PRINT_SENSE, 1274288771Smav "Warning - High citical humidity limit exceeded") }, 1275288771Smav /* DTLPWROMAEBKVF */ 1276311398Smav { SST(0x0B, 0x0F, SS_NOP | SSQ_PRINT_SENSE, 1277288771Smav "Warning - Low citical humidity limit exceeded") }, 1278288771Smav /* DTLPWROMAEBKVF */ 1279311398Smav { SST(0x0B, 0x10, SS_NOP | SSQ_PRINT_SENSE, 1280288771Smav "Warning - High operating humidity limit exceeded") }, 1281288771Smav /* DTLPWROMAEBKVF */ 1282311398Smav { SST(0x0B, 0x11, SS_NOP | SSQ_PRINT_SENSE, 1283288771Smav "Warning - Low operating humidity limit exceeded") }, 1284181381Sjkim /* T R */ 1285181381Sjkim { SST(0x0C, 0x00, SS_RDEF, 1286181381Sjkim "Write error") }, 1287181381Sjkim /* K */ 1288181381Sjkim { SST(0x0C, 0x01, SS_NOP | SSQ_PRINT_SENSE, 1289181381Sjkim "Write error - recovered with auto reallocation") }, 1290181381Sjkim /* D W O BK */ 1291181381Sjkim { SST(0x0C, 0x02, SS_RDEF, 1292181381Sjkim "Write error - auto reallocation failed") }, 1293181381Sjkim /* D W O BK */ 1294181381Sjkim { SST(0x0C, 0x03, SS_RDEF, 1295181381Sjkim "Write error - recommend reassignment") }, 1296181381Sjkim /* DT W O B */ 1297181381Sjkim { SST(0x0C, 0x04, SS_RDEF, 1298181381Sjkim "Compression check miscompare error") }, 1299181381Sjkim /* DT W O B */ 1300181381Sjkim { SST(0x0C, 0x05, SS_RDEF, 1301181381Sjkim "Data expansion occurred during compression") }, 1302181381Sjkim /* DT W O B */ 1303181381Sjkim { SST(0x0C, 0x06, SS_RDEF, 1304181381Sjkim "Block not compressible") }, 1305181381Sjkim /* R */ 1306181381Sjkim { SST(0x0C, 0x07, SS_RDEF, 1307181381Sjkim "Write error - recovery needed") }, 1308181381Sjkim /* R */ 1309181381Sjkim { SST(0x0C, 0x08, SS_RDEF, 1310181381Sjkim "Write error - recovery failed") }, 1311181381Sjkim /* R */ 1312181381Sjkim { SST(0x0C, 0x09, SS_RDEF, 1313181381Sjkim "Write error - loss of streaming") }, 1314181381Sjkim /* R */ 1315181381Sjkim { SST(0x0C, 0x0A, SS_RDEF, 1316181381Sjkim "Write error - padding blocks added") }, 1317181381Sjkim /* DT WROM B */ 1318181381Sjkim { SST(0x0C, 0x0B, SS_RDEF, /* XXX TBD */ 1319181381Sjkim "Auxiliary memory write error") }, 1320181381Sjkim /* DTLPWRO AEBKVF */ 1321181381Sjkim { SST(0x0C, 0x0C, SS_RDEF, /* XXX TBD */ 1322181381Sjkim "Write error - unexpected unsolicited data") }, 1323181381Sjkim /* DTLPWRO AEBKVF */ 1324181381Sjkim { SST(0x0C, 0x0D, SS_RDEF, /* XXX TBD */ 1325181381Sjkim "Write error - not enough unsolicited data") }, 1326238595Smav /* DT W O BK */ 1327238595Smav { SST(0x0C, 0x0E, SS_RDEF, /* XXX TBD */ 1328238595Smav "Multiple write errors") }, 1329181381Sjkim /* R */ 1330181381Sjkim { SST(0x0C, 0x0F, SS_RDEF, /* XXX TBD */ 1331181381Sjkim "Defects in error window") }, 1332288771Smav /* D */ 1333288771Smav { SST(0x0C, 0x10, SS_RDEF, /* XXX TBD */ 1334288771Smav "Incomplete multiple atomic write operations") }, 1335288771Smav /* D */ 1336288771Smav { SST(0x0C, 0x11, SS_RDEF, /* XXX TBD */ 1337288771Smav "Write error - recovery scan needed") }, 1338288771Smav /* D */ 1339288771Smav { SST(0x0C, 0x12, SS_RDEF, /* XXX TBD */ 1340288771Smav "Write error - insufficient zone resources") }, 1341181381Sjkim /* DTLPWRO A K */ 1342181381Sjkim { SST(0x0D, 0x00, SS_RDEF, /* XXX TBD */ 1343181381Sjkim "Error detected by third party temporary initiator") }, 1344181381Sjkim /* DTLPWRO A K */ 1345181381Sjkim { SST(0x0D, 0x01, SS_RDEF, /* XXX TBD */ 1346181381Sjkim "Third party device failure") }, 1347181381Sjkim /* DTLPWRO A K */ 1348181381Sjkim { SST(0x0D, 0x02, SS_RDEF, /* XXX TBD */ 1349181381Sjkim "Copy target device not reachable") }, 1350181381Sjkim /* DTLPWRO A K */ 1351181381Sjkim { SST(0x0D, 0x03, SS_RDEF, /* XXX TBD */ 1352181381Sjkim "Incorrect copy target device type") }, 1353181381Sjkim /* DTLPWRO A K */ 1354181381Sjkim { SST(0x0D, 0x04, SS_RDEF, /* XXX TBD */ 1355181381Sjkim "Copy target device data underrun") }, 1356181381Sjkim /* DTLPWRO A K */ 1357181381Sjkim { SST(0x0D, 0x05, SS_RDEF, /* XXX TBD */ 1358181381Sjkim "Copy target device data overrun") }, 1359181381Sjkim /* DT PWROMAEBK F */ 1360181381Sjkim { SST(0x0E, 0x00, SS_RDEF, /* XXX TBD */ 1361181381Sjkim "Invalid information unit") }, 1362181381Sjkim /* DT PWROMAEBK F */ 1363181381Sjkim { SST(0x0E, 0x01, SS_RDEF, /* XXX TBD */ 1364181381Sjkim "Information unit too short") }, 1365181381Sjkim /* DT PWROMAEBK F */ 1366181381Sjkim { SST(0x0E, 0x02, SS_RDEF, /* XXX TBD */ 1367181381Sjkim "Information unit too long") }, 1368181381Sjkim /* DT P R MAEBK F */ 1369313365Smav { SST(0x0E, 0x03, SS_FATAL | EINVAL, 1370181381Sjkim "Invalid field in command information unit") }, 1371181381Sjkim /* D W O BK */ 1372181381Sjkim { SST(0x10, 0x00, SS_RDEF, 1373181381Sjkim "ID CRC or ECC error") }, 1374181381Sjkim /* DT W O */ 1375181381Sjkim { SST(0x10, 0x01, SS_RDEF, /* XXX TBD */ 1376181381Sjkim "Logical block guard check failed") }, 1377181381Sjkim /* DT W O */ 1378181381Sjkim { SST(0x10, 0x02, SS_RDEF, /* XXX TBD */ 1379181381Sjkim "Logical block application tag check failed") }, 1380181381Sjkim /* DT W O */ 1381181381Sjkim { SST(0x10, 0x03, SS_RDEF, /* XXX TBD */ 1382181381Sjkim "Logical block reference tag check failed") }, 1383238595Smav /* T */ 1384238595Smav { SST(0x10, 0x04, SS_RDEF, /* XXX TBD */ 1385238595Smav "Logical block protection error on recovered buffer data") }, 1386238595Smav /* T */ 1387238595Smav { SST(0x10, 0x05, SS_RDEF, /* XXX TBD */ 1388238595Smav "Logical block protection method error") }, 1389181381Sjkim /* DT WRO BK */ 1390225950Sken { SST(0x11, 0x00, SS_FATAL|EIO, 1391181381Sjkim "Unrecovered read error") }, 1392181381Sjkim /* DT WRO BK */ 1393225950Sken { SST(0x11, 0x01, SS_FATAL|EIO, 1394181381Sjkim "Read retries exhausted") }, 1395181381Sjkim /* DT WRO BK */ 1396225950Sken { SST(0x11, 0x02, SS_FATAL|EIO, 1397181381Sjkim "Error too long to correct") }, 1398181381Sjkim /* DT W O BK */ 1399225950Sken { SST(0x11, 0x03, SS_FATAL|EIO, 1400181381Sjkim "Multiple read errors") }, 1401181381Sjkim /* D W O BK */ 1402225950Sken { SST(0x11, 0x04, SS_FATAL|EIO, 1403181381Sjkim "Unrecovered read error - auto reallocate failed") }, 1404181381Sjkim /* WRO B */ 1405225950Sken { SST(0x11, 0x05, SS_FATAL|EIO, 1406181381Sjkim "L-EC uncorrectable error") }, 1407181381Sjkim /* WRO B */ 1408225950Sken { SST(0x11, 0x06, SS_FATAL|EIO, 1409181381Sjkim "CIRC unrecovered error") }, 1410181381Sjkim /* W O B */ 1411181381Sjkim { SST(0x11, 0x07, SS_RDEF, 1412181381Sjkim "Data re-synchronization error") }, 1413181381Sjkim /* T */ 1414181381Sjkim { SST(0x11, 0x08, SS_RDEF, 1415181381Sjkim "Incomplete block read") }, 1416181381Sjkim /* T */ 1417181381Sjkim { SST(0x11, 0x09, SS_RDEF, 1418181381Sjkim "No gap found") }, 1419181381Sjkim /* DT O BK */ 1420181381Sjkim { SST(0x11, 0x0A, SS_RDEF, 1421181381Sjkim "Miscorrected error") }, 1422181381Sjkim /* D W O BK */ 1423225950Sken { SST(0x11, 0x0B, SS_FATAL|EIO, 1424181381Sjkim "Unrecovered read error - recommend reassignment") }, 1425181381Sjkim /* D W O BK */ 1426225950Sken { SST(0x11, 0x0C, SS_FATAL|EIO, 1427181381Sjkim "Unrecovered read error - recommend rewrite the data") }, 1428181381Sjkim /* DT WRO B */ 1429181381Sjkim { SST(0x11, 0x0D, SS_RDEF, 1430181381Sjkim "De-compression CRC error") }, 1431181381Sjkim /* DT WRO B */ 1432181381Sjkim { SST(0x11, 0x0E, SS_RDEF, 1433181381Sjkim "Cannot decompress using declared algorithm") }, 1434181381Sjkim /* R */ 1435181381Sjkim { SST(0x11, 0x0F, SS_RDEF, 1436181381Sjkim "Error reading UPC/EAN number") }, 1437181381Sjkim /* R */ 1438181381Sjkim { SST(0x11, 0x10, SS_RDEF, 1439181381Sjkim "Error reading ISRC number") }, 1440181381Sjkim /* R */ 1441181381Sjkim { SST(0x11, 0x11, SS_RDEF, 1442181381Sjkim "Read error - loss of streaming") }, 1443181381Sjkim /* DT WROM B */ 1444181381Sjkim { SST(0x11, 0x12, SS_RDEF, /* XXX TBD */ 1445181381Sjkim "Auxiliary memory read error") }, 1446181381Sjkim /* DTLPWRO AEBKVF */ 1447181381Sjkim { SST(0x11, 0x13, SS_RDEF, /* XXX TBD */ 1448181381Sjkim "Read error - failed retransmission request") }, 1449181381Sjkim /* D */ 1450181381Sjkim { SST(0x11, 0x14, SS_RDEF, /* XXX TBD */ 1451181381Sjkim "Read error - LBA marked bad by application client") }, 1452288771Smav /* D */ 1453288771Smav { SST(0x11, 0x15, SS_RDEF, /* XXX TBD */ 1454288771Smav "Write after sanitize required") }, 1455181381Sjkim /* D W O BK */ 1456181381Sjkim { SST(0x12, 0x00, SS_RDEF, 1457181381Sjkim "Address mark not found for ID field") }, 1458181381Sjkim /* D W O BK */ 1459181381Sjkim { SST(0x13, 0x00, SS_RDEF, 1460181381Sjkim "Address mark not found for data field") }, 1461181381Sjkim /* DTL WRO BK */ 1462181381Sjkim { SST(0x14, 0x00, SS_RDEF, 1463181381Sjkim "Recorded entity not found") }, 1464181381Sjkim /* DT WRO BK */ 1465181381Sjkim { SST(0x14, 0x01, SS_RDEF, 1466181381Sjkim "Record not found") }, 1467181381Sjkim /* T */ 1468181381Sjkim { SST(0x14, 0x02, SS_RDEF, 1469181381Sjkim "Filemark or setmark not found") }, 1470181381Sjkim /* T */ 1471181381Sjkim { SST(0x14, 0x03, SS_RDEF, 1472181381Sjkim "End-of-data not found") }, 1473181381Sjkim /* T */ 1474181381Sjkim { SST(0x14, 0x04, SS_RDEF, 1475181381Sjkim "Block sequence error") }, 1476181381Sjkim /* DT W O BK */ 1477181381Sjkim { SST(0x14, 0x05, SS_RDEF, 1478181381Sjkim "Record not found - recommend reassignment") }, 1479181381Sjkim /* DT W O BK */ 1480181381Sjkim { SST(0x14, 0x06, SS_RDEF, 1481181381Sjkim "Record not found - data auto-reallocated") }, 1482181381Sjkim /* T */ 1483181381Sjkim { SST(0x14, 0x07, SS_RDEF, /* XXX TBD */ 1484181381Sjkim "Locate operation failure") }, 1485181381Sjkim /* DTL WROM BK */ 1486181381Sjkim { SST(0x15, 0x00, SS_RDEF, 1487181381Sjkim "Random positioning error") }, 1488181381Sjkim /* DTL WROM BK */ 1489181381Sjkim { SST(0x15, 0x01, SS_RDEF, 1490181381Sjkim "Mechanical positioning error") }, 1491181381Sjkim /* DT WRO BK */ 1492181381Sjkim { SST(0x15, 0x02, SS_RDEF, 1493181381Sjkim "Positioning error detected by read of medium") }, 1494181381Sjkim /* D W O BK */ 1495181381Sjkim { SST(0x16, 0x00, SS_RDEF, 1496181381Sjkim "Data synchronization mark error") }, 1497181381Sjkim /* D W O BK */ 1498181381Sjkim { SST(0x16, 0x01, SS_RDEF, 1499181381Sjkim "Data sync error - data rewritten") }, 1500181381Sjkim /* D W O BK */ 1501181381Sjkim { SST(0x16, 0x02, SS_RDEF, 1502181381Sjkim "Data sync error - recommend rewrite") }, 1503181381Sjkim /* D W O BK */ 1504181381Sjkim { SST(0x16, 0x03, SS_NOP | SSQ_PRINT_SENSE, 1505181381Sjkim "Data sync error - data auto-reallocated") }, 1506181381Sjkim /* D W O BK */ 1507181381Sjkim { SST(0x16, 0x04, SS_RDEF, 1508181381Sjkim "Data sync error - recommend reassignment") }, 1509181381Sjkim /* DT WRO BK */ 1510181381Sjkim { SST(0x17, 0x00, SS_NOP | SSQ_PRINT_SENSE, 1511181381Sjkim "Recovered data with no error correction applied") }, 1512181381Sjkim /* DT WRO BK */ 1513181381Sjkim { SST(0x17, 0x01, SS_NOP | SSQ_PRINT_SENSE, 1514181381Sjkim "Recovered data with retries") }, 1515181381Sjkim /* DT WRO BK */ 1516181381Sjkim { SST(0x17, 0x02, SS_NOP | SSQ_PRINT_SENSE, 1517181381Sjkim "Recovered data with positive head offset") }, 1518181381Sjkim /* DT WRO BK */ 1519181381Sjkim { SST(0x17, 0x03, SS_NOP | SSQ_PRINT_SENSE, 1520181381Sjkim "Recovered data with negative head offset") }, 1521181381Sjkim /* WRO B */ 1522181381Sjkim { SST(0x17, 0x04, SS_NOP | SSQ_PRINT_SENSE, 1523181381Sjkim "Recovered data with retries and/or CIRC applied") }, 1524181381Sjkim /* D WRO BK */ 1525181381Sjkim { SST(0x17, 0x05, SS_NOP | SSQ_PRINT_SENSE, 1526181381Sjkim "Recovered data using previous sector ID") }, 1527181381Sjkim /* D W O BK */ 1528181381Sjkim { SST(0x17, 0x06, SS_NOP | SSQ_PRINT_SENSE, 1529181381Sjkim "Recovered data without ECC - data auto-reallocated") }, 1530181381Sjkim /* D WRO BK */ 1531181381Sjkim { SST(0x17, 0x07, SS_NOP | SSQ_PRINT_SENSE, 1532181381Sjkim "Recovered data without ECC - recommend reassignment") }, 1533181381Sjkim /* D WRO BK */ 1534181381Sjkim { SST(0x17, 0x08, SS_NOP | SSQ_PRINT_SENSE, 1535181381Sjkim "Recovered data without ECC - recommend rewrite") }, 1536181381Sjkim /* D WRO BK */ 1537181381Sjkim { SST(0x17, 0x09, SS_NOP | SSQ_PRINT_SENSE, 1538181381Sjkim "Recovered data without ECC - data rewritten") }, 1539181381Sjkim /* DT WRO BK */ 1540181381Sjkim { SST(0x18, 0x00, SS_NOP | SSQ_PRINT_SENSE, 1541181381Sjkim "Recovered data with error correction applied") }, 1542181381Sjkim /* D WRO BK */ 1543181381Sjkim { SST(0x18, 0x01, SS_NOP | SSQ_PRINT_SENSE, 1544181381Sjkim "Recovered data with error corr. & retries applied") }, 1545181381Sjkim /* D WRO BK */ 1546181381Sjkim { SST(0x18, 0x02, SS_NOP | SSQ_PRINT_SENSE, 1547181381Sjkim "Recovered data - data auto-reallocated") }, 1548181381Sjkim /* R */ 1549181381Sjkim { SST(0x18, 0x03, SS_NOP | SSQ_PRINT_SENSE, 1550181381Sjkim "Recovered data with CIRC") }, 1551181381Sjkim /* R */ 1552181381Sjkim { SST(0x18, 0x04, SS_NOP | SSQ_PRINT_SENSE, 1553181381Sjkim "Recovered data with L-EC") }, 1554181381Sjkim /* D WRO BK */ 1555181381Sjkim { SST(0x18, 0x05, SS_NOP | SSQ_PRINT_SENSE, 1556181381Sjkim "Recovered data - recommend reassignment") }, 1557181381Sjkim /* D WRO BK */ 1558181381Sjkim { SST(0x18, 0x06, SS_NOP | SSQ_PRINT_SENSE, 1559181381Sjkim "Recovered data - recommend rewrite") }, 1560181381Sjkim /* D W O BK */ 1561181381Sjkim { SST(0x18, 0x07, SS_NOP | SSQ_PRINT_SENSE, 1562181381Sjkim "Recovered data with ECC - data rewritten") }, 1563181381Sjkim /* R */ 1564181381Sjkim { SST(0x18, 0x08, SS_RDEF, /* XXX TBD */ 1565181381Sjkim "Recovered data with linking") }, 1566181381Sjkim /* D O K */ 1567181381Sjkim { SST(0x19, 0x00, SS_RDEF, 1568181381Sjkim "Defect list error") }, 1569181381Sjkim /* D O K */ 1570181381Sjkim { SST(0x19, 0x01, SS_RDEF, 1571181381Sjkim "Defect list not available") }, 1572181381Sjkim /* D O K */ 1573181381Sjkim { SST(0x19, 0x02, SS_RDEF, 1574181381Sjkim "Defect list error in primary list") }, 1575181381Sjkim /* D O K */ 1576181381Sjkim { SST(0x19, 0x03, SS_RDEF, 1577181381Sjkim "Defect list error in grown list") }, 1578181381Sjkim /* DTLPWROMAEBKVF */ 1579181381Sjkim { SST(0x1A, 0x00, SS_RDEF, 1580181381Sjkim "Parameter list length error") }, 1581181381Sjkim /* DTLPWROMAEBKVF */ 1582181381Sjkim { SST(0x1B, 0x00, SS_RDEF, 1583181381Sjkim "Synchronous data transfer error") }, 1584181381Sjkim /* D O BK */ 1585181381Sjkim { SST(0x1C, 0x00, SS_RDEF, 1586181381Sjkim "Defect list not found") }, 1587181381Sjkim /* D O BK */ 1588181381Sjkim { SST(0x1C, 0x01, SS_RDEF, 1589181381Sjkim "Primary defect list not found") }, 1590181381Sjkim /* D O BK */ 1591181381Sjkim { SST(0x1C, 0x02, SS_RDEF, 1592181381Sjkim "Grown defect list not found") }, 1593181381Sjkim /* DT WRO BK */ 1594181381Sjkim { SST(0x1D, 0x00, SS_FATAL, 1595181381Sjkim "Miscompare during verify operation") }, 1596238595Smav /* D B */ 1597238595Smav { SST(0x1D, 0x01, SS_RDEF, /* XXX TBD */ 1598238595Smav "Miscomparable verify of unmapped LBA") }, 1599181381Sjkim /* D W O BK */ 1600181381Sjkim { SST(0x1E, 0x00, SS_NOP | SSQ_PRINT_SENSE, 1601181381Sjkim "Recovered ID with ECC correction") }, 1602181381Sjkim /* D O K */ 1603181381Sjkim { SST(0x1F, 0x00, SS_RDEF, 1604181381Sjkim "Partial defect list transfer") }, 1605181381Sjkim /* DTLPWROMAEBKVF */ 1606181381Sjkim { SST(0x20, 0x00, SS_FATAL | EINVAL, 1607181381Sjkim "Invalid command operation code") }, 1608181381Sjkim /* DT PWROMAEBK */ 1609181381Sjkim { SST(0x20, 0x01, SS_RDEF, /* XXX TBD */ 1610181381Sjkim "Access denied - initiator pending-enrolled") }, 1611181381Sjkim /* DT PWROMAEBK */ 1612317941Sken { SST(0x20, 0x02, SS_FATAL | EPERM, 1613181381Sjkim "Access denied - no access rights") }, 1614181381Sjkim /* DT PWROMAEBK */ 1615181381Sjkim { SST(0x20, 0x03, SS_RDEF, /* XXX TBD */ 1616181381Sjkim "Access denied - invalid mgmt ID key") }, 1617181381Sjkim /* T */ 1618181381Sjkim { SST(0x20, 0x04, SS_RDEF, /* XXX TBD */ 1619181381Sjkim "Illegal command while in write capable state") }, 1620181381Sjkim /* T */ 1621181381Sjkim { SST(0x20, 0x05, SS_RDEF, /* XXX TBD */ 1622181381Sjkim "Obsolete") }, 1623181381Sjkim /* T */ 1624181381Sjkim { SST(0x20, 0x06, SS_RDEF, /* XXX TBD */ 1625181381Sjkim "Illegal command while in explicit address mode") }, 1626181381Sjkim /* T */ 1627181381Sjkim { SST(0x20, 0x07, SS_RDEF, /* XXX TBD */ 1628181381Sjkim "Illegal command while in implicit address mode") }, 1629181381Sjkim /* DT PWROMAEBK */ 1630181381Sjkim { SST(0x20, 0x08, SS_RDEF, /* XXX TBD */ 1631181381Sjkim "Access denied - enrollment conflict") }, 1632181381Sjkim /* DT PWROMAEBK */ 1633181381Sjkim { SST(0x20, 0x09, SS_RDEF, /* XXX TBD */ 1634181381Sjkim "Access denied - invalid LU identifier") }, 1635181381Sjkim /* DT PWROMAEBK */ 1636181381Sjkim { SST(0x20, 0x0A, SS_RDEF, /* XXX TBD */ 1637181381Sjkim "Access denied - invalid proxy token") }, 1638181381Sjkim /* DT PWROMAEBK */ 1639181381Sjkim { SST(0x20, 0x0B, SS_RDEF, /* XXX TBD */ 1640181381Sjkim "Access denied - ACL LUN conflict") }, 1641238595Smav /* T */ 1642238595Smav { SST(0x20, 0x0C, SS_FATAL | EINVAL, 1643238595Smav "Illegal command when not in append-only mode") }, 1644181381Sjkim /* DT WRO BK */ 1645181381Sjkim { SST(0x21, 0x00, SS_FATAL | EINVAL, 1646181381Sjkim "Logical block address out of range") }, 1647181381Sjkim /* DT WROM BK */ 1648181381Sjkim { SST(0x21, 0x01, SS_FATAL | EINVAL, 1649181381Sjkim "Invalid element address") }, 1650181381Sjkim /* R */ 1651181381Sjkim { SST(0x21, 0x02, SS_RDEF, /* XXX TBD */ 1652181381Sjkim "Invalid address for write") }, 1653181381Sjkim /* R */ 1654181381Sjkim { SST(0x21, 0x03, SS_RDEF, /* XXX TBD */ 1655181381Sjkim "Invalid write crossing layer jump") }, 1656181381Sjkim /* D */ 1657288771Smav { SST(0x21, 0x04, SS_RDEF, /* XXX TBD */ 1658288771Smav "Unaligned write command") }, 1659288771Smav /* D */ 1660288771Smav { SST(0x21, 0x05, SS_RDEF, /* XXX TBD */ 1661288771Smav "Write boundary violation") }, 1662288771Smav /* D */ 1663288771Smav { SST(0x21, 0x06, SS_RDEF, /* XXX TBD */ 1664288771Smav "Attempt to read invalid data") }, 1665288771Smav /* D */ 1666288771Smav { SST(0x21, 0x07, SS_RDEF, /* XXX TBD */ 1667288771Smav "Read boundary violation") }, 1668288771Smav /* D */ 1669181381Sjkim { SST(0x22, 0x00, SS_FATAL | EINVAL, 1670181381Sjkim "Illegal function (use 20 00, 24 00, or 26 00)") }, 1671238595Smav /* DT P B */ 1672272656Smav { SST(0x23, 0x00, SS_FATAL | EINVAL, 1673238595Smav "Invalid token operation, cause not reportable") }, 1674238595Smav /* DT P B */ 1675272656Smav { SST(0x23, 0x01, SS_FATAL | EINVAL, 1676238595Smav "Invalid token operation, unsupported token type") }, 1677238595Smav /* DT P B */ 1678272656Smav { SST(0x23, 0x02, SS_FATAL | EINVAL, 1679238595Smav "Invalid token operation, remote token usage not supported") }, 1680238595Smav /* DT P B */ 1681272656Smav { SST(0x23, 0x03, SS_FATAL | EINVAL, 1682238595Smav "Invalid token operation, remote ROD token creation not supported") }, 1683238595Smav /* DT P B */ 1684272656Smav { SST(0x23, 0x04, SS_FATAL | EINVAL, 1685238595Smav "Invalid token operation, token unknown") }, 1686238595Smav /* DT P B */ 1687272656Smav { SST(0x23, 0x05, SS_FATAL | EINVAL, 1688238595Smav "Invalid token operation, token corrupt") }, 1689238595Smav /* DT P B */ 1690272656Smav { SST(0x23, 0x06, SS_FATAL | EINVAL, 1691238595Smav "Invalid token operation, token revoked") }, 1692238595Smav /* DT P B */ 1693272656Smav { SST(0x23, 0x07, SS_FATAL | EINVAL, 1694238595Smav "Invalid token operation, token expired") }, 1695238595Smav /* DT P B */ 1696272656Smav { SST(0x23, 0x08, SS_FATAL | EINVAL, 1697238595Smav "Invalid token operation, token cancelled") }, 1698238595Smav /* DT P B */ 1699272656Smav { SST(0x23, 0x09, SS_FATAL | EINVAL, 1700238595Smav "Invalid token operation, token deleted") }, 1701238595Smav /* DT P B */ 1702272656Smav { SST(0x23, 0x0A, SS_FATAL | EINVAL, 1703238595Smav "Invalid token operation, invalid token length") }, 1704181381Sjkim /* DTLPWROMAEBKVF */ 1705181381Sjkim { SST(0x24, 0x00, SS_FATAL | EINVAL, 1706181381Sjkim "Invalid field in CDB") }, 1707181381Sjkim /* DTLPWRO AEBKVF */ 1708181381Sjkim { SST(0x24, 0x01, SS_RDEF, /* XXX TBD */ 1709181381Sjkim "CDB decryption error") }, 1710181381Sjkim /* T */ 1711181381Sjkim { SST(0x24, 0x02, SS_RDEF, /* XXX TBD */ 1712181381Sjkim "Obsolete") }, 1713181381Sjkim /* T */ 1714181381Sjkim { SST(0x24, 0x03, SS_RDEF, /* XXX TBD */ 1715181381Sjkim "Obsolete") }, 1716181381Sjkim /* F */ 1717181381Sjkim { SST(0x24, 0x04, SS_RDEF, /* XXX TBD */ 1718181381Sjkim "Security audit value frozen") }, 1719181381Sjkim /* F */ 1720181381Sjkim { SST(0x24, 0x05, SS_RDEF, /* XXX TBD */ 1721181381Sjkim "Security working key frozen") }, 1722181381Sjkim /* F */ 1723181381Sjkim { SST(0x24, 0x06, SS_RDEF, /* XXX TBD */ 1724181381Sjkim "NONCE not unique") }, 1725181381Sjkim /* F */ 1726181381Sjkim { SST(0x24, 0x07, SS_RDEF, /* XXX TBD */ 1727181381Sjkim "NONCE timestamp out of range") }, 1728181381Sjkim /* DT R MAEBKV */ 1729181381Sjkim { SST(0x24, 0x08, SS_RDEF, /* XXX TBD */ 1730181381Sjkim "Invalid XCDB") }, 1731181381Sjkim /* DTLPWROMAEBKVF */ 1732253322Smav { SST(0x25, 0x00, SS_FATAL | ENXIO | SSQ_LOST, 1733181381Sjkim "Logical unit not supported") }, 1734181381Sjkim /* DTLPWROMAEBKVF */ 1735181381Sjkim { SST(0x26, 0x00, SS_FATAL | EINVAL, 1736181381Sjkim "Invalid field in parameter list") }, 1737181381Sjkim /* DTLPWROMAEBKVF */ 1738181381Sjkim { SST(0x26, 0x01, SS_FATAL | EINVAL, 1739181381Sjkim "Parameter not supported") }, 1740181381Sjkim /* DTLPWROMAEBKVF */ 1741181381Sjkim { SST(0x26, 0x02, SS_FATAL | EINVAL, 1742181381Sjkim "Parameter value invalid") }, 1743181381Sjkim /* DTLPWROMAE K */ 1744181381Sjkim { SST(0x26, 0x03, SS_FATAL | EINVAL, 1745181381Sjkim "Threshold parameters not supported") }, 1746181381Sjkim /* DTLPWROMAEBKVF */ 1747181381Sjkim { SST(0x26, 0x04, SS_FATAL | EINVAL, 1748181381Sjkim "Invalid release of persistent reservation") }, 1749181381Sjkim /* DTLPWRO A BK */ 1750181381Sjkim { SST(0x26, 0x05, SS_RDEF, /* XXX TBD */ 1751181381Sjkim "Data decryption error") }, 1752181381Sjkim /* DTLPWRO K */ 1753272657Smav { SST(0x26, 0x06, SS_FATAL | EINVAL, 1754181381Sjkim "Too many target descriptors") }, 1755181381Sjkim /* DTLPWRO K */ 1756272657Smav { SST(0x26, 0x07, SS_FATAL | EINVAL, 1757181381Sjkim "Unsupported target descriptor type code") }, 1758181381Sjkim /* DTLPWRO K */ 1759272657Smav { SST(0x26, 0x08, SS_FATAL | EINVAL, 1760181381Sjkim "Too many segment descriptors") }, 1761181381Sjkim /* DTLPWRO K */ 1762272657Smav { SST(0x26, 0x09, SS_FATAL | EINVAL, 1763181381Sjkim "Unsupported segment descriptor type code") }, 1764181381Sjkim /* DTLPWRO K */ 1765272657Smav { SST(0x26, 0x0A, SS_FATAL | EINVAL, 1766181381Sjkim "Unexpected inexact segment") }, 1767181381Sjkim /* DTLPWRO K */ 1768272657Smav { SST(0x26, 0x0B, SS_FATAL | EINVAL, 1769181381Sjkim "Inline data length exceeded") }, 1770181381Sjkim /* DTLPWRO K */ 1771272657Smav { SST(0x26, 0x0C, SS_FATAL | EINVAL, 1772181381Sjkim "Invalid operation for copy source or destination") }, 1773181381Sjkim /* DTLPWRO K */ 1774272657Smav { SST(0x26, 0x0D, SS_FATAL | EINVAL, 1775181381Sjkim "Copy segment granularity violation") }, 1776181381Sjkim /* DT PWROMAEBK */ 1777181381Sjkim { SST(0x26, 0x0E, SS_RDEF, /* XXX TBD */ 1778181381Sjkim "Invalid parameter while port is enabled") }, 1779181381Sjkim /* F */ 1780181381Sjkim { SST(0x26, 0x0F, SS_RDEF, /* XXX TBD */ 1781181381Sjkim "Invalid data-out buffer integrity check value") }, 1782181381Sjkim /* T */ 1783181381Sjkim { SST(0x26, 0x10, SS_RDEF, /* XXX TBD */ 1784181381Sjkim "Data decryption key fail limit reached") }, 1785181381Sjkim /* T */ 1786181381Sjkim { SST(0x26, 0x11, SS_RDEF, /* XXX TBD */ 1787181381Sjkim "Incomplete key-associated data set") }, 1788181381Sjkim /* T */ 1789181381Sjkim { SST(0x26, 0x12, SS_RDEF, /* XXX TBD */ 1790181381Sjkim "Vendor specific key reference not found") }, 1791288771Smav /* D */ 1792288771Smav { SST(0x26, 0x13, SS_RDEF, /* XXX TBD */ 1793288771Smav "Application tag mode page is invalid") }, 1794181381Sjkim /* DT WRO BK */ 1795181381Sjkim { SST(0x27, 0x00, SS_FATAL | EACCES, 1796181381Sjkim "Write protected") }, 1797181381Sjkim /* DT WRO BK */ 1798181381Sjkim { SST(0x27, 0x01, SS_FATAL | EACCES, 1799181381Sjkim "Hardware write protected") }, 1800181381Sjkim /* DT WRO BK */ 1801181381Sjkim { SST(0x27, 0x02, SS_FATAL | EACCES, 1802181381Sjkim "Logical unit software write protected") }, 1803181381Sjkim /* T R */ 1804181381Sjkim { SST(0x27, 0x03, SS_FATAL | EACCES, 1805181381Sjkim "Associated write protect") }, 1806181381Sjkim /* T R */ 1807181381Sjkim { SST(0x27, 0x04, SS_FATAL | EACCES, 1808181381Sjkim "Persistent write protect") }, 1809181381Sjkim /* T R */ 1810181381Sjkim { SST(0x27, 0x05, SS_FATAL | EACCES, 1811181381Sjkim "Permanent write protect") }, 1812181381Sjkim /* R F */ 1813181381Sjkim { SST(0x27, 0x06, SS_RDEF, /* XXX TBD */ 1814181381Sjkim "Conditional write protect") }, 1815238595Smav /* D B */ 1816274004Smav { SST(0x27, 0x07, SS_FATAL | ENOSPC, 1817238595Smav "Space allocation failed write protect") }, 1818288771Smav /* D */ 1819288771Smav { SST(0x27, 0x08, SS_FATAL | EACCES, 1820288771Smav "Zone is read only") }, 1821181381Sjkim /* DTLPWROMAEBKVF */ 1822181381Sjkim { SST(0x28, 0x00, SS_FATAL | ENXIO, 1823181381Sjkim "Not ready to ready change, medium may have changed") }, 1824181381Sjkim /* DT WROM B */ 1825181381Sjkim { SST(0x28, 0x01, SS_FATAL | ENXIO, 1826181381Sjkim "Import or export element accessed") }, 1827181381Sjkim /* R */ 1828181381Sjkim { SST(0x28, 0x02, SS_RDEF, /* XXX TBD */ 1829181381Sjkim "Format-layer may have changed") }, 1830181381Sjkim /* M */ 1831181381Sjkim { SST(0x28, 0x03, SS_RDEF, /* XXX TBD */ 1832181381Sjkim "Import/export element accessed, medium changed") }, 1833181381Sjkim /* 1834181381Sjkim * XXX JGibbs - All of these should use the same errno, but I don't 1835181381Sjkim * think ENXIO is the correct choice. Should we borrow from 1836181381Sjkim * the networking errnos? ECONNRESET anyone? 1837181381Sjkim */ 1838181381Sjkim /* DTLPWROMAEBKVF */ 1839181381Sjkim { SST(0x29, 0x00, SS_FATAL | ENXIO, 1840181381Sjkim "Power on, reset, or bus device reset occurred") }, 1841181381Sjkim /* DTLPWROMAEBKVF */ 1842181381Sjkim { SST(0x29, 0x01, SS_RDEF, 1843181381Sjkim "Power on occurred") }, 1844181381Sjkim /* DTLPWROMAEBKVF */ 1845181381Sjkim { SST(0x29, 0x02, SS_RDEF, 1846181381Sjkim "SCSI bus reset occurred") }, 1847181381Sjkim /* DTLPWROMAEBKVF */ 1848181381Sjkim { SST(0x29, 0x03, SS_RDEF, 1849181381Sjkim "Bus device reset function occurred") }, 1850181381Sjkim /* DTLPWROMAEBKVF */ 1851181381Sjkim { SST(0x29, 0x04, SS_RDEF, 1852181381Sjkim "Device internal reset") }, 1853181381Sjkim /* DTLPWROMAEBKVF */ 1854181381Sjkim { SST(0x29, 0x05, SS_RDEF, 1855181381Sjkim "Transceiver mode changed to single-ended") }, 1856181381Sjkim /* DTLPWROMAEBKVF */ 1857181381Sjkim { SST(0x29, 0x06, SS_RDEF, 1858181381Sjkim "Transceiver mode changed to LVD") }, 1859181381Sjkim /* DTLPWROMAEBKVF */ 1860181381Sjkim { SST(0x29, 0x07, SS_RDEF, /* XXX TBD */ 1861181381Sjkim "I_T nexus loss occurred") }, 1862181381Sjkim /* DTL WROMAEBKVF */ 1863181381Sjkim { SST(0x2A, 0x00, SS_RDEF, 1864181381Sjkim "Parameters changed") }, 1865181381Sjkim /* DTL WROMAEBKVF */ 1866181381Sjkim { SST(0x2A, 0x01, SS_RDEF, 1867181381Sjkim "Mode parameters changed") }, 1868181381Sjkim /* DTL WROMAE K */ 1869181381Sjkim { SST(0x2A, 0x02, SS_RDEF, 1870181381Sjkim "Log parameters changed") }, 1871181381Sjkim /* DTLPWROMAE K */ 1872181381Sjkim { SST(0x2A, 0x03, SS_RDEF, 1873181381Sjkim "Reservations preempted") }, 1874181381Sjkim /* DTLPWROMAE */ 1875181381Sjkim { SST(0x2A, 0x04, SS_RDEF, /* XXX TBD */ 1876181381Sjkim "Reservations released") }, 1877181381Sjkim /* DTLPWROMAE */ 1878181381Sjkim { SST(0x2A, 0x05, SS_RDEF, /* XXX TBD */ 1879181381Sjkim "Registrations preempted") }, 1880181381Sjkim /* DTLPWROMAEBKVF */ 1881181381Sjkim { SST(0x2A, 0x06, SS_RDEF, /* XXX TBD */ 1882181381Sjkim "Asymmetric access state changed") }, 1883181381Sjkim /* DTLPWROMAEBKVF */ 1884181381Sjkim { SST(0x2A, 0x07, SS_RDEF, /* XXX TBD */ 1885181381Sjkim "Implicit asymmetric access state transition failed") }, 1886181381Sjkim /* DT WROMAEBKVF */ 1887181381Sjkim { SST(0x2A, 0x08, SS_RDEF, /* XXX TBD */ 1888181381Sjkim "Priority changed") }, 1889181381Sjkim /* D */ 1890181381Sjkim { SST(0x2A, 0x09, SS_RDEF, /* XXX TBD */ 1891181381Sjkim "Capacity data has changed") }, 1892181381Sjkim /* DT */ 1893181381Sjkim { SST(0x2A, 0x0A, SS_RDEF, /* XXX TBD */ 1894181381Sjkim "Error history I_T nexus cleared") }, 1895181381Sjkim /* DT */ 1896181381Sjkim { SST(0x2A, 0x0B, SS_RDEF, /* XXX TBD */ 1897181381Sjkim "Error history snapshot released") }, 1898181381Sjkim /* F */ 1899181381Sjkim { SST(0x2A, 0x0C, SS_RDEF, /* XXX TBD */ 1900181381Sjkim "Error recovery attributes have changed") }, 1901181381Sjkim /* T */ 1902181381Sjkim { SST(0x2A, 0x0D, SS_RDEF, /* XXX TBD */ 1903181381Sjkim "Data encryption capabilities changed") }, 1904181381Sjkim /* DT M E V */ 1905181381Sjkim { SST(0x2A, 0x10, SS_RDEF, /* XXX TBD */ 1906181381Sjkim "Timestamp changed") }, 1907181381Sjkim /* T */ 1908181381Sjkim { SST(0x2A, 0x11, SS_RDEF, /* XXX TBD */ 1909181381Sjkim "Data encryption parameters changed by another I_T nexus") }, 1910181381Sjkim /* T */ 1911181381Sjkim { SST(0x2A, 0x12, SS_RDEF, /* XXX TBD */ 1912181381Sjkim "Data encryption parameters changed by vendor specific event") }, 1913181381Sjkim /* T */ 1914181381Sjkim { SST(0x2A, 0x13, SS_RDEF, /* XXX TBD */ 1915181381Sjkim "Data encryption key instance counter has changed") }, 1916181381Sjkim /* DT R MAEBKV */ 1917181381Sjkim { SST(0x2A, 0x14, SS_RDEF, /* XXX TBD */ 1918181381Sjkim "SA creation capabilities data has changed") }, 1919238595Smav /* T M V */ 1920238595Smav { SST(0x2A, 0x15, SS_RDEF, /* XXX TBD */ 1921238595Smav "Medium removal prevention preempted") }, 1922181381Sjkim /* DTLPWRO K */ 1923181381Sjkim { SST(0x2B, 0x00, SS_RDEF, 1924181381Sjkim "Copy cannot execute since host cannot disconnect") }, 1925181381Sjkim /* DTLPWROMAEBKVF */ 1926181381Sjkim { SST(0x2C, 0x00, SS_RDEF, 1927181381Sjkim "Command sequence error") }, 1928181381Sjkim /* */ 1929181381Sjkim { SST(0x2C, 0x01, SS_RDEF, 1930181381Sjkim "Too many windows specified") }, 1931181381Sjkim /* */ 1932181381Sjkim { SST(0x2C, 0x02, SS_RDEF, 1933181381Sjkim "Invalid combination of windows specified") }, 1934181381Sjkim /* R */ 1935181381Sjkim { SST(0x2C, 0x03, SS_RDEF, 1936181381Sjkim "Current program area is not empty") }, 1937181381Sjkim /* R */ 1938181381Sjkim { SST(0x2C, 0x04, SS_RDEF, 1939181381Sjkim "Current program area is empty") }, 1940181381Sjkim /* B */ 1941181381Sjkim { SST(0x2C, 0x05, SS_RDEF, /* XXX TBD */ 1942181381Sjkim "Illegal power condition request") }, 1943181381Sjkim /* R */ 1944181381Sjkim { SST(0x2C, 0x06, SS_RDEF, /* XXX TBD */ 1945181381Sjkim "Persistent prevent conflict") }, 1946181381Sjkim /* DTLPWROMAEBKVF */ 1947181381Sjkim { SST(0x2C, 0x07, SS_RDEF, /* XXX TBD */ 1948181381Sjkim "Previous busy status") }, 1949181381Sjkim /* DTLPWROMAEBKVF */ 1950181381Sjkim { SST(0x2C, 0x08, SS_RDEF, /* XXX TBD */ 1951181381Sjkim "Previous task set full status") }, 1952181381Sjkim /* DTLPWROM EBKVF */ 1953181381Sjkim { SST(0x2C, 0x09, SS_RDEF, /* XXX TBD */ 1954181381Sjkim "Previous reservation conflict status") }, 1955181381Sjkim /* F */ 1956181381Sjkim { SST(0x2C, 0x0A, SS_RDEF, /* XXX TBD */ 1957181381Sjkim "Partition or collection contains user objects") }, 1958181381Sjkim /* T */ 1959181381Sjkim { SST(0x2C, 0x0B, SS_RDEF, /* XXX TBD */ 1960181381Sjkim "Not reserved") }, 1961238595Smav /* D */ 1962238595Smav { SST(0x2C, 0x0C, SS_RDEF, /* XXX TBD */ 1963238595Smav "ORWRITE generation does not match") }, 1964288771Smav /* D */ 1965288771Smav { SST(0x2C, 0x0D, SS_RDEF, /* XXX TBD */ 1966288771Smav "Reset write pointer not allowed") }, 1967288771Smav /* D */ 1968288771Smav { SST(0x2C, 0x0E, SS_RDEF, /* XXX TBD */ 1969288771Smav "Zone is offline") }, 1970288771Smav /* D */ 1971288771Smav { SST(0x2C, 0x0F, SS_RDEF, /* XXX TBD */ 1972288771Smav "Stream not open") }, 1973288771Smav /* D */ 1974288771Smav { SST(0x2C, 0x10, SS_RDEF, /* XXX TBD */ 1975288771Smav "Unwritten data in zone") }, 1976181381Sjkim /* T */ 1977181381Sjkim { SST(0x2D, 0x00, SS_RDEF, 1978181381Sjkim "Overwrite error on update in place") }, 1979181381Sjkim /* R */ 1980181381Sjkim { SST(0x2E, 0x00, SS_RDEF, /* XXX TBD */ 1981181381Sjkim "Insufficient time for operation") }, 1982288771Smav /* D */ 1983288771Smav { SST(0x2E, 0x01, SS_RDEF, /* XXX TBD */ 1984288771Smav "Command timeout before processing") }, 1985288771Smav /* D */ 1986288771Smav { SST(0x2E, 0x02, SS_RDEF, /* XXX TBD */ 1987288771Smav "Command timeout during processing") }, 1988288771Smav /* D */ 1989288771Smav { SST(0x2E, 0x03, SS_RDEF, /* XXX TBD */ 1990288771Smav "Command timeout during processing due to error recovery") }, 1991181381Sjkim /* DTLPWROMAEBKVF */ 1992181381Sjkim { SST(0x2F, 0x00, SS_RDEF, 1993181381Sjkim "Commands cleared by another initiator") }, 1994181381Sjkim /* D */ 1995181381Sjkim { SST(0x2F, 0x01, SS_RDEF, /* XXX TBD */ 1996181381Sjkim "Commands cleared by power loss notification") }, 1997181381Sjkim /* DTLPWROMAEBKVF */ 1998181381Sjkim { SST(0x2F, 0x02, SS_RDEF, /* XXX TBD */ 1999181381Sjkim "Commands cleared by device server") }, 2000288771Smav /* DTLPWROMAEBKVF */ 2001288771Smav { SST(0x2F, 0x03, SS_RDEF, /* XXX TBD */ 2002288771Smav "Some commands cleared by queuing layer event") }, 2003181381Sjkim /* DT WROM BK */ 2004181381Sjkim { SST(0x30, 0x00, SS_RDEF, 2005181381Sjkim "Incompatible medium installed") }, 2006181381Sjkim /* DT WRO BK */ 2007181381Sjkim { SST(0x30, 0x01, SS_RDEF, 2008181381Sjkim "Cannot read medium - unknown format") }, 2009181381Sjkim /* DT WRO BK */ 2010181381Sjkim { SST(0x30, 0x02, SS_RDEF, 2011181381Sjkim "Cannot read medium - incompatible format") }, 2012181381Sjkim /* DT R K */ 2013181381Sjkim { SST(0x30, 0x03, SS_RDEF, 2014181381Sjkim "Cleaning cartridge installed") }, 2015181381Sjkim /* DT WRO BK */ 2016181381Sjkim { SST(0x30, 0x04, SS_RDEF, 2017181381Sjkim "Cannot write medium - unknown format") }, 2018181381Sjkim /* DT WRO BK */ 2019181381Sjkim { SST(0x30, 0x05, SS_RDEF, 2020181381Sjkim "Cannot write medium - incompatible format") }, 2021181381Sjkim /* DT WRO B */ 2022181381Sjkim { SST(0x30, 0x06, SS_RDEF, 2023181381Sjkim "Cannot format medium - incompatible medium") }, 2024181381Sjkim /* DTL WROMAEBKVF */ 2025181381Sjkim { SST(0x30, 0x07, SS_RDEF, 2026181381Sjkim "Cleaning failure") }, 2027181381Sjkim /* R */ 2028181381Sjkim { SST(0x30, 0x08, SS_RDEF, 2029181381Sjkim "Cannot write - application code mismatch") }, 2030181381Sjkim /* R */ 2031181381Sjkim { SST(0x30, 0x09, SS_RDEF, 2032181381Sjkim "Current session not fixated for append") }, 2033181381Sjkim /* DT WRO AEBK */ 2034181381Sjkim { SST(0x30, 0x0A, SS_RDEF, /* XXX TBD */ 2035181381Sjkim "Cleaning request rejected") }, 2036181381Sjkim /* T */ 2037181381Sjkim { SST(0x30, 0x0C, SS_RDEF, /* XXX TBD */ 2038181381Sjkim "WORM medium - overwrite attempted") }, 2039181381Sjkim /* T */ 2040181381Sjkim { SST(0x30, 0x0D, SS_RDEF, /* XXX TBD */ 2041181381Sjkim "WORM medium - integrity check") }, 2042181381Sjkim /* R */ 2043181381Sjkim { SST(0x30, 0x10, SS_RDEF, /* XXX TBD */ 2044181381Sjkim "Medium not formatted") }, 2045181381Sjkim /* M */ 2046181381Sjkim { SST(0x30, 0x11, SS_RDEF, /* XXX TBD */ 2047181381Sjkim "Incompatible volume type") }, 2048181381Sjkim /* M */ 2049181381Sjkim { SST(0x30, 0x12, SS_RDEF, /* XXX TBD */ 2050181381Sjkim "Incompatible volume qualifier") }, 2051238595Smav /* M */ 2052238595Smav { SST(0x30, 0x13, SS_RDEF, /* XXX TBD */ 2053238595Smav "Cleaning volume expired") }, 2054181381Sjkim /* DT WRO BK */ 2055181381Sjkim { SST(0x31, 0x00, SS_RDEF, 2056181381Sjkim "Medium format corrupted") }, 2057181381Sjkim /* D L RO B */ 2058181381Sjkim { SST(0x31, 0x01, SS_RDEF, 2059181381Sjkim "Format command failed") }, 2060181381Sjkim /* R */ 2061181381Sjkim { SST(0x31, 0x02, SS_RDEF, /* XXX TBD */ 2062181381Sjkim "Zoned formatting failed due to spare linking") }, 2063238595Smav /* D B */ 2064238595Smav { SST(0x31, 0x03, SS_RDEF, /* XXX TBD */ 2065238595Smav "SANITIZE command failed") }, 2066181381Sjkim /* D W O BK */ 2067181381Sjkim { SST(0x32, 0x00, SS_RDEF, 2068181381Sjkim "No defect spare location available") }, 2069181381Sjkim /* D W O BK */ 2070181381Sjkim { SST(0x32, 0x01, SS_RDEF, 2071181381Sjkim "Defect list update failure") }, 2072181381Sjkim /* T */ 2073181381Sjkim { SST(0x33, 0x00, SS_RDEF, 2074181381Sjkim "Tape length error") }, 2075181381Sjkim /* DTLPWROMAEBKVF */ 2076181381Sjkim { SST(0x34, 0x00, SS_RDEF, 2077181381Sjkim "Enclosure failure") }, 2078181381Sjkim /* DTLPWROMAEBKVF */ 2079181381Sjkim { SST(0x35, 0x00, SS_RDEF, 2080181381Sjkim "Enclosure services failure") }, 2081181381Sjkim /* DTLPWROMAEBKVF */ 2082181381Sjkim { SST(0x35, 0x01, SS_RDEF, 2083181381Sjkim "Unsupported enclosure function") }, 2084181381Sjkim /* DTLPWROMAEBKVF */ 2085181381Sjkim { SST(0x35, 0x02, SS_RDEF, 2086181381Sjkim "Enclosure services unavailable") }, 2087181381Sjkim /* DTLPWROMAEBKVF */ 2088181381Sjkim { SST(0x35, 0x03, SS_RDEF, 2089181381Sjkim "Enclosure services transfer failure") }, 2090181381Sjkim /* DTLPWROMAEBKVF */ 2091181381Sjkim { SST(0x35, 0x04, SS_RDEF, 2092181381Sjkim "Enclosure services transfer refused") }, 2093181381Sjkim /* DTL WROMAEBKVF */ 2094181381Sjkim { SST(0x35, 0x05, SS_RDEF, /* XXX TBD */ 2095181381Sjkim "Enclosure services checksum error") }, 2096181381Sjkim /* L */ 2097181381Sjkim { SST(0x36, 0x00, SS_RDEF, 2098181381Sjkim "Ribbon, ink, or toner failure") }, 2099181381Sjkim /* DTL WROMAEBKVF */ 2100181381Sjkim { SST(0x37, 0x00, SS_RDEF, 2101181381Sjkim "Rounded parameter") }, 2102181381Sjkim /* B */ 2103181381Sjkim { SST(0x38, 0x00, SS_RDEF, /* XXX TBD */ 2104181381Sjkim "Event status notification") }, 2105181381Sjkim /* B */ 2106181381Sjkim { SST(0x38, 0x02, SS_RDEF, /* XXX TBD */ 2107181381Sjkim "ESN - power management class event") }, 2108181381Sjkim /* B */ 2109181381Sjkim { SST(0x38, 0x04, SS_RDEF, /* XXX TBD */ 2110181381Sjkim "ESN - media class event") }, 2111181381Sjkim /* B */ 2112181381Sjkim { SST(0x38, 0x06, SS_RDEF, /* XXX TBD */ 2113181381Sjkim "ESN - device busy class event") }, 2114238595Smav /* D */ 2115238595Smav { SST(0x38, 0x07, SS_RDEF, /* XXX TBD */ 2116238595Smav "Thin provisioning soft threshold reached") }, 2117181381Sjkim /* DTL WROMAE K */ 2118181381Sjkim { SST(0x39, 0x00, SS_RDEF, 2119181381Sjkim "Saving parameters not supported") }, 2120181381Sjkim /* DTL WROM BK */ 2121181381Sjkim { SST(0x3A, 0x00, SS_FATAL | ENXIO, 2122181381Sjkim "Medium not present") }, 2123181381Sjkim /* DT WROM BK */ 2124181381Sjkim { SST(0x3A, 0x01, SS_FATAL | ENXIO, 2125181381Sjkim "Medium not present - tray closed") }, 2126181381Sjkim /* DT WROM BK */ 2127181381Sjkim { SST(0x3A, 0x02, SS_FATAL | ENXIO, 2128181381Sjkim "Medium not present - tray open") }, 2129181381Sjkim /* DT WROM B */ 2130181381Sjkim { SST(0x3A, 0x03, SS_RDEF, /* XXX TBD */ 2131181381Sjkim "Medium not present - loadable") }, 2132181381Sjkim /* DT WRO B */ 2133181381Sjkim { SST(0x3A, 0x04, SS_RDEF, /* XXX TBD */ 2134181381Sjkim "Medium not present - medium auxiliary memory accessible") }, 2135181381Sjkim /* TL */ 2136181381Sjkim { SST(0x3B, 0x00, SS_RDEF, 2137181381Sjkim "Sequential positioning error") }, 2138181381Sjkim /* T */ 2139181381Sjkim { SST(0x3B, 0x01, SS_RDEF, 2140181381Sjkim "Tape position error at beginning-of-medium") }, 2141181381Sjkim /* T */ 2142181381Sjkim { SST(0x3B, 0x02, SS_RDEF, 2143181381Sjkim "Tape position error at end-of-medium") }, 2144181381Sjkim /* L */ 2145181381Sjkim { SST(0x3B, 0x03, SS_RDEF, 2146181381Sjkim "Tape or electronic vertical forms unit not ready") }, 2147181381Sjkim /* L */ 2148181381Sjkim { SST(0x3B, 0x04, SS_RDEF, 2149181381Sjkim "Slew failure") }, 2150181381Sjkim /* L */ 2151181381Sjkim { SST(0x3B, 0x05, SS_RDEF, 2152181381Sjkim "Paper jam") }, 2153181381Sjkim /* L */ 2154181381Sjkim { SST(0x3B, 0x06, SS_RDEF, 2155181381Sjkim "Failed to sense top-of-form") }, 2156181381Sjkim /* L */ 2157181381Sjkim { SST(0x3B, 0x07, SS_RDEF, 2158181381Sjkim "Failed to sense bottom-of-form") }, 2159181381Sjkim /* T */ 2160181381Sjkim { SST(0x3B, 0x08, SS_RDEF, 2161181381Sjkim "Reposition error") }, 2162181381Sjkim /* */ 2163181381Sjkim { SST(0x3B, 0x09, SS_RDEF, 2164181381Sjkim "Read past end of medium") }, 2165181381Sjkim /* */ 2166181381Sjkim { SST(0x3B, 0x0A, SS_RDEF, 2167181381Sjkim "Read past beginning of medium") }, 2168181381Sjkim /* */ 2169181381Sjkim { SST(0x3B, 0x0B, SS_RDEF, 2170181381Sjkim "Position past end of medium") }, 2171181381Sjkim /* T */ 2172181381Sjkim { SST(0x3B, 0x0C, SS_RDEF, 2173181381Sjkim "Position past beginning of medium") }, 2174181381Sjkim /* DT WROM BK */ 2175181381Sjkim { SST(0x3B, 0x0D, SS_FATAL | ENOSPC, 2176181381Sjkim "Medium destination element full") }, 2177181381Sjkim /* DT WROM BK */ 2178181381Sjkim { SST(0x3B, 0x0E, SS_RDEF, 2179181381Sjkim "Medium source element empty") }, 2180181381Sjkim /* R */ 2181181381Sjkim { SST(0x3B, 0x0F, SS_RDEF, 2182181381Sjkim "End of medium reached") }, 2183181381Sjkim /* DT WROM BK */ 2184181381Sjkim { SST(0x3B, 0x11, SS_RDEF, 2185181381Sjkim "Medium magazine not accessible") }, 2186181381Sjkim /* DT WROM BK */ 2187181381Sjkim { SST(0x3B, 0x12, SS_RDEF, 2188181381Sjkim "Medium magazine removed") }, 2189181381Sjkim /* DT WROM BK */ 2190181381Sjkim { SST(0x3B, 0x13, SS_RDEF, 2191181381Sjkim "Medium magazine inserted") }, 2192181381Sjkim /* DT WROM BK */ 2193181381Sjkim { SST(0x3B, 0x14, SS_RDEF, 2194181381Sjkim "Medium magazine locked") }, 2195181381Sjkim /* DT WROM BK */ 2196181381Sjkim { SST(0x3B, 0x15, SS_RDEF, 2197181381Sjkim "Medium magazine unlocked") }, 2198181381Sjkim /* R */ 2199181381Sjkim { SST(0x3B, 0x16, SS_RDEF, /* XXX TBD */ 2200181381Sjkim "Mechanical positioning or changer error") }, 2201181381Sjkim /* F */ 2202181381Sjkim { SST(0x3B, 0x17, SS_RDEF, /* XXX TBD */ 2203181381Sjkim "Read past end of user object") }, 2204181381Sjkim /* M */ 2205181381Sjkim { SST(0x3B, 0x18, SS_RDEF, /* XXX TBD */ 2206181381Sjkim "Element disabled") }, 2207181381Sjkim /* M */ 2208181381Sjkim { SST(0x3B, 0x19, SS_RDEF, /* XXX TBD */ 2209181381Sjkim "Element enabled") }, 2210181381Sjkim /* M */ 2211181381Sjkim { SST(0x3B, 0x1A, SS_RDEF, /* XXX TBD */ 2212181381Sjkim "Data transfer device removed") }, 2213181381Sjkim /* M */ 2214181381Sjkim { SST(0x3B, 0x1B, SS_RDEF, /* XXX TBD */ 2215181381Sjkim "Data transfer device inserted") }, 2216238595Smav /* T */ 2217238595Smav { SST(0x3B, 0x1C, SS_RDEF, /* XXX TBD */ 2218238595Smav "Too many logical objects on partition to support operation") }, 2219181381Sjkim /* DTLPWROMAE K */ 2220181381Sjkim { SST(0x3D, 0x00, SS_RDEF, 2221181381Sjkim "Invalid bits in IDENTIFY message") }, 2222181381Sjkim /* DTLPWROMAEBKVF */ 2223181381Sjkim { SST(0x3E, 0x00, SS_RDEF, 2224181381Sjkim "Logical unit has not self-configured yet") }, 2225181381Sjkim /* DTLPWROMAEBKVF */ 2226181381Sjkim { SST(0x3E, 0x01, SS_RDEF, 2227181381Sjkim "Logical unit failure") }, 2228181381Sjkim /* DTLPWROMAEBKVF */ 2229181381Sjkim { SST(0x3E, 0x02, SS_RDEF, 2230181381Sjkim "Timeout on logical unit") }, 2231181381Sjkim /* DTLPWROMAEBKVF */ 2232181381Sjkim { SST(0x3E, 0x03, SS_RDEF, /* XXX TBD */ 2233181381Sjkim "Logical unit failed self-test") }, 2234181381Sjkim /* DTLPWROMAEBKVF */ 2235181381Sjkim { SST(0x3E, 0x04, SS_RDEF, /* XXX TBD */ 2236181381Sjkim "Logical unit unable to update self-test log") }, 2237181381Sjkim /* DTLPWROMAEBKVF */ 2238181381Sjkim { SST(0x3F, 0x00, SS_RDEF, 2239181381Sjkim "Target operating conditions have changed") }, 2240181381Sjkim /* DTLPWROMAEBKVF */ 2241181381Sjkim { SST(0x3F, 0x01, SS_RDEF, 2242181381Sjkim "Microcode has been changed") }, 2243181381Sjkim /* DTLPWROM BK */ 2244181381Sjkim { SST(0x3F, 0x02, SS_RDEF, 2245181381Sjkim "Changed operating definition") }, 2246181381Sjkim /* DTLPWROMAEBKVF */ 2247181381Sjkim { SST(0x3F, 0x03, SS_RDEF, 2248181381Sjkim "INQUIRY data has changed") }, 2249181381Sjkim /* DT WROMAEBK */ 2250181381Sjkim { SST(0x3F, 0x04, SS_RDEF, 2251181381Sjkim "Component device attached") }, 2252181381Sjkim /* DT WROMAEBK */ 2253181381Sjkim { SST(0x3F, 0x05, SS_RDEF, 2254181381Sjkim "Device identifier changed") }, 2255181381Sjkim /* DT WROMAEB */ 2256181381Sjkim { SST(0x3F, 0x06, SS_RDEF, 2257181381Sjkim "Redundancy group created or modified") }, 2258181381Sjkim /* DT WROMAEB */ 2259181381Sjkim { SST(0x3F, 0x07, SS_RDEF, 2260181381Sjkim "Redundancy group deleted") }, 2261181381Sjkim /* DT WROMAEB */ 2262181381Sjkim { SST(0x3F, 0x08, SS_RDEF, 2263181381Sjkim "Spare created or modified") }, 2264181381Sjkim /* DT WROMAEB */ 2265181381Sjkim { SST(0x3F, 0x09, SS_RDEF, 2266181381Sjkim "Spare deleted") }, 2267181381Sjkim /* DT WROMAEBK */ 2268181381Sjkim { SST(0x3F, 0x0A, SS_RDEF, 2269181381Sjkim "Volume set created or modified") }, 2270181381Sjkim /* DT WROMAEBK */ 2271181381Sjkim { SST(0x3F, 0x0B, SS_RDEF, 2272181381Sjkim "Volume set deleted") }, 2273181381Sjkim /* DT WROMAEBK */ 2274181381Sjkim { SST(0x3F, 0x0C, SS_RDEF, 2275181381Sjkim "Volume set deassigned") }, 2276181381Sjkim /* DT WROMAEBK */ 2277181381Sjkim { SST(0x3F, 0x0D, SS_RDEF, 2278181381Sjkim "Volume set reassigned") }, 2279181381Sjkim /* DTLPWROMAE */ 2280253322Smav { SST(0x3F, 0x0E, SS_RDEF | SSQ_RESCAN , 2281181381Sjkim "Reported LUNs data has changed") }, 2282181381Sjkim /* DTLPWROMAEBKVF */ 2283181381Sjkim { SST(0x3F, 0x0F, SS_RDEF, /* XXX TBD */ 2284181381Sjkim "Echo buffer overwritten") }, 2285181381Sjkim /* DT WROM B */ 2286181381Sjkim { SST(0x3F, 0x10, SS_RDEF, /* XXX TBD */ 2287181381Sjkim "Medium loadable") }, 2288181381Sjkim /* DT WROM B */ 2289181381Sjkim { SST(0x3F, 0x11, SS_RDEF, /* XXX TBD */ 2290181381Sjkim "Medium auxiliary memory accessible") }, 2291181381Sjkim /* DTLPWR MAEBK F */ 2292181381Sjkim { SST(0x3F, 0x12, SS_RDEF, /* XXX TBD */ 2293181381Sjkim "iSCSI IP address added") }, 2294181381Sjkim /* DTLPWR MAEBK F */ 2295181381Sjkim { SST(0x3F, 0x13, SS_RDEF, /* XXX TBD */ 2296181381Sjkim "iSCSI IP address removed") }, 2297181381Sjkim /* DTLPWR MAEBK F */ 2298181381Sjkim { SST(0x3F, 0x14, SS_RDEF, /* XXX TBD */ 2299181381Sjkim "iSCSI IP address changed") }, 2300288771Smav /* DTLPWR MAEBK */ 2301288771Smav { SST(0x3F, 0x15, SS_RDEF, /* XXX TBD */ 2302288771Smav "Inspect referrals sense descriptors") }, 2303288771Smav /* DTLPWROMAEBKVF */ 2304288771Smav { SST(0x3F, 0x16, SS_RDEF, /* XXX TBD */ 2305288771Smav "Microcode has been changed without reset") }, 2306181381Sjkim /* D */ 2307288771Smav { SST(0x3F, 0x17, SS_RDEF, /* XXX TBD */ 2308288771Smav "Zone transition to full") }, 2309288771Smav /* D */ 2310181381Sjkim { SST(0x40, 0x00, SS_RDEF, 2311181381Sjkim "RAM failure") }, /* deprecated - use 40 NN instead */ 2312181381Sjkim /* DTLPWROMAEBKVF */ 2313181381Sjkim { SST(0x40, 0x80, SS_RDEF, 2314181381Sjkim "Diagnostic failure: ASCQ = Component ID") }, 2315181381Sjkim /* DTLPWROMAEBKVF */ 2316181381Sjkim { SST(0x40, 0xFF, SS_RDEF | SSQ_RANGE, 2317181381Sjkim NULL) }, /* Range 0x80->0xFF */ 2318181381Sjkim /* D */ 2319181381Sjkim { SST(0x41, 0x00, SS_RDEF, 2320181381Sjkim "Data path failure") }, /* deprecated - use 40 NN instead */ 2321181381Sjkim /* D */ 2322181381Sjkim { SST(0x42, 0x00, SS_RDEF, 2323181381Sjkim "Power-on or self-test failure") }, 2324181381Sjkim /* deprecated - use 40 NN instead */ 2325181381Sjkim /* DTLPWROMAEBKVF */ 2326181381Sjkim { SST(0x43, 0x00, SS_RDEF, 2327181381Sjkim "Message error") }, 2328181381Sjkim /* DTLPWROMAEBKVF */ 2329181381Sjkim { SST(0x44, 0x00, SS_RDEF, 2330181381Sjkim "Internal target failure") }, 2331238595Smav /* DT P MAEBKVF */ 2332238595Smav { SST(0x44, 0x01, SS_RDEF, /* XXX TBD */ 2333238595Smav "Persistent reservation information lost") }, 2334181381Sjkim /* DT B */ 2335181381Sjkim { SST(0x44, 0x71, SS_RDEF, /* XXX TBD */ 2336181381Sjkim "ATA device failed set features") }, 2337181381Sjkim /* DTLPWROMAEBKVF */ 2338181381Sjkim { SST(0x45, 0x00, SS_RDEF, 2339181381Sjkim "Select or reselect failure") }, 2340181381Sjkim /* DTLPWROM BK */ 2341181381Sjkim { SST(0x46, 0x00, SS_RDEF, 2342181381Sjkim "Unsuccessful soft reset") }, 2343181381Sjkim /* DTLPWROMAEBKVF */ 2344181381Sjkim { SST(0x47, 0x00, SS_RDEF, 2345181381Sjkim "SCSI parity error") }, 2346181381Sjkim /* DTLPWROMAEBKVF */ 2347181381Sjkim { SST(0x47, 0x01, SS_RDEF, /* XXX TBD */ 2348181381Sjkim "Data phase CRC error detected") }, 2349181381Sjkim /* DTLPWROMAEBKVF */ 2350181381Sjkim { SST(0x47, 0x02, SS_RDEF, /* XXX TBD */ 2351181381Sjkim "SCSI parity error detected during ST data phase") }, 2352181381Sjkim /* DTLPWROMAEBKVF */ 2353181381Sjkim { SST(0x47, 0x03, SS_RDEF, /* XXX TBD */ 2354181381Sjkim "Information unit iuCRC error detected") }, 2355181381Sjkim /* DTLPWROMAEBKVF */ 2356181381Sjkim { SST(0x47, 0x04, SS_RDEF, /* XXX TBD */ 2357181381Sjkim "Asynchronous information protection error detected") }, 2358181381Sjkim /* DTLPWROMAEBKVF */ 2359181381Sjkim { SST(0x47, 0x05, SS_RDEF, /* XXX TBD */ 2360181381Sjkim "Protocol service CRC error") }, 2361181381Sjkim /* DT MAEBKVF */ 2362181381Sjkim { SST(0x47, 0x06, SS_RDEF, /* XXX TBD */ 2363181381Sjkim "PHY test function in progress") }, 2364181381Sjkim /* DT PWROMAEBK */ 2365181381Sjkim { SST(0x47, 0x7F, SS_RDEF, /* XXX TBD */ 2366181381Sjkim "Some commands cleared by iSCSI protocol event") }, 2367181381Sjkim /* DTLPWROMAEBKVF */ 2368181381Sjkim { SST(0x48, 0x00, SS_RDEF, 2369181381Sjkim "Initiator detected error message received") }, 2370181381Sjkim /* DTLPWROMAEBKVF */ 2371181381Sjkim { SST(0x49, 0x00, SS_RDEF, 2372181381Sjkim "Invalid message error") }, 2373181381Sjkim /* DTLPWROMAEBKVF */ 2374181381Sjkim { SST(0x4A, 0x00, SS_RDEF, 2375181381Sjkim "Command phase error") }, 2376181381Sjkim /* DTLPWROMAEBKVF */ 2377181381Sjkim { SST(0x4B, 0x00, SS_RDEF, 2378181381Sjkim "Data phase error") }, 2379181381Sjkim /* DT PWROMAEBK */ 2380181381Sjkim { SST(0x4B, 0x01, SS_RDEF, /* XXX TBD */ 2381181381Sjkim "Invalid target port transfer tag received") }, 2382181381Sjkim /* DT PWROMAEBK */ 2383181381Sjkim { SST(0x4B, 0x02, SS_RDEF, /* XXX TBD */ 2384181381Sjkim "Too much write data") }, 2385181381Sjkim /* DT PWROMAEBK */ 2386181381Sjkim { SST(0x4B, 0x03, SS_RDEF, /* XXX TBD */ 2387181381Sjkim "ACK/NAK timeout") }, 2388181381Sjkim /* DT PWROMAEBK */ 2389181381Sjkim { SST(0x4B, 0x04, SS_RDEF, /* XXX TBD */ 2390181381Sjkim "NAK received") }, 2391181381Sjkim /* DT PWROMAEBK */ 2392181381Sjkim { SST(0x4B, 0x05, SS_RDEF, /* XXX TBD */ 2393181381Sjkim "Data offset error") }, 2394181381Sjkim /* DT PWROMAEBK */ 2395181381Sjkim { SST(0x4B, 0x06, SS_RDEF, /* XXX TBD */ 2396181381Sjkim "Initiator response timeout") }, 2397238595Smav /* DT PWROMAEBK F */ 2398238595Smav { SST(0x4B, 0x07, SS_RDEF, /* XXX TBD */ 2399238595Smav "Connection lost") }, 2400238595Smav /* DT PWROMAEBK F */ 2401238595Smav { SST(0x4B, 0x08, SS_RDEF, /* XXX TBD */ 2402238595Smav "Data-in buffer overflow - data buffer size") }, 2403238595Smav /* DT PWROMAEBK F */ 2404238595Smav { SST(0x4B, 0x09, SS_RDEF, /* XXX TBD */ 2405238595Smav "Data-in buffer overflow - data buffer descriptor area") }, 2406238595Smav /* DT PWROMAEBK F */ 2407238595Smav { SST(0x4B, 0x0A, SS_RDEF, /* XXX TBD */ 2408238595Smav "Data-in buffer error") }, 2409238595Smav /* DT PWROMAEBK F */ 2410238595Smav { SST(0x4B, 0x0B, SS_RDEF, /* XXX TBD */ 2411238595Smav "Data-out buffer overflow - data buffer size") }, 2412238595Smav /* DT PWROMAEBK F */ 2413238595Smav { SST(0x4B, 0x0C, SS_RDEF, /* XXX TBD */ 2414238595Smav "Data-out buffer overflow - data buffer descriptor area") }, 2415238595Smav /* DT PWROMAEBK F */ 2416238595Smav { SST(0x4B, 0x0D, SS_RDEF, /* XXX TBD */ 2417238595Smav "Data-out buffer error") }, 2418288771Smav /* DT PWROMAEBK F */ 2419288771Smav { SST(0x4B, 0x0E, SS_RDEF, /* XXX TBD */ 2420288771Smav "PCIe fabric error") }, 2421288771Smav /* DT PWROMAEBK F */ 2422288771Smav { SST(0x4B, 0x0F, SS_RDEF, /* XXX TBD */ 2423288771Smav "PCIe completion timeout") }, 2424288771Smav /* DT PWROMAEBK F */ 2425288771Smav { SST(0x4B, 0x10, SS_RDEF, /* XXX TBD */ 2426288771Smav "PCIe completer abort") }, 2427288771Smav /* DT PWROMAEBK F */ 2428288771Smav { SST(0x4B, 0x11, SS_RDEF, /* XXX TBD */ 2429288771Smav "PCIe poisoned TLP received") }, 2430288771Smav /* DT PWROMAEBK F */ 2431288771Smav { SST(0x4B, 0x12, SS_RDEF, /* XXX TBD */ 2432288771Smav "PCIe ECRC check failed") }, 2433288771Smav /* DT PWROMAEBK F */ 2434288771Smav { SST(0x4B, 0x13, SS_RDEF, /* XXX TBD */ 2435288771Smav "PCIe unsupported request") }, 2436288771Smav /* DT PWROMAEBK F */ 2437288771Smav { SST(0x4B, 0x14, SS_RDEF, /* XXX TBD */ 2438288771Smav "PCIe ACS violation") }, 2439288771Smav /* DT PWROMAEBK F */ 2440288771Smav { SST(0x4B, 0x15, SS_RDEF, /* XXX TBD */ 2441288771Smav "PCIe TLP prefix blocket") }, 2442181381Sjkim /* DTLPWROMAEBKVF */ 2443181381Sjkim { SST(0x4C, 0x00, SS_RDEF, 2444181381Sjkim "Logical unit failed self-configuration") }, 2445181381Sjkim /* DTLPWROMAEBKVF */ 2446181381Sjkim { SST(0x4D, 0x00, SS_RDEF, 2447181381Sjkim "Tagged overlapped commands: ASCQ = Queue tag ID") }, 2448181381Sjkim /* DTLPWROMAEBKVF */ 2449181381Sjkim { SST(0x4D, 0xFF, SS_RDEF | SSQ_RANGE, 2450181381Sjkim NULL) }, /* Range 0x00->0xFF */ 2451181381Sjkim /* DTLPWROMAEBKVF */ 2452181381Sjkim { SST(0x4E, 0x00, SS_RDEF, 2453181381Sjkim "Overlapped commands attempted") }, 2454181381Sjkim /* T */ 2455181381Sjkim { SST(0x50, 0x00, SS_RDEF, 2456181381Sjkim "Write append error") }, 2457181381Sjkim /* T */ 2458181381Sjkim { SST(0x50, 0x01, SS_RDEF, 2459181381Sjkim "Write append position error") }, 2460181381Sjkim /* T */ 2461181381Sjkim { SST(0x50, 0x02, SS_RDEF, 2462181381Sjkim "Position error related to timing") }, 2463181381Sjkim /* T RO */ 2464181381Sjkim { SST(0x51, 0x00, SS_RDEF, 2465181381Sjkim "Erase failure") }, 2466181381Sjkim /* R */ 2467181381Sjkim { SST(0x51, 0x01, SS_RDEF, /* XXX TBD */ 2468181381Sjkim "Erase failure - incomplete erase operation detected") }, 2469181381Sjkim /* T */ 2470181381Sjkim { SST(0x52, 0x00, SS_RDEF, 2471181381Sjkim "Cartridge fault") }, 2472181381Sjkim /* DTL WROM BK */ 2473181381Sjkim { SST(0x53, 0x00, SS_RDEF, 2474181381Sjkim "Media load or eject failed") }, 2475181381Sjkim /* T */ 2476181381Sjkim { SST(0x53, 0x01, SS_RDEF, 2477181381Sjkim "Unload tape failure") }, 2478181381Sjkim /* DT WROM BK */ 2479181381Sjkim { SST(0x53, 0x02, SS_RDEF, 2480181381Sjkim "Medium removal prevented") }, 2481181381Sjkim /* M */ 2482181381Sjkim { SST(0x53, 0x03, SS_RDEF, /* XXX TBD */ 2483181381Sjkim "Medium removal prevented by data transfer element") }, 2484181381Sjkim /* T */ 2485181381Sjkim { SST(0x53, 0x04, SS_RDEF, /* XXX TBD */ 2486181381Sjkim "Medium thread or unthread failure") }, 2487238595Smav /* M */ 2488238595Smav { SST(0x53, 0x05, SS_RDEF, /* XXX TBD */ 2489238595Smav "Volume identifier invalid") }, 2490238595Smav /* T */ 2491238595Smav { SST(0x53, 0x06, SS_RDEF, /* XXX TBD */ 2492238595Smav "Volume identifier missing") }, 2493238595Smav /* M */ 2494238595Smav { SST(0x53, 0x07, SS_RDEF, /* XXX TBD */ 2495238595Smav "Duplicate volume identifier") }, 2496238595Smav /* M */ 2497238595Smav { SST(0x53, 0x08, SS_RDEF, /* XXX TBD */ 2498238595Smav "Element status unknown") }, 2499288771Smav /* M */ 2500288771Smav { SST(0x53, 0x09, SS_RDEF, /* XXX TBD */ 2501288771Smav "Data transfer device error - load failed") }, 2502288771Smav /* M */ 2503288771Smav { SST(0x53, 0x0A, SS_RDEF, /* XXX TBD */ 2504288771Smav "Data transfer device error - unload failed") }, 2505288771Smav /* M */ 2506288771Smav { SST(0x53, 0x0B, SS_RDEF, /* XXX TBD */ 2507288771Smav "Data transfer device error - unload missing") }, 2508288771Smav /* M */ 2509288771Smav { SST(0x53, 0x0C, SS_RDEF, /* XXX TBD */ 2510288771Smav "Data transfer device error - eject failed") }, 2511288771Smav /* M */ 2512288771Smav { SST(0x53, 0x0D, SS_RDEF, /* XXX TBD */ 2513288771Smav "Data transfer device error - library communication failed") }, 2514181381Sjkim /* P */ 2515181381Sjkim { SST(0x54, 0x00, SS_RDEF, 2516181381Sjkim "SCSI to host system interface failure") }, 2517181381Sjkim /* P */ 2518181381Sjkim { SST(0x55, 0x00, SS_RDEF, 2519181381Sjkim "System resource failure") }, 2520181381Sjkim /* D O BK */ 2521181381Sjkim { SST(0x55, 0x01, SS_FATAL | ENOSPC, 2522181381Sjkim "System buffer full") }, 2523181381Sjkim /* DTLPWROMAE K */ 2524181381Sjkim { SST(0x55, 0x02, SS_RDEF, /* XXX TBD */ 2525181381Sjkim "Insufficient reservation resources") }, 2526181381Sjkim /* DTLPWROMAE K */ 2527181381Sjkim { SST(0x55, 0x03, SS_RDEF, /* XXX TBD */ 2528181381Sjkim "Insufficient resources") }, 2529181381Sjkim /* DTLPWROMAE K */ 2530181381Sjkim { SST(0x55, 0x04, SS_RDEF, /* XXX TBD */ 2531181381Sjkim "Insufficient registration resources") }, 2532181381Sjkim /* DT PWROMAEBK */ 2533181381Sjkim { SST(0x55, 0x05, SS_RDEF, /* XXX TBD */ 2534181381Sjkim "Insufficient access control resources") }, 2535181381Sjkim /* DT WROM B */ 2536181381Sjkim { SST(0x55, 0x06, SS_RDEF, /* XXX TBD */ 2537181381Sjkim "Auxiliary memory out of space") }, 2538181381Sjkim /* F */ 2539181381Sjkim { SST(0x55, 0x07, SS_RDEF, /* XXX TBD */ 2540181381Sjkim "Quota error") }, 2541181381Sjkim /* T */ 2542181381Sjkim { SST(0x55, 0x08, SS_RDEF, /* XXX TBD */ 2543181381Sjkim "Maximum number of supplemental decryption keys exceeded") }, 2544181381Sjkim /* M */ 2545181381Sjkim { SST(0x55, 0x09, SS_RDEF, /* XXX TBD */ 2546181381Sjkim "Medium auxiliary memory not accessible") }, 2547181381Sjkim /* M */ 2548181381Sjkim { SST(0x55, 0x0A, SS_RDEF, /* XXX TBD */ 2549181381Sjkim "Data currently unavailable") }, 2550238595Smav /* DTLPWROMAEBKVF */ 2551238595Smav { SST(0x55, 0x0B, SS_RDEF, /* XXX TBD */ 2552238595Smav "Insufficient power for operation") }, 2553238595Smav /* DT P B */ 2554238595Smav { SST(0x55, 0x0C, SS_RDEF, /* XXX TBD */ 2555238596Smav "Insufficient resources to create ROD") }, 2556238595Smav /* DT P B */ 2557238595Smav { SST(0x55, 0x0D, SS_RDEF, /* XXX TBD */ 2558238596Smav "Insufficient resources to create ROD token") }, 2559288771Smav /* D */ 2560288771Smav { SST(0x55, 0x0E, SS_RDEF, /* XXX TBD */ 2561288771Smav "Insufficient zone resources") }, 2562288771Smav /* D */ 2563288771Smav { SST(0x55, 0x0F, SS_RDEF, /* XXX TBD */ 2564288771Smav "Insufficient zone resources to complete write") }, 2565288771Smav /* D */ 2566288771Smav { SST(0x55, 0x10, SS_RDEF, /* XXX TBD */ 2567288771Smav "Maximum number of streams open") }, 2568181381Sjkim /* R */ 2569181381Sjkim { SST(0x57, 0x00, SS_RDEF, 2570181381Sjkim "Unable to recover table-of-contents") }, 2571181381Sjkim /* O */ 2572181381Sjkim { SST(0x58, 0x00, SS_RDEF, 2573181381Sjkim "Generation does not exist") }, 2574181381Sjkim /* O */ 2575181381Sjkim { SST(0x59, 0x00, SS_RDEF, 2576181381Sjkim "Updated block read") }, 2577181381Sjkim /* DTLPWRO BK */ 2578181381Sjkim { SST(0x5A, 0x00, SS_RDEF, 2579181381Sjkim "Operator request or state change input") }, 2580181381Sjkim /* DT WROM BK */ 2581181381Sjkim { SST(0x5A, 0x01, SS_RDEF, 2582181381Sjkim "Operator medium removal request") }, 2583181381Sjkim /* DT WRO A BK */ 2584181381Sjkim { SST(0x5A, 0x02, SS_RDEF, 2585181381Sjkim "Operator selected write protect") }, 2586181381Sjkim /* DT WRO A BK */ 2587181381Sjkim { SST(0x5A, 0x03, SS_RDEF, 2588181381Sjkim "Operator selected write permit") }, 2589181381Sjkim /* DTLPWROM K */ 2590181381Sjkim { SST(0x5B, 0x00, SS_RDEF, 2591181381Sjkim "Log exception") }, 2592181381Sjkim /* DTLPWROM K */ 2593181381Sjkim { SST(0x5B, 0x01, SS_RDEF, 2594181381Sjkim "Threshold condition met") }, 2595181381Sjkim /* DTLPWROM K */ 2596181381Sjkim { SST(0x5B, 0x02, SS_RDEF, 2597181381Sjkim "Log counter at maximum") }, 2598181381Sjkim /* DTLPWROM K */ 2599181381Sjkim { SST(0x5B, 0x03, SS_RDEF, 2600181381Sjkim "Log list codes exhausted") }, 2601181381Sjkim /* D O */ 2602181381Sjkim { SST(0x5C, 0x00, SS_RDEF, 2603181381Sjkim "RPL status change") }, 2604181381Sjkim /* D O */ 2605181381Sjkim { SST(0x5C, 0x01, SS_NOP | SSQ_PRINT_SENSE, 2606181381Sjkim "Spindles synchronized") }, 2607181381Sjkim /* D O */ 2608181381Sjkim { SST(0x5C, 0x02, SS_RDEF, 2609181381Sjkim "Spindles not synchronized") }, 2610181381Sjkim /* DTLPWROMAEBKVF */ 2611311398Smav { SST(0x5D, 0x00, SS_NOP | SSQ_PRINT_SENSE, 2612181381Sjkim "Failure prediction threshold exceeded") }, 2613181381Sjkim /* R B */ 2614311398Smav { SST(0x5D, 0x01, SS_NOP | SSQ_PRINT_SENSE, 2615181381Sjkim "Media failure prediction threshold exceeded") }, 2616181381Sjkim /* R */ 2617311398Smav { SST(0x5D, 0x02, SS_NOP | SSQ_PRINT_SENSE, 2618181381Sjkim "Logical unit failure prediction threshold exceeded") }, 2619181381Sjkim /* R */ 2620311398Smav { SST(0x5D, 0x03, SS_NOP | SSQ_PRINT_SENSE, 2621181381Sjkim "Spare area exhaustion prediction threshold exceeded") }, 2622181381Sjkim /* D B */ 2623311398Smav { SST(0x5D, 0x10, SS_NOP | SSQ_PRINT_SENSE, 2624181381Sjkim "Hardware impending failure general hard drive failure") }, 2625181381Sjkim /* D B */ 2626311398Smav { SST(0x5D, 0x11, SS_NOP | SSQ_PRINT_SENSE, 2627181381Sjkim "Hardware impending failure drive error rate too high") }, 2628181381Sjkim /* D B */ 2629311398Smav { SST(0x5D, 0x12, SS_NOP | SSQ_PRINT_SENSE, 2630181381Sjkim "Hardware impending failure data error rate too high") }, 2631181381Sjkim /* D B */ 2632311398Smav { SST(0x5D, 0x13, SS_NOP | SSQ_PRINT_SENSE, 2633181381Sjkim "Hardware impending failure seek error rate too high") }, 2634181381Sjkim /* D B */ 2635311398Smav { SST(0x5D, 0x14, SS_NOP | SSQ_PRINT_SENSE, 2636181381Sjkim "Hardware impending failure too many block reassigns") }, 2637181381Sjkim /* D B */ 2638311398Smav { SST(0x5D, 0x15, SS_NOP | SSQ_PRINT_SENSE, 2639181381Sjkim "Hardware impending failure access times too high") }, 2640181381Sjkim /* D B */ 2641311398Smav { SST(0x5D, 0x16, SS_NOP | SSQ_PRINT_SENSE, 2642181381Sjkim "Hardware impending failure start unit times too high") }, 2643181381Sjkim /* D B */ 2644311398Smav { SST(0x5D, 0x17, SS_NOP | SSQ_PRINT_SENSE, 2645181381Sjkim "Hardware impending failure channel parametrics") }, 2646181381Sjkim /* D B */ 2647311398Smav { SST(0x5D, 0x18, SS_NOP | SSQ_PRINT_SENSE, 2648181381Sjkim "Hardware impending failure controller detected") }, 2649181381Sjkim /* D B */ 2650311398Smav { SST(0x5D, 0x19, SS_NOP | SSQ_PRINT_SENSE, 2651181381Sjkim "Hardware impending failure throughput performance") }, 2652181381Sjkim /* D B */ 2653311398Smav { SST(0x5D, 0x1A, SS_NOP | SSQ_PRINT_SENSE, 2654181381Sjkim "Hardware impending failure seek time performance") }, 2655181381Sjkim /* D B */ 2656311398Smav { SST(0x5D, 0x1B, SS_NOP | SSQ_PRINT_SENSE, 2657181381Sjkim "Hardware impending failure spin-up retry count") }, 2658181381Sjkim /* D B */ 2659311398Smav { SST(0x5D, 0x1C, SS_NOP | SSQ_PRINT_SENSE, 2660181381Sjkim "Hardware impending failure drive calibration retry count") }, 2661181381Sjkim /* D B */ 2662311398Smav { SST(0x5D, 0x1D, SS_NOP | SSQ_PRINT_SENSE, 2663311398Smav "Hardware impending failure power loss protection circuit") }, 2664311398Smav /* D B */ 2665311398Smav { SST(0x5D, 0x20, SS_NOP | SSQ_PRINT_SENSE, 2666181381Sjkim "Controller impending failure general hard drive failure") }, 2667181381Sjkim /* D B */ 2668311398Smav { SST(0x5D, 0x21, SS_NOP | SSQ_PRINT_SENSE, 2669181381Sjkim "Controller impending failure drive error rate too high") }, 2670181381Sjkim /* D B */ 2671311398Smav { SST(0x5D, 0x22, SS_NOP | SSQ_PRINT_SENSE, 2672181381Sjkim "Controller impending failure data error rate too high") }, 2673181381Sjkim /* D B */ 2674311398Smav { SST(0x5D, 0x23, SS_NOP | SSQ_PRINT_SENSE, 2675181381Sjkim "Controller impending failure seek error rate too high") }, 2676181381Sjkim /* D B */ 2677311398Smav { SST(0x5D, 0x24, SS_NOP | SSQ_PRINT_SENSE, 2678181381Sjkim "Controller impending failure too many block reassigns") }, 2679181381Sjkim /* D B */ 2680311398Smav { SST(0x5D, 0x25, SS_NOP | SSQ_PRINT_SENSE, 2681181381Sjkim "Controller impending failure access times too high") }, 2682181381Sjkim /* D B */ 2683311398Smav { SST(0x5D, 0x26, SS_NOP | SSQ_PRINT_SENSE, 2684181381Sjkim "Controller impending failure start unit times too high") }, 2685181381Sjkim /* D B */ 2686311398Smav { SST(0x5D, 0x27, SS_NOP | SSQ_PRINT_SENSE, 2687181381Sjkim "Controller impending failure channel parametrics") }, 2688181381Sjkim /* D B */ 2689311398Smav { SST(0x5D, 0x28, SS_NOP | SSQ_PRINT_SENSE, 2690181381Sjkim "Controller impending failure controller detected") }, 2691181381Sjkim /* D B */ 2692311398Smav { SST(0x5D, 0x29, SS_NOP | SSQ_PRINT_SENSE, 2693181381Sjkim "Controller impending failure throughput performance") }, 2694181381Sjkim /* D B */ 2695311398Smav { SST(0x5D, 0x2A, SS_NOP | SSQ_PRINT_SENSE, 2696181381Sjkim "Controller impending failure seek time performance") }, 2697181381Sjkim /* D B */ 2698311398Smav { SST(0x5D, 0x2B, SS_NOP | SSQ_PRINT_SENSE, 2699181381Sjkim "Controller impending failure spin-up retry count") }, 2700181381Sjkim /* D B */ 2701311398Smav { SST(0x5D, 0x2C, SS_NOP | SSQ_PRINT_SENSE, 2702181381Sjkim "Controller impending failure drive calibration retry count") }, 2703181381Sjkim /* D B */ 2704311398Smav { SST(0x5D, 0x30, SS_NOP | SSQ_PRINT_SENSE, 2705181381Sjkim "Data channel impending failure general hard drive failure") }, 2706181381Sjkim /* D B */ 2707311398Smav { SST(0x5D, 0x31, SS_NOP | SSQ_PRINT_SENSE, 2708181381Sjkim "Data channel impending failure drive error rate too high") }, 2709181381Sjkim /* D B */ 2710311398Smav { SST(0x5D, 0x32, SS_NOP | SSQ_PRINT_SENSE, 2711181381Sjkim "Data channel impending failure data error rate too high") }, 2712181381Sjkim /* D B */ 2713311398Smav { SST(0x5D, 0x33, SS_NOP | SSQ_PRINT_SENSE, 2714181381Sjkim "Data channel impending failure seek error rate too high") }, 2715181381Sjkim /* D B */ 2716311398Smav { SST(0x5D, 0x34, SS_NOP | SSQ_PRINT_SENSE, 2717181381Sjkim "Data channel impending failure too many block reassigns") }, 2718181381Sjkim /* D B */ 2719311398Smav { SST(0x5D, 0x35, SS_NOP | SSQ_PRINT_SENSE, 2720181381Sjkim "Data channel impending failure access times too high") }, 2721181381Sjkim /* D B */ 2722311398Smav { SST(0x5D, 0x36, SS_NOP | SSQ_PRINT_SENSE, 2723181381Sjkim "Data channel impending failure start unit times too high") }, 2724181381Sjkim /* D B */ 2725311398Smav { SST(0x5D, 0x37, SS_NOP | SSQ_PRINT_SENSE, 2726181381Sjkim "Data channel impending failure channel parametrics") }, 2727181381Sjkim /* D B */ 2728311398Smav { SST(0x5D, 0x38, SS_NOP | SSQ_PRINT_SENSE, 2729181381Sjkim "Data channel impending failure controller detected") }, 2730181381Sjkim /* D B */ 2731311398Smav { SST(0x5D, 0x39, SS_NOP | SSQ_PRINT_SENSE, 2732181381Sjkim "Data channel impending failure throughput performance") }, 2733181381Sjkim /* D B */ 2734311398Smav { SST(0x5D, 0x3A, SS_NOP | SSQ_PRINT_SENSE, 2735181381Sjkim "Data channel impending failure seek time performance") }, 2736181381Sjkim /* D B */ 2737311398Smav { SST(0x5D, 0x3B, SS_NOP | SSQ_PRINT_SENSE, 2738181381Sjkim "Data channel impending failure spin-up retry count") }, 2739181381Sjkim /* D B */ 2740311398Smav { SST(0x5D, 0x3C, SS_NOP | SSQ_PRINT_SENSE, 2741181381Sjkim "Data channel impending failure drive calibration retry count") }, 2742181381Sjkim /* D B */ 2743311398Smav { SST(0x5D, 0x40, SS_NOP | SSQ_PRINT_SENSE, 2744181381Sjkim "Servo impending failure general hard drive failure") }, 2745181381Sjkim /* D B */ 2746311398Smav { SST(0x5D, 0x41, SS_NOP | SSQ_PRINT_SENSE, 2747181381Sjkim "Servo impending failure drive error rate too high") }, 2748181381Sjkim /* D B */ 2749311398Smav { SST(0x5D, 0x42, SS_NOP | SSQ_PRINT_SENSE, 2750181381Sjkim "Servo impending failure data error rate too high") }, 2751181381Sjkim /* D B */ 2752311398Smav { SST(0x5D, 0x43, SS_NOP | SSQ_PRINT_SENSE, 2753181381Sjkim "Servo impending failure seek error rate too high") }, 2754181381Sjkim /* D B */ 2755311398Smav { SST(0x5D, 0x44, SS_NOP | SSQ_PRINT_SENSE, 2756181381Sjkim "Servo impending failure too many block reassigns") }, 2757181381Sjkim /* D B */ 2758311398Smav { SST(0x5D, 0x45, SS_NOP | SSQ_PRINT_SENSE, 2759181381Sjkim "Servo impending failure access times too high") }, 2760181381Sjkim /* D B */ 2761311398Smav { SST(0x5D, 0x46, SS_NOP | SSQ_PRINT_SENSE, 2762181381Sjkim "Servo impending failure start unit times too high") }, 2763181381Sjkim /* D B */ 2764311398Smav { SST(0x5D, 0x47, SS_NOP | SSQ_PRINT_SENSE, 2765181381Sjkim "Servo impending failure channel parametrics") }, 2766181381Sjkim /* D B */ 2767311398Smav { SST(0x5D, 0x48, SS_NOP | SSQ_PRINT_SENSE, 2768181381Sjkim "Servo impending failure controller detected") }, 2769181381Sjkim /* D B */ 2770311398Smav { SST(0x5D, 0x49, SS_NOP | SSQ_PRINT_SENSE, 2771181381Sjkim "Servo impending failure throughput performance") }, 2772181381Sjkim /* D B */ 2773311398Smav { SST(0x5D, 0x4A, SS_NOP | SSQ_PRINT_SENSE, 2774181381Sjkim "Servo impending failure seek time performance") }, 2775181381Sjkim /* D B */ 2776311398Smav { SST(0x5D, 0x4B, SS_NOP | SSQ_PRINT_SENSE, 2777181381Sjkim "Servo impending failure spin-up retry count") }, 2778181381Sjkim /* D B */ 2779311398Smav { SST(0x5D, 0x4C, SS_NOP | SSQ_PRINT_SENSE, 2780181381Sjkim "Servo impending failure drive calibration retry count") }, 2781181381Sjkim /* D B */ 2782311398Smav { SST(0x5D, 0x50, SS_NOP | SSQ_PRINT_SENSE, 2783181381Sjkim "Spindle impending failure general hard drive failure") }, 2784181381Sjkim /* D B */ 2785311398Smav { SST(0x5D, 0x51, SS_NOP | SSQ_PRINT_SENSE, 2786181381Sjkim "Spindle impending failure drive error rate too high") }, 2787181381Sjkim /* D B */ 2788311398Smav { SST(0x5D, 0x52, SS_NOP | SSQ_PRINT_SENSE, 2789181381Sjkim "Spindle impending failure data error rate too high") }, 2790181381Sjkim /* D B */ 2791311398Smav { SST(0x5D, 0x53, SS_NOP | SSQ_PRINT_SENSE, 2792181381Sjkim "Spindle impending failure seek error rate too high") }, 2793181381Sjkim /* D B */ 2794311398Smav { SST(0x5D, 0x54, SS_NOP | SSQ_PRINT_SENSE, 2795181381Sjkim "Spindle impending failure too many block reassigns") }, 2796181381Sjkim /* D B */ 2797311398Smav { SST(0x5D, 0x55, SS_NOP | SSQ_PRINT_SENSE, 2798181381Sjkim "Spindle impending failure access times too high") }, 2799181381Sjkim /* D B */ 2800311398Smav { SST(0x5D, 0x56, SS_NOP | SSQ_PRINT_SENSE, 2801181381Sjkim "Spindle impending failure start unit times too high") }, 2802181381Sjkim /* D B */ 2803311398Smav { SST(0x5D, 0x57, SS_NOP | SSQ_PRINT_SENSE, 2804181381Sjkim "Spindle impending failure channel parametrics") }, 2805181381Sjkim /* D B */ 2806311398Smav { SST(0x5D, 0x58, SS_NOP | SSQ_PRINT_SENSE, 2807181381Sjkim "Spindle impending failure controller detected") }, 2808181381Sjkim /* D B */ 2809311398Smav { SST(0x5D, 0x59, SS_NOP | SSQ_PRINT_SENSE, 2810181381Sjkim "Spindle impending failure throughput performance") }, 2811181381Sjkim /* D B */ 2812311398Smav { SST(0x5D, 0x5A, SS_NOP | SSQ_PRINT_SENSE, 2813181381Sjkim "Spindle impending failure seek time performance") }, 2814181381Sjkim /* D B */ 2815311398Smav { SST(0x5D, 0x5B, SS_NOP | SSQ_PRINT_SENSE, 2816181381Sjkim "Spindle impending failure spin-up retry count") }, 2817181381Sjkim /* D B */ 2818311398Smav { SST(0x5D, 0x5C, SS_NOP | SSQ_PRINT_SENSE, 2819181381Sjkim "Spindle impending failure drive calibration retry count") }, 2820181381Sjkim /* D B */ 2821311398Smav { SST(0x5D, 0x60, SS_NOP | SSQ_PRINT_SENSE, 2822181381Sjkim "Firmware impending failure general hard drive failure") }, 2823181381Sjkim /* D B */ 2824311398Smav { SST(0x5D, 0x61, SS_NOP | SSQ_PRINT_SENSE, 2825181381Sjkim "Firmware impending failure drive error rate too high") }, 2826181381Sjkim /* D B */ 2827311398Smav { SST(0x5D, 0x62, SS_NOP | SSQ_PRINT_SENSE, 2828181381Sjkim "Firmware impending failure data error rate too high") }, 2829181381Sjkim /* D B */ 2830311398Smav { SST(0x5D, 0x63, SS_NOP | SSQ_PRINT_SENSE, 2831181381Sjkim "Firmware impending failure seek error rate too high") }, 2832181381Sjkim /* D B */ 2833311398Smav { SST(0x5D, 0x64, SS_NOP | SSQ_PRINT_SENSE, 2834181381Sjkim "Firmware impending failure too many block reassigns") }, 2835181381Sjkim /* D B */ 2836311398Smav { SST(0x5D, 0x65, SS_NOP | SSQ_PRINT_SENSE, 2837181381Sjkim "Firmware impending failure access times too high") }, 2838181381Sjkim /* D B */ 2839311398Smav { SST(0x5D, 0x66, SS_NOP | SSQ_PRINT_SENSE, 2840181381Sjkim "Firmware impending failure start unit times too high") }, 2841181381Sjkim /* D B */ 2842311398Smav { SST(0x5D, 0x67, SS_NOP | SSQ_PRINT_SENSE, 2843181381Sjkim "Firmware impending failure channel parametrics") }, 2844181381Sjkim /* D B */ 2845311398Smav { SST(0x5D, 0x68, SS_NOP | SSQ_PRINT_SENSE, 2846181381Sjkim "Firmware impending failure controller detected") }, 2847181381Sjkim /* D B */ 2848311398Smav { SST(0x5D, 0x69, SS_NOP | SSQ_PRINT_SENSE, 2849181381Sjkim "Firmware impending failure throughput performance") }, 2850181381Sjkim /* D B */ 2851311398Smav { SST(0x5D, 0x6A, SS_NOP | SSQ_PRINT_SENSE, 2852181381Sjkim "Firmware impending failure seek time performance") }, 2853181381Sjkim /* D B */ 2854311398Smav { SST(0x5D, 0x6B, SS_NOP | SSQ_PRINT_SENSE, 2855181381Sjkim "Firmware impending failure spin-up retry count") }, 2856181381Sjkim /* D B */ 2857311398Smav { SST(0x5D, 0x6C, SS_NOP | SSQ_PRINT_SENSE, 2858181381Sjkim "Firmware impending failure drive calibration retry count") }, 2859311398Smav /* D B */ 2860311398Smav { SST(0x5D, 0x73, SS_NOP | SSQ_PRINT_SENSE, 2861311398Smav "Media impending failure endurance limit met") }, 2862181381Sjkim /* DTLPWROMAEBKVF */ 2863311398Smav { SST(0x5D, 0xFF, SS_NOP | SSQ_PRINT_SENSE, 2864181381Sjkim "Failure prediction threshold exceeded (false)") }, 2865181381Sjkim /* DTLPWRO A K */ 2866181381Sjkim { SST(0x5E, 0x00, SS_RDEF, 2867181381Sjkim "Low power condition on") }, 2868181381Sjkim /* DTLPWRO A K */ 2869181381Sjkim { SST(0x5E, 0x01, SS_RDEF, 2870181381Sjkim "Idle condition activated by timer") }, 2871181381Sjkim /* DTLPWRO A K */ 2872181381Sjkim { SST(0x5E, 0x02, SS_RDEF, 2873181381Sjkim "Standby condition activated by timer") }, 2874181381Sjkim /* DTLPWRO A K */ 2875181381Sjkim { SST(0x5E, 0x03, SS_RDEF, 2876181381Sjkim "Idle condition activated by command") }, 2877181381Sjkim /* DTLPWRO A K */ 2878181381Sjkim { SST(0x5E, 0x04, SS_RDEF, 2879181381Sjkim "Standby condition activated by command") }, 2880238595Smav /* DTLPWRO A K */ 2881238595Smav { SST(0x5E, 0x05, SS_RDEF, 2882238595Smav "Idle-B condition activated by timer") }, 2883238595Smav /* DTLPWRO A K */ 2884238595Smav { SST(0x5E, 0x06, SS_RDEF, 2885238595Smav "Idle-B condition activated by command") }, 2886238595Smav /* DTLPWRO A K */ 2887238595Smav { SST(0x5E, 0x07, SS_RDEF, 2888238595Smav "Idle-C condition activated by timer") }, 2889238595Smav /* DTLPWRO A K */ 2890238595Smav { SST(0x5E, 0x08, SS_RDEF, 2891238595Smav "Idle-C condition activated by command") }, 2892238595Smav /* DTLPWRO A K */ 2893238595Smav { SST(0x5E, 0x09, SS_RDEF, 2894238596Smav "Standby-Y condition activated by timer") }, 2895238595Smav /* DTLPWRO A K */ 2896238595Smav { SST(0x5E, 0x0A, SS_RDEF, 2897238595Smav "Standby-Y condition activated by command") }, 2898181381Sjkim /* B */ 2899181381Sjkim { SST(0x5E, 0x41, SS_RDEF, /* XXX TBD */ 2900181381Sjkim "Power state change to active") }, 2901181381Sjkim /* B */ 2902181381Sjkim { SST(0x5E, 0x42, SS_RDEF, /* XXX TBD */ 2903181381Sjkim "Power state change to idle") }, 2904181381Sjkim /* B */ 2905181381Sjkim { SST(0x5E, 0x43, SS_RDEF, /* XXX TBD */ 2906181381Sjkim "Power state change to standby") }, 2907181381Sjkim /* B */ 2908181381Sjkim { SST(0x5E, 0x45, SS_RDEF, /* XXX TBD */ 2909181381Sjkim "Power state change to sleep") }, 2910181381Sjkim /* BK */ 2911181381Sjkim { SST(0x5E, 0x47, SS_RDEF, /* XXX TBD */ 2912181381Sjkim "Power state change to device control") }, 2913181381Sjkim /* */ 2914181381Sjkim { SST(0x60, 0x00, SS_RDEF, 2915181381Sjkim "Lamp failure") }, 2916181381Sjkim /* */ 2917181381Sjkim { SST(0x61, 0x00, SS_RDEF, 2918181381Sjkim "Video acquisition error") }, 2919181381Sjkim /* */ 2920181381Sjkim { SST(0x61, 0x01, SS_RDEF, 2921181381Sjkim "Unable to acquire video") }, 2922181381Sjkim /* */ 2923181381Sjkim { SST(0x61, 0x02, SS_RDEF, 2924181381Sjkim "Out of focus") }, 2925181381Sjkim /* */ 2926181381Sjkim { SST(0x62, 0x00, SS_RDEF, 2927181381Sjkim "Scan head positioning error") }, 2928181381Sjkim /* R */ 2929181381Sjkim { SST(0x63, 0x00, SS_RDEF, 2930181381Sjkim "End of user area encountered on this track") }, 2931181381Sjkim /* R */ 2932181381Sjkim { SST(0x63, 0x01, SS_FATAL | ENOSPC, 2933181381Sjkim "Packet does not fit in available space") }, 2934181381Sjkim /* R */ 2935181381Sjkim { SST(0x64, 0x00, SS_FATAL | ENXIO, 2936181381Sjkim "Illegal mode for this track") }, 2937181381Sjkim /* R */ 2938181381Sjkim { SST(0x64, 0x01, SS_RDEF, 2939181381Sjkim "Invalid packet size") }, 2940181381Sjkim /* DTLPWROMAEBKVF */ 2941181381Sjkim { SST(0x65, 0x00, SS_RDEF, 2942181381Sjkim "Voltage fault") }, 2943181381Sjkim /* */ 2944181381Sjkim { SST(0x66, 0x00, SS_RDEF, 2945181381Sjkim "Automatic document feeder cover up") }, 2946181381Sjkim /* */ 2947181381Sjkim { SST(0x66, 0x01, SS_RDEF, 2948181381Sjkim "Automatic document feeder lift up") }, 2949181381Sjkim /* */ 2950181381Sjkim { SST(0x66, 0x02, SS_RDEF, 2951181381Sjkim "Document jam in automatic document feeder") }, 2952181381Sjkim /* */ 2953181381Sjkim { SST(0x66, 0x03, SS_RDEF, 2954181381Sjkim "Document miss feed automatic in document feeder") }, 2955181381Sjkim /* A */ 2956181381Sjkim { SST(0x67, 0x00, SS_RDEF, 2957181381Sjkim "Configuration failure") }, 2958181381Sjkim /* A */ 2959181381Sjkim { SST(0x67, 0x01, SS_RDEF, 2960181381Sjkim "Configuration of incapable logical units failed") }, 2961181381Sjkim /* A */ 2962181381Sjkim { SST(0x67, 0x02, SS_RDEF, 2963181381Sjkim "Add logical unit failed") }, 2964181381Sjkim /* A */ 2965181381Sjkim { SST(0x67, 0x03, SS_RDEF, 2966181381Sjkim "Modification of logical unit failed") }, 2967181381Sjkim /* A */ 2968181381Sjkim { SST(0x67, 0x04, SS_RDEF, 2969181381Sjkim "Exchange of logical unit failed") }, 2970181381Sjkim /* A */ 2971181381Sjkim { SST(0x67, 0x05, SS_RDEF, 2972181381Sjkim "Remove of logical unit failed") }, 2973181381Sjkim /* A */ 2974181381Sjkim { SST(0x67, 0x06, SS_RDEF, 2975181381Sjkim "Attachment of logical unit failed") }, 2976181381Sjkim /* A */ 2977181381Sjkim { SST(0x67, 0x07, SS_RDEF, 2978181381Sjkim "Creation of logical unit failed") }, 2979181381Sjkim /* A */ 2980181381Sjkim { SST(0x67, 0x08, SS_RDEF, /* XXX TBD */ 2981181381Sjkim "Assign failure occurred") }, 2982181381Sjkim /* A */ 2983181381Sjkim { SST(0x67, 0x09, SS_RDEF, /* XXX TBD */ 2984181381Sjkim "Multiply assigned logical unit") }, 2985181381Sjkim /* DTLPWROMAEBKVF */ 2986181381Sjkim { SST(0x67, 0x0A, SS_RDEF, /* XXX TBD */ 2987181381Sjkim "Set target port groups command failed") }, 2988181381Sjkim /* DT B */ 2989181381Sjkim { SST(0x67, 0x0B, SS_RDEF, /* XXX TBD */ 2990181381Sjkim "ATA device feature not enabled") }, 2991181381Sjkim /* A */ 2992181381Sjkim { SST(0x68, 0x00, SS_RDEF, 2993181381Sjkim "Logical unit not configured") }, 2994288771Smav /* D */ 2995288771Smav { SST(0x68, 0x01, SS_RDEF, 2996288771Smav "Subsidiary logical unit not configured") }, 2997181381Sjkim /* A */ 2998181381Sjkim { SST(0x69, 0x00, SS_RDEF, 2999181381Sjkim "Data loss on logical unit") }, 3000181381Sjkim /* A */ 3001181381Sjkim { SST(0x69, 0x01, SS_RDEF, 3002181381Sjkim "Multiple logical unit failures") }, 3003181381Sjkim /* A */ 3004181381Sjkim { SST(0x69, 0x02, SS_RDEF, 3005181381Sjkim "Parity/data mismatch") }, 3006181381Sjkim /* A */ 3007181381Sjkim { SST(0x6A, 0x00, SS_RDEF, 3008181381Sjkim "Informational, refer to log") }, 3009181381Sjkim /* A */ 3010181381Sjkim { SST(0x6B, 0x00, SS_RDEF, 3011181381Sjkim "State change has occurred") }, 3012181381Sjkim /* A */ 3013181381Sjkim { SST(0x6B, 0x01, SS_RDEF, 3014181381Sjkim "Redundancy level got better") }, 3015181381Sjkim /* A */ 3016181381Sjkim { SST(0x6B, 0x02, SS_RDEF, 3017181381Sjkim "Redundancy level got worse") }, 3018181381Sjkim /* A */ 3019181381Sjkim { SST(0x6C, 0x00, SS_RDEF, 3020181381Sjkim "Rebuild failure occurred") }, 3021181381Sjkim /* A */ 3022181381Sjkim { SST(0x6D, 0x00, SS_RDEF, 3023181381Sjkim "Recalculate failure occurred") }, 3024181381Sjkim /* A */ 3025181381Sjkim { SST(0x6E, 0x00, SS_RDEF, 3026181381Sjkim "Command to logical unit failed") }, 3027181381Sjkim /* R */ 3028181381Sjkim { SST(0x6F, 0x00, SS_RDEF, /* XXX TBD */ 3029181381Sjkim "Copy protection key exchange failure - authentication failure") }, 3030181381Sjkim /* R */ 3031181381Sjkim { SST(0x6F, 0x01, SS_RDEF, /* XXX TBD */ 3032181381Sjkim "Copy protection key exchange failure - key not present") }, 3033181381Sjkim /* R */ 3034181381Sjkim { SST(0x6F, 0x02, SS_RDEF, /* XXX TBD */ 3035181381Sjkim "Copy protection key exchange failure - key not established") }, 3036181381Sjkim /* R */ 3037181381Sjkim { SST(0x6F, 0x03, SS_RDEF, /* XXX TBD */ 3038181381Sjkim "Read of scrambled sector without authentication") }, 3039181381Sjkim /* R */ 3040181381Sjkim { SST(0x6F, 0x04, SS_RDEF, /* XXX TBD */ 3041181381Sjkim "Media region code is mismatched to logical unit region") }, 3042181381Sjkim /* R */ 3043181381Sjkim { SST(0x6F, 0x05, SS_RDEF, /* XXX TBD */ 3044181381Sjkim "Drive region must be permanent/region reset count error") }, 3045181381Sjkim /* R */ 3046181381Sjkim { SST(0x6F, 0x06, SS_RDEF, /* XXX TBD */ 3047181381Sjkim "Insufficient block count for binding NONCE recording") }, 3048181381Sjkim /* R */ 3049181381Sjkim { SST(0x6F, 0x07, SS_RDEF, /* XXX TBD */ 3050181381Sjkim "Conflict in binding NONCE recording") }, 3051181381Sjkim /* T */ 3052181381Sjkim { SST(0x70, 0x00, SS_RDEF, 3053181381Sjkim "Decompression exception short: ASCQ = Algorithm ID") }, 3054181381Sjkim /* T */ 3055181381Sjkim { SST(0x70, 0xFF, SS_RDEF | SSQ_RANGE, 3056181381Sjkim NULL) }, /* Range 0x00 -> 0xFF */ 3057181381Sjkim /* T */ 3058181381Sjkim { SST(0x71, 0x00, SS_RDEF, 3059181381Sjkim "Decompression exception long: ASCQ = Algorithm ID") }, 3060181381Sjkim /* T */ 3061181381Sjkim { SST(0x71, 0xFF, SS_RDEF | SSQ_RANGE, 3062181381Sjkim NULL) }, /* Range 0x00 -> 0xFF */ 3063181381Sjkim /* R */ 3064181381Sjkim { SST(0x72, 0x00, SS_RDEF, 3065181381Sjkim "Session fixation error") }, 3066181381Sjkim /* R */ 3067181381Sjkim { SST(0x72, 0x01, SS_RDEF, 3068181381Sjkim "Session fixation error writing lead-in") }, 3069181381Sjkim /* R */ 3070181381Sjkim { SST(0x72, 0x02, SS_RDEF, 3071181381Sjkim "Session fixation error writing lead-out") }, 3072181381Sjkim /* R */ 3073181381Sjkim { SST(0x72, 0x03, SS_RDEF, 3074181381Sjkim "Session fixation error - incomplete track in session") }, 3075181381Sjkim /* R */ 3076181381Sjkim { SST(0x72, 0x04, SS_RDEF, 3077181381Sjkim "Empty or partially written reserved track") }, 3078181381Sjkim /* R */ 3079181381Sjkim { SST(0x72, 0x05, SS_RDEF, /* XXX TBD */ 3080181381Sjkim "No more track reservations allowed") }, 3081181381Sjkim /* R */ 3082181381Sjkim { SST(0x72, 0x06, SS_RDEF, /* XXX TBD */ 3083181381Sjkim "RMZ extension is not allowed") }, 3084181381Sjkim /* R */ 3085181381Sjkim { SST(0x72, 0x07, SS_RDEF, /* XXX TBD */ 3086181381Sjkim "No more test zone extensions are allowed") }, 3087181381Sjkim /* R */ 3088181381Sjkim { SST(0x73, 0x00, SS_RDEF, 3089181381Sjkim "CD control error") }, 3090181381Sjkim /* R */ 3091181381Sjkim { SST(0x73, 0x01, SS_RDEF, 3092181381Sjkim "Power calibration area almost full") }, 3093181381Sjkim /* R */ 3094181381Sjkim { SST(0x73, 0x02, SS_FATAL | ENOSPC, 3095181381Sjkim "Power calibration area is full") }, 3096181381Sjkim /* R */ 3097181381Sjkim { SST(0x73, 0x03, SS_RDEF, 3098181381Sjkim "Power calibration area error") }, 3099181381Sjkim /* R */ 3100181381Sjkim { SST(0x73, 0x04, SS_RDEF, 3101181381Sjkim "Program memory area update failure") }, 3102181381Sjkim /* R */ 3103181381Sjkim { SST(0x73, 0x05, SS_RDEF, 3104181381Sjkim "Program memory area is full") }, 3105181381Sjkim /* R */ 3106181381Sjkim { SST(0x73, 0x06, SS_RDEF, /* XXX TBD */ 3107181381Sjkim "RMA/PMA is almost full") }, 3108181381Sjkim /* R */ 3109181381Sjkim { SST(0x73, 0x10, SS_RDEF, /* XXX TBD */ 3110181381Sjkim "Current power calibration area almost full") }, 3111181381Sjkim /* R */ 3112181381Sjkim { SST(0x73, 0x11, SS_RDEF, /* XXX TBD */ 3113181381Sjkim "Current power calibration area is full") }, 3114181381Sjkim /* R */ 3115181381Sjkim { SST(0x73, 0x17, SS_RDEF, /* XXX TBD */ 3116181381Sjkim "RDZ is full") }, 3117181381Sjkim /* T */ 3118181381Sjkim { SST(0x74, 0x00, SS_RDEF, /* XXX TBD */ 3119181381Sjkim "Security error") }, 3120181381Sjkim /* T */ 3121181381Sjkim { SST(0x74, 0x01, SS_RDEF, /* XXX TBD */ 3122181381Sjkim "Unable to decrypt data") }, 3123181381Sjkim /* T */ 3124181381Sjkim { SST(0x74, 0x02, SS_RDEF, /* XXX TBD */ 3125181381Sjkim "Unencrypted data encountered while decrypting") }, 3126181381Sjkim /* T */ 3127181381Sjkim { SST(0x74, 0x03, SS_RDEF, /* XXX TBD */ 3128181381Sjkim "Incorrect data encryption key") }, 3129181381Sjkim /* T */ 3130181381Sjkim { SST(0x74, 0x04, SS_RDEF, /* XXX TBD */ 3131181381Sjkim "Cryptographic integrity validation failed") }, 3132181381Sjkim /* T */ 3133181381Sjkim { SST(0x74, 0x05, SS_RDEF, /* XXX TBD */ 3134181381Sjkim "Error decrypting data") }, 3135181381Sjkim /* T */ 3136181381Sjkim { SST(0x74, 0x06, SS_RDEF, /* XXX TBD */ 3137181381Sjkim "Unknown signature verification key") }, 3138181381Sjkim /* T */ 3139181381Sjkim { SST(0x74, 0x07, SS_RDEF, /* XXX TBD */ 3140181381Sjkim "Encryption parameters not useable") }, 3141181381Sjkim /* DT R M E VF */ 3142181381Sjkim { SST(0x74, 0x08, SS_RDEF, /* XXX TBD */ 3143181381Sjkim "Digital signature validation failure") }, 3144181381Sjkim /* T */ 3145181381Sjkim { SST(0x74, 0x09, SS_RDEF, /* XXX TBD */ 3146181381Sjkim "Encryption mode mismatch on read") }, 3147181381Sjkim /* T */ 3148181381Sjkim { SST(0x74, 0x0A, SS_RDEF, /* XXX TBD */ 3149181381Sjkim "Encrypted block not raw read enabled") }, 3150181381Sjkim /* T */ 3151181381Sjkim { SST(0x74, 0x0B, SS_RDEF, /* XXX TBD */ 3152181381Sjkim "Incorrect encryption parameters") }, 3153181381Sjkim /* DT R MAEBKV */ 3154181381Sjkim { SST(0x74, 0x0C, SS_RDEF, /* XXX TBD */ 3155181381Sjkim "Unable to decrypt parameter list") }, 3156181381Sjkim /* T */ 3157181381Sjkim { SST(0x74, 0x0D, SS_RDEF, /* XXX TBD */ 3158181381Sjkim "Encryption algorithm disabled") }, 3159181381Sjkim /* DT R MAEBKV */ 3160181381Sjkim { SST(0x74, 0x10, SS_RDEF, /* XXX TBD */ 3161181381Sjkim "SA creation parameter value invalid") }, 3162181381Sjkim /* DT R MAEBKV */ 3163181381Sjkim { SST(0x74, 0x11, SS_RDEF, /* XXX TBD */ 3164181381Sjkim "SA creation parameter value rejected") }, 3165181381Sjkim /* DT R MAEBKV */ 3166181381Sjkim { SST(0x74, 0x12, SS_RDEF, /* XXX TBD */ 3167181381Sjkim "Invalid SA usage") }, 3168181381Sjkim /* T */ 3169181381Sjkim { SST(0x74, 0x21, SS_RDEF, /* XXX TBD */ 3170181381Sjkim "Data encryption configuration prevented") }, 3171181381Sjkim /* DT R MAEBKV */ 3172181381Sjkim { SST(0x74, 0x30, SS_RDEF, /* XXX TBD */ 3173181381Sjkim "SA creation parameter not supported") }, 3174181381Sjkim /* DT R MAEBKV */ 3175181381Sjkim { SST(0x74, 0x40, SS_RDEF, /* XXX TBD */ 3176181381Sjkim "Authentication failed") }, 3177181381Sjkim /* V */ 3178181381Sjkim { SST(0x74, 0x61, SS_RDEF, /* XXX TBD */ 3179181381Sjkim "External data encryption key manager access error") }, 3180181381Sjkim /* V */ 3181181381Sjkim { SST(0x74, 0x62, SS_RDEF, /* XXX TBD */ 3182181381Sjkim "External data encryption key manager error") }, 3183181381Sjkim /* V */ 3184181381Sjkim { SST(0x74, 0x63, SS_RDEF, /* XXX TBD */ 3185181381Sjkim "External data encryption key not found") }, 3186181381Sjkim /* V */ 3187181381Sjkim { SST(0x74, 0x64, SS_RDEF, /* XXX TBD */ 3188181381Sjkim "External data encryption request not authorized") }, 3189181381Sjkim /* T */ 3190181381Sjkim { SST(0x74, 0x6E, SS_RDEF, /* XXX TBD */ 3191181381Sjkim "External data encryption control timeout") }, 3192181381Sjkim /* T */ 3193181381Sjkim { SST(0x74, 0x6F, SS_RDEF, /* XXX TBD */ 3194181381Sjkim "External data encryption control error") }, 3195181381Sjkim /* DT R M E V */ 3196307129Smav { SST(0x74, 0x71, SS_FATAL | EACCES, 3197181381Sjkim "Logical unit access not authorized") }, 3198181381Sjkim /* D */ 3199307129Smav { SST(0x74, 0x79, SS_FATAL | EACCES, 3200181381Sjkim "Security conflict in translated device") } 320139213Sgibbs}; 320239213Sgibbs 320374840Skenconst int asc_table_size = sizeof(asc_table)/sizeof(asc_table[0]); 320474840Sken 320574840Skenstruct asc_key 320639213Sgibbs{ 320774840Sken int asc; 320874840Sken int ascq; 320974840Sken}; 321074840Sken 321174840Skenstatic int 321274840Skenascentrycomp(const void *key, const void *member) 321374840Sken{ 321474840Sken int asc; 321574840Sken int ascq; 321674840Sken const struct asc_table_entry *table_entry; 321774840Sken 321874840Sken asc = ((const struct asc_key *)key)->asc; 321974840Sken ascq = ((const struct asc_key *)key)->ascq; 322074840Sken table_entry = (const struct asc_table_entry *)member; 322174840Sken 322274840Sken if (asc >= table_entry->asc) { 322374840Sken 322474840Sken if (asc > table_entry->asc) 322574840Sken return (1); 322674840Sken 322774840Sken if (ascq <= table_entry->ascq) { 322874840Sken /* Check for ranges */ 322974840Sken if (ascq == table_entry->ascq 323074840Sken || ((table_entry->action & SSQ_RANGE) != 0 323174840Sken && ascq >= (table_entry - 1)->ascq)) 323274840Sken return (0); 323374840Sken return (-1); 323474840Sken } 323574840Sken return (1); 323674840Sken } 323774840Sken return (-1); 323874840Sken} 323974840Sken 324074840Skenstatic int 324174840Skensenseentrycomp(const void *key, const void *member) 324274840Sken{ 324374840Sken int sense_key; 324474840Sken const struct sense_key_table_entry *table_entry; 324574840Sken 324674840Sken sense_key = *((const int *)key); 324774840Sken table_entry = (const struct sense_key_table_entry *)member; 324874840Sken 324974840Sken if (sense_key >= table_entry->sense_key) { 325074840Sken if (sense_key == table_entry->sense_key) 325174840Sken return (0); 325274840Sken return (1); 325374840Sken } 325474840Sken return (-1); 325574840Sken} 325674840Sken 325774840Skenstatic void 325874840Skenfetchtableentries(int sense_key, int asc, int ascq, 325974840Sken struct scsi_inquiry_data *inq_data, 326074840Sken const struct sense_key_table_entry **sense_entry, 326174840Sken const struct asc_table_entry **asc_entry) 326274840Sken{ 326339213Sgibbs caddr_t match; 326474840Sken const struct asc_table_entry *asc_tables[2]; 326574840Sken const struct sense_key_table_entry *sense_tables[2]; 326674840Sken struct asc_key asc_ascq; 326774840Sken size_t asc_tables_size[2]; 326874840Sken size_t sense_tables_size[2]; 326974840Sken int num_asc_tables; 327074840Sken int num_sense_tables; 327174840Sken int i; 327239213Sgibbs 327374840Sken /* Default to failure */ 327474840Sken *sense_entry = NULL; 327574840Sken *asc_entry = NULL; 327674840Sken match = NULL; 327774840Sken if (inq_data != NULL) 327874840Sken match = cam_quirkmatch((caddr_t)inq_data, 327974840Sken (caddr_t)sense_quirk_table, 328074840Sken sense_quirk_table_size, 328174840Sken sizeof(*sense_quirk_table), 328274840Sken scsi_inquiry_match); 328339213Sgibbs 328474840Sken if (match != NULL) { 328574840Sken struct scsi_sense_quirk_entry *quirk; 328639213Sgibbs 328774840Sken quirk = (struct scsi_sense_quirk_entry *)match; 328874840Sken asc_tables[0] = quirk->asc_info; 328974840Sken asc_tables_size[0] = quirk->num_ascs; 329074840Sken asc_tables[1] = asc_table; 329174840Sken asc_tables_size[1] = asc_table_size; 329274840Sken num_asc_tables = 2; 329374840Sken sense_tables[0] = quirk->sense_key_info; 329474840Sken sense_tables_size[0] = quirk->num_sense_keys; 329574840Sken sense_tables[1] = sense_key_table; 329674840Sken sense_tables_size[1] = sense_key_table_size; 329774840Sken num_sense_tables = 2; 329839213Sgibbs } else { 329974840Sken asc_tables[0] = asc_table; 330074840Sken asc_tables_size[0] = asc_table_size; 330174840Sken num_asc_tables = 1; 330274840Sken sense_tables[0] = sense_key_table; 330374840Sken sense_tables_size[0] = sense_key_table_size; 330474840Sken num_sense_tables = 1; 330539213Sgibbs } 330639213Sgibbs 330774840Sken asc_ascq.asc = asc; 330874840Sken asc_ascq.ascq = ascq; 330974840Sken for (i = 0; i < num_asc_tables; i++) { 331074840Sken void *found_entry; 331139213Sgibbs 331274840Sken found_entry = bsearch(&asc_ascq, asc_tables[i], 331374840Sken asc_tables_size[i], 331474840Sken sizeof(**asc_tables), 331574840Sken ascentrycomp); 331639213Sgibbs 331774840Sken if (found_entry) { 331874840Sken *asc_entry = (struct asc_table_entry *)found_entry; 331974840Sken break; 332039213Sgibbs } 332139213Sgibbs } 332239213Sgibbs 332374840Sken for (i = 0; i < num_sense_tables; i++) { 332474840Sken void *found_entry; 332539213Sgibbs 332674840Sken found_entry = bsearch(&sense_key, sense_tables[i], 332774840Sken sense_tables_size[i], 332874840Sken sizeof(**sense_tables), 332974840Sken senseentrycomp); 333039213Sgibbs 333174840Sken if (found_entry) { 333274840Sken *sense_entry = 333374840Sken (struct sense_key_table_entry *)found_entry; 333474840Sken break; 333574840Sken } 333674840Sken } 333739213Sgibbs} 333839213Sgibbs 333974840Skenvoid 334074840Skenscsi_sense_desc(int sense_key, int asc, int ascq, 334174840Sken struct scsi_inquiry_data *inq_data, 334274840Sken const char **sense_key_desc, const char **asc_desc) 334339213Sgibbs{ 334474840Sken const struct asc_table_entry *asc_entry; 334574840Sken const struct sense_key_table_entry *sense_entry; 334674840Sken 334774840Sken fetchtableentries(sense_key, asc, ascq, 334874840Sken inq_data, 334974840Sken &sense_entry, 335074840Sken &asc_entry); 335174840Sken 3352225950Sken if (sense_entry != NULL) 3353225950Sken *sense_key_desc = sense_entry->desc; 3354225950Sken else 3355225950Sken *sense_key_desc = "Invalid Sense Key"; 335674840Sken 335774840Sken if (asc_entry != NULL) 335874840Sken *asc_desc = asc_entry->desc; 335974840Sken else if (asc >= 0x80 && asc <= 0xff) 336074840Sken *asc_desc = "Vendor Specific ASC"; 336174840Sken else if (ascq >= 0x80 && ascq <= 0xff) 336274840Sken *asc_desc = "Vendor Specific ASCQ"; 336374840Sken else 336474840Sken *asc_desc = "Reserved ASC/ASCQ pair"; 336539213Sgibbs} 336639213Sgibbs 336739213Sgibbs/* 336874840Sken * Given sense and device type information, return the appropriate action. 336974840Sken * If we do not understand the specific error as identified by the ASC/ASCQ 337074840Sken * pair, fall back on the more generic actions derived from the sense key. 337139213Sgibbs */ 337239213Sgibbsscsi_sense_action 337374840Skenscsi_error_action(struct ccb_scsiio *csio, struct scsi_inquiry_data *inq_data, 337474840Sken u_int32_t sense_flags) 337539213Sgibbs{ 337674840Sken const struct asc_table_entry *asc_entry; 337774840Sken const struct sense_key_table_entry *sense_entry; 337874840Sken int error_code, sense_key, asc, ascq; 337974840Sken scsi_sense_action action; 338039213Sgibbs 3381237478Smav if (!scsi_extract_sense_ccb((union ccb *)csio, 3382237478Smav &error_code, &sense_key, &asc, &ascq)) { 3383237478Smav action = SS_RETRY | SSQ_DECREMENT_COUNT | SSQ_PRINT_SENSE | EIO; 3384237478Smav } else if ((error_code == SSD_DEFERRED_ERROR) 3385225950Sken || (error_code == SSD_DESC_DEFERRED_ERROR)) { 338674840Sken /* 338774840Sken * XXX dufault@FreeBSD.org 338874840Sken * This error doesn't relate to the command associated 338974840Sken * with this request sense. A deferred error is an error 339074840Sken * for a command that has already returned GOOD status 339174840Sken * (see SCSI2 8.2.14.2). 339274840Sken * 339374840Sken * By my reading of that section, it looks like the current 339474840Sken * command has been cancelled, we should now clean things up 339574840Sken * (hopefully recovering any lost data) and then retry the 339674840Sken * current command. There are two easy choices, both wrong: 339774840Sken * 339874840Sken * 1. Drop through (like we had been doing), thus treating 339974840Sken * this as if the error were for the current command and 340074840Sken * return and stop the current command. 340174840Sken * 340274840Sken * 2. Issue a retry (like I made it do) thus hopefully 340374840Sken * recovering the current transfer, and ignoring the 340474840Sken * fact that we've dropped a command. 340574840Sken * 340674840Sken * These should probably be handled in a device specific 340774840Sken * sense handler or punted back up to a user mode daemon 340874840Sken */ 340974840Sken action = SS_RETRY|SSQ_DECREMENT_COUNT|SSQ_PRINT_SENSE; 341039213Sgibbs } else { 341174840Sken fetchtableentries(sense_key, asc, ascq, 341274840Sken inq_data, 341374840Sken &sense_entry, 341474840Sken &asc_entry); 341539213Sgibbs 341674840Sken /* 341774840Sken * Override the 'No additional Sense' entry (0,0) 341874840Sken * with the error action of the sense key. 341974840Sken */ 342074840Sken if (asc_entry != NULL 342174840Sken && (asc != 0 || ascq != 0)) 342274840Sken action = asc_entry->action; 3423225950Sken else if (sense_entry != NULL) 3424225950Sken action = sense_entry->action; 342574840Sken else 3426225950Sken action = SS_RETRY|SSQ_DECREMENT_COUNT|SSQ_PRINT_SENSE; 342739213Sgibbs 342874840Sken if (sense_key == SSD_KEY_RECOVERED_ERROR) { 342974840Sken /* 343074840Sken * The action succeeded but the device wants 343174840Sken * the user to know that some recovery action 343274840Sken * was required. 343374840Sken */ 343474840Sken action &= ~(SS_MASK|SSQ_MASK|SS_ERRMASK); 343574840Sken action |= SS_NOP|SSQ_PRINT_SENSE; 343674840Sken } else if (sense_key == SSD_KEY_ILLEGAL_REQUEST) { 343774840Sken if ((sense_flags & SF_QUIET_IR) != 0) 343874840Sken action &= ~SSQ_PRINT_SENSE; 343974840Sken } else if (sense_key == SSD_KEY_UNIT_ATTENTION) { 344074840Sken if ((sense_flags & SF_RETRY_UA) != 0 344174840Sken && (action & SS_MASK) == SS_FAIL) { 344274840Sken action &= ~(SS_MASK|SSQ_MASK); 344374840Sken action |= SS_RETRY|SSQ_DECREMENT_COUNT| 344474840Sken SSQ_PRINT_SENSE; 344539213Sgibbs } 3446253322Smav action |= SSQ_UA; 344739213Sgibbs } 344839213Sgibbs } 3449245647Skan if ((action & SS_MASK) >= SS_START && 3450245647Skan (sense_flags & SF_NO_RECOVERY)) { 3451245647Skan action &= ~SS_MASK; 3452245647Skan action |= SS_FAIL; 3453245647Skan } else if ((action & SS_MASK) == SS_RETRY && 3454245647Skan (sense_flags & SF_NO_RETRY)) { 3455245647Skan action &= ~SS_MASK; 3456245647Skan action |= SS_FAIL; 3457245647Skan } 345874840Sken if ((sense_flags & SF_PRINT_ALWAYS) != 0) 345974840Sken action |= SSQ_PRINT_SENSE; 346074840Sken else if ((sense_flags & SF_NO_PRINT) != 0) 346174840Sken action &= ~SSQ_PRINT_SENSE; 346274840Sken 346374840Sken return (action); 346439213Sgibbs} 346539213Sgibbs 346639213Sgibbschar * 346740401Skenscsi_cdb_string(u_int8_t *cdb_ptr, char *cdb_string, size_t len) 346839213Sgibbs{ 3469298093Sscottl struct sbuf sb; 3470298093Sscottl int error; 3471298093Sscottl 3472298093Sscottl if (len == 0) 3473298093Sscottl return (""); 3474298093Sscottl 3475298093Sscottl sbuf_new(&sb, cdb_string, len, SBUF_FIXEDLEN); 3476298093Sscottl 3477298093Sscottl scsi_cdb_sbuf(cdb_ptr, &sb); 3478298093Sscottl 3479298093Sscottl /* ENOMEM just means that the fixed buffer is full, OK to ignore */ 3480298093Sscottl error = sbuf_finish(&sb); 3481298093Sscottl if (error != 0 && error != ENOMEM) 3482298093Sscottl return (""); 3483298093Sscottl 3484298093Sscottl return(sbuf_data(&sb)); 3485298093Sscottl} 3486298093Sscottl 3487298093Sscottlvoid 3488298093Sscottlscsi_cdb_sbuf(u_int8_t *cdb_ptr, struct sbuf *sb) 3489298093Sscottl{ 349039213Sgibbs u_int8_t cdb_len; 349139213Sgibbs int i; 349239213Sgibbs 349339213Sgibbs if (cdb_ptr == NULL) 3494298093Sscottl return; 349539213Sgibbs 349639213Sgibbs /* 349739213Sgibbs * This is taken from the SCSI-3 draft spec. 349839213Sgibbs * (T10/1157D revision 0.3) 349939213Sgibbs * The top 3 bits of an opcode are the group code. The next 5 bits 350039213Sgibbs * are the command code. 350139213Sgibbs * Group 0: six byte commands 350239213Sgibbs * Group 1: ten byte commands 350339213Sgibbs * Group 2: ten byte commands 350439213Sgibbs * Group 3: reserved 350539213Sgibbs * Group 4: sixteen byte commands 350639213Sgibbs * Group 5: twelve byte commands 350739213Sgibbs * Group 6: vendor specific 350839213Sgibbs * Group 7: vendor specific 350939213Sgibbs */ 351039213Sgibbs switch((*cdb_ptr >> 5) & 0x7) { 351139213Sgibbs case 0: 351239213Sgibbs cdb_len = 6; 351339213Sgibbs break; 351439213Sgibbs case 1: 351539213Sgibbs case 2: 351639213Sgibbs cdb_len = 10; 351739213Sgibbs break; 351839213Sgibbs case 3: 351939213Sgibbs case 6: 352039213Sgibbs case 7: 352139213Sgibbs /* in this case, just print out the opcode */ 352239213Sgibbs cdb_len = 1; 352339213Sgibbs break; 352439213Sgibbs case 4: 352539213Sgibbs cdb_len = 16; 352639213Sgibbs break; 352739213Sgibbs case 5: 352839213Sgibbs cdb_len = 12; 352939213Sgibbs break; 353039213Sgibbs } 3531298093Sscottl 353241514Sarchie for (i = 0; i < cdb_len; i++) 3533298093Sscottl sbuf_printf(sb, "%02hhx ", cdb_ptr[i]); 353440401Sken 3535298093Sscottl return; 353639213Sgibbs} 353774840Sken 353874840Skenconst char * 353974840Skenscsi_status_string(struct ccb_scsiio *csio) 354074840Sken{ 354174840Sken switch(csio->scsi_status) { 354274840Sken case SCSI_STATUS_OK: 354374840Sken return("OK"); 354474840Sken case SCSI_STATUS_CHECK_COND: 354574840Sken return("Check Condition"); 354674840Sken case SCSI_STATUS_BUSY: 354774840Sken return("Busy"); 354874840Sken case SCSI_STATUS_INTERMED: 354974840Sken return("Intermediate"); 355074840Sken case SCSI_STATUS_INTERMED_COND_MET: 355174840Sken return("Intermediate-Condition Met"); 355274840Sken case SCSI_STATUS_RESERV_CONFLICT: 355374840Sken return("Reservation Conflict"); 355474840Sken case SCSI_STATUS_CMD_TERMINATED: 355574840Sken return("Command Terminated"); 355674840Sken case SCSI_STATUS_QUEUE_FULL: 355774840Sken return("Queue Full"); 355874840Sken case SCSI_STATUS_ACA_ACTIVE: 355974840Sken return("ACA Active"); 356074840Sken case SCSI_STATUS_TASK_ABORTED: 356174840Sken return("Task Aborted"); 356274840Sken default: { 356374840Sken static char unkstr[64]; 356474840Sken snprintf(unkstr, sizeof(unkstr), "Unknown %#x", 356574840Sken csio->scsi_status); 356674840Sken return(unkstr); 356774840Sken } 356874840Sken } 356974840Sken} 357074840Sken 357139213Sgibbs/* 357274840Sken * scsi_command_string() returns 0 for success and -1 for failure. 357339213Sgibbs */ 357455205Speter#ifdef _KERNEL 357574840Skenint 357674840Skenscsi_command_string(struct ccb_scsiio *csio, struct sbuf *sb) 357774840Sken#else /* !_KERNEL */ 357874840Skenint 357974840Skenscsi_command_string(struct cam_device *device, struct ccb_scsiio *csio, 358074840Sken struct sbuf *sb) 358174840Sken#endif /* _KERNEL/!_KERNEL */ 358239213Sgibbs{ 358374840Sken struct scsi_inquiry_data *inq_data; 358474840Sken#ifdef _KERNEL 3585203108Smav struct ccb_getdev *cgd; 358674840Sken#endif /* _KERNEL */ 358739213Sgibbs 358874840Sken#ifdef _KERNEL 3589203108Smav if ((cgd = (struct ccb_getdev*)xpt_alloc_ccb_nowait()) == NULL) 3590203108Smav return(-1); 359139213Sgibbs /* 359239213Sgibbs * Get the device information. 359339213Sgibbs */ 3594203108Smav xpt_setup_ccb(&cgd->ccb_h, 359539213Sgibbs csio->ccb_h.path, 3596198382Smav CAM_PRIORITY_NORMAL); 3597203108Smav cgd->ccb_h.func_code = XPT_GDEV_TYPE; 3598203108Smav xpt_action((union ccb *)cgd); 359939213Sgibbs 360039213Sgibbs /* 360139213Sgibbs * If the device is unconfigured, just pretend that it is a hard 360239213Sgibbs * drive. scsi_op_desc() needs this. 360339213Sgibbs */ 3604203108Smav if (cgd->ccb_h.status == CAM_DEV_NOT_THERE) 3605203108Smav cgd->inq_data.device = T_DIRECT; 360639213Sgibbs 3607203108Smav inq_data = &cgd->inq_data; 360839213Sgibbs 360974840Sken#else /* !_KERNEL */ 361039213Sgibbs 361174840Sken inq_data = &device->inq_data; 361239213Sgibbs 361374840Sken#endif /* _KERNEL/!_KERNEL */ 361474840Sken 3615312845Smav sbuf_printf(sb, "%s. CDB: ", 3616312845Smav scsi_op_desc(scsiio_cdb_ptr(csio)[0], inq_data)); 3617312845Smav scsi_cdb_sbuf(scsiio_cdb_ptr(csio), sb); 361839213Sgibbs 3619236689Sken#ifdef _KERNEL 3620236689Sken xpt_free_ccb((union ccb *)cgd); 3621236689Sken#endif 3622236689Sken 362374840Sken return(0); 362474840Sken} 362539213Sgibbs 3626225950Sken/* 3627225950Sken * Iterate over sense descriptors. Each descriptor is passed into iter_func(). 3628225950Sken * If iter_func() returns 0, list traversal continues. If iter_func() 3629225950Sken * returns non-zero, list traversal is stopped. 3630225950Sken */ 3631225950Skenvoid 3632225950Skenscsi_desc_iterate(struct scsi_sense_data_desc *sense, u_int sense_len, 3633225950Sken int (*iter_func)(struct scsi_sense_data_desc *sense, 3634225950Sken u_int, struct scsi_sense_desc_header *, 3635225950Sken void *), void *arg) 3636225950Sken{ 3637225950Sken int cur_pos; 3638225950Sken int desc_len; 363939213Sgibbs 3640225950Sken /* 3641225950Sken * First make sure the extra length field is present. 3642225950Sken */ 3643225950Sken if (SSD_DESC_IS_PRESENT(sense, sense_len, extra_len) == 0) 3644225950Sken return; 3645225950Sken 3646225950Sken /* 3647225950Sken * The length of data actually returned may be different than the 3648311402Smav * extra_len recorded in the structure. 3649225950Sken */ 3650225950Sken desc_len = sense_len -offsetof(struct scsi_sense_data_desc, sense_desc); 3651225950Sken 3652225950Sken /* 3653225950Sken * Limit this further by the extra length reported, and the maximum 3654225950Sken * allowed extra length. 3655225950Sken */ 3656225950Sken desc_len = MIN(desc_len, MIN(sense->extra_len, SSD_EXTRA_MAX)); 3657225950Sken 3658225950Sken /* 3659225950Sken * Subtract the size of the header from the descriptor length. 3660225950Sken * This is to ensure that we have at least the header left, so we 3661225950Sken * don't have to check that inside the loop. This can wind up 3662225950Sken * being a negative value. 3663225950Sken */ 3664225950Sken desc_len -= sizeof(struct scsi_sense_desc_header); 3665225950Sken 3666225950Sken for (cur_pos = 0; cur_pos < desc_len;) { 3667225950Sken struct scsi_sense_desc_header *header; 3668225950Sken 3669225950Sken header = (struct scsi_sense_desc_header *) 3670225950Sken &sense->sense_desc[cur_pos]; 3671225950Sken 3672225950Sken /* 3673225950Sken * Check to make sure we have the entire descriptor. We 3674225950Sken * don't call iter_func() unless we do. 3675225950Sken * 3676225950Sken * Note that although cur_pos is at the beginning of the 3677225950Sken * descriptor, desc_len already has the header length 3678225950Sken * subtracted. So the comparison of the length in the 3679225950Sken * header (which does not include the header itself) to 3680225950Sken * desc_len - cur_pos is correct. 3681225950Sken */ 3682225950Sken if (header->length > (desc_len - cur_pos)) 3683225950Sken break; 3684225950Sken 3685225950Sken if (iter_func(sense, sense_len, header, arg) != 0) 3686225950Sken break; 3687225950Sken 3688225950Sken cur_pos += sizeof(*header) + header->length; 3689225950Sken } 3690225950Sken} 3691225950Sken 3692225950Skenstruct scsi_find_desc_info { 3693225950Sken uint8_t desc_type; 3694225950Sken struct scsi_sense_desc_header *header; 3695225950Sken}; 3696225950Sken 3697225950Skenstatic int 3698225950Skenscsi_find_desc_func(struct scsi_sense_data_desc *sense, u_int sense_len, 3699225950Sken struct scsi_sense_desc_header *header, void *arg) 3700225950Sken{ 3701225950Sken struct scsi_find_desc_info *desc_info; 3702225950Sken 3703225950Sken desc_info = (struct scsi_find_desc_info *)arg; 3704225950Sken 3705225950Sken if (header->desc_type == desc_info->desc_type) { 3706225950Sken desc_info->header = header; 3707225950Sken 3708225950Sken /* We found the descriptor, tell the iterator to stop. */ 3709225950Sken return (1); 3710225950Sken } else 3711225950Sken return (0); 3712225950Sken} 3713225950Sken 371474840Sken/* 3715225950Sken * Given a descriptor type, return a pointer to it if it is in the sense 3716225950Sken * data and not truncated. Avoiding truncating sense data will simplify 3717225950Sken * things significantly for the caller. 3718225950Sken */ 3719225950Skenuint8_t * 3720225950Skenscsi_find_desc(struct scsi_sense_data_desc *sense, u_int sense_len, 3721225950Sken uint8_t desc_type) 3722225950Sken{ 3723225950Sken struct scsi_find_desc_info desc_info; 3724225950Sken 3725225950Sken desc_info.desc_type = desc_type; 3726225950Sken desc_info.header = NULL; 3727225950Sken 3728225950Sken scsi_desc_iterate(sense, sense_len, scsi_find_desc_func, &desc_info); 3729225950Sken 3730225950Sken return ((uint8_t *)desc_info.header); 3731225950Sken} 3732225950Sken 3733225950Sken/* 3734311440Smav * Fill in SCSI descriptor sense data with the specified parameters. 3735225950Sken */ 3736311440Smavstatic void 3737311440Smavscsi_set_sense_data_desc_va(struct scsi_sense_data *sense_data, 3738311440Smav u_int *sense_len, scsi_sense_data_type sense_format, int current_error, 3739311440Smav int sense_key, int asc, int ascq, va_list ap) 3740225950Sken{ 3741311440Smav struct scsi_sense_data_desc *sense; 3742225950Sken scsi_sense_elem_type elem_type; 3743311440Smav int space, len; 3744311440Smav uint8_t *desc, *data; 3745225950Sken 3746311440Smav memset(sense_data, 0, sizeof(*sense_data)); 3747311440Smav sense = (struct scsi_sense_data_desc *)sense_data; 3748311440Smav if (current_error != 0) 3749311440Smav sense->error_code = SSD_DESC_CURRENT_ERROR; 3750225950Sken else 3751311440Smav sense->error_code = SSD_DESC_DEFERRED_ERROR; 3752311440Smav sense->sense_key = sense_key; 3753311440Smav sense->add_sense_code = asc; 3754311440Smav sense->add_sense_code_qual = ascq; 3755311440Smav sense->flags = 0; 3756225950Sken 3757311440Smav desc = &sense->sense_desc[0]; 3758311440Smav space = *sense_len - offsetof(struct scsi_sense_data_desc, sense_desc); 3759311440Smav while ((elem_type = va_arg(ap, scsi_sense_elem_type)) != 3760311440Smav SSD_ELEM_NONE) { 3761311440Smav if (elem_type >= SSD_ELEM_MAX) { 3762311440Smav printf("%s: invalid sense type %d\n", __func__, 3763311440Smav elem_type); 3764311440Smav break; 3765311440Smav } 3766311440Smav len = va_arg(ap, int); 3767311440Smav data = va_arg(ap, uint8_t *); 3768225950Sken 3769311440Smav switch (elem_type) { 3770311440Smav case SSD_ELEM_SKIP: 3771311440Smav break; 3772311440Smav case SSD_ELEM_DESC: 3773311440Smav if (space < len) { 3774311440Smav sense->flags |= SSDD_SDAT_OVFL; 3775225950Sken break; 3776225950Sken } 3777311440Smav bcopy(data, desc, len); 3778311440Smav desc += len; 3779311440Smav space -= len; 3780311440Smav break; 3781311440Smav case SSD_ELEM_SKS: { 3782311440Smav struct scsi_sense_sks *sks = (void *)desc; 3783225950Sken 3784311440Smav if (len > sizeof(sks->sense_key_spec)) 3785225950Sken break; 3786311440Smav if (space < sizeof(*sks)) { 3787311440Smav sense->flags |= SSDD_SDAT_OVFL; 3788311440Smav break; 3789225950Sken } 3790311440Smav sks->desc_type = SSD_DESC_SKS; 3791311440Smav sks->length = sizeof(*sks) - 3792311440Smav (offsetof(struct scsi_sense_sks, length) + 1); 3793311440Smav bcopy(data, &sks->sense_key_spec, len); 3794311440Smav desc += sizeof(*sks); 3795311440Smav space -= sizeof(*sks); 3796311440Smav break; 3797311440Smav } 3798311440Smav case SSD_ELEM_COMMAND: { 3799311440Smav struct scsi_sense_command *cmd = (void *)desc; 3800225950Sken 3801311440Smav if (len > sizeof(cmd->command_info)) 3802225950Sken break; 3803311440Smav if (space < sizeof(*cmd)) { 3804311440Smav sense->flags |= SSDD_SDAT_OVFL; 3805311440Smav break; 3806225950Sken } 3807311440Smav cmd->desc_type = SSD_DESC_COMMAND; 3808311440Smav cmd->length = sizeof(*cmd) - 3809311440Smav (offsetof(struct scsi_sense_command, length) + 1); 3810311440Smav bcopy(data, &cmd->command_info[ 3811311440Smav sizeof(cmd->command_info) - len], len); 3812311440Smav desc += sizeof(*cmd); 3813311440Smav space -= sizeof(*cmd); 3814311440Smav break; 3815311440Smav } 3816311440Smav case SSD_ELEM_INFO: { 3817311440Smav struct scsi_sense_info *info = (void *)desc; 3818225950Sken 3819311440Smav if (len > sizeof(info->info)) 3820225950Sken break; 3821311440Smav if (space < sizeof(*info)) { 3822311440Smav sense->flags |= SSDD_SDAT_OVFL; 3823311440Smav break; 3824225950Sken } 3825311440Smav info->desc_type = SSD_DESC_INFO; 3826311440Smav info->length = sizeof(*info) - 3827311440Smav (offsetof(struct scsi_sense_info, length) + 1); 3828311440Smav info->byte2 = SSD_INFO_VALID; 3829311440Smav bcopy(data, &info->info[sizeof(info->info) - len], len); 3830311440Smav desc += sizeof(*info); 3831311440Smav space -= sizeof(*info); 3832311440Smav break; 3833311440Smav } 3834311440Smav case SSD_ELEM_FRU: { 3835311440Smav struct scsi_sense_fru *fru = (void *)desc; 3836225950Sken 3837311440Smav if (len > sizeof(fru->fru)) 3838225950Sken break; 3839311440Smav if (space < sizeof(*fru)) { 3840311440Smav sense->flags |= SSDD_SDAT_OVFL; 3841311440Smav break; 3842225950Sken } 3843311440Smav fru->desc_type = SSD_DESC_FRU; 3844311440Smav fru->length = sizeof(*fru) - 3845311440Smav (offsetof(struct scsi_sense_fru, length) + 1); 3846311440Smav fru->fru = *data; 3847311440Smav desc += sizeof(*fru); 3848311440Smav space -= sizeof(*fru); 3849311440Smav break; 3850311440Smav } 3851311440Smav case SSD_ELEM_STREAM: { 3852311440Smav struct scsi_sense_stream *stream = (void *)desc; 3853225950Sken 3854311440Smav if (len > sizeof(stream->byte3)) 3855225950Sken break; 3856311440Smav if (space < sizeof(*stream)) { 3857311440Smav sense->flags |= SSDD_SDAT_OVFL; 3858225950Sken break; 3859225950Sken } 3860311440Smav stream->desc_type = SSD_DESC_STREAM; 3861311440Smav stream->length = sizeof(*stream) - 3862311440Smav (offsetof(struct scsi_sense_stream, length) + 1); 3863311440Smav stream->byte3 = *data; 3864311440Smav desc += sizeof(*stream); 3865311440Smav space -= sizeof(*stream); 3866311440Smav break; 3867225950Sken } 3868311440Smav default: 3869311440Smav /* 3870311440Smav * We shouldn't get here, but if we do, do nothing. 3871311440Smav * We've already consumed the arguments above. 3872311440Smav */ 3873311440Smav break; 3874311440Smav } 3875311440Smav } 3876311440Smav sense->extra_len = desc - &sense->sense_desc[0]; 3877311440Smav *sense_len = offsetof(struct scsi_sense_data_desc, extra_len) + 1 + 3878311440Smav sense->extra_len; 3879311440Smav} 3880225950Sken 3881311440Smav/* 3882311440Smav * Fill in SCSI fixed sense data with the specified parameters. 3883311440Smav */ 3884311440Smavstatic void 3885311440Smavscsi_set_sense_data_fixed_va(struct scsi_sense_data *sense_data, 3886311440Smav u_int *sense_len, scsi_sense_data_type sense_format, int current_error, 3887311440Smav int sense_key, int asc, int ascq, va_list ap) 3888311440Smav{ 3889311440Smav struct scsi_sense_data_fixed *sense; 3890311440Smav scsi_sense_elem_type elem_type; 3891311440Smav uint8_t *data; 3892311440Smav int len; 3893225950Sken 3894311440Smav memset(sense_data, 0, sizeof(*sense_data)); 3895311440Smav sense = (struct scsi_sense_data_fixed *)sense_data; 3896311440Smav if (current_error != 0) 3897311440Smav sense->error_code = SSD_CURRENT_ERROR; 3898311440Smav else 3899311440Smav sense->error_code = SSD_DEFERRED_ERROR; 3900311440Smav sense->flags = sense_key & SSD_KEY; 3901311440Smav sense->extra_len = 0; 3902311440Smav if (*sense_len >= 13) { 3903225950Sken sense->add_sense_code = asc; 3904311440Smav sense->extra_len = MAX(sense->extra_len, 5); 3905311440Smav } else 3906311440Smav sense->flags |= SSD_SDAT_OVFL; 3907311440Smav if (*sense_len >= 14) { 3908225950Sken sense->add_sense_code_qual = ascq; 3909311440Smav sense->extra_len = MAX(sense->extra_len, 6); 3910311440Smav } else 3911311440Smav sense->flags |= SSD_SDAT_OVFL; 3912225950Sken 3913311440Smav while ((elem_type = va_arg(ap, scsi_sense_elem_type)) != 3914311440Smav SSD_ELEM_NONE) { 3915311440Smav if (elem_type >= SSD_ELEM_MAX) { 3916311440Smav printf("%s: invalid sense type %d\n", __func__, 3917311440Smav elem_type); 3918311440Smav break; 3919311440Smav } 3920311440Smav len = va_arg(ap, int); 3921311440Smav data = va_arg(ap, uint8_t *); 3922225950Sken 3923311440Smav switch (elem_type) { 3924311440Smav case SSD_ELEM_SKIP: 3925311440Smav break; 3926311440Smav case SSD_ELEM_SKS: 3927311440Smav if (len > sizeof(sense->sense_key_spec)) 3928225950Sken break; 3929311440Smav if (*sense_len < 18) { 3930311440Smav sense->flags |= SSD_SDAT_OVFL; 3931311440Smav break; 3932225950Sken } 3933311440Smav bcopy(data, &sense->sense_key_spec[0], len); 3934311440Smav sense->extra_len = MAX(sense->extra_len, 10); 3935311440Smav break; 3936311440Smav case SSD_ELEM_COMMAND: 3937311440Smav if (*sense_len < 12) { 3938311440Smav sense->flags |= SSD_SDAT_OVFL; 3939225950Sken break; 3940311440Smav } 3941311440Smav if (len > sizeof(sense->cmd_spec_info)) { 3942311440Smav data += len - sizeof(sense->cmd_spec_info); 3943311440Smav len -= len - sizeof(sense->cmd_spec_info); 3944311440Smav } 3945311440Smav bcopy(data, &sense->cmd_spec_info[ 3946311440Smav sizeof(sense->cmd_spec_info) - len], len); 3947311440Smav sense->extra_len = MAX(sense->extra_len, 4); 3948311440Smav break; 3949311440Smav case SSD_ELEM_INFO: 3950311440Smav /* Set VALID bit only if no overflow. */ 3951311440Smav sense->error_code |= SSD_ERRCODE_VALID; 3952311440Smav while (len > sizeof(sense->info)) { 3953311440Smav if (data[0] != 0) 3954311440Smav sense->error_code &= ~SSD_ERRCODE_VALID; 3955311440Smav data ++; 3956311440Smav len --; 3957311440Smav } 3958311440Smav bcopy(data, &sense->info[sizeof(sense->info) - len], len); 3959311440Smav break; 3960311440Smav case SSD_ELEM_FRU: 3961311440Smav if (*sense_len < 15) { 3962311440Smav sense->flags |= SSD_SDAT_OVFL; 3963225950Sken break; 3964225950Sken } 3965311440Smav sense->fru = *data; 3966311440Smav sense->extra_len = MAX(sense->extra_len, 7); 3967311440Smav break; 3968311440Smav case SSD_ELEM_STREAM: 3969311440Smav sense->flags |= *data & 3970311440Smav (SSD_ILI | SSD_EOM | SSD_FILEMARK); 3971311440Smav break; 3972311440Smav default: 3973225950Sken 3974311440Smav /* 3975311440Smav * We can't handle that in fixed format. Skip it. 3976311440Smav */ 3977311440Smav break; 3978225950Sken } 3979225950Sken } 3980311440Smav *sense_len = offsetof(struct scsi_sense_data_fixed, extra_len) + 1 + 3981311440Smav sense->extra_len; 3982225950Sken} 3983225950Sken 3984311440Smav/* 3985311440Smav * Fill in SCSI sense data with the specified parameters. This routine can 3986311440Smav * fill in either fixed or descriptor type sense data. 3987311440Smav */ 3988225950Skenvoid 3989311440Smavscsi_set_sense_data_va(struct scsi_sense_data *sense_data, u_int *sense_len, 3990311440Smav scsi_sense_data_type sense_format, int current_error, 3991311440Smav int sense_key, int asc, int ascq, va_list ap) 3992311440Smav{ 3993311440Smav 3994311440Smav if (*sense_len > SSD_FULL_SIZE) 3995311440Smav *sense_len = SSD_FULL_SIZE; 3996311440Smav if (sense_format == SSD_TYPE_DESC) 3997311440Smav scsi_set_sense_data_desc_va(sense_data, sense_len, 3998311440Smav sense_format, current_error, sense_key, asc, ascq, ap); 3999311440Smav else 4000311440Smav scsi_set_sense_data_fixed_va(sense_data, sense_len, 4001311440Smav sense_format, current_error, sense_key, asc, ascq, ap); 4002311440Smav} 4003311440Smav 4004311440Smavvoid 4005311440Smavscsi_set_sense_data(struct scsi_sense_data *sense_data, 4006225950Sken scsi_sense_data_type sense_format, int current_error, 4007311440Smav int sense_key, int asc, int ascq, ...) 4008225950Sken{ 4009225950Sken va_list ap; 4010311440Smav u_int sense_len = SSD_FULL_SIZE; 4011225950Sken 4012225950Sken va_start(ap, ascq); 4013311440Smav scsi_set_sense_data_va(sense_data, &sense_len, sense_format, 4014311440Smav current_error, sense_key, asc, ascq, ap); 4015225950Sken va_end(ap); 4016225950Sken} 4017225950Sken 4018311440Smavvoid 4019311440Smavscsi_set_sense_data_len(struct scsi_sense_data *sense_data, u_int *sense_len, 4020311440Smav scsi_sense_data_type sense_format, int current_error, 4021311440Smav int sense_key, int asc, int ascq, ...) 4022311440Smav{ 4023311440Smav va_list ap; 4024311440Smav 4025311440Smav va_start(ap, ascq); 4026311440Smav scsi_set_sense_data_va(sense_data, sense_len, sense_format, 4027311440Smav current_error, sense_key, asc, ascq, ap); 4028311440Smav va_end(ap); 4029311440Smav} 4030311440Smav 4031225950Sken/* 4032225950Sken * Get sense information for three similar sense data types. 4033225950Sken */ 4034225950Skenint 4035225950Skenscsi_get_sense_info(struct scsi_sense_data *sense_data, u_int sense_len, 4036225950Sken uint8_t info_type, uint64_t *info, int64_t *signed_info) 4037225950Sken{ 4038225950Sken scsi_sense_data_type sense_type; 4039225950Sken 4040225950Sken if (sense_len == 0) 4041225950Sken goto bailout; 4042225950Sken 4043225950Sken sense_type = scsi_sense_type(sense_data); 4044225950Sken 4045225950Sken switch (sense_type) { 4046225950Sken case SSD_TYPE_DESC: { 4047225950Sken struct scsi_sense_data_desc *sense; 4048225950Sken uint8_t *desc; 4049225950Sken 4050225950Sken sense = (struct scsi_sense_data_desc *)sense_data; 4051225950Sken 4052225950Sken desc = scsi_find_desc(sense, sense_len, info_type); 4053225950Sken if (desc == NULL) 4054225950Sken goto bailout; 4055225950Sken 4056225950Sken switch (info_type) { 4057225950Sken case SSD_DESC_INFO: { 4058225950Sken struct scsi_sense_info *info_desc; 4059225950Sken 4060225950Sken info_desc = (struct scsi_sense_info *)desc; 4061225950Sken *info = scsi_8btou64(info_desc->info); 4062225950Sken if (signed_info != NULL) 4063225950Sken *signed_info = *info; 4064225950Sken break; 4065225950Sken } 4066225950Sken case SSD_DESC_COMMAND: { 4067225950Sken struct scsi_sense_command *cmd_desc; 4068225950Sken 4069225950Sken cmd_desc = (struct scsi_sense_command *)desc; 4070225950Sken 4071225950Sken *info = scsi_8btou64(cmd_desc->command_info); 4072225950Sken if (signed_info != NULL) 4073225950Sken *signed_info = *info; 4074225950Sken break; 4075225950Sken } 4076225950Sken case SSD_DESC_FRU: { 4077225950Sken struct scsi_sense_fru *fru_desc; 4078225950Sken 4079225950Sken fru_desc = (struct scsi_sense_fru *)desc; 4080225950Sken 4081225950Sken *info = fru_desc->fru; 4082225950Sken if (signed_info != NULL) 4083225950Sken *signed_info = (int8_t)fru_desc->fru; 4084225950Sken break; 4085225950Sken } 4086225950Sken default: 4087225950Sken goto bailout; 4088225950Sken break; 4089225950Sken } 4090225950Sken break; 4091225950Sken } 4092225950Sken case SSD_TYPE_FIXED: { 4093225950Sken struct scsi_sense_data_fixed *sense; 4094225950Sken 4095225950Sken sense = (struct scsi_sense_data_fixed *)sense_data; 4096225950Sken 4097225950Sken switch (info_type) { 4098225950Sken case SSD_DESC_INFO: { 4099225950Sken uint32_t info_val; 4100225950Sken 4101225950Sken if ((sense->error_code & SSD_ERRCODE_VALID) == 0) 4102225950Sken goto bailout; 4103225950Sken 4104225950Sken if (SSD_FIXED_IS_PRESENT(sense, sense_len, info) == 0) 4105225950Sken goto bailout; 4106225950Sken 4107225950Sken info_val = scsi_4btoul(sense->info); 4108225950Sken 4109225950Sken *info = info_val; 4110225950Sken if (signed_info != NULL) 4111225950Sken *signed_info = (int32_t)info_val; 4112225950Sken break; 4113225950Sken } 4114225950Sken case SSD_DESC_COMMAND: { 4115225950Sken uint32_t cmd_val; 4116225950Sken 4117225950Sken if ((SSD_FIXED_IS_PRESENT(sense, sense_len, 4118225950Sken cmd_spec_info) == 0) 4119225950Sken || (SSD_FIXED_IS_FILLED(sense, cmd_spec_info) == 0)) 4120225950Sken goto bailout; 4121225950Sken 4122225950Sken cmd_val = scsi_4btoul(sense->cmd_spec_info); 4123225950Sken if (cmd_val == 0) 4124225950Sken goto bailout; 4125225950Sken 4126225950Sken *info = cmd_val; 4127225950Sken if (signed_info != NULL) 4128225950Sken *signed_info = (int32_t)cmd_val; 4129225950Sken break; 4130225950Sken } 4131225950Sken case SSD_DESC_FRU: 4132225950Sken if ((SSD_FIXED_IS_PRESENT(sense, sense_len, fru) == 0) 4133225950Sken || (SSD_FIXED_IS_FILLED(sense, fru) == 0)) 4134225950Sken goto bailout; 4135225950Sken 4136225950Sken if (sense->fru == 0) 4137225950Sken goto bailout; 4138225950Sken 4139225950Sken *info = sense->fru; 4140225950Sken if (signed_info != NULL) 4141225950Sken *signed_info = (int8_t)sense->fru; 4142225950Sken break; 4143225950Sken default: 4144225950Sken goto bailout; 4145225950Sken break; 4146225950Sken } 4147225950Sken break; 4148225950Sken } 4149225950Sken default: 4150225950Sken goto bailout; 4151225950Sken break; 4152225950Sken } 4153225950Sken 4154225950Sken return (0); 4155225950Skenbailout: 4156225950Sken return (1); 4157225950Sken} 4158225950Sken 4159225950Skenint 4160225950Skenscsi_get_sks(struct scsi_sense_data *sense_data, u_int sense_len, uint8_t *sks) 4161225950Sken{ 4162225950Sken scsi_sense_data_type sense_type; 4163225950Sken 4164225950Sken if (sense_len == 0) 4165225950Sken goto bailout; 4166225950Sken 4167225950Sken sense_type = scsi_sense_type(sense_data); 4168225950Sken 4169225950Sken switch (sense_type) { 4170225950Sken case SSD_TYPE_DESC: { 4171225950Sken struct scsi_sense_data_desc *sense; 4172225950Sken struct scsi_sense_sks *desc; 4173225950Sken 4174225950Sken sense = (struct scsi_sense_data_desc *)sense_data; 4175225950Sken 4176225950Sken desc = (struct scsi_sense_sks *)scsi_find_desc(sense, sense_len, 4177225950Sken SSD_DESC_SKS); 4178225950Sken if (desc == NULL) 4179225950Sken goto bailout; 4180225950Sken 4181225950Sken /* 4182225950Sken * No need to check the SKS valid bit for descriptor sense. 4183225950Sken * If the descriptor is present, it is valid. 4184225950Sken */ 4185225950Sken bcopy(desc->sense_key_spec, sks, sizeof(desc->sense_key_spec)); 4186225950Sken break; 4187225950Sken } 4188225950Sken case SSD_TYPE_FIXED: { 4189225950Sken struct scsi_sense_data_fixed *sense; 4190225950Sken 4191225950Sken sense = (struct scsi_sense_data_fixed *)sense_data; 4192225950Sken 4193225950Sken if ((SSD_FIXED_IS_PRESENT(sense, sense_len, sense_key_spec)== 0) 4194225950Sken || (SSD_FIXED_IS_FILLED(sense, sense_key_spec) == 0)) 4195225950Sken goto bailout; 4196225950Sken 4197225950Sken if ((sense->sense_key_spec[0] & SSD_SCS_VALID) == 0) 4198225950Sken goto bailout; 4199225950Sken 4200225950Sken bcopy(sense->sense_key_spec, sks,sizeof(sense->sense_key_spec)); 4201225950Sken break; 4202225950Sken } 4203225950Sken default: 4204225950Sken goto bailout; 4205225950Sken break; 4206225950Sken } 4207225950Sken return (0); 4208225950Skenbailout: 4209225950Sken return (1); 4210225950Sken} 4211225950Sken 4212225950Sken/* 4213225950Sken * Provide a common interface for fixed and descriptor sense to detect 4214225950Sken * whether we have block-specific sense information. It is clear by the 4215225950Sken * presence of the block descriptor in descriptor mode, but we have to 4216225950Sken * infer from the inquiry data and ILI bit in fixed mode. 4217225950Sken */ 4218225950Skenint 4219225950Skenscsi_get_block_info(struct scsi_sense_data *sense_data, u_int sense_len, 4220225950Sken struct scsi_inquiry_data *inq_data, uint8_t *block_bits) 4221225950Sken{ 4222225950Sken scsi_sense_data_type sense_type; 4223225950Sken 4224225950Sken if (inq_data != NULL) { 4225225950Sken switch (SID_TYPE(inq_data)) { 4226225950Sken case T_DIRECT: 4227225950Sken case T_RBC: 4228225950Sken break; 4229225950Sken default: 4230225950Sken goto bailout; 4231225950Sken break; 4232225950Sken } 4233225950Sken } 4234225950Sken 4235225950Sken sense_type = scsi_sense_type(sense_data); 4236225950Sken 4237225950Sken switch (sense_type) { 4238225950Sken case SSD_TYPE_DESC: { 4239225950Sken struct scsi_sense_data_desc *sense; 4240225950Sken struct scsi_sense_block *block; 4241225950Sken 4242225950Sken sense = (struct scsi_sense_data_desc *)sense_data; 4243225950Sken 4244225950Sken block = (struct scsi_sense_block *)scsi_find_desc(sense, 4245225950Sken sense_len, SSD_DESC_BLOCK); 4246225950Sken if (block == NULL) 4247225950Sken goto bailout; 4248225950Sken 4249225950Sken *block_bits = block->byte3; 4250225950Sken break; 4251225950Sken } 4252225950Sken case SSD_TYPE_FIXED: { 4253225950Sken struct scsi_sense_data_fixed *sense; 4254225950Sken 4255225950Sken sense = (struct scsi_sense_data_fixed *)sense_data; 4256225950Sken 4257225950Sken if (SSD_FIXED_IS_PRESENT(sense, sense_len, flags) == 0) 4258225950Sken goto bailout; 4259225950Sken 4260225950Sken if ((sense->flags & SSD_ILI) == 0) 4261225950Sken goto bailout; 4262225950Sken 4263225950Sken *block_bits = sense->flags & SSD_ILI; 4264225950Sken break; 4265225950Sken } 4266225950Sken default: 4267225950Sken goto bailout; 4268225950Sken break; 4269225950Sken } 4270225950Sken return (0); 4271225950Skenbailout: 4272225950Sken return (1); 4273225950Sken} 4274225950Sken 4275225950Skenint 4276225950Skenscsi_get_stream_info(struct scsi_sense_data *sense_data, u_int sense_len, 4277225950Sken struct scsi_inquiry_data *inq_data, uint8_t *stream_bits) 4278225950Sken{ 4279225950Sken scsi_sense_data_type sense_type; 4280225950Sken 4281225950Sken if (inq_data != NULL) { 4282225950Sken switch (SID_TYPE(inq_data)) { 4283225950Sken case T_SEQUENTIAL: 4284225950Sken break; 4285225950Sken default: 4286225950Sken goto bailout; 4287225950Sken break; 4288225950Sken } 4289225950Sken } 4290225950Sken 4291225950Sken sense_type = scsi_sense_type(sense_data); 4292225950Sken 4293225950Sken switch (sense_type) { 4294225950Sken case SSD_TYPE_DESC: { 4295225950Sken struct scsi_sense_data_desc *sense; 4296225950Sken struct scsi_sense_stream *stream; 4297225950Sken 4298225950Sken sense = (struct scsi_sense_data_desc *)sense_data; 4299225950Sken 4300225950Sken stream = (struct scsi_sense_stream *)scsi_find_desc(sense, 4301225950Sken sense_len, SSD_DESC_STREAM); 4302225950Sken if (stream == NULL) 4303225950Sken goto bailout; 4304225950Sken 4305225950Sken *stream_bits = stream->byte3; 4306225950Sken break; 4307225950Sken } 4308225950Sken case SSD_TYPE_FIXED: { 4309225950Sken struct scsi_sense_data_fixed *sense; 4310225950Sken 4311225950Sken sense = (struct scsi_sense_data_fixed *)sense_data; 4312225950Sken 4313225950Sken if (SSD_FIXED_IS_PRESENT(sense, sense_len, flags) == 0) 4314225950Sken goto bailout; 4315225950Sken 4316225950Sken if ((sense->flags & (SSD_ILI|SSD_EOM|SSD_FILEMARK)) == 0) 4317225950Sken goto bailout; 4318225950Sken 4319225950Sken *stream_bits = sense->flags & (SSD_ILI|SSD_EOM|SSD_FILEMARK); 4320225950Sken break; 4321225950Sken } 4322225950Sken default: 4323225950Sken goto bailout; 4324225950Sken break; 4325225950Sken } 4326225950Sken return (0); 4327225950Skenbailout: 4328225950Sken return (1); 4329225950Sken} 4330225950Sken 4331225950Skenvoid 4332225950Skenscsi_info_sbuf(struct sbuf *sb, uint8_t *cdb, int cdb_len, 4333225950Sken struct scsi_inquiry_data *inq_data, uint64_t info) 4334225950Sken{ 4335225950Sken sbuf_printf(sb, "Info: %#jx", info); 4336225950Sken} 4337225950Sken 4338225950Skenvoid 4339225950Skenscsi_command_sbuf(struct sbuf *sb, uint8_t *cdb, int cdb_len, 4340225950Sken struct scsi_inquiry_data *inq_data, uint64_t csi) 4341225950Sken{ 4342225950Sken sbuf_printf(sb, "Command Specific Info: %#jx", csi); 4343225950Sken} 4344225950Sken 4345225950Sken 4346225950Skenvoid 4347225950Skenscsi_progress_sbuf(struct sbuf *sb, uint16_t progress) 4348225950Sken{ 4349225950Sken sbuf_printf(sb, "Progress: %d%% (%d/%d) complete", 4350225950Sken (progress * 100) / SSD_SKS_PROGRESS_DENOM, 4351225950Sken progress, SSD_SKS_PROGRESS_DENOM); 4352225950Sken} 4353225950Sken 4354225950Sken/* 4355225950Sken * Returns 1 for failure (i.e. SKS isn't valid) and 0 for success. 4356225950Sken */ 4357225950Skenint 4358225950Skenscsi_sks_sbuf(struct sbuf *sb, int sense_key, uint8_t *sks) 4359225950Sken{ 4360225950Sken if ((sks[0] & SSD_SKS_VALID) == 0) 4361225950Sken return (1); 4362225950Sken 4363225950Sken switch (sense_key) { 4364225950Sken case SSD_KEY_ILLEGAL_REQUEST: { 4365225950Sken struct scsi_sense_sks_field *field; 4366225950Sken int bad_command; 4367225950Sken char tmpstr[40]; 4368225950Sken 4369225950Sken /*Field Pointer*/ 4370225950Sken field = (struct scsi_sense_sks_field *)sks; 4371225950Sken 4372225950Sken if (field->byte0 & SSD_SKS_FIELD_CMD) 4373225950Sken bad_command = 1; 4374225950Sken else 4375225950Sken bad_command = 0; 4376225950Sken 4377225950Sken tmpstr[0] = '\0'; 4378225950Sken 4379225950Sken /* Bit pointer is valid */ 4380225950Sken if (field->byte0 & SSD_SKS_BPV) 4381225950Sken snprintf(tmpstr, sizeof(tmpstr), "bit %d ", 4382225950Sken field->byte0 & SSD_SKS_BIT_VALUE); 4383225950Sken 4384225950Sken sbuf_printf(sb, "%s byte %d %sis invalid", 4385225950Sken bad_command ? "Command" : "Data", 4386225950Sken scsi_2btoul(field->field), tmpstr); 4387225950Sken break; 4388225950Sken } 4389225950Sken case SSD_KEY_UNIT_ATTENTION: { 4390225950Sken struct scsi_sense_sks_overflow *overflow; 4391225950Sken 4392225950Sken overflow = (struct scsi_sense_sks_overflow *)sks; 4393225950Sken 4394225950Sken /*UA Condition Queue Overflow*/ 4395225950Sken sbuf_printf(sb, "Unit Attention Condition Queue %s", 4396225950Sken (overflow->byte0 & SSD_SKS_OVERFLOW_SET) ? 4397225950Sken "Overflowed" : "Did Not Overflow??"); 4398225950Sken break; 4399225950Sken } 4400225950Sken case SSD_KEY_RECOVERED_ERROR: 4401225950Sken case SSD_KEY_HARDWARE_ERROR: 4402225950Sken case SSD_KEY_MEDIUM_ERROR: { 4403225950Sken struct scsi_sense_sks_retry *retry; 4404225950Sken 4405225950Sken /*Actual Retry Count*/ 4406225950Sken retry = (struct scsi_sense_sks_retry *)sks; 4407225950Sken 4408225950Sken sbuf_printf(sb, "Actual Retry Count: %d", 4409225950Sken scsi_2btoul(retry->actual_retry_count)); 4410225950Sken break; 4411225950Sken } 4412225950Sken case SSD_KEY_NO_SENSE: 4413225950Sken case SSD_KEY_NOT_READY: { 4414225950Sken struct scsi_sense_sks_progress *progress; 4415225950Sken int progress_val; 4416225950Sken 4417225950Sken /*Progress Indication*/ 4418225950Sken progress = (struct scsi_sense_sks_progress *)sks; 4419225950Sken progress_val = scsi_2btoul(progress->progress); 4420225950Sken 4421225950Sken scsi_progress_sbuf(sb, progress_val); 4422225950Sken break; 4423225950Sken } 4424225950Sken case SSD_KEY_COPY_ABORTED: { 4425225950Sken struct scsi_sense_sks_segment *segment; 4426225950Sken char tmpstr[40]; 4427225950Sken 4428225950Sken /*Segment Pointer*/ 4429225950Sken segment = (struct scsi_sense_sks_segment *)sks; 4430225950Sken 4431225950Sken tmpstr[0] = '\0'; 4432225950Sken 4433225950Sken if (segment->byte0 & SSD_SKS_SEGMENT_BPV) 4434225950Sken snprintf(tmpstr, sizeof(tmpstr), "bit %d ", 4435225950Sken segment->byte0 & SSD_SKS_SEGMENT_BITPTR); 4436225950Sken 4437225950Sken sbuf_printf(sb, "%s byte %d %sis invalid", (segment->byte0 & 4438225950Sken SSD_SKS_SEGMENT_SD) ? "Segment" : "Data", 4439225950Sken scsi_2btoul(segment->field), tmpstr); 4440225950Sken break; 4441225950Sken } 4442225950Sken default: 4443225950Sken sbuf_printf(sb, "Sense Key Specific: %#x,%#x", sks[0], 4444225950Sken scsi_2btoul(&sks[1])); 4445225950Sken break; 4446225950Sken } 4447225950Sken 4448225950Sken return (0); 4449225950Sken} 4450225950Sken 4451225950Skenvoid 4452225950Skenscsi_fru_sbuf(struct sbuf *sb, uint64_t fru) 4453225950Sken{ 4454225950Sken sbuf_printf(sb, "Field Replaceable Unit: %d", (int)fru); 4455225950Sken} 4456225950Sken 4457225950Skenvoid 4458225950Skenscsi_stream_sbuf(struct sbuf *sb, uint8_t stream_bits, uint64_t info) 4459225950Sken{ 4460225950Sken int need_comma; 4461225950Sken 4462225950Sken need_comma = 0; 4463225950Sken /* 4464225950Sken * XXX KDM this needs more descriptive decoding. 4465225950Sken */ 4466225950Sken if (stream_bits & SSD_DESC_STREAM_FM) { 4467225950Sken sbuf_printf(sb, "Filemark"); 4468225950Sken need_comma = 1; 4469225950Sken } 4470225950Sken 4471225950Sken if (stream_bits & SSD_DESC_STREAM_EOM) { 4472225950Sken sbuf_printf(sb, "%sEOM", (need_comma) ? "," : ""); 4473225950Sken need_comma = 1; 4474225950Sken } 4475225950Sken 4476225950Sken if (stream_bits & SSD_DESC_STREAM_ILI) 4477225950Sken sbuf_printf(sb, "%sILI", (need_comma) ? "," : ""); 4478225950Sken 4479225950Sken sbuf_printf(sb, ": Info: %#jx", (uintmax_t) info); 4480225950Sken} 4481225950Sken 4482225950Skenvoid 4483225950Skenscsi_block_sbuf(struct sbuf *sb, uint8_t block_bits, uint64_t info) 4484225950Sken{ 4485225950Sken if (block_bits & SSD_DESC_BLOCK_ILI) 4486225950Sken sbuf_printf(sb, "ILI: residue %#jx", (uintmax_t) info); 4487225950Sken} 4488225950Sken 4489225950Skenvoid 4490225950Skenscsi_sense_info_sbuf(struct sbuf *sb, struct scsi_sense_data *sense, 4491225950Sken u_int sense_len, uint8_t *cdb, int cdb_len, 4492225950Sken struct scsi_inquiry_data *inq_data, 4493225950Sken struct scsi_sense_desc_header *header) 4494225950Sken{ 4495225950Sken struct scsi_sense_info *info; 4496225950Sken 4497225950Sken info = (struct scsi_sense_info *)header; 4498225950Sken 4499225950Sken scsi_info_sbuf(sb, cdb, cdb_len, inq_data, scsi_8btou64(info->info)); 4500225950Sken} 4501225950Sken 4502225950Skenvoid 4503225950Skenscsi_sense_command_sbuf(struct sbuf *sb, struct scsi_sense_data *sense, 4504225950Sken u_int sense_len, uint8_t *cdb, int cdb_len, 4505225950Sken struct scsi_inquiry_data *inq_data, 4506225950Sken struct scsi_sense_desc_header *header) 4507225950Sken{ 4508225950Sken struct scsi_sense_command *command; 4509225950Sken 4510225950Sken command = (struct scsi_sense_command *)header; 4511225950Sken 4512225950Sken scsi_command_sbuf(sb, cdb, cdb_len, inq_data, 4513225950Sken scsi_8btou64(command->command_info)); 4514225950Sken} 4515225950Sken 4516225950Skenvoid 4517225950Skenscsi_sense_sks_sbuf(struct sbuf *sb, struct scsi_sense_data *sense, 4518225950Sken u_int sense_len, uint8_t *cdb, int cdb_len, 4519225950Sken struct scsi_inquiry_data *inq_data, 4520225950Sken struct scsi_sense_desc_header *header) 4521225950Sken{ 4522225950Sken struct scsi_sense_sks *sks; 4523225950Sken int error_code, sense_key, asc, ascq; 4524225950Sken 4525225950Sken sks = (struct scsi_sense_sks *)header; 4526225950Sken 4527225950Sken scsi_extract_sense_len(sense, sense_len, &error_code, &sense_key, 4528225950Sken &asc, &ascq, /*show_errors*/ 1); 4529225950Sken 4530225950Sken scsi_sks_sbuf(sb, sense_key, sks->sense_key_spec); 4531225950Sken} 4532225950Sken 4533225950Skenvoid 4534225950Skenscsi_sense_fru_sbuf(struct sbuf *sb, struct scsi_sense_data *sense, 4535225950Sken u_int sense_len, uint8_t *cdb, int cdb_len, 4536225950Sken struct scsi_inquiry_data *inq_data, 4537225950Sken struct scsi_sense_desc_header *header) 4538225950Sken{ 4539225950Sken struct scsi_sense_fru *fru; 4540225950Sken 4541225950Sken fru = (struct scsi_sense_fru *)header; 4542225950Sken 4543225950Sken scsi_fru_sbuf(sb, (uint64_t)fru->fru); 4544225950Sken} 4545225950Sken 4546225950Skenvoid 4547225950Skenscsi_sense_stream_sbuf(struct sbuf *sb, struct scsi_sense_data *sense, 4548225950Sken u_int sense_len, uint8_t *cdb, int cdb_len, 4549225950Sken struct scsi_inquiry_data *inq_data, 4550225950Sken struct scsi_sense_desc_header *header) 4551225950Sken{ 4552225950Sken struct scsi_sense_stream *stream; 4553225950Sken uint64_t info; 4554225950Sken 4555225950Sken stream = (struct scsi_sense_stream *)header; 4556225950Sken info = 0; 4557225950Sken 4558225950Sken scsi_get_sense_info(sense, sense_len, SSD_DESC_INFO, &info, NULL); 4559225950Sken 4560225950Sken scsi_stream_sbuf(sb, stream->byte3, info); 4561225950Sken} 4562225950Sken 4563225950Skenvoid 4564225950Skenscsi_sense_block_sbuf(struct sbuf *sb, struct scsi_sense_data *sense, 4565225950Sken u_int sense_len, uint8_t *cdb, int cdb_len, 4566225950Sken struct scsi_inquiry_data *inq_data, 4567225950Sken struct scsi_sense_desc_header *header) 4568225950Sken{ 4569225950Sken struct scsi_sense_block *block; 4570225950Sken uint64_t info; 4571225950Sken 4572225950Sken block = (struct scsi_sense_block *)header; 4573225950Sken info = 0; 4574225950Sken 4575225950Sken scsi_get_sense_info(sense, sense_len, SSD_DESC_INFO, &info, NULL); 4576225950Sken 4577225950Sken scsi_block_sbuf(sb, block->byte3, info); 4578225950Sken} 4579225950Sken 4580225950Skenvoid 4581225950Skenscsi_sense_progress_sbuf(struct sbuf *sb, struct scsi_sense_data *sense, 4582225950Sken u_int sense_len, uint8_t *cdb, int cdb_len, 4583225950Sken struct scsi_inquiry_data *inq_data, 4584225950Sken struct scsi_sense_desc_header *header) 4585225950Sken{ 4586225950Sken struct scsi_sense_progress *progress; 4587225950Sken const char *sense_key_desc; 4588225950Sken const char *asc_desc; 4589225950Sken int progress_val; 4590225950Sken 4591225950Sken progress = (struct scsi_sense_progress *)header; 4592225950Sken 4593225950Sken /* 4594225950Sken * Get descriptions for the sense key, ASC, and ASCQ in the 4595225950Sken * progress descriptor. These could be different than the values 4596225950Sken * in the overall sense data. 4597225950Sken */ 4598225950Sken scsi_sense_desc(progress->sense_key, progress->add_sense_code, 4599225950Sken progress->add_sense_code_qual, inq_data, 4600225950Sken &sense_key_desc, &asc_desc); 4601225950Sken 4602225950Sken progress_val = scsi_2btoul(progress->progress); 4603225950Sken 4604225950Sken /* 4605225950Sken * The progress indicator is for the operation described by the 4606225950Sken * sense key, ASC, and ASCQ in the descriptor. 4607225950Sken */ 4608225950Sken sbuf_cat(sb, sense_key_desc); 4609225950Sken sbuf_printf(sb, " asc:%x,%x (%s): ", progress->add_sense_code, 4610225950Sken progress->add_sense_code_qual, asc_desc); 4611225950Sken scsi_progress_sbuf(sb, progress_val); 4612225950Sken} 4613225950Sken 4614311438Smavvoid 4615311444Smavscsi_sense_ata_sbuf(struct sbuf *sb, struct scsi_sense_data *sense, 4616311444Smav u_int sense_len, uint8_t *cdb, int cdb_len, 4617311444Smav struct scsi_inquiry_data *inq_data, 4618311444Smav struct scsi_sense_desc_header *header) 4619311444Smav{ 4620311444Smav struct scsi_sense_ata_ret_desc *res; 4621311444Smav 4622311444Smav res = (struct scsi_sense_ata_ret_desc *)header; 4623311444Smav 4624311444Smav sbuf_printf(sb, "ATA status: %02x (%s%s%s%s%s%s%s%s), ", 4625311444Smav res->status, 4626311444Smav (res->status & 0x80) ? "BSY " : "", 4627311444Smav (res->status & 0x40) ? "DRDY " : "", 4628311444Smav (res->status & 0x20) ? "DF " : "", 4629311444Smav (res->status & 0x10) ? "SERV " : "", 4630311444Smav (res->status & 0x08) ? "DRQ " : "", 4631311444Smav (res->status & 0x04) ? "CORR " : "", 4632311444Smav (res->status & 0x02) ? "IDX " : "", 4633311444Smav (res->status & 0x01) ? "ERR" : ""); 4634311444Smav if (res->status & 1) { 4635311444Smav sbuf_printf(sb, "error: %02x (%s%s%s%s%s%s%s%s), ", 4636311444Smav res->error, 4637311444Smav (res->error & 0x80) ? "ICRC " : "", 4638311444Smav (res->error & 0x40) ? "UNC " : "", 4639311444Smav (res->error & 0x20) ? "MC " : "", 4640311444Smav (res->error & 0x10) ? "IDNF " : "", 4641311444Smav (res->error & 0x08) ? "MCR " : "", 4642311444Smav (res->error & 0x04) ? "ABRT " : "", 4643311444Smav (res->error & 0x02) ? "NM " : "", 4644311444Smav (res->error & 0x01) ? "ILI" : ""); 4645311444Smav } 4646311444Smav 4647311444Smav if (res->flags & SSD_DESC_ATA_FLAG_EXTEND) { 4648311444Smav sbuf_printf(sb, "count: %02x%02x, ", 4649311444Smav res->count_15_8, res->count_7_0); 4650311444Smav sbuf_printf(sb, "LBA: %02x%02x%02x%02x%02x%02x, ", 4651311444Smav res->lba_47_40, res->lba_39_32, res->lba_31_24, 4652311444Smav res->lba_23_16, res->lba_15_8, res->lba_7_0); 4653311444Smav } else { 4654311444Smav sbuf_printf(sb, "count: %02x, ", res->count_7_0); 4655311444Smav sbuf_printf(sb, "LBA: %02x%02x%02x, ", 4656311444Smav res->lba_23_16, res->lba_15_8, res->lba_7_0); 4657311444Smav } 4658311444Smav sbuf_printf(sb, "device: %02x, ", res->device); 4659311444Smav} 4660311444Smav 4661311444Smavvoid 4662311438Smavscsi_sense_forwarded_sbuf(struct sbuf *sb, struct scsi_sense_data *sense, 4663311438Smav u_int sense_len, uint8_t *cdb, int cdb_len, 4664311438Smav struct scsi_inquiry_data *inq_data, 4665311438Smav struct scsi_sense_desc_header *header) 4666311438Smav{ 4667311438Smav struct scsi_sense_forwarded *forwarded; 4668311438Smav const char *sense_key_desc; 4669311438Smav const char *asc_desc; 4670311438Smav int error_code, sense_key, asc, ascq; 4671311438Smav 4672311438Smav forwarded = (struct scsi_sense_forwarded *)header; 4673311438Smav scsi_extract_sense_len((struct scsi_sense_data *)forwarded->sense_data, 4674311438Smav forwarded->length - 2, &error_code, &sense_key, &asc, &ascq, 1); 4675311438Smav scsi_sense_desc(sense_key, asc, ascq, NULL, &sense_key_desc, &asc_desc); 4676311438Smav 4677311438Smav sbuf_printf(sb, "Forwarded sense: %s asc:%x,%x (%s): ", 4678311438Smav sense_key_desc, asc, ascq, asc_desc); 4679311438Smav} 4680311438Smav 4681225950Sken/* 4682225950Sken * Generic sense descriptor printing routine. This is used when we have 4683225950Sken * not yet implemented a specific printing routine for this descriptor. 4684225950Sken */ 4685225950Skenvoid 4686225950Skenscsi_sense_generic_sbuf(struct sbuf *sb, struct scsi_sense_data *sense, 4687225950Sken u_int sense_len, uint8_t *cdb, int cdb_len, 4688225950Sken struct scsi_inquiry_data *inq_data, 4689225950Sken struct scsi_sense_desc_header *header) 4690225950Sken{ 4691225950Sken int i; 4692225950Sken uint8_t *buf_ptr; 4693225950Sken 4694225950Sken sbuf_printf(sb, "Descriptor %#x:", header->desc_type); 4695225950Sken 4696225950Sken buf_ptr = (uint8_t *)&header[1]; 4697225950Sken 4698225950Sken for (i = 0; i < header->length; i++, buf_ptr++) 4699225950Sken sbuf_printf(sb, " %02x", *buf_ptr); 4700225950Sken} 4701225950Sken 4702225950Sken/* 4703225950Sken * Keep this list in numeric order. This speeds the array traversal. 4704225950Sken */ 4705225950Skenstruct scsi_sense_desc_printer { 4706225950Sken uint8_t desc_type; 4707225950Sken /* 4708225950Sken * The function arguments here are the superset of what is needed 4709225950Sken * to print out various different descriptors. Command and 4710225950Sken * information descriptors need inquiry data and command type. 4711225950Sken * Sense key specific descriptors need the sense key. 4712225950Sken * 4713225950Sken * The sense, cdb, and inquiry data arguments may be NULL, but the 4714225950Sken * information printed may not be fully decoded as a result. 4715225950Sken */ 4716225950Sken void (*print_func)(struct sbuf *sb, struct scsi_sense_data *sense, 4717225950Sken u_int sense_len, uint8_t *cdb, int cdb_len, 4718225950Sken struct scsi_inquiry_data *inq_data, 4719225950Sken struct scsi_sense_desc_header *header); 4720225950Sken} scsi_sense_printers[] = { 4721225950Sken {SSD_DESC_INFO, scsi_sense_info_sbuf}, 4722225950Sken {SSD_DESC_COMMAND, scsi_sense_command_sbuf}, 4723225950Sken {SSD_DESC_SKS, scsi_sense_sks_sbuf}, 4724225950Sken {SSD_DESC_FRU, scsi_sense_fru_sbuf}, 4725225950Sken {SSD_DESC_STREAM, scsi_sense_stream_sbuf}, 4726225950Sken {SSD_DESC_BLOCK, scsi_sense_block_sbuf}, 4727311444Smav {SSD_DESC_ATA, scsi_sense_ata_sbuf}, 4728311438Smav {SSD_DESC_PROGRESS, scsi_sense_progress_sbuf}, 4729311438Smav {SSD_DESC_FORWARDED, scsi_sense_forwarded_sbuf} 4730225950Sken}; 4731225950Sken 4732225950Skenvoid 4733225950Skenscsi_sense_desc_sbuf(struct sbuf *sb, struct scsi_sense_data *sense, 4734225950Sken u_int sense_len, uint8_t *cdb, int cdb_len, 4735225950Sken struct scsi_inquiry_data *inq_data, 4736225950Sken struct scsi_sense_desc_header *header) 4737225950Sken{ 4738238200Seadler int i; 4739225950Sken 4740238200Seadler for (i = 0; i < (sizeof(scsi_sense_printers) / 4741225950Sken sizeof(scsi_sense_printers[0])); i++) { 4742225950Sken struct scsi_sense_desc_printer *printer; 4743225950Sken 4744225950Sken printer = &scsi_sense_printers[i]; 4745225950Sken 4746225950Sken /* 4747225950Sken * The list is sorted, so quit if we've passed our 4748225950Sken * descriptor number. 4749225950Sken */ 4750225950Sken if (printer->desc_type > header->desc_type) 4751225950Sken break; 4752225950Sken 4753225950Sken if (printer->desc_type != header->desc_type) 4754225950Sken continue; 4755225950Sken 4756225950Sken printer->print_func(sb, sense, sense_len, cdb, cdb_len, 4757225950Sken inq_data, header); 4758225950Sken 4759225950Sken return; 4760225950Sken } 4761225950Sken 4762225950Sken /* 4763225950Sken * No specific printing routine, so use the generic routine. 4764225950Sken */ 4765225950Sken scsi_sense_generic_sbuf(sb, sense, sense_len, cdb, cdb_len, 4766225950Sken inq_data, header); 4767225950Sken} 4768225950Sken 4769225950Skenscsi_sense_data_type 4770225950Skenscsi_sense_type(struct scsi_sense_data *sense_data) 4771225950Sken{ 4772225950Sken switch (sense_data->error_code & SSD_ERRCODE) { 4773225950Sken case SSD_DESC_CURRENT_ERROR: 4774225950Sken case SSD_DESC_DEFERRED_ERROR: 4775225950Sken return (SSD_TYPE_DESC); 4776225950Sken break; 4777225950Sken case SSD_CURRENT_ERROR: 4778225950Sken case SSD_DEFERRED_ERROR: 4779225950Sken return (SSD_TYPE_FIXED); 4780225950Sken break; 4781225950Sken default: 4782225950Sken break; 4783225950Sken } 4784225950Sken 4785225950Sken return (SSD_TYPE_NONE); 4786225950Sken} 4787225950Sken 4788225950Skenstruct scsi_print_sense_info { 4789225950Sken struct sbuf *sb; 4790225950Sken char *path_str; 4791225950Sken uint8_t *cdb; 4792225950Sken int cdb_len; 4793225950Sken struct scsi_inquiry_data *inq_data; 4794225950Sken}; 4795225950Sken 4796225950Skenstatic int 4797225950Skenscsi_print_desc_func(struct scsi_sense_data_desc *sense, u_int sense_len, 4798225950Sken struct scsi_sense_desc_header *header, void *arg) 4799225950Sken{ 4800225950Sken struct scsi_print_sense_info *print_info; 4801225950Sken 4802225950Sken print_info = (struct scsi_print_sense_info *)arg; 4803225950Sken 4804225950Sken switch (header->desc_type) { 4805225950Sken case SSD_DESC_INFO: 4806225950Sken case SSD_DESC_FRU: 4807225950Sken case SSD_DESC_COMMAND: 4808225950Sken case SSD_DESC_SKS: 4809225950Sken case SSD_DESC_BLOCK: 4810225950Sken case SSD_DESC_STREAM: 4811225950Sken /* 4812225950Sken * We have already printed these descriptors, if they are 4813225950Sken * present. 4814225950Sken */ 4815225950Sken break; 4816225950Sken default: { 4817225950Sken sbuf_printf(print_info->sb, "%s", print_info->path_str); 4818225950Sken scsi_sense_desc_sbuf(print_info->sb, 4819225950Sken (struct scsi_sense_data *)sense, sense_len, 4820225950Sken print_info->cdb, print_info->cdb_len, 4821225950Sken print_info->inq_data, header); 4822225950Sken sbuf_printf(print_info->sb, "\n"); 4823225950Sken break; 4824225950Sken } 4825225950Sken } 4826225950Sken 4827225950Sken /* 4828225950Sken * Tell the iterator that we want to see more descriptors if they 4829225950Sken * are present. 4830225950Sken */ 4831225950Sken return (0); 4832225950Sken} 4833225950Sken 4834225950Skenvoid 4835225950Skenscsi_sense_only_sbuf(struct scsi_sense_data *sense, u_int sense_len, 4836225950Sken struct sbuf *sb, char *path_str, 4837225950Sken struct scsi_inquiry_data *inq_data, uint8_t *cdb, 4838225950Sken int cdb_len) 4839225950Sken{ 4840225950Sken int error_code, sense_key, asc, ascq; 4841225950Sken 4842225950Sken sbuf_cat(sb, path_str); 4843225950Sken 4844225950Sken scsi_extract_sense_len(sense, sense_len, &error_code, &sense_key, 4845225950Sken &asc, &ascq, /*show_errors*/ 1); 4846225950Sken 4847225950Sken sbuf_printf(sb, "SCSI sense: "); 4848225950Sken switch (error_code) { 4849225950Sken case SSD_DEFERRED_ERROR: 4850225950Sken case SSD_DESC_DEFERRED_ERROR: 4851225950Sken sbuf_printf(sb, "Deferred error: "); 4852225950Sken 4853225950Sken /* FALLTHROUGH */ 4854225950Sken case SSD_CURRENT_ERROR: 4855225950Sken case SSD_DESC_CURRENT_ERROR: 4856225950Sken { 4857225950Sken struct scsi_sense_data_desc *desc_sense; 4858225950Sken struct scsi_print_sense_info print_info; 4859225950Sken const char *sense_key_desc; 4860225950Sken const char *asc_desc; 4861225950Sken uint8_t sks[3]; 4862225950Sken uint64_t val; 4863225950Sken int info_valid; 4864225950Sken 4865225950Sken /* 4866225950Sken * Get descriptions for the sense key, ASC, and ASCQ. If 4867225950Sken * these aren't present in the sense data (i.e. the sense 4868225950Sken * data isn't long enough), the -1 values that 4869225950Sken * scsi_extract_sense_len() returns will yield default 4870225950Sken * or error descriptions. 4871225950Sken */ 4872225950Sken scsi_sense_desc(sense_key, asc, ascq, inq_data, 4873225950Sken &sense_key_desc, &asc_desc); 4874225950Sken 4875225950Sken /* 4876225950Sken * We first print the sense key and ASC/ASCQ. 4877225950Sken */ 4878225950Sken sbuf_cat(sb, sense_key_desc); 4879225950Sken sbuf_printf(sb, " asc:%x,%x (%s)\n", asc, ascq, asc_desc); 4880225950Sken 4881225950Sken /* 4882225950Sken * Get the info field if it is valid. 4883225950Sken */ 4884225950Sken if (scsi_get_sense_info(sense, sense_len, SSD_DESC_INFO, 4885225950Sken &val, NULL) == 0) 4886225950Sken info_valid = 1; 4887225950Sken else 4888225950Sken info_valid = 0; 4889225950Sken 4890225950Sken if (info_valid != 0) { 4891225950Sken uint8_t bits; 4892225950Sken 4893225950Sken /* 4894225950Sken * Determine whether we have any block or stream 4895225950Sken * device-specific information. 4896225950Sken */ 4897225950Sken if (scsi_get_block_info(sense, sense_len, inq_data, 4898225950Sken &bits) == 0) { 4899225950Sken sbuf_cat(sb, path_str); 4900225950Sken scsi_block_sbuf(sb, bits, val); 4901225950Sken sbuf_printf(sb, "\n"); 4902225950Sken } else if (scsi_get_stream_info(sense, sense_len, 4903225950Sken inq_data, &bits) == 0) { 4904225950Sken sbuf_cat(sb, path_str); 4905225950Sken scsi_stream_sbuf(sb, bits, val); 4906225950Sken sbuf_printf(sb, "\n"); 4907225950Sken } else if (val != 0) { 4908225950Sken /* 4909225950Sken * The information field can be valid but 0. 4910225950Sken * If the block or stream bits aren't set, 4911225950Sken * and this is 0, it isn't terribly useful 4912225950Sken * to print it out. 4913225950Sken */ 4914225950Sken sbuf_cat(sb, path_str); 4915225950Sken scsi_info_sbuf(sb, cdb, cdb_len, inq_data, val); 4916225950Sken sbuf_printf(sb, "\n"); 4917225950Sken } 4918225950Sken } 4919225950Sken 4920225950Sken /* 4921225950Sken * Print the FRU. 4922225950Sken */ 4923225950Sken if (scsi_get_sense_info(sense, sense_len, SSD_DESC_FRU, 4924225950Sken &val, NULL) == 0) { 4925225950Sken sbuf_cat(sb, path_str); 4926225950Sken scsi_fru_sbuf(sb, val); 4927225950Sken sbuf_printf(sb, "\n"); 4928225950Sken } 4929225950Sken 4930225950Sken /* 4931225950Sken * Print any command-specific information. 4932225950Sken */ 4933225950Sken if (scsi_get_sense_info(sense, sense_len, SSD_DESC_COMMAND, 4934225950Sken &val, NULL) == 0) { 4935225950Sken sbuf_cat(sb, path_str); 4936225950Sken scsi_command_sbuf(sb, cdb, cdb_len, inq_data, val); 4937225950Sken sbuf_printf(sb, "\n"); 4938225950Sken } 4939225950Sken 4940225950Sken /* 4941225950Sken * Print out any sense-key-specific information. 4942225950Sken */ 4943225950Sken if (scsi_get_sks(sense, sense_len, sks) == 0) { 4944225950Sken sbuf_cat(sb, path_str); 4945225950Sken scsi_sks_sbuf(sb, sense_key, sks); 4946225950Sken sbuf_printf(sb, "\n"); 4947225950Sken } 4948225950Sken 4949225950Sken /* 4950225950Sken * If this is fixed sense, we're done. If we have 4951225950Sken * descriptor sense, we might have more information 4952225950Sken * available. 4953225950Sken */ 4954225950Sken if (scsi_sense_type(sense) != SSD_TYPE_DESC) 4955225950Sken break; 4956225950Sken 4957225950Sken desc_sense = (struct scsi_sense_data_desc *)sense; 4958225950Sken 4959225950Sken print_info.sb = sb; 4960225950Sken print_info.path_str = path_str; 4961225950Sken print_info.cdb = cdb; 4962225950Sken print_info.cdb_len = cdb_len; 4963225950Sken print_info.inq_data = inq_data; 4964225950Sken 4965225950Sken /* 4966225950Sken * Print any sense descriptors that we have not already printed. 4967225950Sken */ 4968225950Sken scsi_desc_iterate(desc_sense, sense_len, scsi_print_desc_func, 4969225950Sken &print_info); 4970225950Sken break; 4971225950Sken 4972225950Sken } 4973225950Sken case -1: 4974225950Sken /* 4975225950Sken * scsi_extract_sense_len() sets values to -1 if the 4976225950Sken * show_errors flag is set and they aren't present in the 4977225950Sken * sense data. This means that sense_len is 0. 4978225950Sken */ 4979225950Sken sbuf_printf(sb, "No sense data present\n"); 4980225950Sken break; 4981225950Sken default: { 4982225950Sken sbuf_printf(sb, "Error code 0x%x", error_code); 4983225950Sken if (sense->error_code & SSD_ERRCODE_VALID) { 4984225950Sken struct scsi_sense_data_fixed *fixed_sense; 4985225950Sken 4986225950Sken fixed_sense = (struct scsi_sense_data_fixed *)sense; 4987225950Sken 4988225950Sken if (SSD_FIXED_IS_PRESENT(fixed_sense, sense_len, info)){ 4989225950Sken uint32_t info; 4990225950Sken 4991225950Sken info = scsi_4btoul(fixed_sense->info); 4992225950Sken 4993225950Sken sbuf_printf(sb, " at block no. %d (decimal)", 4994225950Sken info); 4995225950Sken } 4996225950Sken } 4997225950Sken sbuf_printf(sb, "\n"); 4998225950Sken break; 4999225950Sken } 5000225950Sken } 5001225950Sken} 5002225950Sken 5003225950Sken/* 500474840Sken * scsi_sense_sbuf() returns 0 for success and -1 for failure. 500574840Sken */ 500674840Sken#ifdef _KERNEL 500774840Skenint 500874840Skenscsi_sense_sbuf(struct ccb_scsiio *csio, struct sbuf *sb, 500974840Sken scsi_sense_string_flags flags) 501055205Speter#else /* !_KERNEL */ 501174840Skenint 501274840Skenscsi_sense_sbuf(struct cam_device *device, struct ccb_scsiio *csio, 501374840Sken struct sbuf *sb, scsi_sense_string_flags flags) 501474840Sken#endif /* _KERNEL/!_KERNEL */ 501539213Sgibbs{ 501639213Sgibbs struct scsi_sense_data *sense; 501774840Sken struct scsi_inquiry_data *inq_data; 501874840Sken#ifdef _KERNEL 5019203108Smav struct ccb_getdev *cgd; 502074840Sken#endif /* _KERNEL */ 502139213Sgibbs char path_str[64]; 502239213Sgibbs 502374840Sken#ifndef _KERNEL 502474840Sken if (device == NULL) 502574840Sken return(-1); 502674840Sken#endif /* !_KERNEL */ 502774840Sken if ((csio == NULL) || (sb == NULL)) 502874840Sken return(-1); 502939213Sgibbs 503039213Sgibbs /* 503139213Sgibbs * If the CDB is a physical address, we can't deal with it.. 503239213Sgibbs */ 503339213Sgibbs if ((csio->ccb_h.flags & CAM_CDB_PHYS) != 0) 503474840Sken flags &= ~SSS_FLAG_PRINT_COMMAND; 503539213Sgibbs 503674840Sken#ifdef _KERNEL 503774840Sken xpt_path_string(csio->ccb_h.path, path_str, sizeof(path_str)); 503874840Sken#else /* !_KERNEL */ 503974840Sken cam_path_string(device, path_str, sizeof(path_str)); 504074840Sken#endif /* _KERNEL/!_KERNEL */ 504139213Sgibbs 504274840Sken#ifdef _KERNEL 5043203108Smav if ((cgd = (struct ccb_getdev*)xpt_alloc_ccb_nowait()) == NULL) 5044203108Smav return(-1); 504574840Sken /* 504674840Sken * Get the device information. 504774840Sken */ 5048203108Smav xpt_setup_ccb(&cgd->ccb_h, 504974840Sken csio->ccb_h.path, 5050198382Smav CAM_PRIORITY_NORMAL); 5051203108Smav cgd->ccb_h.func_code = XPT_GDEV_TYPE; 5052203108Smav xpt_action((union ccb *)cgd); 505339213Sgibbs 505474840Sken /* 505574840Sken * If the device is unconfigured, just pretend that it is a hard 505674840Sken * drive. scsi_op_desc() needs this. 505774840Sken */ 5058203108Smav if (cgd->ccb_h.status == CAM_DEV_NOT_THERE) 5059203108Smav cgd->inq_data.device = T_DIRECT; 506039213Sgibbs 5061203108Smav inq_data = &cgd->inq_data; 506239213Sgibbs 506374840Sken#else /* !_KERNEL */ 506439213Sgibbs 506574840Sken inq_data = &device->inq_data; 506640401Sken 506774840Sken#endif /* _KERNEL/!_KERNEL */ 506839213Sgibbs 506974840Sken sense = NULL; 507040401Sken 507174840Sken if (flags & SSS_FLAG_PRINT_COMMAND) { 507240401Sken 507374840Sken sbuf_cat(sb, path_str); 507474840Sken 507574840Sken#ifdef _KERNEL 507674840Sken scsi_command_string(csio, sb); 507774840Sken#else /* !_KERNEL */ 507874840Sken scsi_command_string(device, csio, sb); 507974840Sken#endif /* _KERNEL/!_KERNEL */ 5080111206Sken sbuf_printf(sb, "\n"); 508139213Sgibbs } 508239213Sgibbs 508339213Sgibbs /* 508439213Sgibbs * If the sense data is a physical pointer, forget it. 508539213Sgibbs */ 508639213Sgibbs if (csio->ccb_h.flags & CAM_SENSE_PTR) { 5087203108Smav if (csio->ccb_h.flags & CAM_SENSE_PHYS) { 5088203108Smav#ifdef _KERNEL 5089203108Smav xpt_free_ccb((union ccb*)cgd); 5090203108Smav#endif /* _KERNEL/!_KERNEL */ 509174840Sken return(-1); 5092203108Smav } else { 509339213Sgibbs /* 509474840Sken * bcopy the pointer to avoid unaligned access 509574840Sken * errors on finicky architectures. We don't 509674840Sken * ensure that the sense data is pointer aligned. 509739213Sgibbs */ 5098142159Sscottl bcopy(&csio->sense_data, &sense, 509939213Sgibbs sizeof(struct scsi_sense_data *)); 510039213Sgibbs } 510139213Sgibbs } else { 510239213Sgibbs /* 510339213Sgibbs * If the physical sense flag is set, but the sense pointer 510439213Sgibbs * is not also set, we assume that the user is an idiot and 510539213Sgibbs * return. (Well, okay, it could be that somehow, the 510639213Sgibbs * entire csio is physical, but we would have probably core 510739213Sgibbs * dumped on one of the bogus pointer deferences above 510839213Sgibbs * already.) 510939213Sgibbs */ 5110203108Smav if (csio->ccb_h.flags & CAM_SENSE_PHYS) { 5111203108Smav#ifdef _KERNEL 5112203108Smav xpt_free_ccb((union ccb*)cgd); 5113203108Smav#endif /* _KERNEL/!_KERNEL */ 511474840Sken return(-1); 5115203108Smav } else 511639213Sgibbs sense = &csio->sense_data; 511739213Sgibbs } 511839213Sgibbs 5119312845Smav scsi_sense_only_sbuf(sense, csio->sense_len - csio->sense_resid, sb, 5120312845Smav path_str, inq_data, scsiio_cdb_ptr(csio), csio->cdb_len); 512139213Sgibbs 5122203108Smav#ifdef _KERNEL 5123203108Smav xpt_free_ccb((union ccb*)cgd); 5124203108Smav#endif /* _KERNEL/!_KERNEL */ 512574840Sken return(0); 512674840Sken} 512740401Sken 512839213Sgibbs 512940401Sken 513074840Sken#ifdef _KERNEL 513174840Skenchar * 513274840Skenscsi_sense_string(struct ccb_scsiio *csio, char *str, int str_len) 513374840Sken#else /* !_KERNEL */ 513474840Skenchar * 513574840Skenscsi_sense_string(struct cam_device *device, struct ccb_scsiio *csio, 513674840Sken char *str, int str_len) 513774840Sken#endif /* _KERNEL/!_KERNEL */ 513839213Sgibbs{ 513974840Sken struct sbuf sb; 514039213Sgibbs 514174840Sken sbuf_new(&sb, str, str_len, 0); 514239213Sgibbs 514374840Sken#ifdef _KERNEL 514474840Sken scsi_sense_sbuf(csio, &sb, SSS_FLAG_PRINT_COMMAND); 514574840Sken#else /* !_KERNEL */ 514674840Sken scsi_sense_sbuf(device, csio, &sb, SSS_FLAG_PRINT_COMMAND); 514774840Sken#endif /* _KERNEL/!_KERNEL */ 514874840Sken 514974840Sken sbuf_finish(&sb); 515074840Sken 515174840Sken return(sbuf_data(&sb)); 515239213Sgibbs} 515339213Sgibbs 515455205Speter#ifdef _KERNEL 515574840Skenvoid 515674840Skenscsi_sense_print(struct ccb_scsiio *csio) 515739213Sgibbs{ 515874840Sken struct sbuf sb; 515974840Sken char str[512]; 516039213Sgibbs 516174840Sken sbuf_new(&sb, str, sizeof(str), 0); 516239213Sgibbs 516374840Sken scsi_sense_sbuf(csio, &sb, SSS_FLAG_PRINT_COMMAND); 516439213Sgibbs 516574840Sken sbuf_finish(&sb); 516639213Sgibbs 516774840Sken printf("%s", sbuf_data(&sb)); 516874840Sken} 516939213Sgibbs 517074840Sken#else /* !_KERNEL */ 517174840Skenvoid 517274840Skenscsi_sense_print(struct cam_device *device, struct ccb_scsiio *csio, 517374840Sken FILE *ofile) 517474840Sken{ 517574840Sken struct sbuf sb; 517674840Sken char str[512]; 517739213Sgibbs 517874840Sken if ((device == NULL) || (csio == NULL) || (ofile == NULL)) 517974840Sken return; 518039213Sgibbs 518174840Sken sbuf_new(&sb, str, sizeof(str), 0); 518239213Sgibbs 518374840Sken scsi_sense_sbuf(device, csio, &sb, SSS_FLAG_PRINT_COMMAND); 518439213Sgibbs 518574840Sken sbuf_finish(&sb); 518639213Sgibbs 518774840Sken fprintf(ofile, "%s", sbuf_data(&sb)); 518839213Sgibbs} 518939213Sgibbs 519074840Sken#endif /* _KERNEL/!_KERNEL */ 519174840Sken 519257349Sken/* 5193225950Sken * Extract basic sense information. This is backward-compatible with the 5194225950Sken * previous implementation. For new implementations, 5195225950Sken * scsi_extract_sense_len() is recommended. 5196225950Sken */ 5197225950Skenvoid 5198225950Skenscsi_extract_sense(struct scsi_sense_data *sense_data, int *error_code, 5199225950Sken int *sense_key, int *asc, int *ascq) 5200225950Sken{ 5201225950Sken scsi_extract_sense_len(sense_data, sizeof(*sense_data), error_code, 5202225950Sken sense_key, asc, ascq, /*show_errors*/ 0); 5203225950Sken} 5204225950Sken 5205225950Sken/* 5206237478Smav * Extract basic sense information from SCSI I/O CCB structure. 5207237478Smav */ 5208237478Smavint 5209237478Smavscsi_extract_sense_ccb(union ccb *ccb, 5210237478Smav int *error_code, int *sense_key, int *asc, int *ascq) 5211237478Smav{ 5212237478Smav struct scsi_sense_data *sense_data; 5213237478Smav 5214237478Smav /* Make sure there are some sense data we can access. */ 5215237478Smav if (ccb->ccb_h.func_code != XPT_SCSI_IO || 5216237478Smav (ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_SCSI_STATUS_ERROR || 5217237478Smav (ccb->csio.scsi_status != SCSI_STATUS_CHECK_COND) || 5218237478Smav (ccb->ccb_h.status & CAM_AUTOSNS_VALID) == 0 || 5219237478Smav (ccb->ccb_h.flags & CAM_SENSE_PHYS)) 5220237478Smav return (0); 5221237478Smav 5222237478Smav if (ccb->ccb_h.flags & CAM_SENSE_PTR) 5223237478Smav bcopy(&ccb->csio.sense_data, &sense_data, 5224237478Smav sizeof(struct scsi_sense_data *)); 5225237478Smav else 5226237478Smav sense_data = &ccb->csio.sense_data; 5227237478Smav scsi_extract_sense_len(sense_data, 5228237478Smav ccb->csio.sense_len - ccb->csio.sense_resid, 5229237478Smav error_code, sense_key, asc, ascq, 1); 5230237478Smav if (*error_code == -1) 5231237478Smav return (0); 5232237478Smav return (1); 5233237478Smav} 5234237478Smav 5235237478Smav/* 5236225950Sken * Extract basic sense information. If show_errors is set, sense values 5237225950Sken * will be set to -1 if they are not present. 5238225950Sken */ 5239225950Skenvoid 5240225950Skenscsi_extract_sense_len(struct scsi_sense_data *sense_data, u_int sense_len, 5241225950Sken int *error_code, int *sense_key, int *asc, int *ascq, 5242225950Sken int show_errors) 5243225950Sken{ 5244225950Sken /* 5245225950Sken * If we have no length, we have no sense. 5246225950Sken */ 5247225950Sken if (sense_len == 0) { 5248225950Sken if (show_errors == 0) { 5249225950Sken *error_code = 0; 5250225950Sken *sense_key = 0; 5251225950Sken *asc = 0; 5252225950Sken *ascq = 0; 5253225950Sken } else { 5254225950Sken *error_code = -1; 5255225950Sken *sense_key = -1; 5256225950Sken *asc = -1; 5257225950Sken *ascq = -1; 5258225950Sken } 5259225950Sken return; 5260225950Sken } 5261225950Sken 5262225950Sken *error_code = sense_data->error_code & SSD_ERRCODE; 5263225950Sken 5264225950Sken switch (*error_code) { 5265225950Sken case SSD_DESC_CURRENT_ERROR: 5266225950Sken case SSD_DESC_DEFERRED_ERROR: { 5267225950Sken struct scsi_sense_data_desc *sense; 5268225950Sken 5269225950Sken sense = (struct scsi_sense_data_desc *)sense_data; 5270225950Sken 5271225950Sken if (SSD_DESC_IS_PRESENT(sense, sense_len, sense_key)) 5272225950Sken *sense_key = sense->sense_key & SSD_KEY; 5273225950Sken else 5274225950Sken *sense_key = (show_errors) ? -1 : 0; 5275225950Sken 5276225950Sken if (SSD_DESC_IS_PRESENT(sense, sense_len, add_sense_code)) 5277225950Sken *asc = sense->add_sense_code; 5278225950Sken else 5279225950Sken *asc = (show_errors) ? -1 : 0; 5280225950Sken 5281225950Sken if (SSD_DESC_IS_PRESENT(sense, sense_len, add_sense_code_qual)) 5282225950Sken *ascq = sense->add_sense_code_qual; 5283225950Sken else 5284225950Sken *ascq = (show_errors) ? -1 : 0; 5285225950Sken break; 5286225950Sken } 5287225950Sken case SSD_CURRENT_ERROR: 5288225950Sken case SSD_DEFERRED_ERROR: 5289225950Sken default: { 5290225950Sken struct scsi_sense_data_fixed *sense; 5291225950Sken 5292225950Sken sense = (struct scsi_sense_data_fixed *)sense_data; 5293225950Sken 5294225950Sken if (SSD_FIXED_IS_PRESENT(sense, sense_len, flags)) 5295225950Sken *sense_key = sense->flags & SSD_KEY; 5296225950Sken else 5297225950Sken *sense_key = (show_errors) ? -1 : 0; 5298225950Sken 5299225950Sken if ((SSD_FIXED_IS_PRESENT(sense, sense_len, add_sense_code)) 5300225950Sken && (SSD_FIXED_IS_FILLED(sense, add_sense_code))) 5301225950Sken *asc = sense->add_sense_code; 5302225950Sken else 5303225950Sken *asc = (show_errors) ? -1 : 0; 5304225950Sken 5305225950Sken if ((SSD_FIXED_IS_PRESENT(sense, sense_len,add_sense_code_qual)) 5306225950Sken && (SSD_FIXED_IS_FILLED(sense, add_sense_code_qual))) 5307225950Sken *ascq = sense->add_sense_code_qual; 5308225950Sken else 5309225950Sken *ascq = (show_errors) ? -1 : 0; 5310225950Sken break; 5311225950Sken } 5312225950Sken } 5313225950Sken} 5314225950Sken 5315225950Skenint 5316225950Skenscsi_get_sense_key(struct scsi_sense_data *sense_data, u_int sense_len, 5317225950Sken int show_errors) 5318225950Sken{ 5319225950Sken int error_code, sense_key, asc, ascq; 5320225950Sken 5321225950Sken scsi_extract_sense_len(sense_data, sense_len, &error_code, 5322225950Sken &sense_key, &asc, &ascq, show_errors); 5323225950Sken 5324225950Sken return (sense_key); 5325225950Sken} 5326225950Sken 5327225950Skenint 5328225950Skenscsi_get_asc(struct scsi_sense_data *sense_data, u_int sense_len, 5329225950Sken int show_errors) 5330225950Sken{ 5331225950Sken int error_code, sense_key, asc, ascq; 5332225950Sken 5333225950Sken scsi_extract_sense_len(sense_data, sense_len, &error_code, 5334225950Sken &sense_key, &asc, &ascq, show_errors); 5335225950Sken 5336225950Sken return (asc); 5337225950Sken} 5338225950Sken 5339225950Skenint 5340225950Skenscsi_get_ascq(struct scsi_sense_data *sense_data, u_int sense_len, 5341225950Sken int show_errors) 5342225950Sken{ 5343225950Sken int error_code, sense_key, asc, ascq; 5344225950Sken 5345225950Sken scsi_extract_sense_len(sense_data, sense_len, &error_code, 5346225950Sken &sense_key, &asc, &ascq, show_errors); 5347225950Sken 5348225950Sken return (ascq); 5349225950Sken} 5350225950Sken 5351225950Sken/* 535257349Sken * This function currently requires at least 36 bytes, or 535357349Sken * SHORT_INQUIRY_LENGTH, worth of data to function properly. If this 535457349Sken * function needs more or less data in the future, another length should be 535557349Sken * defined in scsi_all.h to indicate the minimum amount of data necessary 535657349Sken * for this routine to function properly. 535757349Sken */ 535839213Sgibbsvoid 535939213Sgibbsscsi_print_inquiry(struct scsi_inquiry_data *inq_data) 536039213Sgibbs{ 536139213Sgibbs u_int8_t type; 536239213Sgibbs char *dtype, *qtype; 5363280898Smav char vendor[16], product[48], revision[16], rstr[12]; 536439213Sgibbs 536539213Sgibbs type = SID_TYPE(inq_data); 536639213Sgibbs 536739213Sgibbs /* 536839213Sgibbs * Figure out basic device type and qualifier. 536939213Sgibbs */ 537039213Sgibbs if (SID_QUAL_IS_VENDOR_UNIQUE(inq_data)) { 5371280898Smav qtype = " (vendor-unique qualifier)"; 537239213Sgibbs } else { 537339213Sgibbs switch (SID_QUAL(inq_data)) { 537439213Sgibbs case SID_QUAL_LU_CONNECTED: 537539213Sgibbs qtype = ""; 537639213Sgibbs break; 537739213Sgibbs 537839213Sgibbs case SID_QUAL_LU_OFFLINE: 5379280898Smav qtype = " (offline)"; 538039213Sgibbs break; 538139213Sgibbs 538239213Sgibbs case SID_QUAL_RSVD: 5383280898Smav qtype = " (reserved qualifier)"; 538439213Sgibbs break; 538539213Sgibbs default: 538639213Sgibbs case SID_QUAL_BAD_LU: 5387280898Smav qtype = " (LUN not supported)"; 538839213Sgibbs break; 538939213Sgibbs } 539039213Sgibbs } 539139213Sgibbs 539239213Sgibbs switch (type) { 539339213Sgibbs case T_DIRECT: 539439213Sgibbs dtype = "Direct Access"; 539539213Sgibbs break; 539639213Sgibbs case T_SEQUENTIAL: 539739213Sgibbs dtype = "Sequential Access"; 539839213Sgibbs break; 539939213Sgibbs case T_PRINTER: 540039213Sgibbs dtype = "Printer"; 540139213Sgibbs break; 540239213Sgibbs case T_PROCESSOR: 540339213Sgibbs dtype = "Processor"; 540439213Sgibbs break; 5405181381Sjkim case T_WORM: 5406181381Sjkim dtype = "WORM"; 5407181381Sjkim break; 540839213Sgibbs case T_CDROM: 540939213Sgibbs dtype = "CD-ROM"; 541039213Sgibbs break; 541139213Sgibbs case T_SCANNER: 541239213Sgibbs dtype = "Scanner"; 541339213Sgibbs break; 541439213Sgibbs case T_OPTICAL: 541539213Sgibbs dtype = "Optical"; 541639213Sgibbs break; 541739213Sgibbs case T_CHANGER: 541839213Sgibbs dtype = "Changer"; 541939213Sgibbs break; 542039213Sgibbs case T_COMM: 542139213Sgibbs dtype = "Communication"; 542239213Sgibbs break; 542339213Sgibbs case T_STORARRAY: 542481448Sphk dtype = "Storage Array"; 542539213Sgibbs break; 542639213Sgibbs case T_ENCLOSURE: 542739213Sgibbs dtype = "Enclosure Services"; 542839213Sgibbs break; 542991016Ssimokawa case T_RBC: 543091016Ssimokawa dtype = "Simplified Direct Access"; 543191016Ssimokawa break; 543291016Ssimokawa case T_OCRW: 543391016Ssimokawa dtype = "Optical Card Read/Write"; 543491016Ssimokawa break; 5435181381Sjkim case T_OSD: 5436181381Sjkim dtype = "Object-Based Storage"; 5437181381Sjkim break; 5438181381Sjkim case T_ADC: 5439181381Sjkim dtype = "Automation/Drive Interface"; 5440181381Sjkim break; 544139213Sgibbs case T_NODEVICE: 544239213Sgibbs dtype = "Uninstalled"; 5443187243Strasz break; 544439213Sgibbs default: 544539213Sgibbs dtype = "unknown"; 544639213Sgibbs break; 544739213Sgibbs } 544839213Sgibbs 544939213Sgibbs cam_strvis(vendor, inq_data->vendor, sizeof(inq_data->vendor), 545039213Sgibbs sizeof(vendor)); 545139213Sgibbs cam_strvis(product, inq_data->product, sizeof(inq_data->product), 545239213Sgibbs sizeof(product)); 545339213Sgibbs cam_strvis(revision, inq_data->revision, sizeof(inq_data->revision), 545439213Sgibbs sizeof(revision)); 545539213Sgibbs 5456280898Smav if (SID_ANSI_REV(inq_data) == SCSI_REV_0) 5457280898Smav snprintf(rstr, sizeof(rstr), "SCSI"); 5458280898Smav else if (SID_ANSI_REV(inq_data) <= SCSI_REV_SPC) { 5459280898Smav snprintf(rstr, sizeof(rstr), "SCSI-%d", 5460280898Smav SID_ANSI_REV(inq_data)); 5461280898Smav } else { 5462280898Smav snprintf(rstr, sizeof(rstr), "SPC-%d SCSI", 5463280898Smav SID_ANSI_REV(inq_data) - 2); 5464280898Smav } 5465280898Smav printf("<%s %s %s> %s %s %s device%s\n", 546639213Sgibbs vendor, product, revision, 546739213Sgibbs SID_IS_REMOVABLE(inq_data) ? "Removable" : "Fixed", 546841549Smjacob dtype, rstr, qtype); 546939213Sgibbs} 547039213Sgibbs 5471257049Smavvoid 5472257049Smavscsi_print_inquiry_short(struct scsi_inquiry_data *inq_data) 5473257049Smav{ 5474257049Smav char vendor[16], product[48], revision[16]; 5475257049Smav 5476257049Smav cam_strvis(vendor, inq_data->vendor, sizeof(inq_data->vendor), 5477257049Smav sizeof(vendor)); 5478257049Smav cam_strvis(product, inq_data->product, sizeof(inq_data->product), 5479257049Smav sizeof(product)); 5480257049Smav cam_strvis(revision, inq_data->revision, sizeof(inq_data->revision), 5481257049Smav sizeof(revision)); 5482257049Smav 5483257049Smav printf("<%s %s %s>", vendor, product, revision); 5484257049Smav} 5485257049Smav 548639213Sgibbs/* 548739213Sgibbs * Table of syncrates that don't follow the "divisible by 4" 548839213Sgibbs * rule. This table will be expanded in future SCSI specs. 548939213Sgibbs */ 549039213Sgibbsstatic struct { 549163456Sgibbs u_int period_factor; 549297882Sgibbs u_int period; /* in 100ths of ns */ 549339213Sgibbs} scsi_syncrates[] = { 549497882Sgibbs { 0x08, 625 }, /* FAST-160 */ 549597882Sgibbs { 0x09, 1250 }, /* FAST-80 */ 549697882Sgibbs { 0x0a, 2500 }, /* FAST-40 40MHz */ 549797882Sgibbs { 0x0b, 3030 }, /* FAST-40 33MHz */ 549897882Sgibbs { 0x0c, 5000 } /* FAST-20 */ 549939213Sgibbs}; 550039213Sgibbs 550139213Sgibbs/* 550239213Sgibbs * Return the frequency in kHz corresponding to the given 550339213Sgibbs * sync period factor. 550439213Sgibbs */ 550539213Sgibbsu_int 550639213Sgibbsscsi_calc_syncsrate(u_int period_factor) 550739213Sgibbs{ 550839213Sgibbs int i; 550939213Sgibbs int num_syncrates; 551039213Sgibbs 5511145042Smjacob /* 5512145042Smjacob * It's a bug if period is zero, but if it is anyway, don't 5513145042Smjacob * die with a divide fault- instead return something which 5514145042Smjacob * 'approximates' async 5515145042Smjacob */ 5516145042Smjacob if (period_factor == 0) { 5517145042Smjacob return (3300); 5518145042Smjacob } 5519145042Smjacob 552039213Sgibbs num_syncrates = sizeof(scsi_syncrates) / sizeof(scsi_syncrates[0]); 552139213Sgibbs /* See if the period is in the "exception" table */ 552239213Sgibbs for (i = 0; i < num_syncrates; i++) { 552339213Sgibbs 552439213Sgibbs if (period_factor == scsi_syncrates[i].period_factor) { 552539213Sgibbs /* Period in kHz */ 552697882Sgibbs return (100000000 / scsi_syncrates[i].period); 552739213Sgibbs } 552839213Sgibbs } 552939213Sgibbs 553039213Sgibbs /* 553139213Sgibbs * Wasn't in the table, so use the standard 553239213Sgibbs * 4 times conversion. 553339213Sgibbs */ 553439213Sgibbs return (10000000 / (period_factor * 4 * 10)); 553539213Sgibbs} 553639213Sgibbs 553739213Sgibbs/* 553839213Sgibbs * Return the SCSI sync parameter that corresponsd to 553939213Sgibbs * the passed in period in 10ths of ns. 554039213Sgibbs */ 554139213Sgibbsu_int 554239213Sgibbsscsi_calc_syncparam(u_int period) 554339213Sgibbs{ 554439213Sgibbs int i; 554539213Sgibbs int num_syncrates; 554639213Sgibbs 554739213Sgibbs if (period == 0) 554839213Sgibbs return (~0); /* Async */ 554939213Sgibbs 5550102443Sgibbs /* Adjust for exception table being in 100ths. */ 5551102443Sgibbs period *= 10; 555239213Sgibbs num_syncrates = sizeof(scsi_syncrates) / sizeof(scsi_syncrates[0]); 555339213Sgibbs /* See if the period is in the "exception" table */ 555439213Sgibbs for (i = 0; i < num_syncrates; i++) { 555539213Sgibbs 555639213Sgibbs if (period <= scsi_syncrates[i].period) { 5557102443Sgibbs /* Period in 100ths of ns */ 555839213Sgibbs return (scsi_syncrates[i].period_factor); 555939213Sgibbs } 556039213Sgibbs } 556139213Sgibbs 556239213Sgibbs /* 556339213Sgibbs * Wasn't in the table, so use the standard 556439213Sgibbs * 1/4 period in ns conversion. 556539213Sgibbs */ 5566102443Sgibbs return (period/400); 556739213Sgibbs} 556839213Sgibbs 5569223081Sgibbsint 5570223081Sgibbsscsi_devid_is_naa_ieee_reg(uint8_t *bufp) 5571216088Sken{ 5572216088Sken struct scsi_vpd_id_descriptor *descr; 5573216088Sken struct scsi_vpd_id_naa_basic *naa; 5574216088Sken 5575223081Sgibbs descr = (struct scsi_vpd_id_descriptor *)bufp; 5576223081Sgibbs naa = (struct scsi_vpd_id_naa_basic *)descr->identifier; 5577223081Sgibbs if ((descr->id_type & SVPD_ID_TYPE_MASK) != SVPD_ID_TYPE_NAA) 5578223081Sgibbs return 0; 5579223081Sgibbs if (descr->length < sizeof(struct scsi_vpd_id_naa_ieee_reg)) 5580223081Sgibbs return 0; 5581223081Sgibbs if ((naa->naa >> SVPD_ID_NAA_NAA_SHIFT) != SVPD_ID_NAA_IEEE_REG) 5582223081Sgibbs return 0; 5583223081Sgibbs return 1; 5584223081Sgibbs} 5585223081Sgibbs 5586223081Sgibbsint 5587223081Sgibbsscsi_devid_is_sas_target(uint8_t *bufp) 5588223081Sgibbs{ 5589223081Sgibbs struct scsi_vpd_id_descriptor *descr; 5590223081Sgibbs 5591223081Sgibbs descr = (struct scsi_vpd_id_descriptor *)bufp; 5592223081Sgibbs if (!scsi_devid_is_naa_ieee_reg(bufp)) 5593223081Sgibbs return 0; 5594223081Sgibbs if ((descr->id_type & SVPD_ID_PIV) == 0) /* proto field reserved */ 5595223081Sgibbs return 0; 5596223081Sgibbs if ((descr->proto_codeset >> SVPD_ID_PROTO_SHIFT) != SCSI_PROTO_SAS) 5597223081Sgibbs return 0; 5598223081Sgibbs return 1; 5599223081Sgibbs} 5600223081Sgibbs 5601251654Smavint 5602251654Smavscsi_devid_is_lun_eui64(uint8_t *bufp) 5603251654Smav{ 5604251654Smav struct scsi_vpd_id_descriptor *descr; 5605251654Smav 5606251654Smav descr = (struct scsi_vpd_id_descriptor *)bufp; 5607251654Smav if ((descr->id_type & SVPD_ID_ASSOC_MASK) != SVPD_ID_ASSOC_LUN) 5608251654Smav return 0; 5609251654Smav if ((descr->id_type & SVPD_ID_TYPE_MASK) != SVPD_ID_TYPE_EUI64) 5610251654Smav return 0; 5611251654Smav return 1; 5612251654Smav} 5613251654Smav 5614251654Smavint 5615251654Smavscsi_devid_is_lun_naa(uint8_t *bufp) 5616251654Smav{ 5617251654Smav struct scsi_vpd_id_descriptor *descr; 5618251654Smav 5619251654Smav descr = (struct scsi_vpd_id_descriptor *)bufp; 5620251654Smav if ((descr->id_type & SVPD_ID_ASSOC_MASK) != SVPD_ID_ASSOC_LUN) 5621251654Smav return 0; 5622251654Smav if ((descr->id_type & SVPD_ID_TYPE_MASK) != SVPD_ID_TYPE_NAA) 5623251654Smav return 0; 5624251654Smav return 1; 5625251654Smav} 5626251654Smav 5627251654Smavint 5628251654Smavscsi_devid_is_lun_t10(uint8_t *bufp) 5629251654Smav{ 5630251654Smav struct scsi_vpd_id_descriptor *descr; 5631251654Smav 5632251654Smav descr = (struct scsi_vpd_id_descriptor *)bufp; 5633251654Smav if ((descr->id_type & SVPD_ID_ASSOC_MASK) != SVPD_ID_ASSOC_LUN) 5634251654Smav return 0; 5635251654Smav if ((descr->id_type & SVPD_ID_TYPE_MASK) != SVPD_ID_TYPE_T10) 5636251654Smav return 0; 5637251654Smav return 1; 5638251654Smav} 5639251654Smav 5640251654Smavint 5641251654Smavscsi_devid_is_lun_name(uint8_t *bufp) 5642251654Smav{ 5643251654Smav struct scsi_vpd_id_descriptor *descr; 5644251654Smav 5645251654Smav descr = (struct scsi_vpd_id_descriptor *)bufp; 5646251654Smav if ((descr->id_type & SVPD_ID_ASSOC_MASK) != SVPD_ID_ASSOC_LUN) 5647251654Smav return 0; 5648251654Smav if ((descr->id_type & SVPD_ID_TYPE_MASK) != SVPD_ID_TYPE_SCSI_NAME) 5649251654Smav return 0; 5650251654Smav return 1; 5651251654Smav} 5652251654Smav 5653299961Sasomersint 5654311425Smavscsi_devid_is_lun_md5(uint8_t *bufp) 5655311425Smav{ 5656311425Smav struct scsi_vpd_id_descriptor *descr; 5657311425Smav 5658311425Smav descr = (struct scsi_vpd_id_descriptor *)bufp; 5659311425Smav if ((descr->id_type & SVPD_ID_ASSOC_MASK) != SVPD_ID_ASSOC_LUN) 5660311425Smav return 0; 5661311425Smav if ((descr->id_type & SVPD_ID_TYPE_MASK) != SVPD_ID_TYPE_MD5_LUN_ID) 5662311425Smav return 0; 5663311425Smav return 1; 5664311425Smav} 5665311425Smav 5666311425Smavint 5667311425Smavscsi_devid_is_lun_uuid(uint8_t *bufp) 5668311425Smav{ 5669311425Smav struct scsi_vpd_id_descriptor *descr; 5670311425Smav 5671311425Smav descr = (struct scsi_vpd_id_descriptor *)bufp; 5672311425Smav if ((descr->id_type & SVPD_ID_ASSOC_MASK) != SVPD_ID_ASSOC_LUN) 5673311425Smav return 0; 5674311425Smav if ((descr->id_type & SVPD_ID_TYPE_MASK) != SVPD_ID_TYPE_UUID) 5675311425Smav return 0; 5676311425Smav return 1; 5677311425Smav} 5678311425Smav 5679311425Smavint 5680299961Sasomersscsi_devid_is_port_naa(uint8_t *bufp) 5681299961Sasomers{ 5682299961Sasomers struct scsi_vpd_id_descriptor *descr; 5683299961Sasomers 5684299961Sasomers descr = (struct scsi_vpd_id_descriptor *)bufp; 5685299961Sasomers if ((descr->id_type & SVPD_ID_ASSOC_MASK) != SVPD_ID_ASSOC_PORT) 5686299961Sasomers return 0; 5687299961Sasomers if ((descr->id_type & SVPD_ID_TYPE_MASK) != SVPD_ID_TYPE_NAA) 5688299961Sasomers return 0; 5689299961Sasomers return 1; 5690299961Sasomers} 5691299961Sasomers 5692251654Smavstruct scsi_vpd_id_descriptor * 5693270106Smavscsi_get_devid_desc(struct scsi_vpd_id_descriptor *desc, uint32_t len, 5694223081Sgibbs scsi_devid_checkfn_t ck_fn) 5695223081Sgibbs{ 5696223081Sgibbs uint8_t *desc_buf_end; 5697223081Sgibbs 5698270106Smav desc_buf_end = (uint8_t *)desc + len; 5699223081Sgibbs 5700270106Smav for (; desc->identifier <= desc_buf_end && 5701270106Smav desc->identifier + desc->length <= desc_buf_end; 5702270106Smav desc = (struct scsi_vpd_id_descriptor *)(desc->identifier 5703223081Sgibbs + desc->length)) { 5704223081Sgibbs 5705223081Sgibbs if (ck_fn == NULL || ck_fn((uint8_t *)desc) != 0) 5706251654Smav return (desc); 5707216088Sken } 5708223081Sgibbs return (NULL); 5709216088Sken} 5710216088Sken 5711270106Smavstruct scsi_vpd_id_descriptor * 5712270106Smavscsi_get_devid(struct scsi_vpd_device_id *id, uint32_t page_len, 5713270106Smav scsi_devid_checkfn_t ck_fn) 5714270106Smav{ 5715270106Smav uint32_t len; 5716270106Smav 5717270106Smav if (page_len < sizeof(*id)) 5718270106Smav return (NULL); 5719270106Smav len = MIN(scsi_2btoul(id->length), page_len - sizeof(*id)); 5720270106Smav return (scsi_get_devid_desc((struct scsi_vpd_id_descriptor *) 5721270106Smav id->desc_list, len, ck_fn)); 5722270106Smav} 5723270106Smav 5724268700Smavint 5725268700Smavscsi_transportid_sbuf(struct sbuf *sb, struct scsi_transportid_header *hdr, 5726268700Smav uint32_t valid_len) 5727268700Smav{ 5728268700Smav switch (hdr->format_protocol & SCSI_TRN_PROTO_MASK) { 5729268700Smav case SCSI_PROTO_FC: { 5730268700Smav struct scsi_transportid_fcp *fcp; 5731268700Smav uint64_t n_port_name; 5732268700Smav 5733268700Smav fcp = (struct scsi_transportid_fcp *)hdr; 5734268700Smav 5735268700Smav n_port_name = scsi_8btou64(fcp->n_port_name); 5736268700Smav 5737268700Smav sbuf_printf(sb, "FCP address: 0x%.16jx",(uintmax_t)n_port_name); 5738268700Smav break; 5739268700Smav } 5740268700Smav case SCSI_PROTO_SPI: { 5741268700Smav struct scsi_transportid_spi *spi; 5742268700Smav 5743268700Smav spi = (struct scsi_transportid_spi *)hdr; 5744268700Smav 5745268700Smav sbuf_printf(sb, "SPI address: %u,%u", 5746268700Smav scsi_2btoul(spi->scsi_addr), 5747268700Smav scsi_2btoul(spi->rel_trgt_port_id)); 5748268700Smav break; 5749268700Smav } 5750268700Smav case SCSI_PROTO_SSA: 5751268700Smav /* 5752268700Smav * XXX KDM there is no transport ID defined in SPC-4 for 5753268700Smav * SSA. 5754268700Smav */ 5755268700Smav break; 5756268700Smav case SCSI_PROTO_1394: { 5757268700Smav struct scsi_transportid_1394 *sbp; 5758268700Smav uint64_t eui64; 5759268700Smav 5760268700Smav sbp = (struct scsi_transportid_1394 *)hdr; 5761268700Smav 5762268700Smav eui64 = scsi_8btou64(sbp->eui64); 5763268700Smav sbuf_printf(sb, "SBP address: 0x%.16jx", (uintmax_t)eui64); 5764268700Smav break; 5765268700Smav } 5766268700Smav case SCSI_PROTO_RDMA: { 5767268700Smav struct scsi_transportid_rdma *rdma; 5768268700Smav unsigned int i; 5769268700Smav 5770268700Smav rdma = (struct scsi_transportid_rdma *)hdr; 5771268700Smav 5772268700Smav sbuf_printf(sb, "RDMA address: 0x"); 5773268700Smav for (i = 0; i < sizeof(rdma->initiator_port_id); i++) 5774268700Smav sbuf_printf(sb, "%02x", rdma->initiator_port_id[i]); 5775268700Smav break; 5776268700Smav } 5777268700Smav case SCSI_PROTO_ISCSI: { 5778268700Smav uint32_t add_len, i; 5779268700Smav uint8_t *iscsi_name = NULL; 5780268700Smav int nul_found = 0; 5781268700Smav 5782268700Smav sbuf_printf(sb, "iSCSI address: "); 5783268700Smav if ((hdr->format_protocol & SCSI_TRN_FORMAT_MASK) == 5784268700Smav SCSI_TRN_ISCSI_FORMAT_DEVICE) { 5785268700Smav struct scsi_transportid_iscsi_device *dev; 5786268700Smav 5787268700Smav dev = (struct scsi_transportid_iscsi_device *)hdr; 5788268700Smav 5789268700Smav /* 5790268700Smav * Verify how much additional data we really have. 5791268700Smav */ 5792268700Smav add_len = scsi_2btoul(dev->additional_length); 5793268700Smav add_len = MIN(add_len, valid_len - 5794268700Smav __offsetof(struct scsi_transportid_iscsi_device, 5795268700Smav iscsi_name)); 5796268700Smav iscsi_name = &dev->iscsi_name[0]; 5797268700Smav 5798268700Smav } else if ((hdr->format_protocol & SCSI_TRN_FORMAT_MASK) == 5799268700Smav SCSI_TRN_ISCSI_FORMAT_PORT) { 5800268700Smav struct scsi_transportid_iscsi_port *port; 5801268700Smav 5802268700Smav port = (struct scsi_transportid_iscsi_port *)hdr; 5803268700Smav 5804268700Smav add_len = scsi_2btoul(port->additional_length); 5805268700Smav add_len = MIN(add_len, valid_len - 5806268700Smav __offsetof(struct scsi_transportid_iscsi_port, 5807268700Smav iscsi_name)); 5808268700Smav iscsi_name = &port->iscsi_name[0]; 5809268700Smav } else { 5810268700Smav sbuf_printf(sb, "unknown format %x", 5811268700Smav (hdr->format_protocol & 5812268700Smav SCSI_TRN_FORMAT_MASK) >> 5813268700Smav SCSI_TRN_FORMAT_SHIFT); 5814268700Smav break; 5815268700Smav } 5816268700Smav if (add_len == 0) { 5817268700Smav sbuf_printf(sb, "not enough data"); 5818268700Smav break; 5819268700Smav } 5820268700Smav /* 5821268700Smav * This is supposed to be a NUL-terminated ASCII 5822268700Smav * string, but you never know. So we're going to 5823268700Smav * check. We need to do this because there is no 5824268700Smav * sbuf equivalent of strncat(). 5825268700Smav */ 5826268700Smav for (i = 0; i < add_len; i++) { 5827268700Smav if (iscsi_name[i] == '\0') { 5828268700Smav nul_found = 1; 5829268700Smav break; 5830268700Smav } 5831268700Smav } 5832268700Smav /* 5833268700Smav * If there is a NUL in the name, we can just use 5834268700Smav * sbuf_cat(). Otherwise we need to use sbuf_bcat(). 5835268700Smav */ 5836268700Smav if (nul_found != 0) 5837268700Smav sbuf_cat(sb, iscsi_name); 5838268700Smav else 5839268700Smav sbuf_bcat(sb, iscsi_name, add_len); 5840268700Smav break; 5841268700Smav } 5842268700Smav case SCSI_PROTO_SAS: { 5843268700Smav struct scsi_transportid_sas *sas; 5844268700Smav uint64_t sas_addr; 5845268700Smav 5846268700Smav sas = (struct scsi_transportid_sas *)hdr; 5847268700Smav 5848268700Smav sas_addr = scsi_8btou64(sas->sas_address); 5849268700Smav sbuf_printf(sb, "SAS address: 0x%.16jx", (uintmax_t)sas_addr); 5850268700Smav break; 5851268700Smav } 5852268700Smav case SCSI_PROTO_ADITP: 5853268700Smav case SCSI_PROTO_ATA: 5854268700Smav case SCSI_PROTO_UAS: 5855268700Smav /* 5856268700Smav * No Transport ID format for ADI, ATA or USB is defined in 5857268700Smav * SPC-4. 5858268700Smav */ 5859268700Smav sbuf_printf(sb, "No known Transport ID format for protocol " 5860268700Smav "%#x", hdr->format_protocol & SCSI_TRN_PROTO_MASK); 5861268700Smav break; 5862268700Smav case SCSI_PROTO_SOP: { 5863268700Smav struct scsi_transportid_sop *sop; 5864268700Smav struct scsi_sop_routing_id_norm *rid; 5865268700Smav 5866268700Smav sop = (struct scsi_transportid_sop *)hdr; 5867268700Smav rid = (struct scsi_sop_routing_id_norm *)sop->routing_id; 5868268700Smav 5869268700Smav /* 5870268700Smav * Note that there is no alternate format specified in SPC-4 5871268700Smav * for the PCIe routing ID, so we don't really have a way 5872268700Smav * to know whether the second byte of the routing ID is 5873268700Smav * a device and function or just a function. So we just 5874268700Smav * assume bus,device,function. 5875268700Smav */ 5876268700Smav sbuf_printf(sb, "SOP Routing ID: %u,%u,%u", 5877268700Smav rid->bus, rid->devfunc >> SCSI_TRN_SOP_DEV_SHIFT, 5878268700Smav rid->devfunc & SCSI_TRN_SOP_FUNC_NORM_MAX); 5879268700Smav break; 5880268700Smav } 5881268700Smav case SCSI_PROTO_NONE: 5882268700Smav default: 5883268700Smav sbuf_printf(sb, "Unknown protocol %#x", 5884268700Smav hdr->format_protocol & SCSI_TRN_PROTO_MASK); 5885268700Smav break; 5886268700Smav } 5887268700Smav 5888268700Smav return (0); 5889268700Smav} 5890268700Smav 5891268700Smavstruct scsi_nv scsi_proto_map[] = { 5892268700Smav { "fcp", SCSI_PROTO_FC }, 5893268700Smav { "spi", SCSI_PROTO_SPI }, 5894268700Smav { "ssa", SCSI_PROTO_SSA }, 5895268700Smav { "sbp", SCSI_PROTO_1394 }, 5896268700Smav { "1394", SCSI_PROTO_1394 }, 5897268700Smav { "srp", SCSI_PROTO_RDMA }, 5898268700Smav { "rdma", SCSI_PROTO_RDMA }, 5899268700Smav { "iscsi", SCSI_PROTO_ISCSI }, 5900268700Smav { "iqn", SCSI_PROTO_ISCSI }, 5901268700Smav { "sas", SCSI_PROTO_SAS }, 5902268700Smav { "aditp", SCSI_PROTO_ADITP }, 5903268700Smav { "ata", SCSI_PROTO_ATA }, 5904268700Smav { "uas", SCSI_PROTO_UAS }, 5905268700Smav { "usb", SCSI_PROTO_UAS }, 5906268700Smav { "sop", SCSI_PROTO_SOP } 5907268700Smav}; 5908268700Smav 5909268700Smavconst char * 5910268700Smavscsi_nv_to_str(struct scsi_nv *table, int num_table_entries, uint64_t value) 5911268700Smav{ 5912268700Smav int i; 5913268700Smav 5914268700Smav for (i = 0; i < num_table_entries; i++) { 5915268700Smav if (table[i].value == value) 5916268700Smav return (table[i].name); 5917268700Smav } 5918268700Smav 5919268700Smav return (NULL); 5920268700Smav} 5921268700Smav 5922268700Smav/* 5923268700Smav * Given a name/value table, find a value matching the given name. 5924268700Smav * Return values: 5925268700Smav * SCSI_NV_FOUND - match found 5926268700Smav * SCSI_NV_AMBIGUOUS - more than one match, none of them exact 5927268700Smav * SCSI_NV_NOT_FOUND - no match found 5928268700Smav */ 5929268700Smavscsi_nv_status 5930268700Smavscsi_get_nv(struct scsi_nv *table, int num_table_entries, 5931268700Smav char *name, int *table_entry, scsi_nv_flags flags) 5932268700Smav{ 5933268700Smav int i, num_matches = 0; 5934268700Smav 5935268700Smav for (i = 0; i < num_table_entries; i++) { 5936268700Smav size_t table_len, name_len; 5937268700Smav 5938268700Smav table_len = strlen(table[i].name); 5939268700Smav name_len = strlen(name); 5940268700Smav 5941268700Smav if ((((flags & SCSI_NV_FLAG_IG_CASE) != 0) 5942268700Smav && (strncasecmp(table[i].name, name, name_len) == 0)) 5943268700Smav || (((flags & SCSI_NV_FLAG_IG_CASE) == 0) 5944268700Smav && (strncmp(table[i].name, name, name_len) == 0))) { 5945268700Smav *table_entry = i; 5946268700Smav 5947268700Smav /* 5948268700Smav * Check for an exact match. If we have the same 5949268700Smav * number of characters in the table as the argument, 5950268700Smav * and we already know they're the same, we have 5951268700Smav * an exact match. 5952268700Smav */ 5953268700Smav if (table_len == name_len) 5954268700Smav return (SCSI_NV_FOUND); 5955268700Smav 5956268700Smav /* 5957268700Smav * Otherwise, bump up the number of matches. We'll 5958268700Smav * see later how many we have. 5959268700Smav */ 5960268700Smav num_matches++; 5961268700Smav } 5962268700Smav } 5963268700Smav 5964268700Smav if (num_matches > 1) 5965268700Smav return (SCSI_NV_AMBIGUOUS); 5966268700Smav else if (num_matches == 1) 5967268700Smav return (SCSI_NV_FOUND); 5968268700Smav else 5969268700Smav return (SCSI_NV_NOT_FOUND); 5970268700Smav} 5971268700Smav 5972268700Smav/* 5973268700Smav * Parse transport IDs for Fibre Channel, 1394 and SAS. Since these are 5974268700Smav * all 64-bit numbers, the code is similar. 5975268700Smav */ 5976268700Smavint 5977268700Smavscsi_parse_transportid_64bit(int proto_id, char *id_str, 5978268700Smav struct scsi_transportid_header **hdr, 5979268700Smav unsigned int *alloc_len, 5980268700Smav#ifdef _KERNEL 5981268700Smav struct malloc_type *type, int flags, 5982268700Smav#endif 5983268700Smav char *error_str, int error_str_len) 5984268700Smav{ 5985268700Smav uint64_t value; 5986268700Smav char *endptr; 5987268700Smav int retval; 5988268700Smav size_t alloc_size; 5989268700Smav 5990268700Smav retval = 0; 5991268700Smav 5992268700Smav value = strtouq(id_str, &endptr, 0); 5993268700Smav if (*endptr != '\0') { 5994268700Smav if (error_str != NULL) { 5995268700Smav snprintf(error_str, error_str_len, "%s: error " 5996268700Smav "parsing ID %s, 64-bit number required", 5997268700Smav __func__, id_str); 5998268700Smav } 5999268700Smav retval = 1; 6000268700Smav goto bailout; 6001268700Smav } 6002268700Smav 6003268700Smav switch (proto_id) { 6004268700Smav case SCSI_PROTO_FC: 6005268700Smav alloc_size = sizeof(struct scsi_transportid_fcp); 6006268700Smav break; 6007268700Smav case SCSI_PROTO_1394: 6008268700Smav alloc_size = sizeof(struct scsi_transportid_1394); 6009268700Smav break; 6010268700Smav case SCSI_PROTO_SAS: 6011268700Smav alloc_size = sizeof(struct scsi_transportid_sas); 6012268700Smav break; 6013268700Smav default: 6014268700Smav if (error_str != NULL) { 6015268700Smav snprintf(error_str, error_str_len, "%s: unsupoprted " 6016268700Smav "protocol %d", __func__, proto_id); 6017268700Smav } 6018268700Smav retval = 1; 6019268700Smav goto bailout; 6020268700Smav break; /* NOTREACHED */ 6021268700Smav } 6022268700Smav#ifdef _KERNEL 6023268700Smav *hdr = malloc(alloc_size, type, flags); 6024268700Smav#else /* _KERNEL */ 6025268700Smav *hdr = malloc(alloc_size); 6026268700Smav#endif /*_KERNEL */ 6027268700Smav if (*hdr == NULL) { 6028268700Smav if (error_str != NULL) { 6029268700Smav snprintf(error_str, error_str_len, "%s: unable to " 6030268700Smav "allocate %zu bytes", __func__, alloc_size); 6031268700Smav } 6032268700Smav retval = 1; 6033268700Smav goto bailout; 6034268700Smav } 6035268700Smav 6036268700Smav *alloc_len = alloc_size; 6037268700Smav 6038268700Smav bzero(*hdr, alloc_size); 6039268700Smav 6040268700Smav switch (proto_id) { 6041268700Smav case SCSI_PROTO_FC: { 6042268700Smav struct scsi_transportid_fcp *fcp; 6043268700Smav 6044268700Smav fcp = (struct scsi_transportid_fcp *)(*hdr); 6045268700Smav fcp->format_protocol = SCSI_PROTO_FC | 6046268700Smav SCSI_TRN_FCP_FORMAT_DEFAULT; 6047268700Smav scsi_u64to8b(value, fcp->n_port_name); 6048268700Smav break; 6049268700Smav } 6050268700Smav case SCSI_PROTO_1394: { 6051268700Smav struct scsi_transportid_1394 *sbp; 6052268700Smav 6053268700Smav sbp = (struct scsi_transportid_1394 *)(*hdr); 6054268700Smav sbp->format_protocol = SCSI_PROTO_1394 | 6055268700Smav SCSI_TRN_1394_FORMAT_DEFAULT; 6056268700Smav scsi_u64to8b(value, sbp->eui64); 6057268700Smav break; 6058268700Smav } 6059268700Smav case SCSI_PROTO_SAS: { 6060268700Smav struct scsi_transportid_sas *sas; 6061268700Smav 6062268700Smav sas = (struct scsi_transportid_sas *)(*hdr); 6063268700Smav sas->format_protocol = SCSI_PROTO_SAS | 6064268700Smav SCSI_TRN_SAS_FORMAT_DEFAULT; 6065268700Smav scsi_u64to8b(value, sas->sas_address); 6066268700Smav break; 6067268700Smav } 6068268700Smav default: 6069268700Smav break; 6070268700Smav } 6071268700Smavbailout: 6072268700Smav return (retval); 6073268700Smav} 6074268700Smav 6075268700Smav/* 6076268700Smav * Parse a SPI (Parallel SCSI) address of the form: id,rel_tgt_port 6077268700Smav */ 6078268700Smavint 6079268700Smavscsi_parse_transportid_spi(char *id_str, struct scsi_transportid_header **hdr, 6080268700Smav unsigned int *alloc_len, 6081268700Smav#ifdef _KERNEL 6082268700Smav struct malloc_type *type, int flags, 6083268700Smav#endif 6084268700Smav char *error_str, int error_str_len) 6085268700Smav{ 6086268700Smav unsigned long scsi_addr, target_port; 6087268700Smav struct scsi_transportid_spi *spi; 6088268700Smav char *tmpstr, *endptr; 6089268700Smav int retval; 6090268700Smav 6091268700Smav retval = 0; 6092268700Smav 6093268700Smav tmpstr = strsep(&id_str, ","); 6094268700Smav if (tmpstr == NULL) { 6095268700Smav if (error_str != NULL) { 6096268700Smav snprintf(error_str, error_str_len, 6097268700Smav "%s: no ID found", __func__); 6098268700Smav } 6099268700Smav retval = 1; 6100268700Smav goto bailout; 6101268700Smav } 6102268700Smav scsi_addr = strtoul(tmpstr, &endptr, 0); 6103268700Smav if (*endptr != '\0') { 6104268700Smav if (error_str != NULL) { 6105268700Smav snprintf(error_str, error_str_len, "%s: error " 6106268700Smav "parsing SCSI ID %s, number required", 6107268700Smav __func__, tmpstr); 6108268700Smav } 6109268700Smav retval = 1; 6110268700Smav goto bailout; 6111268700Smav } 6112268700Smav 6113268700Smav if (id_str == NULL) { 6114268700Smav if (error_str != NULL) { 6115268700Smav snprintf(error_str, error_str_len, "%s: no relative " 6116268700Smav "target port found", __func__); 6117268700Smav } 6118268700Smav retval = 1; 6119268700Smav goto bailout; 6120268700Smav } 6121268700Smav 6122268700Smav target_port = strtoul(id_str, &endptr, 0); 6123268700Smav if (*endptr != '\0') { 6124268700Smav if (error_str != NULL) { 6125268700Smav snprintf(error_str, error_str_len, "%s: error " 6126268700Smav "parsing relative target port %s, number " 6127268700Smav "required", __func__, id_str); 6128268700Smav } 6129268700Smav retval = 1; 6130268700Smav goto bailout; 6131268700Smav } 6132268700Smav#ifdef _KERNEL 6133268700Smav spi = malloc(sizeof(*spi), type, flags); 6134268700Smav#else 6135268700Smav spi = malloc(sizeof(*spi)); 6136268700Smav#endif 6137268700Smav if (spi == NULL) { 6138268700Smav if (error_str != NULL) { 6139268700Smav snprintf(error_str, error_str_len, "%s: unable to " 6140268700Smav "allocate %zu bytes", __func__, 6141268700Smav sizeof(*spi)); 6142268700Smav } 6143268700Smav retval = 1; 6144268700Smav goto bailout; 6145268700Smav } 6146268700Smav *alloc_len = sizeof(*spi); 6147268700Smav bzero(spi, sizeof(*spi)); 6148268700Smav 6149268700Smav spi->format_protocol = SCSI_PROTO_SPI | SCSI_TRN_SPI_FORMAT_DEFAULT; 6150268700Smav scsi_ulto2b(scsi_addr, spi->scsi_addr); 6151268700Smav scsi_ulto2b(target_port, spi->rel_trgt_port_id); 6152268700Smav 6153268700Smav *hdr = (struct scsi_transportid_header *)spi; 6154268700Smavbailout: 6155268700Smav return (retval); 6156268700Smav} 6157268700Smav 6158268700Smav/* 6159268700Smav * Parse an RDMA/SRP Initiator Port ID string. This is 32 hexadecimal digits, 6160268700Smav * optionally prefixed by "0x" or "0X". 6161268700Smav */ 6162268700Smavint 6163268700Smavscsi_parse_transportid_rdma(char *id_str, struct scsi_transportid_header **hdr, 6164268700Smav unsigned int *alloc_len, 6165268700Smav#ifdef _KERNEL 6166268700Smav struct malloc_type *type, int flags, 6167268700Smav#endif 6168268700Smav char *error_str, int error_str_len) 6169268700Smav{ 6170268700Smav struct scsi_transportid_rdma *rdma; 6171268700Smav int retval; 6172268700Smav size_t id_len, rdma_id_size; 6173268700Smav uint8_t rdma_id[SCSI_TRN_RDMA_PORT_LEN]; 6174268700Smav char *tmpstr; 6175268700Smav unsigned int i, j; 6176268700Smav 6177268700Smav retval = 0; 6178268700Smav id_len = strlen(id_str); 6179268700Smav rdma_id_size = SCSI_TRN_RDMA_PORT_LEN; 6180268700Smav 6181268700Smav /* 6182268700Smav * Check the size. It needs to be either 32 or 34 characters long. 6183268700Smav */ 6184268700Smav if ((id_len != (rdma_id_size * 2)) 6185268700Smav && (id_len != ((rdma_id_size * 2) + 2))) { 6186268700Smav if (error_str != NULL) { 6187268700Smav snprintf(error_str, error_str_len, "%s: RDMA ID " 6188268700Smav "must be 32 hex digits (0x prefix " 6189268700Smav "optional), only %zu seen", __func__, id_len); 6190268700Smav } 6191268700Smav retval = 1; 6192268700Smav goto bailout; 6193268700Smav } 6194268700Smav 6195268700Smav tmpstr = id_str; 6196268700Smav /* 6197268700Smav * If the user gave us 34 characters, the string needs to start 6198268700Smav * with '0x'. 6199268700Smav */ 6200268700Smav if (id_len == ((rdma_id_size * 2) + 2)) { 6201268700Smav if ((tmpstr[0] == '0') 6202268700Smav && ((tmpstr[1] == 'x') || (tmpstr[1] == 'X'))) { 6203268700Smav tmpstr += 2; 6204268700Smav } else { 6205268700Smav if (error_str != NULL) { 6206268700Smav snprintf(error_str, error_str_len, "%s: RDMA " 6207268700Smav "ID prefix, if used, must be \"0x\", " 6208268700Smav "got %s", __func__, tmpstr); 6209268700Smav } 6210268700Smav retval = 1; 6211268700Smav goto bailout; 6212268700Smav } 6213268700Smav } 6214268700Smav bzero(rdma_id, sizeof(rdma_id)); 6215268700Smav 6216268700Smav /* 6217268700Smav * Convert ASCII hex into binary bytes. There is no standard 6218268700Smav * 128-bit integer type, and so no strtou128t() routine to convert 6219268700Smav * from hex into a large integer. In the end, we're not going to 6220268700Smav * an integer, but rather to a byte array, so that and the fact 6221268700Smav * that we require the user to give us 32 hex digits simplifies the 6222268700Smav * logic. 6223268700Smav */ 6224268700Smav for (i = 0; i < (rdma_id_size * 2); i++) { 6225268700Smav int cur_shift; 6226268700Smav unsigned char c; 6227268700Smav 6228268700Smav /* Increment the byte array one for every 2 hex digits */ 6229268700Smav j = i >> 1; 6230268700Smav 6231268700Smav /* 6232268700Smav * The first digit in every pair is the most significant 6233268700Smav * 4 bits. The second is the least significant 4 bits. 6234268700Smav */ 6235268700Smav if ((i % 2) == 0) 6236268700Smav cur_shift = 4; 6237268700Smav else 6238268700Smav cur_shift = 0; 6239268700Smav 6240268700Smav c = tmpstr[i]; 6241268700Smav /* Convert the ASCII hex character into a number */ 6242268700Smav if (isdigit(c)) 6243268700Smav c -= '0'; 6244268700Smav else if (isalpha(c)) 6245268700Smav c -= isupper(c) ? 'A' - 10 : 'a' - 10; 6246268700Smav else { 6247268700Smav if (error_str != NULL) { 6248268700Smav snprintf(error_str, error_str_len, "%s: " 6249268700Smav "RDMA ID must be hex digits, got " 6250268700Smav "invalid character %c", __func__, 6251268700Smav tmpstr[i]); 6252268700Smav } 6253268700Smav retval = 1; 6254268700Smav goto bailout; 6255268700Smav } 6256268700Smav /* 6257268700Smav * The converted number can't be less than 0; the type is 6258268700Smav * unsigned, and the subtraction logic will not give us 6259268700Smav * a negative number. So we only need to make sure that 6260268700Smav * the value is not greater than 0xf. (i.e. make sure the 6261268700Smav * user didn't give us a value like "0x12jklmno"). 6262268700Smav */ 6263268700Smav if (c > 0xf) { 6264268700Smav if (error_str != NULL) { 6265268700Smav snprintf(error_str, error_str_len, "%s: " 6266268700Smav "RDMA ID must be hex digits, got " 6267268700Smav "invalid character %c", __func__, 6268268700Smav tmpstr[i]); 6269268700Smav } 6270268700Smav retval = 1; 6271268700Smav goto bailout; 6272268700Smav } 6273268700Smav 6274268700Smav rdma_id[j] |= c << cur_shift; 6275268700Smav } 6276268700Smav 6277268700Smav#ifdef _KERNEL 6278268700Smav rdma = malloc(sizeof(*rdma), type, flags); 6279268700Smav#else 6280268700Smav rdma = malloc(sizeof(*rdma)); 6281268700Smav#endif 6282268700Smav if (rdma == NULL) { 6283268700Smav if (error_str != NULL) { 6284268700Smav snprintf(error_str, error_str_len, "%s: unable to " 6285268700Smav "allocate %zu bytes", __func__, 6286268700Smav sizeof(*rdma)); 6287268700Smav } 6288268700Smav retval = 1; 6289268700Smav goto bailout; 6290268700Smav } 6291268700Smav *alloc_len = sizeof(*rdma); 6292281961Spfg bzero(rdma, *alloc_len); 6293268700Smav 6294268700Smav rdma->format_protocol = SCSI_PROTO_RDMA | SCSI_TRN_RDMA_FORMAT_DEFAULT; 6295268700Smav bcopy(rdma_id, rdma->initiator_port_id, SCSI_TRN_RDMA_PORT_LEN); 6296268700Smav 6297268700Smav *hdr = (struct scsi_transportid_header *)rdma; 6298268700Smav 6299268700Smavbailout: 6300268700Smav return (retval); 6301268700Smav} 6302268700Smav 6303268700Smav/* 6304268700Smav * Parse an iSCSI name. The format is either just the name: 6305268700Smav * 6306268700Smav * iqn.2012-06.com.example:target0 6307268700Smav * or the name, separator and initiator session ID: 6308268700Smav * 6309268700Smav * iqn.2012-06.com.example:target0,i,0x123 6310268700Smav * 6311268700Smav * The separator format is exact. 6312268700Smav */ 6313268700Smavint 6314268700Smavscsi_parse_transportid_iscsi(char *id_str, struct scsi_transportid_header **hdr, 6315268700Smav unsigned int *alloc_len, 6316268700Smav#ifdef _KERNEL 6317268700Smav struct malloc_type *type, int flags, 6318268700Smav#endif 6319268700Smav char *error_str, int error_str_len) 6320268700Smav{ 6321268700Smav size_t id_len, sep_len, id_size, name_len; 6322288692Smav int retval; 6323268700Smav unsigned int i, sep_pos, sep_found; 6324268700Smav const char *sep_template = ",i,0x"; 6325268700Smav const char *iqn_prefix = "iqn."; 6326268700Smav struct scsi_transportid_iscsi_device *iscsi; 6327268700Smav 6328268700Smav retval = 0; 6329268700Smav sep_found = 0; 6330268700Smav 6331268700Smav id_len = strlen(id_str); 6332268700Smav sep_len = strlen(sep_template); 6333268700Smav 6334268700Smav /* 6335268700Smav * The separator is defined as exactly ',i,0x'. Any other commas, 6336268700Smav * or any other form, is an error. So look for a comma, and once 6337268700Smav * we find that, the next few characters must match the separator 6338268700Smav * exactly. Once we get through the separator, there should be at 6339268700Smav * least one character. 6340268700Smav */ 6341268700Smav for (i = 0, sep_pos = 0; i < id_len; i++) { 6342268700Smav if (sep_pos == 0) { 6343268700Smav if (id_str[i] == sep_template[sep_pos]) 6344268700Smav sep_pos++; 6345268700Smav 6346268700Smav continue; 6347268700Smav } 6348268700Smav if (sep_pos < sep_len) { 6349268700Smav if (id_str[i] == sep_template[sep_pos]) { 6350268700Smav sep_pos++; 6351268700Smav continue; 6352268700Smav } 6353268700Smav if (error_str != NULL) { 6354268700Smav snprintf(error_str, error_str_len, "%s: " 6355268700Smav "invalid separator in iSCSI name " 6356268700Smav "\"%s\"", 6357268700Smav __func__, id_str); 6358268700Smav } 6359268700Smav retval = 1; 6360268700Smav goto bailout; 6361268700Smav } else { 6362268700Smav sep_found = 1; 6363268700Smav break; 6364268700Smav } 6365268700Smav } 6366268700Smav 6367268700Smav /* 6368268700Smav * Check to see whether we have a separator but no digits after it. 6369268700Smav */ 6370268700Smav if ((sep_pos != 0) 6371268700Smav && (sep_found == 0)) { 6372268700Smav if (error_str != NULL) { 6373268700Smav snprintf(error_str, error_str_len, "%s: no digits " 6374268700Smav "found after separator in iSCSI name \"%s\"", 6375268700Smav __func__, id_str); 6376268700Smav } 6377268700Smav retval = 1; 6378268700Smav goto bailout; 6379268700Smav } 6380268700Smav 6381268700Smav /* 6382268700Smav * The incoming ID string has the "iqn." prefix stripped off. We 6383268700Smav * need enough space for the base structure (the structures are the 6384268700Smav * same for the two iSCSI forms), the prefix, the ID string and a 6385268700Smav * terminating NUL. 6386268700Smav */ 6387268700Smav id_size = sizeof(*iscsi) + strlen(iqn_prefix) + id_len + 1; 6388268700Smav 6389268700Smav#ifdef _KERNEL 6390268700Smav iscsi = malloc(id_size, type, flags); 6391268700Smav#else 6392268700Smav iscsi = malloc(id_size); 6393268700Smav#endif 6394268700Smav if (iscsi == NULL) { 6395268700Smav if (error_str != NULL) { 6396268700Smav snprintf(error_str, error_str_len, "%s: unable to " 6397268700Smav "allocate %zu bytes", __func__, id_size); 6398268700Smav } 6399268700Smav retval = 1; 6400268700Smav goto bailout; 6401268700Smav } 6402268700Smav *alloc_len = id_size; 6403268700Smav bzero(iscsi, id_size); 6404268700Smav 6405268700Smav iscsi->format_protocol = SCSI_PROTO_ISCSI; 6406268700Smav if (sep_found == 0) 6407268700Smav iscsi->format_protocol |= SCSI_TRN_ISCSI_FORMAT_DEVICE; 6408268700Smav else 6409268700Smav iscsi->format_protocol |= SCSI_TRN_ISCSI_FORMAT_PORT; 6410268700Smav name_len = id_size - sizeof(*iscsi); 6411268700Smav scsi_ulto2b(name_len, iscsi->additional_length); 6412268700Smav snprintf(iscsi->iscsi_name, name_len, "%s%s", iqn_prefix, id_str); 6413268700Smav 6414268700Smav *hdr = (struct scsi_transportid_header *)iscsi; 6415268700Smav 6416268700Smavbailout: 6417268700Smav return (retval); 6418268700Smav} 6419268700Smav 6420268700Smav/* 6421268700Smav * Parse a SCSI over PCIe (SOP) identifier. The Routing ID can either be 6422268700Smav * of the form 'bus,device,function' or 'bus,function'. 6423268700Smav */ 6424268700Smavint 6425268700Smavscsi_parse_transportid_sop(char *id_str, struct scsi_transportid_header **hdr, 6426268700Smav unsigned int *alloc_len, 6427268700Smav#ifdef _KERNEL 6428268700Smav struct malloc_type *type, int flags, 6429268700Smav#endif 6430268700Smav char *error_str, int error_str_len) 6431268700Smav{ 6432268700Smav struct scsi_transportid_sop *sop; 6433268700Smav unsigned long bus, device, function; 6434268700Smav char *tmpstr, *endptr; 6435268700Smav int retval, device_spec; 6436268700Smav 6437268700Smav retval = 0; 6438268700Smav device_spec = 0; 6439268700Smav device = 0; 6440268700Smav 6441268700Smav tmpstr = strsep(&id_str, ","); 6442268700Smav if ((tmpstr == NULL) 6443268700Smav || (*tmpstr == '\0')) { 6444268700Smav if (error_str != NULL) { 6445268700Smav snprintf(error_str, error_str_len, "%s: no ID found", 6446268700Smav __func__); 6447268700Smav } 6448268700Smav retval = 1; 6449268700Smav goto bailout; 6450268700Smav } 6451268700Smav bus = strtoul(tmpstr, &endptr, 0); 6452268700Smav if (*endptr != '\0') { 6453268700Smav if (error_str != NULL) { 6454268700Smav snprintf(error_str, error_str_len, "%s: error " 6455268700Smav "parsing PCIe bus %s, number required", 6456268700Smav __func__, tmpstr); 6457268700Smav } 6458268700Smav retval = 1; 6459268700Smav goto bailout; 6460268700Smav } 6461268700Smav if ((id_str == NULL) 6462268700Smav || (*id_str == '\0')) { 6463268700Smav if (error_str != NULL) { 6464268700Smav snprintf(error_str, error_str_len, "%s: no PCIe " 6465268700Smav "device or function found", __func__); 6466268700Smav } 6467268700Smav retval = 1; 6468268700Smav goto bailout; 6469268700Smav } 6470268700Smav tmpstr = strsep(&id_str, ","); 6471268700Smav function = strtoul(tmpstr, &endptr, 0); 6472268700Smav if (*endptr != '\0') { 6473268700Smav if (error_str != NULL) { 6474268700Smav snprintf(error_str, error_str_len, "%s: error " 6475268700Smav "parsing PCIe device/function %s, number " 6476268700Smav "required", __func__, tmpstr); 6477268700Smav } 6478268700Smav retval = 1; 6479268700Smav goto bailout; 6480268700Smav } 6481268700Smav /* 6482268700Smav * Check to see whether the user specified a third value. If so, 6483268700Smav * the second is the device. 6484268700Smav */ 6485268700Smav if (id_str != NULL) { 6486268700Smav if (*id_str == '\0') { 6487268700Smav if (error_str != NULL) { 6488268700Smav snprintf(error_str, error_str_len, "%s: " 6489268700Smav "no PCIe function found", __func__); 6490268700Smav } 6491268700Smav retval = 1; 6492268700Smav goto bailout; 6493268700Smav } 6494268700Smav device = function; 6495268700Smav device_spec = 1; 6496268700Smav function = strtoul(id_str, &endptr, 0); 6497268700Smav if (*endptr != '\0') { 6498268700Smav if (error_str != NULL) { 6499268700Smav snprintf(error_str, error_str_len, "%s: " 6500268700Smav "error parsing PCIe function %s, " 6501268700Smav "number required", __func__, id_str); 6502268700Smav } 6503268700Smav retval = 1; 6504268700Smav goto bailout; 6505268700Smav } 6506268700Smav } 6507268700Smav if (bus > SCSI_TRN_SOP_BUS_MAX) { 6508268700Smav if (error_str != NULL) { 6509268700Smav snprintf(error_str, error_str_len, "%s: bus value " 6510268700Smav "%lu greater than maximum %u", __func__, 6511268700Smav bus, SCSI_TRN_SOP_BUS_MAX); 6512268700Smav } 6513268700Smav retval = 1; 6514268700Smav goto bailout; 6515268700Smav } 6516268700Smav 6517268700Smav if ((device_spec != 0) 6518268700Smav && (device > SCSI_TRN_SOP_DEV_MASK)) { 6519268700Smav if (error_str != NULL) { 6520268700Smav snprintf(error_str, error_str_len, "%s: device value " 6521268700Smav "%lu greater than maximum %u", __func__, 6522268700Smav device, SCSI_TRN_SOP_DEV_MAX); 6523268700Smav } 6524268700Smav retval = 1; 6525268700Smav goto bailout; 6526268700Smav } 6527268700Smav 6528268700Smav if (((device_spec != 0) 6529268700Smav && (function > SCSI_TRN_SOP_FUNC_NORM_MAX)) 6530268700Smav || ((device_spec == 0) 6531268700Smav && (function > SCSI_TRN_SOP_FUNC_ALT_MAX))) { 6532268700Smav if (error_str != NULL) { 6533268700Smav snprintf(error_str, error_str_len, "%s: function value " 6534268700Smav "%lu greater than maximum %u", __func__, 6535268700Smav function, (device_spec == 0) ? 6536268700Smav SCSI_TRN_SOP_FUNC_ALT_MAX : 6537268700Smav SCSI_TRN_SOP_FUNC_NORM_MAX); 6538268700Smav } 6539268700Smav retval = 1; 6540268700Smav goto bailout; 6541268700Smav } 6542268700Smav 6543268700Smav#ifdef _KERNEL 6544268700Smav sop = malloc(sizeof(*sop), type, flags); 6545268700Smav#else 6546268700Smav sop = malloc(sizeof(*sop)); 6547268700Smav#endif 6548268700Smav if (sop == NULL) { 6549268700Smav if (error_str != NULL) { 6550268700Smav snprintf(error_str, error_str_len, "%s: unable to " 6551268700Smav "allocate %zu bytes", __func__, sizeof(*sop)); 6552268700Smav } 6553268700Smav retval = 1; 6554268700Smav goto bailout; 6555268700Smav } 6556268700Smav *alloc_len = sizeof(*sop); 6557268700Smav bzero(sop, sizeof(*sop)); 6558268700Smav sop->format_protocol = SCSI_PROTO_SOP | SCSI_TRN_SOP_FORMAT_DEFAULT; 6559268700Smav if (device_spec != 0) { 6560268700Smav struct scsi_sop_routing_id_norm rid; 6561268700Smav 6562268700Smav rid.bus = bus; 6563268700Smav rid.devfunc = (device << SCSI_TRN_SOP_DEV_SHIFT) | function; 6564268700Smav bcopy(&rid, sop->routing_id, MIN(sizeof(rid), 6565268700Smav sizeof(sop->routing_id))); 6566268700Smav } else { 6567268700Smav struct scsi_sop_routing_id_alt rid; 6568268700Smav 6569268700Smav rid.bus = bus; 6570268700Smav rid.function = function; 6571268700Smav bcopy(&rid, sop->routing_id, MIN(sizeof(rid), 6572268700Smav sizeof(sop->routing_id))); 6573268700Smav } 6574268700Smav 6575268700Smav *hdr = (struct scsi_transportid_header *)sop; 6576268700Smavbailout: 6577268700Smav return (retval); 6578268700Smav} 6579268700Smav 6580268700Smav/* 6581268700Smav * transportid_str: NUL-terminated string with format: protcol,id 6582268700Smav * The ID is protocol specific. 6583268700Smav * hdr: Storage will be allocated for the transport ID. 6584268700Smav * alloc_len: The amount of memory allocated is returned here. 6585268700Smav * type: Malloc bucket (kernel only). 6586268700Smav * flags: Malloc flags (kernel only). 6587268700Smav * error_str: If non-NULL, it will contain error information (without 6588268700Smav * a terminating newline) if an error is returned. 6589268700Smav * error_str_len: Allocated length of the error string. 6590268700Smav * 6591268700Smav * Returns 0 for success, non-zero for failure. 6592268700Smav */ 6593268700Smavint 6594268700Smavscsi_parse_transportid(char *transportid_str, 6595268700Smav struct scsi_transportid_header **hdr, 6596268700Smav unsigned int *alloc_len, 6597268700Smav#ifdef _KERNEL 6598268700Smav struct malloc_type *type, int flags, 6599268700Smav#endif 6600268700Smav char *error_str, int error_str_len) 6601268700Smav{ 6602268700Smav char *tmpstr; 6603268700Smav scsi_nv_status status; 6604268700Smav int retval, num_proto_entries, table_entry; 6605268700Smav 6606268700Smav retval = 0; 6607268700Smav table_entry = 0; 6608268700Smav 6609268700Smav /* 6610268700Smav * We do allow a period as well as a comma to separate the protocol 6611268700Smav * from the ID string. This is to accommodate iSCSI names, which 6612268700Smav * start with "iqn.". 6613268700Smav */ 6614268700Smav tmpstr = strsep(&transportid_str, ",."); 6615268700Smav if (tmpstr == NULL) { 6616268700Smav if (error_str != NULL) { 6617268700Smav snprintf(error_str, error_str_len, 6618268700Smav "%s: transportid_str is NULL", __func__); 6619268700Smav } 6620268700Smav retval = 1; 6621268700Smav goto bailout; 6622268700Smav } 6623268700Smav 6624268700Smav num_proto_entries = sizeof(scsi_proto_map) / 6625268700Smav sizeof(scsi_proto_map[0]); 6626268700Smav status = scsi_get_nv(scsi_proto_map, num_proto_entries, tmpstr, 6627268700Smav &table_entry, SCSI_NV_FLAG_IG_CASE); 6628268700Smav if (status != SCSI_NV_FOUND) { 6629268700Smav if (error_str != NULL) { 6630268700Smav snprintf(error_str, error_str_len, "%s: %s protocol " 6631268700Smav "name %s", __func__, 6632268700Smav (status == SCSI_NV_AMBIGUOUS) ? "ambiguous" : 6633268700Smav "invalid", tmpstr); 6634268700Smav } 6635268700Smav retval = 1; 6636268700Smav goto bailout; 6637268700Smav } 6638268700Smav switch (scsi_proto_map[table_entry].value) { 6639268700Smav case SCSI_PROTO_FC: 6640268700Smav case SCSI_PROTO_1394: 6641268700Smav case SCSI_PROTO_SAS: 6642268700Smav retval = scsi_parse_transportid_64bit( 6643268700Smav scsi_proto_map[table_entry].value, transportid_str, hdr, 6644268700Smav alloc_len, 6645268700Smav#ifdef _KERNEL 6646268700Smav type, flags, 6647268700Smav#endif 6648268700Smav error_str, error_str_len); 6649268700Smav break; 6650268700Smav case SCSI_PROTO_SPI: 6651268700Smav retval = scsi_parse_transportid_spi(transportid_str, hdr, 6652268700Smav alloc_len, 6653268700Smav#ifdef _KERNEL 6654268700Smav type, flags, 6655268700Smav#endif 6656268700Smav error_str, error_str_len); 6657268700Smav break; 6658268700Smav case SCSI_PROTO_RDMA: 6659268700Smav retval = scsi_parse_transportid_rdma(transportid_str, hdr, 6660268700Smav alloc_len, 6661268700Smav#ifdef _KERNEL 6662268700Smav type, flags, 6663268700Smav#endif 6664268700Smav error_str, error_str_len); 6665268700Smav break; 6666268700Smav case SCSI_PROTO_ISCSI: 6667268700Smav retval = scsi_parse_transportid_iscsi(transportid_str, hdr, 6668268700Smav alloc_len, 6669268700Smav#ifdef _KERNEL 6670268700Smav type, flags, 6671268700Smav#endif 6672268700Smav error_str, error_str_len); 6673268700Smav break; 6674268700Smav case SCSI_PROTO_SOP: 6675268700Smav retval = scsi_parse_transportid_sop(transportid_str, hdr, 6676268700Smav alloc_len, 6677268700Smav#ifdef _KERNEL 6678268700Smav type, flags, 6679268700Smav#endif 6680268700Smav error_str, error_str_len); 6681268700Smav break; 6682268700Smav case SCSI_PROTO_SSA: 6683268700Smav case SCSI_PROTO_ADITP: 6684268700Smav case SCSI_PROTO_ATA: 6685268700Smav case SCSI_PROTO_UAS: 6686268700Smav case SCSI_PROTO_NONE: 6687268700Smav default: 6688268700Smav /* 6689268700Smav * There is no format defined for a Transport ID for these 6690268700Smav * protocols. So even if the user gives us something, we 6691268700Smav * have no way to turn it into a standard SCSI Transport ID. 6692268700Smav */ 6693268700Smav retval = 1; 6694268700Smav if (error_str != NULL) { 6695268700Smav snprintf(error_str, error_str_len, "%s: no Transport " 6696268700Smav "ID format exists for protocol %s", 6697268700Smav __func__, tmpstr); 6698268700Smav } 6699268700Smav goto bailout; 6700268700Smav break; /* NOTREACHED */ 6701268700Smav } 6702268700Smavbailout: 6703268700Smav return (retval); 6704268700Smav} 6705268700Smav 6706284435Skenstruct scsi_attrib_table_entry scsi_mam_attr_table[] = { 6707284435Sken { SMA_ATTR_REM_CAP_PARTITION, SCSI_ATTR_FLAG_NONE, 6708284435Sken "Remaining Capacity in Partition", 6709284435Sken /*suffix*/ "MB", /*to_str*/ scsi_attrib_int_sbuf,/*parse_str*/ NULL }, 6710284435Sken { SMA_ATTR_MAX_CAP_PARTITION, SCSI_ATTR_FLAG_NONE, 6711284435Sken "Maximum Capacity in Partition", 6712284435Sken /*suffix*/"MB", /*to_str*/ scsi_attrib_int_sbuf, /*parse_str*/ NULL }, 6713284435Sken { SMA_ATTR_TAPEALERT_FLAGS, SCSI_ATTR_FLAG_HEX, 6714284435Sken "TapeAlert Flags", 6715284435Sken /*suffix*/NULL, /*to_str*/ scsi_attrib_int_sbuf, /*parse_str*/ NULL }, 6716284435Sken { SMA_ATTR_LOAD_COUNT, SCSI_ATTR_FLAG_NONE, 6717284435Sken "Load Count", 6718284435Sken /*suffix*/NULL, /*to_str*/ scsi_attrib_int_sbuf, /*parse_str*/ NULL }, 6719284435Sken { SMA_ATTR_MAM_SPACE_REMAINING, SCSI_ATTR_FLAG_NONE, 6720284435Sken "MAM Space Remaining", 6721284435Sken /*suffix*/"bytes", /*to_str*/ scsi_attrib_int_sbuf, 6722284435Sken /*parse_str*/ NULL }, 6723284435Sken { SMA_ATTR_DEV_ASSIGNING_ORG, SCSI_ATTR_FLAG_NONE, 6724284435Sken "Assigning Organization", 6725284435Sken /*suffix*/NULL, /*to_str*/ scsi_attrib_ascii_sbuf, 6726284435Sken /*parse_str*/ NULL }, 6727284435Sken { SMA_ATTR_FORMAT_DENSITY_CODE, SCSI_ATTR_FLAG_HEX, 6728284435Sken "Format Density Code", 6729284435Sken /*suffix*/NULL, /*to_str*/ scsi_attrib_int_sbuf, /*parse_str*/ NULL }, 6730284435Sken { SMA_ATTR_INITIALIZATION_COUNT, SCSI_ATTR_FLAG_NONE, 6731284435Sken "Initialization Count", 6732284435Sken /*suffix*/NULL, /*to_str*/ scsi_attrib_int_sbuf, /*parse_str*/ NULL }, 6733284435Sken { SMA_ATTR_VOLUME_ID, SCSI_ATTR_FLAG_NONE, 6734284435Sken "Volume Identifier", 6735284435Sken /*suffix*/NULL, /*to_str*/ scsi_attrib_ascii_sbuf, 6736284435Sken /*parse_str*/ NULL }, 6737284435Sken { SMA_ATTR_VOLUME_CHANGE_REF, SCSI_ATTR_FLAG_HEX, 6738284435Sken "Volume Change Reference", 6739284435Sken /*suffix*/NULL, /*to_str*/ scsi_attrib_int_sbuf, 6740284435Sken /*parse_str*/ NULL }, 6741284435Sken { SMA_ATTR_DEV_SERIAL_LAST_LOAD, SCSI_ATTR_FLAG_NONE, 6742284435Sken "Device Vendor/Serial at Last Load", 6743284435Sken /*suffix*/NULL, /*to_str*/ scsi_attrib_vendser_sbuf, 6744284435Sken /*parse_str*/ NULL }, 6745284435Sken { SMA_ATTR_DEV_SERIAL_LAST_LOAD_1, SCSI_ATTR_FLAG_NONE, 6746284435Sken "Device Vendor/Serial at Last Load - 1", 6747284435Sken /*suffix*/NULL, /*to_str*/ scsi_attrib_vendser_sbuf, 6748284435Sken /*parse_str*/ NULL }, 6749284435Sken { SMA_ATTR_DEV_SERIAL_LAST_LOAD_2, SCSI_ATTR_FLAG_NONE, 6750284435Sken "Device Vendor/Serial at Last Load - 2", 6751284435Sken /*suffix*/NULL, /*to_str*/ scsi_attrib_vendser_sbuf, 6752284435Sken /*parse_str*/ NULL }, 6753284435Sken { SMA_ATTR_DEV_SERIAL_LAST_LOAD_3, SCSI_ATTR_FLAG_NONE, 6754284435Sken "Device Vendor/Serial at Last Load - 3", 6755284435Sken /*suffix*/NULL, /*to_str*/ scsi_attrib_vendser_sbuf, 6756284435Sken /*parse_str*/ NULL }, 6757284435Sken { SMA_ATTR_TOTAL_MB_WRITTEN_LT, SCSI_ATTR_FLAG_NONE, 6758284435Sken "Total MB Written in Medium Life", 6759284435Sken /*suffix*/ "MB", /*to_str*/ scsi_attrib_int_sbuf, 6760284435Sken /*parse_str*/ NULL }, 6761284435Sken { SMA_ATTR_TOTAL_MB_READ_LT, SCSI_ATTR_FLAG_NONE, 6762284435Sken "Total MB Read in Medium Life", 6763284435Sken /*suffix*/ "MB", /*to_str*/ scsi_attrib_int_sbuf, 6764284435Sken /*parse_str*/ NULL }, 6765284435Sken { SMA_ATTR_TOTAL_MB_WRITTEN_CUR, SCSI_ATTR_FLAG_NONE, 6766284435Sken "Total MB Written in Current/Last Load", 6767284435Sken /*suffix*/ "MB", /*to_str*/ scsi_attrib_int_sbuf, 6768284435Sken /*parse_str*/ NULL }, 6769284435Sken { SMA_ATTR_TOTAL_MB_READ_CUR, SCSI_ATTR_FLAG_NONE, 6770284435Sken "Total MB Read in Current/Last Load", 6771284435Sken /*suffix*/ "MB", /*to_str*/ scsi_attrib_int_sbuf, 6772284435Sken /*parse_str*/ NULL }, 6773284435Sken { SMA_ATTR_FIRST_ENC_BLOCK, SCSI_ATTR_FLAG_NONE, 6774284435Sken "Logical Position of First Encrypted Block", 6775284435Sken /*suffix*/ NULL, /*to_str*/ scsi_attrib_int_sbuf, 6776284435Sken /*parse_str*/ NULL }, 6777284435Sken { SMA_ATTR_NEXT_UNENC_BLOCK, SCSI_ATTR_FLAG_NONE, 6778284435Sken "Logical Position of First Unencrypted Block after First " 6779284435Sken "Encrypted Block", 6780284435Sken /*suffix*/ NULL, /*to_str*/ scsi_attrib_int_sbuf, 6781284435Sken /*parse_str*/ NULL }, 6782284435Sken { SMA_ATTR_MEDIUM_USAGE_HIST, SCSI_ATTR_FLAG_NONE, 6783284435Sken "Medium Usage History", 6784284435Sken /*suffix*/ NULL, /*to_str*/ NULL, 6785284435Sken /*parse_str*/ NULL }, 6786284435Sken { SMA_ATTR_PART_USAGE_HIST, SCSI_ATTR_FLAG_NONE, 6787284435Sken "Partition Usage History", 6788284435Sken /*suffix*/ NULL, /*to_str*/ NULL, 6789284435Sken /*parse_str*/ NULL }, 6790284435Sken { SMA_ATTR_MED_MANUF, SCSI_ATTR_FLAG_NONE, 6791284435Sken "Medium Manufacturer", 6792284435Sken /*suffix*/NULL, /*to_str*/ scsi_attrib_ascii_sbuf, 6793284435Sken /*parse_str*/ NULL }, 6794284435Sken { SMA_ATTR_MED_SERIAL, SCSI_ATTR_FLAG_NONE, 6795284435Sken "Medium Serial Number", 6796284435Sken /*suffix*/NULL, /*to_str*/ scsi_attrib_ascii_sbuf, 6797284435Sken /*parse_str*/ NULL }, 6798284435Sken { SMA_ATTR_MED_LENGTH, SCSI_ATTR_FLAG_NONE, 6799284435Sken "Medium Length", 6800284435Sken /*suffix*/"m", /*to_str*/ scsi_attrib_int_sbuf, 6801284435Sken /*parse_str*/ NULL }, 6802284435Sken { SMA_ATTR_MED_WIDTH, SCSI_ATTR_FLAG_FP | SCSI_ATTR_FLAG_DIV_10 | 6803284435Sken SCSI_ATTR_FLAG_FP_1DIGIT, 6804284435Sken "Medium Width", 6805284435Sken /*suffix*/"mm", /*to_str*/ scsi_attrib_int_sbuf, 6806284435Sken /*parse_str*/ NULL }, 6807284435Sken { SMA_ATTR_MED_ASSIGNING_ORG, SCSI_ATTR_FLAG_NONE, 6808284435Sken "Assigning Organization", 6809284435Sken /*suffix*/NULL, /*to_str*/ scsi_attrib_ascii_sbuf, 6810284435Sken /*parse_str*/ NULL }, 6811284435Sken { SMA_ATTR_MED_DENSITY_CODE, SCSI_ATTR_FLAG_HEX, 6812284435Sken "Medium Density Code", 6813284435Sken /*suffix*/NULL, /*to_str*/ scsi_attrib_int_sbuf, 6814284435Sken /*parse_str*/ NULL }, 6815284435Sken { SMA_ATTR_MED_MANUF_DATE, SCSI_ATTR_FLAG_NONE, 6816284435Sken "Medium Manufacture Date", 6817284435Sken /*suffix*/NULL, /*to_str*/ scsi_attrib_ascii_sbuf, 6818284435Sken /*parse_str*/ NULL }, 6819284435Sken { SMA_ATTR_MAM_CAPACITY, SCSI_ATTR_FLAG_NONE, 6820284435Sken "MAM Capacity", 6821284435Sken /*suffix*/"bytes", /*to_str*/ scsi_attrib_int_sbuf, 6822284435Sken /*parse_str*/ NULL }, 6823284435Sken { SMA_ATTR_MED_TYPE, SCSI_ATTR_FLAG_HEX, 6824284435Sken "Medium Type", 6825284435Sken /*suffix*/NULL, /*to_str*/ scsi_attrib_int_sbuf, 6826284435Sken /*parse_str*/ NULL }, 6827284435Sken { SMA_ATTR_MED_TYPE_INFO, SCSI_ATTR_FLAG_HEX, 6828284435Sken "Medium Type Information", 6829284435Sken /*suffix*/NULL, /*to_str*/ scsi_attrib_int_sbuf, 6830284435Sken /*parse_str*/ NULL }, 6831284435Sken { SMA_ATTR_MED_SERIAL_NUM, SCSI_ATTR_FLAG_NONE, 6832284435Sken "Medium Serial Number", 6833284435Sken /*suffix*/NULL, /*to_str*/ scsi_attrib_int_sbuf, 6834284435Sken /*parse_str*/ NULL }, 6835284435Sken { SMA_ATTR_APP_VENDOR, SCSI_ATTR_FLAG_NONE, 6836284435Sken "Application Vendor", 6837284435Sken /*suffix*/NULL, /*to_str*/ scsi_attrib_ascii_sbuf, 6838284435Sken /*parse_str*/ NULL }, 6839284435Sken { SMA_ATTR_APP_NAME, SCSI_ATTR_FLAG_NONE, 6840284435Sken "Application Name", 6841284435Sken /*suffix*/NULL, /*to_str*/ scsi_attrib_ascii_sbuf, 6842284435Sken /*parse_str*/ NULL }, 6843284435Sken { SMA_ATTR_APP_VERSION, SCSI_ATTR_FLAG_NONE, 6844284435Sken "Application Version", 6845284435Sken /*suffix*/NULL, /*to_str*/ scsi_attrib_ascii_sbuf, 6846284435Sken /*parse_str*/ NULL }, 6847284435Sken { SMA_ATTR_USER_MED_TEXT_LABEL, SCSI_ATTR_FLAG_NONE, 6848284435Sken "User Medium Text Label", 6849284435Sken /*suffix*/NULL, /*to_str*/ scsi_attrib_text_sbuf, 6850284435Sken /*parse_str*/ NULL }, 6851284435Sken { SMA_ATTR_LAST_WRITTEN_TIME, SCSI_ATTR_FLAG_NONE, 6852284435Sken "Date and Time Last Written", 6853284435Sken /*suffix*/NULL, /*to_str*/ scsi_attrib_ascii_sbuf, 6854284435Sken /*parse_str*/ NULL }, 6855284435Sken { SMA_ATTR_TEXT_LOCAL_ID, SCSI_ATTR_FLAG_HEX, 6856284435Sken "Text Localization Identifier", 6857284435Sken /*suffix*/NULL, /*to_str*/ scsi_attrib_int_sbuf, 6858284435Sken /*parse_str*/ NULL }, 6859284435Sken { SMA_ATTR_BARCODE, SCSI_ATTR_FLAG_NONE, 6860284435Sken "Barcode", 6861284435Sken /*suffix*/NULL, /*to_str*/ scsi_attrib_ascii_sbuf, 6862284435Sken /*parse_str*/ NULL }, 6863284435Sken { SMA_ATTR_HOST_OWNER_NAME, SCSI_ATTR_FLAG_NONE, 6864284435Sken "Owning Host Textual Name", 6865284435Sken /*suffix*/NULL, /*to_str*/ scsi_attrib_text_sbuf, 6866284435Sken /*parse_str*/ NULL }, 6867284435Sken { SMA_ATTR_MEDIA_POOL, SCSI_ATTR_FLAG_NONE, 6868284435Sken "Media Pool", 6869284435Sken /*suffix*/NULL, /*to_str*/ scsi_attrib_text_sbuf, 6870284435Sken /*parse_str*/ NULL }, 6871284435Sken { SMA_ATTR_PART_USER_LABEL, SCSI_ATTR_FLAG_NONE, 6872284435Sken "Partition User Text Label", 6873284435Sken /*suffix*/NULL, /*to_str*/ scsi_attrib_ascii_sbuf, 6874284435Sken /*parse_str*/ NULL }, 6875284435Sken { SMA_ATTR_LOAD_UNLOAD_AT_PART, SCSI_ATTR_FLAG_NONE, 6876284435Sken "Load/Unload at Partition", 6877284435Sken /*suffix*/NULL, /*to_str*/ scsi_attrib_int_sbuf, 6878284435Sken /*parse_str*/ NULL }, 6879284435Sken { SMA_ATTR_APP_FORMAT_VERSION, SCSI_ATTR_FLAG_NONE, 6880284435Sken "Application Format Version", 6881284435Sken /*suffix*/NULL, /*to_str*/ scsi_attrib_ascii_sbuf, 6882284435Sken /*parse_str*/ NULL }, 6883284435Sken { SMA_ATTR_VOL_COHERENCY_INFO, SCSI_ATTR_FLAG_NONE, 6884284435Sken "Volume Coherency Information", 6885284435Sken /*suffix*/NULL, /*to_str*/ scsi_attrib_volcoh_sbuf, 6886284435Sken /*parse_str*/ NULL }, 6887284435Sken { 0x0ff1, SCSI_ATTR_FLAG_NONE, 6888284435Sken "Spectra MLM Creation", 6889284435Sken /*suffix*/NULL, /*to_str*/ scsi_attrib_hexdump_sbuf, 6890284435Sken /*parse_str*/ NULL }, 6891284435Sken { 0x0ff2, SCSI_ATTR_FLAG_NONE, 6892284435Sken "Spectra MLM C3", 6893284435Sken /*suffix*/NULL, /*to_str*/ scsi_attrib_hexdump_sbuf, 6894284435Sken /*parse_str*/ NULL }, 6895284435Sken { 0x0ff3, SCSI_ATTR_FLAG_NONE, 6896284435Sken "Spectra MLM RW", 6897284435Sken /*suffix*/NULL, /*to_str*/ scsi_attrib_hexdump_sbuf, 6898284435Sken /*parse_str*/ NULL }, 6899284435Sken { 0x0ff4, SCSI_ATTR_FLAG_NONE, 6900284435Sken "Spectra MLM SDC List", 6901284435Sken /*suffix*/NULL, /*to_str*/ scsi_attrib_hexdump_sbuf, 6902284435Sken /*parse_str*/ NULL }, 6903284435Sken { 0x0ff7, SCSI_ATTR_FLAG_NONE, 6904284435Sken "Spectra MLM Post Scan", 6905284435Sken /*suffix*/NULL, /*to_str*/ scsi_attrib_hexdump_sbuf, 6906284435Sken /*parse_str*/ NULL }, 6907284435Sken { 0x0ffe, SCSI_ATTR_FLAG_NONE, 6908284435Sken "Spectra MLM Checksum", 6909284435Sken /*suffix*/NULL, /*to_str*/ scsi_attrib_hexdump_sbuf, 6910284435Sken /*parse_str*/ NULL }, 6911284435Sken { 0x17f1, SCSI_ATTR_FLAG_NONE, 6912284435Sken "Spectra MLM Creation", 6913284435Sken /*suffix*/NULL, /*to_str*/ scsi_attrib_hexdump_sbuf, 6914284435Sken /*parse_str*/ NULL }, 6915284435Sken { 0x17f2, SCSI_ATTR_FLAG_NONE, 6916284435Sken "Spectra MLM C3", 6917284435Sken /*suffix*/NULL, /*to_str*/ scsi_attrib_hexdump_sbuf, 6918284435Sken /*parse_str*/ NULL }, 6919284435Sken { 0x17f3, SCSI_ATTR_FLAG_NONE, 6920284435Sken "Spectra MLM RW", 6921284435Sken /*suffix*/NULL, /*to_str*/ scsi_attrib_hexdump_sbuf, 6922284435Sken /*parse_str*/ NULL }, 6923284435Sken { 0x17f4, SCSI_ATTR_FLAG_NONE, 6924284435Sken "Spectra MLM SDC List", 6925284435Sken /*suffix*/NULL, /*to_str*/ scsi_attrib_hexdump_sbuf, 6926284435Sken /*parse_str*/ NULL }, 6927284435Sken { 0x17f7, SCSI_ATTR_FLAG_NONE, 6928284435Sken "Spectra MLM Post Scan", 6929284435Sken /*suffix*/NULL, /*to_str*/ scsi_attrib_hexdump_sbuf, 6930284435Sken /*parse_str*/ NULL }, 6931284435Sken { 0x17ff, SCSI_ATTR_FLAG_NONE, 6932284435Sken "Spectra MLM Checksum", 6933284435Sken /*suffix*/NULL, /*to_str*/ scsi_attrib_hexdump_sbuf, 6934284435Sken /*parse_str*/ NULL }, 6935284435Sken}; 6936284435Sken 6937284435Sken/* 6938284435Sken * Print out Volume Coherency Information (Attribute 0x080c). 6939284435Sken * This field has two variable length members, including one at the 6940284435Sken * beginning, so it isn't practical to have a fixed structure definition. 6941284435Sken * This is current as of SSC4r03 (see section 4.2.21.3), dated March 25, 6942284435Sken * 2013. 6943284435Sken */ 6944284435Skenint 6945284435Skenscsi_attrib_volcoh_sbuf(struct sbuf *sb, struct scsi_mam_attribute_header *hdr, 6946284435Sken uint32_t valid_len, uint32_t flags, 6947284435Sken uint32_t output_flags, char *error_str, 6948284435Sken int error_str_len) 6949284435Sken{ 6950284435Sken size_t avail_len; 6951284435Sken uint32_t field_size; 6952284435Sken uint64_t tmp_val; 6953284435Sken uint8_t *cur_ptr; 6954284435Sken int retval; 6955284435Sken int vcr_len, as_len; 6956284435Sken 6957284435Sken retval = 0; 6958284435Sken tmp_val = 0; 6959284435Sken 6960284435Sken field_size = scsi_2btoul(hdr->length); 6961284435Sken avail_len = valid_len - sizeof(*hdr); 6962284435Sken if (field_size > avail_len) { 6963284435Sken if (error_str != NULL) { 6964284435Sken snprintf(error_str, error_str_len, "Available " 6965284435Sken "length of attribute ID 0x%.4x %zu < field " 6966284435Sken "length %u", scsi_2btoul(hdr->id), avail_len, 6967284435Sken field_size); 6968284435Sken } 6969284435Sken retval = 1; 6970284435Sken goto bailout; 6971284435Sken } else if (field_size == 0) { 6972284435Sken /* 6973284435Sken * It isn't clear from the spec whether a field length of 6974284435Sken * 0 is invalid here. It probably is, but be lenient here 6975284435Sken * to avoid inconveniencing the user. 6976284435Sken */ 6977284435Sken goto bailout; 6978284435Sken } 6979284435Sken cur_ptr = hdr->attribute; 6980284435Sken vcr_len = *cur_ptr; 6981284435Sken cur_ptr++; 6982284435Sken 6983284435Sken sbuf_printf(sb, "\n\tVolume Change Reference Value:"); 6984284435Sken 6985284435Sken switch (vcr_len) { 6986284435Sken case 0: 6987284435Sken if (error_str != NULL) { 6988284435Sken snprintf(error_str, error_str_len, "Volume Change " 6989284435Sken "Reference value has length of 0"); 6990284435Sken } 6991284435Sken retval = 1; 6992284435Sken goto bailout; 6993284435Sken break; /*NOTREACHED*/ 6994284435Sken case 1: 6995284435Sken tmp_val = *cur_ptr; 6996284435Sken break; 6997284435Sken case 2: 6998284435Sken tmp_val = scsi_2btoul(cur_ptr); 6999284435Sken break; 7000284435Sken case 3: 7001284435Sken tmp_val = scsi_3btoul(cur_ptr); 7002284435Sken break; 7003284435Sken case 4: 7004284435Sken tmp_val = scsi_4btoul(cur_ptr); 7005284435Sken break; 7006284435Sken case 8: 7007284435Sken tmp_val = scsi_8btou64(cur_ptr); 7008284435Sken break; 7009284435Sken default: 7010284435Sken sbuf_printf(sb, "\n"); 7011284435Sken sbuf_hexdump(sb, cur_ptr, vcr_len, NULL, 0); 7012284435Sken break; 7013284435Sken } 7014284435Sken if (vcr_len <= 8) 7015284435Sken sbuf_printf(sb, " 0x%jx\n", (uintmax_t)tmp_val); 7016284435Sken 7017284435Sken cur_ptr += vcr_len; 7018284435Sken tmp_val = scsi_8btou64(cur_ptr); 7019284435Sken sbuf_printf(sb, "\tVolume Coherency Count: %ju\n", (uintmax_t)tmp_val); 7020284435Sken 7021284435Sken cur_ptr += sizeof(tmp_val); 7022284435Sken tmp_val = scsi_8btou64(cur_ptr); 7023284435Sken sbuf_printf(sb, "\tVolume Coherency Set Identifier: 0x%jx\n", 7024284435Sken (uintmax_t)tmp_val); 7025284435Sken 7026284435Sken /* 7027284435Sken * Figure out how long the Application Client Specific Information 7028284435Sken * is and produce a hexdump. 7029284435Sken */ 7030284435Sken cur_ptr += sizeof(tmp_val); 7031284435Sken as_len = scsi_2btoul(cur_ptr); 7032284435Sken cur_ptr += sizeof(uint16_t); 7033284435Sken sbuf_printf(sb, "\tApplication Client Specific Information: "); 7034284435Sken if (((as_len == SCSI_LTFS_VER0_LEN) 7035284435Sken || (as_len == SCSI_LTFS_VER1_LEN)) 7036284435Sken && (strncmp(cur_ptr, SCSI_LTFS_STR_NAME, SCSI_LTFS_STR_LEN) == 0)) { 7037284435Sken sbuf_printf(sb, "LTFS\n"); 7038284435Sken cur_ptr += SCSI_LTFS_STR_LEN + 1; 7039284435Sken if (cur_ptr[SCSI_LTFS_UUID_LEN] != '\0') 7040284435Sken cur_ptr[SCSI_LTFS_UUID_LEN] = '\0'; 7041284435Sken sbuf_printf(sb, "\tLTFS UUID: %s\n", cur_ptr); 7042284435Sken cur_ptr += SCSI_LTFS_UUID_LEN + 1; 7043284435Sken /* XXX KDM check the length */ 7044284435Sken sbuf_printf(sb, "\tLTFS Version: %d\n", *cur_ptr); 7045284435Sken } else { 7046284435Sken sbuf_printf(sb, "Unknown\n"); 7047284435Sken sbuf_hexdump(sb, cur_ptr, as_len, NULL, 0); 7048284435Sken } 7049284435Sken 7050284435Skenbailout: 7051284435Sken return (retval); 7052284435Sken} 7053284435Sken 7054284435Skenint 7055284435Skenscsi_attrib_vendser_sbuf(struct sbuf *sb, struct scsi_mam_attribute_header *hdr, 7056284435Sken uint32_t valid_len, uint32_t flags, 7057284435Sken uint32_t output_flags, char *error_str, 7058284435Sken int error_str_len) 7059284435Sken{ 7060284435Sken size_t avail_len; 7061284435Sken uint32_t field_size; 7062284435Sken struct scsi_attrib_vendser *vendser; 7063284435Sken cam_strvis_flags strvis_flags; 7064284435Sken int retval = 0; 7065284435Sken 7066284435Sken field_size = scsi_2btoul(hdr->length); 7067284435Sken avail_len = valid_len - sizeof(*hdr); 7068284435Sken if (field_size > avail_len) { 7069284435Sken if (error_str != NULL) { 7070284435Sken snprintf(error_str, error_str_len, "Available " 7071284435Sken "length of attribute ID 0x%.4x %zu < field " 7072284435Sken "length %u", scsi_2btoul(hdr->id), avail_len, 7073284435Sken field_size); 7074284435Sken } 7075284435Sken retval = 1; 7076284435Sken goto bailout; 7077284435Sken } else if (field_size == 0) { 7078284435Sken /* 7079284435Sken * A field size of 0 doesn't make sense here. The device 7080284435Sken * can at least give you the vendor ID, even if it can't 7081284435Sken * give you the serial number. 7082284435Sken */ 7083284435Sken if (error_str != NULL) { 7084284435Sken snprintf(error_str, error_str_len, "The length of " 7085284435Sken "attribute ID 0x%.4x is 0", 7086284435Sken scsi_2btoul(hdr->id)); 7087284435Sken } 7088284435Sken retval = 1; 7089284435Sken goto bailout; 7090284435Sken } 7091284435Sken vendser = (struct scsi_attrib_vendser *)hdr->attribute; 7092284435Sken 7093284435Sken switch (output_flags & SCSI_ATTR_OUTPUT_NONASCII_MASK) { 7094284435Sken case SCSI_ATTR_OUTPUT_NONASCII_TRIM: 7095284435Sken strvis_flags = CAM_STRVIS_FLAG_NONASCII_TRIM; 7096284435Sken break; 7097284435Sken case SCSI_ATTR_OUTPUT_NONASCII_RAW: 7098284435Sken strvis_flags = CAM_STRVIS_FLAG_NONASCII_RAW; 7099284435Sken break; 7100284435Sken case SCSI_ATTR_OUTPUT_NONASCII_ESC: 7101284435Sken default: 7102284435Sken strvis_flags = CAM_STRVIS_FLAG_NONASCII_ESC; 7103284435Sken break;; 7104284435Sken } 7105284435Sken cam_strvis_sbuf(sb, vendser->vendor, sizeof(vendser->vendor), 7106284435Sken strvis_flags); 7107284435Sken sbuf_putc(sb, ' '); 7108284435Sken cam_strvis_sbuf(sb, vendser->serial_num, sizeof(vendser->serial_num), 7109284435Sken strvis_flags); 7110284435Skenbailout: 7111284435Sken return (retval); 7112284435Sken} 7113284435Sken 7114284435Skenint 7115284435Skenscsi_attrib_hexdump_sbuf(struct sbuf *sb, struct scsi_mam_attribute_header *hdr, 7116284435Sken uint32_t valid_len, uint32_t flags, 7117284435Sken uint32_t output_flags, char *error_str, 7118284435Sken int error_str_len) 7119284435Sken{ 7120284435Sken uint32_t field_size; 7121284435Sken ssize_t avail_len; 7122284435Sken uint32_t print_len; 7123284435Sken uint8_t *num_ptr; 7124284435Sken int retval = 0; 7125284435Sken 7126284435Sken field_size = scsi_2btoul(hdr->length); 7127284435Sken avail_len = valid_len - sizeof(*hdr); 7128284435Sken print_len = MIN(avail_len, field_size); 7129284435Sken num_ptr = hdr->attribute; 7130284435Sken 7131284435Sken if (print_len > 0) { 7132284435Sken sbuf_printf(sb, "\n"); 7133284435Sken sbuf_hexdump(sb, num_ptr, print_len, NULL, 0); 7134284435Sken } 7135284435Sken 7136284435Sken return (retval); 7137284435Sken} 7138284435Sken 7139284435Skenint 7140284435Skenscsi_attrib_int_sbuf(struct sbuf *sb, struct scsi_mam_attribute_header *hdr, 7141284435Sken uint32_t valid_len, uint32_t flags, 7142284435Sken uint32_t output_flags, char *error_str, 7143284435Sken int error_str_len) 7144284435Sken{ 7145284435Sken uint64_t print_number; 7146284435Sken size_t avail_len; 7147284435Sken uint32_t number_size; 7148284435Sken int retval = 0; 7149284435Sken 7150284435Sken number_size = scsi_2btoul(hdr->length); 7151284435Sken 7152284435Sken avail_len = valid_len - sizeof(*hdr); 7153284435Sken if (avail_len < number_size) { 7154284435Sken if (error_str != NULL) { 7155284435Sken snprintf(error_str, error_str_len, "Available " 7156284435Sken "length of attribute ID 0x%.4x %zu < field " 7157284435Sken "length %u", scsi_2btoul(hdr->id), avail_len, 7158284435Sken number_size); 7159284435Sken } 7160284435Sken retval = 1; 7161284435Sken goto bailout; 7162284435Sken } 7163284435Sken 7164284435Sken switch (number_size) { 7165284435Sken case 0: 7166284435Sken /* 7167284435Sken * We don't treat this as an error, since there may be 7168284435Sken * scenarios where a device reports a field but then gives 7169284435Sken * a length of 0. See the note in scsi_attrib_ascii_sbuf(). 7170284435Sken */ 7171284435Sken goto bailout; 7172284435Sken break; /*NOTREACHED*/ 7173284435Sken case 1: 7174284435Sken print_number = hdr->attribute[0]; 7175284435Sken break; 7176284435Sken case 2: 7177284435Sken print_number = scsi_2btoul(hdr->attribute); 7178284435Sken break; 7179284435Sken case 3: 7180284435Sken print_number = scsi_3btoul(hdr->attribute); 7181284435Sken break; 7182284435Sken case 4: 7183284435Sken print_number = scsi_4btoul(hdr->attribute); 7184284435Sken break; 7185284435Sken case 8: 7186284435Sken print_number = scsi_8btou64(hdr->attribute); 7187284435Sken break; 7188284435Sken default: 7189284435Sken /* 7190284435Sken * If we wind up here, the number is too big to print 7191284435Sken * normally, so just do a hexdump. 7192284435Sken */ 7193284435Sken retval = scsi_attrib_hexdump_sbuf(sb, hdr, valid_len, 7194284435Sken flags, output_flags, 7195284435Sken error_str, error_str_len); 7196284435Sken goto bailout; 7197284435Sken break; 7198284435Sken } 7199284435Sken 7200284435Sken if (flags & SCSI_ATTR_FLAG_FP) { 7201284435Sken#ifndef _KERNEL 7202284435Sken long double num_float; 7203284435Sken 7204284435Sken num_float = (long double)print_number; 7205284435Sken 7206284435Sken if (flags & SCSI_ATTR_FLAG_DIV_10) 7207284435Sken num_float /= 10; 7208284435Sken 7209284435Sken sbuf_printf(sb, "%.*Lf", (flags & SCSI_ATTR_FLAG_FP_1DIGIT) ? 7210284435Sken 1 : 0, num_float); 7211284435Sken#else /* _KERNEL */ 7212284435Sken sbuf_printf(sb, "%ju", (flags & SCSI_ATTR_FLAG_DIV_10) ? 7213284435Sken (print_number / 10) : print_number); 7214284435Sken#endif /* _KERNEL */ 7215284435Sken } else if (flags & SCSI_ATTR_FLAG_HEX) { 7216284435Sken sbuf_printf(sb, "0x%jx", (uintmax_t)print_number); 7217284435Sken } else 7218284435Sken sbuf_printf(sb, "%ju", (uintmax_t)print_number); 7219284435Sken 7220284435Skenbailout: 7221284435Sken return (retval); 7222284435Sken} 7223284435Sken 7224284435Skenint 7225284435Skenscsi_attrib_ascii_sbuf(struct sbuf *sb, struct scsi_mam_attribute_header *hdr, 7226284435Sken uint32_t valid_len, uint32_t flags, 7227284435Sken uint32_t output_flags, char *error_str, 7228284435Sken int error_str_len) 7229284435Sken{ 7230284435Sken size_t avail_len; 7231284435Sken uint32_t field_size, print_size; 7232284435Sken int retval = 0; 7233284435Sken 7234284435Sken avail_len = valid_len - sizeof(*hdr); 7235284435Sken field_size = scsi_2btoul(hdr->length); 7236284435Sken print_size = MIN(avail_len, field_size); 7237284435Sken 7238284435Sken if (print_size > 0) { 7239284435Sken cam_strvis_flags strvis_flags; 7240284435Sken 7241284435Sken switch (output_flags & SCSI_ATTR_OUTPUT_NONASCII_MASK) { 7242284435Sken case SCSI_ATTR_OUTPUT_NONASCII_TRIM: 7243284435Sken strvis_flags = CAM_STRVIS_FLAG_NONASCII_TRIM; 7244284435Sken break; 7245284435Sken case SCSI_ATTR_OUTPUT_NONASCII_RAW: 7246284435Sken strvis_flags = CAM_STRVIS_FLAG_NONASCII_RAW; 7247284435Sken break; 7248284435Sken case SCSI_ATTR_OUTPUT_NONASCII_ESC: 7249284435Sken default: 7250284435Sken strvis_flags = CAM_STRVIS_FLAG_NONASCII_ESC; 7251284435Sken break; 7252284435Sken } 7253284435Sken cam_strvis_sbuf(sb, hdr->attribute, print_size, strvis_flags); 7254284435Sken } else if (avail_len < field_size) { 7255284435Sken /* 7256284435Sken * We only report an error if the user didn't allocate 7257284435Sken * enough space to hold the full value of this field. If 7258284435Sken * the field length is 0, that is allowed by the spec. 7259284435Sken * e.g. in SPC-4r37, section 7.4.2.2.5, VOLUME IDENTIFIER 7260284435Sken * "This attribute indicates the current volume identifier 7261284435Sken * (see SMC-3) of the medium. If the device server supports 7262284435Sken * this attribute but does not have access to the volume 7263284435Sken * identifier, the device server shall report this attribute 7264284435Sken * with an attribute length value of zero." 7265284435Sken */ 7266284435Sken if (error_str != NULL) { 7267284435Sken snprintf(error_str, error_str_len, "Available " 7268284435Sken "length of attribute ID 0x%.4x %zu < field " 7269284435Sken "length %u", scsi_2btoul(hdr->id), avail_len, 7270284435Sken field_size); 7271284435Sken } 7272284435Sken retval = 1; 7273284435Sken } 7274284435Sken 7275284435Sken return (retval); 7276284435Sken} 7277284435Sken 7278284435Skenint 7279284435Skenscsi_attrib_text_sbuf(struct sbuf *sb, struct scsi_mam_attribute_header *hdr, 7280284435Sken uint32_t valid_len, uint32_t flags, 7281284435Sken uint32_t output_flags, char *error_str, 7282284435Sken int error_str_len) 7283284435Sken{ 7284284435Sken size_t avail_len; 7285284435Sken uint32_t field_size, print_size; 7286284435Sken int retval = 0; 7287284435Sken int esc_text = 1; 7288284435Sken 7289284435Sken avail_len = valid_len - sizeof(*hdr); 7290284435Sken field_size = scsi_2btoul(hdr->length); 7291284435Sken print_size = MIN(avail_len, field_size); 7292284435Sken 7293284435Sken if ((output_flags & SCSI_ATTR_OUTPUT_TEXT_MASK) == 7294284435Sken SCSI_ATTR_OUTPUT_TEXT_RAW) 7295284435Sken esc_text = 0; 7296284435Sken 7297284435Sken if (print_size > 0) { 7298284435Sken uint32_t i; 7299284435Sken 7300284435Sken for (i = 0; i < print_size; i++) { 7301284435Sken if (hdr->attribute[i] == '\0') 7302284435Sken continue; 7303284435Sken else if (((unsigned char)hdr->attribute[i] < 0x80) 7304284435Sken || (esc_text == 0)) 7305284435Sken sbuf_putc(sb, hdr->attribute[i]); 7306284435Sken else 7307284435Sken sbuf_printf(sb, "%%%02x", 7308284435Sken (unsigned char)hdr->attribute[i]); 7309284435Sken } 7310284435Sken } else if (avail_len < field_size) { 7311284435Sken /* 7312284435Sken * We only report an error if the user didn't allocate 7313284435Sken * enough space to hold the full value of this field. 7314284435Sken */ 7315284435Sken if (error_str != NULL) { 7316284435Sken snprintf(error_str, error_str_len, "Available " 7317284435Sken "length of attribute ID 0x%.4x %zu < field " 7318284435Sken "length %u", scsi_2btoul(hdr->id), avail_len, 7319284435Sken field_size); 7320284435Sken } 7321284435Sken retval = 1; 7322284435Sken } 7323284435Sken 7324284435Sken return (retval); 7325284435Sken} 7326284435Sken 7327284435Skenstruct scsi_attrib_table_entry * 7328284435Skenscsi_find_attrib_entry(struct scsi_attrib_table_entry *table, 7329284435Sken size_t num_table_entries, uint32_t id) 7330284435Sken{ 7331284435Sken uint32_t i; 7332284435Sken 7333284435Sken for (i = 0; i < num_table_entries; i++) { 7334284435Sken if (table[i].id == id) 7335284435Sken return (&table[i]); 7336284435Sken } 7337284435Sken 7338284435Sken return (NULL); 7339284435Sken} 7340284435Sken 7341284435Skenstruct scsi_attrib_table_entry * 7342284435Skenscsi_get_attrib_entry(uint32_t id) 7343284435Sken{ 7344284435Sken return (scsi_find_attrib_entry(scsi_mam_attr_table, 7345284435Sken sizeof(scsi_mam_attr_table) / sizeof(scsi_mam_attr_table[0]), 7346284435Sken id)); 7347284435Sken} 7348284435Sken 7349284435Skenint 7350284435Skenscsi_attrib_value_sbuf(struct sbuf *sb, uint32_t valid_len, 7351284435Sken struct scsi_mam_attribute_header *hdr, uint32_t output_flags, 7352284435Sken char *error_str, size_t error_str_len) 7353284435Sken{ 7354284435Sken int retval; 7355284435Sken 7356284435Sken switch (hdr->byte2 & SMA_FORMAT_MASK) { 7357284435Sken case SMA_FORMAT_ASCII: 7358284435Sken retval = scsi_attrib_ascii_sbuf(sb, hdr, valid_len, 7359284435Sken SCSI_ATTR_FLAG_NONE, output_flags, error_str,error_str_len); 7360284435Sken break; 7361284435Sken case SMA_FORMAT_BINARY: 7362284435Sken if (scsi_2btoul(hdr->length) <= 8) 7363284435Sken retval = scsi_attrib_int_sbuf(sb, hdr, valid_len, 7364284435Sken SCSI_ATTR_FLAG_NONE, output_flags, error_str, 7365284435Sken error_str_len); 7366284435Sken else 7367284435Sken retval = scsi_attrib_hexdump_sbuf(sb, hdr, valid_len, 7368284435Sken SCSI_ATTR_FLAG_NONE, output_flags, error_str, 7369284435Sken error_str_len); 7370284435Sken break; 7371284435Sken case SMA_FORMAT_TEXT: 7372284435Sken retval = scsi_attrib_text_sbuf(sb, hdr, valid_len, 7373284435Sken SCSI_ATTR_FLAG_NONE, output_flags, error_str, 7374284435Sken error_str_len); 7375284435Sken break; 7376284435Sken default: 7377284435Sken if (error_str != NULL) { 7378284435Sken snprintf(error_str, error_str_len, "Unknown attribute " 7379284435Sken "format 0x%x", hdr->byte2 & SMA_FORMAT_MASK); 7380284435Sken } 7381284435Sken retval = 1; 7382284435Sken goto bailout; 7383284435Sken break; /*NOTREACHED*/ 7384284435Sken } 7385284435Sken 7386284435Sken sbuf_trim(sb); 7387284435Sken 7388284435Skenbailout: 7389284435Sken 7390284435Sken return (retval); 7391284435Sken} 7392284435Sken 739339213Sgibbsvoid 7394284435Skenscsi_attrib_prefix_sbuf(struct sbuf *sb, uint32_t output_flags, 7395284435Sken struct scsi_mam_attribute_header *hdr, 7396284435Sken uint32_t valid_len, const char *desc) 7397284435Sken{ 7398284435Sken int need_space = 0; 7399284435Sken uint32_t len; 7400284435Sken uint32_t id; 7401284435Sken 7402284435Sken /* 7403284435Sken * We can't do anything if we don't have enough valid data for the 7404284435Sken * header. 7405284435Sken */ 7406284435Sken if (valid_len < sizeof(*hdr)) 7407284435Sken return; 7408284435Sken 7409284435Sken id = scsi_2btoul(hdr->id); 7410284435Sken /* 7411284435Sken * Note that we print out the value of the attribute listed in the 7412284435Sken * header, regardless of whether we actually got that many bytes 7413284435Sken * back from the device through the controller. A truncated result 7414284435Sken * could be the result of a failure to ask for enough data; the 7415284435Sken * header indicates how many bytes are allocated for this attribute 7416284435Sken * in the MAM. 7417284435Sken */ 7418284435Sken len = scsi_2btoul(hdr->length); 7419284435Sken 7420284435Sken if ((output_flags & SCSI_ATTR_OUTPUT_FIELD_MASK) == 7421284435Sken SCSI_ATTR_OUTPUT_FIELD_NONE) 7422284435Sken return; 7423284435Sken 7424284435Sken if ((output_flags & SCSI_ATTR_OUTPUT_FIELD_DESC) 7425284435Sken && (desc != NULL)) { 7426284435Sken sbuf_printf(sb, "%s", desc); 7427284435Sken need_space = 1; 7428284435Sken } 7429284435Sken 7430284435Sken if (output_flags & SCSI_ATTR_OUTPUT_FIELD_NUM) { 7431284435Sken sbuf_printf(sb, "%s(0x%.4x)", (need_space) ? " " : "", id); 7432284435Sken need_space = 0; 7433284435Sken } 7434284435Sken 7435284435Sken if (output_flags & SCSI_ATTR_OUTPUT_FIELD_SIZE) { 7436284435Sken sbuf_printf(sb, "%s[%d]", (need_space) ? " " : "", len); 7437284435Sken need_space = 0; 7438284435Sken } 7439284435Sken if (output_flags & SCSI_ATTR_OUTPUT_FIELD_RW) { 7440284435Sken sbuf_printf(sb, "%s(%s)", (need_space) ? " " : "", 7441284435Sken (hdr->byte2 & SMA_READ_ONLY) ? "RO" : "RW"); 7442284435Sken } 7443284435Sken sbuf_printf(sb, ": "); 7444284435Sken} 7445284435Sken 7446284435Skenint 7447284435Skenscsi_attrib_sbuf(struct sbuf *sb, struct scsi_mam_attribute_header *hdr, 7448284435Sken uint32_t valid_len, struct scsi_attrib_table_entry *user_table, 7449284435Sken size_t num_user_entries, int prefer_user_table, 7450284435Sken uint32_t output_flags, char *error_str, int error_str_len) 7451284435Sken{ 7452284435Sken int retval; 7453284435Sken struct scsi_attrib_table_entry *table1 = NULL, *table2 = NULL; 7454284435Sken struct scsi_attrib_table_entry *entry = NULL; 7455284435Sken size_t table1_size = 0, table2_size = 0; 7456284435Sken uint32_t id; 7457284435Sken 7458284435Sken retval = 0; 7459284435Sken 7460284435Sken if (valid_len < sizeof(*hdr)) { 7461284435Sken retval = 1; 7462284435Sken goto bailout; 7463284435Sken } 7464284435Sken 7465284435Sken id = scsi_2btoul(hdr->id); 7466284435Sken 7467284435Sken if (user_table != NULL) { 7468284435Sken if (prefer_user_table != 0) { 7469284435Sken table1 = user_table; 7470284435Sken table1_size = num_user_entries; 7471284435Sken table2 = scsi_mam_attr_table; 7472284435Sken table2_size = sizeof(scsi_mam_attr_table) / 7473284435Sken sizeof(scsi_mam_attr_table[0]); 7474284435Sken } else { 7475284435Sken table1 = scsi_mam_attr_table; 7476284435Sken table1_size = sizeof(scsi_mam_attr_table) / 7477284435Sken sizeof(scsi_mam_attr_table[0]); 7478284435Sken table2 = user_table; 7479284435Sken table2_size = num_user_entries; 7480284435Sken } 7481284435Sken } else { 7482284435Sken table1 = scsi_mam_attr_table; 7483284435Sken table1_size = sizeof(scsi_mam_attr_table) / 7484284435Sken sizeof(scsi_mam_attr_table[0]); 7485284435Sken } 7486284435Sken 7487284435Sken entry = scsi_find_attrib_entry(table1, table1_size, id); 7488284435Sken if (entry != NULL) { 7489284435Sken scsi_attrib_prefix_sbuf(sb, output_flags, hdr, valid_len, 7490284435Sken entry->desc); 7491284435Sken if (entry->to_str == NULL) 7492284435Sken goto print_default; 7493284435Sken retval = entry->to_str(sb, hdr, valid_len, entry->flags, 7494284435Sken output_flags, error_str, error_str_len); 7495284435Sken goto bailout; 7496284435Sken } 7497284435Sken if (table2 != NULL) { 7498284435Sken entry = scsi_find_attrib_entry(table2, table2_size, id); 7499284435Sken if (entry != NULL) { 7500284435Sken if (entry->to_str == NULL) 7501284435Sken goto print_default; 7502284435Sken 7503284435Sken scsi_attrib_prefix_sbuf(sb, output_flags, hdr, 7504284435Sken valid_len, entry->desc); 7505284435Sken retval = entry->to_str(sb, hdr, valid_len, entry->flags, 7506284435Sken output_flags, error_str, 7507284435Sken error_str_len); 7508284435Sken goto bailout; 7509284435Sken } 7510284435Sken } 7511284435Sken 7512284435Sken scsi_attrib_prefix_sbuf(sb, output_flags, hdr, valid_len, NULL); 7513284435Sken 7514284435Skenprint_default: 7515284435Sken retval = scsi_attrib_value_sbuf(sb, valid_len, hdr, output_flags, 7516284435Sken error_str, error_str_len); 7517284435Skenbailout: 7518284435Sken if (retval == 0) { 7519284435Sken if ((entry != NULL) 7520284435Sken && (entry->suffix != NULL)) 7521284435Sken sbuf_printf(sb, " %s", entry->suffix); 7522284435Sken 7523284435Sken sbuf_trim(sb); 7524284435Sken sbuf_printf(sb, "\n"); 7525284435Sken } 7526284435Sken 7527284435Sken return (retval); 7528284435Sken} 7529284435Sken 7530284435Skenvoid 753139213Sgibbsscsi_test_unit_ready(struct ccb_scsiio *csio, u_int32_t retries, 753239213Sgibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 753339213Sgibbs u_int8_t tag_action, u_int8_t sense_len, u_int32_t timeout) 753439213Sgibbs{ 753539213Sgibbs struct scsi_test_unit_ready *scsi_cmd; 753639213Sgibbs 753739213Sgibbs cam_fill_csio(csio, 753839213Sgibbs retries, 753939213Sgibbs cbfcnp, 754039213Sgibbs CAM_DIR_NONE, 754139213Sgibbs tag_action, 754239213Sgibbs /*data_ptr*/NULL, 754339213Sgibbs /*dxfer_len*/0, 754439213Sgibbs sense_len, 754539213Sgibbs sizeof(*scsi_cmd), 754639213Sgibbs timeout); 754739213Sgibbs 754839213Sgibbs scsi_cmd = (struct scsi_test_unit_ready *)&csio->cdb_io.cdb_bytes; 754939213Sgibbs bzero(scsi_cmd, sizeof(*scsi_cmd)); 755039213Sgibbs scsi_cmd->opcode = TEST_UNIT_READY; 755139213Sgibbs} 755239213Sgibbs 755339213Sgibbsvoid 755439213Sgibbsscsi_request_sense(struct ccb_scsiio *csio, u_int32_t retries, 755539213Sgibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 755639213Sgibbs void *data_ptr, u_int8_t dxfer_len, u_int8_t tag_action, 755739213Sgibbs u_int8_t sense_len, u_int32_t timeout) 755839213Sgibbs{ 755939213Sgibbs struct scsi_request_sense *scsi_cmd; 756039213Sgibbs 756139213Sgibbs cam_fill_csio(csio, 756239213Sgibbs retries, 756339213Sgibbs cbfcnp, 756439213Sgibbs CAM_DIR_IN, 756539213Sgibbs tag_action, 756639213Sgibbs data_ptr, 756739213Sgibbs dxfer_len, 756839213Sgibbs sense_len, 756939213Sgibbs sizeof(*scsi_cmd), 757039213Sgibbs timeout); 757139213Sgibbs 757239213Sgibbs scsi_cmd = (struct scsi_request_sense *)&csio->cdb_io.cdb_bytes; 757339213Sgibbs bzero(scsi_cmd, sizeof(*scsi_cmd)); 757439213Sgibbs scsi_cmd->opcode = REQUEST_SENSE; 7575120314Sthomas scsi_cmd->length = dxfer_len; 757639213Sgibbs} 757739213Sgibbs 757839213Sgibbsvoid 757939213Sgibbsscsi_inquiry(struct ccb_scsiio *csio, u_int32_t retries, 758039213Sgibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 758139213Sgibbs u_int8_t tag_action, u_int8_t *inq_buf, u_int32_t inq_len, 758239213Sgibbs int evpd, u_int8_t page_code, u_int8_t sense_len, 758339213Sgibbs u_int32_t timeout) 758439213Sgibbs{ 758539213Sgibbs struct scsi_inquiry *scsi_cmd; 758639213Sgibbs 758739213Sgibbs cam_fill_csio(csio, 758839213Sgibbs retries, 758939213Sgibbs cbfcnp, 759039213Sgibbs /*flags*/CAM_DIR_IN, 759139213Sgibbs tag_action, 759239213Sgibbs /*data_ptr*/inq_buf, 759339213Sgibbs /*dxfer_len*/inq_len, 759439213Sgibbs sense_len, 759539213Sgibbs sizeof(*scsi_cmd), 759639213Sgibbs timeout); 759739213Sgibbs 759839213Sgibbs scsi_cmd = (struct scsi_inquiry *)&csio->cdb_io.cdb_bytes; 759939213Sgibbs bzero(scsi_cmd, sizeof(*scsi_cmd)); 760039213Sgibbs scsi_cmd->opcode = INQUIRY; 760139213Sgibbs if (evpd) { 760239213Sgibbs scsi_cmd->byte2 |= SI_EVPD; 760339213Sgibbs scsi_cmd->page_code = page_code; 760439213Sgibbs } 7605229997Sken scsi_ulto2b(inq_len, scsi_cmd->length); 760639213Sgibbs} 760739213Sgibbs 760839213Sgibbsvoid 7609312567Smavscsi_mode_sense(struct ccb_scsiio *csio, uint32_t retries, 7610312567Smav void (*cbfcnp)(struct cam_periph *, union ccb *), uint8_t tag_action, 7611312567Smav int dbd, uint8_t pc, uint8_t page, uint8_t *param_buf, uint32_t param_len, 7612312567Smav uint8_t sense_len, uint32_t timeout) 761339213Sgibbs{ 7614115454Sphk 7615312567Smav scsi_mode_sense_subpage(csio, retries, cbfcnp, tag_action, dbd, 7616312567Smav pc, page, 0, param_buf, param_len, 0, sense_len, timeout); 7617111206Sken} 7618115454Sphk 7619111206Skenvoid 7620312567Smavscsi_mode_sense_len(struct ccb_scsiio *csio, uint32_t retries, 7621312567Smav void (*cbfcnp)(struct cam_periph *, union ccb *), uint8_t tag_action, 7622312567Smav int dbd, uint8_t pc, uint8_t page, uint8_t *param_buf, uint32_t param_len, 7623312567Smav int minimum_cmd_size, uint8_t sense_len, uint32_t timeout) 7624111206Sken{ 7625312567Smav 7626312567Smav scsi_mode_sense_subpage(csio, retries, cbfcnp, tag_action, dbd, 7627312567Smav pc, page, 0, param_buf, param_len, minimum_cmd_size, 7628312567Smav sense_len, timeout); 7629312567Smav} 7630312567Smav 7631312567Smavvoid 7632312567Smavscsi_mode_sense_subpage(struct ccb_scsiio *csio, uint32_t retries, 7633312567Smav void (*cbfcnp)(struct cam_periph *, union ccb *), uint8_t tag_action, 7634312567Smav int dbd, uint8_t pc, uint8_t page, uint8_t subpage, uint8_t *param_buf, 7635312567Smav uint32_t param_len, int minimum_cmd_size, uint8_t sense_len, 7636312567Smav uint32_t timeout) 7637312567Smav{ 763839213Sgibbs u_int8_t cdb_len; 763939213Sgibbs 764039213Sgibbs /* 764139213Sgibbs * Use the smallest possible command to perform the operation. 764239213Sgibbs */ 7643111206Sken if ((param_len < 256) 7644111206Sken && (minimum_cmd_size < 10)) { 764539213Sgibbs /* 764639213Sgibbs * We can fit in a 6 byte cdb. 764739213Sgibbs */ 764839213Sgibbs struct scsi_mode_sense_6 *scsi_cmd; 764939213Sgibbs 765039213Sgibbs scsi_cmd = (struct scsi_mode_sense_6 *)&csio->cdb_io.cdb_bytes; 765139213Sgibbs bzero(scsi_cmd, sizeof(*scsi_cmd)); 765239213Sgibbs scsi_cmd->opcode = MODE_SENSE_6; 765339213Sgibbs if (dbd != 0) 765439213Sgibbs scsi_cmd->byte2 |= SMS_DBD; 7655312567Smav scsi_cmd->page = pc | page; 7656312567Smav scsi_cmd->subpage = subpage; 765739213Sgibbs scsi_cmd->length = param_len; 765839213Sgibbs cdb_len = sizeof(*scsi_cmd); 765939213Sgibbs } else { 766039213Sgibbs /* 766139213Sgibbs * Need a 10 byte cdb. 766239213Sgibbs */ 766339213Sgibbs struct scsi_mode_sense_10 *scsi_cmd; 766439213Sgibbs 766539213Sgibbs scsi_cmd = (struct scsi_mode_sense_10 *)&csio->cdb_io.cdb_bytes; 766639213Sgibbs bzero(scsi_cmd, sizeof(*scsi_cmd)); 766739213Sgibbs scsi_cmd->opcode = MODE_SENSE_10; 766839213Sgibbs if (dbd != 0) 766939213Sgibbs scsi_cmd->byte2 |= SMS_DBD; 7670312567Smav scsi_cmd->page = pc | page; 7671312567Smav scsi_cmd->subpage = subpage; 767239213Sgibbs scsi_ulto2b(param_len, scsi_cmd->length); 767339213Sgibbs cdb_len = sizeof(*scsi_cmd); 767439213Sgibbs } 767539213Sgibbs cam_fill_csio(csio, 767639213Sgibbs retries, 767739213Sgibbs cbfcnp, 767839213Sgibbs CAM_DIR_IN, 767939213Sgibbs tag_action, 768039213Sgibbs param_buf, 768139213Sgibbs param_len, 768239213Sgibbs sense_len, 768339213Sgibbs cdb_len, 768439213Sgibbs timeout); 768539213Sgibbs} 768639213Sgibbs 768739213Sgibbsvoid 768839213Sgibbsscsi_mode_select(struct ccb_scsiio *csio, u_int32_t retries, 768939213Sgibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 769039213Sgibbs u_int8_t tag_action, int scsi_page_fmt, int save_pages, 769139213Sgibbs u_int8_t *param_buf, u_int32_t param_len, u_int8_t sense_len, 769239213Sgibbs u_int32_t timeout) 769339213Sgibbs{ 7694115454Sphk scsi_mode_select_len(csio, retries, cbfcnp, tag_action, 7695115454Sphk scsi_page_fmt, save_pages, param_buf, 7696115454Sphk param_len, 0, sense_len, timeout); 7697111206Sken} 7698111206Sken 7699111206Skenvoid 7700111206Skenscsi_mode_select_len(struct ccb_scsiio *csio, u_int32_t retries, 7701111206Sken void (*cbfcnp)(struct cam_periph *, union ccb *), 7702111206Sken u_int8_t tag_action, int scsi_page_fmt, int save_pages, 7703111206Sken u_int8_t *param_buf, u_int32_t param_len, 7704111206Sken int minimum_cmd_size, u_int8_t sense_len, 7705111206Sken u_int32_t timeout) 7706111206Sken{ 770739213Sgibbs u_int8_t cdb_len; 770839213Sgibbs 770939213Sgibbs /* 771039213Sgibbs * Use the smallest possible command to perform the operation. 771139213Sgibbs */ 7712111206Sken if ((param_len < 256) 7713111206Sken && (minimum_cmd_size < 10)) { 771439213Sgibbs /* 771539213Sgibbs * We can fit in a 6 byte cdb. 771639213Sgibbs */ 771739213Sgibbs struct scsi_mode_select_6 *scsi_cmd; 771839213Sgibbs 771939213Sgibbs scsi_cmd = (struct scsi_mode_select_6 *)&csio->cdb_io.cdb_bytes; 772039213Sgibbs bzero(scsi_cmd, sizeof(*scsi_cmd)); 772139213Sgibbs scsi_cmd->opcode = MODE_SELECT_6; 772239213Sgibbs if (scsi_page_fmt != 0) 772339213Sgibbs scsi_cmd->byte2 |= SMS_PF; 772439213Sgibbs if (save_pages != 0) 772539213Sgibbs scsi_cmd->byte2 |= SMS_SP; 772639213Sgibbs scsi_cmd->length = param_len; 772739213Sgibbs cdb_len = sizeof(*scsi_cmd); 772839213Sgibbs } else { 772939213Sgibbs /* 773039213Sgibbs * Need a 10 byte cdb. 773139213Sgibbs */ 773239213Sgibbs struct scsi_mode_select_10 *scsi_cmd; 773339213Sgibbs 773439213Sgibbs scsi_cmd = 773539213Sgibbs (struct scsi_mode_select_10 *)&csio->cdb_io.cdb_bytes; 773639213Sgibbs bzero(scsi_cmd, sizeof(*scsi_cmd)); 773739213Sgibbs scsi_cmd->opcode = MODE_SELECT_10; 773839213Sgibbs if (scsi_page_fmt != 0) 773939213Sgibbs scsi_cmd->byte2 |= SMS_PF; 774039213Sgibbs if (save_pages != 0) 774139213Sgibbs scsi_cmd->byte2 |= SMS_SP; 774239213Sgibbs scsi_ulto2b(param_len, scsi_cmd->length); 774339213Sgibbs cdb_len = sizeof(*scsi_cmd); 774439213Sgibbs } 774539213Sgibbs cam_fill_csio(csio, 774639213Sgibbs retries, 774739213Sgibbs cbfcnp, 774839213Sgibbs CAM_DIR_OUT, 774939213Sgibbs tag_action, 775039213Sgibbs param_buf, 775139213Sgibbs param_len, 775239213Sgibbs sense_len, 775339213Sgibbs cdb_len, 775439213Sgibbs timeout); 775539213Sgibbs} 775639213Sgibbs 775782384Skbyancvoid 775882384Skbyancscsi_log_sense(struct ccb_scsiio *csio, u_int32_t retries, 775982384Skbyanc void (*cbfcnp)(struct cam_periph *, union ccb *), 776082384Skbyanc u_int8_t tag_action, u_int8_t page_code, u_int8_t page, 776182384Skbyanc int save_pages, int ppc, u_int32_t paramptr, 776282384Skbyanc u_int8_t *param_buf, u_int32_t param_len, u_int8_t sense_len, 776382384Skbyanc u_int32_t timeout) 776482384Skbyanc{ 776582384Skbyanc struct scsi_log_sense *scsi_cmd; 776682384Skbyanc u_int8_t cdb_len; 776739213Sgibbs 776882384Skbyanc scsi_cmd = (struct scsi_log_sense *)&csio->cdb_io.cdb_bytes; 776982384Skbyanc bzero(scsi_cmd, sizeof(*scsi_cmd)); 777082384Skbyanc scsi_cmd->opcode = LOG_SENSE; 777182384Skbyanc scsi_cmd->page = page_code | page; 777282384Skbyanc if (save_pages != 0) 777382384Skbyanc scsi_cmd->byte2 |= SLS_SP; 777482384Skbyanc if (ppc != 0) 777582384Skbyanc scsi_cmd->byte2 |= SLS_PPC; 777682384Skbyanc scsi_ulto2b(paramptr, scsi_cmd->paramptr); 777782384Skbyanc scsi_ulto2b(param_len, scsi_cmd->length); 777882384Skbyanc cdb_len = sizeof(*scsi_cmd); 777982384Skbyanc 778082384Skbyanc cam_fill_csio(csio, 778182384Skbyanc retries, 778282384Skbyanc cbfcnp, 778382384Skbyanc /*flags*/CAM_DIR_IN, 778482384Skbyanc tag_action, 778582384Skbyanc /*data_ptr*/param_buf, 778682384Skbyanc /*dxfer_len*/param_len, 778782384Skbyanc sense_len, 778882384Skbyanc cdb_len, 778982384Skbyanc timeout); 779082384Skbyanc} 779182384Skbyanc 779282384Skbyancvoid 779382384Skbyancscsi_log_select(struct ccb_scsiio *csio, u_int32_t retries, 779482384Skbyanc void (*cbfcnp)(struct cam_periph *, union ccb *), 779582384Skbyanc u_int8_t tag_action, u_int8_t page_code, int save_pages, 779682384Skbyanc int pc_reset, u_int8_t *param_buf, u_int32_t param_len, 779782384Skbyanc u_int8_t sense_len, u_int32_t timeout) 779882384Skbyanc{ 779982384Skbyanc struct scsi_log_select *scsi_cmd; 780082384Skbyanc u_int8_t cdb_len; 780182384Skbyanc 780282384Skbyanc scsi_cmd = (struct scsi_log_select *)&csio->cdb_io.cdb_bytes; 780382384Skbyanc bzero(scsi_cmd, sizeof(*scsi_cmd)); 780482384Skbyanc scsi_cmd->opcode = LOG_SELECT; 780582384Skbyanc scsi_cmd->page = page_code & SLS_PAGE_CODE; 780682384Skbyanc if (save_pages != 0) 780782384Skbyanc scsi_cmd->byte2 |= SLS_SP; 780882384Skbyanc if (pc_reset != 0) 780982384Skbyanc scsi_cmd->byte2 |= SLS_PCR; 781082384Skbyanc scsi_ulto2b(param_len, scsi_cmd->length); 781182384Skbyanc cdb_len = sizeof(*scsi_cmd); 781282384Skbyanc 781382384Skbyanc cam_fill_csio(csio, 781482384Skbyanc retries, 781582384Skbyanc cbfcnp, 781682384Skbyanc /*flags*/CAM_DIR_OUT, 781782384Skbyanc tag_action, 781882384Skbyanc /*data_ptr*/param_buf, 781982384Skbyanc /*dxfer_len*/param_len, 782082384Skbyanc sense_len, 782182384Skbyanc cdb_len, 782282384Skbyanc timeout); 782382384Skbyanc} 782482384Skbyanc 782597825Smjacob/* 782697825Smjacob * Prevent or allow the user to remove the media 782797825Smjacob */ 782897825Smjacobvoid 782997825Smjacobscsi_prevent(struct ccb_scsiio *csio, u_int32_t retries, 783097825Smjacob void (*cbfcnp)(struct cam_periph *, union ccb *), 783197825Smjacob u_int8_t tag_action, u_int8_t action, 783297825Smjacob u_int8_t sense_len, u_int32_t timeout) 783397825Smjacob{ 783497825Smjacob struct scsi_prevent *scsi_cmd; 783597825Smjacob 783697825Smjacob cam_fill_csio(csio, 783797825Smjacob retries, 783897825Smjacob cbfcnp, 783997825Smjacob /*flags*/CAM_DIR_NONE, 784097825Smjacob tag_action, 784197825Smjacob /*data_ptr*/NULL, 784297825Smjacob /*dxfer_len*/0, 784397825Smjacob sense_len, 784497825Smjacob sizeof(*scsi_cmd), 784597825Smjacob timeout); 784697825Smjacob 784797825Smjacob scsi_cmd = (struct scsi_prevent *)&csio->cdb_io.cdb_bytes; 784897825Smjacob bzero(scsi_cmd, sizeof(*scsi_cmd)); 784997825Smjacob scsi_cmd->opcode = PREVENT_ALLOW; 785097825Smjacob scsi_cmd->how = action; 785197825Smjacob} 785297825Smjacob 785339213Sgibbs/* XXX allow specification of address and PMI bit and LBA */ 785439213Sgibbsvoid 785539213Sgibbsscsi_read_capacity(struct ccb_scsiio *csio, u_int32_t retries, 785639213Sgibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 785739213Sgibbs u_int8_t tag_action, 785839213Sgibbs struct scsi_read_capacity_data *rcap_buf, 785939213Sgibbs u_int8_t sense_len, u_int32_t timeout) 786039213Sgibbs{ 786139213Sgibbs struct scsi_read_capacity *scsi_cmd; 786239213Sgibbs 786339213Sgibbs cam_fill_csio(csio, 786439213Sgibbs retries, 786539213Sgibbs cbfcnp, 786639213Sgibbs /*flags*/CAM_DIR_IN, 786739213Sgibbs tag_action, 786839213Sgibbs /*data_ptr*/(u_int8_t *)rcap_buf, 786939213Sgibbs /*dxfer_len*/sizeof(*rcap_buf), 787039213Sgibbs sense_len, 787139213Sgibbs sizeof(*scsi_cmd), 787239213Sgibbs timeout); 787339213Sgibbs 787439213Sgibbs scsi_cmd = (struct scsi_read_capacity *)&csio->cdb_io.cdb_bytes; 787539213Sgibbs bzero(scsi_cmd, sizeof(*scsi_cmd)); 787639213Sgibbs scsi_cmd->opcode = READ_CAPACITY; 787739213Sgibbs} 787839213Sgibbs 787939213Sgibbsvoid 7880114261Skenscsi_read_capacity_16(struct ccb_scsiio *csio, uint32_t retries, 7881114261Sken void (*cbfcnp)(struct cam_periph *, union ccb *), 7882114261Sken uint8_t tag_action, uint64_t lba, int reladr, int pmi, 7883230590Sken uint8_t *rcap_buf, int rcap_buf_len, uint8_t sense_len, 7884230590Sken uint32_t timeout) 7885114261Sken{ 7886114261Sken struct scsi_read_capacity_16 *scsi_cmd; 7887114261Sken 7888114261Sken 7889114261Sken cam_fill_csio(csio, 7890114261Sken retries, 7891114261Sken cbfcnp, 7892114261Sken /*flags*/CAM_DIR_IN, 7893114261Sken tag_action, 7894114261Sken /*data_ptr*/(u_int8_t *)rcap_buf, 7895230590Sken /*dxfer_len*/rcap_buf_len, 7896114261Sken sense_len, 7897114261Sken sizeof(*scsi_cmd), 7898114261Sken timeout); 7899114261Sken scsi_cmd = (struct scsi_read_capacity_16 *)&csio->cdb_io.cdb_bytes; 7900114261Sken bzero(scsi_cmd, sizeof(*scsi_cmd)); 7901114261Sken scsi_cmd->opcode = SERVICE_ACTION_IN; 7902114261Sken scsi_cmd->service_action = SRC16_SERVICE_ACTION; 7903114261Sken scsi_u64to8b(lba, scsi_cmd->addr); 7904230590Sken scsi_ulto4b(rcap_buf_len, scsi_cmd->alloc_len); 7905114261Sken if (pmi) 7906114261Sken reladr |= SRC16_PMI; 7907114261Sken if (reladr) 7908114261Sken reladr |= SRC16_RELADR; 7909114261Sken} 7910114261Sken 7911114261Skenvoid 791297825Smjacobscsi_report_luns(struct ccb_scsiio *csio, u_int32_t retries, 791397825Smjacob void (*cbfcnp)(struct cam_periph *, union ccb *), 7914161506Sken u_int8_t tag_action, u_int8_t select_report, 7915161506Sken struct scsi_report_luns_data *rpl_buf, u_int32_t alloc_len, 7916161506Sken u_int8_t sense_len, u_int32_t timeout) 791739213Sgibbs{ 791897825Smjacob struct scsi_report_luns *scsi_cmd; 791939213Sgibbs 792039213Sgibbs cam_fill_csio(csio, 792139213Sgibbs retries, 792239213Sgibbs cbfcnp, 792397825Smjacob /*flags*/CAM_DIR_IN, 792439213Sgibbs tag_action, 792597825Smjacob /*data_ptr*/(u_int8_t *)rpl_buf, 792697825Smjacob /*dxfer_len*/alloc_len, 792739213Sgibbs sense_len, 792839213Sgibbs sizeof(*scsi_cmd), 792939213Sgibbs timeout); 793097825Smjacob scsi_cmd = (struct scsi_report_luns *)&csio->cdb_io.cdb_bytes; 793139213Sgibbs bzero(scsi_cmd, sizeof(*scsi_cmd)); 793297825Smjacob scsi_cmd->opcode = REPORT_LUNS; 7933161506Sken scsi_cmd->select_report = select_report; 7934161506Sken scsi_ulto4b(alloc_len, scsi_cmd->length); 793539213Sgibbs} 793639213Sgibbs 7937208905Smjacobvoid 7938208905Smjacobscsi_report_target_group(struct ccb_scsiio *csio, u_int32_t retries, 7939208905Smjacob void (*cbfcnp)(struct cam_periph *, union ccb *), 7940208905Smjacob u_int8_t tag_action, u_int8_t pdf, 7941208905Smjacob void *buf, u_int32_t alloc_len, 7942208905Smjacob u_int8_t sense_len, u_int32_t timeout) 7943208905Smjacob{ 7944208905Smjacob struct scsi_target_group *scsi_cmd; 7945208905Smjacob 7946208905Smjacob cam_fill_csio(csio, 7947208905Smjacob retries, 7948208905Smjacob cbfcnp, 7949208905Smjacob /*flags*/CAM_DIR_IN, 7950208905Smjacob tag_action, 7951208905Smjacob /*data_ptr*/(u_int8_t *)buf, 7952208905Smjacob /*dxfer_len*/alloc_len, 7953208905Smjacob sense_len, 7954208905Smjacob sizeof(*scsi_cmd), 7955208905Smjacob timeout); 7956208905Smjacob scsi_cmd = (struct scsi_target_group *)&csio->cdb_io.cdb_bytes; 7957208905Smjacob bzero(scsi_cmd, sizeof(*scsi_cmd)); 7958208905Smjacob scsi_cmd->opcode = MAINTENANCE_IN; 7959208905Smjacob scsi_cmd->service_action = REPORT_TARGET_PORT_GROUPS | pdf; 7960208905Smjacob scsi_ulto4b(alloc_len, scsi_cmd->length); 7961208905Smjacob} 7962208905Smjacob 7963208905Smjacobvoid 7964208905Smjacobscsi_set_target_group(struct ccb_scsiio *csio, u_int32_t retries, 7965208905Smjacob void (*cbfcnp)(struct cam_periph *, union ccb *), 7966208905Smjacob u_int8_t tag_action, void *buf, u_int32_t alloc_len, 7967208905Smjacob u_int8_t sense_len, u_int32_t timeout) 7968208905Smjacob{ 7969208905Smjacob struct scsi_target_group *scsi_cmd; 7970208905Smjacob 7971208905Smjacob cam_fill_csio(csio, 7972208905Smjacob retries, 7973208905Smjacob cbfcnp, 7974208905Smjacob /*flags*/CAM_DIR_OUT, 7975208905Smjacob tag_action, 7976208905Smjacob /*data_ptr*/(u_int8_t *)buf, 7977208905Smjacob /*dxfer_len*/alloc_len, 7978208905Smjacob sense_len, 7979208905Smjacob sizeof(*scsi_cmd), 7980208905Smjacob timeout); 7981208905Smjacob scsi_cmd = (struct scsi_target_group *)&csio->cdb_io.cdb_bytes; 7982208905Smjacob bzero(scsi_cmd, sizeof(*scsi_cmd)); 7983208905Smjacob scsi_cmd->opcode = MAINTENANCE_OUT; 7984208905Smjacob scsi_cmd->service_action = SET_TARGET_PORT_GROUPS; 7985208905Smjacob scsi_ulto4b(alloc_len, scsi_cmd->length); 7986208905Smjacob} 7987208905Smjacob 798839213Sgibbs/* 798939213Sgibbs * Syncronize the media to the contents of the cache for 799039213Sgibbs * the given lba/count pair. Specifying 0/0 means sync 799139213Sgibbs * the whole cache. 799239213Sgibbs */ 799339213Sgibbsvoid 799439213Sgibbsscsi_synchronize_cache(struct ccb_scsiio *csio, u_int32_t retries, 799539213Sgibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 799639213Sgibbs u_int8_t tag_action, u_int32_t begin_lba, 799739213Sgibbs u_int16_t lb_count, u_int8_t sense_len, 799839213Sgibbs u_int32_t timeout) 799939213Sgibbs{ 800039213Sgibbs struct scsi_sync_cache *scsi_cmd; 800139213Sgibbs 800239213Sgibbs cam_fill_csio(csio, 800339213Sgibbs retries, 800439213Sgibbs cbfcnp, 800539213Sgibbs /*flags*/CAM_DIR_NONE, 800639213Sgibbs tag_action, 800739213Sgibbs /*data_ptr*/NULL, 800839213Sgibbs /*dxfer_len*/0, 800939213Sgibbs sense_len, 801039213Sgibbs sizeof(*scsi_cmd), 801139213Sgibbs timeout); 801239213Sgibbs 801339213Sgibbs scsi_cmd = (struct scsi_sync_cache *)&csio->cdb_io.cdb_bytes; 801439213Sgibbs bzero(scsi_cmd, sizeof(*scsi_cmd)); 801539213Sgibbs scsi_cmd->opcode = SYNCHRONIZE_CACHE; 801639213Sgibbs scsi_ulto4b(begin_lba, scsi_cmd->begin_lba); 801739213Sgibbs scsi_ulto2b(lb_count, scsi_cmd->lb_count); 801839213Sgibbs} 801939213Sgibbs 802039466Skenvoid 802139466Skenscsi_read_write(struct ccb_scsiio *csio, u_int32_t retries, 802239466Sken void (*cbfcnp)(struct cam_periph *, union ccb *), 802339466Sken u_int8_t tag_action, int readop, u_int8_t byte2, 8024114261Sken int minimum_cmd_size, u_int64_t lba, u_int32_t block_count, 802539466Sken u_int8_t *data_ptr, u_int32_t dxfer_len, u_int8_t sense_len, 802639466Sken u_int32_t timeout) 802739466Sken{ 8028248519Skib int read; 802939466Sken u_int8_t cdb_len; 8030248519Skib 8031248519Skib read = (readop & SCSI_RW_DIRMASK) == SCSI_RW_READ; 8032248519Skib 803339466Sken /* 803439466Sken * Use the smallest possible command to perform the operation 803586161Skbyanc * as some legacy hardware does not support the 10 byte commands. 803686161Skbyanc * If any of the bits in byte2 is set, we have to go with a larger 803786161Skbyanc * command. 803839466Sken */ 803939466Sken if ((minimum_cmd_size < 10) 804039466Sken && ((lba & 0x1fffff) == lba) 804139466Sken && ((block_count & 0xff) == block_count) 804286161Skbyanc && (byte2 == 0)) { 804339466Sken /* 804439466Sken * We can fit in a 6 byte cdb. 804539466Sken */ 804639466Sken struct scsi_rw_6 *scsi_cmd; 804739466Sken 804839466Sken scsi_cmd = (struct scsi_rw_6 *)&csio->cdb_io.cdb_bytes; 8049248519Skib scsi_cmd->opcode = read ? READ_6 : WRITE_6; 805039466Sken scsi_ulto3b(lba, scsi_cmd->addr); 805139466Sken scsi_cmd->length = block_count & 0xff; 805239466Sken scsi_cmd->control = 0; 805339466Sken cdb_len = sizeof(*scsi_cmd); 805439466Sken 805539466Sken CAM_DEBUG(csio->ccb_h.path, CAM_DEBUG_SUBTRACE, 805639466Sken ("6byte: %x%x%x:%d:%d\n", scsi_cmd->addr[0], 805739466Sken scsi_cmd->addr[1], scsi_cmd->addr[2], 805839466Sken scsi_cmd->length, dxfer_len)); 805939466Sken } else if ((minimum_cmd_size < 12) 8060114261Sken && ((block_count & 0xffff) == block_count) 8061114261Sken && ((lba & 0xffffffff) == lba)) { 806239466Sken /* 806339466Sken * Need a 10 byte cdb. 806439466Sken */ 806539466Sken struct scsi_rw_10 *scsi_cmd; 806639466Sken 806739466Sken scsi_cmd = (struct scsi_rw_10 *)&csio->cdb_io.cdb_bytes; 8068248519Skib scsi_cmd->opcode = read ? READ_10 : WRITE_10; 806939466Sken scsi_cmd->byte2 = byte2; 807039466Sken scsi_ulto4b(lba, scsi_cmd->addr); 807139466Sken scsi_cmd->reserved = 0; 807239466Sken scsi_ulto2b(block_count, scsi_cmd->length); 807339466Sken scsi_cmd->control = 0; 807439466Sken cdb_len = sizeof(*scsi_cmd); 807539466Sken 807639466Sken CAM_DEBUG(csio->ccb_h.path, CAM_DEBUG_SUBTRACE, 807739466Sken ("10byte: %x%x%x%x:%x%x: %d\n", scsi_cmd->addr[0], 807839466Sken scsi_cmd->addr[1], scsi_cmd->addr[2], 807939466Sken scsi_cmd->addr[3], scsi_cmd->length[0], 808039466Sken scsi_cmd->length[1], dxfer_len)); 8081114261Sken } else if ((minimum_cmd_size < 16) 8082114261Sken && ((block_count & 0xffffffff) == block_count) 8083114261Sken && ((lba & 0xffffffff) == lba)) { 808439466Sken /* 808539466Sken * The block count is too big for a 10 byte CDB, use a 12 8086114261Sken * byte CDB. 808739466Sken */ 808839466Sken struct scsi_rw_12 *scsi_cmd; 808939466Sken 809039466Sken scsi_cmd = (struct scsi_rw_12 *)&csio->cdb_io.cdb_bytes; 8091248519Skib scsi_cmd->opcode = read ? READ_12 : WRITE_12; 809239466Sken scsi_cmd->byte2 = byte2; 809339466Sken scsi_ulto4b(lba, scsi_cmd->addr); 809439466Sken scsi_cmd->reserved = 0; 809539466Sken scsi_ulto4b(block_count, scsi_cmd->length); 809639466Sken scsi_cmd->control = 0; 809739466Sken cdb_len = sizeof(*scsi_cmd); 809839466Sken 809939466Sken CAM_DEBUG(csio->ccb_h.path, CAM_DEBUG_SUBTRACE, 810039466Sken ("12byte: %x%x%x%x:%x%x%x%x: %d\n", scsi_cmd->addr[0], 810139466Sken scsi_cmd->addr[1], scsi_cmd->addr[2], 810239466Sken scsi_cmd->addr[3], scsi_cmd->length[0], 810339466Sken scsi_cmd->length[1], scsi_cmd->length[2], 810439466Sken scsi_cmd->length[3], dxfer_len)); 8105114261Sken } else { 8106114261Sken /* 8107114261Sken * 16 byte CDB. We'll only get here if the LBA is larger 8108114261Sken * than 2^32, or if the user asks for a 16 byte command. 8109114261Sken */ 8110114261Sken struct scsi_rw_16 *scsi_cmd; 8111114261Sken 8112114261Sken scsi_cmd = (struct scsi_rw_16 *)&csio->cdb_io.cdb_bytes; 8113248519Skib scsi_cmd->opcode = read ? READ_16 : WRITE_16; 8114114261Sken scsi_cmd->byte2 = byte2; 8115114261Sken scsi_u64to8b(lba, scsi_cmd->addr); 8116114261Sken scsi_cmd->reserved = 0; 8117114261Sken scsi_ulto4b(block_count, scsi_cmd->length); 8118114261Sken scsi_cmd->control = 0; 8119114261Sken cdb_len = sizeof(*scsi_cmd); 812039466Sken } 812139466Sken cam_fill_csio(csio, 812239466Sken retries, 812339466Sken cbfcnp, 8124248519Skib (read ? CAM_DIR_IN : CAM_DIR_OUT) | 8125248519Skib ((readop & SCSI_RW_BIO) != 0 ? CAM_DATA_BIO : 0), 812639466Sken tag_action, 812739466Sken data_ptr, 812839466Sken dxfer_len, 812939466Sken sense_len, 813039466Sken cdb_len, 813139466Sken timeout); 813239466Sken} 813339466Sken 8134223081Sgibbsvoid 8135230053Smavscsi_write_same(struct ccb_scsiio *csio, u_int32_t retries, 8136230053Smav void (*cbfcnp)(struct cam_periph *, union ccb *), 8137230053Smav u_int8_t tag_action, u_int8_t byte2, 8138230053Smav int minimum_cmd_size, u_int64_t lba, u_int32_t block_count, 8139230053Smav u_int8_t *data_ptr, u_int32_t dxfer_len, u_int8_t sense_len, 8140230053Smav u_int32_t timeout) 8141230053Smav{ 8142230053Smav u_int8_t cdb_len; 8143230053Smav if ((minimum_cmd_size < 16) && 8144230053Smav ((block_count & 0xffff) == block_count) && 8145230053Smav ((lba & 0xffffffff) == lba)) { 8146230053Smav /* 8147230053Smav * Need a 10 byte cdb. 8148230053Smav */ 8149230053Smav struct scsi_write_same_10 *scsi_cmd; 8150230053Smav 8151230053Smav scsi_cmd = (struct scsi_write_same_10 *)&csio->cdb_io.cdb_bytes; 8152230053Smav scsi_cmd->opcode = WRITE_SAME_10; 8153230053Smav scsi_cmd->byte2 = byte2; 8154230053Smav scsi_ulto4b(lba, scsi_cmd->addr); 8155230053Smav scsi_cmd->group = 0; 8156230053Smav scsi_ulto2b(block_count, scsi_cmd->length); 8157230053Smav scsi_cmd->control = 0; 8158230053Smav cdb_len = sizeof(*scsi_cmd); 8159230053Smav 8160230053Smav CAM_DEBUG(csio->ccb_h.path, CAM_DEBUG_SUBTRACE, 8161230053Smav ("10byte: %x%x%x%x:%x%x: %d\n", scsi_cmd->addr[0], 8162230053Smav scsi_cmd->addr[1], scsi_cmd->addr[2], 8163230053Smav scsi_cmd->addr[3], scsi_cmd->length[0], 8164230053Smav scsi_cmd->length[1], dxfer_len)); 8165230053Smav } else { 8166230053Smav /* 8167230053Smav * 16 byte CDB. We'll only get here if the LBA is larger 8168230053Smav * than 2^32, or if the user asks for a 16 byte command. 8169230053Smav */ 8170230053Smav struct scsi_write_same_16 *scsi_cmd; 8171230053Smav 8172230053Smav scsi_cmd = (struct scsi_write_same_16 *)&csio->cdb_io.cdb_bytes; 8173230053Smav scsi_cmd->opcode = WRITE_SAME_16; 8174230053Smav scsi_cmd->byte2 = byte2; 8175230053Smav scsi_u64to8b(lba, scsi_cmd->addr); 8176230053Smav scsi_ulto4b(block_count, scsi_cmd->length); 8177230053Smav scsi_cmd->group = 0; 8178230053Smav scsi_cmd->control = 0; 8179230053Smav cdb_len = sizeof(*scsi_cmd); 8180230053Smav 8181230053Smav CAM_DEBUG(csio->ccb_h.path, CAM_DEBUG_SUBTRACE, 8182230053Smav ("16byte: %x%x%x%x%x%x%x%x:%x%x%x%x: %d\n", 8183230053Smav scsi_cmd->addr[0], scsi_cmd->addr[1], 8184230053Smav scsi_cmd->addr[2], scsi_cmd->addr[3], 8185230053Smav scsi_cmd->addr[4], scsi_cmd->addr[5], 8186230053Smav scsi_cmd->addr[6], scsi_cmd->addr[7], 8187230053Smav scsi_cmd->length[0], scsi_cmd->length[1], 8188230053Smav scsi_cmd->length[2], scsi_cmd->length[3], 8189230053Smav dxfer_len)); 8190230053Smav } 8191230053Smav cam_fill_csio(csio, 8192230053Smav retries, 8193230053Smav cbfcnp, 8194230053Smav /*flags*/CAM_DIR_OUT, 8195230053Smav tag_action, 8196230053Smav data_ptr, 8197230053Smav dxfer_len, 8198230053Smav sense_len, 8199230053Smav cdb_len, 8200230053Smav timeout); 8201230053Smav} 8202230053Smav 8203230053Smavvoid 8204249933Ssmhscsi_ata_identify(struct ccb_scsiio *csio, u_int32_t retries, 8205249933Ssmh void (*cbfcnp)(struct cam_periph *, union ccb *), 8206249933Ssmh u_int8_t tag_action, u_int8_t *data_ptr, 8207249933Ssmh u_int16_t dxfer_len, u_int8_t sense_len, 8208249933Ssmh u_int32_t timeout) 8209249933Ssmh{ 8210249933Ssmh scsi_ata_pass_16(csio, 8211249933Ssmh retries, 8212249933Ssmh cbfcnp, 8213249933Ssmh /*flags*/CAM_DIR_IN, 8214249933Ssmh tag_action, 8215249933Ssmh /*protocol*/AP_PROTO_PIO_IN, 8216249933Ssmh /*ata_flags*/AP_FLAG_TDIR_FROM_DEV| 8217249933Ssmh AP_FLAG_BYT_BLOK_BYTES|AP_FLAG_TLEN_SECT_CNT, 8218249933Ssmh /*features*/0, 8219249933Ssmh /*sector_count*/dxfer_len, 8220249933Ssmh /*lba*/0, 8221249933Ssmh /*command*/ATA_ATA_IDENTIFY, 8222249933Ssmh /*control*/0, 8223249933Ssmh data_ptr, 8224249933Ssmh dxfer_len, 8225249933Ssmh sense_len, 8226249933Ssmh timeout); 8227249933Ssmh} 8228249933Ssmh 8229249933Ssmhvoid 8230249933Ssmhscsi_ata_trim(struct ccb_scsiio *csio, u_int32_t retries, 8231249933Ssmh void (*cbfcnp)(struct cam_periph *, union ccb *), 8232249933Ssmh u_int8_t tag_action, u_int16_t block_count, 8233249933Ssmh u_int8_t *data_ptr, u_int16_t dxfer_len, u_int8_t sense_len, 8234249933Ssmh u_int32_t timeout) 8235249933Ssmh{ 8236249933Ssmh scsi_ata_pass_16(csio, 8237249933Ssmh retries, 8238249933Ssmh cbfcnp, 8239249933Ssmh /*flags*/CAM_DIR_OUT, 8240249933Ssmh tag_action, 8241249933Ssmh /*protocol*/AP_EXTEND|AP_PROTO_DMA, 8242249933Ssmh /*ata_flags*/AP_FLAG_TLEN_SECT_CNT|AP_FLAG_BYT_BLOK_BLOCKS, 8243249933Ssmh /*features*/ATA_DSM_TRIM, 8244249933Ssmh /*sector_count*/block_count, 8245249933Ssmh /*lba*/0, 8246249933Ssmh /*command*/ATA_DATA_SET_MANAGEMENT, 8247249933Ssmh /*control*/0, 8248249933Ssmh data_ptr, 8249249933Ssmh dxfer_len, 8250249933Ssmh sense_len, 8251249933Ssmh timeout); 8252249933Ssmh} 8253249933Ssmh 8254249933Ssmhvoid 8255248992Ssmhscsi_ata_pass_16(struct ccb_scsiio *csio, u_int32_t retries, 8256248992Ssmh void (*cbfcnp)(struct cam_periph *, union ccb *), 8257248992Ssmh u_int32_t flags, u_int8_t tag_action, 8258248992Ssmh u_int8_t protocol, u_int8_t ata_flags, u_int16_t features, 8259248992Ssmh u_int16_t sector_count, uint64_t lba, u_int8_t command, 8260248992Ssmh u_int8_t control, u_int8_t *data_ptr, u_int16_t dxfer_len, 8261248992Ssmh u_int8_t sense_len, u_int32_t timeout) 8262248992Ssmh{ 8263248992Ssmh struct ata_pass_16 *ata_cmd; 8264248992Ssmh 8265248992Ssmh ata_cmd = (struct ata_pass_16 *)&csio->cdb_io.cdb_bytes; 8266248992Ssmh ata_cmd->opcode = ATA_PASS_16; 8267248992Ssmh ata_cmd->protocol = protocol; 8268248992Ssmh ata_cmd->flags = ata_flags; 8269248992Ssmh ata_cmd->features_ext = features >> 8; 8270248992Ssmh ata_cmd->features = features; 8271248992Ssmh ata_cmd->sector_count_ext = sector_count >> 8; 8272248992Ssmh ata_cmd->sector_count = sector_count; 8273248992Ssmh ata_cmd->lba_low = lba; 8274248992Ssmh ata_cmd->lba_mid = lba >> 8; 8275248992Ssmh ata_cmd->lba_high = lba >> 16; 8276248992Ssmh ata_cmd->device = ATA_DEV_LBA; 8277248992Ssmh if (protocol & AP_EXTEND) { 8278248992Ssmh ata_cmd->lba_low_ext = lba >> 24; 8279248992Ssmh ata_cmd->lba_mid_ext = lba >> 32; 8280248992Ssmh ata_cmd->lba_high_ext = lba >> 40; 8281248992Ssmh } else 8282248992Ssmh ata_cmd->device |= (lba >> 24) & 0x0f; 8283248992Ssmh ata_cmd->command = command; 8284248992Ssmh ata_cmd->control = control; 8285248992Ssmh 8286248992Ssmh cam_fill_csio(csio, 8287248992Ssmh retries, 8288248992Ssmh cbfcnp, 8289248992Ssmh flags, 8290248992Ssmh tag_action, 8291248992Ssmh data_ptr, 8292248992Ssmh dxfer_len, 8293248992Ssmh sense_len, 8294248992Ssmh sizeof(*ata_cmd), 8295248992Ssmh timeout); 8296248992Ssmh} 8297248992Ssmh 8298248992Ssmhvoid 8299230053Smavscsi_unmap(struct ccb_scsiio *csio, u_int32_t retries, 8300230053Smav void (*cbfcnp)(struct cam_periph *, union ccb *), 8301230053Smav u_int8_t tag_action, u_int8_t byte2, 8302230053Smav u_int8_t *data_ptr, u_int16_t dxfer_len, u_int8_t sense_len, 8303230053Smav u_int32_t timeout) 8304230053Smav{ 8305230053Smav struct scsi_unmap *scsi_cmd; 8306230053Smav 8307230053Smav scsi_cmd = (struct scsi_unmap *)&csio->cdb_io.cdb_bytes; 8308230053Smav scsi_cmd->opcode = UNMAP; 8309230053Smav scsi_cmd->byte2 = byte2; 8310230053Smav scsi_ulto4b(0, scsi_cmd->reserved); 8311230053Smav scsi_cmd->group = 0; 8312230053Smav scsi_ulto2b(dxfer_len, scsi_cmd->length); 8313230053Smav scsi_cmd->control = 0; 8314230053Smav 8315230053Smav cam_fill_csio(csio, 8316230053Smav retries, 8317230053Smav cbfcnp, 8318230053Smav /*flags*/CAM_DIR_OUT, 8319230053Smav tag_action, 8320230053Smav data_ptr, 8321230053Smav dxfer_len, 8322230053Smav sense_len, 8323230053Smav sizeof(*scsi_cmd), 8324230053Smav timeout); 8325230053Smav} 8326230053Smav 8327230053Smavvoid 8328223081Sgibbsscsi_receive_diagnostic_results(struct ccb_scsiio *csio, u_int32_t retries, 8329223081Sgibbs void (*cbfcnp)(struct cam_periph *, union ccb*), 8330223081Sgibbs uint8_t tag_action, int pcv, uint8_t page_code, 8331223081Sgibbs uint8_t *data_ptr, uint16_t allocation_length, 8332223081Sgibbs uint8_t sense_len, uint32_t timeout) 8333223081Sgibbs{ 8334223081Sgibbs struct scsi_receive_diag *scsi_cmd; 8335223081Sgibbs 8336223081Sgibbs scsi_cmd = (struct scsi_receive_diag *)&csio->cdb_io.cdb_bytes; 8337223081Sgibbs memset(scsi_cmd, 0, sizeof(*scsi_cmd)); 8338223081Sgibbs scsi_cmd->opcode = RECEIVE_DIAGNOSTIC; 8339223081Sgibbs if (pcv) { 8340223081Sgibbs scsi_cmd->byte2 |= SRD_PCV; 8341223081Sgibbs scsi_cmd->page_code = page_code; 8342223081Sgibbs } 8343223081Sgibbs scsi_ulto2b(allocation_length, scsi_cmd->length); 8344223081Sgibbs 8345223081Sgibbs cam_fill_csio(csio, 8346223081Sgibbs retries, 8347223081Sgibbs cbfcnp, 8348223081Sgibbs /*flags*/CAM_DIR_IN, 8349223081Sgibbs tag_action, 8350223081Sgibbs data_ptr, 8351223081Sgibbs allocation_length, 8352223081Sgibbs sense_len, 8353223081Sgibbs sizeof(*scsi_cmd), 8354223081Sgibbs timeout); 8355223081Sgibbs} 8356223081Sgibbs 8357223081Sgibbsvoid 8358223081Sgibbsscsi_send_diagnostic(struct ccb_scsiio *csio, u_int32_t retries, 8359223081Sgibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 8360223081Sgibbs uint8_t tag_action, int unit_offline, int device_offline, 8361223081Sgibbs int self_test, int page_format, int self_test_code, 8362223081Sgibbs uint8_t *data_ptr, uint16_t param_list_length, 8363223081Sgibbs uint8_t sense_len, uint32_t timeout) 8364223081Sgibbs{ 8365223081Sgibbs struct scsi_send_diag *scsi_cmd; 8366223081Sgibbs 8367223081Sgibbs scsi_cmd = (struct scsi_send_diag *)&csio->cdb_io.cdb_bytes; 8368223081Sgibbs memset(scsi_cmd, 0, sizeof(*scsi_cmd)); 8369223081Sgibbs scsi_cmd->opcode = SEND_DIAGNOSTIC; 8370223081Sgibbs 8371223081Sgibbs /* 8372223081Sgibbs * The default self-test mode control and specific test 8373223081Sgibbs * control are mutually exclusive. 8374223081Sgibbs */ 8375223081Sgibbs if (self_test) 8376223081Sgibbs self_test_code = SSD_SELF_TEST_CODE_NONE; 8377223081Sgibbs 8378223081Sgibbs scsi_cmd->byte2 = ((self_test_code << SSD_SELF_TEST_CODE_SHIFT) 8379223081Sgibbs & SSD_SELF_TEST_CODE_MASK) 8380223081Sgibbs | (unit_offline ? SSD_UNITOFFL : 0) 8381223081Sgibbs | (device_offline ? SSD_DEVOFFL : 0) 8382223081Sgibbs | (self_test ? SSD_SELFTEST : 0) 8383223081Sgibbs | (page_format ? SSD_PF : 0); 8384223081Sgibbs scsi_ulto2b(param_list_length, scsi_cmd->length); 8385223081Sgibbs 8386223081Sgibbs cam_fill_csio(csio, 8387223081Sgibbs retries, 8388223081Sgibbs cbfcnp, 8389223081Sgibbs /*flags*/param_list_length ? CAM_DIR_OUT : CAM_DIR_NONE, 8390223081Sgibbs tag_action, 8391223081Sgibbs data_ptr, 8392223081Sgibbs param_list_length, 8393223081Sgibbs sense_len, 8394223081Sgibbs sizeof(*scsi_cmd), 8395223081Sgibbs timeout); 8396223081Sgibbs} 8397223081Sgibbs 8398235897Smavvoid 8399235897Smavscsi_read_buffer(struct ccb_scsiio *csio, u_int32_t retries, 8400235897Smav void (*cbfcnp)(struct cam_periph *, union ccb*), 8401235897Smav uint8_t tag_action, int mode, 8402235897Smav uint8_t buffer_id, u_int32_t offset, 8403235897Smav uint8_t *data_ptr, uint32_t allocation_length, 8404235897Smav uint8_t sense_len, uint32_t timeout) 8405235897Smav{ 8406235897Smav struct scsi_read_buffer *scsi_cmd; 8407235897Smav 8408235897Smav scsi_cmd = (struct scsi_read_buffer *)&csio->cdb_io.cdb_bytes; 8409235897Smav memset(scsi_cmd, 0, sizeof(*scsi_cmd)); 8410235897Smav scsi_cmd->opcode = READ_BUFFER; 8411235897Smav scsi_cmd->byte2 = mode; 8412235897Smav scsi_cmd->buffer_id = buffer_id; 8413235897Smav scsi_ulto3b(offset, scsi_cmd->offset); 8414235897Smav scsi_ulto3b(allocation_length, scsi_cmd->length); 8415235897Smav 8416235897Smav cam_fill_csio(csio, 8417235897Smav retries, 8418235897Smav cbfcnp, 8419235897Smav /*flags*/CAM_DIR_IN, 8420235897Smav tag_action, 8421235897Smav data_ptr, 8422235897Smav allocation_length, 8423235897Smav sense_len, 8424235897Smav sizeof(*scsi_cmd), 8425235897Smav timeout); 8426235897Smav} 8427235897Smav 8428235897Smavvoid 8429235897Smavscsi_write_buffer(struct ccb_scsiio *csio, u_int32_t retries, 8430235897Smav void (*cbfcnp)(struct cam_periph *, union ccb *), 8431235897Smav uint8_t tag_action, int mode, 8432235897Smav uint8_t buffer_id, u_int32_t offset, 8433235897Smav uint8_t *data_ptr, uint32_t param_list_length, 8434235897Smav uint8_t sense_len, uint32_t timeout) 8435235897Smav{ 8436235897Smav struct scsi_write_buffer *scsi_cmd; 8437235897Smav 8438235897Smav scsi_cmd = (struct scsi_write_buffer *)&csio->cdb_io.cdb_bytes; 8439235897Smav memset(scsi_cmd, 0, sizeof(*scsi_cmd)); 8440235897Smav scsi_cmd->opcode = WRITE_BUFFER; 8441235897Smav scsi_cmd->byte2 = mode; 8442235897Smav scsi_cmd->buffer_id = buffer_id; 8443235897Smav scsi_ulto3b(offset, scsi_cmd->offset); 8444235897Smav scsi_ulto3b(param_list_length, scsi_cmd->length); 8445235897Smav 8446235897Smav cam_fill_csio(csio, 8447235897Smav retries, 8448235897Smav cbfcnp, 8449235897Smav /*flags*/param_list_length ? CAM_DIR_OUT : CAM_DIR_NONE, 8450235897Smav tag_action, 8451235897Smav data_ptr, 8452235897Smav param_list_length, 8453235897Smav sense_len, 8454235897Smav sizeof(*scsi_cmd), 8455235897Smav timeout); 8456235897Smav} 8457235897Smav 845839466Skenvoid 845939466Skenscsi_start_stop(struct ccb_scsiio *csio, u_int32_t retries, 846039466Sken void (*cbfcnp)(struct cam_periph *, union ccb *), 846139466Sken u_int8_t tag_action, int start, int load_eject, 846239466Sken int immediate, u_int8_t sense_len, u_int32_t timeout) 846339466Sken{ 846439466Sken struct scsi_start_stop_unit *scsi_cmd; 846539466Sken int extra_flags = 0; 846639466Sken 846739466Sken scsi_cmd = (struct scsi_start_stop_unit *)&csio->cdb_io.cdb_bytes; 846839466Sken bzero(scsi_cmd, sizeof(*scsi_cmd)); 846939466Sken scsi_cmd->opcode = START_STOP_UNIT; 847039466Sken if (start != 0) { 847176153Sken scsi_cmd->how |= SSS_START; 847239466Sken /* it takes a lot of power to start a drive */ 847339466Sken extra_flags |= CAM_HIGH_POWER; 847439466Sken } 847539466Sken if (load_eject != 0) 847639466Sken scsi_cmd->how |= SSS_LOEJ; 847739466Sken if (immediate != 0) 847839466Sken scsi_cmd->byte2 |= SSS_IMMED; 847939466Sken 848039466Sken cam_fill_csio(csio, 848139466Sken retries, 848239466Sken cbfcnp, 848339466Sken /*flags*/CAM_DIR_NONE | extra_flags, 848439466Sken tag_action, 848539466Sken /*data_ptr*/NULL, 848639466Sken /*dxfer_len*/0, 848739466Sken sense_len, 848839466Sken sizeof(*scsi_cmd), 848939466Sken timeout); 849039466Sken} 849139466Sken 8492284435Skenvoid 8493284435Skenscsi_read_attribute(struct ccb_scsiio *csio, u_int32_t retries, 8494284435Sken void (*cbfcnp)(struct cam_periph *, union ccb *), 8495284435Sken u_int8_t tag_action, u_int8_t service_action, 8496284435Sken uint32_t element, u_int8_t elem_type, int logical_volume, 8497284435Sken int partition, u_int32_t first_attribute, int cache, 8498284435Sken u_int8_t *data_ptr, u_int32_t length, int sense_len, 8499284435Sken u_int32_t timeout) 8500284435Sken{ 8501284435Sken struct scsi_read_attribute *scsi_cmd; 850239466Sken 8503284435Sken scsi_cmd = (struct scsi_read_attribute *)&csio->cdb_io.cdb_bytes; 8504284435Sken bzero(scsi_cmd, sizeof(*scsi_cmd)); 8505284435Sken 8506284435Sken scsi_cmd->opcode = READ_ATTRIBUTE; 8507305615Spfg scsi_cmd->service_action = service_action; 8508284435Sken scsi_ulto2b(element, scsi_cmd->element); 8509284435Sken scsi_cmd->elem_type = elem_type; 8510284435Sken scsi_cmd->logical_volume = logical_volume; 8511284435Sken scsi_cmd->partition = partition; 8512284435Sken scsi_ulto2b(first_attribute, scsi_cmd->first_attribute); 8513284435Sken scsi_ulto4b(length, scsi_cmd->length); 8514284435Sken if (cache != 0) 8515284435Sken scsi_cmd->cache |= SRA_CACHE; 8516284435Sken 8517284435Sken cam_fill_csio(csio, 8518284435Sken retries, 8519284435Sken cbfcnp, 8520284435Sken /*flags*/CAM_DIR_IN, 8521284435Sken tag_action, 8522284435Sken /*data_ptr*/data_ptr, 8523284435Sken /*dxfer_len*/length, 8524284435Sken sense_len, 8525284435Sken sizeof(*scsi_cmd), 8526284435Sken timeout); 8527284435Sken} 8528284435Sken 8529268700Smavvoid 8530284435Skenscsi_write_attribute(struct ccb_scsiio *csio, u_int32_t retries, 8531284435Sken void (*cbfcnp)(struct cam_periph *, union ccb *), 8532284435Sken u_int8_t tag_action, uint32_t element, int logical_volume, 8533284435Sken int partition, int wtc, u_int8_t *data_ptr, 8534284435Sken u_int32_t length, int sense_len, u_int32_t timeout) 8535284435Sken{ 8536284435Sken struct scsi_write_attribute *scsi_cmd; 8537284435Sken 8538284435Sken scsi_cmd = (struct scsi_write_attribute *)&csio->cdb_io.cdb_bytes; 8539284435Sken bzero(scsi_cmd, sizeof(*scsi_cmd)); 8540284435Sken 8541284435Sken scsi_cmd->opcode = WRITE_ATTRIBUTE; 8542284435Sken if (wtc != 0) 8543284435Sken scsi_cmd->byte2 = SWA_WTC; 8544284435Sken scsi_ulto3b(element, scsi_cmd->element); 8545284435Sken scsi_cmd->logical_volume = logical_volume; 8546284435Sken scsi_cmd->partition = partition; 8547284435Sken scsi_ulto4b(length, scsi_cmd->length); 8548284435Sken 8549284435Sken cam_fill_csio(csio, 8550284435Sken retries, 8551284435Sken cbfcnp, 8552284435Sken /*flags*/CAM_DIR_OUT, 8553284435Sken tag_action, 8554284435Sken /*data_ptr*/data_ptr, 8555284435Sken /*dxfer_len*/length, 8556284435Sken sense_len, 8557284435Sken sizeof(*scsi_cmd), 8558284435Sken timeout); 8559284435Sken} 8560284435Sken 8561284435Skenvoid 8562268700Smavscsi_persistent_reserve_in(struct ccb_scsiio *csio, uint32_t retries, 8563268700Smav void (*cbfcnp)(struct cam_periph *, union ccb *), 8564268700Smav uint8_t tag_action, int service_action, 8565268700Smav uint8_t *data_ptr, uint32_t dxfer_len, int sense_len, 8566268700Smav int timeout) 8567268700Smav{ 8568268700Smav struct scsi_per_res_in *scsi_cmd; 8569268700Smav 8570268700Smav scsi_cmd = (struct scsi_per_res_in *)&csio->cdb_io.cdb_bytes; 8571268700Smav bzero(scsi_cmd, sizeof(*scsi_cmd)); 8572268700Smav 8573268700Smav scsi_cmd->opcode = PERSISTENT_RES_IN; 8574268700Smav scsi_cmd->action = service_action; 8575268700Smav scsi_ulto2b(dxfer_len, scsi_cmd->length); 8576268700Smav 8577268700Smav cam_fill_csio(csio, 8578268700Smav retries, 8579268700Smav cbfcnp, 8580268700Smav /*flags*/CAM_DIR_IN, 8581268700Smav tag_action, 8582268700Smav data_ptr, 8583268700Smav dxfer_len, 8584268700Smav sense_len, 8585268700Smav sizeof(*scsi_cmd), 8586268700Smav timeout); 8587268700Smav} 8588268700Smav 8589268700Smavvoid 8590268700Smavscsi_persistent_reserve_out(struct ccb_scsiio *csio, uint32_t retries, 8591268700Smav void (*cbfcnp)(struct cam_periph *, union ccb *), 8592268700Smav uint8_t tag_action, int service_action, 8593268700Smav int scope, int res_type, uint8_t *data_ptr, 8594268700Smav uint32_t dxfer_len, int sense_len, int timeout) 8595268700Smav{ 8596268700Smav struct scsi_per_res_out *scsi_cmd; 8597268700Smav 8598268700Smav scsi_cmd = (struct scsi_per_res_out *)&csio->cdb_io.cdb_bytes; 8599268700Smav bzero(scsi_cmd, sizeof(*scsi_cmd)); 8600268700Smav 8601268700Smav scsi_cmd->opcode = PERSISTENT_RES_OUT; 8602268700Smav scsi_cmd->action = service_action; 8603268700Smav scsi_cmd->scope_type = scope | res_type; 8604303179Ssbruno scsi_ulto4b(dxfer_len, scsi_cmd->length); 8605280438Sken 8606280438Sken cam_fill_csio(csio, 8607280438Sken retries, 8608280438Sken cbfcnp, 8609280438Sken /*flags*/CAM_DIR_OUT, 8610280438Sken tag_action, 8611280438Sken /*data_ptr*/data_ptr, 8612280438Sken /*dxfer_len*/dxfer_len, 8613280438Sken sense_len, 8614280438Sken sizeof(*scsi_cmd), 8615280438Sken timeout); 8616280438Sken} 8617280438Sken 8618280438Skenvoid 8619280438Skenscsi_security_protocol_in(struct ccb_scsiio *csio, uint32_t retries, 8620280438Sken void (*cbfcnp)(struct cam_periph *, union ccb *), 8621280438Sken uint8_t tag_action, uint32_t security_protocol, 8622280438Sken uint32_t security_protocol_specific, int byte4, 8623280438Sken uint8_t *data_ptr, uint32_t dxfer_len, int sense_len, 8624280438Sken int timeout) 8625280438Sken{ 8626280438Sken struct scsi_security_protocol_in *scsi_cmd; 8627280438Sken 8628280438Sken scsi_cmd = (struct scsi_security_protocol_in *)&csio->cdb_io.cdb_bytes; 8629280438Sken bzero(scsi_cmd, sizeof(*scsi_cmd)); 8630280438Sken 8631280438Sken scsi_cmd->opcode = SECURITY_PROTOCOL_IN; 8632280438Sken 8633280438Sken scsi_cmd->security_protocol = security_protocol; 8634280438Sken scsi_ulto2b(security_protocol_specific, 8635280438Sken scsi_cmd->security_protocol_specific); 8636280438Sken scsi_cmd->byte4 = byte4; 8637268700Smav scsi_ulto4b(dxfer_len, scsi_cmd->length); 8638268700Smav 8639268700Smav cam_fill_csio(csio, 8640268700Smav retries, 8641268700Smav cbfcnp, 8642280438Sken /*flags*/CAM_DIR_IN, 8643280438Sken tag_action, 8644280438Sken data_ptr, 8645280438Sken dxfer_len, 8646280438Sken sense_len, 8647280438Sken sizeof(*scsi_cmd), 8648280438Sken timeout); 8649280438Sken} 8650280438Sken 8651280438Skenvoid 8652280438Skenscsi_security_protocol_out(struct ccb_scsiio *csio, uint32_t retries, 8653280438Sken void (*cbfcnp)(struct cam_periph *, union ccb *), 8654280438Sken uint8_t tag_action, uint32_t security_protocol, 8655280438Sken uint32_t security_protocol_specific, int byte4, 8656280438Sken uint8_t *data_ptr, uint32_t dxfer_len, int sense_len, 8657280438Sken int timeout) 8658280438Sken{ 8659280438Sken struct scsi_security_protocol_out *scsi_cmd; 8660280438Sken 8661280438Sken scsi_cmd = (struct scsi_security_protocol_out *)&csio->cdb_io.cdb_bytes; 8662280438Sken bzero(scsi_cmd, sizeof(*scsi_cmd)); 8663280438Sken 8664280438Sken scsi_cmd->opcode = SECURITY_PROTOCOL_OUT; 8665280438Sken 8666280438Sken scsi_cmd->security_protocol = security_protocol; 8667280438Sken scsi_ulto2b(security_protocol_specific, 8668280438Sken scsi_cmd->security_protocol_specific); 8669280438Sken scsi_cmd->byte4 = byte4; 8670280438Sken scsi_ulto4b(dxfer_len, scsi_cmd->length); 8671280438Sken 8672280438Sken cam_fill_csio(csio, 8673280438Sken retries, 8674280438Sken cbfcnp, 8675268700Smav /*flags*/CAM_DIR_OUT, 8676268700Smav tag_action, 8677268700Smav data_ptr, 8678268700Smav dxfer_len, 8679268700Smav sense_len, 8680268700Smav sizeof(*scsi_cmd), 8681268700Smav timeout); 8682268700Smav} 8683268700Smav 8684287203Skenvoid 8685287203Skenscsi_report_supported_opcodes(struct ccb_scsiio *csio, uint32_t retries, 8686287203Sken void (*cbfcnp)(struct cam_periph *, union ccb *), 8687287203Sken uint8_t tag_action, int options, int req_opcode, 8688287203Sken int req_service_action, uint8_t *data_ptr, 8689287203Sken uint32_t dxfer_len, int sense_len, int timeout) 8690287203Sken{ 8691287203Sken struct scsi_report_supported_opcodes *scsi_cmd; 8692287203Sken 8693287203Sken scsi_cmd = (struct scsi_report_supported_opcodes *) 8694287203Sken &csio->cdb_io.cdb_bytes; 8695287203Sken bzero(scsi_cmd, sizeof(*scsi_cmd)); 8696287203Sken 8697287203Sken scsi_cmd->opcode = MAINTENANCE_IN; 8698287203Sken scsi_cmd->service_action = REPORT_SUPPORTED_OPERATION_CODES; 8699287203Sken scsi_cmd->options = options; 8700287203Sken scsi_cmd->requested_opcode = req_opcode; 8701287203Sken scsi_ulto2b(req_service_action, scsi_cmd->requested_service_action); 8702287203Sken scsi_ulto4b(dxfer_len, scsi_cmd->length); 8703287203Sken 8704287203Sken cam_fill_csio(csio, 8705287203Sken retries, 8706287203Sken cbfcnp, 8707287203Sken /*flags*/CAM_DIR_IN, 8708287203Sken tag_action, 8709287203Sken data_ptr, 8710287203Sken dxfer_len, 8711287203Sken sense_len, 8712287203Sken sizeof(*scsi_cmd), 8713287203Sken timeout); 8714287203Sken} 8715287203Sken 871639213Sgibbs/* 871739213Sgibbs * Try make as good a match as possible with 871839213Sgibbs * available sub drivers 871939213Sgibbs */ 872039213Sgibbsint 872139213Sgibbsscsi_inquiry_match(caddr_t inqbuffer, caddr_t table_entry) 872239213Sgibbs{ 872339213Sgibbs struct scsi_inquiry_pattern *entry; 872439213Sgibbs struct scsi_inquiry_data *inq; 872539213Sgibbs 872639213Sgibbs entry = (struct scsi_inquiry_pattern *)table_entry; 872739213Sgibbs inq = (struct scsi_inquiry_data *)inqbuffer; 872839213Sgibbs 872939213Sgibbs if (((SID_TYPE(inq) == entry->type) 873039213Sgibbs || (entry->type == T_ANY)) 873139213Sgibbs && (SID_IS_REMOVABLE(inq) ? entry->media_type & SIP_MEDIA_REMOVABLE 873239213Sgibbs : entry->media_type & SIP_MEDIA_FIXED) 873339213Sgibbs && (cam_strmatch(inq->vendor, entry->vendor, sizeof(inq->vendor)) == 0) 873439466Sken && (cam_strmatch(inq->product, entry->product, 873539466Sken sizeof(inq->product)) == 0) 873639466Sken && (cam_strmatch(inq->revision, entry->revision, 873739466Sken sizeof(inq->revision)) == 0)) { 873839213Sgibbs return (0); 873939213Sgibbs } 874039213Sgibbs return (-1); 874139213Sgibbs} 874239213Sgibbs 874339213Sgibbs/* 874439213Sgibbs * Try make as good a match as possible with 874539213Sgibbs * available sub drivers 874639213Sgibbs */ 874739213Sgibbsint 874839213Sgibbsscsi_static_inquiry_match(caddr_t inqbuffer, caddr_t table_entry) 874939213Sgibbs{ 875039213Sgibbs struct scsi_static_inquiry_pattern *entry; 875139213Sgibbs struct scsi_inquiry_data *inq; 875239213Sgibbs 875339213Sgibbs entry = (struct scsi_static_inquiry_pattern *)table_entry; 875439213Sgibbs inq = (struct scsi_inquiry_data *)inqbuffer; 875539213Sgibbs 875639213Sgibbs if (((SID_TYPE(inq) == entry->type) 875739213Sgibbs || (entry->type == T_ANY)) 875839213Sgibbs && (SID_IS_REMOVABLE(inq) ? entry->media_type & SIP_MEDIA_REMOVABLE 875939213Sgibbs : entry->media_type & SIP_MEDIA_FIXED) 876039213Sgibbs && (cam_strmatch(inq->vendor, entry->vendor, sizeof(inq->vendor)) == 0) 876139466Sken && (cam_strmatch(inq->product, entry->product, 876239466Sken sizeof(inq->product)) == 0) 876339466Sken && (cam_strmatch(inq->revision, entry->revision, 876439466Sken sizeof(inq->revision)) == 0)) { 876539213Sgibbs return (0); 876639213Sgibbs } 876739213Sgibbs return (-1); 876839213Sgibbs} 8769102862Sbrooks 8770223081Sgibbs/** 8771223081Sgibbs * Compare two buffers of vpd device descriptors for a match. 8772223081Sgibbs * 8773223081Sgibbs * \param lhs Pointer to first buffer of descriptors to compare. 8774223081Sgibbs * \param lhs_len The length of the first buffer. 8775223081Sgibbs * \param rhs Pointer to second buffer of descriptors to compare. 8776223081Sgibbs * \param rhs_len The length of the second buffer. 8777223081Sgibbs * 8778223081Sgibbs * \return 0 on a match, -1 otherwise. 8779223081Sgibbs * 8780223081Sgibbs * Treat rhs and lhs as arrays of vpd device id descriptors. Walk lhs matching 8781311402Smav * against each element in rhs until all data are exhausted or we have found 8782223081Sgibbs * a match. 8783223081Sgibbs */ 8784223081Sgibbsint 8785223081Sgibbsscsi_devid_match(uint8_t *lhs, size_t lhs_len, uint8_t *rhs, size_t rhs_len) 8786223081Sgibbs{ 8787223081Sgibbs struct scsi_vpd_id_descriptor *lhs_id; 8788223081Sgibbs struct scsi_vpd_id_descriptor *lhs_last; 8789223081Sgibbs struct scsi_vpd_id_descriptor *rhs_last; 8790223081Sgibbs uint8_t *lhs_end; 8791223081Sgibbs uint8_t *rhs_end; 8792223081Sgibbs 8793223081Sgibbs lhs_end = lhs + lhs_len; 8794223081Sgibbs rhs_end = rhs + rhs_len; 8795223081Sgibbs 8796223081Sgibbs /* 8797223081Sgibbs * rhs_last and lhs_last are the last posible position of a valid 8798223081Sgibbs * descriptor assuming it had a zero length identifier. We use 8799223081Sgibbs * these variables to insure we can safely dereference the length 8800223081Sgibbs * field in our loop termination tests. 8801223081Sgibbs */ 8802223081Sgibbs lhs_last = (struct scsi_vpd_id_descriptor *) 8803223081Sgibbs (lhs_end - __offsetof(struct scsi_vpd_id_descriptor, identifier)); 8804223081Sgibbs rhs_last = (struct scsi_vpd_id_descriptor *) 8805223081Sgibbs (rhs_end - __offsetof(struct scsi_vpd_id_descriptor, identifier)); 8806223081Sgibbs 8807223081Sgibbs lhs_id = (struct scsi_vpd_id_descriptor *)lhs; 8808223081Sgibbs while (lhs_id <= lhs_last 8809223081Sgibbs && (lhs_id->identifier + lhs_id->length) <= lhs_end) { 8810223081Sgibbs struct scsi_vpd_id_descriptor *rhs_id; 8811223081Sgibbs 8812223081Sgibbs rhs_id = (struct scsi_vpd_id_descriptor *)rhs; 8813223081Sgibbs while (rhs_id <= rhs_last 8814223081Sgibbs && (rhs_id->identifier + rhs_id->length) <= rhs_end) { 8815223081Sgibbs 8816259721Smav if ((rhs_id->id_type & 8817259721Smav (SVPD_ID_ASSOC_MASK | SVPD_ID_TYPE_MASK)) == 8818259721Smav (lhs_id->id_type & 8819259721Smav (SVPD_ID_ASSOC_MASK | SVPD_ID_TYPE_MASK)) 8820259721Smav && rhs_id->length == lhs_id->length 8821223081Sgibbs && memcmp(rhs_id->identifier, lhs_id->identifier, 8822223081Sgibbs rhs_id->length) == 0) 8823223081Sgibbs return (0); 8824223081Sgibbs 8825223081Sgibbs rhs_id = (struct scsi_vpd_id_descriptor *) 8826223081Sgibbs (rhs_id->identifier + rhs_id->length); 8827223081Sgibbs } 8828223081Sgibbs lhs_id = (struct scsi_vpd_id_descriptor *) 8829223081Sgibbs (lhs_id->identifier + lhs_id->length); 8830223081Sgibbs } 8831223081Sgibbs return (-1); 8832223081Sgibbs} 8833223081Sgibbs 8834102862Sbrooks#ifdef _KERNEL 8835249937Ssmhint 8836249937Ssmhscsi_vpd_supported_page(struct cam_periph *periph, uint8_t page_id) 8837249937Ssmh{ 8838249937Ssmh struct cam_ed *device; 8839249937Ssmh struct scsi_vpd_supported_pages *vpds; 8840249937Ssmh int i, num_pages; 8841249937Ssmh 8842249937Ssmh device = periph->path->device; 8843249937Ssmh vpds = (struct scsi_vpd_supported_pages *)device->supported_vpds; 8844249937Ssmh 8845249937Ssmh if (vpds != NULL) { 8846249937Ssmh num_pages = device->supported_vpds_len - 8847249937Ssmh SVPD_SUPPORTED_PAGES_HDR_LEN; 8848249937Ssmh for (i = 0; i < num_pages; i++) { 8849249937Ssmh if (vpds->page_list[i] == page_id) 8850249937Ssmh return (1); 8851249937Ssmh } 8852249937Ssmh } 8853249937Ssmh 8854249937Ssmh return (0); 8855249937Ssmh} 8856249937Ssmh 8857102862Sbrooksstatic void 8858102862Sbrooksinit_scsi_delay(void) 8859102862Sbrooks{ 8860102862Sbrooks int delay; 8861102862Sbrooks 8862102862Sbrooks delay = SCSI_DELAY; 8863102862Sbrooks TUNABLE_INT_FETCH("kern.cam.scsi_delay", &delay); 8864102862Sbrooks 8865102862Sbrooks if (set_scsi_delay(delay) != 0) { 8866102862Sbrooks printf("cam: invalid value for tunable kern.cam.scsi_delay\n"); 8867102862Sbrooks set_scsi_delay(SCSI_DELAY); 8868102862Sbrooks } 8869102862Sbrooks} 8870102862SbrooksSYSINIT(scsi_delay, SI_SUB_TUNABLES, SI_ORDER_ANY, init_scsi_delay, NULL); 8871102862Sbrooks 8872102862Sbrooksstatic int 8873102862Sbrookssysctl_scsi_delay(SYSCTL_HANDLER_ARGS) 8874102862Sbrooks{ 8875102862Sbrooks int error, delay; 8876102862Sbrooks 8877102862Sbrooks delay = scsi_delay; 8878170289Sdwmalone error = sysctl_handle_int(oidp, &delay, 0, req); 8879102862Sbrooks if (error != 0 || req->newptr == NULL) 8880102862Sbrooks return (error); 8881102862Sbrooks return (set_scsi_delay(delay)); 8882102862Sbrooks} 8883102862SbrooksSYSCTL_PROC(_kern_cam, OID_AUTO, scsi_delay, CTLTYPE_INT|CTLFLAG_RW, 8884102862Sbrooks 0, 0, sysctl_scsi_delay, "I", 8885102862Sbrooks "Delay to allow devices to settle after a SCSI bus reset (ms)"); 8886102862Sbrooks 8887102862Sbrooksstatic int 8888102862Sbrooksset_scsi_delay(int delay) 8889102862Sbrooks{ 8890102862Sbrooks /* 8891102862Sbrooks * If someone sets this to 0, we assume that they want the 8892102862Sbrooks * minimum allowable bus settle delay. 8893102862Sbrooks */ 8894102862Sbrooks if (delay == 0) { 8895102862Sbrooks printf("cam: using minimum scsi_delay (%dms)\n", 8896102862Sbrooks SCSI_MIN_DELAY); 8897102862Sbrooks delay = SCSI_MIN_DELAY; 8898102862Sbrooks } 8899102862Sbrooks if (delay < SCSI_MIN_DELAY) 8900102862Sbrooks return (EINVAL); 8901102862Sbrooks scsi_delay = delay; 8902102862Sbrooks return (0); 8903102862Sbrooks} 8904102862Sbrooks#endif /* _KERNEL */ 8905