summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/cam
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2013-10-09 22:42:09 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2013-10-10 09:06:58 +0200
commitbceabc95c1c85d793200446fa85f1ddc6313ea29 (patch)
tree973c8bd8deca9fd69913f2895cc91e0e6114d46c /freebsd/sys/cam
parentAdd FreeBSD sources as a submodule (diff)
downloadrtems-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.h127
-rw-r--r--freebsd/sys/cam/cam.c438
-rw-r--r--freebsd/sys/cam/cam.h263
-rw-r--r--freebsd/sys/cam/cam_ccb.h1193
-rw-r--r--freebsd/sys/cam/cam_debug.h87
-rw-r--r--freebsd/sys/cam/cam_periph.h204
-rw-r--r--freebsd/sys/cam/cam_sim.h201
-rw-r--r--freebsd/sys/cam/cam_xpt.h138
-rw-r--r--freebsd/sys/cam/cam_xpt_sim.h57
-rw-r--r--freebsd/sys/cam/scsi/scsi_all.c4305
-rw-r--r--freebsd/sys/cam/scsi/scsi_all.h1454
-rw-r--r--freebsd/sys/cam/scsi/scsi_da.h463
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 */