diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2013-10-09 22:42:09 +0200 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2013-10-10 09:06:58 +0200 |
commit | bceabc95c1c85d793200446fa85f1ddc6313ea29 (patch) | |
tree | 973c8bd8deca9fd69913f2895cc91e0e6114d46c /freebsd/sys/cam | |
parent | Add FreeBSD sources as a submodule (diff) | |
download | rtems-libbsd-bceabc95c1c85d793200446fa85f1ddc6313ea29.tar.bz2 |
Move files to match FreeBSD layout
Diffstat (limited to 'freebsd/sys/cam')
-rw-r--r-- | freebsd/sys/cam/ata/ata_all.h | 127 | ||||
-rw-r--r-- | freebsd/sys/cam/cam.c | 438 | ||||
-rw-r--r-- | freebsd/sys/cam/cam.h | 263 | ||||
-rw-r--r-- | freebsd/sys/cam/cam_ccb.h | 1193 | ||||
-rw-r--r-- | freebsd/sys/cam/cam_debug.h | 87 | ||||
-rw-r--r-- | freebsd/sys/cam/cam_periph.h | 204 | ||||
-rw-r--r-- | freebsd/sys/cam/cam_sim.h | 201 | ||||
-rw-r--r-- | freebsd/sys/cam/cam_xpt.h | 138 | ||||
-rw-r--r-- | freebsd/sys/cam/cam_xpt_sim.h | 57 | ||||
-rw-r--r-- | freebsd/sys/cam/scsi/scsi_all.c | 4305 | ||||
-rw-r--r-- | freebsd/sys/cam/scsi/scsi_all.h | 1454 | ||||
-rw-r--r-- | freebsd/sys/cam/scsi/scsi_da.h | 463 |
12 files changed, 8930 insertions, 0 deletions
diff --git a/freebsd/sys/cam/ata/ata_all.h b/freebsd/sys/cam/ata/ata_all.h new file mode 100644 index 00000000..6b23bd79 --- /dev/null +++ b/freebsd/sys/cam/ata/ata_all.h @@ -0,0 +1,127 @@ +/*- + * Copyright (c) 2009 Alexander Motin <mav@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef CAM_ATA_ALL_H +#define CAM_ATA_ALL_H 1 + +#include <freebsd/sys/ata.h> + +struct ccb_ataio; +struct cam_periph; +union ccb; + +struct ata_cmd { + u_int8_t flags; /* ATA command flags */ +#define CAM_ATAIO_48BIT 0x01 /* Command has 48-bit format */ +#define CAM_ATAIO_FPDMA 0x02 /* FPDMA command */ +#define CAM_ATAIO_CONTROL 0x04 /* Control, not a command */ +#define CAM_ATAIO_NEEDRESULT 0x08 /* Request requires result. */ +#define CAM_ATAIO_DMA 0x10 /* DMA command */ + + u_int8_t command; + u_int8_t features; + + u_int8_t lba_low; + u_int8_t lba_mid; + u_int8_t lba_high; + u_int8_t device; + + u_int8_t lba_low_exp; + u_int8_t lba_mid_exp; + u_int8_t lba_high_exp; + u_int8_t features_exp; + + u_int8_t sector_count; + u_int8_t sector_count_exp; + u_int8_t control; +}; + +struct ata_res { + u_int8_t flags; /* ATA command flags */ +#define CAM_ATAIO_48BIT 0x01 /* Command has 48-bit format */ + + u_int8_t status; + u_int8_t error; + + u_int8_t lba_low; + u_int8_t lba_mid; + u_int8_t lba_high; + u_int8_t device; + + u_int8_t lba_low_exp; + u_int8_t lba_mid_exp; + u_int8_t lba_high_exp; + + u_int8_t sector_count; + u_int8_t sector_count_exp; +}; + +int ata_version(int ver); + +char * ata_op_string(struct ata_cmd *cmd); +char * ata_cmd_string(struct ata_cmd *cmd, char *cmd_string, size_t len); +char * ata_res_string(struct ata_res *res, char *res_string, size_t len); +int ata_command_sbuf(struct ccb_ataio *ataio, struct sbuf *sb); +int ata_status_sbuf(struct ccb_ataio *ataio, struct sbuf *sb); +int ata_res_sbuf(struct ccb_ataio *ataio, struct sbuf *sb); + +void ata_print_ident(struct ata_params *ident_data); + +uint32_t ata_logical_sector_size(struct ata_params *ident_data); +uint64_t ata_physical_sector_size(struct ata_params *ident_data); +uint64_t ata_logical_sector_offset(struct ata_params *ident_data); + +void ata_28bit_cmd(struct ccb_ataio *ataio, uint8_t cmd, uint8_t features, + uint32_t lba, uint8_t sector_count); +void ata_48bit_cmd(struct ccb_ataio *ataio, uint8_t cmd, uint16_t features, + uint64_t lba, uint16_t sector_count); +void ata_ncq_cmd(struct ccb_ataio *ataio, uint8_t cmd, + uint64_t lba, uint16_t sector_count); +void ata_reset_cmd(struct ccb_ataio *ataio); +void ata_pm_read_cmd(struct ccb_ataio *ataio, int reg, int port); +void ata_pm_write_cmd(struct ccb_ataio *ataio, int reg, int port, uint32_t val); + +void ata_bswap(int8_t *buf, int len); +void ata_btrim(int8_t *buf, int len); +void ata_bpack(int8_t *src, int8_t *dst, int len); + +int ata_max_pmode(struct ata_params *ap); +int ata_max_wmode(struct ata_params *ap); +int ata_max_umode(struct ata_params *ap); +int ata_max_mode(struct ata_params *ap, int maxmode); + +char * ata_mode2string(int mode); +int ata_string2mode(char *str); +u_int ata_mode2speed(int mode); +u_int ata_revision2speed(int revision); +int ata_speed2revision(u_int speed); + +int ata_identify_match(caddr_t identbuffer, caddr_t table_entry); +int ata_static_identify_match(caddr_t identbuffer, caddr_t table_entry); + +#endif diff --git a/freebsd/sys/cam/cam.c b/freebsd/sys/cam/cam.c new file mode 100644 index 00000000..852d1d5b --- /dev/null +++ b/freebsd/sys/cam/cam.c @@ -0,0 +1,438 @@ +#include <freebsd/machine/rtems-bsd-config.h> + +/*- + * Generic utility routines for the Common Access Method layer. + * + * Copyright (c) 1997 Justin T. Gibbs. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <freebsd/sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <freebsd/sys/param.h> +#ifdef _KERNEL +#include <freebsd/sys/systm.h> +#include <freebsd/sys/kernel.h> +#include <freebsd/sys/sysctl.h> +#else /* _KERNEL */ +#include <freebsd/stdlib.h> +#include <freebsd/stdio.h> +#include <freebsd/camlib.h> +#endif /* _KERNEL */ + +#include <freebsd/cam/cam.h> +#include <freebsd/cam/cam_ccb.h> +#include <freebsd/cam/scsi/scsi_all.h> +#include <freebsd/sys/sbuf.h> + +#ifdef _KERNEL +#include <freebsd/sys/libkern.h> +#include <freebsd/cam/cam_queue.h> +#include <freebsd/cam/cam_xpt.h> +#endif + +static int camstatusentrycomp(const void *key, const void *member); + +const struct cam_status_entry cam_status_table[] = { + { CAM_REQ_INPROG, "CCB request is in progress" }, + { CAM_REQ_CMP, "CCB request completed without error" }, + { CAM_REQ_ABORTED, "CCB request aborted by the host" }, + { CAM_UA_ABORT, "Unable to abort CCB request" }, + { CAM_REQ_CMP_ERR, "CCB request completed with an error" }, + { CAM_BUSY, "CAM subsystem is busy" }, + { CAM_REQ_INVALID, "CCB request was invalid" }, + { CAM_PATH_INVALID, "Supplied Path ID is invalid" }, + { CAM_DEV_NOT_THERE, "Device Not Present" }, + { CAM_UA_TERMIO, "Unable to terminate I/O CCB request" }, + { CAM_SEL_TIMEOUT, "Selection Timeout" }, + { CAM_CMD_TIMEOUT, "Command timeout" }, + { CAM_SCSI_STATUS_ERROR, "SCSI Status Error" }, + { CAM_MSG_REJECT_REC, "Message Reject Reveived" }, + { CAM_SCSI_BUS_RESET, "SCSI Bus Reset Sent/Received" }, + { CAM_UNCOR_PARITY, "Uncorrectable parity/CRC error" }, + { CAM_AUTOSENSE_FAIL, "Auto-Sense Retrieval Failed" }, + { CAM_NO_HBA, "No HBA Detected" }, + { CAM_DATA_RUN_ERR, "Data Overrun error" }, + { CAM_UNEXP_BUSFREE, "Unexpected Bus Free" }, + { CAM_SEQUENCE_FAIL, "Target Bus Phase Sequence Failure" }, + { CAM_CCB_LEN_ERR, "CCB length supplied is inadequate" }, + { CAM_PROVIDE_FAIL, "Unable to provide requested capability" }, + { CAM_BDR_SENT, "SCSI BDR Message Sent" }, + { CAM_REQ_TERMIO, "CCB request terminated by the host" }, + { CAM_UNREC_HBA_ERROR, "Unrecoverable Host Bus Adapter Error" }, + { CAM_REQ_TOO_BIG, "The request was too large for this host" }, + { CAM_REQUEUE_REQ, "Unconditionally Re-queue Request", }, + { CAM_ATA_STATUS_ERROR, "ATA Status Error" }, + { CAM_IDE, "Initiator Detected Error Message Received" }, + { CAM_RESRC_UNAVAIL, "Resource Unavailable" }, + { CAM_UNACKED_EVENT, "Unacknowledged Event by Host" }, + { CAM_MESSAGE_RECV, "Message Received in Host Target Mode" }, + { CAM_INVALID_CDB, "Invalid CDB received in Host Target Mode" }, + { CAM_LUN_INVALID, "Invalid Lun" }, + { CAM_TID_INVALID, "Invalid Target ID" }, + { CAM_FUNC_NOTAVAIL, "Function Not Available" }, + { CAM_NO_NEXUS, "Nexus Not Established" }, + { CAM_IID_INVALID, "Invalid Initiator ID" }, + { CAM_CDB_RECVD, "CDB Received" }, + { CAM_LUN_ALRDY_ENA, "LUN Already Enabled for Target Mode" }, + { CAM_SCSI_BUSY, "SCSI Bus Busy" }, +}; + +const int num_cam_status_entries = + sizeof(cam_status_table)/sizeof(*cam_status_table); + +#ifdef _KERNEL +SYSCTL_NODE(_kern, OID_AUTO, cam, CTLFLAG_RD, 0, "CAM Subsystem"); +#endif + +void +cam_strvis(u_int8_t *dst, const u_int8_t *src, int srclen, int dstlen) +{ + + /* Trim leading/trailing spaces, nulls. */ + while (srclen > 0 && src[0] == ' ') + src++, srclen--; + while (srclen > 0 + && (src[srclen-1] == ' ' || src[srclen-1] == '\0')) + srclen--; + + while (srclen > 0 && dstlen > 1) { + u_int8_t *cur_pos = dst; + + if (*src < 0x20 || *src >= 0x80) { + /* SCSI-II Specifies that these should never occur. */ + /* non-printable character */ + if (dstlen > 4) { + *cur_pos++ = '\\'; + *cur_pos++ = ((*src & 0300) >> 6) + '0'; + *cur_pos++ = ((*src & 0070) >> 3) + '0'; + *cur_pos++ = ((*src & 0007) >> 0) + '0'; + } else { + *cur_pos++ = '?'; + } + } else { + /* normal character */ + *cur_pos++ = *src; + } + src++; + srclen--; + dstlen -= cur_pos - dst; + dst = cur_pos; + } + *dst = '\0'; +} + +/* + * Compare string with pattern, returning 0 on match. + * Short pattern matches trailing blanks in name, + * wildcard '*' in pattern matches rest of name, + * wildcard '?' matches a single non-space character. + */ +int +cam_strmatch(const u_int8_t *str, const u_int8_t *pattern, int str_len) +{ + + while (*pattern != '\0'&& str_len > 0) { + + if (*pattern == '*') { + return (0); + } + if ((*pattern != *str) + && (*pattern != '?' || *str == ' ')) { + return (1); + } + pattern++; + str++; + str_len--; + } + while (str_len > 0 && *str == ' ') { + str++; + str_len--; + } + if (str_len > 0 && *str == 0) + str_len = 0; + + return (str_len); +} + +caddr_t +cam_quirkmatch(caddr_t target, caddr_t quirk_table, int num_entries, + int entry_size, cam_quirkmatch_t *comp_func) +{ + for (; num_entries > 0; num_entries--, quirk_table += entry_size) { + if ((*comp_func)(target, quirk_table) == 0) + return (quirk_table); + } + return (NULL); +} + +const struct cam_status_entry* +cam_fetch_status_entry(cam_status status) +{ + status &= CAM_STATUS_MASK; + return (bsearch(&status, &cam_status_table, + num_cam_status_entries, + sizeof(*cam_status_table), + camstatusentrycomp)); +} + +static int +camstatusentrycomp(const void *key, const void *member) +{ + cam_status status; + const struct cam_status_entry *table_entry; + + status = *(const cam_status *)key; + table_entry = (const struct cam_status_entry *)member; + + return (status - table_entry->status_code); +} + + +#ifndef __rtems__ +#ifdef _KERNEL +char * +cam_error_string(union ccb *ccb, char *str, int str_len, + cam_error_string_flags flags, + cam_error_proto_flags proto_flags) +#else /* !_KERNEL */ +char * +cam_error_string(struct cam_device *device, union ccb *ccb, char *str, + int str_len, cam_error_string_flags flags, + cam_error_proto_flags proto_flags) +#endif /* _KERNEL/!_KERNEL */ +{ + char path_str[64]; + struct sbuf sb; + + if ((ccb == NULL) + || (str == NULL) + || (str_len <= 0)) + return(NULL); + + if (flags == CAM_ESF_NONE) + return(NULL); + + switch (ccb->ccb_h.func_code) { + case XPT_ATA_IO: + switch (proto_flags & CAM_EPF_LEVEL_MASK) { + case CAM_EPF_NONE: + break; + case CAM_EPF_ALL: + case CAM_EPF_NORMAL: + proto_flags |= CAM_EAF_PRINT_RESULT; + /* FALLTHROUGH */ + case CAM_EPF_MINIMAL: + proto_flags |= CAM_EAF_PRINT_STATUS; + /* FALLTHROUGH */ + default: + break; + } + break; + case XPT_SCSI_IO: + switch (proto_flags & CAM_EPF_LEVEL_MASK) { + case CAM_EPF_NONE: + break; + case CAM_EPF_ALL: + case CAM_EPF_NORMAL: + proto_flags |= CAM_ESF_PRINT_SENSE; + /* FALLTHROUGH */ + case CAM_EPF_MINIMAL: + proto_flags |= CAM_ESF_PRINT_STATUS; + /* FALLTHROUGH */ + default: + break; + } + break; + default: + break; + } +#ifdef _KERNEL + xpt_path_string(ccb->csio.ccb_h.path, path_str, sizeof(path_str)); +#else /* !_KERNEL */ + cam_path_string(device, path_str, sizeof(path_str)); +#endif /* _KERNEL/!_KERNEL */ + + sbuf_new(&sb, str, str_len, 0); + + if (flags & CAM_ESF_COMMAND) { + sbuf_cat(&sb, path_str); + switch (ccb->ccb_h.func_code) { + case XPT_ATA_IO: + ata_command_sbuf(&ccb->ataio, &sb); + sbuf_printf(&sb, "\n"); + break; + case XPT_SCSI_IO: +#ifdef _KERNEL + scsi_command_string(&ccb->csio, &sb); +#else /* !_KERNEL */ + scsi_command_string(device, &ccb->csio, &sb); +#endif /* _KERNEL/!_KERNEL */ + sbuf_printf(&sb, "\n"); + break; + default: + break; + } + } + + if (flags & CAM_ESF_CAM_STATUS) { + cam_status status; + const struct cam_status_entry *entry; + + sbuf_cat(&sb, path_str); + + status = ccb->ccb_h.status & CAM_STATUS_MASK; + + entry = cam_fetch_status_entry(status); + + if (entry == NULL) + sbuf_printf(&sb, "CAM status: Unknown (%#x)\n", + ccb->ccb_h.status); + else + sbuf_printf(&sb, "CAM status: %s\n", + entry->status_text); + } + + if (flags & CAM_ESF_PROTO_STATUS) { + + switch (ccb->ccb_h.func_code) { + case XPT_ATA_IO: + if ((ccb->ccb_h.status & CAM_STATUS_MASK) != + CAM_ATA_STATUS_ERROR) + break; + if (proto_flags & CAM_EAF_PRINT_STATUS) { + sbuf_cat(&sb, path_str); + ata_status_sbuf(&ccb->ataio, &sb); + sbuf_printf(&sb, "\n"); + } + if (proto_flags & CAM_EAF_PRINT_RESULT) { + sbuf_cat(&sb, path_str); + ata_res_sbuf(&ccb->ataio, &sb); + sbuf_printf(&sb, "\n"); + } + + break; + case XPT_SCSI_IO: + if ((ccb->ccb_h.status & CAM_STATUS_MASK) != + CAM_SCSI_STATUS_ERROR) + break; + + if (proto_flags & CAM_ESF_PRINT_STATUS) { + sbuf_cat(&sb, path_str); + sbuf_printf(&sb, "SCSI status: %s\n", + scsi_status_string(&ccb->csio)); + } + + if ((proto_flags & CAM_ESF_PRINT_SENSE) + && (ccb->csio.scsi_status == SCSI_STATUS_CHECK_COND) + && (ccb->ccb_h.status & CAM_AUTOSNS_VALID)) { + +#ifdef _KERNEL + scsi_sense_sbuf(&ccb->csio, &sb, + SSS_FLAG_NONE); +#else /* !_KERNEL */ + scsi_sense_sbuf(device, &ccb->csio, &sb, + SSS_FLAG_NONE); +#endif /* _KERNEL/!_KERNEL */ + } + break; + default: + break; + } + } + + sbuf_finish(&sb); + + return(sbuf_data(&sb)); +} + +#ifdef _KERNEL + +void +cam_error_print(union ccb *ccb, cam_error_string_flags flags, + cam_error_proto_flags proto_flags) +{ + char str[512]; + + printf("%s", cam_error_string(ccb, str, sizeof(str), flags, + proto_flags)); +} + +#else /* !_KERNEL */ + +void +cam_error_print(struct cam_device *device, union ccb *ccb, + cam_error_string_flags flags, cam_error_proto_flags proto_flags, + FILE *ofile) +{ + char str[512]; + + if ((device == NULL) || (ccb == NULL) || (ofile == NULL)) + return; + + fprintf(ofile, "%s", cam_error_string(device, ccb, str, sizeof(str), + flags, proto_flags)); +} + +#endif /* _KERNEL/!_KERNEL */ + +/* + * Common calculate geometry fuction + * + * Caller should set ccg->volume_size and block_size. + * The extended parameter should be zero if extended translation + * should not be used. + */ +void +cam_calc_geometry(struct ccb_calc_geometry *ccg, int extended) +{ + uint32_t size_mb, secs_per_cylinder; + + if (ccg->block_size == 0) { + ccg->ccb_h.status = CAM_REQ_CMP_ERR; + return; + } + size_mb = (1024L * 1024L) / ccg->block_size; + if (size_mb == 0) { + ccg->ccb_h.status = CAM_REQ_CMP_ERR; + return; + } + size_mb = ccg->volume_size / size_mb; + if (size_mb > 1024 && extended) { + ccg->heads = 255; + ccg->secs_per_track = 63; + } else { + ccg->heads = 64; + ccg->secs_per_track = 32; + } + secs_per_cylinder = ccg->heads * ccg->secs_per_track; + if (secs_per_cylinder == 0) { + ccg->ccb_h.status = CAM_REQ_CMP_ERR; + return; + } + ccg->cylinders = ccg->volume_size / secs_per_cylinder; + ccg->ccb_h.status = CAM_REQ_CMP; +} +#endif /* __rtems__ */ diff --git a/freebsd/sys/cam/cam.h b/freebsd/sys/cam/cam.h new file mode 100644 index 00000000..6533fa42 --- /dev/null +++ b/freebsd/sys/cam/cam.h @@ -0,0 +1,263 @@ +/*- + * Data structures and definitions for the CAM system. + * + * Copyright (c) 1997 Justin T. Gibbs. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _CAM_CAM_H +#define _CAM_CAM_H 1 + +#ifdef _KERNEL +#ifndef __rtems__ +#include <freebsd/opt_cam.h> +#else /* __rtems__ */ +#include <freebsd/local/opt_cam.h> +#endif /* __rtems__ */ +#endif + +#include <freebsd/sys/cdefs.h> + +typedef u_int path_id_t; +typedef u_int target_id_t; +typedef u_int lun_id_t; + +#define CAM_XPT_PATH_ID ((path_id_t)~0) +#define CAM_BUS_WILDCARD ((path_id_t)~0) +#define CAM_TARGET_WILDCARD ((target_id_t)~0) +#define CAM_LUN_WILDCARD ((lun_id_t)~0) + +/* + * Maximum length for a CAM CDB. + */ +#define CAM_MAX_CDBLEN 16 + +/* + * Definition of a CAM peripheral driver entry. Peripheral drivers instantiate + * one of these for each device they wish to communicate with and pass it into + * the xpt layer when they wish to schedule work on that device via the + * xpt_schedule API. + */ +struct cam_periph; + +/* + * Priority information for a CAM structure. + */ +typedef enum { + CAM_RL_HOST, + CAM_RL_BUS, + CAM_RL_XPT, + CAM_RL_DEV, + CAM_RL_NORMAL, + CAM_RL_VALUES +} cam_rl; +/* + * The generation number is incremented everytime a new entry is entered into + * the queue giving round robin per priority level scheduling. + */ +typedef struct { + u_int32_t priority; +#define CAM_PRIORITY_HOST ((CAM_RL_HOST << 8) + 0x80) +#define CAM_PRIORITY_BUS ((CAM_RL_BUS << 8) + 0x80) +#define CAM_PRIORITY_XPT ((CAM_RL_XPT << 8) + 0x80) +#define CAM_PRIORITY_DEV ((CAM_RL_DEV << 8) + 0x80) +#define CAM_PRIORITY_NORMAL ((CAM_RL_NORMAL << 8) + 0x80) +#define CAM_PRIORITY_NONE (u_int32_t)-1 +#define CAM_PRIORITY_TO_RL(x) ((x) >> 8) + u_int32_t generation; + int index; +#define CAM_UNQUEUED_INDEX -1 +#define CAM_ACTIVE_INDEX -2 +#define CAM_DONEQ_INDEX -3 +} cam_pinfo; + +/* + * Macro to compare two generation numbers. It is used like this: + * + * if (GENERATIONCMP(a, >=, b)) + * ...; + * + * GERERATIONCMP uses modular arithmetic to guard against wraps + * wraps in the generation number. + */ +#define GENERATIONCMP(x, op, y) ((int32_t)((x) - (y)) op 0) + +/* CAM flags XXX Move to cam_periph.h ??? */ +typedef enum { + CAM_FLAG_NONE = 0x00, + CAM_EXPECT_INQ_CHANGE = 0x01, + CAM_RETRY_SELTO = 0x02 /* Retry Selection Timeouts */ +} cam_flags; + +/* CAM Status field values */ +typedef enum { + CAM_REQ_INPROG, /* CCB request is in progress */ + CAM_REQ_CMP, /* CCB request completed without error */ + CAM_REQ_ABORTED, /* CCB request aborted by the host */ + CAM_UA_ABORT, /* Unable to abort CCB request */ + CAM_REQ_CMP_ERR, /* CCB request completed with an error */ + CAM_BUSY, /* CAM subsystem is busy */ + CAM_REQ_INVALID, /* CCB request was invalid */ + CAM_PATH_INVALID, /* Supplied Path ID is invalid */ + CAM_DEV_NOT_THERE, /* SCSI Device Not Installed/there */ + CAM_UA_TERMIO, /* Unable to terminate I/O CCB request */ + CAM_SEL_TIMEOUT, /* Target Selection Timeout */ + CAM_CMD_TIMEOUT, /* Command timeout */ + CAM_SCSI_STATUS_ERROR, /* SCSI error, look at error code in CCB */ + CAM_MSG_REJECT_REC, /* Message Reject Received */ + CAM_SCSI_BUS_RESET, /* SCSI Bus Reset Sent/Received */ + CAM_UNCOR_PARITY, /* Uncorrectable parity error occurred */ + CAM_AUTOSENSE_FAIL = 0x10,/* Autosense: request sense cmd fail */ + CAM_NO_HBA, /* No HBA Detected error */ + CAM_DATA_RUN_ERR, /* Data Overrun error */ + CAM_UNEXP_BUSFREE, /* Unexpected Bus Free */ + CAM_SEQUENCE_FAIL, /* Target Bus Phase Sequence Failure */ + CAM_CCB_LEN_ERR, /* CCB length supplied is inadequate */ + CAM_PROVIDE_FAIL, /* Unable to provide requested capability */ + CAM_BDR_SENT, /* A SCSI BDR msg was sent to target */ + CAM_REQ_TERMIO, /* CCB request terminated by the host */ + CAM_UNREC_HBA_ERROR, /* Unrecoverable Host Bus Adapter Error */ + CAM_REQ_TOO_BIG, /* The request was too large for this host */ + CAM_REQUEUE_REQ, /* + * This request should be requeued to preserve + * transaction ordering. This typically occurs + * when the SIM recognizes an error that should + * freeze the queue and must place additional + * requests for the target at the sim level + * back into the XPT queue. + */ + CAM_ATA_STATUS_ERROR, /* ATA error, look at error code in CCB */ + CAM_SCSI_IT_NEXUS_LOST, /* Initiator/Target Nexus lost. */ + CAM_IDE = 0x33, /* Initiator Detected Error */ + CAM_RESRC_UNAVAIL, /* Resource Unavailable */ + CAM_UNACKED_EVENT, /* Unacknowledged Event by Host */ + CAM_MESSAGE_RECV, /* Message Received in Host Target Mode */ + CAM_INVALID_CDB, /* Invalid CDB received in Host Target Mode */ + CAM_LUN_INVALID, /* Lun supplied is invalid */ + CAM_TID_INVALID, /* Target ID supplied is invalid */ + CAM_FUNC_NOTAVAIL, /* The requested function is not available */ + CAM_NO_NEXUS, /* Nexus is not established */ + CAM_IID_INVALID, /* The initiator ID is invalid */ + CAM_CDB_RECVD, /* The SCSI CDB has been received */ + CAM_LUN_ALRDY_ENA, /* The LUN is already enabled for target mode */ + CAM_SCSI_BUSY, /* SCSI Bus Busy */ + + CAM_DEV_QFRZN = 0x40, /* The DEV queue is frozen w/this err */ + + /* Autosense data valid for target */ + CAM_AUTOSNS_VALID = 0x80, + CAM_RELEASE_SIMQ = 0x100,/* SIM ready to take more commands */ + CAM_SIM_QUEUED = 0x200,/* SIM has this command in it's queue */ + + CAM_STATUS_MASK = 0x3F, /* Mask bits for just the status # */ + + /* Target Specific Adjunct Status */ + CAM_SENT_SENSE = 0x40000000 /* sent sense with status */ +} cam_status; + +typedef enum { + CAM_ESF_NONE = 0x00, + CAM_ESF_COMMAND = 0x01, + CAM_ESF_CAM_STATUS = 0x02, + CAM_ESF_PROTO_STATUS = 0x04, + CAM_ESF_ALL = 0xff +} cam_error_string_flags; + +typedef enum { + CAM_EPF_NONE = 0x00, + CAM_EPF_MINIMAL = 0x01, + CAM_EPF_NORMAL = 0x02, + CAM_EPF_ALL = 0x03, + CAM_EPF_LEVEL_MASK = 0x0f + /* All bits above bit 3 are protocol-specific */ +} cam_error_proto_flags; + +typedef enum { + CAM_ESF_PRINT_NONE = 0x00, + CAM_ESF_PRINT_STATUS = 0x10, + CAM_ESF_PRINT_SENSE = 0x20 +} cam_error_scsi_flags; + +typedef enum { + CAM_EAF_PRINT_NONE = 0x00, + CAM_EAF_PRINT_STATUS = 0x10, + CAM_EAF_PRINT_RESULT = 0x20 +} cam_error_ata_flags; + +struct cam_status_entry +{ + cam_status status_code; + const char *status_text; +}; + +extern const struct cam_status_entry cam_status_table[]; +extern const int num_cam_status_entries; +union ccb; + +#ifdef SYSCTL_DECL /* from sysctl.h */ +SYSCTL_DECL(_kern_cam); +#endif + +__BEGIN_DECLS +typedef int (cam_quirkmatch_t)(caddr_t, caddr_t); + +caddr_t cam_quirkmatch(caddr_t target, caddr_t quirk_table, int num_entries, + int entry_size, cam_quirkmatch_t *comp_func); + +void cam_strvis(u_int8_t *dst, const u_int8_t *src, int srclen, int dstlen); + +int cam_strmatch(const u_int8_t *str, const u_int8_t *pattern, int str_len); +const struct cam_status_entry* + cam_fetch_status_entry(cam_status status); +#ifdef _KERNEL +char * cam_error_string(union ccb *ccb, char *str, int str_len, + cam_error_string_flags flags, + cam_error_proto_flags proto_flags); +void cam_error_print(union ccb *ccb, cam_error_string_flags flags, + cam_error_proto_flags proto_flags); +#else /* _KERNEL */ +struct cam_device; + +char * cam_error_string(struct cam_device *device, union ccb *ccb, char *str, + int str_len, cam_error_string_flags flags, + cam_error_proto_flags proto_flags); +void cam_error_print(struct cam_device *device, union ccb *ccb, + cam_error_string_flags flags, + cam_error_proto_flags proto_flags, FILE *ofile); +#endif /* _KERNEL */ +__END_DECLS + +#ifdef _KERNEL +static __inline void cam_init_pinfo(cam_pinfo *pinfo); + +static __inline void cam_init_pinfo(cam_pinfo *pinfo) +{ + pinfo->priority = CAM_PRIORITY_NONE; + pinfo->index = CAM_UNQUEUED_INDEX; +} +#endif + +#endif /* _CAM_CAM_H */ diff --git a/freebsd/sys/cam/cam_ccb.h b/freebsd/sys/cam/cam_ccb.h new file mode 100644 index 00000000..d8b14458 --- /dev/null +++ b/freebsd/sys/cam/cam_ccb.h @@ -0,0 +1,1193 @@ +/*- + * Data structures and definitions for CAM Control Blocks (CCBs). + * + * Copyright (c) 1997, 1998 Justin T. Gibbs. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _CAM_CAM_CCB_H +#define _CAM_CAM_CCB_H 1 + +#include <freebsd/sys/queue.h> +#include <freebsd/sys/cdefs.h> +#include <freebsd/sys/time.h> +#include <freebsd/sys/limits.h> +#ifndef _KERNEL +#include <freebsd/sys/callout.h> +#endif +#include <freebsd/cam/cam_debug.h> +#include <freebsd/cam/scsi/scsi_all.h> +#include <freebsd/cam/ata/ata_all.h> + +#ifdef __rtems__ +#include <rtems/blkdev.h> +#endif /* __rtems__ */ + +/* General allocation length definitions for CCB structures */ +#define IOCDBLEN CAM_MAX_CDBLEN /* Space for CDB bytes/pointer */ +#define VUHBALEN 14 /* Vendor Unique HBA length */ +#define SIM_IDLEN 16 /* ASCII string len for SIM ID */ +#define HBA_IDLEN 16 /* ASCII string len for HBA ID */ +#define DEV_IDLEN 16 /* ASCII string len for device names */ +#define CCB_PERIPH_PRIV_SIZE 2 /* size of peripheral private area */ +#define CCB_SIM_PRIV_SIZE 2 /* size of sim private area */ + +/* Struct definitions for CAM control blocks */ + +/* Common CCB header */ +/* CAM CCB flags */ +typedef enum { + CAM_CDB_POINTER = 0x00000001,/* The CDB field is a pointer */ + CAM_QUEUE_ENABLE = 0x00000002,/* SIM queue actions are enabled */ + CAM_CDB_LINKED = 0x00000004,/* CCB contains a linked CDB */ + CAM_NEGOTIATE = 0x00000008,/* + * Perform transport negotiation + * with this command. + */ + CAM_SCATTER_VALID = 0x00000010,/* Scatter/gather list is valid */ + CAM_DIS_AUTOSENSE = 0x00000020,/* Disable autosense feature */ + CAM_DIR_RESV = 0x00000000,/* Data direction (00:reserved) */ + CAM_DIR_IN = 0x00000040,/* Data direction (01:DATA IN) */ + CAM_DIR_OUT = 0x00000080,/* Data direction (10:DATA OUT) */ + CAM_DIR_NONE = 0x000000C0,/* Data direction (11:no data) */ + CAM_DIR_MASK = 0x000000C0,/* Data direction Mask */ + CAM_SOFT_RST_OP = 0x00000100,/* Use Soft reset alternative */ + CAM_ENG_SYNC = 0x00000200,/* Flush resid bytes on complete */ + CAM_DEV_QFRZDIS = 0x00000400,/* Disable DEV Q freezing */ + CAM_DEV_QFREEZE = 0x00000800,/* Freeze DEV Q on execution */ + CAM_HIGH_POWER = 0x00001000,/* Command takes a lot of power */ + CAM_SENSE_PTR = 0x00002000,/* Sense data is a pointer */ + CAM_SENSE_PHYS = 0x00004000,/* Sense pointer is physical addr*/ + CAM_TAG_ACTION_VALID = 0x00008000,/* Use the tag action in this ccb*/ + CAM_PASS_ERR_RECOVER = 0x00010000,/* Pass driver does err. recovery*/ + CAM_DIS_DISCONNECT = 0x00020000,/* Disable disconnect */ + CAM_SG_LIST_PHYS = 0x00040000,/* SG list has physical addrs. */ + CAM_MSG_BUF_PHYS = 0x00080000,/* Message buffer ptr is physical*/ + CAM_SNS_BUF_PHYS = 0x00100000,/* Autosense data ptr is physical*/ + CAM_DATA_PHYS = 0x00200000,/* SG/Buffer data ptrs are phys. */ + CAM_CDB_PHYS = 0x00400000,/* CDB poiner is physical */ + CAM_ENG_SGLIST = 0x00800000,/* SG list is for the HBA engine */ + +/* Phase cognizant mode flags */ + CAM_DIS_AUTOSRP = 0x01000000,/* Disable autosave/restore ptrs */ + CAM_DIS_AUTODISC = 0x02000000,/* Disable auto disconnect */ + CAM_TGT_CCB_AVAIL = 0x04000000,/* Target CCB available */ + CAM_TGT_PHASE_MODE = 0x08000000,/* The SIM runs in phase mode */ + CAM_MSGB_VALID = 0x10000000,/* Message buffer valid */ + CAM_STATUS_VALID = 0x20000000,/* Status buffer valid */ + CAM_DATAB_VALID = 0x40000000,/* Data buffer valid */ + +/* Host target Mode flags */ + CAM_SEND_SENSE = 0x08000000,/* Send sense data with status */ + CAM_TERM_IO = 0x10000000,/* Terminate I/O Message sup. */ + CAM_DISCONNECT = 0x20000000,/* Disconnects are mandatory */ + CAM_SEND_STATUS = 0x40000000 /* Send status after data phase */ +} ccb_flags; + +/* XPT Opcodes for xpt_action */ +typedef enum { +/* Function code flags are bits greater than 0xff */ + XPT_FC_QUEUED = 0x100, + /* Non-immediate function code */ + XPT_FC_USER_CCB = 0x200, + XPT_FC_XPT_ONLY = 0x400, + /* Only for the transport layer device */ + XPT_FC_DEV_QUEUED = 0x800 | XPT_FC_QUEUED, + /* Passes through the device queues */ +/* Common function commands: 0x00->0x0F */ + XPT_NOOP = 0x00, + /* Execute Nothing */ + XPT_SCSI_IO = 0x01 | XPT_FC_DEV_QUEUED, + /* Execute the requested I/O operation */ + XPT_GDEV_TYPE = 0x02, + /* Get type information for specified device */ + XPT_GDEVLIST = 0x03, + /* Get a list of peripheral devices */ + XPT_PATH_INQ = 0x04, + /* Path routing inquiry */ + XPT_REL_SIMQ = 0x05, + /* Release a frozen device queue */ + XPT_SASYNC_CB = 0x06, + /* Set Asynchronous Callback Parameters */ + XPT_SDEV_TYPE = 0x07, + /* Set device type information */ + XPT_SCAN_BUS = 0x08 | XPT_FC_QUEUED | XPT_FC_USER_CCB + | XPT_FC_XPT_ONLY, + /* (Re)Scan the SCSI Bus */ + XPT_DEV_MATCH = 0x09 | XPT_FC_XPT_ONLY, + /* Get EDT entries matching the given pattern */ + XPT_DEBUG = 0x0a, + /* Turn on debugging for a bus, target or lun */ + XPT_PATH_STATS = 0x0b, + /* Path statistics (error counts, etc.) */ + XPT_GDEV_STATS = 0x0c, + /* Device statistics (error counts, etc.) */ + XPT_FREEZE_QUEUE = 0x0d, + /* Freeze device queue */ +/* SCSI Control Functions: 0x10->0x1F */ + XPT_ABORT = 0x10, + /* Abort the specified CCB */ + XPT_RESET_BUS = 0x11 | XPT_FC_XPT_ONLY, + /* Reset the specified SCSI bus */ + XPT_RESET_DEV = 0x12 | XPT_FC_DEV_QUEUED, + /* Bus Device Reset the specified SCSI device */ + XPT_TERM_IO = 0x13, + /* Terminate the I/O process */ + XPT_SCAN_LUN = 0x14 | XPT_FC_QUEUED | XPT_FC_USER_CCB + | XPT_FC_XPT_ONLY, + /* Scan Logical Unit */ + XPT_GET_TRAN_SETTINGS = 0x15, + /* + * Get default/user transfer settings + * for the target + */ + XPT_SET_TRAN_SETTINGS = 0x16, + /* + * Set transfer rate/width + * negotiation settings + */ + XPT_CALC_GEOMETRY = 0x17, + /* + * Calculate the geometry parameters for + * a device give the sector size and + * volume size. + */ + XPT_ATA_IO = 0x18 | XPT_FC_DEV_QUEUED, + /* Execute the requested ATA I/O operation */ + + XPT_GET_SIM_KNOB = 0x18, + /* + * Get SIM specific knob values. + */ + + XPT_SET_SIM_KNOB = 0x19, + /* + * Set SIM specific knob values. + */ +/* HBA engine commands 0x20->0x2F */ + XPT_ENG_INQ = 0x20 | XPT_FC_XPT_ONLY, + /* HBA engine feature inquiry */ + XPT_ENG_EXEC = 0x21 | XPT_FC_DEV_QUEUED, + /* HBA execute engine request */ + +/* Target mode commands: 0x30->0x3F */ + XPT_EN_LUN = 0x30, + /* Enable LUN as a target */ + XPT_TARGET_IO = 0x31 | XPT_FC_DEV_QUEUED, + /* Execute target I/O request */ + XPT_ACCEPT_TARGET_IO = 0x32 | XPT_FC_QUEUED | XPT_FC_USER_CCB, + /* Accept Host Target Mode CDB */ + XPT_CONT_TARGET_IO = 0x33 | XPT_FC_DEV_QUEUED, + /* Continue Host Target I/O Connection */ + XPT_IMMED_NOTIFY = 0x34 | XPT_FC_QUEUED | XPT_FC_USER_CCB, + /* Notify Host Target driver of event (obsolete) */ + XPT_NOTIFY_ACK = 0x35, + /* Acknowledgement of event (obsolete) */ + XPT_IMMEDIATE_NOTIFY = 0x36 | XPT_FC_QUEUED | XPT_FC_USER_CCB, + /* Notify Host Target driver of event */ + XPT_NOTIFY_ACKNOWLEDGE = 0x37 | XPT_FC_QUEUED | XPT_FC_USER_CCB, + /* Acknowledgement of event */ + +/* Vendor Unique codes: 0x80->0x8F */ + XPT_VUNIQUE = 0x80 +} xpt_opcode; + +#define XPT_FC_GROUP_MASK 0xF0 +#define XPT_FC_GROUP(op) ((op) & XPT_FC_GROUP_MASK) +#define XPT_FC_GROUP_COMMON 0x00 +#define XPT_FC_GROUP_SCSI_CONTROL 0x10 +#define XPT_FC_GROUP_HBA_ENGINE 0x20 +#define XPT_FC_GROUP_TMODE 0x30 +#define XPT_FC_GROUP_VENDOR_UNIQUE 0x80 + +#define XPT_FC_IS_DEV_QUEUED(ccb) \ + (((ccb)->ccb_h.func_code & XPT_FC_DEV_QUEUED) == XPT_FC_DEV_QUEUED) +#define XPT_FC_IS_QUEUED(ccb) \ + (((ccb)->ccb_h.func_code & XPT_FC_QUEUED) != 0) + +typedef enum { + PROTO_UNKNOWN, + PROTO_UNSPECIFIED, + PROTO_SCSI, /* Small Computer System Interface */ + PROTO_ATA, /* AT Attachment */ + PROTO_ATAPI, /* AT Attachment Packetized Interface */ + PROTO_SATAPM, /* SATA Port Multiplier */ +} cam_proto; + +typedef enum { + XPORT_UNKNOWN, + XPORT_UNSPECIFIED, + XPORT_SPI, /* SCSI Parallel Interface */ + XPORT_FC, /* Fiber Channel */ + XPORT_SSA, /* Serial Storage Architecture */ + XPORT_USB, /* Universal Serial Bus */ + XPORT_PPB, /* Parallel Port Bus */ + XPORT_ATA, /* AT Attachment */ + XPORT_SAS, /* Serial Attached SCSI */ + XPORT_SATA, /* Serial AT Attachment */ + XPORT_ISCSI, /* iSCSI */ +} cam_xport; + +#define PROTO_VERSION_UNKNOWN (UINT_MAX - 1) +#define PROTO_VERSION_UNSPECIFIED UINT_MAX +#define XPORT_VERSION_UNKNOWN (UINT_MAX - 1) +#define XPORT_VERSION_UNSPECIFIED UINT_MAX + +typedef union { + LIST_ENTRY(ccb_hdr) le; + SLIST_ENTRY(ccb_hdr) sle; + TAILQ_ENTRY(ccb_hdr) tqe; + STAILQ_ENTRY(ccb_hdr) stqe; +} camq_entry; + +typedef union { + void *ptr; + u_long field; + u_int8_t bytes[sizeof(uintptr_t)]; +} ccb_priv_entry; + +typedef union { + ccb_priv_entry entries[CCB_PERIPH_PRIV_SIZE]; + u_int8_t bytes[CCB_PERIPH_PRIV_SIZE * sizeof(ccb_priv_entry)]; +} ccb_ppriv_area; + +typedef union { + ccb_priv_entry entries[CCB_SIM_PRIV_SIZE]; + u_int8_t bytes[CCB_SIM_PRIV_SIZE * sizeof(ccb_priv_entry)]; +} ccb_spriv_area; + +struct ccb_hdr { +#ifndef __rtems__ + cam_pinfo pinfo; /* Info for priority scheduling */ + camq_entry xpt_links; /* For chaining in the XPT layer */ + camq_entry sim_links; /* For chaining in the SIM layer */ + camq_entry periph_links; /* For chaining in the type driver */ +#else /* __rtems__ */ + struct cam_sim *sim; +#endif /* __rtems__ */ + u_int32_t retry_count; + void (*cbfcnp)(struct cam_periph *, union ccb *); + /* Callback on completion function */ + xpt_opcode func_code; /* XPT function code */ + u_int32_t status; /* Status returned by CAM subsystem */ +#ifndef __rtems__ + struct cam_path *path; /* Compiled path for this ccb */ + path_id_t path_id; /* Path ID for the request */ +#endif /* __rtems__ */ + target_id_t target_id; /* Target device ID */ + lun_id_t target_lun; /* Target LUN number */ + u_int32_t flags; /* ccb_flags */ +#ifndef __rtems__ + ccb_ppriv_area periph_priv; + ccb_spriv_area sim_priv; +#endif /* __rtems__ */ + u_int32_t timeout; /* Timeout value */ + +#ifndef __rtems__ + /* + * Deprecated, only for use by non-MPSAFE SIMs. All others must + * allocate and initialize their own callout storage. + */ + struct callout_handle timeout_ch; +#endif /* __rtems__ */ +}; + +/* Get Device Information CCB */ +struct ccb_getdev { + struct ccb_hdr ccb_h; + cam_proto protocol; + struct scsi_inquiry_data inq_data; + struct ata_params ident_data; + u_int8_t serial_num[252]; + u_int8_t inq_flags; + u_int8_t serial_num_len; +}; + +/* Device Statistics CCB */ +struct ccb_getdevstats { + struct ccb_hdr ccb_h; + int dev_openings; /* Space left for more work on device*/ + int dev_active; /* Transactions running on the device */ + int devq_openings; /* Space left for more queued work */ + int devq_queued; /* Transactions queued to be sent */ + int held; /* + * CCBs held by peripheral drivers + * for this device + */ + int maxtags; /* + * Boundary conditions for number of + * tagged operations + */ + int mintags; + struct timeval last_reset; /* Time of last bus reset/loop init */ +}; + +typedef enum { + CAM_GDEVLIST_LAST_DEVICE, + CAM_GDEVLIST_LIST_CHANGED, + CAM_GDEVLIST_MORE_DEVS, + CAM_GDEVLIST_ERROR +} ccb_getdevlist_status_e; + +struct ccb_getdevlist { + struct ccb_hdr ccb_h; + char periph_name[DEV_IDLEN]; + u_int32_t unit_number; + unsigned int generation; + u_int32_t index; + ccb_getdevlist_status_e status; +}; + +typedef enum { + PERIPH_MATCH_NONE = 0x000, + PERIPH_MATCH_PATH = 0x001, + PERIPH_MATCH_TARGET = 0x002, + PERIPH_MATCH_LUN = 0x004, + PERIPH_MATCH_NAME = 0x008, + PERIPH_MATCH_UNIT = 0x010, + PERIPH_MATCH_ANY = 0x01f +} periph_pattern_flags; + +struct periph_match_pattern { + char periph_name[DEV_IDLEN]; + u_int32_t unit_number; + path_id_t path_id; + target_id_t target_id; + lun_id_t target_lun; + periph_pattern_flags flags; +}; + +typedef enum { + DEV_MATCH_NONE = 0x000, + DEV_MATCH_PATH = 0x001, + DEV_MATCH_TARGET = 0x002, + DEV_MATCH_LUN = 0x004, + DEV_MATCH_INQUIRY = 0x008, + DEV_MATCH_ANY = 0x00f +} dev_pattern_flags; + +struct device_match_pattern { + path_id_t path_id; + target_id_t target_id; + lun_id_t target_lun; + struct scsi_static_inquiry_pattern inq_pat; + dev_pattern_flags flags; +}; + +typedef enum { + BUS_MATCH_NONE = 0x000, + BUS_MATCH_PATH = 0x001, + BUS_MATCH_NAME = 0x002, + BUS_MATCH_UNIT = 0x004, + BUS_MATCH_BUS_ID = 0x008, + BUS_MATCH_ANY = 0x00f +} bus_pattern_flags; + +struct bus_match_pattern { + path_id_t path_id; + char dev_name[DEV_IDLEN]; + u_int32_t unit_number; + u_int32_t bus_id; + bus_pattern_flags flags; +}; + +union match_pattern { + struct periph_match_pattern periph_pattern; + struct device_match_pattern device_pattern; + struct bus_match_pattern bus_pattern; +}; + +typedef enum { + DEV_MATCH_PERIPH, + DEV_MATCH_DEVICE, + DEV_MATCH_BUS +} dev_match_type; + +struct dev_match_pattern { + dev_match_type type; + union match_pattern pattern; +}; + +struct periph_match_result { + char periph_name[DEV_IDLEN]; + u_int32_t unit_number; + path_id_t path_id; + target_id_t target_id; + lun_id_t target_lun; +}; + +typedef enum { + DEV_RESULT_NOFLAG = 0x00, + DEV_RESULT_UNCONFIGURED = 0x01 +} dev_result_flags; + +struct device_match_result { + path_id_t path_id; + target_id_t target_id; + lun_id_t target_lun; + cam_proto protocol; + struct scsi_inquiry_data inq_data; + struct ata_params ident_data; + dev_result_flags flags; +}; + +struct bus_match_result { + path_id_t path_id; + char dev_name[DEV_IDLEN]; + u_int32_t unit_number; + u_int32_t bus_id; +}; + +union match_result { + struct periph_match_result periph_result; + struct device_match_result device_result; + struct bus_match_result bus_result; +}; + +struct dev_match_result { + dev_match_type type; + union match_result result; +}; + +typedef enum { + CAM_DEV_MATCH_LAST, + CAM_DEV_MATCH_MORE, + CAM_DEV_MATCH_LIST_CHANGED, + CAM_DEV_MATCH_SIZE_ERROR, + CAM_DEV_MATCH_ERROR +} ccb_dev_match_status; + +typedef enum { + CAM_DEV_POS_NONE = 0x000, + CAM_DEV_POS_BUS = 0x001, + CAM_DEV_POS_TARGET = 0x002, + CAM_DEV_POS_DEVICE = 0x004, + CAM_DEV_POS_PERIPH = 0x008, + CAM_DEV_POS_PDPTR = 0x010, + CAM_DEV_POS_TYPEMASK = 0xf00, + CAM_DEV_POS_EDT = 0x100, + CAM_DEV_POS_PDRV = 0x200 +} dev_pos_type; + +struct ccb_dm_cookie { + void *bus; + void *target; + void *device; + void *periph; + void *pdrv; +}; + +struct ccb_dev_position { + u_int generations[4]; +#define CAM_BUS_GENERATION 0x00 +#define CAM_TARGET_GENERATION 0x01 +#define CAM_DEV_GENERATION 0x02 +#define CAM_PERIPH_GENERATION 0x03 + dev_pos_type position_type; + struct ccb_dm_cookie cookie; +}; + +struct ccb_dev_match { + struct ccb_hdr ccb_h; + ccb_dev_match_status status; + u_int32_t num_patterns; + u_int32_t pattern_buf_len; + struct dev_match_pattern *patterns; + u_int32_t num_matches; + u_int32_t match_buf_len; + struct dev_match_result *matches; + struct ccb_dev_position pos; +}; + +/* + * Definitions for the path inquiry CCB fields. + */ +#define CAM_VERSION 0x15 /* Hex value for current version */ + +typedef enum { + PI_MDP_ABLE = 0x80, /* Supports MDP message */ + PI_WIDE_32 = 0x40, /* Supports 32 bit wide SCSI */ + PI_WIDE_16 = 0x20, /* Supports 16 bit wide SCSI */ + PI_SDTR_ABLE = 0x10, /* Supports SDTR message */ + PI_LINKED_CDB = 0x08, /* Supports linked CDBs */ + PI_SATAPM = 0x04, /* Supports SATA PM */ + PI_TAG_ABLE = 0x02, /* Supports tag queue messages */ + PI_SOFT_RST = 0x01 /* Supports soft reset alternative */ +} pi_inqflag; + +typedef enum { + PIT_PROCESSOR = 0x80, /* Target mode processor mode */ + PIT_PHASE = 0x40, /* Target mode phase cog. mode */ + PIT_DISCONNECT = 0x20, /* Disconnects supported in target mode */ + PIT_TERM_IO = 0x10, /* Terminate I/O message supported in TM */ + PIT_GRP_6 = 0x08, /* Group 6 commands supported */ + PIT_GRP_7 = 0x04 /* Group 7 commands supported */ +} pi_tmflag; + +typedef enum { + PIM_SCANHILO = 0x80, /* Bus scans from high ID to low ID */ + PIM_NOREMOVE = 0x40, /* Removeable devices not included in scan */ + PIM_NOINITIATOR = 0x20, /* Initiator role not supported. */ + PIM_NOBUSRESET = 0x10, /* User has disabled initial BUS RESET */ + PIM_NO_6_BYTE = 0x08, /* Do not send 6-byte commands */ + PIM_SEQSCAN = 0x04 /* Do bus scans sequentially, not in parallel */ +} pi_miscflag; + +/* Path Inquiry CCB */ +struct ccb_pathinq_settings_spi { + u_int8_t ppr_options; +}; + +struct ccb_pathinq_settings_fc { + u_int64_t wwnn; /* world wide node name */ + u_int64_t wwpn; /* world wide port name */ + u_int32_t port; /* 24 bit port id, if known */ + u_int32_t bitrate; /* Mbps */ +}; + +struct ccb_pathinq_settings_sas { + u_int32_t bitrate; /* Mbps */ +}; +#define PATHINQ_SETTINGS_SIZE 128 + +struct ccb_pathinq { + struct ccb_hdr ccb_h; + u_int8_t version_num; /* Version number for the SIM/HBA */ + u_int8_t hba_inquiry; /* Mimic of INQ byte 7 for the HBA */ + u_int8_t target_sprt; /* Flags for target mode support */ + u_int8_t hba_misc; /* Misc HBA features */ + u_int16_t hba_eng_cnt; /* HBA engine count */ + /* Vendor Unique capabilities */ + u_int8_t vuhba_flags[VUHBALEN]; + u_int32_t max_target; /* Maximum supported Target */ + u_int32_t max_lun; /* Maximum supported Lun */ + u_int32_t async_flags; /* Installed Async handlers */ + path_id_t hpath_id; /* Highest Path ID in the subsystem */ + target_id_t initiator_id; /* ID of the HBA on the SCSI bus */ + char sim_vid[SIM_IDLEN]; /* Vendor ID of the SIM */ + char hba_vid[HBA_IDLEN]; /* Vendor ID of the HBA */ + char dev_name[DEV_IDLEN];/* Device name for SIM */ + u_int32_t unit_number; /* Unit number for SIM */ + u_int32_t bus_id; /* Bus ID for SIM */ + u_int32_t base_transfer_speed;/* Base bus speed in KB/sec */ + cam_proto protocol; + u_int protocol_version; + cam_xport transport; + u_int transport_version; + union { + struct ccb_pathinq_settings_spi spi; + struct ccb_pathinq_settings_fc fc; + struct ccb_pathinq_settings_sas sas; + char ccb_pathinq_settings_opaque[PATHINQ_SETTINGS_SIZE]; + } xport_specific; + u_int maxio; /* Max supported I/O size, in bytes. */ +}; + +/* Path Statistics CCB */ +struct ccb_pathstats { + struct ccb_hdr ccb_h; + struct timeval last_reset; /* Time of last bus reset/loop init */ +}; + +typedef union { + u_int8_t *sense_ptr; /* + * Pointer to storage + * for sense information + */ + /* Storage Area for sense information */ + struct scsi_sense_data sense_buf; +} sense_t; + +typedef union { + u_int8_t *cdb_ptr; /* Pointer to the CDB bytes to send */ + /* Area for the CDB send */ + u_int8_t cdb_bytes[IOCDBLEN]; +} cdb_t; + +/* + * SCSI I/O Request CCB used for the XPT_SCSI_IO and XPT_CONT_TARGET_IO + * function codes. + */ +struct ccb_scsiio { + struct ccb_hdr ccb_h; + union ccb *next_ccb; /* Ptr for next CCB for action */ + u_int8_t *req_map; /* Ptr to mapping info */ + u_int8_t *data_ptr; /* Ptr to the data buf/SG list */ + u_int32_t dxfer_len; /* Data transfer length */ + /* Autosense storage */ + struct scsi_sense_data sense_data; + u_int8_t sense_len; /* Number of bytes to autosense */ + u_int8_t cdb_len; /* Number of bytes for the CDB */ + u_int16_t sglist_cnt; /* Number of SG list entries */ + u_int8_t scsi_status; /* Returned SCSI status */ + u_int8_t sense_resid; /* Autosense resid length: 2's comp */ + u_int32_t resid; /* Transfer residual length: 2's comp */ + cdb_t cdb_io; /* Union for CDB bytes/pointer */ + u_int8_t *msg_ptr; /* Pointer to the message buffer */ + u_int16_t msg_len; /* Number of bytes for the Message */ + u_int8_t tag_action; /* What to do for tag queueing */ + /* + * The tag action should be either the define below (to send a + * non-tagged transaction) or one of the defined scsi tag messages + * from scsi_message.h. + */ +#define CAM_TAG_ACTION_NONE 0x00 + u_int tag_id; /* tag id from initator (target mode) */ + u_int init_id; /* initiator id of who selected */ +#ifdef __rtems__ + int readop; + rtems_blkdev_sg_buffer *sg_current; + rtems_blkdev_sg_buffer *sg_end; + rtems_blkdev_request *req; +#endif /* __rtems__ */ +}; + +/* + * ATA I/O Request CCB used for the XPT_ATA_IO function code. + */ +struct ccb_ataio { + struct ccb_hdr ccb_h; + union ccb *next_ccb; /* Ptr for next CCB for action */ + struct ata_cmd cmd; /* ATA command register set */ + struct ata_res res; /* ATA result register set */ + u_int8_t *data_ptr; /* Ptr to the data buf/SG list */ + u_int32_t dxfer_len; /* Data transfer length */ + u_int32_t resid; /* Transfer residual length: 2's comp */ + u_int8_t tag_action; /* What to do for tag queueing */ + /* + * The tag action should be either the define below (to send a + * non-tagged transaction) or one of the defined scsi tag messages + * from scsi_message.h. + */ +#define CAM_TAG_ACTION_NONE 0x00 + u_int tag_id; /* tag id from initator (target mode) */ + u_int init_id; /* initiator id of who selected */ +}; + +struct ccb_accept_tio { + struct ccb_hdr ccb_h; + cdb_t cdb_io; /* Union for CDB bytes/pointer */ + u_int8_t cdb_len; /* Number of bytes for the CDB */ + u_int8_t tag_action; /* What to do for tag queueing */ + u_int8_t sense_len; /* Number of bytes of Sense Data */ + u_int tag_id; /* tag id from initator (target mode) */ + u_int init_id; /* initiator id of who selected */ + struct scsi_sense_data sense_data; +}; + +/* Release SIM Queue */ +struct ccb_relsim { + struct ccb_hdr ccb_h; + u_int32_t release_flags; +#define RELSIM_ADJUST_OPENINGS 0x01 +#define RELSIM_RELEASE_AFTER_TIMEOUT 0x02 +#define RELSIM_RELEASE_AFTER_CMDCMPLT 0x04 +#define RELSIM_RELEASE_AFTER_QEMPTY 0x08 +#define RELSIM_RELEASE_RUNLEVEL 0x10 + u_int32_t openings; + u_int32_t release_timeout; /* Abstract argument. */ + u_int32_t qfrozen_cnt; +}; + +/* + * Definitions for the asynchronous callback CCB fields. + */ +typedef enum { + AC_CONTRACT = 0x1000,/* A contractual callback */ + AC_GETDEV_CHANGED = 0x800,/* Getdev info might have changed */ + AC_INQ_CHANGED = 0x400,/* Inquiry info might have changed */ + AC_TRANSFER_NEG = 0x200,/* New transfer settings in effect */ + AC_LOST_DEVICE = 0x100,/* A device went away */ + AC_FOUND_DEVICE = 0x080,/* A new device was found */ + AC_PATH_DEREGISTERED = 0x040,/* A path has de-registered */ + AC_PATH_REGISTERED = 0x020,/* A new path has been registered */ + AC_SENT_BDR = 0x010,/* A BDR message was sent to target */ + AC_SCSI_AEN = 0x008,/* A SCSI AEN has been received */ + AC_UNSOL_RESEL = 0x002,/* Unsolicited reselection occurred */ + AC_BUS_RESET = 0x001 /* A SCSI bus reset occurred */ +} ac_code; + +#ifdef __rtems__ +struct cam_path; +#endif /* __rtems__ */ + +typedef void ac_callback_t (void *softc, u_int32_t code, + struct cam_path *path, void *args); + +/* + * Generic Asynchronous callbacks. + * + * Generic arguments passed bac which are then interpreted between a per-system + * contract number. + */ +#define AC_CONTRACT_DATA_MAX (128 - sizeof (u_int64_t)) +struct ac_contract { + u_int64_t contract_number; + u_int8_t contract_data[AC_CONTRACT_DATA_MAX]; +}; + +#define AC_CONTRACT_DEV_CHG 1 +struct ac_device_changed { + u_int64_t wwpn; + u_int32_t port; + target_id_t target; + u_int8_t arrived; +}; + +/* Set Asynchronous Callback CCB */ +struct ccb_setasync { + struct ccb_hdr ccb_h; + u_int32_t event_enable; /* Async Event enables */ + ac_callback_t *callback; + void *callback_arg; +}; + +/* Set Device Type CCB */ +struct ccb_setdev { + struct ccb_hdr ccb_h; + u_int8_t dev_type; /* Value for dev type field in EDT */ +}; + +/* SCSI Control Functions */ + +/* Abort XPT request CCB */ +struct ccb_abort { + struct ccb_hdr ccb_h; + union ccb *abort_ccb; /* Pointer to CCB to abort */ +}; + +/* Reset SCSI Bus CCB */ +struct ccb_resetbus { + struct ccb_hdr ccb_h; +}; + +/* Reset SCSI Device CCB */ +struct ccb_resetdev { + struct ccb_hdr ccb_h; +}; + +/* Terminate I/O Process Request CCB */ +struct ccb_termio { + struct ccb_hdr ccb_h; + union ccb *termio_ccb; /* Pointer to CCB to terminate */ +}; + +typedef enum { + CTS_TYPE_CURRENT_SETTINGS, + CTS_TYPE_USER_SETTINGS +} cts_type; + +struct ccb_trans_settings_scsi +{ + u_int valid; /* Which fields to honor */ +#define CTS_SCSI_VALID_TQ 0x01 + u_int flags; +#define CTS_SCSI_FLAGS_TAG_ENB 0x01 +}; + +struct ccb_trans_settings_spi +{ + u_int valid; /* Which fields to honor */ +#define CTS_SPI_VALID_SYNC_RATE 0x01 +#define CTS_SPI_VALID_SYNC_OFFSET 0x02 +#define CTS_SPI_VALID_BUS_WIDTH 0x04 +#define CTS_SPI_VALID_DISC 0x08 +#define CTS_SPI_VALID_PPR_OPTIONS 0x10 + u_int flags; +#define CTS_SPI_FLAGS_DISC_ENB 0x01 + u_int sync_period; + u_int sync_offset; + u_int bus_width; + u_int ppr_options; +}; + +struct ccb_trans_settings_fc { + u_int valid; /* Which fields to honor */ +#define CTS_FC_VALID_WWNN 0x8000 +#define CTS_FC_VALID_WWPN 0x4000 +#define CTS_FC_VALID_PORT 0x2000 +#define CTS_FC_VALID_SPEED 0x1000 + u_int64_t wwnn; /* world wide node name */ + u_int64_t wwpn; /* world wide port name */ + u_int32_t port; /* 24 bit port id, if known */ + u_int32_t bitrate; /* Mbps */ +}; + +struct ccb_trans_settings_sas { + u_int valid; /* Which fields to honor */ +#define CTS_SAS_VALID_SPEED 0x1000 + u_int32_t bitrate; /* Mbps */ +}; + +struct ccb_trans_settings_ata { + u_int valid; /* Which fields to honor */ +#define CTS_ATA_VALID_MODE 0x01 +#define CTS_ATA_VALID_BYTECOUNT 0x02 +#define CTS_ATA_VALID_ATAPI 0x20 + int mode; /* Mode */ + u_int bytecount; /* Length of PIO transaction */ + u_int atapi; /* Length of ATAPI CDB */ +}; + +struct ccb_trans_settings_sata { + u_int valid; /* Which fields to honor */ +#define CTS_SATA_VALID_MODE 0x01 +#define CTS_SATA_VALID_BYTECOUNT 0x02 +#define CTS_SATA_VALID_REVISION 0x04 +#define CTS_SATA_VALID_PM 0x08 +#define CTS_SATA_VALID_TAGS 0x10 +#define CTS_SATA_VALID_ATAPI 0x20 +#define CTS_SATA_VALID_CAPS 0x40 + int mode; /* Legacy PATA mode */ + u_int bytecount; /* Length of PIO transaction */ + int revision; /* SATA revision */ + u_int pm_present; /* PM is present (XPT->SIM) */ + u_int tags; /* Number of allowed tags */ + u_int atapi; /* Length of ATAPI CDB */ + u_int caps; /* Device and host SATA caps. */ +#define CTS_SATA_CAPS_H 0x0000ffff +#define CTS_SATA_CAPS_HH_PMREQ 0x00000001 +#define CTS_SATA_CAPS_HH_APST 0x00000002 +#define CTS_SATA_CAPS_HH_DMAAA 0x00000010 /* Auto-activation */ +#define CTS_SATA_CAPS_D 0xffff0000 +#define CTS_SATA_CAPS_D_PMREQ 0x00010000 +#define CTS_SATA_CAPS_D_APST 0x00020000 +}; + +/* Get/Set transfer rate/width/disconnection/tag queueing settings */ +struct ccb_trans_settings { + struct ccb_hdr ccb_h; + cts_type type; /* Current or User settings */ + cam_proto protocol; + u_int protocol_version; + cam_xport transport; + u_int transport_version; + union { + u_int valid; /* Which fields to honor */ + struct ccb_trans_settings_scsi scsi; + } proto_specific; + union { + u_int valid; /* Which fields to honor */ + struct ccb_trans_settings_spi spi; + struct ccb_trans_settings_fc fc; + struct ccb_trans_settings_sas sas; + struct ccb_trans_settings_ata ata; + struct ccb_trans_settings_sata sata; + } xport_specific; +}; + + +/* + * Calculate the geometry parameters for a device + * give the block size and volume size in blocks. + */ +struct ccb_calc_geometry { + struct ccb_hdr ccb_h; + u_int32_t block_size; + u_int64_t volume_size; + u_int32_t cylinders; + u_int8_t heads; + u_int8_t secs_per_track; +}; + +/* + * Set or get SIM (and transport) specific knobs + */ + +#define KNOB_VALID_ADDRESS 0x1 +#define KNOB_VALID_ROLE 0x2 + + +#define KNOB_ROLE_NONE 0x0 +#define KNOB_ROLE_INITIATOR 0x1 +#define KNOB_ROLE_TARGET 0x2 +#define KNOB_ROLE_BOTH 0x3 + +struct ccb_sim_knob_settings_spi { + u_int valid; + u_int initiator_id; + u_int role; +}; + +struct ccb_sim_knob_settings_fc { + u_int valid; + u_int64_t wwnn; /* world wide node name */ + u_int64_t wwpn; /* world wide port name */ + u_int role; +}; + +struct ccb_sim_knob_settings_sas { + u_int valid; + u_int64_t wwnn; /* world wide node name */ + u_int role; +}; +#define KNOB_SETTINGS_SIZE 128 + +struct ccb_sim_knob { + struct ccb_hdr ccb_h; + union { + u_int valid; /* Which fields to honor */ + struct ccb_sim_knob_settings_spi spi; + struct ccb_sim_knob_settings_fc fc; + struct ccb_sim_knob_settings_sas sas; + char pad[KNOB_SETTINGS_SIZE]; + } xport_specific; +}; + +/* + * Rescan the given bus, or bus/target/lun + */ +struct ccb_rescan { + struct ccb_hdr ccb_h; + cam_flags flags; +}; + +/* + * Turn on debugging for the given bus, bus/target, or bus/target/lun. + */ +struct ccb_debug { + struct ccb_hdr ccb_h; + cam_debug_flags flags; +}; + +/* Target mode structures. */ + +struct ccb_en_lun { + struct ccb_hdr ccb_h; + u_int16_t grp6_len; /* Group 6 VU CDB length */ + u_int16_t grp7_len; /* Group 7 VU CDB length */ + u_int8_t enable; +}; + +/* old, barely used immediate notify, binary compatibility */ +struct ccb_immed_notify { + struct ccb_hdr ccb_h; + struct scsi_sense_data sense_data; + u_int8_t sense_len; /* Number of bytes in sense buffer */ + u_int8_t initiator_id; /* Id of initiator that selected */ + u_int8_t message_args[7]; /* Message Arguments */ +}; + +struct ccb_notify_ack { + struct ccb_hdr ccb_h; + u_int16_t seq_id; /* Sequence identifier */ + u_int8_t event; /* Event flags */ +}; + +struct ccb_immediate_notify { + struct ccb_hdr ccb_h; + u_int tag_id; /* Tag for immediate notify */ + u_int seq_id; /* Tag for target of notify */ + u_int initiator_id; /* Initiator Identifier */ + u_int arg; /* Function specific */ +}; + +struct ccb_notify_acknowledge { + struct ccb_hdr ccb_h; + u_int tag_id; /* Tag for immediate notify */ + u_int seq_id; /* Tar for target of notify */ + u_int initiator_id; /* Initiator Identifier */ + u_int arg; /* Function specific */ +}; + +/* HBA engine structures. */ + +typedef enum { + EIT_BUFFER, /* Engine type: buffer memory */ + EIT_LOSSLESS, /* Engine type: lossless compression */ + EIT_LOSSY, /* Engine type: lossy compression */ + EIT_ENCRYPT /* Engine type: encryption */ +} ei_type; + +typedef enum { + EAD_VUNIQUE, /* Engine algorithm ID: vendor unique */ + EAD_LZ1V1, /* Engine algorithm ID: LZ1 var.1 */ + EAD_LZ2V1, /* Engine algorithm ID: LZ2 var.1 */ + EAD_LZ2V2 /* Engine algorithm ID: LZ2 var.2 */ +} ei_algo; + +struct ccb_eng_inq { + struct ccb_hdr ccb_h; + u_int16_t eng_num; /* The engine number for this inquiry */ + ei_type eng_type; /* Returned engine type */ + ei_algo eng_algo; /* Returned engine algorithm type */ + u_int32_t eng_memeory; /* Returned engine memory size */ +}; + +struct ccb_eng_exec { /* This structure must match SCSIIO size */ + struct ccb_hdr ccb_h; + u_int8_t *pdrv_ptr; /* Ptr used by the peripheral driver */ + u_int8_t *req_map; /* Ptr for mapping info on the req. */ + u_int8_t *data_ptr; /* Pointer to the data buf/SG list */ + u_int32_t dxfer_len; /* Data transfer length */ + u_int8_t *engdata_ptr; /* Pointer to the engine buffer data */ + u_int16_t sglist_cnt; /* Num of scatter gather list entries */ + u_int32_t dmax_len; /* Destination data maximum length */ + u_int32_t dest_len; /* Destination data length */ + int32_t src_resid; /* Source residual length: 2's comp */ + u_int32_t timeout; /* Timeout value */ + u_int16_t eng_num; /* Engine number for this request */ + u_int16_t vu_flags; /* Vendor Unique flags */ +}; + +/* + * Definitions for the timeout field in the SCSI I/O CCB. + */ +#define CAM_TIME_DEFAULT 0x00000000 /* Use SIM default value */ +#define CAM_TIME_INFINITY 0xFFFFFFFF /* Infinite timeout */ + +#define CAM_SUCCESS 0 /* For signaling general success */ +#define CAM_FAILURE 1 /* For signaling general failure */ + +#define CAM_FALSE 0 +#define CAM_TRUE 1 + +#define XPT_CCB_INVALID -1 /* for signaling a bad CCB to free */ + +/* + * Union of all CCB types for kernel space allocation. This union should + * never be used for manipulating CCBs - its only use is for the allocation + * and deallocation of raw CCB space and is the return type of xpt_ccb_alloc + * and the argument to xpt_ccb_free. + */ +union ccb { + struct ccb_hdr ccb_h; /* For convenience */ + struct ccb_scsiio csio; + struct ccb_getdev cgd; + struct ccb_getdevlist cgdl; + struct ccb_pathinq cpi; + struct ccb_relsim crs; + struct ccb_setasync csa; + struct ccb_setdev csd; + struct ccb_pathstats cpis; + struct ccb_getdevstats cgds; + struct ccb_dev_match cdm; + struct ccb_trans_settings cts; + struct ccb_calc_geometry ccg; + struct ccb_sim_knob knob; + struct ccb_abort cab; + struct ccb_resetbus crb; + struct ccb_resetdev crd; + struct ccb_termio tio; + struct ccb_accept_tio atio; + struct ccb_scsiio ctio; + struct ccb_en_lun cel; + struct ccb_immed_notify cin; + struct ccb_notify_ack cna; + struct ccb_immediate_notify cin1; + struct ccb_notify_acknowledge cna2; + struct ccb_eng_inq cei; + struct ccb_eng_exec cee; + struct ccb_rescan crcn; + struct ccb_debug cdbg; + struct ccb_ataio ataio; +}; + +__BEGIN_DECLS +static __inline void +cam_fill_csio(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb *), + u_int32_t flags, u_int8_t tag_action, + u_int8_t *data_ptr, u_int32_t dxfer_len, + u_int8_t sense_len, u_int8_t cdb_len, + u_int32_t timeout); + +static __inline void +cam_fill_ctio(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb *), + u_int32_t flags, u_int tag_action, u_int tag_id, + u_int init_id, u_int scsi_status, u_int8_t *data_ptr, + u_int32_t dxfer_len, u_int32_t timeout); + +static __inline void +cam_fill_ataio(struct ccb_ataio *ataio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb *), + u_int32_t flags, u_int tag_action, + u_int8_t *data_ptr, u_int32_t dxfer_len, + u_int32_t timeout); + +static __inline void +cam_fill_csio(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb *), + u_int32_t flags, u_int8_t tag_action, + u_int8_t *data_ptr, u_int32_t dxfer_len, + u_int8_t sense_len, u_int8_t cdb_len, + u_int32_t timeout) +{ + csio->ccb_h.func_code = XPT_SCSI_IO; + csio->ccb_h.flags = flags; + csio->ccb_h.retry_count = retries; + csio->ccb_h.cbfcnp = cbfcnp; + csio->ccb_h.timeout = timeout; + csio->data_ptr = data_ptr; + csio->dxfer_len = dxfer_len; + csio->sense_len = sense_len; + csio->cdb_len = cdb_len; + csio->tag_action = tag_action; +} + +static __inline void +cam_fill_ctio(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb *), + u_int32_t flags, u_int tag_action, u_int tag_id, + u_int init_id, u_int scsi_status, u_int8_t *data_ptr, + u_int32_t dxfer_len, u_int32_t timeout) +{ + csio->ccb_h.func_code = XPT_CONT_TARGET_IO; + csio->ccb_h.flags = flags; + csio->ccb_h.retry_count = retries; + csio->ccb_h.cbfcnp = cbfcnp; + csio->ccb_h.timeout = timeout; + csio->data_ptr = data_ptr; + csio->dxfer_len = dxfer_len; + csio->scsi_status = scsi_status; + csio->tag_action = tag_action; + csio->tag_id = tag_id; + csio->init_id = init_id; +} + +static __inline void +cam_fill_ataio(struct ccb_ataio *ataio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb *), + u_int32_t flags, u_int tag_action, + u_int8_t *data_ptr, u_int32_t dxfer_len, + u_int32_t timeout) +{ + ataio->ccb_h.func_code = XPT_ATA_IO; + ataio->ccb_h.flags = flags; + ataio->ccb_h.retry_count = retries; + ataio->ccb_h.cbfcnp = cbfcnp; + ataio->ccb_h.timeout = timeout; + ataio->data_ptr = data_ptr; + ataio->dxfer_len = dxfer_len; + ataio->tag_action = tag_action; +} + +void cam_calc_geometry(struct ccb_calc_geometry *ccg, int extended); + +__END_DECLS + +#endif /* _CAM_CAM_CCB_H */ diff --git a/freebsd/sys/cam/cam_debug.h b/freebsd/sys/cam/cam_debug.h new file mode 100644 index 00000000..4b0fd245 --- /dev/null +++ b/freebsd/sys/cam/cam_debug.h @@ -0,0 +1,87 @@ +/*- + * Macros for tracing/loging information in the CAM layer + * + * Copyright (c) 1997 Justin T. Gibbs. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ +#ifndef _CAM_CAM_DEBUG_H +#define _CAM_CAM_DEBUG_H 1 + +/* + * Debugging flags. + */ +typedef enum { + CAM_DEBUG_NONE = 0x00, /* no debugging */ + CAM_DEBUG_INFO = 0x01, /* scsi commands, errors, data */ + CAM_DEBUG_TRACE = 0x02, /* routine flow tracking */ + CAM_DEBUG_SUBTRACE = 0x04, /* internal to routine flows */ + CAM_DEBUG_CDB = 0x08, /* print out SCSI CDBs only */ + CAM_DEBUG_XPT = 0x10, /* print out xpt scheduling */ + CAM_DEBUG_PERIPH = 0x20 /* print out peripheral calls */ +} cam_debug_flags; + +#if defined(CAMDEBUG) && defined(_KERNEL) + +/* Path we want to debug */ +extern struct cam_path *cam_dpath; +/* Current debug levels set */ +extern u_int32_t cam_dflags; +/* Printf delay value (to prevent scrolling) */ +extern u_int32_t cam_debug_delay; + +/* Debugging macros. */ +#define CAM_DEBUGGED(path, flag) \ + ((cam_dflags & (flag)) \ + && (cam_dpath != NULL) \ + && (xpt_path_comp(cam_dpath, path) >= 0) \ + && (xpt_path_comp(cam_dpath, path) < 2)) +#define CAM_DEBUG(path, flag, printfargs) \ + if ((cam_dflags & (flag)) \ + && (cam_dpath != NULL) \ + && (xpt_path_comp(cam_dpath, path) >= 0) \ + && (xpt_path_comp(cam_dpath, path) < 2)) { \ + xpt_print_path(path); \ + printf printfargs; \ + if (cam_debug_delay != 0) \ + DELAY(cam_debug_delay); \ + } +#define CAM_DEBUG_PRINT(flag, printfargs) \ + if (cam_dflags & (flag)) { \ + printf("cam_debug: "); \ + printf printfargs; \ + if (cam_debug_delay != 0) \ + DELAY(cam_debug_delay); \ + } + +#else /* !CAMDEBUG || !_KERNEL */ + +#define CAM_DEBUGGED(A, B) 0 +#define CAM_DEBUG(A, B, C) +#define CAM_DEBUG_PRINT(A, B) + +#endif /* CAMDEBUG && _KERNEL */ + +#endif /* _CAM_CAM_DEBUG_H */ diff --git a/freebsd/sys/cam/cam_periph.h b/freebsd/sys/cam/cam_periph.h new file mode 100644 index 00000000..8bf8fd21 --- /dev/null +++ b/freebsd/sys/cam/cam_periph.h @@ -0,0 +1,204 @@ +/*- + * Data structures and definitions for CAM peripheral ("type") drivers. + * + * Copyright (c) 1997, 1998 Justin T. Gibbs. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _CAM_CAM_PERIPH_H +#define _CAM_CAM_PERIPH_H 1 + +#include <freebsd/sys/queue.h> +#include <freebsd/cam/cam_sim.h> + +#ifdef _KERNEL + +struct devstat; + +extern struct cam_periph *xpt_periph; + +extern struct periph_driver **periph_drivers; +void periphdriver_register(void *); +void periphdriver_init(int level); + +#include <freebsd/sys/module.h> +#define PERIPHDRIVER_DECLARE(name, driver) \ + static int name ## _modevent(module_t mod, int type, void *data) \ + { \ + switch (type) { \ + case MOD_LOAD: \ + periphdriver_register(data); \ + break; \ + case MOD_UNLOAD: \ + printf(#name " module unload - not possible for this module type\n"); \ + return EINVAL; \ + default: \ + return EOPNOTSUPP; \ + } \ + return 0; \ + } \ + static moduledata_t name ## _mod = { \ + #name, \ + name ## _modevent, \ + (void *)&driver \ + }; \ + DECLARE_MODULE(name, name ## _mod, SI_SUB_DRIVERS, SI_ORDER_ANY); \ + MODULE_DEPEND(name, cam, 1, 1, 1) + +typedef void (periph_init_t)(void); /* + * Callback informing the peripheral driver + * it can perform it's initialization since + * the XPT is now fully initialized. + */ +typedef periph_init_t *periph_init_func_t; + +struct periph_driver { + periph_init_func_t init; + char *driver_name; + TAILQ_HEAD(,cam_periph) units; + u_int generation; + u_int flags; +#define CAM_PERIPH_DRV_EARLY 0x01 +}; + +typedef enum { + CAM_PERIPH_BIO +} cam_periph_type; + +/* Generically usefull offsets into the peripheral private area */ +#define ppriv_ptr0 periph_priv.entries[0].ptr +#define ppriv_ptr1 periph_priv.entries[1].ptr +#define ppriv_field0 periph_priv.entries[0].field +#define ppriv_field1 periph_priv.entries[1].field + +typedef void periph_start_t (struct cam_periph *periph, + union ccb *start_ccb); +typedef cam_status periph_ctor_t (struct cam_periph *periph, + void *arg); +typedef void periph_oninv_t (struct cam_periph *periph); +typedef void periph_dtor_t (struct cam_periph *periph); +struct cam_periph { + cam_pinfo pinfo; + periph_start_t *periph_start; + periph_oninv_t *periph_oninval; + periph_dtor_t *periph_dtor; + char *periph_name; + struct cam_path *path; /* Compiled path to device */ + void *softc; + struct cam_sim *sim; + u_int32_t unit_number; + cam_periph_type type; + u_int32_t flags; +#define CAM_PERIPH_RUNNING 0x01 +#define CAM_PERIPH_LOCKED 0x02 +#define CAM_PERIPH_LOCK_WANTED 0x04 +#define CAM_PERIPH_INVALID 0x08 +#define CAM_PERIPH_NEW_DEV_FOUND 0x10 +#define CAM_PERIPH_RECOVERY_INPROG 0x20 +#define CAM_PERIPH_SENSE_INPROG 0x40 + u_int32_t immediate_priority; + u_int32_t refcount; + SLIST_HEAD(, ccb_hdr) ccb_list; /* For "immediate" requests */ + SLIST_ENTRY(cam_periph) periph_links; + TAILQ_ENTRY(cam_periph) unit_links; + ac_callback_t *deferred_callback; + ac_code deferred_ac; +}; + +#define CAM_PERIPH_MAXMAPS 2 + +struct cam_periph_map_info { + int num_bufs_used; + struct buf *bp[CAM_PERIPH_MAXMAPS]; +}; + +cam_status cam_periph_alloc(periph_ctor_t *periph_ctor, + periph_oninv_t *periph_oninvalidate, + periph_dtor_t *periph_dtor, + periph_start_t *periph_start, + char *name, cam_periph_type type, struct cam_path *, + ac_callback_t *, ac_code, void *arg); +struct cam_periph *cam_periph_find(struct cam_path *path, char *name); +cam_status cam_periph_acquire(struct cam_periph *periph); +void cam_periph_release(struct cam_periph *periph); +void cam_periph_release_locked(struct cam_periph *periph); +int cam_periph_hold(struct cam_periph *periph, int priority); +void cam_periph_unhold(struct cam_periph *periph); +void cam_periph_invalidate(struct cam_periph *periph); +int cam_periph_mapmem(union ccb *ccb, + struct cam_periph_map_info *mapinfo); +void cam_periph_unmapmem(union ccb *ccb, + struct cam_periph_map_info *mapinfo); +union ccb *cam_periph_getccb(struct cam_periph *periph, + u_int32_t priority); +void cam_periph_ccbwait(union ccb *ccb); +int cam_periph_runccb(union ccb *ccb, + int (*error_routine)(union ccb *ccb, + cam_flags camflags, + u_int32_t sense_flags), + cam_flags camflags, u_int32_t sense_flags, + struct devstat *ds); +int cam_periph_ioctl(struct cam_periph *periph, u_long cmd, + caddr_t addr, + int (*error_routine)(union ccb *ccb, + cam_flags camflags, + u_int32_t sense_flags)); +void cam_freeze_devq(struct cam_path *path); +void cam_freeze_devq_arg(struct cam_path *path, u_int32_t flags, + uint32_t arg); +u_int32_t cam_release_devq(struct cam_path *path, u_int32_t relsim_flags, + u_int32_t opening_reduction, u_int32_t arg, + int getcount_only); +void cam_periph_async(struct cam_periph *periph, u_int32_t code, + struct cam_path *path, void *arg); +void cam_periph_bus_settle(struct cam_periph *periph, + u_int bus_settle_ms); +void cam_periph_freeze_after_event(struct cam_periph *periph, + struct timeval* event_time, + u_int duration_ms); +int cam_periph_error(union ccb *ccb, cam_flags camflags, + u_int32_t sense_flags, union ccb *save_ccb); + +static __inline void +cam_periph_lock(struct cam_periph *periph) +{ + mtx_lock(periph->sim->mtx); +} + +static __inline void +cam_periph_unlock(struct cam_periph *periph) +{ + mtx_unlock(periph->sim->mtx); +} + +static __inline int +cam_periph_owned(struct cam_periph *periph) +{ + return (mtx_owned(periph->sim->mtx)); +} + +#endif /* _KERNEL */ +#endif /* _CAM_CAM_PERIPH_H */ diff --git a/freebsd/sys/cam/cam_sim.h b/freebsd/sys/cam/cam_sim.h new file mode 100644 index 00000000..6b5a496f --- /dev/null +++ b/freebsd/sys/cam/cam_sim.h @@ -0,0 +1,201 @@ +/*- + * Data structures and definitions for SCSI Interface Modules (SIMs). + * + * Copyright (c) 1997 Justin T. Gibbs. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _CAM_CAM_SIM_H +#define _CAM_CAM_SIM_H 1 + +#ifdef _KERNEL + +/* + * The sim driver creates a sim for each controller. The sim device + * queue is separately created in order to allow resource sharing between + * sims. For instance, a driver may create one sim for each channel of + * a multi-channel controller and use the same queue for each channel. + * In this way, the queue resources are shared across all the channels + * of the multi-channel controller. + */ + +struct cam_sim; +struct cam_devq; + +typedef void (*sim_action_func)(struct cam_sim *sim, union ccb *ccb); +typedef void (*sim_poll_func)(struct cam_sim *sim); + +struct cam_devq * cam_simq_alloc(u_int32_t max_sim_transactions); +void cam_simq_free(struct cam_devq *devq); + +struct cam_sim * cam_sim_alloc(sim_action_func sim_action, + sim_poll_func sim_poll, + const char *sim_name, + void *softc, + u_int32_t unit, + struct mtx *mtx, + int max_dev_transactions, + int max_tagged_dev_transactions, + struct cam_devq *queue); +void cam_sim_free(struct cam_sim *sim, int free_devq); +void cam_sim_hold(struct cam_sim *sim); +void cam_sim_release(struct cam_sim *sim); + +/* Optional sim attributes may be set with these. */ +void cam_sim_set_path(struct cam_sim *sim, u_int32_t path_id); + + + +/* Convenience routines for accessing sim attributes. */ +static __inline u_int32_t cam_sim_path(struct cam_sim *sim); +static __inline const char * cam_sim_name(struct cam_sim *sim); +static __inline void * cam_sim_softc(struct cam_sim *sim); +static __inline u_int32_t cam_sim_unit(struct cam_sim *sim); +#ifndef __rtems__ +static __inline u_int32_t cam_sim_bus(struct cam_sim *sim); +#endif /* __rtems__ */ + + + +/* Generically useful offsets into the sim private area */ +#define spriv_ptr0 sim_priv.entries[0].ptr +#define spriv_ptr1 sim_priv.entries[1].ptr +#define spriv_field0 sim_priv.entries[0].field +#define spriv_field1 sim_priv.entries[1].field + +#ifdef __rtems__ +/** + * @brief SIM states. + * + * @dot + * digraph bsd_sim_state { + * BSD_SIM_INIT -> BSD_SIM_INIT_BUSY; + * BSD_SIM_INIT -> BSD_SIM_IDLE; + * BSD_SIM_INIT_BUSY -> BSD_SIM_INIT_READY; + * BSD_SIM_BUSY -> BSD_SIM_IDLE; + * BSD_SIM_INIT_READY -> BSD_SIM_INIT; + * BSD_SIM_IDLE -> BSD_SIM_BUSY; + * BSD_SIM_IDLE -> BSD_SIM_DELETED; + * } + * @enddot + */ +enum bsd_sim_state { + BSD_SIM_INIT = 0, + BSD_SIM_INIT_BUSY, + BSD_SIM_INIT_READY, + BSD_SIM_IDLE, + BSD_SIM_BUSY, + BSD_SIM_DELETED +}; +#endif /* __rtems__ */ + +/* + * The sim driver should not access anything directly from this + * structure. + */ +struct cam_sim { + sim_action_func sim_action; + sim_poll_func sim_poll; + const char *sim_name; + void *softc; + struct mtx *mtx; +#ifndef __rtems__ + TAILQ_HEAD(, ccb_hdr) sim_doneq; + TAILQ_ENTRY(cam_sim) links; + u_int32_t path_id;/* The Boot device may set this to 0? */ +#else /* __rtems__ */ + char *disk; + enum bsd_sim_state state; + struct cv state_changed; + union ccb ccb; +#endif /* __rtems__ */ + u_int32_t unit_number; +#ifndef __rtems__ + u_int32_t bus_id; + int max_tagged_dev_openings; + int max_dev_openings; + u_int32_t flags; +#define CAM_SIM_REL_TIMEOUT_PENDING 0x01 +#define CAM_SIM_MPSAFE 0x02 +#define CAM_SIM_ON_DONEQ 0x04 + struct callout callout; + struct cam_devq *devq; /* Device Queue to use for this SIM */ + int refcount; /* References to the SIM. */ + + /* "Pool" of inactive ccbs managed by xpt_get_ccb and xpt_release_ccb */ + SLIST_HEAD(,ccb_hdr) ccb_freeq; + /* + * Maximum size of ccb pool. Modified as devices are added/removed + * or have their * opening counts changed. + */ + u_int max_ccbs; + /* Current count of allocated ccbs */ + u_int ccb_count; +#endif /* __rtems__ */ + +}; + +#define CAM_SIM_LOCK(sim) mtx_lock((sim)->mtx); +#define CAM_SIM_UNLOCK(sim) mtx_unlock((sim)->mtx); + +static __inline u_int32_t +cam_sim_path(struct cam_sim *sim) +{ +#ifndef __rtems__ + return (sim->path_id); +#else /* __rtems__ */ + return (0); +#endif /* __rtems__ */ +} + +static __inline const char * +cam_sim_name(struct cam_sim *sim) +{ + return (sim->sim_name); +} + +static __inline void * +cam_sim_softc(struct cam_sim *sim) +{ + return (sim->softc); +} + +static __inline u_int32_t +cam_sim_unit(struct cam_sim *sim) +{ + return (sim->unit_number); +} + +#ifndef __rtems__ +static __inline u_int32_t +cam_sim_bus(struct cam_sim *sim) +{ + return (sim->bus_id); +} +#endif /* __rtems__ */ + +#endif /* _KERNEL */ +#endif /* _CAM_CAM_SIM_H */ diff --git a/freebsd/sys/cam/cam_xpt.h b/freebsd/sys/cam/cam_xpt.h new file mode 100644 index 00000000..61a7f3f0 --- /dev/null +++ b/freebsd/sys/cam/cam_xpt.h @@ -0,0 +1,138 @@ +/*- + * Data structures and definitions for dealing with the + * Common Access Method Transport (xpt) layer. + * + * Copyright (c) 1997 Justin T. Gibbs. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _CAM_CAM_XPT_H +#define _CAM_CAM_XPT_H 1 + +/* Forward Declarations */ +union ccb; +struct cam_periph; +struct cam_sim; + +/* + * Definition of a CAM path. Paths are created from bus, target, and lun ids + * via xpt_create_path and allow for reference to devices without recurring + * lookups in the edt. + */ +struct cam_path; + +/* Path functions */ + +#ifdef _KERNEL + +/* + * Definition of an async handler callback block. These are used to add + * SIMs and peripherals to the async callback lists. + */ +struct async_node { + SLIST_ENTRY(async_node) links; + u_int32_t event_enable; /* Async Event enables */ + void (*callback)(void *arg, u_int32_t code, + struct cam_path *path, void *args); + void *callback_arg; +}; + +SLIST_HEAD(async_list, async_node); +SLIST_HEAD(periph_list, cam_periph); + +#if defined(CAM_DEBUG_FLAGS) && !defined(CAMDEBUG) +#error "You must have options CAMDEBUG to use options CAM_DEBUG_FLAGS" +#endif + +/* + * In order to enable the CAM_DEBUG_* options, the user must have CAMDEBUG + * enabled. Also, the user must have either none, or all of CAM_DEBUG_BUS, + * CAM_DEBUG_TARGET, and CAM_DEBUG_LUN specified. + */ +#if defined(CAM_DEBUG_BUS) || defined(CAM_DEBUG_TARGET) \ + || defined(CAM_DEBUG_LUN) +#ifdef CAMDEBUG +#if !defined(CAM_DEBUG_BUS) || !defined(CAM_DEBUG_TARGET) \ + || !defined(CAM_DEBUG_LUN) +#error "You must define all or none of CAM_DEBUG_BUS, CAM_DEBUG_TARGET \ + and CAM_DEBUG_LUN" +#endif /* !CAM_DEBUG_BUS || !CAM_DEBUG_TARGET || !CAM_DEBUG_LUN */ +#else /* !CAMDEBUG */ +#error "You must use options CAMDEBUG if you use the CAM_DEBUG_* options" +#endif /* CAMDEBUG */ +#endif /* CAM_DEBUG_BUS || CAM_DEBUG_TARGET || CAM_DEBUG_LUN */ + +void xpt_action(union ccb *new_ccb); +void xpt_action_default(union ccb *new_ccb); +union ccb *xpt_alloc_ccb(void); +union ccb *xpt_alloc_ccb_nowait(void); +void xpt_free_ccb(union ccb *free_ccb); +void xpt_setup_ccb(struct ccb_hdr *ccb_h, + struct cam_path *path, + u_int32_t priority); +void xpt_merge_ccb(union ccb *master_ccb, + union ccb *slave_ccb); +cam_status xpt_create_path(struct cam_path **new_path_ptr, + struct cam_periph *perph, + path_id_t path_id, + target_id_t target_id, lun_id_t lun_id); +cam_status xpt_create_path_unlocked(struct cam_path **new_path_ptr, + struct cam_periph *perph, + path_id_t path_id, + target_id_t target_id, lun_id_t lun_id); +void xpt_free_path(struct cam_path *path); +int xpt_path_comp(struct cam_path *path1, + struct cam_path *path2); +void xpt_print_path(struct cam_path *path); +void xpt_print(struct cam_path *path, const char *fmt, ...); +int xpt_path_string(struct cam_path *path, char *str, + size_t str_len); +path_id_t xpt_path_path_id(struct cam_path *path); +target_id_t xpt_path_target_id(struct cam_path *path); +lun_id_t xpt_path_lun_id(struct cam_path *path); +struct cam_sim *xpt_path_sim(struct cam_path *path); +struct cam_periph *xpt_path_periph(struct cam_path *path); +void xpt_async(u_int32_t async_code, struct cam_path *path, + void *async_arg); +void xpt_rescan(union ccb *ccb); +void xpt_hold_boot(void); +void xpt_release_boot(void); +void xpt_lock_buses(void); +void xpt_unlock_buses(void); +cam_status xpt_register_async(int event, ac_callback_t *cbfunc, + void *cbarg, struct cam_path *path); +cam_status xpt_compile_path(struct cam_path *new_path, + struct cam_periph *perph, + path_id_t path_id, + target_id_t target_id, + lun_id_t lun_id); + +void xpt_release_path(struct cam_path *path); + +#endif /* _KERNEL */ + +#endif /* _CAM_CAM_XPT_H */ + diff --git a/freebsd/sys/cam/cam_xpt_sim.h b/freebsd/sys/cam/cam_xpt_sim.h new file mode 100644 index 00000000..32c3082b --- /dev/null +++ b/freebsd/sys/cam/cam_xpt_sim.h @@ -0,0 +1,57 @@ +/*- + * Data structures and definitions for dealing with the + * Common Access Method Transport (xpt) layer. + * + * Copyright (c) 1997 Justin T. Gibbs. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _CAM_CAM_XPT_SIM_H +#define _CAM_CAM_XPT_SIM_H 1 + +#include <freebsd/cam/cam_xpt.h> +#include <freebsd/cam/cam_queue.h> + +/* Functions accessed by SIM drivers */ +#ifdef _KERNEL +int32_t xpt_bus_register(struct cam_sim *sim, device_t parent, + u_int32_t bus); +int32_t xpt_bus_deregister(path_id_t path_id); +u_int32_t xpt_freeze_simq(struct cam_sim *sim, u_int count); +void xpt_release_simq(struct cam_sim *sim, int run_queue); +u_int32_t xpt_freeze_devq(struct cam_path *path, u_int count); +u_int32_t xpt_freeze_devq_rl(struct cam_path *path, cam_rl rl, + u_int count); +void xpt_release_devq(struct cam_path *path, + u_int count, int run_queue); +void xpt_release_devq_rl(struct cam_path *path, cam_rl rl, + u_int count, int run_queue); +int xpt_sim_opened(struct cam_sim *sim); +void xpt_done(union ccb *done_ccb); +#endif + +#endif /* _CAM_CAM_XPT_SIM_H */ + diff --git a/freebsd/sys/cam/scsi/scsi_all.c b/freebsd/sys/cam/scsi/scsi_all.c new file mode 100644 index 00000000..a25a20b8 --- /dev/null +++ b/freebsd/sys/cam/scsi/scsi_all.c @@ -0,0 +1,4305 @@ +#include <freebsd/machine/rtems-bsd-config.h> + +/*- + * Implementation of Utility functions for all SCSI device types. + * + * Copyright (c) 1997, 1998, 1999 Justin T. Gibbs. + * Copyright (c) 1997, 1998, 2003 Kenneth D. Merry. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <freebsd/sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <freebsd/sys/param.h> + +#ifdef _KERNEL +#ifndef __rtems__ +#include <freebsd/opt_scsi.h> +#else /* __rtems__ */ +#include <freebsd/local/opt_scsi.h> +#endif /* __rtems__ */ + +#include <freebsd/sys/systm.h> +#include <freebsd/sys/libkern.h> +#include <freebsd/sys/kernel.h> +#include <freebsd/sys/sysctl.h> +#else +#include <freebsd/errno.h> +#include <freebsd/stdio.h> +#include <freebsd/stdlib.h> +#include <freebsd/string.h> +#endif + +#include <freebsd/cam/cam.h> +#include <freebsd/cam/cam_ccb.h> +#include <freebsd/cam/cam_queue.h> +#include <freebsd/cam/cam_xpt.h> +#include <freebsd/cam/scsi/scsi_all.h> +#include <freebsd/sys/sbuf.h> +#ifndef _KERNEL +#include <freebsd/camlib.h> + +#ifndef FALSE +#define FALSE 0 +#endif /* FALSE */ +#ifndef TRUE +#define TRUE 1 +#endif /* TRUE */ +#define ERESTART -1 /* restart syscall */ +#define EJUSTRETURN -2 /* don't modify regs, just return */ +#endif /* !_KERNEL */ + +/* + * This is the default number of milliseconds we wait for devices to settle + * after a SCSI bus reset. + */ +#ifndef SCSI_DELAY +#define SCSI_DELAY 2000 +#endif +/* + * All devices need _some_ sort of bus settle delay, so we'll set it to + * a minimum value of 100ms. Note that this is pertinent only for SPI- + * not transport like Fibre Channel or iSCSI where 'delay' is completely + * meaningless. + */ +#ifndef SCSI_MIN_DELAY +#define SCSI_MIN_DELAY 100 +#endif +/* + * Make sure the user isn't using seconds instead of milliseconds. + */ +#if (SCSI_DELAY < SCSI_MIN_DELAY && SCSI_DELAY != 0) +#error "SCSI_DELAY is in milliseconds, not seconds! Please use a larger value" +#endif + +#ifndef __rtems__ +int scsi_delay; + +static int ascentrycomp(const void *key, const void *member); +static int senseentrycomp(const void *key, const void *member); +static void fetchtableentries(int sense_key, int asc, int ascq, + struct scsi_inquiry_data *, + const struct sense_key_table_entry **, + const struct asc_table_entry **); +#ifdef _KERNEL +static void init_scsi_delay(void); +static int sysctl_scsi_delay(SYSCTL_HANDLER_ARGS); +static int set_scsi_delay(int delay); +#endif + +#if !defined(SCSI_NO_OP_STRINGS) + +#define D (1 << T_DIRECT) +#define T (1 << T_SEQUENTIAL) +#define L (1 << T_PRINTER) +#define P (1 << T_PROCESSOR) +#define W (1 << T_WORM) +#define R (1 << T_CDROM) +#define O (1 << T_OPTICAL) +#define M (1 << T_CHANGER) +#define A (1 << T_STORARRAY) +#define E (1 << T_ENCLOSURE) +#define B (1 << T_RBC) +#define K (1 << T_OCRW) +#define V (1 << T_ADC) +#define F (1 << T_OSD) +#define S (1 << T_SCANNER) +#define C (1 << T_COMM) + +#define ALL (D | T | L | P | W | R | O | M | A | E | B | K | V | F | S | C) + +static struct op_table_entry plextor_cd_ops[] = { + { 0xD8, R, "CD-DA READ" } +}; + +static struct scsi_op_quirk_entry scsi_op_quirk_table[] = { + { + /* + * I believe that 0xD8 is the Plextor proprietary command + * to read CD-DA data. I'm not sure which Plextor CDROM + * models support the command, though. I know for sure + * that the 4X, 8X, and 12X models do, and presumably the + * 12-20X does. I don't know about any earlier models, + * though. If anyone has any more complete information, + * feel free to change this quirk entry. + */ + {T_CDROM, SIP_MEDIA_REMOVABLE, "PLEXTOR", "CD-ROM PX*", "*"}, + sizeof(plextor_cd_ops)/sizeof(struct op_table_entry), + plextor_cd_ops + } +}; + +static struct op_table_entry scsi_op_codes[] = { + /* + * From: http://www.t10.org/lists/op-num.txt + * Modifications by Kenneth Merry (ken@FreeBSD.ORG) + * and Jung-uk Kim (jkim@FreeBSD.org) + * + * Note: order is important in this table, scsi_op_desc() currently + * depends on the opcodes in the table being in order to save + * search time. + * Note: scanner and comm. devices are carried over from the previous + * version because they were removed in the latest spec. + */ + /* File: OP-NUM.TXT + * + * SCSI Operation Codes + * Numeric Sorted Listing + * as of 3/11/08 + * + * D - DIRECT ACCESS DEVICE (SBC-2) device column key + * .T - SEQUENTIAL ACCESS DEVICE (SSC-2) ----------------- + * . L - PRINTER DEVICE (SSC) M = Mandatory + * . P - PROCESSOR DEVICE (SPC) O = Optional + * . .W - WRITE ONCE READ MULTIPLE DEVICE (SBC-2) V = Vendor spec. + * . . R - CD/DVE DEVICE (MMC-3) Z = Obsolete + * . . O - OPTICAL MEMORY DEVICE (SBC-2) + * . . .M - MEDIA CHANGER DEVICE (SMC-2) + * . . . A - STORAGE ARRAY DEVICE (SCC-2) + * . . . .E - ENCLOSURE SERVICES DEVICE (SES) + * . . . .B - SIMPLIFIED DIRECT-ACCESS DEVICE (RBC) + * . . . . K - OPTICAL CARD READER/WRITER DEVICE (OCRW) + * . . . . V - AUTOMATION/DRIVE INTERFACE (ADC) + * . . . . .F - OBJECT-BASED STORAGE (OSD) + * OP DTLPWROMAEBKVF Description + * -- -------------- ---------------------------------------------- */ + /* 00 MMMMMMMMMMMMMM TEST UNIT READY */ + { 0x00, ALL, "TEST UNIT READY" }, + /* 01 M REWIND */ + { 0x01, T, "REWIND" }, + /* 01 Z V ZZZZ REZERO UNIT */ + { 0x01, D | W | R | O | M, "REZERO UNIT" }, + /* 02 VVVVVV V */ + /* 03 MMMMMMMMMMOMMM REQUEST SENSE */ + { 0x03, ALL, "REQUEST SENSE" }, + /* 04 M OO FORMAT UNIT */ + { 0x04, D | R | O, "FORMAT UNIT" }, + /* 04 O FORMAT MEDIUM */ + { 0x04, T, "FORMAT MEDIUM" }, + /* 04 O FORMAT */ + { 0x04, L, "FORMAT" }, + /* 05 VMVVVV V READ BLOCK LIMITS */ + { 0x05, T, "READ BLOCK LIMITS" }, + /* 06 VVVVVV V */ + /* 07 OVV O OV REASSIGN BLOCKS */ + { 0x07, D | W | O, "REASSIGN BLOCKS" }, + /* 07 O INITIALIZE ELEMENT STATUS */ + { 0x07, M, "INITIALIZE ELEMENT STATUS" }, + /* 08 MOV O OV READ(6) */ + { 0x08, D | T | W | O, "READ(6)" }, + /* 08 O RECEIVE */ + { 0x08, P, "RECEIVE" }, + /* 08 GET MESSAGE(6) */ + { 0x08, C, "GET MESSAGE(6)" }, + /* 09 VVVVVV V */ + /* 0A OO O OV WRITE(6) */ + { 0x0A, D | T | W | O, "WRITE(6)" }, + /* 0A M SEND(6) */ + { 0x0A, P, "SEND(6)" }, + /* 0A SEND MESSAGE(6) */ + { 0x0A, C, "SEND MESSAGE(6)" }, + /* 0A M PRINT */ + { 0x0A, L, "PRINT" }, + /* 0B Z ZOZV SEEK(6) */ + { 0x0B, D | W | R | O, "SEEK(6)" }, + /* 0B O SET CAPACITY */ + { 0x0B, T, "SET CAPACITY" }, + /* 0B O SLEW AND PRINT */ + { 0x0B, L, "SLEW AND PRINT" }, + /* 0C VVVVVV V */ + /* 0D VVVVVV V */ + /* 0E VVVVVV V */ + /* 0F VOVVVV V READ REVERSE(6) */ + { 0x0F, T, "READ REVERSE(6)" }, + /* 10 VM VVV WRITE FILEMARKS(6) */ + { 0x10, T, "WRITE FILEMARKS(6)" }, + /* 10 O SYNCHRONIZE BUFFER */ + { 0x10, L, "SYNCHRONIZE BUFFER" }, + /* 11 VMVVVV SPACE(6) */ + { 0x11, T, "SPACE(6)" }, + /* 12 MMMMMMMMMMMMMM INQUIRY */ + { 0x12, ALL, "INQUIRY" }, + /* 13 V VVVV */ + /* 13 O VERIFY(6) */ + { 0x13, T, "VERIFY(6)" }, + /* 14 VOOVVV RECOVER BUFFERED DATA */ + { 0x14, T | L, "RECOVER BUFFERED DATA" }, + /* 15 OMO O OOOO OO MODE SELECT(6) */ + { 0x15, ALL & ~(P | R | B | F), "MODE SELECT(6)" }, + /* 16 ZZMZO OOOZ O RESERVE(6) */ + { 0x16, ALL & ~(R | B | V | F | C), "RESERVE(6)" }, + /* 16 Z RESERVE ELEMENT(6) */ + { 0x16, M, "RESERVE ELEMENT(6)" }, + /* 17 ZZMZO OOOZ O RELEASE(6) */ + { 0x17, ALL & ~(R | B | V | F | C), "RELEASE(6)" }, + /* 17 Z RELEASE ELEMENT(6) */ + { 0x17, M, "RELEASE ELEMENT(6)" }, + /* 18 ZZZZOZO Z COPY */ + { 0x18, D | T | L | P | W | R | O | K | S, "COPY" }, + /* 19 VMVVVV ERASE(6) */ + { 0x19, T, "ERASE(6)" }, + /* 1A OMO O OOOO OO MODE SENSE(6) */ + { 0x1A, ALL & ~(P | R | B | F), "MODE SENSE(6)" }, + /* 1B O OOO O MO O START STOP UNIT */ + { 0x1B, D | W | R | O | A | B | K | F, "START STOP UNIT" }, + /* 1B O M LOAD UNLOAD */ + { 0x1B, T | V, "LOAD UNLOAD" }, + /* 1B SCAN */ + { 0x1B, S, "SCAN" }, + /* 1B O STOP PRINT */ + { 0x1B, L, "STOP PRINT" }, + /* 1B O OPEN/CLOSE IMPORT/EXPORT ELEMENT */ + { 0x1B, M, "OPEN/CLOSE IMPORT/EXPORT ELEMENT" }, + /* 1C OOOOO OOOM OOO RECEIVE DIAGNOSTIC RESULTS */ + { 0x1C, ALL & ~(R | B), "RECEIVE DIAGNOSTIC RESULTS" }, + /* 1D MMMMM MMOM MMM SEND DIAGNOSTIC */ + { 0x1D, ALL & ~(R | B), "SEND DIAGNOSTIC" }, + /* 1E OO OOOO O O PREVENT ALLOW MEDIUM REMOVAL */ + { 0x1E, D | T | W | R | O | M | K | F, "PREVENT ALLOW MEDIUM REMOVAL" }, + /* 1F */ + /* 20 V VVV V */ + /* 21 V VVV V */ + /* 22 V VVV V */ + /* 23 V V V V */ + /* 23 O READ FORMAT CAPACITIES */ + { 0x23, R, "READ FORMAT CAPACITIES" }, + /* 24 V VV SET WINDOW */ + { 0x24, S, "SET WINDOW" }, + /* 25 M M M M READ CAPACITY(10) */ + { 0x25, D | W | O | B, "READ CAPACITY(10)" }, + /* 25 O READ CAPACITY */ + { 0x25, R, "READ CAPACITY" }, + /* 25 M READ CARD CAPACITY */ + { 0x25, K, "READ CARD CAPACITY" }, + /* 25 GET WINDOW */ + { 0x25, S, "GET WINDOW" }, + /* 26 V VV */ + /* 27 V VV */ + /* 28 M MOM MM READ(10) */ + { 0x28, D | W | R | O | B | K | S, "READ(10)" }, + /* 28 GET MESSAGE(10) */ + { 0x28, C, "GET MESSAGE(10)" }, + /* 29 V VVO READ GENERATION */ + { 0x29, O, "READ GENERATION" }, + /* 2A O MOM MO WRITE(10) */ + { 0x2A, D | W | R | O | B | K, "WRITE(10)" }, + /* 2A SEND(10) */ + { 0x2A, S, "SEND(10)" }, + /* 2A SEND MESSAGE(10) */ + { 0x2A, C, "SEND MESSAGE(10)" }, + /* 2B Z OOO O SEEK(10) */ + { 0x2B, D | W | R | O | K, "SEEK(10)" }, + /* 2B O LOCATE(10) */ + { 0x2B, T, "LOCATE(10)" }, + /* 2B O POSITION TO ELEMENT */ + { 0x2B, M, "POSITION TO ELEMENT" }, + /* 2C V OO ERASE(10) */ + { 0x2C, R | O, "ERASE(10)" }, + /* 2D O READ UPDATED BLOCK */ + { 0x2D, O, "READ UPDATED BLOCK" }, + /* 2D V */ + /* 2E O OOO MO WRITE AND VERIFY(10) */ + { 0x2E, D | W | R | O | B | K, "WRITE AND VERIFY(10)" }, + /* 2F O OOO VERIFY(10) */ + { 0x2F, D | W | R | O, "VERIFY(10)" }, + /* 30 Z ZZZ SEARCH DATA HIGH(10) */ + { 0x30, D | W | R | O, "SEARCH DATA HIGH(10)" }, + /* 31 Z ZZZ SEARCH DATA EQUAL(10) */ + { 0x31, D | W | R | O, "SEARCH DATA EQUAL(10)" }, + /* 31 OBJECT POSITION */ + { 0x31, S, "OBJECT POSITION" }, + /* 32 Z ZZZ SEARCH DATA LOW(10) */ + { 0x32, D | W | R | O, "SEARCH DATA LOW(10)" }, + /* 33 Z OZO SET LIMITS(10) */ + { 0x33, D | W | R | O, "SET LIMITS(10)" }, + /* 34 O O O O PRE-FETCH(10) */ + { 0x34, D | W | O | K, "PRE-FETCH(10)" }, + /* 34 M READ POSITION */ + { 0x34, T, "READ POSITION" }, + /* 34 GET DATA BUFFER STATUS */ + { 0x34, S, "GET DATA BUFFER STATUS" }, + /* 35 O OOO MO SYNCHRONIZE CACHE(10) */ + { 0x35, D | W | R | O | B | K, "SYNCHRONIZE CACHE(10)" }, + /* 36 Z O O O LOCK UNLOCK CACHE(10) */ + { 0x36, D | W | O | K, "LOCK UNLOCK CACHE(10)" }, + /* 37 O O READ DEFECT DATA(10) */ + { 0x37, D | O, "READ DEFECT DATA(10)" }, + /* 37 O INITIALIZE ELEMENT STATUS WITH RANGE */ + { 0x37, M, "INITIALIZE ELEMENT STATUS WITH RANGE" }, + /* 38 O O O MEDIUM SCAN */ + { 0x38, W | O | K, "MEDIUM SCAN" }, + /* 39 ZZZZOZO Z COMPARE */ + { 0x39, D | T | L | P | W | R | O | K | S, "COMPARE" }, + /* 3A ZZZZOZO Z COPY AND VERIFY */ + { 0x3A, D | T | L | P | W | R | O | K | S, "COPY AND VERIFY" }, + /* 3B OOOOOOOOOOMOOO WRITE BUFFER */ + { 0x3B, ALL, "WRITE BUFFER" }, + /* 3C OOOOOOOOOO OOO READ BUFFER */ + { 0x3C, ALL & ~(B), "READ BUFFER" }, + /* 3D O UPDATE BLOCK */ + { 0x3D, O, "UPDATE BLOCK" }, + /* 3E O O O READ LONG(10) */ + { 0x3E, D | W | O, "READ LONG(10)" }, + /* 3F O O O WRITE LONG(10) */ + { 0x3F, D | W | O, "WRITE LONG(10)" }, + /* 40 ZZZZOZOZ CHANGE DEFINITION */ + { 0x40, D | T | L | P | W | R | O | M | S | C, "CHANGE DEFINITION" }, + /* 41 O WRITE SAME(10) */ + { 0x41, D, "WRITE SAME(10)" }, + /* 42 O READ SUB-CHANNEL */ + { 0x42, R, "READ SUB-CHANNEL" }, + /* 43 O READ TOC/PMA/ATIP */ + { 0x43, R, "READ TOC/PMA/ATIP" }, + /* 44 M M REPORT DENSITY SUPPORT */ + { 0x44, T | V, "REPORT DENSITY SUPPORT" }, + /* 44 READ HEADER */ + /* 45 O PLAY AUDIO(10) */ + { 0x45, R, "PLAY AUDIO(10)" }, + /* 46 M GET CONFIGURATION */ + { 0x46, R, "GET CONFIGURATION" }, + /* 47 O PLAY AUDIO MSF */ + { 0x47, R, "PLAY AUDIO MSF" }, + /* 48 */ + /* 49 */ + /* 4A M GET EVENT STATUS NOTIFICATION */ + { 0x4A, R, "GET EVENT STATUS NOTIFICATION" }, + /* 4B O PAUSE/RESUME */ + { 0x4B, R, "PAUSE/RESUME" }, + /* 4C OOOOO OOOO OOO LOG SELECT */ + { 0x4C, ALL & ~(R | B), "LOG SELECT" }, + /* 4D OOOOO OOOO OMO LOG SENSE */ + { 0x4D, ALL & ~(R | B), "LOG SENSE" }, + /* 4E O STOP PLAY/SCAN */ + { 0x4E, R, "STOP PLAY/SCAN" }, + /* 4F */ + /* 50 O XDWRITE(10) */ + { 0x50, D, "XDWRITE(10)" }, + /* 51 O XPWRITE(10) */ + { 0x51, D, "XPWRITE(10)" }, + /* 51 O READ DISC INFORMATION */ + { 0x51, R, "READ DISC INFORMATION" }, + /* 52 O XDREAD(10) */ + { 0x52, D, "XDREAD(10)" }, + /* 52 O READ TRACK INFORMATION */ + { 0x52, R, "READ TRACK INFORMATION" }, + /* 53 O RESERVE TRACK */ + { 0x53, R, "RESERVE TRACK" }, + /* 54 O SEND OPC INFORMATION */ + { 0x54, R, "SEND OPC INFORMATION" }, + /* 55 OOO OMOOOOMOMO MODE SELECT(10) */ + { 0x55, ALL & ~(P), "MODE SELECT(10)" }, + /* 56 ZZMZO OOOZ RESERVE(10) */ + { 0x56, ALL & ~(R | B | K | V | F | C), "RESERVE(10)" }, + /* 56 Z RESERVE ELEMENT(10) */ + { 0x56, M, "RESERVE ELEMENT(10)" }, + /* 57 ZZMZO OOOZ RELEASE(10) */ + { 0x57, ALL & ~(R | B | K | V | F | C), "RELEASE(10)" }, + /* 57 Z RELEASE ELEMENT(10) */ + { 0x57, M, "RELEASE ELEMENT(10)" }, + /* 58 O REPAIR TRACK */ + { 0x58, R, "REPAIR TRACK" }, + /* 59 */ + /* 5A OOO OMOOOOMOMO MODE SENSE(10) */ + { 0x5A, ALL & ~(P), "MODE SENSE(10)" }, + /* 5B O CLOSE TRACK/SESSION */ + { 0x5B, R, "CLOSE TRACK/SESSION" }, + /* 5C O READ BUFFER CAPACITY */ + { 0x5C, R, "READ BUFFER CAPACITY" }, + /* 5D O SEND CUE SHEET */ + { 0x5D, R, "SEND CUE SHEET" }, + /* 5E OOOOO OOOO M PERSISTENT RESERVE IN */ + { 0x5E, ALL & ~(R | B | K | V | C), "PERSISTENT RESERVE IN" }, + /* 5F OOOOO OOOO M PERSISTENT RESERVE OUT */ + { 0x5F, ALL & ~(R | B | K | V | C), "PERSISTENT RESERVE OUT" }, + /* 7E OO O OOOO O extended CDB */ + { 0x7E, D | T | R | M | A | E | B | V, "extended CDB" }, + /* 7F O M variable length CDB (more than 16 bytes) */ + { 0x7F, D | F, "variable length CDB (more than 16 bytes)" }, + /* 80 Z XDWRITE EXTENDED(16) */ + { 0x80, D, "XDWRITE EXTENDED(16)" }, + /* 80 M WRITE FILEMARKS(16) */ + { 0x80, T, "WRITE FILEMARKS(16)" }, + /* 81 Z REBUILD(16) */ + { 0x81, D, "REBUILD(16)" }, + /* 81 O READ REVERSE(16) */ + { 0x81, T, "READ REVERSE(16)" }, + /* 82 Z REGENERATE(16) */ + { 0x82, D, "REGENERATE(16)" }, + /* 83 OOOOO O OO EXTENDED COPY */ + { 0x83, D | T | L | P | W | O | K | V, "EXTENDED COPY" }, + /* 84 OOOOO O OO RECEIVE COPY RESULTS */ + { 0x84, D | T | L | P | W | O | K | V, "RECEIVE COPY RESULTS" }, + /* 85 O O O ATA COMMAND PASS THROUGH(16) */ + { 0x85, D | R | B, "ATA COMMAND PASS THROUGH(16)" }, + /* 86 OO OO OOOOOOO ACCESS CONTROL IN */ + { 0x86, ALL & ~(L | R | F), "ACCESS CONTROL IN" }, + /* 87 OO OO OOOOOOO ACCESS CONTROL OUT */ + { 0x87, ALL & ~(L | R | F), "ACCESS CONTROL OUT" }, + /* + * XXX READ(16)/WRITE(16) were not listed for CD/DVE in op-num.txt + * but we had it since r1.40. Do we really want them? + */ + /* 88 MM O O O READ(16) */ + { 0x88, D | T | W | O | B, "READ(16)" }, + /* 89 */ + /* 8A OM O O O WRITE(16) */ + { 0x8A, D | T | W | O | B, "WRITE(16)" }, + /* 8B O ORWRITE */ + { 0x8B, D, "ORWRITE" }, + /* 8C OO O OO O M READ ATTRIBUTE */ + { 0x8C, D | T | W | O | M | B | V, "READ ATTRIBUTE" }, + /* 8D OO O OO O O WRITE ATTRIBUTE */ + { 0x8D, D | T | W | O | M | B | V, "WRITE ATTRIBUTE" }, + /* 8E O O O O WRITE AND VERIFY(16) */ + { 0x8E, D | W | O | B, "WRITE AND VERIFY(16)" }, + /* 8F OO O O O VERIFY(16) */ + { 0x8F, D | T | W | O | B, "VERIFY(16)" }, + /* 90 O O O O PRE-FETCH(16) */ + { 0x90, D | W | O | B, "PRE-FETCH(16)" }, + /* 91 O O O O SYNCHRONIZE CACHE(16) */ + { 0x91, D | W | O | B, "SYNCHRONIZE CACHE(16)" }, + /* 91 O SPACE(16) */ + { 0x91, T, "SPACE(16)" }, + /* 92 Z O O LOCK UNLOCK CACHE(16) */ + { 0x92, D | W | O, "LOCK UNLOCK CACHE(16)" }, + /* 92 O LOCATE(16) */ + { 0x92, T, "LOCATE(16)" }, + /* 93 O WRITE SAME(16) */ + { 0x93, D, "WRITE SAME(16)" }, + /* 93 M ERASE(16) */ + { 0x93, T, "ERASE(16)" }, + /* 94 [usage proposed by SCSI Socket Services project] */ + /* 95 [usage proposed by SCSI Socket Services project] */ + /* 96 [usage proposed by SCSI Socket Services project] */ + /* 97 [usage proposed by SCSI Socket Services project] */ + /* 98 */ + /* 99 */ + /* 9A */ + /* 9B */ + /* 9C */ + /* 9D */ + /* XXX KDM ALL for this? op-num.txt defines it for none.. */ + /* 9E SERVICE ACTION IN(16) */ + { 0x9E, ALL, "SERVICE ACTION IN(16)" }, + /* XXX KDM ALL for this? op-num.txt defines it for ADC.. */ + /* 9F M SERVICE ACTION OUT(16) */ + { 0x9F, ALL, "SERVICE ACTION OUT(16)" }, + /* A0 MMOOO OMMM OMO REPORT LUNS */ + { 0xA0, ALL & ~(R | B), "REPORT LUNS" }, + /* A1 O BLANK */ + { 0xA1, R, "BLANK" }, + /* A1 O O ATA COMMAND PASS THROUGH(12) */ + { 0xA1, D | B, "ATA COMMAND PASS THROUGH(12)" }, + /* A2 OO O O SECURITY PROTOCOL IN */ + { 0xA2, D | T | R | V, "SECURITY PROTOCOL IN" }, + /* A3 OOO O OOMOOOM MAINTENANCE (IN) */ + { 0xA3, ALL & ~(P | R | F), "MAINTENANCE (IN)" }, + /* A3 O SEND KEY */ + { 0xA3, R, "SEND KEY" }, + /* A4 OOO O OOOOOOO MAINTENANCE (OUT) */ + { 0xA4, ALL & ~(P | R | F), "MAINTENANCE (OUT)" }, + /* A4 O REPORT KEY */ + { 0xA4, R, "REPORT KEY" }, + /* A5 O O OM MOVE MEDIUM */ + { 0xA5, T | W | O | M, "MOVE MEDIUM" }, + /* A5 O PLAY AUDIO(12) */ + { 0xA5, R, "PLAY AUDIO(12)" }, + /* A6 O EXCHANGE MEDIUM */ + { 0xA6, M, "EXCHANGE MEDIUM" }, + /* A6 O LOAD/UNLOAD C/DVD */ + { 0xA6, R, "LOAD/UNLOAD C/DVD" }, + /* A7 ZZ O O MOVE MEDIUM ATTACHED */ + { 0xA7, D | T | W | O, "MOVE MEDIUM ATTACHED" }, + /* A7 O SET READ AHEAD */ + { 0xA7, R, "SET READ AHEAD" }, + /* A8 O OOO READ(12) */ + { 0xA8, D | W | R | O, "READ(12)" }, + /* A8 GET MESSAGE(12) */ + { 0xA8, C, "GET MESSAGE(12)" }, + /* A9 O SERVICE ACTION OUT(12) */ + { 0xA9, V, "SERVICE ACTION OUT(12)" }, + /* AA O OOO WRITE(12) */ + { 0xAA, D | W | R | O, "WRITE(12)" }, + /* AA SEND MESSAGE(12) */ + { 0xAA, C, "SEND MESSAGE(12)" }, + /* AB O O SERVICE ACTION IN(12) */ + { 0xAB, R | V, "SERVICE ACTION IN(12)" }, + /* AC O ERASE(12) */ + { 0xAC, O, "ERASE(12)" }, + /* AC O GET PERFORMANCE */ + { 0xAC, R, "GET PERFORMANCE" }, + /* AD O READ DVD STRUCTURE */ + { 0xAD, R, "READ DVD STRUCTURE" }, + /* AE O O O WRITE AND VERIFY(12) */ + { 0xAE, D | W | O, "WRITE AND VERIFY(12)" }, + /* AF O OZO VERIFY(12) */ + { 0xAF, D | W | R | O, "VERIFY(12)" }, + /* B0 ZZZ SEARCH DATA HIGH(12) */ + { 0xB0, W | R | O, "SEARCH DATA HIGH(12)" }, + /* B1 ZZZ SEARCH DATA EQUAL(12) */ + { 0xB1, W | R | O, "SEARCH DATA EQUAL(12)" }, + /* B2 ZZZ SEARCH DATA LOW(12) */ + { 0xB2, W | R | O, "SEARCH DATA LOW(12)" }, + /* B3 Z OZO SET LIMITS(12) */ + { 0xB3, D | W | R | O, "SET LIMITS(12)" }, + /* B4 ZZ OZO READ ELEMENT STATUS ATTACHED */ + { 0xB4, D | T | W | R | O, "READ ELEMENT STATUS ATTACHED" }, + /* B5 OO O O SECURITY PROTOCOL OUT */ + { 0xB5, D | T | R | V, "SECURITY PROTOCOL OUT" }, + /* B5 O REQUEST VOLUME ELEMENT ADDRESS */ + { 0xB5, M, "REQUEST VOLUME ELEMENT ADDRESS" }, + /* B6 O SEND VOLUME TAG */ + { 0xB6, M, "SEND VOLUME TAG" }, + /* B6 O SET STREAMING */ + { 0xB6, R, "SET STREAMING" }, + /* B7 O O READ DEFECT DATA(12) */ + { 0xB7, D | O, "READ DEFECT DATA(12)" }, + /* B8 O OZOM READ ELEMENT STATUS */ + { 0xB8, T | W | R | O | M, "READ ELEMENT STATUS" }, + /* B9 O READ CD MSF */ + { 0xB9, R, "READ CD MSF" }, + /* BA O O OOMO REDUNDANCY GROUP (IN) */ + { 0xBA, D | W | O | M | A | E, "REDUNDANCY GROUP (IN)" }, + /* BA O SCAN */ + { 0xBA, R, "SCAN" }, + /* BB O O OOOO REDUNDANCY GROUP (OUT) */ + { 0xBB, D | W | O | M | A | E, "REDUNDANCY GROUP (OUT)" }, + /* BB O SET CD SPEED */ + { 0xBB, R, "SET CD SPEED" }, + /* BC O O OOMO SPARE (IN) */ + { 0xBC, D | W | O | M | A | E, "SPARE (IN)" }, + /* BD O O OOOO SPARE (OUT) */ + { 0xBD, D | W | O | M | A | E, "SPARE (OUT)" }, + /* BD O MECHANISM STATUS */ + { 0xBD, R, "MECHANISM STATUS" }, + /* BE O O OOMO VOLUME SET (IN) */ + { 0xBE, D | W | O | M | A | E, "VOLUME SET (IN)" }, + /* BE O READ CD */ + { 0xBE, R, "READ CD" }, + /* BF O O OOOO VOLUME SET (OUT) */ + { 0xBF, D | W | O | M | A | E, "VOLUME SET (OUT)" }, + /* BF O SEND DVD STRUCTURE */ + { 0xBF, R, "SEND DVD STRUCTURE" } +}; + +const char * +scsi_op_desc(u_int16_t opcode, struct scsi_inquiry_data *inq_data) +{ + caddr_t match; + int i, j; + u_int32_t opmask; + u_int16_t pd_type; + int num_ops[2]; + struct op_table_entry *table[2]; + int num_tables; + + pd_type = SID_TYPE(inq_data); + + match = cam_quirkmatch((caddr_t)inq_data, + (caddr_t)scsi_op_quirk_table, + sizeof(scsi_op_quirk_table)/ + sizeof(*scsi_op_quirk_table), + sizeof(*scsi_op_quirk_table), + scsi_inquiry_match); + + if (match != NULL) { + table[0] = ((struct scsi_op_quirk_entry *)match)->op_table; + num_ops[0] = ((struct scsi_op_quirk_entry *)match)->num_ops; + table[1] = scsi_op_codes; + num_ops[1] = sizeof(scsi_op_codes)/sizeof(scsi_op_codes[0]); + num_tables = 2; + } else { + /* + * If this is true, we have a vendor specific opcode that + * wasn't covered in the quirk table. + */ + if ((opcode > 0xBF) || ((opcode > 0x5F) && (opcode < 0x80))) + return("Vendor Specific Command"); + + table[0] = scsi_op_codes; + num_ops[0] = sizeof(scsi_op_codes)/sizeof(scsi_op_codes[0]); + num_tables = 1; + } + + /* RBC is 'Simplified' Direct Access Device */ + if (pd_type == T_RBC) + pd_type = T_DIRECT; + + opmask = 1 << pd_type; + + for (j = 0; j < num_tables; j++) { + for (i = 0;i < num_ops[j] && table[j][i].opcode <= opcode; i++){ + if ((table[j][i].opcode == opcode) + && ((table[j][i].opmask & opmask) != 0)) + return(table[j][i].desc); + } + } + + /* + * If we can't find a match for the command in the table, we just + * assume it's a vendor specifc command. + */ + return("Vendor Specific Command"); + +} + +#else /* SCSI_NO_OP_STRINGS */ + +const char * +scsi_op_desc(u_int16_t opcode, struct scsi_inquiry_data *inq_data) +{ + return(""); +} + +#endif + + +#if !defined(SCSI_NO_SENSE_STRINGS) +#define SST(asc, ascq, action, desc) \ + asc, ascq, action, desc +#else +const char empty_string[] = ""; + +#define SST(asc, ascq, action, desc) \ + asc, ascq, action, empty_string +#endif + +const struct sense_key_table_entry sense_key_table[] = +{ + { SSD_KEY_NO_SENSE, SS_NOP, "NO SENSE" }, + { SSD_KEY_RECOVERED_ERROR, SS_NOP|SSQ_PRINT_SENSE, "RECOVERED ERROR" }, + { + SSD_KEY_NOT_READY, SS_TUR|SSQ_MANY|SSQ_DECREMENT_COUNT|EBUSY, + "NOT READY" + }, + { SSD_KEY_MEDIUM_ERROR, SS_RDEF, "MEDIUM ERROR" }, + { SSD_KEY_HARDWARE_ERROR, SS_RDEF, "HARDWARE FAILURE" }, + { SSD_KEY_ILLEGAL_REQUEST, SS_FATAL|EINVAL, "ILLEGAL REQUEST" }, + { SSD_KEY_UNIT_ATTENTION, SS_FATAL|ENXIO, "UNIT ATTENTION" }, + { SSD_KEY_DATA_PROTECT, SS_FATAL|EACCES, "DATA PROTECT" }, + { SSD_KEY_BLANK_CHECK, SS_FATAL|ENOSPC, "BLANK CHECK" }, + { SSD_KEY_Vendor_Specific, SS_FATAL|EIO, "Vendor Specific" }, + { SSD_KEY_COPY_ABORTED, SS_FATAL|EIO, "COPY ABORTED" }, + { SSD_KEY_ABORTED_COMMAND, SS_RDEF, "ABORTED COMMAND" }, + { SSD_KEY_EQUAL, SS_NOP, "EQUAL" }, + { SSD_KEY_VOLUME_OVERFLOW, SS_FATAL|EIO, "VOLUME OVERFLOW" }, + { SSD_KEY_MISCOMPARE, SS_NOP, "MISCOMPARE" }, + { SSD_KEY_RESERVED, SS_FATAL|EIO, "RESERVED" } +}; + +const int sense_key_table_size = + sizeof(sense_key_table)/sizeof(sense_key_table[0]); + +static struct asc_table_entry quantum_fireball_entries[] = { + { SST(0x04, 0x0b, SS_START | SSQ_DECREMENT_COUNT | ENXIO, + "Logical unit not ready, initializing cmd. required") } +}; + +static struct asc_table_entry sony_mo_entries[] = { + { SST(0x04, 0x00, SS_START | SSQ_DECREMENT_COUNT | ENXIO, + "Logical unit not ready, cause not reportable") } +}; + +static struct scsi_sense_quirk_entry sense_quirk_table[] = { + { + /* + * XXX The Quantum Fireball ST and SE like to return 0x04 0x0b + * when they really should return 0x04 0x02. + */ + {T_DIRECT, SIP_MEDIA_FIXED, "QUANTUM", "FIREBALL S*", "*"}, + /*num_sense_keys*/0, + sizeof(quantum_fireball_entries)/sizeof(struct asc_table_entry), + /*sense key entries*/NULL, + quantum_fireball_entries + }, + { + /* + * This Sony MO drive likes to return 0x04, 0x00 when it + * isn't spun up. + */ + {T_DIRECT, SIP_MEDIA_REMOVABLE, "SONY", "SMO-*", "*"}, + /*num_sense_keys*/0, + sizeof(sony_mo_entries)/sizeof(struct asc_table_entry), + /*sense key entries*/NULL, + sony_mo_entries + } +}; + +const int sense_quirk_table_size = + sizeof(sense_quirk_table)/sizeof(sense_quirk_table[0]); + +static struct asc_table_entry asc_table[] = { + /* + * From: http://www.t10.org/lists/asc-num.txt + * Modifications by Jung-uk Kim (jkim@FreeBSD.org) + */ + /* + * File: ASC-NUM.TXT + * + * SCSI ASC/ASCQ Assignments + * Numeric Sorted Listing + * as of 7/29/08 + * + * D - DIRECT ACCESS DEVICE (SBC-2) device column key + * .T - SEQUENTIAL ACCESS DEVICE (SSC) ------------------- + * . L - PRINTER DEVICE (SSC) blank = reserved + * . P - PROCESSOR DEVICE (SPC) not blank = allowed + * . .W - WRITE ONCE READ MULTIPLE DEVICE (SBC-2) + * . . R - CD DEVICE (MMC) + * . . O - OPTICAL MEMORY DEVICE (SBC-2) + * . . .M - MEDIA CHANGER DEVICE (SMC) + * . . . A - STORAGE ARRAY DEVICE (SCC) + * . . . E - ENCLOSURE SERVICES DEVICE (SES) + * . . . .B - SIMPLIFIED DIRECT-ACCESS DEVICE (RBC) + * . . . . K - OPTICAL CARD READER/WRITER DEVICE (OCRW) + * . . . . V - AUTOMATION/DRIVE INTERFACE (ADC) + * . . . . .F - OBJECT-BASED STORAGE (OSD) + * DTLPWROMAEBKVF + * ASC ASCQ Action + * Description + */ + /* DTLPWROMAEBKVF */ + { SST(0x00, 0x00, SS_NOP, + "No additional sense information") }, + /* T */ + { SST(0x00, 0x01, SS_RDEF, + "Filemark detected") }, + /* T */ + { SST(0x00, 0x02, SS_RDEF, + "End-of-partition/medium detected") }, + /* T */ + { SST(0x00, 0x03, SS_RDEF, + "Setmark detected") }, + /* T */ + { SST(0x00, 0x04, SS_RDEF, + "Beginning-of-partition/medium detected") }, + /* TL */ + { SST(0x00, 0x05, SS_RDEF, + "End-of-data detected") }, + /* DTLPWROMAEBKVF */ + { SST(0x00, 0x06, SS_RDEF, + "I/O process terminated") }, + /* T */ + { SST(0x00, 0x07, SS_RDEF, /* XXX TBD */ + "Programmable early warning detected") }, + /* R */ + { SST(0x00, 0x11, SS_FATAL | EBUSY, + "Audio play operation in progress") }, + /* R */ + { SST(0x00, 0x12, SS_NOP, + "Audio play operation paused") }, + /* R */ + { SST(0x00, 0x13, SS_NOP, + "Audio play operation successfully completed") }, + /* R */ + { SST(0x00, 0x14, SS_RDEF, + "Audio play operation stopped due to error") }, + /* R */ + { SST(0x00, 0x15, SS_NOP, + "No current audio status to return") }, + /* DTLPWROMAEBKVF */ + { SST(0x00, 0x16, SS_FATAL | EBUSY, + "Operation in progress") }, + /* DTL WROMAEBKVF */ + { SST(0x00, 0x17, SS_RDEF, + "Cleaning requested") }, + /* T */ + { SST(0x00, 0x18, SS_RDEF, /* XXX TBD */ + "Erase operation in progress") }, + /* T */ + { SST(0x00, 0x19, SS_RDEF, /* XXX TBD */ + "Locate operation in progress") }, + /* T */ + { SST(0x00, 0x1A, SS_RDEF, /* XXX TBD */ + "Rewind operation in progress") }, + /* T */ + { SST(0x00, 0x1B, SS_RDEF, /* XXX TBD */ + "Set capacity operation in progress") }, + /* T */ + { SST(0x00, 0x1C, SS_RDEF, /* XXX TBD */ + "Verify operation in progress") }, + /* DT B */ + { SST(0x00, 0x1D, SS_RDEF, /* XXX TBD */ + "ATA pass through information available") }, + /* DT R MAEBKV */ + { SST(0x00, 0x1E, SS_RDEF, /* XXX TBD */ + "Conflicting SA creation request") }, + /* D W O BK */ + { SST(0x01, 0x00, SS_RDEF, + "No index/sector signal") }, + /* D WRO BK */ + { SST(0x02, 0x00, SS_RDEF, + "No seek complete") }, + /* DTL W O BK */ + { SST(0x03, 0x00, SS_RDEF, + "Peripheral device write fault") }, + /* T */ + { SST(0x03, 0x01, SS_RDEF, + "No write current") }, + /* T */ + { SST(0x03, 0x02, SS_RDEF, + "Excessive write errors") }, + /* DTLPWROMAEBKVF */ + { SST(0x04, 0x00, SS_TUR | SSQ_MANY | SSQ_DECREMENT_COUNT | EIO, + "Logical unit not ready, cause not reportable") }, + /* DTLPWROMAEBKVF */ + { SST(0x04, 0x01, SS_TUR | SSQ_MANY | SSQ_DECREMENT_COUNT | EBUSY, + "Logical unit is in process of becoming ready") }, + /* DTLPWROMAEBKVF */ + { SST(0x04, 0x02, SS_START | SSQ_DECREMENT_COUNT | ENXIO, + "Logical unit not ready, initializing command required") }, + /* DTLPWROMAEBKVF */ + { SST(0x04, 0x03, SS_FATAL | ENXIO, + "Logical unit not ready, manual intervention required") }, + /* DTL RO B */ + { SST(0x04, 0x04, SS_FATAL | EBUSY, + "Logical unit not ready, format in progress") }, + /* DT W O A BK F */ + { SST(0x04, 0x05, SS_FATAL | EBUSY, + "Logical unit not ready, rebuild in progress") }, + /* DT W O A BK */ + { SST(0x04, 0x06, SS_FATAL | EBUSY, + "Logical unit not ready, recalculation in progress") }, + /* DTLPWROMAEBKVF */ + { SST(0x04, 0x07, SS_FATAL | EBUSY, + "Logical unit not ready, operation in progress") }, + /* R */ + { SST(0x04, 0x08, SS_FATAL | EBUSY, + "Logical unit not ready, long write in progress") }, + /* DTLPWROMAEBKVF */ + { SST(0x04, 0x09, SS_RDEF, /* XXX TBD */ + "Logical unit not ready, self-test in progress") }, + /* DTLPWROMAEBKVF */ + { SST(0x04, 0x0A, SS_RDEF, /* XXX TBD */ + "Logical unit not accessible, asymmetric access state transition")}, + /* DTLPWROMAEBKVF */ + { SST(0x04, 0x0B, SS_RDEF, /* XXX TBD */ + "Logical unit not accessible, target port in standby state") }, + /* DTLPWROMAEBKVF */ + { SST(0x04, 0x0C, SS_RDEF, /* XXX TBD */ + "Logical unit not accessible, target port in unavailable state") }, + /* F */ + { SST(0x04, 0x0D, SS_RDEF, /* XXX TBD */ + "Logical unit not ready, structure check required") }, + /* DT WROM B */ + { SST(0x04, 0x10, SS_RDEF, /* XXX TBD */ + "Logical unit not ready, auxiliary memory not accessible") }, + /* DT WRO AEB VF */ + { SST(0x04, 0x11, SS_RDEF, /* XXX TBD */ + "Logical unit not ready, notify (enable spinup) required") }, + /* M V */ + { SST(0x04, 0x12, SS_RDEF, /* XXX TBD */ + "Logical unit not ready, offline") }, + /* DT R MAEBKV */ + { SST(0x04, 0x13, SS_RDEF, /* XXX TBD */ + "Logical unit not ready, SA creation in progress") }, + /* DTL WROMAEBKVF */ + { SST(0x05, 0x00, SS_RDEF, + "Logical unit does not respond to selection") }, + /* D WROM BK */ + { SST(0x06, 0x00, SS_RDEF, + "No reference position found") }, + /* DTL WROM BK */ + { SST(0x07, 0x00, SS_RDEF, + "Multiple peripheral devices selected") }, + /* DTL WROMAEBKVF */ + { SST(0x08, 0x00, SS_RDEF, + "Logical unit communication failure") }, + /* DTL WROMAEBKVF */ + { SST(0x08, 0x01, SS_RDEF, + "Logical unit communication time-out") }, + /* DTL WROMAEBKVF */ + { SST(0x08, 0x02, SS_RDEF, + "Logical unit communication parity error") }, + /* DT ROM BK */ + { SST(0x08, 0x03, SS_RDEF, + "Logical unit communication CRC error (Ultra-DMA/32)") }, + /* DTLPWRO K */ + { SST(0x08, 0x04, SS_RDEF, /* XXX TBD */ + "Unreachable copy target") }, + /* DT WRO B */ + { SST(0x09, 0x00, SS_RDEF, + "Track following error") }, + /* WRO K */ + { SST(0x09, 0x01, SS_RDEF, + "Tracking servo failure") }, + /* WRO K */ + { SST(0x09, 0x02, SS_RDEF, + "Focus servo failure") }, + /* WRO */ + { SST(0x09, 0x03, SS_RDEF, + "Spindle servo failure") }, + /* DT WRO B */ + { SST(0x09, 0x04, SS_RDEF, + "Head select fault") }, + /* DTLPWROMAEBKVF */ + { SST(0x0A, 0x00, SS_FATAL | ENOSPC, + "Error log overflow") }, + /* DTLPWROMAEBKVF */ + { SST(0x0B, 0x00, SS_RDEF, + "Warning") }, + /* DTLPWROMAEBKVF */ + { SST(0x0B, 0x01, SS_RDEF, + "Warning - specified temperature exceeded") }, + /* DTLPWROMAEBKVF */ + { SST(0x0B, 0x02, SS_RDEF, + "Warning - enclosure degraded") }, + /* DTLPWROMAEBKVF */ + { SST(0x0B, 0x03, SS_RDEF, /* XXX TBD */ + "Warning - background self-test failed") }, + /* DTLPWRO AEBKVF */ + { SST(0x0B, 0x04, SS_RDEF, /* XXX TBD */ + "Warning - background pre-scan detected medium error") }, + /* DTLPWRO AEBKVF */ + { SST(0x0B, 0x05, SS_RDEF, /* XXX TBD */ + "Warning - background medium scan detected medium error") }, + /* DTLPWROMAEBKVF */ + { SST(0x0B, 0x06, SS_RDEF, /* XXX TBD */ + "Warning - non-volatile cache now volatile") }, + /* DTLPWROMAEBKVF */ + { SST(0x0B, 0x07, SS_RDEF, /* XXX TBD */ + "Warning - degraded power to non-volatile cache") }, + /* T R */ + { SST(0x0C, 0x00, SS_RDEF, + "Write error") }, + /* K */ + { SST(0x0C, 0x01, SS_NOP | SSQ_PRINT_SENSE, + "Write error - recovered with auto reallocation") }, + /* D W O BK */ + { SST(0x0C, 0x02, SS_RDEF, + "Write error - auto reallocation failed") }, + /* D W O BK */ + { SST(0x0C, 0x03, SS_RDEF, + "Write error - recommend reassignment") }, + /* DT W O B */ + { SST(0x0C, 0x04, SS_RDEF, + "Compression check miscompare error") }, + /* DT W O B */ + { SST(0x0C, 0x05, SS_RDEF, + "Data expansion occurred during compression") }, + /* DT W O B */ + { SST(0x0C, 0x06, SS_RDEF, + "Block not compressible") }, + /* R */ + { SST(0x0C, 0x07, SS_RDEF, + "Write error - recovery needed") }, + /* R */ + { SST(0x0C, 0x08, SS_RDEF, + "Write error - recovery failed") }, + /* R */ + { SST(0x0C, 0x09, SS_RDEF, + "Write error - loss of streaming") }, + /* R */ + { SST(0x0C, 0x0A, SS_RDEF, + "Write error - padding blocks added") }, + /* DT WROM B */ + { SST(0x0C, 0x0B, SS_RDEF, /* XXX TBD */ + "Auxiliary memory write error") }, + /* DTLPWRO AEBKVF */ + { SST(0x0C, 0x0C, SS_RDEF, /* XXX TBD */ + "Write error - unexpected unsolicited data") }, + /* DTLPWRO AEBKVF */ + { SST(0x0C, 0x0D, SS_RDEF, /* XXX TBD */ + "Write error - not enough unsolicited data") }, + /* R */ + { SST(0x0C, 0x0F, SS_RDEF, /* XXX TBD */ + "Defects in error window") }, + /* DTLPWRO A K */ + { SST(0x0D, 0x00, SS_RDEF, /* XXX TBD */ + "Error detected by third party temporary initiator") }, + /* DTLPWRO A K */ + { SST(0x0D, 0x01, SS_RDEF, /* XXX TBD */ + "Third party device failure") }, + /* DTLPWRO A K */ + { SST(0x0D, 0x02, SS_RDEF, /* XXX TBD */ + "Copy target device not reachable") }, + /* DTLPWRO A K */ + { SST(0x0D, 0x03, SS_RDEF, /* XXX TBD */ + "Incorrect copy target device type") }, + /* DTLPWRO A K */ + { SST(0x0D, 0x04, SS_RDEF, /* XXX TBD */ + "Copy target device data underrun") }, + /* DTLPWRO A K */ + { SST(0x0D, 0x05, SS_RDEF, /* XXX TBD */ + "Copy target device data overrun") }, + /* DT PWROMAEBK F */ + { SST(0x0E, 0x00, SS_RDEF, /* XXX TBD */ + "Invalid information unit") }, + /* DT PWROMAEBK F */ + { SST(0x0E, 0x01, SS_RDEF, /* XXX TBD */ + "Information unit too short") }, + /* DT PWROMAEBK F */ + { SST(0x0E, 0x02, SS_RDEF, /* XXX TBD */ + "Information unit too long") }, + /* DT P R MAEBK F */ + { SST(0x0E, 0x03, SS_RDEF, /* XXX TBD */ + "Invalid field in command information unit") }, + /* D W O BK */ + { SST(0x10, 0x00, SS_RDEF, + "ID CRC or ECC error") }, + /* DT W O */ + { SST(0x10, 0x01, SS_RDEF, /* XXX TBD */ + "Logical block guard check failed") }, + /* DT W O */ + { SST(0x10, 0x02, SS_RDEF, /* XXX TBD */ + "Logical block application tag check failed") }, + /* DT W O */ + { SST(0x10, 0x03, SS_RDEF, /* XXX TBD */ + "Logical block reference tag check failed") }, + /* DT WRO BK */ + { SST(0x11, 0x00, SS_RDEF, + "Unrecovered read error") }, + /* DT WRO BK */ + { SST(0x11, 0x01, SS_RDEF, + "Read retries exhausted") }, + /* DT WRO BK */ + { SST(0x11, 0x02, SS_RDEF, + "Error too long to correct") }, + /* DT W O BK */ + { SST(0x11, 0x03, SS_RDEF, + "Multiple read errors") }, + /* D W O BK */ + { SST(0x11, 0x04, SS_RDEF, + "Unrecovered read error - auto reallocate failed") }, + /* WRO B */ + { SST(0x11, 0x05, SS_RDEF, + "L-EC uncorrectable error") }, + /* WRO B */ + { SST(0x11, 0x06, SS_RDEF, + "CIRC unrecovered error") }, + /* W O B */ + { SST(0x11, 0x07, SS_RDEF, + "Data re-synchronization error") }, + /* T */ + { SST(0x11, 0x08, SS_RDEF, + "Incomplete block read") }, + /* T */ + { SST(0x11, 0x09, SS_RDEF, + "No gap found") }, + /* DT O BK */ + { SST(0x11, 0x0A, SS_RDEF, + "Miscorrected error") }, + /* D W O BK */ + { SST(0x11, 0x0B, SS_RDEF, + "Unrecovered read error - recommend reassignment") }, + /* D W O BK */ + { SST(0x11, 0x0C, SS_RDEF, + "Unrecovered read error - recommend rewrite the data") }, + /* DT WRO B */ + { SST(0x11, 0x0D, SS_RDEF, + "De-compression CRC error") }, + /* DT WRO B */ + { SST(0x11, 0x0E, SS_RDEF, + "Cannot decompress using declared algorithm") }, + /* R */ + { SST(0x11, 0x0F, SS_RDEF, + "Error reading UPC/EAN number") }, + /* R */ + { SST(0x11, 0x10, SS_RDEF, + "Error reading ISRC number") }, + /* R */ + { SST(0x11, 0x11, SS_RDEF, + "Read error - loss of streaming") }, + /* DT WROM B */ + { SST(0x11, 0x12, SS_RDEF, /* XXX TBD */ + "Auxiliary memory read error") }, + /* DTLPWRO AEBKVF */ + { SST(0x11, 0x13, SS_RDEF, /* XXX TBD */ + "Read error - failed retransmission request") }, + /* D */ + { SST(0x11, 0x14, SS_RDEF, /* XXX TBD */ + "Read error - LBA marked bad by application client") }, + /* D W O BK */ + { SST(0x12, 0x00, SS_RDEF, + "Address mark not found for ID field") }, + /* D W O BK */ + { SST(0x13, 0x00, SS_RDEF, + "Address mark not found for data field") }, + /* DTL WRO BK */ + { SST(0x14, 0x00, SS_RDEF, + "Recorded entity not found") }, + /* DT WRO BK */ + { SST(0x14, 0x01, SS_RDEF, + "Record not found") }, + /* T */ + { SST(0x14, 0x02, SS_RDEF, + "Filemark or setmark not found") }, + /* T */ + { SST(0x14, 0x03, SS_RDEF, + "End-of-data not found") }, + /* T */ + { SST(0x14, 0x04, SS_RDEF, + "Block sequence error") }, + /* DT W O BK */ + { SST(0x14, 0x05, SS_RDEF, + "Record not found - recommend reassignment") }, + /* DT W O BK */ + { SST(0x14, 0x06, SS_RDEF, + "Record not found - data auto-reallocated") }, + /* T */ + { SST(0x14, 0x07, SS_RDEF, /* XXX TBD */ + "Locate operation failure") }, + /* DTL WROM BK */ + { SST(0x15, 0x00, SS_RDEF, + "Random positioning error") }, + /* DTL WROM BK */ + { SST(0x15, 0x01, SS_RDEF, + "Mechanical positioning error") }, + /* DT WRO BK */ + { SST(0x15, 0x02, SS_RDEF, + "Positioning error detected by read of medium") }, + /* D W O BK */ + { SST(0x16, 0x00, SS_RDEF, + "Data synchronization mark error") }, + /* D W O BK */ + { SST(0x16, 0x01, SS_RDEF, + "Data sync error - data rewritten") }, + /* D W O BK */ + { SST(0x16, 0x02, SS_RDEF, + "Data sync error - recommend rewrite") }, + /* D W O BK */ + { SST(0x16, 0x03, SS_NOP | SSQ_PRINT_SENSE, + "Data sync error - data auto-reallocated") }, + /* D W O BK */ + { SST(0x16, 0x04, SS_RDEF, + "Data sync error - recommend reassignment") }, + /* DT WRO BK */ + { SST(0x17, 0x00, SS_NOP | SSQ_PRINT_SENSE, + "Recovered data with no error correction applied") }, + /* DT WRO BK */ + { SST(0x17, 0x01, SS_NOP | SSQ_PRINT_SENSE, + "Recovered data with retries") }, + /* DT WRO BK */ + { SST(0x17, 0x02, SS_NOP | SSQ_PRINT_SENSE, + "Recovered data with positive head offset") }, + /* DT WRO BK */ + { SST(0x17, 0x03, SS_NOP | SSQ_PRINT_SENSE, + "Recovered data with negative head offset") }, + /* WRO B */ + { SST(0x17, 0x04, SS_NOP | SSQ_PRINT_SENSE, + "Recovered data with retries and/or CIRC applied") }, + /* D WRO BK */ + { SST(0x17, 0x05, SS_NOP | SSQ_PRINT_SENSE, + "Recovered data using previous sector ID") }, + /* D W O BK */ + { SST(0x17, 0x06, SS_NOP | SSQ_PRINT_SENSE, + "Recovered data without ECC - data auto-reallocated") }, + /* D WRO BK */ + { SST(0x17, 0x07, SS_NOP | SSQ_PRINT_SENSE, + "Recovered data without ECC - recommend reassignment") }, + /* D WRO BK */ + { SST(0x17, 0x08, SS_NOP | SSQ_PRINT_SENSE, + "Recovered data without ECC - recommend rewrite") }, + /* D WRO BK */ + { SST(0x17, 0x09, SS_NOP | SSQ_PRINT_SENSE, + "Recovered data without ECC - data rewritten") }, + /* DT WRO BK */ + { SST(0x18, 0x00, SS_NOP | SSQ_PRINT_SENSE, + "Recovered data with error correction applied") }, + /* D WRO BK */ + { SST(0x18, 0x01, SS_NOP | SSQ_PRINT_SENSE, + "Recovered data with error corr. & retries applied") }, + /* D WRO BK */ + { SST(0x18, 0x02, SS_NOP | SSQ_PRINT_SENSE, + "Recovered data - data auto-reallocated") }, + /* R */ + { SST(0x18, 0x03, SS_NOP | SSQ_PRINT_SENSE, + "Recovered data with CIRC") }, + /* R */ + { SST(0x18, 0x04, SS_NOP | SSQ_PRINT_SENSE, + "Recovered data with L-EC") }, + /* D WRO BK */ + { SST(0x18, 0x05, SS_NOP | SSQ_PRINT_SENSE, + "Recovered data - recommend reassignment") }, + /* D WRO BK */ + { SST(0x18, 0x06, SS_NOP | SSQ_PRINT_SENSE, + "Recovered data - recommend rewrite") }, + /* D W O BK */ + { SST(0x18, 0x07, SS_NOP | SSQ_PRINT_SENSE, + "Recovered data with ECC - data rewritten") }, + /* R */ + { SST(0x18, 0x08, SS_RDEF, /* XXX TBD */ + "Recovered data with linking") }, + /* D O K */ + { SST(0x19, 0x00, SS_RDEF, + "Defect list error") }, + /* D O K */ + { SST(0x19, 0x01, SS_RDEF, + "Defect list not available") }, + /* D O K */ + { SST(0x19, 0x02, SS_RDEF, + "Defect list error in primary list") }, + /* D O K */ + { SST(0x19, 0x03, SS_RDEF, + "Defect list error in grown list") }, + /* DTLPWROMAEBKVF */ + { SST(0x1A, 0x00, SS_RDEF, + "Parameter list length error") }, + /* DTLPWROMAEBKVF */ + { SST(0x1B, 0x00, SS_RDEF, + "Synchronous data transfer error") }, + /* D O BK */ + { SST(0x1C, 0x00, SS_RDEF, + "Defect list not found") }, + /* D O BK */ + { SST(0x1C, 0x01, SS_RDEF, + "Primary defect list not found") }, + /* D O BK */ + { SST(0x1C, 0x02, SS_RDEF, + "Grown defect list not found") }, + /* DT WRO BK */ + { SST(0x1D, 0x00, SS_FATAL, + "Miscompare during verify operation") }, + /* D W O BK */ + { SST(0x1E, 0x00, SS_NOP | SSQ_PRINT_SENSE, + "Recovered ID with ECC correction") }, + /* D O K */ + { SST(0x1F, 0x00, SS_RDEF, + "Partial defect list transfer") }, + /* DTLPWROMAEBKVF */ + { SST(0x20, 0x00, SS_FATAL | EINVAL, + "Invalid command operation code") }, + /* DT PWROMAEBK */ + { SST(0x20, 0x01, SS_RDEF, /* XXX TBD */ + "Access denied - initiator pending-enrolled") }, + /* DT PWROMAEBK */ + { SST(0x20, 0x02, SS_RDEF, /* XXX TBD */ + "Access denied - no access rights") }, + /* DT PWROMAEBK */ + { SST(0x20, 0x03, SS_RDEF, /* XXX TBD */ + "Access denied - invalid mgmt ID key") }, + /* T */ + { SST(0x20, 0x04, SS_RDEF, /* XXX TBD */ + "Illegal command while in write capable state") }, + /* T */ + { SST(0x20, 0x05, SS_RDEF, /* XXX TBD */ + "Obsolete") }, + /* T */ + { SST(0x20, 0x06, SS_RDEF, /* XXX TBD */ + "Illegal command while in explicit address mode") }, + /* T */ + { SST(0x20, 0x07, SS_RDEF, /* XXX TBD */ + "Illegal command while in implicit address mode") }, + /* DT PWROMAEBK */ + { SST(0x20, 0x08, SS_RDEF, /* XXX TBD */ + "Access denied - enrollment conflict") }, + /* DT PWROMAEBK */ + { SST(0x20, 0x09, SS_RDEF, /* XXX TBD */ + "Access denied - invalid LU identifier") }, + /* DT PWROMAEBK */ + { SST(0x20, 0x0A, SS_RDEF, /* XXX TBD */ + "Access denied - invalid proxy token") }, + /* DT PWROMAEBK */ + { SST(0x20, 0x0B, SS_RDEF, /* XXX TBD */ + "Access denied - ACL LUN conflict") }, + /* DT WRO BK */ + { SST(0x21, 0x00, SS_FATAL | EINVAL, + "Logical block address out of range") }, + /* DT WROM BK */ + { SST(0x21, 0x01, SS_FATAL | EINVAL, + "Invalid element address") }, + /* R */ + { SST(0x21, 0x02, SS_RDEF, /* XXX TBD */ + "Invalid address for write") }, + /* R */ + { SST(0x21, 0x03, SS_RDEF, /* XXX TBD */ + "Invalid write crossing layer jump") }, + /* D */ + { SST(0x22, 0x00, SS_FATAL | EINVAL, + "Illegal function (use 20 00, 24 00, or 26 00)") }, + /* DTLPWROMAEBKVF */ + { SST(0x24, 0x00, SS_FATAL | EINVAL, + "Invalid field in CDB") }, + /* DTLPWRO AEBKVF */ + { SST(0x24, 0x01, SS_RDEF, /* XXX TBD */ + "CDB decryption error") }, + /* T */ + { SST(0x24, 0x02, SS_RDEF, /* XXX TBD */ + "Obsolete") }, + /* T */ + { SST(0x24, 0x03, SS_RDEF, /* XXX TBD */ + "Obsolete") }, + /* F */ + { SST(0x24, 0x04, SS_RDEF, /* XXX TBD */ + "Security audit value frozen") }, + /* F */ + { SST(0x24, 0x05, SS_RDEF, /* XXX TBD */ + "Security working key frozen") }, + /* F */ + { SST(0x24, 0x06, SS_RDEF, /* XXX TBD */ + "NONCE not unique") }, + /* F */ + { SST(0x24, 0x07, SS_RDEF, /* XXX TBD */ + "NONCE timestamp out of range") }, + /* DT R MAEBKV */ + { SST(0x24, 0x08, SS_RDEF, /* XXX TBD */ + "Invalid XCDB") }, + /* DTLPWROMAEBKVF */ + { SST(0x25, 0x00, SS_FATAL | ENXIO, + "Logical unit not supported") }, + /* DTLPWROMAEBKVF */ + { SST(0x26, 0x00, SS_FATAL | EINVAL, + "Invalid field in parameter list") }, + /* DTLPWROMAEBKVF */ + { SST(0x26, 0x01, SS_FATAL | EINVAL, + "Parameter not supported") }, + /* DTLPWROMAEBKVF */ + { SST(0x26, 0x02, SS_FATAL | EINVAL, + "Parameter value invalid") }, + /* DTLPWROMAE K */ + { SST(0x26, 0x03, SS_FATAL | EINVAL, + "Threshold parameters not supported") }, + /* DTLPWROMAEBKVF */ + { SST(0x26, 0x04, SS_FATAL | EINVAL, + "Invalid release of persistent reservation") }, + /* DTLPWRO A BK */ + { SST(0x26, 0x05, SS_RDEF, /* XXX TBD */ + "Data decryption error") }, + /* DTLPWRO K */ + { SST(0x26, 0x06, SS_RDEF, /* XXX TBD */ + "Too many target descriptors") }, + /* DTLPWRO K */ + { SST(0x26, 0x07, SS_RDEF, /* XXX TBD */ + "Unsupported target descriptor type code") }, + /* DTLPWRO K */ + { SST(0x26, 0x08, SS_RDEF, /* XXX TBD */ + "Too many segment descriptors") }, + /* DTLPWRO K */ + { SST(0x26, 0x09, SS_RDEF, /* XXX TBD */ + "Unsupported segment descriptor type code") }, + /* DTLPWRO K */ + { SST(0x26, 0x0A, SS_RDEF, /* XXX TBD */ + "Unexpected inexact segment") }, + /* DTLPWRO K */ + { SST(0x26, 0x0B, SS_RDEF, /* XXX TBD */ + "Inline data length exceeded") }, + /* DTLPWRO K */ + { SST(0x26, 0x0C, SS_RDEF, /* XXX TBD */ + "Invalid operation for copy source or destination") }, + /* DTLPWRO K */ + { SST(0x26, 0x0D, SS_RDEF, /* XXX TBD */ + "Copy segment granularity violation") }, + /* DT PWROMAEBK */ + { SST(0x26, 0x0E, SS_RDEF, /* XXX TBD */ + "Invalid parameter while port is enabled") }, + /* F */ + { SST(0x26, 0x0F, SS_RDEF, /* XXX TBD */ + "Invalid data-out buffer integrity check value") }, + /* T */ + { SST(0x26, 0x10, SS_RDEF, /* XXX TBD */ + "Data decryption key fail limit reached") }, + /* T */ + { SST(0x26, 0x11, SS_RDEF, /* XXX TBD */ + "Incomplete key-associated data set") }, + /* T */ + { SST(0x26, 0x12, SS_RDEF, /* XXX TBD */ + "Vendor specific key reference not found") }, + /* DT WRO BK */ + { SST(0x27, 0x00, SS_FATAL | EACCES, + "Write protected") }, + /* DT WRO BK */ + { SST(0x27, 0x01, SS_FATAL | EACCES, + "Hardware write protected") }, + /* DT WRO BK */ + { SST(0x27, 0x02, SS_FATAL | EACCES, + "Logical unit software write protected") }, + /* T R */ + { SST(0x27, 0x03, SS_FATAL | EACCES, + "Associated write protect") }, + /* T R */ + { SST(0x27, 0x04, SS_FATAL | EACCES, + "Persistent write protect") }, + /* T R */ + { SST(0x27, 0x05, SS_FATAL | EACCES, + "Permanent write protect") }, + /* R F */ + { SST(0x27, 0x06, SS_RDEF, /* XXX TBD */ + "Conditional write protect") }, + /* DTLPWROMAEBKVF */ + { SST(0x28, 0x00, SS_FATAL | ENXIO, + "Not ready to ready change, medium may have changed") }, + /* DT WROM B */ + { SST(0x28, 0x01, SS_FATAL | ENXIO, + "Import or export element accessed") }, + /* R */ + { SST(0x28, 0x02, SS_RDEF, /* XXX TBD */ + "Format-layer may have changed") }, + /* M */ + { SST(0x28, 0x03, SS_RDEF, /* XXX TBD */ + "Import/export element accessed, medium changed") }, + /* + * XXX JGibbs - All of these should use the same errno, but I don't + * think ENXIO is the correct choice. Should we borrow from + * the networking errnos? ECONNRESET anyone? + */ + /* DTLPWROMAEBKVF */ + { SST(0x29, 0x00, SS_FATAL | ENXIO, + "Power on, reset, or bus device reset occurred") }, + /* DTLPWROMAEBKVF */ + { SST(0x29, 0x01, SS_RDEF, + "Power on occurred") }, + /* DTLPWROMAEBKVF */ + { SST(0x29, 0x02, SS_RDEF, + "SCSI bus reset occurred") }, + /* DTLPWROMAEBKVF */ + { SST(0x29, 0x03, SS_RDEF, + "Bus device reset function occurred") }, + /* DTLPWROMAEBKVF */ + { SST(0x29, 0x04, SS_RDEF, + "Device internal reset") }, + /* DTLPWROMAEBKVF */ + { SST(0x29, 0x05, SS_RDEF, + "Transceiver mode changed to single-ended") }, + /* DTLPWROMAEBKVF */ + { SST(0x29, 0x06, SS_RDEF, + "Transceiver mode changed to LVD") }, + /* DTLPWROMAEBKVF */ + { SST(0x29, 0x07, SS_RDEF, /* XXX TBD */ + "I_T nexus loss occurred") }, + /* DTL WROMAEBKVF */ + { SST(0x2A, 0x00, SS_RDEF, + "Parameters changed") }, + /* DTL WROMAEBKVF */ + { SST(0x2A, 0x01, SS_RDEF, + "Mode parameters changed") }, + /* DTL WROMAE K */ + { SST(0x2A, 0x02, SS_RDEF, + "Log parameters changed") }, + /* DTLPWROMAE K */ + { SST(0x2A, 0x03, SS_RDEF, + "Reservations preempted") }, + /* DTLPWROMAE */ + { SST(0x2A, 0x04, SS_RDEF, /* XXX TBD */ + "Reservations released") }, + /* DTLPWROMAE */ + { SST(0x2A, 0x05, SS_RDEF, /* XXX TBD */ + "Registrations preempted") }, + /* DTLPWROMAEBKVF */ + { SST(0x2A, 0x06, SS_RDEF, /* XXX TBD */ + "Asymmetric access state changed") }, + /* DTLPWROMAEBKVF */ + { SST(0x2A, 0x07, SS_RDEF, /* XXX TBD */ + "Implicit asymmetric access state transition failed") }, + /* DT WROMAEBKVF */ + { SST(0x2A, 0x08, SS_RDEF, /* XXX TBD */ + "Priority changed") }, + /* D */ + { SST(0x2A, 0x09, SS_RDEF, /* XXX TBD */ + "Capacity data has changed") }, + /* DT */ + { SST(0x2A, 0x0A, SS_RDEF, /* XXX TBD */ + "Error history I_T nexus cleared") }, + /* DT */ + { SST(0x2A, 0x0B, SS_RDEF, /* XXX TBD */ + "Error history snapshot released") }, + /* F */ + { SST(0x2A, 0x0C, SS_RDEF, /* XXX TBD */ + "Error recovery attributes have changed") }, + /* T */ + { SST(0x2A, 0x0D, SS_RDEF, /* XXX TBD */ + "Data encryption capabilities changed") }, + /* DT M E V */ + { SST(0x2A, 0x10, SS_RDEF, /* XXX TBD */ + "Timestamp changed") }, + /* T */ + { SST(0x2A, 0x11, SS_RDEF, /* XXX TBD */ + "Data encryption parameters changed by another I_T nexus") }, + /* T */ + { SST(0x2A, 0x12, SS_RDEF, /* XXX TBD */ + "Data encryption parameters changed by vendor specific event") }, + /* T */ + { SST(0x2A, 0x13, SS_RDEF, /* XXX TBD */ + "Data encryption key instance counter has changed") }, + /* DT R MAEBKV */ + { SST(0x2A, 0x14, SS_RDEF, /* XXX TBD */ + "SA creation capabilities data has changed") }, + /* DTLPWRO K */ + { SST(0x2B, 0x00, SS_RDEF, + "Copy cannot execute since host cannot disconnect") }, + /* DTLPWROMAEBKVF */ + { SST(0x2C, 0x00, SS_RDEF, + "Command sequence error") }, + /* */ + { SST(0x2C, 0x01, SS_RDEF, + "Too many windows specified") }, + /* */ + { SST(0x2C, 0x02, SS_RDEF, + "Invalid combination of windows specified") }, + /* R */ + { SST(0x2C, 0x03, SS_RDEF, + "Current program area is not empty") }, + /* R */ + { SST(0x2C, 0x04, SS_RDEF, + "Current program area is empty") }, + /* B */ + { SST(0x2C, 0x05, SS_RDEF, /* XXX TBD */ + "Illegal power condition request") }, + /* R */ + { SST(0x2C, 0x06, SS_RDEF, /* XXX TBD */ + "Persistent prevent conflict") }, + /* DTLPWROMAEBKVF */ + { SST(0x2C, 0x07, SS_RDEF, /* XXX TBD */ + "Previous busy status") }, + /* DTLPWROMAEBKVF */ + { SST(0x2C, 0x08, SS_RDEF, /* XXX TBD */ + "Previous task set full status") }, + /* DTLPWROM EBKVF */ + { SST(0x2C, 0x09, SS_RDEF, /* XXX TBD */ + "Previous reservation conflict status") }, + /* F */ + { SST(0x2C, 0x0A, SS_RDEF, /* XXX TBD */ + "Partition or collection contains user objects") }, + /* T */ + { SST(0x2C, 0x0B, SS_RDEF, /* XXX TBD */ + "Not reserved") }, + /* T */ + { SST(0x2D, 0x00, SS_RDEF, + "Overwrite error on update in place") }, + /* R */ + { SST(0x2E, 0x00, SS_RDEF, /* XXX TBD */ + "Insufficient time for operation") }, + /* DTLPWROMAEBKVF */ + { SST(0x2F, 0x00, SS_RDEF, + "Commands cleared by another initiator") }, + /* D */ + { SST(0x2F, 0x01, SS_RDEF, /* XXX TBD */ + "Commands cleared by power loss notification") }, + /* DTLPWROMAEBKVF */ + { SST(0x2F, 0x02, SS_RDEF, /* XXX TBD */ + "Commands cleared by device server") }, + /* DT WROM BK */ + { SST(0x30, 0x00, SS_RDEF, + "Incompatible medium installed") }, + /* DT WRO BK */ + { SST(0x30, 0x01, SS_RDEF, + "Cannot read medium - unknown format") }, + /* DT WRO BK */ + { SST(0x30, 0x02, SS_RDEF, + "Cannot read medium - incompatible format") }, + /* DT R K */ + { SST(0x30, 0x03, SS_RDEF, + "Cleaning cartridge installed") }, + /* DT WRO BK */ + { SST(0x30, 0x04, SS_RDEF, + "Cannot write medium - unknown format") }, + /* DT WRO BK */ + { SST(0x30, 0x05, SS_RDEF, + "Cannot write medium - incompatible format") }, + /* DT WRO B */ + { SST(0x30, 0x06, SS_RDEF, + "Cannot format medium - incompatible medium") }, + /* DTL WROMAEBKVF */ + { SST(0x30, 0x07, SS_RDEF, + "Cleaning failure") }, + /* R */ + { SST(0x30, 0x08, SS_RDEF, + "Cannot write - application code mismatch") }, + /* R */ + { SST(0x30, 0x09, SS_RDEF, + "Current session not fixated for append") }, + /* DT WRO AEBK */ + { SST(0x30, 0x0A, SS_RDEF, /* XXX TBD */ + "Cleaning request rejected") }, + /* T */ + { SST(0x30, 0x0C, SS_RDEF, /* XXX TBD */ + "WORM medium - overwrite attempted") }, + /* T */ + { SST(0x30, 0x0D, SS_RDEF, /* XXX TBD */ + "WORM medium - integrity check") }, + /* R */ + { SST(0x30, 0x10, SS_RDEF, /* XXX TBD */ + "Medium not formatted") }, + /* M */ + { SST(0x30, 0x11, SS_RDEF, /* XXX TBD */ + "Incompatible volume type") }, + /* M */ + { SST(0x30, 0x12, SS_RDEF, /* XXX TBD */ + "Incompatible volume qualifier") }, + /* DT WRO BK */ + { SST(0x31, 0x00, SS_RDEF, + "Medium format corrupted") }, + /* D L RO B */ + { SST(0x31, 0x01, SS_RDEF, + "Format command failed") }, + /* R */ + { SST(0x31, 0x02, SS_RDEF, /* XXX TBD */ + "Zoned formatting failed due to spare linking") }, + /* D W O BK */ + { SST(0x32, 0x00, SS_RDEF, + "No defect spare location available") }, + /* D W O BK */ + { SST(0x32, 0x01, SS_RDEF, + "Defect list update failure") }, + /* T */ + { SST(0x33, 0x00, SS_RDEF, + "Tape length error") }, + /* DTLPWROMAEBKVF */ + { SST(0x34, 0x00, SS_RDEF, + "Enclosure failure") }, + /* DTLPWROMAEBKVF */ + { SST(0x35, 0x00, SS_RDEF, + "Enclosure services failure") }, + /* DTLPWROMAEBKVF */ + { SST(0x35, 0x01, SS_RDEF, + "Unsupported enclosure function") }, + /* DTLPWROMAEBKVF */ + { SST(0x35, 0x02, SS_RDEF, + "Enclosure services unavailable") }, + /* DTLPWROMAEBKVF */ + { SST(0x35, 0x03, SS_RDEF, + "Enclosure services transfer failure") }, + /* DTLPWROMAEBKVF */ + { SST(0x35, 0x04, SS_RDEF, + "Enclosure services transfer refused") }, + /* DTL WROMAEBKVF */ + { SST(0x35, 0x05, SS_RDEF, /* XXX TBD */ + "Enclosure services checksum error") }, + /* L */ + { SST(0x36, 0x00, SS_RDEF, + "Ribbon, ink, or toner failure") }, + /* DTL WROMAEBKVF */ + { SST(0x37, 0x00, SS_RDEF, + "Rounded parameter") }, + /* B */ + { SST(0x38, 0x00, SS_RDEF, /* XXX TBD */ + "Event status notification") }, + /* B */ + { SST(0x38, 0x02, SS_RDEF, /* XXX TBD */ + "ESN - power management class event") }, + /* B */ + { SST(0x38, 0x04, SS_RDEF, /* XXX TBD */ + "ESN - media class event") }, + /* B */ + { SST(0x38, 0x06, SS_RDEF, /* XXX TBD */ + "ESN - device busy class event") }, + /* DTL WROMAE K */ + { SST(0x39, 0x00, SS_RDEF, + "Saving parameters not supported") }, + /* DTL WROM BK */ + { SST(0x3A, 0x00, SS_FATAL | ENXIO, + "Medium not present") }, + /* DT WROM BK */ + { SST(0x3A, 0x01, SS_FATAL | ENXIO, + "Medium not present - tray closed") }, + /* DT WROM BK */ + { SST(0x3A, 0x02, SS_FATAL | ENXIO, + "Medium not present - tray open") }, + /* DT WROM B */ + { SST(0x3A, 0x03, SS_RDEF, /* XXX TBD */ + "Medium not present - loadable") }, + /* DT WRO B */ + { SST(0x3A, 0x04, SS_RDEF, /* XXX TBD */ + "Medium not present - medium auxiliary memory accessible") }, + /* TL */ + { SST(0x3B, 0x00, SS_RDEF, + "Sequential positioning error") }, + /* T */ + { SST(0x3B, 0x01, SS_RDEF, + "Tape position error at beginning-of-medium") }, + /* T */ + { SST(0x3B, 0x02, SS_RDEF, + "Tape position error at end-of-medium") }, + /* L */ + { SST(0x3B, 0x03, SS_RDEF, + "Tape or electronic vertical forms unit not ready") }, + /* L */ + { SST(0x3B, 0x04, SS_RDEF, + "Slew failure") }, + /* L */ + { SST(0x3B, 0x05, SS_RDEF, + "Paper jam") }, + /* L */ + { SST(0x3B, 0x06, SS_RDEF, + "Failed to sense top-of-form") }, + /* L */ + { SST(0x3B, 0x07, SS_RDEF, + "Failed to sense bottom-of-form") }, + /* T */ + { SST(0x3B, 0x08, SS_RDEF, + "Reposition error") }, + /* */ + { SST(0x3B, 0x09, SS_RDEF, + "Read past end of medium") }, + /* */ + { SST(0x3B, 0x0A, SS_RDEF, + "Read past beginning of medium") }, + /* */ + { SST(0x3B, 0x0B, SS_RDEF, + "Position past end of medium") }, + /* T */ + { SST(0x3B, 0x0C, SS_RDEF, + "Position past beginning of medium") }, + /* DT WROM BK */ + { SST(0x3B, 0x0D, SS_FATAL | ENOSPC, + "Medium destination element full") }, + /* DT WROM BK */ + { SST(0x3B, 0x0E, SS_RDEF, + "Medium source element empty") }, + /* R */ + { SST(0x3B, 0x0F, SS_RDEF, + "End of medium reached") }, + /* DT WROM BK */ + { SST(0x3B, 0x11, SS_RDEF, + "Medium magazine not accessible") }, + /* DT WROM BK */ + { SST(0x3B, 0x12, SS_RDEF, + "Medium magazine removed") }, + /* DT WROM BK */ + { SST(0x3B, 0x13, SS_RDEF, + "Medium magazine inserted") }, + /* DT WROM BK */ + { SST(0x3B, 0x14, SS_RDEF, + "Medium magazine locked") }, + /* DT WROM BK */ + { SST(0x3B, 0x15, SS_RDEF, + "Medium magazine unlocked") }, + /* R */ + { SST(0x3B, 0x16, SS_RDEF, /* XXX TBD */ + "Mechanical positioning or changer error") }, + /* F */ + { SST(0x3B, 0x17, SS_RDEF, /* XXX TBD */ + "Read past end of user object") }, + /* M */ + { SST(0x3B, 0x18, SS_RDEF, /* XXX TBD */ + "Element disabled") }, + /* M */ + { SST(0x3B, 0x19, SS_RDEF, /* XXX TBD */ + "Element enabled") }, + /* M */ + { SST(0x3B, 0x1A, SS_RDEF, /* XXX TBD */ + "Data transfer device removed") }, + /* M */ + { SST(0x3B, 0x1B, SS_RDEF, /* XXX TBD */ + "Data transfer device inserted") }, + /* DTLPWROMAE K */ + { SST(0x3D, 0x00, SS_RDEF, + "Invalid bits in IDENTIFY message") }, + /* DTLPWROMAEBKVF */ + { SST(0x3E, 0x00, SS_RDEF, + "Logical unit has not self-configured yet") }, + /* DTLPWROMAEBKVF */ + { SST(0x3E, 0x01, SS_RDEF, + "Logical unit failure") }, + /* DTLPWROMAEBKVF */ + { SST(0x3E, 0x02, SS_RDEF, + "Timeout on logical unit") }, + /* DTLPWROMAEBKVF */ + { SST(0x3E, 0x03, SS_RDEF, /* XXX TBD */ + "Logical unit failed self-test") }, + /* DTLPWROMAEBKVF */ + { SST(0x3E, 0x04, SS_RDEF, /* XXX TBD */ + "Logical unit unable to update self-test log") }, + /* DTLPWROMAEBKVF */ + { SST(0x3F, 0x00, SS_RDEF, + "Target operating conditions have changed") }, + /* DTLPWROMAEBKVF */ + { SST(0x3F, 0x01, SS_RDEF, + "Microcode has been changed") }, + /* DTLPWROM BK */ + { SST(0x3F, 0x02, SS_RDEF, + "Changed operating definition") }, + /* DTLPWROMAEBKVF */ + { SST(0x3F, 0x03, SS_RDEF, + "INQUIRY data has changed") }, + /* DT WROMAEBK */ + { SST(0x3F, 0x04, SS_RDEF, + "Component device attached") }, + /* DT WROMAEBK */ + { SST(0x3F, 0x05, SS_RDEF, + "Device identifier changed") }, + /* DT WROMAEB */ + { SST(0x3F, 0x06, SS_RDEF, + "Redundancy group created or modified") }, + /* DT WROMAEB */ + { SST(0x3F, 0x07, SS_RDEF, + "Redundancy group deleted") }, + /* DT WROMAEB */ + { SST(0x3F, 0x08, SS_RDEF, + "Spare created or modified") }, + /* DT WROMAEB */ + { SST(0x3F, 0x09, SS_RDEF, + "Spare deleted") }, + /* DT WROMAEBK */ + { SST(0x3F, 0x0A, SS_RDEF, + "Volume set created or modified") }, + /* DT WROMAEBK */ + { SST(0x3F, 0x0B, SS_RDEF, + "Volume set deleted") }, + /* DT WROMAEBK */ + { SST(0x3F, 0x0C, SS_RDEF, + "Volume set deassigned") }, + /* DT WROMAEBK */ + { SST(0x3F, 0x0D, SS_RDEF, + "Volume set reassigned") }, + /* DTLPWROMAE */ + { SST(0x3F, 0x0E, SS_RDEF, /* XXX TBD */ + "Reported LUNs data has changed") }, + /* DTLPWROMAEBKVF */ + { SST(0x3F, 0x0F, SS_RDEF, /* XXX TBD */ + "Echo buffer overwritten") }, + /* DT WROM B */ + { SST(0x3F, 0x10, SS_RDEF, /* XXX TBD */ + "Medium loadable") }, + /* DT WROM B */ + { SST(0x3F, 0x11, SS_RDEF, /* XXX TBD */ + "Medium auxiliary memory accessible") }, + /* DTLPWR MAEBK F */ + { SST(0x3F, 0x12, SS_RDEF, /* XXX TBD */ + "iSCSI IP address added") }, + /* DTLPWR MAEBK F */ + { SST(0x3F, 0x13, SS_RDEF, /* XXX TBD */ + "iSCSI IP address removed") }, + /* DTLPWR MAEBK F */ + { SST(0x3F, 0x14, SS_RDEF, /* XXX TBD */ + "iSCSI IP address changed") }, + /* D */ + { SST(0x40, 0x00, SS_RDEF, + "RAM failure") }, /* deprecated - use 40 NN instead */ + /* DTLPWROMAEBKVF */ + { SST(0x40, 0x80, SS_RDEF, + "Diagnostic failure: ASCQ = Component ID") }, + /* DTLPWROMAEBKVF */ + { SST(0x40, 0xFF, SS_RDEF | SSQ_RANGE, + NULL) }, /* Range 0x80->0xFF */ + /* D */ + { SST(0x41, 0x00, SS_RDEF, + "Data path failure") }, /* deprecated - use 40 NN instead */ + /* D */ + { SST(0x42, 0x00, SS_RDEF, + "Power-on or self-test failure") }, + /* deprecated - use 40 NN instead */ + /* DTLPWROMAEBKVF */ + { SST(0x43, 0x00, SS_RDEF, + "Message error") }, + /* DTLPWROMAEBKVF */ + { SST(0x44, 0x00, SS_RDEF, + "Internal target failure") }, + /* DT B */ + { SST(0x44, 0x71, SS_RDEF, /* XXX TBD */ + "ATA device failed set features") }, + /* DTLPWROMAEBKVF */ + { SST(0x45, 0x00, SS_RDEF, + "Select or reselect failure") }, + /* DTLPWROM BK */ + { SST(0x46, 0x00, SS_RDEF, + "Unsuccessful soft reset") }, + /* DTLPWROMAEBKVF */ + { SST(0x47, 0x00, SS_RDEF, + "SCSI parity error") }, + /* DTLPWROMAEBKVF */ + { SST(0x47, 0x01, SS_RDEF, /* XXX TBD */ + "Data phase CRC error detected") }, + /* DTLPWROMAEBKVF */ + { SST(0x47, 0x02, SS_RDEF, /* XXX TBD */ + "SCSI parity error detected during ST data phase") }, + /* DTLPWROMAEBKVF */ + { SST(0x47, 0x03, SS_RDEF, /* XXX TBD */ + "Information unit iuCRC error detected") }, + /* DTLPWROMAEBKVF */ + { SST(0x47, 0x04, SS_RDEF, /* XXX TBD */ + "Asynchronous information protection error detected") }, + /* DTLPWROMAEBKVF */ + { SST(0x47, 0x05, SS_RDEF, /* XXX TBD */ + "Protocol service CRC error") }, + /* DT MAEBKVF */ + { SST(0x47, 0x06, SS_RDEF, /* XXX TBD */ + "PHY test function in progress") }, + /* DT PWROMAEBK */ + { SST(0x47, 0x7F, SS_RDEF, /* XXX TBD */ + "Some commands cleared by iSCSI protocol event") }, + /* DTLPWROMAEBKVF */ + { SST(0x48, 0x00, SS_RDEF, + "Initiator detected error message received") }, + /* DTLPWROMAEBKVF */ + { SST(0x49, 0x00, SS_RDEF, + "Invalid message error") }, + /* DTLPWROMAEBKVF */ + { SST(0x4A, 0x00, SS_RDEF, + "Command phase error") }, + /* DTLPWROMAEBKVF */ + { SST(0x4B, 0x00, SS_RDEF, + "Data phase error") }, + /* DT PWROMAEBK */ + { SST(0x4B, 0x01, SS_RDEF, /* XXX TBD */ + "Invalid target port transfer tag received") }, + /* DT PWROMAEBK */ + { SST(0x4B, 0x02, SS_RDEF, /* XXX TBD */ + "Too much write data") }, + /* DT PWROMAEBK */ + { SST(0x4B, 0x03, SS_RDEF, /* XXX TBD */ + "ACK/NAK timeout") }, + /* DT PWROMAEBK */ + { SST(0x4B, 0x04, SS_RDEF, /* XXX TBD */ + "NAK received") }, + /* DT PWROMAEBK */ + { SST(0x4B, 0x05, SS_RDEF, /* XXX TBD */ + "Data offset error") }, + /* DT PWROMAEBK */ + { SST(0x4B, 0x06, SS_RDEF, /* XXX TBD */ + "Initiator response timeout") }, + /* DTLPWROMAEBKVF */ + { SST(0x4C, 0x00, SS_RDEF, + "Logical unit failed self-configuration") }, + /* DTLPWROMAEBKVF */ + { SST(0x4D, 0x00, SS_RDEF, + "Tagged overlapped commands: ASCQ = Queue tag ID") }, + /* DTLPWROMAEBKVF */ + { SST(0x4D, 0xFF, SS_RDEF | SSQ_RANGE, + NULL) }, /* Range 0x00->0xFF */ + /* DTLPWROMAEBKVF */ + { SST(0x4E, 0x00, SS_RDEF, + "Overlapped commands attempted") }, + /* T */ + { SST(0x50, 0x00, SS_RDEF, + "Write append error") }, + /* T */ + { SST(0x50, 0x01, SS_RDEF, + "Write append position error") }, + /* T */ + { SST(0x50, 0x02, SS_RDEF, + "Position error related to timing") }, + /* T RO */ + { SST(0x51, 0x00, SS_RDEF, + "Erase failure") }, + /* R */ + { SST(0x51, 0x01, SS_RDEF, /* XXX TBD */ + "Erase failure - incomplete erase operation detected") }, + /* T */ + { SST(0x52, 0x00, SS_RDEF, + "Cartridge fault") }, + /* DTL WROM BK */ + { SST(0x53, 0x00, SS_RDEF, + "Media load or eject failed") }, + /* T */ + { SST(0x53, 0x01, SS_RDEF, + "Unload tape failure") }, + /* DT WROM BK */ + { SST(0x53, 0x02, SS_RDEF, + "Medium removal prevented") }, + /* M */ + { SST(0x53, 0x03, SS_RDEF, /* XXX TBD */ + "Medium removal prevented by data transfer element") }, + /* T */ + { SST(0x53, 0x04, SS_RDEF, /* XXX TBD */ + "Medium thread or unthread failure") }, + /* P */ + { SST(0x54, 0x00, SS_RDEF, + "SCSI to host system interface failure") }, + /* P */ + { SST(0x55, 0x00, SS_RDEF, + "System resource failure") }, + /* D O BK */ + { SST(0x55, 0x01, SS_FATAL | ENOSPC, + "System buffer full") }, + /* DTLPWROMAE K */ + { SST(0x55, 0x02, SS_RDEF, /* XXX TBD */ + "Insufficient reservation resources") }, + /* DTLPWROMAE K */ + { SST(0x55, 0x03, SS_RDEF, /* XXX TBD */ + "Insufficient resources") }, + /* DTLPWROMAE K */ + { SST(0x55, 0x04, SS_RDEF, /* XXX TBD */ + "Insufficient registration resources") }, + /* DT PWROMAEBK */ + { SST(0x55, 0x05, SS_RDEF, /* XXX TBD */ + "Insufficient access control resources") }, + /* DT WROM B */ + { SST(0x55, 0x06, SS_RDEF, /* XXX TBD */ + "Auxiliary memory out of space") }, + /* F */ + { SST(0x55, 0x07, SS_RDEF, /* XXX TBD */ + "Quota error") }, + /* T */ + { SST(0x55, 0x08, SS_RDEF, /* XXX TBD */ + "Maximum number of supplemental decryption keys exceeded") }, + /* M */ + { SST(0x55, 0x09, SS_RDEF, /* XXX TBD */ + "Medium auxiliary memory not accessible") }, + /* M */ + { SST(0x55, 0x0A, SS_RDEF, /* XXX TBD */ + "Data currently unavailable") }, + /* R */ + { SST(0x57, 0x00, SS_RDEF, + "Unable to recover table-of-contents") }, + /* O */ + { SST(0x58, 0x00, SS_RDEF, + "Generation does not exist") }, + /* O */ + { SST(0x59, 0x00, SS_RDEF, + "Updated block read") }, + /* DTLPWRO BK */ + { SST(0x5A, 0x00, SS_RDEF, + "Operator request or state change input") }, + /* DT WROM BK */ + { SST(0x5A, 0x01, SS_RDEF, + "Operator medium removal request") }, + /* DT WRO A BK */ + { SST(0x5A, 0x02, SS_RDEF, + "Operator selected write protect") }, + /* DT WRO A BK */ + { SST(0x5A, 0x03, SS_RDEF, + "Operator selected write permit") }, + /* DTLPWROM K */ + { SST(0x5B, 0x00, SS_RDEF, + "Log exception") }, + /* DTLPWROM K */ + { SST(0x5B, 0x01, SS_RDEF, + "Threshold condition met") }, + /* DTLPWROM K */ + { SST(0x5B, 0x02, SS_RDEF, + "Log counter at maximum") }, + /* DTLPWROM K */ + { SST(0x5B, 0x03, SS_RDEF, + "Log list codes exhausted") }, + /* D O */ + { SST(0x5C, 0x00, SS_RDEF, + "RPL status change") }, + /* D O */ + { SST(0x5C, 0x01, SS_NOP | SSQ_PRINT_SENSE, + "Spindles synchronized") }, + /* D O */ + { SST(0x5C, 0x02, SS_RDEF, + "Spindles not synchronized") }, + /* DTLPWROMAEBKVF */ + { SST(0x5D, 0x00, SS_RDEF, + "Failure prediction threshold exceeded") }, + /* R B */ + { SST(0x5D, 0x01, SS_RDEF, /* XXX TBD */ + "Media failure prediction threshold exceeded") }, + /* R */ + { SST(0x5D, 0x02, SS_RDEF, /* XXX TBD */ + "Logical unit failure prediction threshold exceeded") }, + /* R */ + { SST(0x5D, 0x03, SS_RDEF, /* XXX TBD */ + "Spare area exhaustion prediction threshold exceeded") }, + /* D B */ + { SST(0x5D, 0x10, SS_RDEF, /* XXX TBD */ + "Hardware impending failure general hard drive failure") }, + /* D B */ + { SST(0x5D, 0x11, SS_RDEF, /* XXX TBD */ + "Hardware impending failure drive error rate too high") }, + /* D B */ + { SST(0x5D, 0x12, SS_RDEF, /* XXX TBD */ + "Hardware impending failure data error rate too high") }, + /* D B */ + { SST(0x5D, 0x13, SS_RDEF, /* XXX TBD */ + "Hardware impending failure seek error rate too high") }, + /* D B */ + { SST(0x5D, 0x14, SS_RDEF, /* XXX TBD */ + "Hardware impending failure too many block reassigns") }, + /* D B */ + { SST(0x5D, 0x15, SS_RDEF, /* XXX TBD */ + "Hardware impending failure access times too high") }, + /* D B */ + { SST(0x5D, 0x16, SS_RDEF, /* XXX TBD */ + "Hardware impending failure start unit times too high") }, + /* D B */ + { SST(0x5D, 0x17, SS_RDEF, /* XXX TBD */ + "Hardware impending failure channel parametrics") }, + /* D B */ + { SST(0x5D, 0x18, SS_RDEF, /* XXX TBD */ + "Hardware impending failure controller detected") }, + /* D B */ + { SST(0x5D, 0x19, SS_RDEF, /* XXX TBD */ + "Hardware impending failure throughput performance") }, + /* D B */ + { SST(0x5D, 0x1A, SS_RDEF, /* XXX TBD */ + "Hardware impending failure seek time performance") }, + /* D B */ + { SST(0x5D, 0x1B, SS_RDEF, /* XXX TBD */ + "Hardware impending failure spin-up retry count") }, + /* D B */ + { SST(0x5D, 0x1C, SS_RDEF, /* XXX TBD */ + "Hardware impending failure drive calibration retry count") }, + /* D B */ + { SST(0x5D, 0x20, SS_RDEF, /* XXX TBD */ + "Controller impending failure general hard drive failure") }, + /* D B */ + { SST(0x5D, 0x21, SS_RDEF, /* XXX TBD */ + "Controller impending failure drive error rate too high") }, + /* D B */ + { SST(0x5D, 0x22, SS_RDEF, /* XXX TBD */ + "Controller impending failure data error rate too high") }, + /* D B */ + { SST(0x5D, 0x23, SS_RDEF, /* XXX TBD */ + "Controller impending failure seek error rate too high") }, + /* D B */ + { SST(0x5D, 0x24, SS_RDEF, /* XXX TBD */ + "Controller impending failure too many block reassigns") }, + /* D B */ + { SST(0x5D, 0x25, SS_RDEF, /* XXX TBD */ + "Controller impending failure access times too high") }, + /* D B */ + { SST(0x5D, 0x26, SS_RDEF, /* XXX TBD */ + "Controller impending failure start unit times too high") }, + /* D B */ + { SST(0x5D, 0x27, SS_RDEF, /* XXX TBD */ + "Controller impending failure channel parametrics") }, + /* D B */ + { SST(0x5D, 0x28, SS_RDEF, /* XXX TBD */ + "Controller impending failure controller detected") }, + /* D B */ + { SST(0x5D, 0x29, SS_RDEF, /* XXX TBD */ + "Controller impending failure throughput performance") }, + /* D B */ + { SST(0x5D, 0x2A, SS_RDEF, /* XXX TBD */ + "Controller impending failure seek time performance") }, + /* D B */ + { SST(0x5D, 0x2B, SS_RDEF, /* XXX TBD */ + "Controller impending failure spin-up retry count") }, + /* D B */ + { SST(0x5D, 0x2C, SS_RDEF, /* XXX TBD */ + "Controller impending failure drive calibration retry count") }, + /* D B */ + { SST(0x5D, 0x30, SS_RDEF, /* XXX TBD */ + "Data channel impending failure general hard drive failure") }, + /* D B */ + { SST(0x5D, 0x31, SS_RDEF, /* XXX TBD */ + "Data channel impending failure drive error rate too high") }, + /* D B */ + { SST(0x5D, 0x32, SS_RDEF, /* XXX TBD */ + "Data channel impending failure data error rate too high") }, + /* D B */ + { SST(0x5D, 0x33, SS_RDEF, /* XXX TBD */ + "Data channel impending failure seek error rate too high") }, + /* D B */ + { SST(0x5D, 0x34, SS_RDEF, /* XXX TBD */ + "Data channel impending failure too many block reassigns") }, + /* D B */ + { SST(0x5D, 0x35, SS_RDEF, /* XXX TBD */ + "Data channel impending failure access times too high") }, + /* D B */ + { SST(0x5D, 0x36, SS_RDEF, /* XXX TBD */ + "Data channel impending failure start unit times too high") }, + /* D B */ + { SST(0x5D, 0x37, SS_RDEF, /* XXX TBD */ + "Data channel impending failure channel parametrics") }, + /* D B */ + { SST(0x5D, 0x38, SS_RDEF, /* XXX TBD */ + "Data channel impending failure controller detected") }, + /* D B */ + { SST(0x5D, 0x39, SS_RDEF, /* XXX TBD */ + "Data channel impending failure throughput performance") }, + /* D B */ + { SST(0x5D, 0x3A, SS_RDEF, /* XXX TBD */ + "Data channel impending failure seek time performance") }, + /* D B */ + { SST(0x5D, 0x3B, SS_RDEF, /* XXX TBD */ + "Data channel impending failure spin-up retry count") }, + /* D B */ + { SST(0x5D, 0x3C, SS_RDEF, /* XXX TBD */ + "Data channel impending failure drive calibration retry count") }, + /* D B */ + { SST(0x5D, 0x40, SS_RDEF, /* XXX TBD */ + "Servo impending failure general hard drive failure") }, + /* D B */ + { SST(0x5D, 0x41, SS_RDEF, /* XXX TBD */ + "Servo impending failure drive error rate too high") }, + /* D B */ + { SST(0x5D, 0x42, SS_RDEF, /* XXX TBD */ + "Servo impending failure data error rate too high") }, + /* D B */ + { SST(0x5D, 0x43, SS_RDEF, /* XXX TBD */ + "Servo impending failure seek error rate too high") }, + /* D B */ + { SST(0x5D, 0x44, SS_RDEF, /* XXX TBD */ + "Servo impending failure too many block reassigns") }, + /* D B */ + { SST(0x5D, 0x45, SS_RDEF, /* XXX TBD */ + "Servo impending failure access times too high") }, + /* D B */ + { SST(0x5D, 0x46, SS_RDEF, /* XXX TBD */ + "Servo impending failure start unit times too high") }, + /* D B */ + { SST(0x5D, 0x47, SS_RDEF, /* XXX TBD */ + "Servo impending failure channel parametrics") }, + /* D B */ + { SST(0x5D, 0x48, SS_RDEF, /* XXX TBD */ + "Servo impending failure controller detected") }, + /* D B */ + { SST(0x5D, 0x49, SS_RDEF, /* XXX TBD */ + "Servo impending failure throughput performance") }, + /* D B */ + { SST(0x5D, 0x4A, SS_RDEF, /* XXX TBD */ + "Servo impending failure seek time performance") }, + /* D B */ + { SST(0x5D, 0x4B, SS_RDEF, /* XXX TBD */ + "Servo impending failure spin-up retry count") }, + /* D B */ + { SST(0x5D, 0x4C, SS_RDEF, /* XXX TBD */ + "Servo impending failure drive calibration retry count") }, + /* D B */ + { SST(0x5D, 0x50, SS_RDEF, /* XXX TBD */ + "Spindle impending failure general hard drive failure") }, + /* D B */ + { SST(0x5D, 0x51, SS_RDEF, /* XXX TBD */ + "Spindle impending failure drive error rate too high") }, + /* D B */ + { SST(0x5D, 0x52, SS_RDEF, /* XXX TBD */ + "Spindle impending failure data error rate too high") }, + /* D B */ + { SST(0x5D, 0x53, SS_RDEF, /* XXX TBD */ + "Spindle impending failure seek error rate too high") }, + /* D B */ + { SST(0x5D, 0x54, SS_RDEF, /* XXX TBD */ + "Spindle impending failure too many block reassigns") }, + /* D B */ + { SST(0x5D, 0x55, SS_RDEF, /* XXX TBD */ + "Spindle impending failure access times too high") }, + /* D B */ + { SST(0x5D, 0x56, SS_RDEF, /* XXX TBD */ + "Spindle impending failure start unit times too high") }, + /* D B */ + { SST(0x5D, 0x57, SS_RDEF, /* XXX TBD */ + "Spindle impending failure channel parametrics") }, + /* D B */ + { SST(0x5D, 0x58, SS_RDEF, /* XXX TBD */ + "Spindle impending failure controller detected") }, + /* D B */ + { SST(0x5D, 0x59, SS_RDEF, /* XXX TBD */ + "Spindle impending failure throughput performance") }, + /* D B */ + { SST(0x5D, 0x5A, SS_RDEF, /* XXX TBD */ + "Spindle impending failure seek time performance") }, + /* D B */ + { SST(0x5D, 0x5B, SS_RDEF, /* XXX TBD */ + "Spindle impending failure spin-up retry count") }, + /* D B */ + { SST(0x5D, 0x5C, SS_RDEF, /* XXX TBD */ + "Spindle impending failure drive calibration retry count") }, + /* D B */ + { SST(0x5D, 0x60, SS_RDEF, /* XXX TBD */ + "Firmware impending failure general hard drive failure") }, + /* D B */ + { SST(0x5D, 0x61, SS_RDEF, /* XXX TBD */ + "Firmware impending failure drive error rate too high") }, + /* D B */ + { SST(0x5D, 0x62, SS_RDEF, /* XXX TBD */ + "Firmware impending failure data error rate too high") }, + /* D B */ + { SST(0x5D, 0x63, SS_RDEF, /* XXX TBD */ + "Firmware impending failure seek error rate too high") }, + /* D B */ + { SST(0x5D, 0x64, SS_RDEF, /* XXX TBD */ + "Firmware impending failure too many block reassigns") }, + /* D B */ + { SST(0x5D, 0x65, SS_RDEF, /* XXX TBD */ + "Firmware impending failure access times too high") }, + /* D B */ + { SST(0x5D, 0x66, SS_RDEF, /* XXX TBD */ + "Firmware impending failure start unit times too high") }, + /* D B */ + { SST(0x5D, 0x67, SS_RDEF, /* XXX TBD */ + "Firmware impending failure channel parametrics") }, + /* D B */ + { SST(0x5D, 0x68, SS_RDEF, /* XXX TBD */ + "Firmware impending failure controller detected") }, + /* D B */ + { SST(0x5D, 0x69, SS_RDEF, /* XXX TBD */ + "Firmware impending failure throughput performance") }, + /* D B */ + { SST(0x5D, 0x6A, SS_RDEF, /* XXX TBD */ + "Firmware impending failure seek time performance") }, + /* D B */ + { SST(0x5D, 0x6B, SS_RDEF, /* XXX TBD */ + "Firmware impending failure spin-up retry count") }, + /* D B */ + { SST(0x5D, 0x6C, SS_RDEF, /* XXX TBD */ + "Firmware impending failure drive calibration retry count") }, + /* DTLPWROMAEBKVF */ + { SST(0x5D, 0xFF, SS_RDEF, + "Failure prediction threshold exceeded (false)") }, + /* DTLPWRO A K */ + { SST(0x5E, 0x00, SS_RDEF, + "Low power condition on") }, + /* DTLPWRO A K */ + { SST(0x5E, 0x01, SS_RDEF, + "Idle condition activated by timer") }, + /* DTLPWRO A K */ + { SST(0x5E, 0x02, SS_RDEF, + "Standby condition activated by timer") }, + /* DTLPWRO A K */ + { SST(0x5E, 0x03, SS_RDEF, + "Idle condition activated by command") }, + /* DTLPWRO A K */ + { SST(0x5E, 0x04, SS_RDEF, + "Standby condition activated by command") }, + /* B */ + { SST(0x5E, 0x41, SS_RDEF, /* XXX TBD */ + "Power state change to active") }, + /* B */ + { SST(0x5E, 0x42, SS_RDEF, /* XXX TBD */ + "Power state change to idle") }, + /* B */ + { SST(0x5E, 0x43, SS_RDEF, /* XXX TBD */ + "Power state change to standby") }, + /* B */ + { SST(0x5E, 0x45, SS_RDEF, /* XXX TBD */ + "Power state change to sleep") }, + /* BK */ + { SST(0x5E, 0x47, SS_RDEF, /* XXX TBD */ + "Power state change to device control") }, + /* */ + { SST(0x60, 0x00, SS_RDEF, + "Lamp failure") }, + /* */ + { SST(0x61, 0x00, SS_RDEF, + "Video acquisition error") }, + /* */ + { SST(0x61, 0x01, SS_RDEF, + "Unable to acquire video") }, + /* */ + { SST(0x61, 0x02, SS_RDEF, + "Out of focus") }, + /* */ + { SST(0x62, 0x00, SS_RDEF, + "Scan head positioning error") }, + /* R */ + { SST(0x63, 0x00, SS_RDEF, + "End of user area encountered on this track") }, + /* R */ + { SST(0x63, 0x01, SS_FATAL | ENOSPC, + "Packet does not fit in available space") }, + /* R */ + { SST(0x64, 0x00, SS_FATAL | ENXIO, + "Illegal mode for this track") }, + /* R */ + { SST(0x64, 0x01, SS_RDEF, + "Invalid packet size") }, + /* DTLPWROMAEBKVF */ + { SST(0x65, 0x00, SS_RDEF, + "Voltage fault") }, + /* */ + { SST(0x66, 0x00, SS_RDEF, + "Automatic document feeder cover up") }, + /* */ + { SST(0x66, 0x01, SS_RDEF, + "Automatic document feeder lift up") }, + /* */ + { SST(0x66, 0x02, SS_RDEF, + "Document jam in automatic document feeder") }, + /* */ + { SST(0x66, 0x03, SS_RDEF, + "Document miss feed automatic in document feeder") }, + /* A */ + { SST(0x67, 0x00, SS_RDEF, + "Configuration failure") }, + /* A */ + { SST(0x67, 0x01, SS_RDEF, + "Configuration of incapable logical units failed") }, + /* A */ + { SST(0x67, 0x02, SS_RDEF, + "Add logical unit failed") }, + /* A */ + { SST(0x67, 0x03, SS_RDEF, + "Modification of logical unit failed") }, + /* A */ + { SST(0x67, 0x04, SS_RDEF, + "Exchange of logical unit failed") }, + /* A */ + { SST(0x67, 0x05, SS_RDEF, + "Remove of logical unit failed") }, + /* A */ + { SST(0x67, 0x06, SS_RDEF, + "Attachment of logical unit failed") }, + /* A */ + { SST(0x67, 0x07, SS_RDEF, + "Creation of logical unit failed") }, + /* A */ + { SST(0x67, 0x08, SS_RDEF, /* XXX TBD */ + "Assign failure occurred") }, + /* A */ + { SST(0x67, 0x09, SS_RDEF, /* XXX TBD */ + "Multiply assigned logical unit") }, + /* DTLPWROMAEBKVF */ + { SST(0x67, 0x0A, SS_RDEF, /* XXX TBD */ + "Set target port groups command failed") }, + /* DT B */ + { SST(0x67, 0x0B, SS_RDEF, /* XXX TBD */ + "ATA device feature not enabled") }, + /* A */ + { SST(0x68, 0x00, SS_RDEF, + "Logical unit not configured") }, + /* A */ + { SST(0x69, 0x00, SS_RDEF, + "Data loss on logical unit") }, + /* A */ + { SST(0x69, 0x01, SS_RDEF, + "Multiple logical unit failures") }, + /* A */ + { SST(0x69, 0x02, SS_RDEF, + "Parity/data mismatch") }, + /* A */ + { SST(0x6A, 0x00, SS_RDEF, + "Informational, refer to log") }, + /* A */ + { SST(0x6B, 0x00, SS_RDEF, + "State change has occurred") }, + /* A */ + { SST(0x6B, 0x01, SS_RDEF, + "Redundancy level got better") }, + /* A */ + { SST(0x6B, 0x02, SS_RDEF, + "Redundancy level got worse") }, + /* A */ + { SST(0x6C, 0x00, SS_RDEF, + "Rebuild failure occurred") }, + /* A */ + { SST(0x6D, 0x00, SS_RDEF, + "Recalculate failure occurred") }, + /* A */ + { SST(0x6E, 0x00, SS_RDEF, + "Command to logical unit failed") }, + /* R */ + { SST(0x6F, 0x00, SS_RDEF, /* XXX TBD */ + "Copy protection key exchange failure - authentication failure") }, + /* R */ + { SST(0x6F, 0x01, SS_RDEF, /* XXX TBD */ + "Copy protection key exchange failure - key not present") }, + /* R */ + { SST(0x6F, 0x02, SS_RDEF, /* XXX TBD */ + "Copy protection key exchange failure - key not established") }, + /* R */ + { SST(0x6F, 0x03, SS_RDEF, /* XXX TBD */ + "Read of scrambled sector without authentication") }, + /* R */ + { SST(0x6F, 0x04, SS_RDEF, /* XXX TBD */ + "Media region code is mismatched to logical unit region") }, + /* R */ + { SST(0x6F, 0x05, SS_RDEF, /* XXX TBD */ + "Drive region must be permanent/region reset count error") }, + /* R */ + { SST(0x6F, 0x06, SS_RDEF, /* XXX TBD */ + "Insufficient block count for binding NONCE recording") }, + /* R */ + { SST(0x6F, 0x07, SS_RDEF, /* XXX TBD */ + "Conflict in binding NONCE recording") }, + /* T */ + { SST(0x70, 0x00, SS_RDEF, + "Decompression exception short: ASCQ = Algorithm ID") }, + /* T */ + { SST(0x70, 0xFF, SS_RDEF | SSQ_RANGE, + NULL) }, /* Range 0x00 -> 0xFF */ + /* T */ + { SST(0x71, 0x00, SS_RDEF, + "Decompression exception long: ASCQ = Algorithm ID") }, + /* T */ + { SST(0x71, 0xFF, SS_RDEF | SSQ_RANGE, + NULL) }, /* Range 0x00 -> 0xFF */ + /* R */ + { SST(0x72, 0x00, SS_RDEF, + "Session fixation error") }, + /* R */ + { SST(0x72, 0x01, SS_RDEF, + "Session fixation error writing lead-in") }, + /* R */ + { SST(0x72, 0x02, SS_RDEF, + "Session fixation error writing lead-out") }, + /* R */ + { SST(0x72, 0x03, SS_RDEF, + "Session fixation error - incomplete track in session") }, + /* R */ + { SST(0x72, 0x04, SS_RDEF, + "Empty or partially written reserved track") }, + /* R */ + { SST(0x72, 0x05, SS_RDEF, /* XXX TBD */ + "No more track reservations allowed") }, + /* R */ + { SST(0x72, 0x06, SS_RDEF, /* XXX TBD */ + "RMZ extension is not allowed") }, + /* R */ + { SST(0x72, 0x07, SS_RDEF, /* XXX TBD */ + "No more test zone extensions are allowed") }, + /* R */ + { SST(0x73, 0x00, SS_RDEF, + "CD control error") }, + /* R */ + { SST(0x73, 0x01, SS_RDEF, + "Power calibration area almost full") }, + /* R */ + { SST(0x73, 0x02, SS_FATAL | ENOSPC, + "Power calibration area is full") }, + /* R */ + { SST(0x73, 0x03, SS_RDEF, + "Power calibration area error") }, + /* R */ + { SST(0x73, 0x04, SS_RDEF, + "Program memory area update failure") }, + /* R */ + { SST(0x73, 0x05, SS_RDEF, + "Program memory area is full") }, + /* R */ + { SST(0x73, 0x06, SS_RDEF, /* XXX TBD */ + "RMA/PMA is almost full") }, + /* R */ + { SST(0x73, 0x10, SS_RDEF, /* XXX TBD */ + "Current power calibration area almost full") }, + /* R */ + { SST(0x73, 0x11, SS_RDEF, /* XXX TBD */ + "Current power calibration area is full") }, + /* R */ + { SST(0x73, 0x17, SS_RDEF, /* XXX TBD */ + "RDZ is full") }, + /* T */ + { SST(0x74, 0x00, SS_RDEF, /* XXX TBD */ + "Security error") }, + /* T */ + { SST(0x74, 0x01, SS_RDEF, /* XXX TBD */ + "Unable to decrypt data") }, + /* T */ + { SST(0x74, 0x02, SS_RDEF, /* XXX TBD */ + "Unencrypted data encountered while decrypting") }, + /* T */ + { SST(0x74, 0x03, SS_RDEF, /* XXX TBD */ + "Incorrect data encryption key") }, + /* T */ + { SST(0x74, 0x04, SS_RDEF, /* XXX TBD */ + "Cryptographic integrity validation failed") }, + /* T */ + { SST(0x74, 0x05, SS_RDEF, /* XXX TBD */ + "Error decrypting data") }, + /* T */ + { SST(0x74, 0x06, SS_RDEF, /* XXX TBD */ + "Unknown signature verification key") }, + /* T */ + { SST(0x74, 0x07, SS_RDEF, /* XXX TBD */ + "Encryption parameters not useable") }, + /* DT R M E VF */ + { SST(0x74, 0x08, SS_RDEF, /* XXX TBD */ + "Digital signature validation failure") }, + /* T */ + { SST(0x74, 0x09, SS_RDEF, /* XXX TBD */ + "Encryption mode mismatch on read") }, + /* T */ + { SST(0x74, 0x0A, SS_RDEF, /* XXX TBD */ + "Encrypted block not raw read enabled") }, + /* T */ + { SST(0x74, 0x0B, SS_RDEF, /* XXX TBD */ + "Incorrect encryption parameters") }, + /* DT R MAEBKV */ + { SST(0x74, 0x0C, SS_RDEF, /* XXX TBD */ + "Unable to decrypt parameter list") }, + /* T */ + { SST(0x74, 0x0D, SS_RDEF, /* XXX TBD */ + "Encryption algorithm disabled") }, + /* DT R MAEBKV */ + { SST(0x74, 0x10, SS_RDEF, /* XXX TBD */ + "SA creation parameter value invalid") }, + /* DT R MAEBKV */ + { SST(0x74, 0x11, SS_RDEF, /* XXX TBD */ + "SA creation parameter value rejected") }, + /* DT R MAEBKV */ + { SST(0x74, 0x12, SS_RDEF, /* XXX TBD */ + "Invalid SA usage") }, + /* T */ + { SST(0x74, 0x21, SS_RDEF, /* XXX TBD */ + "Data encryption configuration prevented") }, + /* DT R MAEBKV */ + { SST(0x74, 0x30, SS_RDEF, /* XXX TBD */ + "SA creation parameter not supported") }, + /* DT R MAEBKV */ + { SST(0x74, 0x40, SS_RDEF, /* XXX TBD */ + "Authentication failed") }, + /* V */ + { SST(0x74, 0x61, SS_RDEF, /* XXX TBD */ + "External data encryption key manager access error") }, + /* V */ + { SST(0x74, 0x62, SS_RDEF, /* XXX TBD */ + "External data encryption key manager error") }, + /* V */ + { SST(0x74, 0x63, SS_RDEF, /* XXX TBD */ + "External data encryption key not found") }, + /* V */ + { SST(0x74, 0x64, SS_RDEF, /* XXX TBD */ + "External data encryption request not authorized") }, + /* T */ + { SST(0x74, 0x6E, SS_RDEF, /* XXX TBD */ + "External data encryption control timeout") }, + /* T */ + { SST(0x74, 0x6F, SS_RDEF, /* XXX TBD */ + "External data encryption control error") }, + /* DT R M E V */ + { SST(0x74, 0x71, SS_RDEF, /* XXX TBD */ + "Logical unit access not authorized") }, + /* D */ + { SST(0x74, 0x79, SS_RDEF, /* XXX TBD */ + "Security conflict in translated device") } +}; + +const int asc_table_size = sizeof(asc_table)/sizeof(asc_table[0]); + +struct asc_key +{ + int asc; + int ascq; +}; + +static int +ascentrycomp(const void *key, const void *member) +{ + int asc; + int ascq; + const struct asc_table_entry *table_entry; + + asc = ((const struct asc_key *)key)->asc; + ascq = ((const struct asc_key *)key)->ascq; + table_entry = (const struct asc_table_entry *)member; + + if (asc >= table_entry->asc) { + + if (asc > table_entry->asc) + return (1); + + if (ascq <= table_entry->ascq) { + /* Check for ranges */ + if (ascq == table_entry->ascq + || ((table_entry->action & SSQ_RANGE) != 0 + && ascq >= (table_entry - 1)->ascq)) + return (0); + return (-1); + } + return (1); + } + return (-1); +} + +static int +senseentrycomp(const void *key, const void *member) +{ + int sense_key; + const struct sense_key_table_entry *table_entry; + + sense_key = *((const int *)key); + table_entry = (const struct sense_key_table_entry *)member; + + if (sense_key >= table_entry->sense_key) { + if (sense_key == table_entry->sense_key) + return (0); + return (1); + } + return (-1); +} + +static void +fetchtableentries(int sense_key, int asc, int ascq, + struct scsi_inquiry_data *inq_data, + const struct sense_key_table_entry **sense_entry, + const struct asc_table_entry **asc_entry) +{ + caddr_t match; + const struct asc_table_entry *asc_tables[2]; + const struct sense_key_table_entry *sense_tables[2]; + struct asc_key asc_ascq; + size_t asc_tables_size[2]; + size_t sense_tables_size[2]; + int num_asc_tables; + int num_sense_tables; + int i; + + /* Default to failure */ + *sense_entry = NULL; + *asc_entry = NULL; + match = NULL; + if (inq_data != NULL) + match = cam_quirkmatch((caddr_t)inq_data, + (caddr_t)sense_quirk_table, + sense_quirk_table_size, + sizeof(*sense_quirk_table), + scsi_inquiry_match); + + if (match != NULL) { + struct scsi_sense_quirk_entry *quirk; + + quirk = (struct scsi_sense_quirk_entry *)match; + asc_tables[0] = quirk->asc_info; + asc_tables_size[0] = quirk->num_ascs; + asc_tables[1] = asc_table; + asc_tables_size[1] = asc_table_size; + num_asc_tables = 2; + sense_tables[0] = quirk->sense_key_info; + sense_tables_size[0] = quirk->num_sense_keys; + sense_tables[1] = sense_key_table; + sense_tables_size[1] = sense_key_table_size; + num_sense_tables = 2; + } else { + asc_tables[0] = asc_table; + asc_tables_size[0] = asc_table_size; + num_asc_tables = 1; + sense_tables[0] = sense_key_table; + sense_tables_size[0] = sense_key_table_size; + num_sense_tables = 1; + } + + asc_ascq.asc = asc; + asc_ascq.ascq = ascq; + for (i = 0; i < num_asc_tables; i++) { + void *found_entry; + + found_entry = bsearch(&asc_ascq, asc_tables[i], + asc_tables_size[i], + sizeof(**asc_tables), + ascentrycomp); + + if (found_entry) { + *asc_entry = (struct asc_table_entry *)found_entry; + break; + } + } + + for (i = 0; i < num_sense_tables; i++) { + void *found_entry; + + found_entry = bsearch(&sense_key, sense_tables[i], + sense_tables_size[i], + sizeof(**sense_tables), + senseentrycomp); + + if (found_entry) { + *sense_entry = + (struct sense_key_table_entry *)found_entry; + break; + } + } +} + +void +scsi_sense_desc(int sense_key, int asc, int ascq, + struct scsi_inquiry_data *inq_data, + const char **sense_key_desc, const char **asc_desc) +{ + const struct asc_table_entry *asc_entry; + const struct sense_key_table_entry *sense_entry; + + fetchtableentries(sense_key, asc, ascq, + inq_data, + &sense_entry, + &asc_entry); + + *sense_key_desc = sense_entry->desc; + + if (asc_entry != NULL) + *asc_desc = asc_entry->desc; + else if (asc >= 0x80 && asc <= 0xff) + *asc_desc = "Vendor Specific ASC"; + else if (ascq >= 0x80 && ascq <= 0xff) + *asc_desc = "Vendor Specific ASCQ"; + else + *asc_desc = "Reserved ASC/ASCQ pair"; +} + +/* + * Given sense and device type information, return the appropriate action. + * If we do not understand the specific error as identified by the ASC/ASCQ + * pair, fall back on the more generic actions derived from the sense key. + */ +scsi_sense_action +scsi_error_action(struct ccb_scsiio *csio, struct scsi_inquiry_data *inq_data, + u_int32_t sense_flags) +{ + const struct asc_table_entry *asc_entry; + const struct sense_key_table_entry *sense_entry; + int error_code, sense_key, asc, ascq; + scsi_sense_action action; + + scsi_extract_sense(&csio->sense_data, &error_code, + &sense_key, &asc, &ascq); + + if (error_code == SSD_DEFERRED_ERROR) { + /* + * XXX dufault@FreeBSD.org + * This error doesn't relate to the command associated + * with this request sense. A deferred error is an error + * for a command that has already returned GOOD status + * (see SCSI2 8.2.14.2). + * + * By my reading of that section, it looks like the current + * command has been cancelled, we should now clean things up + * (hopefully recovering any lost data) and then retry the + * current command. There are two easy choices, both wrong: + * + * 1. Drop through (like we had been doing), thus treating + * this as if the error were for the current command and + * return and stop the current command. + * + * 2. Issue a retry (like I made it do) thus hopefully + * recovering the current transfer, and ignoring the + * fact that we've dropped a command. + * + * These should probably be handled in a device specific + * sense handler or punted back up to a user mode daemon + */ + action = SS_RETRY|SSQ_DECREMENT_COUNT|SSQ_PRINT_SENSE; + } else { + fetchtableentries(sense_key, asc, ascq, + inq_data, + &sense_entry, + &asc_entry); + + /* + * Override the 'No additional Sense' entry (0,0) + * with the error action of the sense key. + */ + if (asc_entry != NULL + && (asc != 0 || ascq != 0)) + action = asc_entry->action; + else + action = sense_entry->action; + + if (sense_key == SSD_KEY_RECOVERED_ERROR) { + /* + * The action succeeded but the device wants + * the user to know that some recovery action + * was required. + */ + action &= ~(SS_MASK|SSQ_MASK|SS_ERRMASK); + action |= SS_NOP|SSQ_PRINT_SENSE; + } else if (sense_key == SSD_KEY_ILLEGAL_REQUEST) { + if ((sense_flags & SF_QUIET_IR) != 0) + action &= ~SSQ_PRINT_SENSE; + } else if (sense_key == SSD_KEY_UNIT_ATTENTION) { + if ((sense_flags & SF_RETRY_UA) != 0 + && (action & SS_MASK) == SS_FAIL) { + action &= ~(SS_MASK|SSQ_MASK); + action |= SS_RETRY|SSQ_DECREMENT_COUNT| + SSQ_PRINT_SENSE; + } + } + } +#ifdef _KERNEL + if (bootverbose) + sense_flags |= SF_PRINT_ALWAYS; +#endif + if ((sense_flags & SF_PRINT_ALWAYS) != 0) + action |= SSQ_PRINT_SENSE; + else if ((sense_flags & SF_NO_PRINT) != 0) + action &= ~SSQ_PRINT_SENSE; + + return (action); +} + +char * +scsi_cdb_string(u_int8_t *cdb_ptr, char *cdb_string, size_t len) +{ + u_int8_t cdb_len; + int i; + + if (cdb_ptr == NULL) + return(""); + + /* Silence warnings */ + cdb_len = 0; + + /* + * This is taken from the SCSI-3 draft spec. + * (T10/1157D revision 0.3) + * The top 3 bits of an opcode are the group code. The next 5 bits + * are the command code. + * Group 0: six byte commands + * Group 1: ten byte commands + * Group 2: ten byte commands + * Group 3: reserved + * Group 4: sixteen byte commands + * Group 5: twelve byte commands + * Group 6: vendor specific + * Group 7: vendor specific + */ + switch((*cdb_ptr >> 5) & 0x7) { + case 0: + cdb_len = 6; + break; + case 1: + case 2: + cdb_len = 10; + break; + case 3: + case 6: + case 7: + /* in this case, just print out the opcode */ + cdb_len = 1; + break; + case 4: + cdb_len = 16; + break; + case 5: + cdb_len = 12; + break; + } + *cdb_string = '\0'; + for (i = 0; i < cdb_len; i++) + snprintf(cdb_string + strlen(cdb_string), + len - strlen(cdb_string), "%x ", cdb_ptr[i]); + + return(cdb_string); +} + +const char * +scsi_status_string(struct ccb_scsiio *csio) +{ + switch(csio->scsi_status) { + case SCSI_STATUS_OK: + return("OK"); + case SCSI_STATUS_CHECK_COND: + return("Check Condition"); + case SCSI_STATUS_BUSY: + return("Busy"); + case SCSI_STATUS_INTERMED: + return("Intermediate"); + case SCSI_STATUS_INTERMED_COND_MET: + return("Intermediate-Condition Met"); + case SCSI_STATUS_RESERV_CONFLICT: + return("Reservation Conflict"); + case SCSI_STATUS_CMD_TERMINATED: + return("Command Terminated"); + case SCSI_STATUS_QUEUE_FULL: + return("Queue Full"); + case SCSI_STATUS_ACA_ACTIVE: + return("ACA Active"); + case SCSI_STATUS_TASK_ABORTED: + return("Task Aborted"); + default: { + static char unkstr[64]; + snprintf(unkstr, sizeof(unkstr), "Unknown %#x", + csio->scsi_status); + return(unkstr); + } + } +} + +/* + * scsi_command_string() returns 0 for success and -1 for failure. + */ +#ifdef _KERNEL +int +scsi_command_string(struct ccb_scsiio *csio, struct sbuf *sb) +#else /* !_KERNEL */ +int +scsi_command_string(struct cam_device *device, struct ccb_scsiio *csio, + struct sbuf *sb) +#endif /* _KERNEL/!_KERNEL */ +{ + struct scsi_inquiry_data *inq_data; + char cdb_str[(SCSI_MAX_CDBLEN * 3) + 1]; +#ifdef _KERNEL + struct ccb_getdev *cgd; +#endif /* _KERNEL */ + +#ifdef _KERNEL + if ((cgd = (struct ccb_getdev*)xpt_alloc_ccb_nowait()) == NULL) + return(-1); + /* + * Get the device information. + */ + xpt_setup_ccb(&cgd->ccb_h, + csio->ccb_h.path, + CAM_PRIORITY_NORMAL); + cgd->ccb_h.func_code = XPT_GDEV_TYPE; + xpt_action((union ccb *)cgd); + + /* + * If the device is unconfigured, just pretend that it is a hard + * drive. scsi_op_desc() needs this. + */ + if (cgd->ccb_h.status == CAM_DEV_NOT_THERE) + cgd->inq_data.device = T_DIRECT; + + inq_data = &cgd->inq_data; + +#else /* !_KERNEL */ + + inq_data = &device->inq_data; + +#endif /* _KERNEL/!_KERNEL */ + + if ((csio->ccb_h.flags & CAM_CDB_POINTER) != 0) { + sbuf_printf(sb, "%s. CDB: %s", + scsi_op_desc(csio->cdb_io.cdb_ptr[0], inq_data), + scsi_cdb_string(csio->cdb_io.cdb_ptr, cdb_str, + sizeof(cdb_str))); + } else { + sbuf_printf(sb, "%s. CDB: %s", + scsi_op_desc(csio->cdb_io.cdb_bytes[0], inq_data), + scsi_cdb_string(csio->cdb_io.cdb_bytes, cdb_str, + sizeof(cdb_str))); + } + + return(0); +} + + +/* + * scsi_sense_sbuf() returns 0 for success and -1 for failure. + */ +#ifdef _KERNEL +int +scsi_sense_sbuf(struct ccb_scsiio *csio, struct sbuf *sb, + scsi_sense_string_flags flags) +#else /* !_KERNEL */ +int +scsi_sense_sbuf(struct cam_device *device, struct ccb_scsiio *csio, + struct sbuf *sb, scsi_sense_string_flags flags) +#endif /* _KERNEL/!_KERNEL */ +{ + struct scsi_sense_data *sense; + struct scsi_inquiry_data *inq_data; +#ifdef _KERNEL + struct ccb_getdev *cgd; +#endif /* _KERNEL */ + u_int32_t info; + int error_code; + int sense_key; + int asc, ascq; + char path_str[64]; + +#ifndef _KERNEL + if (device == NULL) + return(-1); +#endif /* !_KERNEL */ + if ((csio == NULL) || (sb == NULL)) + return(-1); + + /* + * If the CDB is a physical address, we can't deal with it.. + */ + if ((csio->ccb_h.flags & CAM_CDB_PHYS) != 0) + flags &= ~SSS_FLAG_PRINT_COMMAND; + +#ifdef _KERNEL + xpt_path_string(csio->ccb_h.path, path_str, sizeof(path_str)); +#else /* !_KERNEL */ + cam_path_string(device, path_str, sizeof(path_str)); +#endif /* _KERNEL/!_KERNEL */ + +#ifdef _KERNEL + if ((cgd = (struct ccb_getdev*)xpt_alloc_ccb_nowait()) == NULL) + return(-1); + /* + * Get the device information. + */ + xpt_setup_ccb(&cgd->ccb_h, + csio->ccb_h.path, + CAM_PRIORITY_NORMAL); + cgd->ccb_h.func_code = XPT_GDEV_TYPE; + xpt_action((union ccb *)cgd); + + /* + * If the device is unconfigured, just pretend that it is a hard + * drive. scsi_op_desc() needs this. + */ + if (cgd->ccb_h.status == CAM_DEV_NOT_THERE) + cgd->inq_data.device = T_DIRECT; + + inq_data = &cgd->inq_data; + +#else /* !_KERNEL */ + + inq_data = &device->inq_data; + +#endif /* _KERNEL/!_KERNEL */ + + sense = NULL; + + if (flags & SSS_FLAG_PRINT_COMMAND) { + + sbuf_cat(sb, path_str); + +#ifdef _KERNEL + scsi_command_string(csio, sb); +#else /* !_KERNEL */ + scsi_command_string(device, csio, sb); +#endif /* _KERNEL/!_KERNEL */ + sbuf_printf(sb, "\n"); + } + + /* + * If the sense data is a physical pointer, forget it. + */ + if (csio->ccb_h.flags & CAM_SENSE_PTR) { + if (csio->ccb_h.flags & CAM_SENSE_PHYS) { +#ifdef _KERNEL + xpt_free_ccb((union ccb*)cgd); +#endif /* _KERNEL/!_KERNEL */ + return(-1); + } else { + /* + * bcopy the pointer to avoid unaligned access + * errors on finicky architectures. We don't + * ensure that the sense data is pointer aligned. + */ + bcopy(&csio->sense_data, &sense, + sizeof(struct scsi_sense_data *)); + } + } else { + /* + * If the physical sense flag is set, but the sense pointer + * is not also set, we assume that the user is an idiot and + * return. (Well, okay, it could be that somehow, the + * entire csio is physical, but we would have probably core + * dumped on one of the bogus pointer deferences above + * already.) + */ + if (csio->ccb_h.flags & CAM_SENSE_PHYS) { +#ifdef _KERNEL + xpt_free_ccb((union ccb*)cgd); +#endif /* _KERNEL/!_KERNEL */ + return(-1); + } else + sense = &csio->sense_data; + } + + + sbuf_cat(sb, path_str); + + error_code = sense->error_code & SSD_ERRCODE; + sense_key = sense->flags & SSD_KEY; + + sbuf_printf(sb, "SCSI sense: "); + switch (error_code) { + case SSD_DEFERRED_ERROR: + sbuf_printf(sb, "Deferred error: "); + + /* FALLTHROUGH */ + case SSD_CURRENT_ERROR: + { + const char *sense_key_desc; + const char *asc_desc; + + asc = (sense->extra_len >= 5) ? sense->add_sense_code : 0; + ascq = (sense->extra_len >= 6) ? sense->add_sense_code_qual : 0; + scsi_sense_desc(sense_key, asc, ascq, inq_data, + &sense_key_desc, &asc_desc); + sbuf_cat(sb, sense_key_desc); + + info = scsi_4btoul(sense->info); + + if (sense->error_code & SSD_ERRCODE_VALID) { + + switch (sense_key) { + case SSD_KEY_NOT_READY: + case SSD_KEY_ILLEGAL_REQUEST: + case SSD_KEY_UNIT_ATTENTION: + case SSD_KEY_DATA_PROTECT: + break; + case SSD_KEY_BLANK_CHECK: + sbuf_printf(sb, " req sz: %d (decimal)", info); + break; + default: + if (info) { + if (sense->flags & SSD_ILI) { + sbuf_printf(sb, " ILI (length " + "mismatch): %d", info); + + } else { + sbuf_printf(sb, " info:%x", + info); + } + } + } + } else if (info) { + sbuf_printf(sb, " info?:%x", info); + } + + if (sense->extra_len >= 4) { + if (bcmp(sense->cmd_spec_info, "\0\0\0\0", 4)) { + sbuf_printf(sb, " csi:%x,%x,%x,%x", + sense->cmd_spec_info[0], + sense->cmd_spec_info[1], + sense->cmd_spec_info[2], + sense->cmd_spec_info[3]); + } + } + + sbuf_printf(sb, " asc:%x,%x (%s)", asc, ascq, asc_desc); + + if (sense->extra_len >= 7 && sense->fru) { + sbuf_printf(sb, " field replaceable unit: %x", + sense->fru); + } + + if ((sense->extra_len >= 10) + && (sense->sense_key_spec[0] & SSD_SCS_VALID) != 0) { + switch(sense_key) { + case SSD_KEY_ILLEGAL_REQUEST: { + int bad_command; + char tmpstr2[40]; + + if (sense->sense_key_spec[0] & 0x40) + bad_command = 1; + else + bad_command = 0; + + tmpstr2[0] = '\0'; + + /* Bit pointer is valid */ + if (sense->sense_key_spec[0] & 0x08) + snprintf(tmpstr2, sizeof(tmpstr2), + "bit %d ", + sense->sense_key_spec[0] & 0x7); + sbuf_printf(sb, ": %s byte %d %sis invalid", + bad_command ? "Command" : "Data", + scsi_2btoul( + &sense->sense_key_spec[1]), + tmpstr2); + break; + } + case SSD_KEY_RECOVERED_ERROR: + case SSD_KEY_HARDWARE_ERROR: + case SSD_KEY_MEDIUM_ERROR: + sbuf_printf(sb, " actual retry count: %d", + scsi_2btoul( + &sense->sense_key_spec[1])); + break; + default: + sbuf_printf(sb, " sks:%#x,%#x", + sense->sense_key_spec[0], + scsi_2btoul( + &sense->sense_key_spec[1])); + break; + } + } + break; + + } + default: + sbuf_printf(sb, "Error code 0x%x", sense->error_code); + if (sense->error_code & SSD_ERRCODE_VALID) { + sbuf_printf(sb, " at block no. %d (decimal)", + info = scsi_4btoul(sense->info)); + } + } + + sbuf_printf(sb, "\n"); + +#ifdef _KERNEL + xpt_free_ccb((union ccb*)cgd); +#endif /* _KERNEL/!_KERNEL */ + return(0); +} + + + +#ifdef _KERNEL +char * +scsi_sense_string(struct ccb_scsiio *csio, char *str, int str_len) +#else /* !_KERNEL */ +char * +scsi_sense_string(struct cam_device *device, struct ccb_scsiio *csio, + char *str, int str_len) +#endif /* _KERNEL/!_KERNEL */ +{ + struct sbuf sb; + + sbuf_new(&sb, str, str_len, 0); + +#ifdef _KERNEL + scsi_sense_sbuf(csio, &sb, SSS_FLAG_PRINT_COMMAND); +#else /* !_KERNEL */ + scsi_sense_sbuf(device, csio, &sb, SSS_FLAG_PRINT_COMMAND); +#endif /* _KERNEL/!_KERNEL */ + + sbuf_finish(&sb); + + return(sbuf_data(&sb)); +} + +#ifdef _KERNEL +void +scsi_sense_print(struct ccb_scsiio *csio) +{ + struct sbuf sb; + char str[512]; + + sbuf_new(&sb, str, sizeof(str), 0); + + scsi_sense_sbuf(csio, &sb, SSS_FLAG_PRINT_COMMAND); + + sbuf_finish(&sb); + + printf("%s", sbuf_data(&sb)); +} + +#else /* !_KERNEL */ +void +scsi_sense_print(struct cam_device *device, struct ccb_scsiio *csio, + FILE *ofile) +{ + struct sbuf sb; + char str[512]; + + if ((device == NULL) || (csio == NULL) || (ofile == NULL)) + return; + + sbuf_new(&sb, str, sizeof(str), 0); + + scsi_sense_sbuf(device, csio, &sb, SSS_FLAG_PRINT_COMMAND); + + sbuf_finish(&sb); + + fprintf(ofile, "%s", sbuf_data(&sb)); +} + +#endif /* _KERNEL/!_KERNEL */ +#endif /* __rtems__ */ + +/* + * This function currently requires at least 36 bytes, or + * SHORT_INQUIRY_LENGTH, worth of data to function properly. If this + * function needs more or less data in the future, another length should be + * defined in scsi_all.h to indicate the minimum amount of data necessary + * for this routine to function properly. + */ +void +scsi_print_inquiry(struct scsi_inquiry_data *inq_data) +{ + u_int8_t type; + char *dtype, *qtype; + char vendor[16], product[48], revision[16], rstr[4]; + + type = SID_TYPE(inq_data); + + /* + * Figure out basic device type and qualifier. + */ + if (SID_QUAL_IS_VENDOR_UNIQUE(inq_data)) { + qtype = "(vendor-unique qualifier)"; + } else { + switch (SID_QUAL(inq_data)) { + case SID_QUAL_LU_CONNECTED: + qtype = ""; + break; + + case SID_QUAL_LU_OFFLINE: + qtype = "(offline)"; + break; + + case SID_QUAL_RSVD: + qtype = "(reserved qualifier)"; + break; + default: + case SID_QUAL_BAD_LU: + qtype = "(LUN not supported)"; + break; + } + } + + switch (type) { + case T_DIRECT: + dtype = "Direct Access"; + break; + case T_SEQUENTIAL: + dtype = "Sequential Access"; + break; + case T_PRINTER: + dtype = "Printer"; + break; + case T_PROCESSOR: + dtype = "Processor"; + break; + case T_WORM: + dtype = "WORM"; + break; + case T_CDROM: + dtype = "CD-ROM"; + break; + case T_SCANNER: + dtype = "Scanner"; + break; + case T_OPTICAL: + dtype = "Optical"; + break; + case T_CHANGER: + dtype = "Changer"; + break; + case T_COMM: + dtype = "Communication"; + break; + case T_STORARRAY: + dtype = "Storage Array"; + break; + case T_ENCLOSURE: + dtype = "Enclosure Services"; + break; + case T_RBC: + dtype = "Simplified Direct Access"; + break; + case T_OCRW: + dtype = "Optical Card Read/Write"; + break; + case T_OSD: + dtype = "Object-Based Storage"; + break; + case T_ADC: + dtype = "Automation/Drive Interface"; + break; + case T_NODEVICE: + dtype = "Uninstalled"; + break; + default: + dtype = "unknown"; + break; + } + + cam_strvis(vendor, inq_data->vendor, sizeof(inq_data->vendor), + sizeof(vendor)); + cam_strvis(product, inq_data->product, sizeof(inq_data->product), + sizeof(product)); + cam_strvis(revision, inq_data->revision, sizeof(inq_data->revision), + sizeof(revision)); + + if (SID_ANSI_REV(inq_data) == SCSI_REV_CCS) + bcopy("CCS", rstr, 4); + else + snprintf(rstr, sizeof (rstr), "%d", SID_ANSI_REV(inq_data)); + printf("<%s %s %s> %s %s SCSI-%s device %s\n", + vendor, product, revision, + SID_IS_REMOVABLE(inq_data) ? "Removable" : "Fixed", + dtype, rstr, qtype); +} + +#ifndef __rtems__ +/* + * Table of syncrates that don't follow the "divisible by 4" + * rule. This table will be expanded in future SCSI specs. + */ +static struct { + u_int period_factor; + u_int period; /* in 100ths of ns */ +} scsi_syncrates[] = { + { 0x08, 625 }, /* FAST-160 */ + { 0x09, 1250 }, /* FAST-80 */ + { 0x0a, 2500 }, /* FAST-40 40MHz */ + { 0x0b, 3030 }, /* FAST-40 33MHz */ + { 0x0c, 5000 } /* FAST-20 */ +}; + +/* + * Return the frequency in kHz corresponding to the given + * sync period factor. + */ +u_int +scsi_calc_syncsrate(u_int period_factor) +{ + int i; + int num_syncrates; + + /* + * It's a bug if period is zero, but if it is anyway, don't + * die with a divide fault- instead return something which + * 'approximates' async + */ + if (period_factor == 0) { + return (3300); + } + + num_syncrates = sizeof(scsi_syncrates) / sizeof(scsi_syncrates[0]); + /* See if the period is in the "exception" table */ + for (i = 0; i < num_syncrates; i++) { + + if (period_factor == scsi_syncrates[i].period_factor) { + /* Period in kHz */ + return (100000000 / scsi_syncrates[i].period); + } + } + + /* + * Wasn't in the table, so use the standard + * 4 times conversion. + */ + return (10000000 / (period_factor * 4 * 10)); +} + +/* + * Return the SCSI sync parameter that corresponsd to + * the passed in period in 10ths of ns. + */ +u_int +scsi_calc_syncparam(u_int period) +{ + int i; + int num_syncrates; + + if (period == 0) + return (~0); /* Async */ + + /* Adjust for exception table being in 100ths. */ + period *= 10; + num_syncrates = sizeof(scsi_syncrates) / sizeof(scsi_syncrates[0]); + /* See if the period is in the "exception" table */ + for (i = 0; i < num_syncrates; i++) { + + if (period <= scsi_syncrates[i].period) { + /* Period in 100ths of ns */ + return (scsi_syncrates[i].period_factor); + } + } + + /* + * Wasn't in the table, so use the standard + * 1/4 period in ns conversion. + */ + return (period/400); +} +#endif /* __rtems__ */ + +void +scsi_test_unit_ready(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb *), + u_int8_t tag_action, u_int8_t sense_len, u_int32_t timeout) +{ + struct scsi_test_unit_ready *scsi_cmd; + + cam_fill_csio(csio, + retries, + cbfcnp, + CAM_DIR_NONE, + tag_action, + /*data_ptr*/NULL, + /*dxfer_len*/0, + sense_len, + sizeof(*scsi_cmd), + timeout); + + scsi_cmd = (struct scsi_test_unit_ready *)&csio->cdb_io.cdb_bytes; + bzero(scsi_cmd, sizeof(*scsi_cmd)); + scsi_cmd->opcode = TEST_UNIT_READY; +} + +#ifndef __rtems__ +void +scsi_request_sense(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb *), + void *data_ptr, u_int8_t dxfer_len, u_int8_t tag_action, + u_int8_t sense_len, u_int32_t timeout) +{ + struct scsi_request_sense *scsi_cmd; + + cam_fill_csio(csio, + retries, + cbfcnp, + CAM_DIR_IN, + tag_action, + data_ptr, + dxfer_len, + sense_len, + sizeof(*scsi_cmd), + timeout); + + scsi_cmd = (struct scsi_request_sense *)&csio->cdb_io.cdb_bytes; + bzero(scsi_cmd, sizeof(*scsi_cmd)); + scsi_cmd->opcode = REQUEST_SENSE; + scsi_cmd->length = dxfer_len; +} +#endif /* __rtems__ */ + +void +scsi_inquiry(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb *), + u_int8_t tag_action, u_int8_t *inq_buf, u_int32_t inq_len, + int evpd, u_int8_t page_code, u_int8_t sense_len, + u_int32_t timeout) +{ + struct scsi_inquiry *scsi_cmd; + + cam_fill_csio(csio, + retries, + cbfcnp, + /*flags*/CAM_DIR_IN, + tag_action, + /*data_ptr*/inq_buf, + /*dxfer_len*/inq_len, + sense_len, + sizeof(*scsi_cmd), + timeout); + + scsi_cmd = (struct scsi_inquiry *)&csio->cdb_io.cdb_bytes; + bzero(scsi_cmd, sizeof(*scsi_cmd)); + scsi_cmd->opcode = INQUIRY; + if (evpd) { + scsi_cmd->byte2 |= SI_EVPD; + scsi_cmd->page_code = page_code; + } + /* + * A 'transfer units' count of 256 is coded as + * zero for all commands with a single byte count + * field. + */ + if (inq_len == 256) + inq_len = 0; + scsi_cmd->length = inq_len; +} + +#ifndef __rtems__ +void +scsi_mode_sense(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb *), + u_int8_t tag_action, int dbd, u_int8_t page_code, + u_int8_t page, u_int8_t *param_buf, u_int32_t param_len, + u_int8_t sense_len, u_int32_t timeout) +{ + + scsi_mode_sense_len(csio, retries, cbfcnp, tag_action, dbd, + page_code, page, param_buf, param_len, 0, + sense_len, timeout); +} + +void +scsi_mode_sense_len(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb *), + u_int8_t tag_action, int dbd, u_int8_t page_code, + u_int8_t page, u_int8_t *param_buf, u_int32_t param_len, + int minimum_cmd_size, u_int8_t sense_len, u_int32_t timeout) +{ + u_int8_t cdb_len; + + /* + * Use the smallest possible command to perform the operation. + */ + if ((param_len < 256) + && (minimum_cmd_size < 10)) { + /* + * We can fit in a 6 byte cdb. + */ + struct scsi_mode_sense_6 *scsi_cmd; + + scsi_cmd = (struct scsi_mode_sense_6 *)&csio->cdb_io.cdb_bytes; + bzero(scsi_cmd, sizeof(*scsi_cmd)); + scsi_cmd->opcode = MODE_SENSE_6; + if (dbd != 0) + scsi_cmd->byte2 |= SMS_DBD; + scsi_cmd->page = page_code | page; + scsi_cmd->length = param_len; + cdb_len = sizeof(*scsi_cmd); + } else { + /* + * Need a 10 byte cdb. + */ + struct scsi_mode_sense_10 *scsi_cmd; + + scsi_cmd = (struct scsi_mode_sense_10 *)&csio->cdb_io.cdb_bytes; + bzero(scsi_cmd, sizeof(*scsi_cmd)); + scsi_cmd->opcode = MODE_SENSE_10; + if (dbd != 0) + scsi_cmd->byte2 |= SMS_DBD; + scsi_cmd->page = page_code | page; + scsi_ulto2b(param_len, scsi_cmd->length); + cdb_len = sizeof(*scsi_cmd); + } + cam_fill_csio(csio, + retries, + cbfcnp, + CAM_DIR_IN, + tag_action, + param_buf, + param_len, + sense_len, + cdb_len, + timeout); +} + +void +scsi_mode_select(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb *), + u_int8_t tag_action, int scsi_page_fmt, int save_pages, + u_int8_t *param_buf, u_int32_t param_len, u_int8_t sense_len, + u_int32_t timeout) +{ + scsi_mode_select_len(csio, retries, cbfcnp, tag_action, + scsi_page_fmt, save_pages, param_buf, + param_len, 0, sense_len, timeout); +} + +void +scsi_mode_select_len(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb *), + u_int8_t tag_action, int scsi_page_fmt, int save_pages, + u_int8_t *param_buf, u_int32_t param_len, + int minimum_cmd_size, u_int8_t sense_len, + u_int32_t timeout) +{ + u_int8_t cdb_len; + + /* + * Use the smallest possible command to perform the operation. + */ + if ((param_len < 256) + && (minimum_cmd_size < 10)) { + /* + * We can fit in a 6 byte cdb. + */ + struct scsi_mode_select_6 *scsi_cmd; + + scsi_cmd = (struct scsi_mode_select_6 *)&csio->cdb_io.cdb_bytes; + bzero(scsi_cmd, sizeof(*scsi_cmd)); + scsi_cmd->opcode = MODE_SELECT_6; + if (scsi_page_fmt != 0) + scsi_cmd->byte2 |= SMS_PF; + if (save_pages != 0) + scsi_cmd->byte2 |= SMS_SP; + scsi_cmd->length = param_len; + cdb_len = sizeof(*scsi_cmd); + } else { + /* + * Need a 10 byte cdb. + */ + struct scsi_mode_select_10 *scsi_cmd; + + scsi_cmd = + (struct scsi_mode_select_10 *)&csio->cdb_io.cdb_bytes; + bzero(scsi_cmd, sizeof(*scsi_cmd)); + scsi_cmd->opcode = MODE_SELECT_10; + if (scsi_page_fmt != 0) + scsi_cmd->byte2 |= SMS_PF; + if (save_pages != 0) + scsi_cmd->byte2 |= SMS_SP; + scsi_ulto2b(param_len, scsi_cmd->length); + cdb_len = sizeof(*scsi_cmd); + } + cam_fill_csio(csio, + retries, + cbfcnp, + CAM_DIR_OUT, + tag_action, + param_buf, + param_len, + sense_len, + cdb_len, + timeout); +} + +void +scsi_log_sense(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb *), + u_int8_t tag_action, u_int8_t page_code, u_int8_t page, + int save_pages, int ppc, u_int32_t paramptr, + u_int8_t *param_buf, u_int32_t param_len, u_int8_t sense_len, + u_int32_t timeout) +{ + struct scsi_log_sense *scsi_cmd; + u_int8_t cdb_len; + + scsi_cmd = (struct scsi_log_sense *)&csio->cdb_io.cdb_bytes; + bzero(scsi_cmd, sizeof(*scsi_cmd)); + scsi_cmd->opcode = LOG_SENSE; + scsi_cmd->page = page_code | page; + if (save_pages != 0) + scsi_cmd->byte2 |= SLS_SP; + if (ppc != 0) + scsi_cmd->byte2 |= SLS_PPC; + scsi_ulto2b(paramptr, scsi_cmd->paramptr); + scsi_ulto2b(param_len, scsi_cmd->length); + cdb_len = sizeof(*scsi_cmd); + + cam_fill_csio(csio, + retries, + cbfcnp, + /*flags*/CAM_DIR_IN, + tag_action, + /*data_ptr*/param_buf, + /*dxfer_len*/param_len, + sense_len, + cdb_len, + timeout); +} + +void +scsi_log_select(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb *), + u_int8_t tag_action, u_int8_t page_code, int save_pages, + int pc_reset, u_int8_t *param_buf, u_int32_t param_len, + u_int8_t sense_len, u_int32_t timeout) +{ + struct scsi_log_select *scsi_cmd; + u_int8_t cdb_len; + + scsi_cmd = (struct scsi_log_select *)&csio->cdb_io.cdb_bytes; + bzero(scsi_cmd, sizeof(*scsi_cmd)); + scsi_cmd->opcode = LOG_SELECT; + scsi_cmd->page = page_code & SLS_PAGE_CODE; + if (save_pages != 0) + scsi_cmd->byte2 |= SLS_SP; + if (pc_reset != 0) + scsi_cmd->byte2 |= SLS_PCR; + scsi_ulto2b(param_len, scsi_cmd->length); + cdb_len = sizeof(*scsi_cmd); + + cam_fill_csio(csio, + retries, + cbfcnp, + /*flags*/CAM_DIR_OUT, + tag_action, + /*data_ptr*/param_buf, + /*dxfer_len*/param_len, + sense_len, + cdb_len, + timeout); +} + +/* + * Prevent or allow the user to remove the media + */ +void +scsi_prevent(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb *), + u_int8_t tag_action, u_int8_t action, + u_int8_t sense_len, u_int32_t timeout) +{ + struct scsi_prevent *scsi_cmd; + + cam_fill_csio(csio, + retries, + cbfcnp, + /*flags*/CAM_DIR_NONE, + tag_action, + /*data_ptr*/NULL, + /*dxfer_len*/0, + sense_len, + sizeof(*scsi_cmd), + timeout); + + scsi_cmd = (struct scsi_prevent *)&csio->cdb_io.cdb_bytes; + bzero(scsi_cmd, sizeof(*scsi_cmd)); + scsi_cmd->opcode = PREVENT_ALLOW; + scsi_cmd->how = action; +} +#endif /* __rtems__ */ + +/* XXX allow specification of address and PMI bit and LBA */ +void +scsi_read_capacity(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb *), + u_int8_t tag_action, + struct scsi_read_capacity_data *rcap_buf, + u_int8_t sense_len, u_int32_t timeout) +{ + struct scsi_read_capacity *scsi_cmd; + + cam_fill_csio(csio, + retries, + cbfcnp, + /*flags*/CAM_DIR_IN, + tag_action, + /*data_ptr*/(u_int8_t *)rcap_buf, + /*dxfer_len*/sizeof(*rcap_buf), + sense_len, + sizeof(*scsi_cmd), + timeout); + + scsi_cmd = (struct scsi_read_capacity *)&csio->cdb_io.cdb_bytes; + bzero(scsi_cmd, sizeof(*scsi_cmd)); + scsi_cmd->opcode = READ_CAPACITY; +} + +#ifndef __rtems__ +void +scsi_read_capacity_16(struct ccb_scsiio *csio, uint32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb *), + uint8_t tag_action, uint64_t lba, int reladr, int pmi, + struct scsi_read_capacity_data_long *rcap_buf, + uint8_t sense_len, uint32_t timeout) +{ + struct scsi_read_capacity_16 *scsi_cmd; + + + cam_fill_csio(csio, + retries, + cbfcnp, + /*flags*/CAM_DIR_IN, + tag_action, + /*data_ptr*/(u_int8_t *)rcap_buf, + /*dxfer_len*/sizeof(*rcap_buf), + sense_len, + sizeof(*scsi_cmd), + timeout); + scsi_cmd = (struct scsi_read_capacity_16 *)&csio->cdb_io.cdb_bytes; + bzero(scsi_cmd, sizeof(*scsi_cmd)); + scsi_cmd->opcode = SERVICE_ACTION_IN; + scsi_cmd->service_action = SRC16_SERVICE_ACTION; + scsi_u64to8b(lba, scsi_cmd->addr); + scsi_ulto4b(sizeof(*rcap_buf), scsi_cmd->alloc_len); + if (pmi) + reladr |= SRC16_PMI; + if (reladr) + reladr |= SRC16_RELADR; +} + +void +scsi_report_luns(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb *), + u_int8_t tag_action, u_int8_t select_report, + struct scsi_report_luns_data *rpl_buf, u_int32_t alloc_len, + u_int8_t sense_len, u_int32_t timeout) +{ + struct scsi_report_luns *scsi_cmd; + + cam_fill_csio(csio, + retries, + cbfcnp, + /*flags*/CAM_DIR_IN, + tag_action, + /*data_ptr*/(u_int8_t *)rpl_buf, + /*dxfer_len*/alloc_len, + sense_len, + sizeof(*scsi_cmd), + timeout); + scsi_cmd = (struct scsi_report_luns *)&csio->cdb_io.cdb_bytes; + bzero(scsi_cmd, sizeof(*scsi_cmd)); + scsi_cmd->opcode = REPORT_LUNS; + scsi_cmd->select_report = select_report; + scsi_ulto4b(alloc_len, scsi_cmd->length); +} + +void +scsi_report_target_group(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb *), + u_int8_t tag_action, u_int8_t pdf, + void *buf, u_int32_t alloc_len, + u_int8_t sense_len, u_int32_t timeout) +{ + struct scsi_target_group *scsi_cmd; + + cam_fill_csio(csio, + retries, + cbfcnp, + /*flags*/CAM_DIR_IN, + tag_action, + /*data_ptr*/(u_int8_t *)buf, + /*dxfer_len*/alloc_len, + sense_len, + sizeof(*scsi_cmd), + timeout); + scsi_cmd = (struct scsi_target_group *)&csio->cdb_io.cdb_bytes; + bzero(scsi_cmd, sizeof(*scsi_cmd)); + scsi_cmd->opcode = MAINTENANCE_IN; + scsi_cmd->service_action = REPORT_TARGET_PORT_GROUPS | pdf; + scsi_ulto4b(alloc_len, scsi_cmd->length); +} + +void +scsi_set_target_group(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb *), + u_int8_t tag_action, void *buf, u_int32_t alloc_len, + u_int8_t sense_len, u_int32_t timeout) +{ + struct scsi_target_group *scsi_cmd; + + cam_fill_csio(csio, + retries, + cbfcnp, + /*flags*/CAM_DIR_OUT, + tag_action, + /*data_ptr*/(u_int8_t *)buf, + /*dxfer_len*/alloc_len, + sense_len, + sizeof(*scsi_cmd), + timeout); + scsi_cmd = (struct scsi_target_group *)&csio->cdb_io.cdb_bytes; + bzero(scsi_cmd, sizeof(*scsi_cmd)); + scsi_cmd->opcode = MAINTENANCE_OUT; + scsi_cmd->service_action = SET_TARGET_PORT_GROUPS; + scsi_ulto4b(alloc_len, scsi_cmd->length); +} + +/* + * Syncronize the media to the contents of the cache for + * the given lba/count pair. Specifying 0/0 means sync + * the whole cache. + */ +void +scsi_synchronize_cache(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb *), + u_int8_t tag_action, u_int32_t begin_lba, + u_int16_t lb_count, u_int8_t sense_len, + u_int32_t timeout) +{ + struct scsi_sync_cache *scsi_cmd; + + cam_fill_csio(csio, + retries, + cbfcnp, + /*flags*/CAM_DIR_NONE, + tag_action, + /*data_ptr*/NULL, + /*dxfer_len*/0, + sense_len, + sizeof(*scsi_cmd), + timeout); + + scsi_cmd = (struct scsi_sync_cache *)&csio->cdb_io.cdb_bytes; + bzero(scsi_cmd, sizeof(*scsi_cmd)); + scsi_cmd->opcode = SYNCHRONIZE_CACHE; + scsi_ulto4b(begin_lba, scsi_cmd->begin_lba); + scsi_ulto2b(lb_count, scsi_cmd->lb_count); +} +#endif /* __rtems__ */ + +void +scsi_read_write(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb *), + u_int8_t tag_action, int readop, u_int8_t byte2, + int minimum_cmd_size, u_int64_t lba, u_int32_t block_count, + u_int8_t *data_ptr, u_int32_t dxfer_len, u_int8_t sense_len, + u_int32_t timeout) +{ + u_int8_t cdb_len; + /* + * Use the smallest possible command to perform the operation + * as some legacy hardware does not support the 10 byte commands. + * If any of the bits in byte2 is set, we have to go with a larger + * command. + */ + if ((minimum_cmd_size < 10) + && ((lba & 0x1fffff) == lba) + && ((block_count & 0xff) == block_count) + && (byte2 == 0)) { + /* + * We can fit in a 6 byte cdb. + */ + struct scsi_rw_6 *scsi_cmd; + + scsi_cmd = (struct scsi_rw_6 *)&csio->cdb_io.cdb_bytes; + scsi_cmd->opcode = readop ? READ_6 : WRITE_6; + scsi_ulto3b(lba, scsi_cmd->addr); + scsi_cmd->length = block_count & 0xff; + scsi_cmd->control = 0; + cdb_len = sizeof(*scsi_cmd); + + CAM_DEBUG(csio->ccb_h.path, CAM_DEBUG_SUBTRACE, + ("6byte: %x%x%x:%d:%d\n", scsi_cmd->addr[0], + scsi_cmd->addr[1], scsi_cmd->addr[2], + scsi_cmd->length, dxfer_len)); + } else if ((minimum_cmd_size < 12) + && ((block_count & 0xffff) == block_count) + && ((lba & 0xffffffff) == lba)) { + /* + * Need a 10 byte cdb. + */ + struct scsi_rw_10 *scsi_cmd; + + scsi_cmd = (struct scsi_rw_10 *)&csio->cdb_io.cdb_bytes; + scsi_cmd->opcode = readop ? READ_10 : WRITE_10; + scsi_cmd->byte2 = byte2; + scsi_ulto4b(lba, scsi_cmd->addr); + scsi_cmd->reserved = 0; + scsi_ulto2b(block_count, scsi_cmd->length); + scsi_cmd->control = 0; + cdb_len = sizeof(*scsi_cmd); + + CAM_DEBUG(csio->ccb_h.path, CAM_DEBUG_SUBTRACE, + ("10byte: %x%x%x%x:%x%x: %d\n", scsi_cmd->addr[0], + scsi_cmd->addr[1], scsi_cmd->addr[2], + scsi_cmd->addr[3], scsi_cmd->length[0], + scsi_cmd->length[1], dxfer_len)); + } else if ((minimum_cmd_size < 16) + && ((block_count & 0xffffffff) == block_count) + && ((lba & 0xffffffff) == lba)) { + /* + * The block count is too big for a 10 byte CDB, use a 12 + * byte CDB. + */ + struct scsi_rw_12 *scsi_cmd; + + scsi_cmd = (struct scsi_rw_12 *)&csio->cdb_io.cdb_bytes; + scsi_cmd->opcode = readop ? READ_12 : WRITE_12; + scsi_cmd->byte2 = byte2; + scsi_ulto4b(lba, scsi_cmd->addr); + scsi_cmd->reserved = 0; + scsi_ulto4b(block_count, scsi_cmd->length); + scsi_cmd->control = 0; + cdb_len = sizeof(*scsi_cmd); + + CAM_DEBUG(csio->ccb_h.path, CAM_DEBUG_SUBTRACE, + ("12byte: %x%x%x%x:%x%x%x%x: %d\n", scsi_cmd->addr[0], + scsi_cmd->addr[1], scsi_cmd->addr[2], + scsi_cmd->addr[3], scsi_cmd->length[0], + scsi_cmd->length[1], scsi_cmd->length[2], + scsi_cmd->length[3], dxfer_len)); + } else { + /* + * 16 byte CDB. We'll only get here if the LBA is larger + * than 2^32, or if the user asks for a 16 byte command. + */ + struct scsi_rw_16 *scsi_cmd; + + scsi_cmd = (struct scsi_rw_16 *)&csio->cdb_io.cdb_bytes; + scsi_cmd->opcode = readop ? READ_16 : WRITE_16; + scsi_cmd->byte2 = byte2; + scsi_u64to8b(lba, scsi_cmd->addr); + scsi_cmd->reserved = 0; + scsi_ulto4b(block_count, scsi_cmd->length); + scsi_cmd->control = 0; + cdb_len = sizeof(*scsi_cmd); + } + cam_fill_csio(csio, + retries, + cbfcnp, + /*flags*/readop ? CAM_DIR_IN : CAM_DIR_OUT, + tag_action, + data_ptr, + dxfer_len, + sense_len, + cdb_len, + timeout); +} + +#ifndef __rtems__ +void +scsi_start_stop(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb *), + u_int8_t tag_action, int start, int load_eject, + int immediate, u_int8_t sense_len, u_int32_t timeout) +{ + struct scsi_start_stop_unit *scsi_cmd; + int extra_flags = 0; + + scsi_cmd = (struct scsi_start_stop_unit *)&csio->cdb_io.cdb_bytes; + bzero(scsi_cmd, sizeof(*scsi_cmd)); + scsi_cmd->opcode = START_STOP_UNIT; + if (start != 0) { + scsi_cmd->how |= SSS_START; + /* it takes a lot of power to start a drive */ + extra_flags |= CAM_HIGH_POWER; + } + if (load_eject != 0) + scsi_cmd->how |= SSS_LOEJ; + if (immediate != 0) + scsi_cmd->byte2 |= SSS_IMMED; + + cam_fill_csio(csio, + retries, + cbfcnp, + /*flags*/CAM_DIR_NONE | extra_flags, + tag_action, + /*data_ptr*/NULL, + /*dxfer_len*/0, + sense_len, + sizeof(*scsi_cmd), + timeout); + +} + + +/* + * Try make as good a match as possible with + * available sub drivers + */ +int +scsi_inquiry_match(caddr_t inqbuffer, caddr_t table_entry) +{ + struct scsi_inquiry_pattern *entry; + struct scsi_inquiry_data *inq; + + entry = (struct scsi_inquiry_pattern *)table_entry; + inq = (struct scsi_inquiry_data *)inqbuffer; + + if (((SID_TYPE(inq) == entry->type) + || (entry->type == T_ANY)) + && (SID_IS_REMOVABLE(inq) ? entry->media_type & SIP_MEDIA_REMOVABLE + : entry->media_type & SIP_MEDIA_FIXED) + && (cam_strmatch(inq->vendor, entry->vendor, sizeof(inq->vendor)) == 0) + && (cam_strmatch(inq->product, entry->product, + sizeof(inq->product)) == 0) + && (cam_strmatch(inq->revision, entry->revision, + sizeof(inq->revision)) == 0)) { + return (0); + } + return (-1); +} + +/* + * Try make as good a match as possible with + * available sub drivers + */ +int +scsi_static_inquiry_match(caddr_t inqbuffer, caddr_t table_entry) +{ + struct scsi_static_inquiry_pattern *entry; + struct scsi_inquiry_data *inq; + + entry = (struct scsi_static_inquiry_pattern *)table_entry; + inq = (struct scsi_inquiry_data *)inqbuffer; + + if (((SID_TYPE(inq) == entry->type) + || (entry->type == T_ANY)) + && (SID_IS_REMOVABLE(inq) ? entry->media_type & SIP_MEDIA_REMOVABLE + : entry->media_type & SIP_MEDIA_FIXED) + && (cam_strmatch(inq->vendor, entry->vendor, sizeof(inq->vendor)) == 0) + && (cam_strmatch(inq->product, entry->product, + sizeof(inq->product)) == 0) + && (cam_strmatch(inq->revision, entry->revision, + sizeof(inq->revision)) == 0)) { + return (0); + } + return (-1); +} + +#ifdef _KERNEL +static void +init_scsi_delay(void) +{ + int delay; + + delay = SCSI_DELAY; + TUNABLE_INT_FETCH("kern.cam.scsi_delay", &delay); + + if (set_scsi_delay(delay) != 0) { + printf("cam: invalid value for tunable kern.cam.scsi_delay\n"); + set_scsi_delay(SCSI_DELAY); + } +} +SYSINIT(scsi_delay, SI_SUB_TUNABLES, SI_ORDER_ANY, init_scsi_delay, NULL); + +static int +sysctl_scsi_delay(SYSCTL_HANDLER_ARGS) +{ + int error, delay; + + delay = scsi_delay; + error = sysctl_handle_int(oidp, &delay, 0, req); + if (error != 0 || req->newptr == NULL) + return (error); + return (set_scsi_delay(delay)); +} +SYSCTL_PROC(_kern_cam, OID_AUTO, scsi_delay, CTLTYPE_INT|CTLFLAG_RW, + 0, 0, sysctl_scsi_delay, "I", + "Delay to allow devices to settle after a SCSI bus reset (ms)"); + +static int +set_scsi_delay(int delay) +{ + /* + * If someone sets this to 0, we assume that they want the + * minimum allowable bus settle delay. + */ + if (delay == 0) { + printf("cam: using minimum scsi_delay (%dms)\n", + SCSI_MIN_DELAY); + delay = SCSI_MIN_DELAY; + } + if (delay < SCSI_MIN_DELAY) + return (EINVAL); + scsi_delay = delay; + return (0); +} +#endif /* _KERNEL */ +#endif /* __rtems__ */ diff --git a/freebsd/sys/cam/scsi/scsi_all.h b/freebsd/sys/cam/scsi/scsi_all.h new file mode 100644 index 00000000..47908b82 --- /dev/null +++ b/freebsd/sys/cam/scsi/scsi_all.h @@ -0,0 +1,1454 @@ +/*- + * Largely written by Julian Elischer (julian@tfs.com) + * for TRW Financial Systems. + * + * TRW Financial Systems, in accordance with their agreement with Carnegie + * Mellon University, makes this software available to CMU to distribute + * or use in any manner that they see fit as long as this message is kept with + * the software. For this reason TFS also grants any other persons or + * organisations permission to use or modify this software. + * + * TFS supplies this software to be publicly redistributed + * on the understanding that TFS is not responsible for the correct + * functioning of this software in any circumstances. + * + * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 + * + * $FreeBSD$ + */ + +/* + * SCSI general interface description + */ + +#ifndef _SCSI_SCSI_ALL_H +#define _SCSI_SCSI_ALL_H 1 + +#include <freebsd/sys/cdefs.h> + +#ifdef _KERNEL +/* + * This is the number of seconds we wait for devices to settle after a SCSI + * bus reset. + */ +extern int scsi_delay; +#endif /* _KERNEL */ + +/* + * SCSI command format + */ + +/* + * Define dome bits that are in ALL (or a lot of) scsi commands + */ +#define SCSI_CTL_LINK 0x01 +#define SCSI_CTL_FLAG 0x02 +#define SCSI_CTL_VENDOR 0xC0 +#define SCSI_CMD_LUN 0xA0 /* these two should not be needed */ +#define SCSI_CMD_LUN_SHIFT 5 /* LUN in the cmd is no longer SCSI */ + +#define SCSI_MAX_CDBLEN 16 /* + * 16 byte commands are in the + * SCSI-3 spec + */ +#if defined(CAM_MAX_CDBLEN) && (CAM_MAX_CDBLEN < SCSI_MAX_CDBLEN) +#error "CAM_MAX_CDBLEN cannot be less than SCSI_MAX_CDBLEN" +#endif + +/* 6byte CDBs special case 0 length to be 256 */ +#define SCSI_CDB6_LEN(len) ((len) == 0 ? 256 : len) + +/* + * This type defines actions to be taken when a particular sense code is + * received. Right now, these flags are only defined to take up 16 bits, + * but can be expanded in the future if necessary. + */ +typedef enum { + SS_NOP = 0x000000, /* Do nothing */ + SS_RETRY = 0x010000, /* Retry the command */ + SS_FAIL = 0x020000, /* Bail out */ + SS_START = 0x030000, /* Send a Start Unit command to the device, + * then retry the original command. + */ + SS_TUR = 0x040000, /* Send a Test Unit Ready command to the + * device, then retry the original command. + */ + SS_REQSENSE = 0x050000, /* Send a RequestSense command to the + * device, then retry the original command. + */ + SS_MASK = 0xff0000 +} scsi_sense_action; + +typedef enum { + SSQ_NONE = 0x0000, + SSQ_DECREMENT_COUNT = 0x0100, /* Decrement the retry count */ + SSQ_MANY = 0x0200, /* send lots of recovery commands */ + SSQ_RANGE = 0x0400, /* + * This table entry represents the + * end of a range of ASCQs that + * have identical error actions + * and text. + */ + SSQ_PRINT_SENSE = 0x0800, + SSQ_MASK = 0xff00 +} scsi_sense_action_qualifier; + +/* Mask for error status values */ +#define SS_ERRMASK 0xff + +/* The default, retyable, error action */ +#define SS_RDEF SS_RETRY|SSQ_DECREMENT_COUNT|SSQ_PRINT_SENSE|EIO + +/* The retyable, error action, with table specified error code */ +#define SS_RET SS_RETRY|SSQ_DECREMENT_COUNT|SSQ_PRINT_SENSE + +/* Fatal error action, with table specified error code */ +#define SS_FATAL SS_FAIL|SSQ_PRINT_SENSE + +struct scsi_generic +{ + u_int8_t opcode; + u_int8_t bytes[11]; +}; + +struct scsi_request_sense +{ + u_int8_t opcode; + u_int8_t byte2; + u_int8_t unused[2]; + u_int8_t length; + u_int8_t control; +}; + +struct scsi_test_unit_ready +{ + u_int8_t opcode; + u_int8_t byte2; + u_int8_t unused[3]; + u_int8_t control; +}; + +struct scsi_send_diag +{ + u_int8_t opcode; + u_int8_t byte2; +#define SSD_UOL 0x01 +#define SSD_DOL 0x02 +#define SSD_SELFTEST 0x04 +#define SSD_PF 0x10 + u_int8_t unused[1]; + u_int8_t paramlen[2]; + u_int8_t control; +}; + +struct scsi_sense +{ + u_int8_t opcode; + u_int8_t byte2; + u_int8_t unused[2]; + u_int8_t length; + u_int8_t control; +}; + +struct scsi_inquiry +{ + u_int8_t opcode; + u_int8_t byte2; +#define SI_EVPD 0x01 + u_int8_t page_code; + u_int8_t reserved; + u_int8_t length; + u_int8_t control; +}; + +struct scsi_mode_sense_6 +{ + u_int8_t opcode; + u_int8_t byte2; +#define SMS_DBD 0x08 + u_int8_t page; +#define SMS_PAGE_CODE 0x3F +#define SMS_VENDOR_SPECIFIC_PAGE 0x00 +#define SMS_DISCONNECT_RECONNECT_PAGE 0x02 +#define SMS_FORMAT_DEVICE_PAGE 0x03 +#define SMS_GEOMETRY_PAGE 0x04 +#define SMS_CACHE_PAGE 0x08 +#define SMS_PERIPHERAL_DEVICE_PAGE 0x09 +#define SMS_CONTROL_MODE_PAGE 0x0A +#define SMS_PROTO_SPECIFIC_PAGE 0x19 +#define SMS_INFO_EXCEPTIONS_PAGE 0x1C +#define SMS_ALL_PAGES_PAGE 0x3F +#define SMS_PAGE_CTRL_MASK 0xC0 +#define SMS_PAGE_CTRL_CURRENT 0x00 +#define SMS_PAGE_CTRL_CHANGEABLE 0x40 +#define SMS_PAGE_CTRL_DEFAULT 0x80 +#define SMS_PAGE_CTRL_SAVED 0xC0 + u_int8_t unused; + u_int8_t length; + u_int8_t control; +}; + +struct scsi_mode_sense_10 +{ + u_int8_t opcode; + u_int8_t byte2; /* same bits as small version */ + u_int8_t page; /* same bits as small version */ + u_int8_t unused[4]; + u_int8_t length[2]; + u_int8_t control; +}; + +struct scsi_mode_select_6 +{ + u_int8_t opcode; + u_int8_t byte2; +#define SMS_SP 0x01 +#define SMS_PF 0x10 + u_int8_t unused[2]; + u_int8_t length; + u_int8_t control; +}; + +struct scsi_mode_select_10 +{ + u_int8_t opcode; + u_int8_t byte2; /* same bits as small version */ + u_int8_t unused[5]; + u_int8_t length[2]; + u_int8_t control; +}; + +/* + * When sending a mode select to a tape drive, the medium type must be 0. + */ +struct scsi_mode_hdr_6 +{ + u_int8_t datalen; + u_int8_t medium_type; + u_int8_t dev_specific; + u_int8_t block_descr_len; +}; + +struct scsi_mode_hdr_10 +{ + u_int8_t datalen[2]; + u_int8_t medium_type; + u_int8_t dev_specific; + u_int8_t reserved[2]; + u_int8_t block_descr_len[2]; +}; + +struct scsi_mode_block_descr +{ + u_int8_t density_code; + u_int8_t num_blocks[3]; + u_int8_t reserved; + u_int8_t block_len[3]; +}; + +struct scsi_log_sense +{ + u_int8_t opcode; + u_int8_t byte2; +#define SLS_SP 0x01 +#define SLS_PPC 0x02 + u_int8_t page; +#define SLS_PAGE_CODE 0x3F +#define SLS_ALL_PAGES_PAGE 0x00 +#define SLS_OVERRUN_PAGE 0x01 +#define SLS_ERROR_WRITE_PAGE 0x02 +#define SLS_ERROR_READ_PAGE 0x03 +#define SLS_ERROR_READREVERSE_PAGE 0x04 +#define SLS_ERROR_VERIFY_PAGE 0x05 +#define SLS_ERROR_NONMEDIUM_PAGE 0x06 +#define SLS_ERROR_LASTN_PAGE 0x07 +#define SLS_SELF_TEST_PAGE 0x10 +#define SLS_IE_PAGE 0x2f +#define SLS_PAGE_CTRL_MASK 0xC0 +#define SLS_PAGE_CTRL_THRESHOLD 0x00 +#define SLS_PAGE_CTRL_CUMULATIVE 0x40 +#define SLS_PAGE_CTRL_THRESH_DEFAULT 0x80 +#define SLS_PAGE_CTRL_CUMUL_DEFAULT 0xC0 + u_int8_t reserved[2]; + u_int8_t paramptr[2]; + u_int8_t length[2]; + u_int8_t control; +}; + +struct scsi_log_select +{ + u_int8_t opcode; + u_int8_t byte2; +/* SLS_SP 0x01 */ +#define SLS_PCR 0x02 + u_int8_t page; +/* SLS_PAGE_CTRL_MASK 0xC0 */ +/* SLS_PAGE_CTRL_THRESHOLD 0x00 */ +/* SLS_PAGE_CTRL_CUMULATIVE 0x40 */ +/* SLS_PAGE_CTRL_THRESH_DEFAULT 0x80 */ +/* SLS_PAGE_CTRL_CUMUL_DEFAULT 0xC0 */ + u_int8_t reserved[4]; + u_int8_t length[2]; + u_int8_t control; +}; + +struct scsi_log_header +{ + u_int8_t page; + u_int8_t reserved; + u_int8_t datalen[2]; +}; + +struct scsi_log_param_header { + u_int8_t param_code[2]; + u_int8_t param_control; +#define SLP_LP 0x01 +#define SLP_LBIN 0x02 +#define SLP_TMC_MASK 0x0C +#define SLP_TMC_ALWAYS 0x00 +#define SLP_TMC_EQUAL 0x04 +#define SLP_TMC_NOTEQUAL 0x08 +#define SLP_TMC_GREATER 0x0C +#define SLP_ETC 0x10 +#define SLP_TSD 0x20 +#define SLP_DS 0x40 +#define SLP_DU 0x80 + u_int8_t param_len; +}; + +struct scsi_control_page { + u_int8_t page_code; + u_int8_t page_length; + u_int8_t rlec; +#define SCB_RLEC 0x01 /*Report Log Exception Cond*/ + u_int8_t queue_flags; +#define SCP_QUEUE_ALG_MASK 0xF0 +#define SCP_QUEUE_ALG_RESTRICTED 0x00 +#define SCP_QUEUE_ALG_UNRESTRICTED 0x10 +#define SCP_QUEUE_ERR 0x02 /*Queued I/O aborted for CACs*/ +#define SCP_QUEUE_DQUE 0x01 /*Queued I/O disabled*/ + u_int8_t eca_and_aen; +#define SCP_EECA 0x80 /*Enable Extended CA*/ +#define SCP_RAENP 0x04 /*Ready AEN Permission*/ +#define SCP_UAAENP 0x02 /*UA AEN Permission*/ +#define SCP_EAENP 0x01 /*Error AEN Permission*/ + u_int8_t reserved; + u_int8_t aen_holdoff_period[2]; +}; + +struct scsi_cache_page { + u_int8_t page_code; +#define SCHP_PAGE_SAVABLE 0x80 /* Page is savable */ + u_int8_t page_length; + u_int8_t cache_flags; +#define SCHP_FLAGS_WCE 0x04 /* Write Cache Enable */ +#define SCHP_FLAGS_MF 0x02 /* Multiplication factor */ +#define SCHP_FLAGS_RCD 0x01 /* Read Cache Disable */ + u_int8_t rw_cache_policy; + u_int8_t dis_prefetch[2]; + u_int8_t min_prefetch[2]; + u_int8_t max_prefetch[2]; + u_int8_t max_prefetch_ceil[2]; +}; + +struct scsi_info_exceptions_page { + u_int8_t page_code; +#define SIEP_PAGE_SAVABLE 0x80 /* Page is savable */ + u_int8_t page_length; + u_int8_t info_flags; +#define SIEP_FLAGS_PERF 0x80 +#define SIEP_FLAGS_EBF 0x20 +#define SIEP_FLAGS_EWASC 0x10 +#define SIEP_FLAGS_DEXCPT 0x08 +#define SIEP_FLAGS_TEST 0x04 +#define SIEP_FLAGS_EBACKERR 0x02 +#define SIEP_FLAGS_LOGERR 0x01 + u_int8_t mrie; + u_int8_t interval_timer[4]; + u_int8_t report_count[4]; +}; + +struct scsi_proto_specific_page { + u_int8_t page_code; +#define SPSP_PAGE_SAVABLE 0x80 /* Page is savable */ + u_int8_t page_length; + u_int8_t protocol; +#define SPSP_PROTO_FC 0x00 +#define SPSP_PROTO_SPI 0x01 +#define SPSP_PROTO_SSA 0x02 +#define SPSP_PROTO_1394 0x03 +#define SPSP_PROTO_RDMA 0x04 +#define SPSP_PROTO_ISCSI 0x05 +#define SPSP_PROTO_SAS 0x06 +#define SPSP_PROTO_ADT 0x07 +#define SPSP_PROTO_ATA 0x08 +#define SPSP_PROTO_NONE 0x0f +}; + +struct scsi_reserve +{ + u_int8_t opcode; + u_int8_t byte2; + u_int8_t unused[2]; + u_int8_t length; + u_int8_t control; +}; + +struct scsi_release +{ + u_int8_t opcode; + u_int8_t byte2; + u_int8_t unused[2]; + u_int8_t length; + u_int8_t control; +}; + +struct scsi_prevent +{ + u_int8_t opcode; + u_int8_t byte2; + u_int8_t unused[2]; + u_int8_t how; + u_int8_t control; +}; +#define PR_PREVENT 0x01 +#define PR_ALLOW 0x00 + +struct scsi_sync_cache +{ + u_int8_t opcode; + u_int8_t byte2; + u_int8_t begin_lba[4]; + u_int8_t reserved; + u_int8_t lb_count[2]; + u_int8_t control; +}; + + +struct scsi_changedef +{ + u_int8_t opcode; + u_int8_t byte2; + u_int8_t unused1; + u_int8_t how; + u_int8_t unused[4]; + u_int8_t datalen; + u_int8_t control; +}; + +struct scsi_read_buffer +{ + u_int8_t opcode; + u_int8_t byte2; +#define RWB_MODE 0x07 +#define RWB_MODE_HDR_DATA 0x00 +#define RWB_MODE_DATA 0x02 +#define RWB_MODE_DOWNLOAD 0x04 +#define RWB_MODE_DOWNLOAD_SAVE 0x05 + u_int8_t buffer_id; + u_int8_t offset[3]; + u_int8_t length[3]; + u_int8_t control; +}; + +struct scsi_write_buffer +{ + u_int8_t opcode; + u_int8_t byte2; + u_int8_t buffer_id; + u_int8_t offset[3]; + u_int8_t length[3]; + u_int8_t control; +}; + +struct scsi_rw_6 +{ + u_int8_t opcode; + u_int8_t addr[3]; +/* only 5 bits are valid in the MSB address byte */ +#define SRW_TOPADDR 0x1F + u_int8_t length; + u_int8_t control; +}; + +struct scsi_rw_10 +{ + u_int8_t opcode; +#define SRW10_RELADDR 0x01 +/* EBP defined for WRITE(10) only */ +#define SRW10_EBP 0x04 +#define SRW10_FUA 0x08 +#define SRW10_DPO 0x10 + u_int8_t byte2; + u_int8_t addr[4]; + u_int8_t reserved; + u_int8_t length[2]; + u_int8_t control; +}; + +struct scsi_rw_12 +{ + u_int8_t opcode; +#define SRW12_RELADDR 0x01 +#define SRW12_FUA 0x08 +#define SRW12_DPO 0x10 + u_int8_t byte2; + u_int8_t addr[4]; + u_int8_t length[4]; + u_int8_t reserved; + u_int8_t control; +}; + +struct scsi_rw_16 +{ + u_int8_t opcode; +#define SRW16_RELADDR 0x01 +#define SRW16_FUA 0x08 +#define SRW16_DPO 0x10 + u_int8_t byte2; + u_int8_t addr[8]; + u_int8_t length[4]; + u_int8_t reserved; + u_int8_t control; +}; + +struct scsi_start_stop_unit +{ + u_int8_t opcode; + u_int8_t byte2; +#define SSS_IMMED 0x01 + u_int8_t reserved[2]; + u_int8_t how; +#define SSS_START 0x01 +#define SSS_LOEJ 0x02 + u_int8_t control; +}; + +struct ata_pass_12 { + u_int8_t opcode; + u_int8_t protocol; +#define AP_MULTI 0xe0 + u_int8_t flags; +#define AP_T_LEN 0x03 +#define AP_BB 0x04 +#define AP_T_DIR 0x08 +#define AP_CK_COND 0x20 +#define AP_OFFLINE 0x60 + u_int8_t features; + u_int8_t sector_count; + u_int8_t lba_low; + u_int8_t lba_mid; + u_int8_t lba_high; + u_int8_t device; + u_int8_t command; + u_int8_t reserved; + u_int8_t control; +}; + +struct ata_pass_16 { + u_int8_t opcode; + u_int8_t protocol; +#define AP_EXTEND 0x01 + u_int8_t flags; + u_int8_t features_ext; + u_int8_t features; + u_int8_t sector_count_ext; + u_int8_t sector_count; + u_int8_t lba_low_ext; + u_int8_t lba_low; + u_int8_t lba_mid_ext; + u_int8_t lba_mid; + u_int8_t lba_high_ext; + u_int8_t lba_high; + u_int8_t device; + u_int8_t command; + u_int8_t control; +}; + +#define SC_SCSI_1 0x01 +#define SC_SCSI_2 0x03 + +/* + * Opcodes + */ + +#define TEST_UNIT_READY 0x00 +#define REQUEST_SENSE 0x03 +#define READ_6 0x08 +#define WRITE_6 0x0A +#define INQUIRY 0x12 +#define MODE_SELECT_6 0x15 +#define MODE_SENSE_6 0x1A +#define START_STOP_UNIT 0x1B +#define START_STOP 0x1B +#define RESERVE 0x16 +#define RELEASE 0x17 +#define RECEIVE_DIAGNOSTIC 0x1C +#define SEND_DIAGNOSTIC 0x1D +#define PREVENT_ALLOW 0x1E +#define READ_CAPACITY 0x25 +#define READ_10 0x28 +#define WRITE_10 0x2A +#define POSITION_TO_ELEMENT 0x2B +#define SYNCHRONIZE_CACHE 0x35 +#define READ_DEFECT_DATA_10 0x37 +#define WRITE_BUFFER 0x3B +#define READ_BUFFER 0x3C +#define CHANGE_DEFINITION 0x40 +#define LOG_SELECT 0x4C +#define LOG_SENSE 0x4D +#define MODE_SELECT_10 0x55 +#define MODE_SENSE_10 0x5A +#define ATA_PASS_16 0x85 +#define READ_16 0x88 +#define WRITE_16 0x8A +#define SERVICE_ACTION_IN 0x9E +#define REPORT_LUNS 0xA0 +#define ATA_PASS_12 0xA1 +#define MAINTENANCE_IN 0xA3 +#define MAINTENANCE_OUT 0xA4 +#define MOVE_MEDIUM 0xA5 +#define READ_12 0xA8 +#define WRITE_12 0xAA +#define READ_ELEMENT_STATUS 0xB8 + +/* Maintenance In Service Action Codes */ +#define REPORT_IDENTIFYING_INFRMATION 0x05 +#define REPORT_TARGET_PORT_GROUPS 0x0A +#define REPORT_ALIASES 0x0B +#define REPORT_SUPPORTED_OPERATION_CODES 0x0C +#define REPORT_SUPPORTED_TASK_MANAGEMENT_FUNCTIONS 0x0D +#define REPORT_PRIORITY 0x0E +#define REPORT_TIMESTAMP 0x0F +#define MANAGEMENT_PROTOCOL_IN 0x10 +/* Maintenance Out Service Action Codes */ +#define SET_IDENTIFY_INFORMATION 0x06 +#define SET_TARGET_PORT_GROUPS 0x0A +#define CHANGE_ALIASES 0x0B +#define SET_PRIORITY 0x0E +#define SET_TIMESTAMP 0x0F +#define MANGAEMENT_PROTOCOL_OUT 0x10 + +/* + * Device Types + */ +#define T_DIRECT 0x00 +#define T_SEQUENTIAL 0x01 +#define T_PRINTER 0x02 +#define T_PROCESSOR 0x03 +#define T_WORM 0x04 +#define T_CDROM 0x05 +#define T_SCANNER 0x06 +#define T_OPTICAL 0x07 +#define T_CHANGER 0x08 +#define T_COMM 0x09 +#define T_ASC0 0x0a +#define T_ASC1 0x0b +#define T_STORARRAY 0x0c +#define T_ENCLOSURE 0x0d +#define T_RBC 0x0e +#define T_OCRW 0x0f +#define T_OSD 0x11 +#define T_ADC 0x12 +#define T_NODEVICE 0x1f +#define T_ANY 0xff /* Used in Quirk table matches */ + +#define T_REMOV 1 +#define T_FIXED 0 + +/* + * This length is the initial inquiry length used by the probe code, as + * well as the legnth necessary for scsi_print_inquiry() to function + * correctly. If either use requires a different length in the future, + * the two values should be de-coupled. + */ +#define SHORT_INQUIRY_LENGTH 36 + +struct scsi_inquiry_data +{ + u_int8_t device; +#define SID_TYPE(inq_data) ((inq_data)->device & 0x1f) +#define SID_QUAL(inq_data) (((inq_data)->device & 0xE0) >> 5) +#define SID_QUAL_LU_CONNECTED 0x00 /* + * The specified peripheral device + * type is currently connected to + * logical unit. If the target cannot + * determine whether or not a physical + * device is currently connected, it + * shall also use this peripheral + * qualifier when returning the INQUIRY + * data. This peripheral qualifier + * does not mean that the device is + * ready for access by the initiator. + */ +#define SID_QUAL_LU_OFFLINE 0x01 /* + * The target is capable of supporting + * the specified peripheral device type + * on this logical unit; however, the + * physical device is not currently + * connected to this logical unit. + */ +#define SID_QUAL_RSVD 0x02 +#define SID_QUAL_BAD_LU 0x03 /* + * The target is not capable of + * supporting a physical device on + * this logical unit. For this + * peripheral qualifier the peripheral + * device type shall be set to 1Fh to + * provide compatibility with previous + * versions of SCSI. All other + * peripheral device type values are + * reserved for this peripheral + * qualifier. + */ +#define SID_QUAL_IS_VENDOR_UNIQUE(inq_data) ((SID_QUAL(inq_data) & 0x08) != 0) + u_int8_t dev_qual2; +#define SID_QUAL2 0x7F +#define SID_IS_REMOVABLE(inq_data) (((inq_data)->dev_qual2 & 0x80) != 0) + u_int8_t version; +#define SID_ANSI_REV(inq_data) ((inq_data)->version & 0x07) +#define SCSI_REV_0 0 +#define SCSI_REV_CCS 1 +#define SCSI_REV_2 2 +#define SCSI_REV_SPC 3 +#define SCSI_REV_SPC2 4 +#define SCSI_REV_SPC3 5 +#define SCSI_REV_SPC4 6 + +#define SID_ECMA 0x38 +#define SID_ISO 0xC0 + u_int8_t response_format; +#define SID_AENC 0x80 +#define SID_TrmIOP 0x40 + u_int8_t additional_length; +#define SID_ADDITIONAL_LENGTH(iqd) \ + ((iqd)->additional_length + \ + offsetof(struct scsi_inquiry_data, additional_length) + 1) + u_int8_t spc3_flags; +#define SPC3_SID_PROTECT 0x01 +#define SPC3_SID_3PC 0x08 +#define SPC3_SID_TPGS_MASK 0x30 +#define SPC3_SID_TPGS_IMPLICIT 0x10 +#define SPC3_SID_TPGS_EXPLICIT 0x20 +#define SPC3_SID_ACC 0x40 +#define SPC3_SID_SCCS 0x80 + u_int8_t spc2_flags; +#define SPC2_SID_MChngr 0x08 +#define SPC2_SID_MultiP 0x10 +#define SPC2_SID_EncServ 0x40 +#define SPC2_SID_BQueue 0x80 + +#define INQ_DATA_TQ_ENABLED(iqd) \ + ((SID_ANSI_REV(iqd) < SCSI_REV_SPC2)? ((iqd)->flags & SID_CmdQue) : \ + (((iqd)->flags & SID_CmdQue) && !((iqd)->spc2_flags & SPC2_SID_BQueue)) || \ + (!((iqd)->flags & SID_CmdQue) && ((iqd)->spc2_flags & SPC2_SID_BQueue))) + + u_int8_t flags; +#define SID_SftRe 0x01 +#define SID_CmdQue 0x02 +#define SID_Linked 0x08 +#define SID_Sync 0x10 +#define SID_WBus16 0x20 +#define SID_WBus32 0x40 +#define SID_RelAdr 0x80 +#define SID_VENDOR_SIZE 8 + char vendor[SID_VENDOR_SIZE]; +#define SID_PRODUCT_SIZE 16 + char product[SID_PRODUCT_SIZE]; +#define SID_REVISION_SIZE 4 + char revision[SID_REVISION_SIZE]; + /* + * The following fields were taken from SCSI Primary Commands - 2 + * (SPC-2) Revision 14, Dated 11 November 1999 + */ +#define SID_VENDOR_SPECIFIC_0_SIZE 20 + u_int8_t vendor_specific0[SID_VENDOR_SPECIFIC_0_SIZE]; + /* + * An extension of SCSI Parallel Specific Values + */ +#define SID_SPI_IUS 0x01 +#define SID_SPI_QAS 0x02 +#define SID_SPI_CLOCK_ST 0x00 +#define SID_SPI_CLOCK_DT 0x04 +#define SID_SPI_CLOCK_DT_ST 0x0C +#define SID_SPI_MASK 0x0F + u_int8_t spi3data; + u_int8_t reserved2; + /* + * Version Descriptors, stored 2 byte values. + */ + u_int8_t version1[2]; + u_int8_t version2[2]; + u_int8_t version3[2]; + u_int8_t version4[2]; + u_int8_t version5[2]; + u_int8_t version6[2]; + u_int8_t version7[2]; + u_int8_t version8[2]; + + u_int8_t reserved3[22]; + +#define SID_VENDOR_SPECIFIC_1_SIZE 160 + u_int8_t vendor_specific1[SID_VENDOR_SPECIFIC_1_SIZE]; +}; + +struct scsi_vpd_supported_page_list +{ + u_int8_t device; + u_int8_t page_code; +#define SVPD_SUPPORTED_PAGE_LIST 0x00 + u_int8_t reserved; + u_int8_t length; /* number of VPD entries */ +#define SVPD_SUPPORTED_PAGES_SIZE 251 + u_int8_t list[SVPD_SUPPORTED_PAGES_SIZE]; +}; + +struct scsi_vpd_unit_serial_number +{ + u_int8_t device; + u_int8_t page_code; +#define SVPD_UNIT_SERIAL_NUMBER 0x80 + u_int8_t reserved; + u_int8_t length; /* serial number length */ +#define SVPD_SERIAL_NUM_SIZE 251 + u_int8_t serial_num[SVPD_SERIAL_NUM_SIZE]; +}; + +struct scsi_read_capacity +{ + u_int8_t opcode; + u_int8_t byte2; + u_int8_t addr[4]; + u_int8_t unused[3]; + u_int8_t control; +}; + +struct scsi_read_capacity_16 +{ + uint8_t opcode; +#define SRC16_SERVICE_ACTION 0x10 + uint8_t service_action; + uint8_t addr[8]; + uint8_t alloc_len[4]; +#define SRC16_PMI 0x01 +#define SRC16_RELADR 0x02 + uint8_t reladr; + uint8_t control; +}; + +struct scsi_read_capacity_data +{ + u_int8_t addr[4]; + u_int8_t length[4]; +}; + +struct scsi_read_capacity_data_long +{ + uint8_t addr[8]; + uint8_t length[4]; +}; + +struct scsi_report_luns +{ + uint8_t opcode; + uint8_t reserved1; +#define RPL_REPORT_DEFAULT 0x00 +#define RPL_REPORT_WELLKNOWN 0x01 +#define RPL_REPORT_ALL 0x02 + uint8_t select_report; + uint8_t reserved2[3]; + uint8_t length[4]; + uint8_t reserved3; + uint8_t control; +}; + +struct scsi_report_luns_data { + u_int8_t length[4]; /* length of LUN inventory, in bytes */ + u_int8_t reserved[4]; /* unused */ + /* + * LUN inventory- we only support the type zero form for now. + */ + struct { + u_int8_t lundata[8]; + } luns[0]; +}; +#define RPL_LUNDATA_PERIPH_BUS_MASK 0x3f +#define RPL_LUNDATA_FLAT_LUN_MASK 0x3f +#define RPL_LUNDATA_LUN_TARG_MASK 0x3f +#define RPL_LUNDATA_LUN_BUS_MASK 0xe0 +#define RPL_LUNDATA_LUN_LUN_MASK 0x1f +#define RPL_LUNDATA_EXT_LEN_MASK 0x30 +#define RPL_LUNDATA_EXT_EAM_MASK 0x0f +#define RPL_LUNDATA_EXT_EAM_WK 0x01 +#define RPL_LUNDATA_EXT_EAM_NOT_SPEC 0x0f +#define RPL_LUNDATA_ATYP_MASK 0xc0 /* MBZ for type 0 lun */ +#define RPL_LUNDATA_ATYP_PERIPH 0x00 +#define RPL_LUNDATA_ATYP_FLAT 0x40 +#define RPL_LUNDATA_ATYP_LUN 0x80 +#define RPL_LUNDATA_ATYP_EXTLUN 0xc0 + +struct scsi_target_group +{ + uint8_t opcode; + uint8_t service_action; +#define STG_PDF_LENGTH 0x00 +#define RPL_PDF_EXTENDED 0x20 + uint8_t reserved1[4]; + uint8_t length[4]; + uint8_t reserved2; + uint8_t control; +}; + +struct scsi_target_port_descriptor { + uint8_t reserved[2]; + uint8_t relative_target_port_identifier[2]; + uint8_t desc_list[]; +}; + +struct scsi_target_port_group_descriptor { + uint8_t pref_state; +#define TPG_PRIMARY 0x80 +#define TPG_ASYMMETRIC_ACCESS_STATE_MASK 0xf +#define TPG_ASYMMETRIC_ACCESS_OPTIMIZED 0x0 +#define TPG_ASYMMETRIC_ACCESS_NONOPTIMIZED 0x1 +#define TPG_ASYMMETRIC_ACCESS_STANDBY 0x2 +#define TPG_ASYMMETRIC_ACCESS_UNAVAILABLE 0x3 +#define TPG_ASYMMETRIC_ACCESS_LBA_DEPENDENT 0x4 +#define TPG_ASYMMETRIC_ACCESS_OFFLINE 0xE +#define TPG_ASYMMETRIC_ACCESS_TRANSITIONING 0xF + uint8_t support; +#define TPG_AO_SUP 0x01 +#define TPG_AN_SUP 0x02 +#define TPG_S_SUP 0x04 +#define TPG_U_SUP 0x08 +#define TPG_LBD_SUP 0x10 +#define TPG_O_SUP 0x40 +#define TPG_T_SUP 0x80 + uint8_t target_port_group[2]; + uint8_t reserved; + uint8_t status; + uint8_t vendor_specific; + uint8_t target_port_count; + struct scsi_target_port_descriptor descriptors[]; +}; + +struct scsi_target_group_data { + uint8_t length[4]; /* length of returned data, in bytes */ + struct scsi_target_port_group_descriptor groups[]; +}; + +struct scsi_target_group_data_extended { + uint8_t length[4]; /* length of returned data, in bytes */ + uint8_t format_type; /* STG_PDF_LENGTH or RPL_PDF_EXTENDED */ + uint8_t implicit_transition_time; + uint8_t reserved[2]; + struct scsi_target_port_group_descriptor groups[]; +}; + + +struct scsi_sense_data +{ + u_int8_t error_code; +#define SSD_ERRCODE 0x7F +#define SSD_CURRENT_ERROR 0x70 +#define SSD_DEFERRED_ERROR 0x71 +#define SSD_ERRCODE_VALID 0x80 + u_int8_t segment; + u_int8_t flags; +#define SSD_KEY 0x0F +#define SSD_KEY_NO_SENSE 0x00 +#define SSD_KEY_RECOVERED_ERROR 0x01 +#define SSD_KEY_NOT_READY 0x02 +#define SSD_KEY_MEDIUM_ERROR 0x03 +#define SSD_KEY_HARDWARE_ERROR 0x04 +#define SSD_KEY_ILLEGAL_REQUEST 0x05 +#define SSD_KEY_UNIT_ATTENTION 0x06 +#define SSD_KEY_DATA_PROTECT 0x07 +#define SSD_KEY_BLANK_CHECK 0x08 +#define SSD_KEY_Vendor_Specific 0x09 +#define SSD_KEY_COPY_ABORTED 0x0a +#define SSD_KEY_ABORTED_COMMAND 0x0b +#define SSD_KEY_EQUAL 0x0c +#define SSD_KEY_VOLUME_OVERFLOW 0x0d +#define SSD_KEY_MISCOMPARE 0x0e +#define SSD_KEY_RESERVED 0x0f +#define SSD_ILI 0x20 +#define SSD_EOM 0x40 +#define SSD_FILEMARK 0x80 + u_int8_t info[4]; + u_int8_t extra_len; + u_int8_t cmd_spec_info[4]; + u_int8_t add_sense_code; + u_int8_t add_sense_code_qual; + u_int8_t fru; + u_int8_t sense_key_spec[3]; +#define SSD_SCS_VALID 0x80 +#define SSD_FIELDPTR_CMD 0x40 +#define SSD_BITPTR_VALID 0x08 +#define SSD_BITPTR_VALUE 0x07 +#define SSD_MIN_SIZE 18 + u_int8_t extra_bytes[14]; +#define SSD_FULL_SIZE sizeof(struct scsi_sense_data) +}; + +struct scsi_mode_header_6 +{ + u_int8_t data_length; /* Sense data length */ + u_int8_t medium_type; + u_int8_t dev_spec; + u_int8_t blk_desc_len; +}; + +struct scsi_mode_header_10 +{ + u_int8_t data_length[2];/* Sense data length */ + u_int8_t medium_type; + u_int8_t dev_spec; + u_int8_t unused[2]; + u_int8_t blk_desc_len[2]; +}; + +struct scsi_mode_page_header +{ + u_int8_t page_code; + u_int8_t page_length; +}; + +struct scsi_mode_blk_desc +{ + u_int8_t density; + u_int8_t nblocks[3]; + u_int8_t reserved; + u_int8_t blklen[3]; +}; + +#define SCSI_DEFAULT_DENSITY 0x00 /* use 'default' density */ +#define SCSI_SAME_DENSITY 0x7f /* use 'same' density- >= SCSI-2 only */ + + +/* + * Status Byte + */ +#define SCSI_STATUS_OK 0x00 +#define SCSI_STATUS_CHECK_COND 0x02 +#define SCSI_STATUS_COND_MET 0x04 +#define SCSI_STATUS_BUSY 0x08 +#define SCSI_STATUS_INTERMED 0x10 +#define SCSI_STATUS_INTERMED_COND_MET 0x14 +#define SCSI_STATUS_RESERV_CONFLICT 0x18 +#define SCSI_STATUS_CMD_TERMINATED 0x22 /* Obsolete in SAM-2 */ +#define SCSI_STATUS_QUEUE_FULL 0x28 +#define SCSI_STATUS_ACA_ACTIVE 0x30 +#define SCSI_STATUS_TASK_ABORTED 0x40 + +struct scsi_inquiry_pattern { + u_int8_t type; + u_int8_t media_type; +#define SIP_MEDIA_REMOVABLE 0x01 +#define SIP_MEDIA_FIXED 0x02 + const char *vendor; + const char *product; + const char *revision; +}; + +struct scsi_static_inquiry_pattern { + u_int8_t type; + u_int8_t media_type; + char vendor[SID_VENDOR_SIZE+1]; + char product[SID_PRODUCT_SIZE+1]; + char revision[SID_REVISION_SIZE+1]; +}; + +struct scsi_sense_quirk_entry { + struct scsi_inquiry_pattern inq_pat; + int num_sense_keys; + int num_ascs; + struct sense_key_table_entry *sense_key_info; + struct asc_table_entry *asc_info; +}; + +struct sense_key_table_entry { + u_int8_t sense_key; + u_int32_t action; + const char *desc; +}; + +struct asc_table_entry { + u_int8_t asc; + u_int8_t ascq; + u_int32_t action; + const char *desc; +}; + +struct op_table_entry { + u_int8_t opcode; + u_int32_t opmask; + const char *desc; +}; + +struct scsi_op_quirk_entry { + struct scsi_inquiry_pattern inq_pat; + int num_ops; + struct op_table_entry *op_table; +}; + +typedef enum { + SSS_FLAG_NONE = 0x00, + SSS_FLAG_PRINT_COMMAND = 0x01 +} scsi_sense_string_flags; + +struct ccb_scsiio; +struct cam_periph; +union ccb; +#ifndef _KERNEL +struct cam_device; +#endif + +extern const char *scsi_sense_key_text[]; + +struct sbuf; + +__BEGIN_DECLS +void scsi_sense_desc(int sense_key, int asc, int ascq, + struct scsi_inquiry_data *inq_data, + const char **sense_key_desc, const char **asc_desc); +scsi_sense_action scsi_error_action(struct ccb_scsiio* csio, + struct scsi_inquiry_data *inq_data, + u_int32_t sense_flags); +const char * scsi_status_string(struct ccb_scsiio *csio); +#ifdef _KERNEL +int scsi_command_string(struct ccb_scsiio *csio, struct sbuf *sb); +int scsi_sense_sbuf(struct ccb_scsiio *csio, struct sbuf *sb, + scsi_sense_string_flags flags); +char * scsi_sense_string(struct ccb_scsiio *csio, + char *str, int str_len); +void scsi_sense_print(struct ccb_scsiio *csio); +int scsi_interpret_sense(union ccb *ccb, + u_int32_t sense_flags, + u_int32_t *relsim_flags, + u_int32_t *reduction, + u_int32_t *timeout, + scsi_sense_action error_action); +#else /* _KERNEL */ +int scsi_command_string(struct cam_device *device, + struct ccb_scsiio *csio, struct sbuf *sb); +int scsi_sense_sbuf(struct cam_device *device, + struct ccb_scsiio *csio, struct sbuf *sb, + scsi_sense_string_flags flags); +char * scsi_sense_string(struct cam_device *device, + struct ccb_scsiio *csio, + char *str, int str_len); +void scsi_sense_print(struct cam_device *device, + struct ccb_scsiio *csio, FILE *ofile); +int scsi_interpret_sense(struct cam_device *device, + union ccb *ccb, + u_int32_t sense_flags, + u_int32_t *relsim_flags, + u_int32_t *reduction, + u_int32_t *timeout, + scsi_sense_action error_action); +#endif /* _KERNEL */ + +#define SF_RETRY_UA 0x01 +#define SF_NO_PRINT 0x02 +#define SF_QUIET_IR 0x04 /* Be quiet about Illegal Request reponses */ +#define SF_PRINT_ALWAYS 0x08 + + +const char * scsi_op_desc(u_int16_t opcode, + struct scsi_inquiry_data *inq_data); +char * scsi_cdb_string(u_int8_t *cdb_ptr, char *cdb_string, + size_t len); + +void scsi_print_inquiry(struct scsi_inquiry_data *inq_data); + +u_int scsi_calc_syncsrate(u_int period_factor); +u_int scsi_calc_syncparam(u_int period); + +void scsi_test_unit_ready(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, + union ccb *), + u_int8_t tag_action, + u_int8_t sense_len, u_int32_t timeout); + +void scsi_request_sense(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, + union ccb *), + void *data_ptr, u_int8_t dxfer_len, + u_int8_t tag_action, u_int8_t sense_len, + u_int32_t timeout); + +void scsi_inquiry(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb *), + u_int8_t tag_action, u_int8_t *inq_buf, + u_int32_t inq_len, int evpd, u_int8_t page_code, + u_int8_t sense_len, u_int32_t timeout); + +void scsi_mode_sense(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, + union ccb *), + u_int8_t tag_action, int dbd, + u_int8_t page_code, u_int8_t page, + u_int8_t *param_buf, u_int32_t param_len, + u_int8_t sense_len, u_int32_t timeout); + +void scsi_mode_sense_len(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, + union ccb *), + u_int8_t tag_action, int dbd, + u_int8_t page_code, u_int8_t page, + u_int8_t *param_buf, u_int32_t param_len, + int minimum_cmd_size, u_int8_t sense_len, + u_int32_t timeout); + +void scsi_mode_select(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, + union ccb *), + u_int8_t tag_action, int scsi_page_fmt, + int save_pages, u_int8_t *param_buf, + u_int32_t param_len, u_int8_t sense_len, + u_int32_t timeout); + +void scsi_mode_select_len(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, + union ccb *), + u_int8_t tag_action, int scsi_page_fmt, + int save_pages, u_int8_t *param_buf, + u_int32_t param_len, int minimum_cmd_size, + u_int8_t sense_len, u_int32_t timeout); + +void scsi_log_sense(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb *), + u_int8_t tag_action, u_int8_t page_code, + u_int8_t page, int save_pages, int ppc, + u_int32_t paramptr, u_int8_t *param_buf, + u_int32_t param_len, u_int8_t sense_len, + u_int32_t timeout); + +void scsi_log_select(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, + union ccb *), u_int8_t tag_action, + u_int8_t page_code, int save_pages, + int pc_reset, u_int8_t *param_buf, + u_int32_t param_len, u_int8_t sense_len, + u_int32_t timeout); + +void scsi_prevent(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb *), + u_int8_t tag_action, u_int8_t action, + u_int8_t sense_len, u_int32_t timeout); + +void scsi_read_capacity(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, + union ccb *), u_int8_t tag_action, + struct scsi_read_capacity_data *, + u_int8_t sense_len, u_int32_t timeout); +void scsi_read_capacity_16(struct ccb_scsiio *csio, uint32_t retries, + void (*cbfcnp)(struct cam_periph *, + union ccb *), uint8_t tag_action, + uint64_t lba, int reladr, int pmi, + struct scsi_read_capacity_data_long + *rcap_buf, uint8_t sense_len, + uint32_t timeout); + +void scsi_report_luns(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, + union ccb *), u_int8_t tag_action, + u_int8_t select_report, + struct scsi_report_luns_data *rpl_buf, + u_int32_t alloc_len, u_int8_t sense_len, + u_int32_t timeout); + +void scsi_report_target_group(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, + union ccb *), u_int8_t tag_action, + u_int8_t pdf, + void *buf, + u_int32_t alloc_len, u_int8_t sense_len, + u_int32_t timeout); + +void scsi_set_target_group(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, + union ccb *), u_int8_t tag_action, void *buf, + u_int32_t alloc_len, u_int8_t sense_len, + u_int32_t timeout); + +void scsi_synchronize_cache(struct ccb_scsiio *csio, + u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, + union ccb *), u_int8_t tag_action, + u_int32_t begin_lba, u_int16_t lb_count, + u_int8_t sense_len, u_int32_t timeout); + +void scsi_read_write(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb *), + u_int8_t tag_action, int readop, u_int8_t byte2, + int minimum_cmd_size, u_int64_t lba, + u_int32_t block_count, u_int8_t *data_ptr, + u_int32_t dxfer_len, u_int8_t sense_len, + u_int32_t timeout); + +void scsi_start_stop(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb *), + u_int8_t tag_action, int start, int load_eject, + int immediate, u_int8_t sense_len, u_int32_t timeout); + +int scsi_inquiry_match(caddr_t inqbuffer, caddr_t table_entry); +int scsi_static_inquiry_match(caddr_t inqbuffer, + caddr_t table_entry); + +static __inline void scsi_extract_sense(struct scsi_sense_data *sense, + int *error_code, int *sense_key, + int *asc, int *ascq); +static __inline void scsi_ulto2b(u_int32_t val, u_int8_t *bytes); +static __inline void scsi_ulto3b(u_int32_t val, u_int8_t *bytes); +static __inline void scsi_ulto4b(u_int32_t val, u_int8_t *bytes); +static __inline void scsi_u64to8b(u_int64_t val, u_int8_t *bytes); +static __inline u_int32_t scsi_2btoul(u_int8_t *bytes); +static __inline u_int32_t scsi_3btoul(u_int8_t *bytes); +static __inline int32_t scsi_3btol(u_int8_t *bytes); +static __inline u_int32_t scsi_4btoul(u_int8_t *bytes); +static __inline u_int64_t scsi_8btou64(u_int8_t *bytes); +static __inline void *find_mode_page_6(struct scsi_mode_header_6 *mode_header); +static __inline void *find_mode_page_10(struct scsi_mode_header_10 *mode_header); + +static __inline void scsi_extract_sense(struct scsi_sense_data *sense, + int *error_code, int *sense_key, + int *asc, int *ascq) +{ + *error_code = sense->error_code & SSD_ERRCODE; + *sense_key = sense->flags & SSD_KEY; + *asc = (sense->extra_len >= 5) ? sense->add_sense_code : 0; + *ascq = (sense->extra_len >= 6) ? sense->add_sense_code_qual : 0; +} + +static __inline void +scsi_ulto2b(u_int32_t val, u_int8_t *bytes) +{ + + bytes[0] = (val >> 8) & 0xff; + bytes[1] = val & 0xff; +} + +static __inline void +scsi_ulto3b(u_int32_t val, u_int8_t *bytes) +{ + + bytes[0] = (val >> 16) & 0xff; + bytes[1] = (val >> 8) & 0xff; + bytes[2] = val & 0xff; +} + +static __inline void +scsi_ulto4b(u_int32_t val, u_int8_t *bytes) +{ + + bytes[0] = (val >> 24) & 0xff; + bytes[1] = (val >> 16) & 0xff; + bytes[2] = (val >> 8) & 0xff; + bytes[3] = val & 0xff; +} + +static __inline void +scsi_u64to8b(u_int64_t val, u_int8_t *bytes) +{ + + bytes[0] = (val >> 56) & 0xff; + bytes[1] = (val >> 48) & 0xff; + bytes[2] = (val >> 40) & 0xff; + bytes[3] = (val >> 32) & 0xff; + bytes[4] = (val >> 24) & 0xff; + bytes[5] = (val >> 16) & 0xff; + bytes[6] = (val >> 8) & 0xff; + bytes[7] = val & 0xff; +} + +static __inline u_int32_t +scsi_2btoul(u_int8_t *bytes) +{ + u_int32_t rv; + + rv = (bytes[0] << 8) | + bytes[1]; + return (rv); +} + +static __inline u_int32_t +scsi_3btoul(u_int8_t *bytes) +{ + u_int32_t rv; + + rv = (bytes[0] << 16) | + (bytes[1] << 8) | + bytes[2]; + return (rv); +} + +static __inline int32_t +scsi_3btol(u_int8_t *bytes) +{ + u_int32_t rc = scsi_3btoul(bytes); + + if (rc & 0x00800000) + rc |= 0xff000000; + + return (int32_t) rc; +} + +static __inline u_int32_t +scsi_4btoul(u_int8_t *bytes) +{ + u_int32_t rv; + + rv = (bytes[0] << 24) | + (bytes[1] << 16) | + (bytes[2] << 8) | + bytes[3]; + return (rv); +} + +static __inline uint64_t +scsi_8btou64(uint8_t *bytes) +{ + uint64_t rv; + + rv = (((uint64_t)bytes[0]) << 56) | + (((uint64_t)bytes[1]) << 48) | + (((uint64_t)bytes[2]) << 40) | + (((uint64_t)bytes[3]) << 32) | + (((uint64_t)bytes[4]) << 24) | + (((uint64_t)bytes[5]) << 16) | + (((uint64_t)bytes[6]) << 8) | + bytes[7]; + return (rv); +} + +/* + * Given the pointer to a returned mode sense buffer, return a pointer to + * the start of the first mode page. + */ +static __inline void * +find_mode_page_6(struct scsi_mode_header_6 *mode_header) +{ + void *page_start; + + page_start = (void *)((u_int8_t *)&mode_header[1] + + mode_header->blk_desc_len); + + return(page_start); +} + +static __inline void * +find_mode_page_10(struct scsi_mode_header_10 *mode_header) +{ + void *page_start; + + page_start = (void *)((u_int8_t *)&mode_header[1] + + scsi_2btoul(mode_header->blk_desc_len)); + + return(page_start); +} + +__END_DECLS + +#endif /*_SCSI_SCSI_ALL_H*/ diff --git a/freebsd/sys/cam/scsi/scsi_da.h b/freebsd/sys/cam/scsi/scsi_da.h new file mode 100644 index 00000000..69dafefc --- /dev/null +++ b/freebsd/sys/cam/scsi/scsi_da.h @@ -0,0 +1,463 @@ +/* + * Structures and definitions for SCSI commands to Direct Access Devices + */ + +/*- + * Some lines of this file come from a file of the name "scsi.h" + * distributed by OSF as part of mach2.5, + * so the following disclaimer has been kept. + * + * Copyright 1990 by Open Software Foundation, + * Grenoble, FRANCE + * + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both the copyright notice and this permission notice appear in + * supporting documentation, and that the name of OSF or Open Software + * Foundation not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. + * + * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, + * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, + * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/*- + * Largely written by Julian Elischer (julian@tfs.com) + * for TRW Financial Systems. + * + * TRW Financial Systems, in accordance with their agreement with Carnegie + * Mellon University, makes this software available to CMU to distribute + * or use in any manner that they see fit as long as this message is kept with + * the software. For this reason TFS also grants any other persons or + * organisations permission to use or modify this software. + * + * TFS supplies this software to be publicly redistributed + * on the understanding that TFS is not responsible for the correct + * functioning of this software in any circumstances. + * + * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 + * + * $FreeBSD$ + */ + +#ifndef _SCSI_SCSI_DA_H +#define _SCSI_SCSI_DA_H 1 + +#include <freebsd/sys/cdefs.h> + +struct scsi_rezero_unit +{ + u_int8_t opcode; +#define SRZU_LUN_MASK 0xE0 + u_int8_t byte2; + u_int8_t reserved[3]; + u_int8_t control; +}; + +/* + * NOTE: The lower three bits of byte2 of the format CDB are the same as + * the lower three bits of byte2 of the read defect data CDB, below. + */ +struct scsi_format_unit +{ + u_int8_t opcode; + u_int8_t byte2; +#define FU_FORMAT_MASK SRDD10_DLIST_FORMAT_MASK +#define FU_BLOCK_FORMAT SRDD10_BLOCK_FORMAT +#define FU_BFI_FORMAT SRDD10_BYTES_FROM_INDEX_FORMAT +#define FU_PHYS_FORMAT SRDD10_PHYSICAL_SECTOR_FORMAT +#define FU_CMPLST 0x08 +#define FU_FMT_DATA 0x10 + u_int8_t vendor_specific; + u_int8_t interleave[2]; + u_int8_t control; +}; + +struct scsi_reassign_blocks +{ + u_int8_t opcode; + u_int8_t byte2; + u_int8_t unused[3]; + u_int8_t control; +}; + +struct scsi_read_defect_data_10 +{ + u_int8_t opcode; + + /* + * The most significant 3 bits are the LUN, the other 5 are + * reserved. + */ +#define SRDD10_LUN_MASK 0xE0 + u_int8_t byte2; +#define SRDD10_GLIST 0x08 +#define SRDD10_PLIST 0x10 +#define SRDD10_DLIST_FORMAT_MASK 0x07 +#define SRDD10_BLOCK_FORMAT 0x00 +#define SRDD10_BYTES_FROM_INDEX_FORMAT 0x04 +#define SRDD10_PHYSICAL_SECTOR_FORMAT 0x05 + u_int8_t format; + + u_int8_t reserved[4]; + + u_int8_t alloc_length[2]; + + u_int8_t control; +}; + +struct scsi_read_defect_data_12 +{ + u_int8_t opcode; + + /* + * The most significant 3 bits are the LUN, the other 5 are + * reserved. + */ +#define SRDD12_LUN_MASK 0xE0 + u_int8_t byte2; + +#define SRDD12_GLIST 0x08 +#define SRDD12_PLIST 0x10 +#define SRDD12_DLIST_FORMAT_MASK 0x07 +#define SRDD12_BLOCK_FORMAT 0x00 +#define SRDD12_BYTES_FROM_INDEX_FORMAT 0x04 +#define SRDD12_PHYSICAL_SECTOR_FORMAT 0x05 + u_int8_t format; + + u_int8_t reserved[4]; + + u_int8_t alloc_length[4]; + + u_int8_t control; + +}; + + +/* + * Opcodes + */ +#define REZERO_UNIT 0x01 +#define FORMAT_UNIT 0x04 +#define REASSIGN_BLOCKS 0x07 +#define MODE_SELECT 0x15 +#define MODE_SENSE 0x1a +#define READ_FORMAT_CAPACITIES 0x23 +#define WRITE_AND_VERIFY 0x2e +#define VERIFY 0x2f +#define READ_DEFECT_DATA_10 0x37 +#define READ_DEFECT_DATA_12 0xb7 + +struct format_defect_list_header +{ + u_int8_t reserved; + u_int8_t byte2; +#define FU_DLH_VS 0x01 +#define FU_DLH_IMMED 0x02 +#define FU_DLH_DSP 0x04 +#define FU_DLH_IP 0x08 +#define FU_DLH_STPF 0x10 +#define FU_DLH_DCRT 0x20 +#define FU_DLH_DPRY 0x40 +#define FU_DLH_FOV 0x80 + u_int8_t defect_list_length[2]; +}; + +struct format_ipat_descriptor +{ + u_int8_t byte1; +#define FU_INIT_NO_HDR 0x00 +#define FU_INIT_LBA_MSB 0x40 +#define FU_INIT_LBA_EACH 0x80 +#define FU_INIT_SI 0x20 + u_int8_t pattern_type; +#define FU_INIT_PAT_DEFAULT 0x00 +#define FU_INIT_PAT_REPEAT 0x01 + u_int8_t pat_length[2]; +}; + +struct scsi_read_format_capacities +{ + uint8_t opcode; /* READ_FORMAT_CAPACITIES */ + uint8_t byte2; +#define SRFC_LUN_MASK 0xE0 + uint8_t reserved0[5]; + uint8_t alloc_length[2]; + uint8_t reserved1[3]; +}; + +struct scsi_verify +{ + uint8_t opcode; /* VERIFY */ + uint8_t byte2; +#define SVFY_LUN_MASK 0xE0 +#define SVFY_RELADR 0x01 +#define SVFY_BYTECHK 0x02 +#define SVFY_DPO 0x10 + uint8_t addr[4]; /* LBA to begin verification at */ + uint8_t reserved0[1]; + uint8_t len[2]; /* number of blocks to verify */ + uint8_t reserved1[3]; +}; + +struct scsi_write_and_verify +{ + uint8_t opcode; /* WRITE_AND_VERIFY */ + uint8_t byte2; +#define SWVY_LUN_MASK 0xE0 +#define SWVY_RELADR 0x01 +#define SWVY_BYTECHK 0x02 +#define SWVY_DPO 0x10 + uint8_t addr[4]; /* LBA to begin verification at */ + uint8_t reserved0[1]; + uint8_t len[2]; /* number of blocks to write and verify */ + uint8_t reserved1[3]; +}; + +/* + * Replies to READ_FORMAT_CAPACITIES look like this: + * + * struct format_capacity_list_header + * struct format_capacity_descriptor[1..n] + * + * These are similar, but not totally identical to, the + * defect list used to format a rigid disk. + * + * The appropriate csio_decode() format string looks like this: + * "{} *i3 {Len} i1 {Blocks} i4 {} *b6 {Code} b2 {Blocklen} i3" + * + * If the capacity_list_length is greater than + * sizeof(struct format_capacity_descriptor), then there are + * additional format capacity descriptors available which + * denote which format(s) the drive can handle. + * + * (Source: USB Mass Storage UFI Specification) + */ + +struct format_capacity_list_header { + uint8_t unused[3]; + uint8_t capacity_list_length; +}; + +struct format_capacity_descriptor { + uint8_t nblocks[4]; /* total number of LBAs */ + uint8_t byte4; /* only present in max/cur descriptor */ +#define FCD_CODE_MASK 0x03 /* mask for code field above */ +#define FCD_UNFORMATTED 0x01 /* unformatted media present, + * maximum capacity returned */ +#define FCD_FORMATTED 0x02 /* formatted media present, + * current capacity returned */ +#define FCD_NOMEDIA 0x03 /* no media present, + * maximum device capacity returned */ + uint8_t block_length[3]; /* length of an LBA in bytes */ +}; + +struct scsi_reassign_blocks_data +{ + u_int8_t reserved[2]; + u_int8_t length[2]; + struct { + u_int8_t dlbaddr[4]; /* defect logical block address */ + } defect_descriptor[1]; +}; + + +/* + * This is the list header for the READ DEFECT DATA(10) command above. + * It may be a bit wrong to append the 10 at the end of the data structure, + * since it's only 4 bytes but it does tie it to the 10 byte command. + */ +struct scsi_read_defect_data_hdr_10 +{ + u_int8_t reserved; +#define SRDDH10_GLIST 0x08 +#define SRDDH10_PLIST 0x10 +#define SRDDH10_DLIST_FORMAT_MASK 0x07 +#define SRDDH10_BLOCK_FORMAT 0x00 +#define SRDDH10_BYTES_FROM_INDEX_FORMAT 0x04 +#define SRDDH10_PHYSICAL_SECTOR_FORMAT 0x05 + u_int8_t format; + u_int8_t length[2]; +}; + +struct scsi_defect_desc_block +{ + u_int8_t address[4]; +}; + +struct scsi_defect_desc_bytes_from_index +{ + u_int8_t cylinder[3]; + u_int8_t head; + u_int8_t bytes_from_index[4]; +}; + +struct scsi_defect_desc_phys_sector +{ + u_int8_t cylinder[3]; + u_int8_t head; + u_int8_t sector[4]; +}; + +struct scsi_read_defect_data_hdr_12 +{ + u_int8_t reserved; +#define SRDDH12_GLIST 0x08 +#define SRDDH12_PLIST 0x10 +#define SRDDH12_DLIST_FORMAT_MASK 0x07 +#define SRDDH12_BLOCK_FORMAT 0x00 +#define SRDDH12_BYTES_FROM_INDEX_FORMAT 0x04 +#define SRDDH12_PHYSICAL_SECTOR_FORMAT 0x05 + u_int8_t format; + u_int8_t length[4]; +}; + +union disk_pages /* this is the structure copied from osf */ +{ + struct format_device_page { + u_int8_t pg_code; /* page code (should be 3) */ +#define SMS_FORMAT_DEVICE_PAGE 0x03 /* only 6 bits valid */ + u_int8_t pg_length; /* page length (should be 0x16) */ +#define SMS_FORMAT_DEVICE_PLEN 0x16 + u_int8_t trk_z_1; /* tracks per zone (MSB) */ + u_int8_t trk_z_0; /* tracks per zone (LSB) */ + u_int8_t alt_sec_1; /* alternate sectors per zone (MSB) */ + u_int8_t alt_sec_0; /* alternate sectors per zone (LSB) */ + u_int8_t alt_trk_z_1; /* alternate tracks per zone (MSB) */ + u_int8_t alt_trk_z_0; /* alternate tracks per zone (LSB) */ + u_int8_t alt_trk_v_1; /* alternate tracks per volume (MSB) */ + u_int8_t alt_trk_v_0; /* alternate tracks per volume (LSB) */ + u_int8_t ph_sec_t_1; /* physical sectors per track (MSB) */ + u_int8_t ph_sec_t_0; /* physical sectors per track (LSB) */ + u_int8_t bytes_s_1; /* bytes per sector (MSB) */ + u_int8_t bytes_s_0; /* bytes per sector (LSB) */ + u_int8_t interleave_1; /* interleave (MSB) */ + u_int8_t interleave_0; /* interleave (LSB) */ + u_int8_t trk_skew_1; /* track skew factor (MSB) */ + u_int8_t trk_skew_0; /* track skew factor (LSB) */ + u_int8_t cyl_skew_1; /* cylinder skew (MSB) */ + u_int8_t cyl_skew_0; /* cylinder skew (LSB) */ + u_int8_t flags; /* various */ +#define DISK_FMT_SURF 0x10 +#define DISK_FMT_RMB 0x20 +#define DISK_FMT_HSEC 0x40 +#define DISK_FMT_SSEC 0x80 + u_int8_t reserved21; + u_int8_t reserved22; + u_int8_t reserved23; + } format_device; + struct rigid_geometry_page { + u_int8_t pg_code; /* page code (should be 4) */ +#define SMS_RIGID_GEOMETRY_PAGE 0x04 + u_int8_t pg_length; /* page length (should be 0x16) */ +#define SMS_RIGID_GEOMETRY_PLEN 0x16 + u_int8_t ncyl_2; /* number of cylinders (MSB) */ + u_int8_t ncyl_1; /* number of cylinders */ + u_int8_t ncyl_0; /* number of cylinders (LSB) */ + u_int8_t nheads; /* number of heads */ + u_int8_t st_cyl_wp_2; /* starting cyl., write precomp (MSB) */ + u_int8_t st_cyl_wp_1; /* starting cyl., write precomp */ + u_int8_t st_cyl_wp_0; /* starting cyl., write precomp (LSB) */ + u_int8_t st_cyl_rwc_2; /* starting cyl., red. write cur (MSB)*/ + u_int8_t st_cyl_rwc_1; /* starting cyl., red. write cur */ + u_int8_t st_cyl_rwc_0; /* starting cyl., red. write cur (LSB)*/ + u_int8_t driv_step_1; /* drive step rate (MSB) */ + u_int8_t driv_step_0; /* drive step rate (LSB) */ + u_int8_t land_zone_2; /* landing zone cylinder (MSB) */ + u_int8_t land_zone_1; /* landing zone cylinder */ + u_int8_t land_zone_0; /* landing zone cylinder (LSB) */ + u_int8_t rpl; /* rotational position locking (2 bits) */ + u_int8_t rot_offset; /* rotational offset */ + u_int8_t reserved19; + u_int8_t medium_rot_rate_1; /* medium rotation rate (RPM) (MSB) */ + u_int8_t medium_rot_rate_0; /* medium rotation rate (RPM) (LSB) */ + u_int8_t reserved22; + u_int8_t reserved23; + } rigid_geometry; + struct flexible_disk_page { + u_int8_t pg_code; /* page code (should be 5) */ +#define SMS_FLEXIBLE_GEOMETRY_PAGE 0x05 + u_int8_t pg_length; /* page length (should be 0x1E) */ +#define SMS_FLEXIBLE_GEOMETRY_PLEN 0x1E + u_int8_t xfr_rate_1; /* transfer rate (MSB) */ + u_int8_t xfr_rate_0; /* transfer rate (LSB) */ + u_int8_t nheads; /* number of heads */ + u_int8_t sec_per_track; /* Sectors per track */ + u_int8_t bytes_s_1; /* bytes per sector (MSB) */ + u_int8_t bytes_s_0; /* bytes per sector (LSB) */ + u_int8_t ncyl_1; /* number of cylinders (MSB) */ + u_int8_t ncyl_0; /* number of cylinders (LSB) */ + u_int8_t st_cyl_wp_1; /* starting cyl., write precomp (MSB) */ + u_int8_t st_cyl_wp_0; /* starting cyl., write precomp (LSB) */ + u_int8_t st_cyl_rwc_1; /* starting cyl., red. write cur (MSB)*/ + u_int8_t st_cyl_rwc_0; /* starting cyl., red. write cur (LSB)*/ + u_int8_t driv_step_1; /* drive step rate (MSB) */ + u_int8_t driv_step_0; /* drive step rate (LSB) */ + u_int8_t driv_step_pw; /* drive step pulse width */ + u_int8_t head_stl_del_1;/* Head settle delay (MSB) */ + u_int8_t head_stl_del_0;/* Head settle delay (LSB) */ + u_int8_t motor_on_del; /* Motor on delay */ + u_int8_t motor_off_del; /* Motor off delay */ + u_int8_t trdy_ssn_mo; /* XXX ??? */ + u_int8_t spc; /* XXX ??? */ + u_int8_t write_comp; /* Write compensation */ + u_int8_t head_load_del; /* Head load delay */ + u_int8_t head_uload_del;/* Head un-load delay */ + u_int8_t pin32_pin2; + u_int8_t pin4_pint1; + u_int8_t medium_rot_rate_1; /* medium rotation rate (RPM) (MSB) */ + u_int8_t medium_rot_rate_0; /* medium rotation rate (RPM) (LSB) */ + u_int8_t reserved30; + u_int8_t reserved31; + } flexible_disk; +}; + +struct scsi_da_rw_recovery_page { + u_int8_t page_code; +#define SMS_RW_ERROR_RECOVERY_PAGE 0x01 + u_int8_t page_length; + u_int8_t byte3; +#define SMS_RWER_AWRE 0x80 +#define SMS_RWER_ARRE 0x40 +#define SMS_RWER_TB 0x20 +#define SMS_RWER_RC 0x10 +#define SMS_RWER_EER 0x08 +#define SMS_RWER_PER 0x04 +#define SMS_RWER_DTE 0x02 +#define SMS_RWER_DCR 0x01 + u_int8_t read_retry_count; + u_int8_t correction_span; + u_int8_t head_offset_count; + u_int8_t data_strobe_offset_cnt; + u_int8_t reserved; + u_int8_t write_retry_count; + u_int8_t reserved2; + u_int8_t recovery_time_limit[2]; +}; + +__BEGIN_DECLS +/* + * XXX This is only left out of the kernel build to silence warnings. If, + * for some reason this function is used in the kernel, the ifdefs should + * be moved so it is included both in the kernel and userland. + */ +#ifndef _KERNEL +void scsi_format_unit(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb *), + u_int8_t tag_action, u_int8_t byte2, u_int16_t ileave, + u_int8_t *data_ptr, u_int32_t dxfer_len, + u_int8_t sense_len, u_int32_t timeout); + +#endif /* !_KERNEL */ +__END_DECLS + +#endif /* _SCSI_SCSI_DA_H */ |