summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/cam
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2016-10-07 15:10:20 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2017-01-10 09:53:31 +0100
commitc40e45b75eb76d79a05c7fa85c1fa9b5c728a12f (patch)
treead4f2519067709f00ab98b3c591186c26dc3a21f /freebsd/sys/cam
parentuserspace-header-gen.py: Simplify program ports (diff)
downloadrtems-libbsd-c40e45b75eb76d79a05c7fa85c1fa9b5c728a12f.tar.bz2
Update to FreeBSD head 2016-08-23
Git mirror commit 9fe7c416e6abb28b1398fd3e5687099846800cfd.
Diffstat (limited to 'freebsd/sys/cam')
-rw-r--r--freebsd/sys/cam/ata/ata_all.h20
-rw-r--r--freebsd/sys/cam/cam.c125
-rw-r--r--freebsd/sys/cam/cam.h267
-rw-r--r--freebsd/sys/cam/cam_ccb.h194
-rw-r--r--freebsd/sys/cam/cam_periph.h51
-rw-r--r--freebsd/sys/cam/cam_sim.h14
-rw-r--r--freebsd/sys/cam/cam_xpt.h17
-rw-r--r--freebsd/sys/cam/cam_xpt_sim.h4
-rw-r--r--freebsd/sys/cam/nvme/nvme_all.h48
-rw-r--r--freebsd/sys/cam/scsi/scsi_all.c2726
-rw-r--r--freebsd/sys/cam/scsi/scsi_all.h1761
-rw-r--r--freebsd/sys/cam/scsi/scsi_da.h236
12 files changed, 5047 insertions, 416 deletions
diff --git a/freebsd/sys/cam/ata/ata_all.h b/freebsd/sys/cam/ata/ata_all.h
index 91e941c8..ea902d09 100644
--- a/freebsd/sys/cam/ata/ata_all.h
+++ b/freebsd/sys/cam/ata/ata_all.h
@@ -103,10 +103,11 @@ 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);
+void ata_cmd_sbuf(struct ata_cmd *cmd, struct sbuf *sb);
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);
+int ata_res_sbuf(struct ata_res *res, struct sbuf *sb);
void ata_print_ident(struct ata_params *ident_data);
void ata_print_ident_short(struct ata_params *ident_data);
@@ -124,6 +125,11 @@ void ata_ncq_cmd(struct ccb_ataio *ataio, uint8_t cmd,
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_read_log(struct ccb_ataio *ataio, uint32_t retries,
+ void (*cbfcnp)(struct cam_periph *, union ccb *),
+ uint32_t log_address, uint32_t page_number,
+ uint16_t block_count, uint32_t protocol,
+ uint8_t *data_ptr, uint32_t dxfer_len, uint32_t timeout);
void ata_bswap(int8_t *buf, int len);
void ata_btrim(int8_t *buf, int len);
@@ -166,4 +172,16 @@ void semb_write_buffer(struct ccb_ataio *ataio,
uint8_t tag_action, uint8_t *data_ptr, uint16_t param_list_length,
uint32_t timeout);
+void ata_zac_mgmt_out(struct ccb_ataio *ataio, uint32_t retries,
+ void (*cbfcnp)(struct cam_periph *, union ccb *),
+ int use_ncq __unused, uint8_t zm_action, uint64_t zone_id,
+ uint8_t zone_flags, uint16_t sector_count, uint8_t *data_ptr,
+ uint32_t dxfer_len, uint32_t timeout);
+
+void ata_zac_mgmt_in(struct ccb_ataio *ataio, uint32_t retries,
+ void (*cbfcnp)(struct cam_periph *, union ccb *),
+ int use_ncq __unused, uint8_t zm_action, uint64_t zone_id,
+ uint8_t zone_flags, uint8_t *data_ptr, uint32_t dxfer_len,
+ uint32_t timeout);
+
#endif
diff --git a/freebsd/sys/cam/cam.c b/freebsd/sys/cam/cam.c
index 18628cd0..71523db2 100644
--- a/freebsd/sys/cam/cam.c
+++ b/freebsd/sys/cam/cam.c
@@ -107,9 +107,6 @@ const struct cam_status_entry cam_status_table[] = {
{ 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");
@@ -118,7 +115,6 @@ SYSCTL_NODE(_kern, OID_AUTO, cam, CTLFLAG_RD, 0, "CAM Subsystem");
#endif
int cam_sort_io_queues = CAM_DEFAULT_SORT_IO_QUEUES;
-TUNABLE_INT("kern.cam.sort_io_queues", &cam_sort_io_queues);
SYSCTL_INT(_kern_cam, OID_AUTO, sort_io_queues, CTLFLAG_RWTUN,
&cam_sort_io_queues, 0, "Sort IO queues to try and optimise disk access patterns");
#endif
@@ -160,35 +156,125 @@ cam_strvis(u_int8_t *dst, const u_int8_t *src, int srclen, int dstlen)
*dst = '\0';
}
+void
+cam_strvis_sbuf(struct sbuf *sb, const u_int8_t *src, int srclen,
+ uint32_t flags)
+{
+
+ /* 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) {
+ if (*src < 0x20 || *src >= 0x80) {
+ /* SCSI-II Specifies that these should never occur. */
+ /* non-printable character */
+ switch (flags & CAM_STRVIS_FLAG_NONASCII_MASK) {
+ case CAM_STRVIS_FLAG_NONASCII_ESC:
+ sbuf_printf(sb, "\\%c%c%c",
+ ((*src & 0300) >> 6) + '0',
+ ((*src & 0070) >> 3) + '0',
+ ((*src & 0007) >> 0) + '0');
+ break;
+ case CAM_STRVIS_FLAG_NONASCII_RAW:
+ /*
+ * If we run into a NUL, just transform it
+ * into a space.
+ */
+ if (*src != 0x00)
+ sbuf_putc(sb, *src);
+ else
+ sbuf_putc(sb, ' ');
+ break;
+ case CAM_STRVIS_FLAG_NONASCII_SPC:
+ sbuf_putc(sb, ' ');
+ break;
+ case CAM_STRVIS_FLAG_NONASCII_TRIM:
+ default:
+ break;
+ }
+ } else {
+ /* normal character */
+ sbuf_putc(sb, *src);
+ }
+ src++;
+ srclen--;
+ }
+}
+
+
/*
* 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.
+ * Shell globbing rules apply: * matches 0 or more characters,
+ * ? matchces one character, [...] denotes a set to match one char,
+ * [^...] denotes a complimented set to match one character.
+ * Spaces in str used to match anything in the pattern string
+ * but was removed because it's a bug. No current patterns require
+ * it, as far as I know, but it's impossible to know what drives
+ * returned.
+ *
+ * Each '*' generates recursion, so keep the number of * in check.
*/
int
cam_strmatch(const u_int8_t *str, const u_int8_t *pattern, int str_len)
{
- while (*pattern != '\0'&& str_len > 0) {
-
+ while (*pattern != '\0' && str_len > 0) {
if (*pattern == '*') {
- return (0);
- }
- if ((*pattern != *str)
- && (*pattern != '?' || *str == ' ')) {
+ pattern++;
+ if (*pattern == '\0')
+ return (0);
+ do {
+ if (cam_strmatch(str, pattern, str_len) == 0)
+ return (0);
+ str++;
+ str_len--;
+ } while (str_len > 0);
return (1);
+ } else if (*pattern == '[') {
+ int negate_range, ok;
+ uint8_t pc, sc;
+
+ ok = 0;
+ sc = *str++;
+ str_len--;
+ if ((negate_range = (*pattern == '^')) != 0)
+ pattern++;
+ while (((pc = *pattern) != ']') && *pattern != '\0') {
+ pattern++;
+ if (*pattern == '-') {
+ if (pattern[1] == '\0') /* Bad pattern */
+ return (1);
+ if (sc >= pc && sc <= pattern[1])
+ ok = 1;
+ pattern += 2;
+ } else if (pc == sc)
+ ok = 1;
+ }
+ if (ok == negate_range)
+ return (1);
+ } else if (*pattern == '?') {
+ /* NB: || *str == ' ' of the old code is a bug and was removed */
+ /* if you add it back, keep this the last if before the naked else */
+ pattern++;
+ str++;
+ str_len--;
+ } else {
+ if (*str != *pattern)
+ return (1);
+ pattern++;
+ str++;
+ str_len--;
}
- pattern++;
- str++;
- str_len--;
}
while (str_len > 0 && *str == ' ') {
str++;
str_len--;
}
- if (str_len > 0 && *str == 0)
- str_len = 0;
return (str_len);
}
@@ -209,7 +295,7 @@ cam_fetch_status_entry(cam_status status)
{
status &= CAM_STATUS_MASK;
return (bsearch(&status, &cam_status_table,
- num_cam_status_entries,
+ nitems(cam_status_table),
sizeof(*cam_status_table),
camstatusentrycomp));
}
@@ -366,7 +452,8 @@ cam_error_string(struct cam_device *device, union ccb *ccb, char *str,
}
if (proto_flags & CAM_EAF_PRINT_RESULT) {
sbuf_cat(&sb, path_str);
- ata_res_sbuf(&ccb->ataio, &sb);
+ sbuf_printf(&sb, "RES: ");
+ ata_res_sbuf(&ccb->ataio.res, &sb);
sbuf_printf(&sb, "\n");
}
diff --git a/freebsd/sys/cam/cam.h b/freebsd/sys/cam/cam.h
index ba0e43c7..5eb0a776 100644
--- a/freebsd/sys/cam/cam.h
+++ b/freebsd/sys/cam/cam.h
@@ -43,12 +43,18 @@
typedef u_int path_id_t;
typedef u_int target_id_t;
-typedef u_int lun_id_t;
+typedef u_int64_t 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)
+#define CAM_LUN_WILDCARD (~(u_int)0)
+
+#define CAM_EXTLUN_BYTE_SWIZZLE(lun) ( \
+ ((((u_int64_t)lun) & 0xffff000000000000L) >> 48) | \
+ ((((u_int64_t)lun) & 0x0000ffff00000000L) >> 16) | \
+ ((((u_int64_t)lun) & 0x00000000ffff0000L) << 16) | \
+ ((((u_int64_t)lun) & 0x000000000000ffffL) << 48))
/*
* Maximum length for a CAM CDB.
@@ -75,7 +81,7 @@ typedef enum {
CAM_RL_VALUES
} cam_rl;
/*
- * The generation number is incremented everytime a new entry is entered into
+ * The generation number is incremented every time a new entry is entered into
* the queue giving round robin per priority level scheduling.
*/
typedef struct {
@@ -116,7 +122,7 @@ typedef enum {
enum {
SF_RETRY_UA = 0x01, /* Retry UNIT ATTENTION conditions. */
SF_NO_PRINT = 0x02, /* Never print error status. */
- SF_QUIET_IR = 0x04, /* Be quiet about Illegal Request reponses */
+ SF_QUIET_IR = 0x04, /* Be quiet about Illegal Request responses */
SF_PRINT_ALWAYS = 0x08, /* Always print error status. */
SF_NO_RECOVERY = 0x10, /* Don't do active error recovery. */
SF_NO_RETRY = 0x20, /* Don't do any retries. */
@@ -125,69 +131,184 @@ enum {
/* 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_SMP_STATUS_ERROR, /* SMP error, look at error code in CCB */
- 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 */
+ /* CCB request is in progress */
+ CAM_REQ_INPROG = 0x00,
+
+ /* CCB request completed without error */
+ CAM_REQ_CMP = 0x01,
+
+ /* CCB request aborted by the host */
+ CAM_REQ_ABORTED = 0x02,
+
+ /* Unable to abort CCB request */
+ CAM_UA_ABORT = 0x03,
+
+ /* CCB request completed with an error */
+ CAM_REQ_CMP_ERR = 0x04,
+
+ /* CAM subsystem is busy */
+ CAM_BUSY = 0x05,
+
+ /* CCB request was invalid */
+ CAM_REQ_INVALID = 0x06,
+
+ /* Supplied Path ID is invalid */
+ CAM_PATH_INVALID = 0x07,
+
+ /* SCSI Device Not Installed/there */
+ CAM_DEV_NOT_THERE = 0x08,
+
+ /* Unable to terminate I/O CCB request */
+ CAM_UA_TERMIO = 0x09,
+
+ /* Target Selection Timeout */
+ CAM_SEL_TIMEOUT = 0x0a,
+
+ /* Command timeout */
+ CAM_CMD_TIMEOUT = 0x0b,
+
+ /* SCSI error, look at error code in CCB */
+ CAM_SCSI_STATUS_ERROR = 0x0c,
+
+ /* Message Reject Received */
+ CAM_MSG_REJECT_REC = 0x0d,
+
+ /* SCSI Bus Reset Sent/Received */
+ CAM_SCSI_BUS_RESET = 0x0e,
+
+ /* Uncorrectable parity error occurred */
+ CAM_UNCOR_PARITY = 0x0f,
+
+ /* Autosense: request sense cmd fail */
+ CAM_AUTOSENSE_FAIL = 0x10,
+
+ /* No HBA Detected error */
+ CAM_NO_HBA = 0x11,
+
+ /* Data Overrun error */
+ CAM_DATA_RUN_ERR = 0x12,
+
+ /* Unexpected Bus Free */
+ CAM_UNEXP_BUSFREE = 0x13,
+
+ /* Target Bus Phase Sequence Failure */
+ CAM_SEQUENCE_FAIL = 0x14,
+
+ /* CCB length supplied is inadequate */
+ CAM_CCB_LEN_ERR = 0x15,
+
+ /* Unable to provide requested capability*/
+ CAM_PROVIDE_FAIL = 0x16,
+
+ /* A SCSI BDR msg was sent to target */
+ CAM_BDR_SENT = 0x17,
+
+ /* CCB request terminated by the host */
+ CAM_REQ_TERMIO = 0x18,
+
+ /* Unrecoverable Host Bus Adapter Error */
+ CAM_UNREC_HBA_ERROR = 0x19,
+
+ /* Request was too large for this host */
+ CAM_REQ_TOO_BIG = 0x1a,
+
+ /*
+ * 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_REQUEUE_REQ = 0x1b,
+
+ /* ATA error, look at error code in CCB */
+ CAM_ATA_STATUS_ERROR = 0x1c,
+
+ /* Initiator/Target Nexus lost. */
+ CAM_SCSI_IT_NEXUS_LOST = 0x1d,
+
+ /* SMP error, look at error code in CCB */
+ CAM_SMP_STATUS_ERROR = 0x1e,
+
+ /*
+ * Command completed without error but exceeded the soft
+ * timeout threshold.
+ */
+ CAM_REQ_SOFTTIMEOUT = 0x1f,
+
+ /*
+ * 0x20 - 0x32 are unassigned
+ */
+
+ /* Initiator Detected Error */
+ CAM_IDE = 0x33,
+
+ /* Resource Unavailable */
+ CAM_RESRC_UNAVAIL = 0x34,
+
+ /* Unacknowledged Event by Host */
+ CAM_UNACKED_EVENT = 0x35,
+
+ /* Message Received in Host Target Mode */
+ CAM_MESSAGE_RECV = 0x36,
+
+ /* Invalid CDB received in Host Target Mode */
+ CAM_INVALID_CDB = 0x37,
+
+ /* Lun supplied is invalid */
+ CAM_LUN_INVALID = 0x38,
+
+ /* Target ID supplied is invalid */
+ CAM_TID_INVALID = 0x39,
+
+ /* The requested function is not available */
+ CAM_FUNC_NOTAVAIL = 0x3a,
+
+ /* Nexus is not established */
+ CAM_NO_NEXUS = 0x3b,
+
+ /* The initiator ID is invalid */
+ CAM_IID_INVALID = 0x3c,
+
+ /* The SCSI CDB has been received */
+ CAM_CDB_RECVD = 0x3d,
+
+ /* The LUN is already enabled for target mode */
+ CAM_LUN_ALRDY_ENA = 0x3e,
+
+ /* SCSI Bus Busy */
+ CAM_SCSI_BUSY = 0x3f,
+
+
+ /*
+ * Flags
+ */
+
+ /* The DEV queue is frozen w/this err */
+ CAM_DEV_QFRZN = 0x40,
+
+ /* Autosense data valid for target */
+ CAM_AUTOSNS_VALID = 0x80,
+
+ /* SIM ready to take more commands */
+ CAM_RELEASE_SIMQ = 0x100,
+
+ /* SIM has this command in it's queue */
+ CAM_SIM_QUEUED = 0x200,
+
+ /* Quality of service data is valid */
+ CAM_QOS_VALID = 0x400,
+
+ /* Mask bits for just the status # */
+ CAM_STATUS_MASK = 0x3F,
+
+ /*
+ * Target Specific Adjunct Status
+ */
+
+ /* sent sense with status */
+ CAM_SENT_SENSE = 0x40000000
} cam_status;
typedef enum {
@@ -225,6 +346,15 @@ typedef enum {
CAM_EAF_PRINT_RESULT = 0x20
} cam_error_ata_flags;
+typedef enum {
+ CAM_STRVIS_FLAG_NONE = 0x00,
+ CAM_STRVIS_FLAG_NONASCII_MASK = 0x03,
+ CAM_STRVIS_FLAG_NONASCII_TRIM = 0x00,
+ CAM_STRVIS_FLAG_NONASCII_RAW = 0x01,
+ CAM_STRVIS_FLAG_NONASCII_SPC = 0x02,
+ CAM_STRVIS_FLAG_NONASCII_ESC = 0x03
+} cam_strvis_flags;
+
struct cam_status_entry
{
cam_status status_code;
@@ -237,6 +367,7 @@ extern const int num_cam_status_entries;
extern int cam_sort_io_queues;
#endif
union ccb;
+struct sbuf;
#ifdef SYSCTL_DECL /* from sysctl.h */
SYSCTL_DECL(_kern_cam);
@@ -249,6 +380,8 @@ 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);
+void cam_strvis_sbuf(struct sbuf *sb, const u_int8_t *src, int srclen,
+ uint32_t flags);
int cam_strmatch(const u_int8_t *str, const u_int8_t *pattern, int str_len);
const struct cam_status_entry*
diff --git a/freebsd/sys/cam/cam_ccb.h b/freebsd/sys/cam/cam_ccb.h
index 359064b6..e00b5bd3 100644
--- a/freebsd/sys/cam/cam_ccb.h
+++ b/freebsd/sys/cam/cam_ccb.h
@@ -41,7 +41,7 @@
#include <cam/cam_debug.h>
#include <cam/scsi/scsi_all.h>
#include <cam/ata/ata_all.h>
-
+#include <cam/nvme/nvme_all.h>
#ifdef __rtems__
#include <rtems/blkdev.h>
#endif /* __rtems__ */
@@ -67,7 +67,7 @@ typedef enum {
* Perform transport negotiation
* with this command.
*/
- CAM_DATA_ISPHYS = 0x00200000,/* Data type with physical addrs */
+ CAM_DATA_ISPHYS = 0x00000010,/* Data type with physical addrs */
CAM_DIS_AUTOSENSE = 0x00000020,/* Disable autosense feature */
CAM_DIR_BOTH = 0x00000000,/* Data direction (00:IN/OUT) */
CAM_DIR_IN = 0x00000040,/* Data direction (01:DATA IN) */
@@ -75,10 +75,10 @@ typedef enum {
CAM_DIR_NONE = 0x000000C0,/* Data direction (11:no data) */
CAM_DIR_MASK = 0x000000C0,/* Data direction Mask */
CAM_DATA_VADDR = 0x00000000,/* Data type (000:Virtual) */
- CAM_DATA_PADDR = 0x00200000,/* Data type (001:Physical) */
- CAM_DATA_SG = 0x00000010,/* Data type (010:sglist) */
- CAM_DATA_SG_PADDR = 0x00200010,/* Data type (011:sglist phys) */
- CAM_DATA_BIO = 0x00040000,/* Data type (100:bio) */
+ CAM_DATA_PADDR = 0x00000010,/* Data type (001:Physical) */
+ CAM_DATA_SG = 0x00040000,/* Data type (010:sglist) */
+ CAM_DATA_SG_PADDR = 0x00040010,/* Data type (011:sglist phys) */
+ CAM_DATA_BIO = 0x00200000,/* Data type (100:bio) */
CAM_DATA_MASK = 0x00240010,/* Data type mask */
CAM_SOFT_RST_OP = 0x00000100,/* Use Soft reset alternative */
CAM_ENG_SYNC = 0x00000200,/* Flush resid bytes on complete */
@@ -95,11 +95,6 @@ typedef enum {
CAM_CDB_PHYS = 0x00400000,/* CDB poiner is physical */
CAM_ENG_SGLIST = 0x00800000,/* SG list is for the HBA engine */
-/* Compatibility for FreeBSD 9.x*/
- CAM_SCATTER_VALID = 0x00000010,/* These exist for src compat for*/
- CAM_SG_LIST_PHYS = 0x00200010,/* old drivers. Hardly anything */
- CAM_DATA_PHYS = 0x00200000,/* uses them. */
-
/* Phase cognizant mode flags */
CAM_DIS_AUTOSRP = 0x01000000,/* Disable autosave/restore ptrs */
CAM_DIS_AUTODISC = 0x02000000,/* Disable auto disconnect */
@@ -113,9 +108,17 @@ typedef enum {
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 */
+ CAM_SEND_STATUS = 0x40000000,/* Send status after data phase */
+
+ CAM_UNLOCKED = 0x80000000 /* Call callback without lock. */
} ccb_flags;
+typedef enum {
+ CAM_USER_DATA_ADDR = 0x00000002,/* Userspace data pointers */
+ CAM_SG_FORMAT_IOVEC = 0x00000004,/* iovec instead of busdma S/G*/
+ CAM_UNMAPPED_BUF = 0x00000008 /* use unmapped I/O */
+} ccb_xflags;
+
/* XPT Opcodes for xpt_action */
typedef enum {
/* Function code flags are bits greater than 0xff */
@@ -156,6 +159,9 @@ typedef enum {
/* Device statistics (error counts, etc.) */
XPT_DEV_ADVINFO = 0x0e,
/* Get/Set Device advanced information */
+ XPT_ASYNC = 0x0f | XPT_FC_QUEUED | XPT_FC_USER_CCB
+ | XPT_FC_XPT_ONLY,
+ /* Asynchronous event */
/* SCSI Control Functions: 0x10->0x1F */
XPT_ABORT = 0x10,
/* Abort the specified CCB */
@@ -187,19 +193,27 @@ typedef enum {
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_GET_SIM_KNOB_OLD = 0x18, /* Compat only */
XPT_SET_SIM_KNOB = 0x19,
/*
* Set SIM specific knob values.
*/
+ XPT_GET_SIM_KNOB = 0x1a,
+ /*
+ * Get SIM specific knob values.
+ */
+
XPT_SMP_IO = 0x1b | XPT_FC_DEV_QUEUED,
/* Serial Management Protocol */
+ XPT_NVME_IO = 0x1c | XPT_FC_DEV_QUEUED,
+ /* Execiute the requestred NVMe I/O operation */
+
+ XPT_MMCSD_IO = 0x1d | XPT_FC_DEV_QUEUED,
+ /* Placeholder for MMC / SD / SDIO I/O stuff */
+
XPT_SCAN_TGT = 0x1E | XPT_FC_QUEUED | XPT_FC_USER_CCB
| XPT_FC_XPT_ONLY,
/* Scan Target */
@@ -227,6 +241,8 @@ typedef enum {
/* Notify Host Target driver of event */
XPT_NOTIFY_ACKNOWLEDGE = 0x37 | XPT_FC_QUEUED | XPT_FC_USER_CCB,
/* Acknowledgement of event */
+ XPT_REPROBE_LUN = 0x38 | XPT_FC_QUEUED | XPT_FC_USER_CCB,
+ /* Query device capacity and notify GEOM */
/* Vendor Unique codes: 0x80->0x8F */
XPT_VUNIQUE = 0x80
@@ -253,6 +269,7 @@ typedef enum {
PROTO_ATAPI, /* AT Attachment Packetized Interface */
PROTO_SATAPM, /* SATA Port Multiplier */
PROTO_SEMB, /* SATA Enclosure Management Bridge */
+ PROTO_NVME, /* NVME */
} cam_proto;
typedef enum {
@@ -267,12 +284,15 @@ typedef enum {
XPORT_SAS, /* Serial Attached SCSI */
XPORT_SATA, /* Serial AT Attachment */
XPORT_ISCSI, /* iSCSI */
+ XPORT_SRP, /* SCSI RDMA Protocol */
+ XPORT_NVME, /* NVMe over PCIe */
} cam_xport;
+#define XPORT_IS_NVME(t) ((t) == XPORT_NVME)
#define XPORT_IS_ATA(t) ((t) == XPORT_ATA || (t) == XPORT_SATA)
#define XPORT_IS_SCSI(t) ((t) != XPORT_UNKNOWN && \
(t) != XPORT_UNSPECIFIED && \
- !XPORT_IS_ATA(t))
+ !XPORT_IS_ATA(t) && !XPORT_IS_NVME(t))
#define XPORT_DEVSTAT_TYPE(t) (XPORT_IS_ATA(t) ? DEVSTAT_TYPE_IF_IDE : \
XPORT_IS_SCSI(t) ? DEVSTAT_TYPE_IF_SCSI : \
DEVSTAT_TYPE_IF_OTHER)
@@ -305,6 +325,12 @@ typedef union {
u_int8_t bytes[CCB_SIM_PRIV_SIZE * sizeof(ccb_priv_entry)];
} ccb_spriv_area;
+typedef struct {
+ struct timeval *etime;
+ uintptr_t sim_data;
+ uintptr_t periph_data;
+} ccb_qos_area;
+
struct ccb_hdr {
#ifndef __rtems__
cam_pinfo pinfo; /* Info for priority scheduling */
@@ -326,18 +352,15 @@ struct ccb_hdr {
target_id_t target_id; /* Target device ID */
lun_id_t target_lun; /* Target LUN number */
u_int32_t flags; /* ccb_flags */
+ u_int32_t xflags; /* Extended flags */
#ifndef __rtems__
ccb_ppriv_area periph_priv;
ccb_spriv_area sim_priv;
+ ccb_qos_area qos;
#endif /* __rtems__ */
- u_int32_t timeout; /* Timeout value */
-
+ u_int32_t timeout; /* Hard timeout value in mseconds */
#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;
+ struct timeval softtimeout; /* Soft timeout value in sec + usec */
#endif /* __rtems__ */
};
@@ -350,6 +373,8 @@ struct ccb_getdev {
u_int8_t serial_num[252];
u_int8_t inq_flags;
u_int8_t serial_num_len;
+ const struct nvme_controller_data *nvme_cdata;
+ const struct nvme_namespace_data *nvme_data;
};
/* Device Statistics CCB */
@@ -357,8 +382,8 @@ 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 allocated; /* CCBs allocated for the device */
+ int queued; /* CCBs queued to be sent to the device */
int held; /*
* CCBs held by peripheral drivers
* for this device
@@ -560,7 +585,7 @@ struct ccb_dev_match {
/*
* Definitions for the path inquiry CCB fields.
*/
-#define CAM_VERSION 0x17 /* Hex value for current version */
+#define CAM_VERSION 0x19 /* Hex value for current version */
typedef enum {
PI_MDP_ABLE = 0x80, /* Supports MDP message */
@@ -583,6 +608,8 @@ typedef enum {
} pi_tmflag;
typedef enum {
+ PIM_ATA_EXT = 0x200,/* ATA requests can understand ata_ext requests */
+ PIM_EXTLUNS = 0x100,/* 64bit extended LUNs supported */
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. */
@@ -608,14 +635,19 @@ struct ccb_pathinq_settings_fc {
struct ccb_pathinq_settings_sas {
u_int32_t bitrate; /* Mbps */
};
+
+struct ccb_pathinq_settings_nvme {
+ uint16_t nsid; /* Namespace ID for this path */
+};
+
#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 target_sprt; /* Flags for target mode support */
+ u_int32_t hba_misc; /* Misc HBA features */
u_int16_t hba_eng_cnt; /* HBA engine count */
/* Vendor Unique capabilities */
u_int8_t vuhba_flags[VUHBALEN];
@@ -638,6 +670,7 @@ struct ccb_pathinq {
struct ccb_pathinq_settings_spi spi;
struct ccb_pathinq_settings_fc fc;
struct ccb_pathinq_settings_sas sas;
+ struct ccb_pathinq_settings_nvme nvme;
char ccb_pathinq_settings_opaque[PATHINQ_SETTINGS_SIZE];
} xport_specific;
u_int maxio; /* Max supported I/O size, in bytes. */
@@ -732,6 +765,13 @@ struct ccb_scsiio {
#endif /* __rtems__ */
};
+static __inline uint8_t *
+scsiio_cdb_ptr(struct ccb_scsiio *ccb)
+{
+ return ((ccb->ccb_h.flags & CAM_CDB_POINTER) ?
+ ccb->cdb_io.cdb_ptr : ccb->cdb_io.cdb_bytes);
+}
+
/*
* ATA I/O Request CCB used for the XPT_ATA_IO function code.
*/
@@ -743,15 +783,10 @@ struct ccb_ataio {
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 */
+ u_int8_t ata_flags; /* Flags for the rest of the buffer */
+#define ATA_FLAG_AUX 0x1
+ uint32_t aux;
+ uint32_t unused;
};
struct ccb_accept_tio {
@@ -779,6 +814,19 @@ struct ccb_relsim {
};
/*
+ * NVMe I/O Request CCB used for the XPT_NVME_IO function code.
+ */
+struct ccb_nvmeio {
+ struct ccb_hdr ccb_h;
+ union ccb *next_ccb; /* Ptr for next CCB for action */
+ struct nvme_command cmd; /* NVME command, per NVME standard */
+ struct nvme_completion cpl; /* NVME completion, per NVME standard */
+ uint8_t *data_ptr; /* Ptr to the data buf/SG list */
+ uint32_t dxfer_len; /* Data transfer length */
+ uint32_t resid; /* Transfer residual length: 2's comp unused ?*/
+};
+
+/*
* Definitions for the asynchronous callback CCB fields.
*/
typedef enum {
@@ -959,6 +1007,18 @@ struct ccb_trans_settings_sata {
#define CTS_SATA_CAPS_D_APST 0x00020000
};
+struct ccb_trans_settings_nvme
+{
+ u_int valid; /* Which fields to honor */
+#define CTS_NVME_VALID_SPEC 0x01
+#define CTS_NVME_VALID_CAPS 0x02
+ u_int spec_major; /* Major version of spec supported */
+ u_int spec_minor; /* Minor verison of spec supported */
+ u_int spec_tiny; /* Tiny version of spec supported */
+ u_int max_xfer; /* Max transfer size (0 -> unlimited */
+ u_int caps;
+};
+
/* Get/Set transfer rate/width/disconnection/tag queueing settings */
struct ccb_trans_settings {
struct ccb_hdr ccb_h;
@@ -971,6 +1031,7 @@ struct ccb_trans_settings {
u_int valid; /* Which fields to honor */
struct ccb_trans_settings_ata ata;
struct ccb_trans_settings_scsi scsi;
+ struct ccb_trans_settings_nvme nvme;
} proto_specific;
union {
u_int valid; /* Which fields to honor */
@@ -979,6 +1040,7 @@ struct ccb_trans_settings {
struct ccb_trans_settings_sas sas;
struct ccb_trans_settings_pata ata;
struct ccb_trans_settings_sata sata;
+ struct ccb_trans_settings_nvme nvme;
} xport_specific;
};
@@ -1093,7 +1155,17 @@ struct ccb_notify_acknowledge {
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 */
+ u_int arg; /* Response information */
+ /*
+ * Lower byte of arg is one of RESPONSE CODE values defined below
+ * (subset of response codes from SPL-4 and FCP-4 specifications),
+ * upper 3 bytes is code-specific ADDITIONAL RESPONSE INFORMATION.
+ */
+#define CAM_RSP_TMF_COMPLETE 0x00
+#define CAM_RSP_TMF_REJECTED 0x04
+#define CAM_RSP_TMF_FAILED 0x05
+#define CAM_RSP_TMF_SUCCEEDED 0x08
+#define CAM_RSP_TMF_INCORRECT_LUN 0x09
};
/* HBA engine structures. */
@@ -1159,6 +1231,7 @@ struct ccb_eng_exec { /* This structure must match SCSIIO size */
struct ccb_dev_advinfo {
struct ccb_hdr ccb_h;
uint32_t flags;
+#define CDAI_FLAG_NONE 0x0 /* No flags set */
#define CDAI_FLAG_STORE 0x1 /* If set, action becomes store */
uint32_t buftype; /* IN: Type of data being requested */
/* NB: buftype is interpreted on a per-transport basis */
@@ -1166,6 +1239,7 @@ struct ccb_dev_advinfo {
#define CDAI_TYPE_SERIAL_NUM 2
#define CDAI_TYPE_PHYS_PATH 3
#define CDAI_TYPE_RCAPLONG 4
+#define CDAI_TYPE_EXT_INQ 5
off_t bufsiz; /* IN: Size of external buffer */
#define CAM_SCSI_DEVID_MAXLEN 65536 /* length in buffer is an uint16_t */
off_t provsiz; /* OUT: Size required/used */
@@ -1173,6 +1247,16 @@ struct ccb_dev_advinfo {
};
/*
+ * CCB for sending async events
+ */
+struct ccb_async {
+ struct ccb_hdr ccb_h;
+ uint32_t async_code;
+ off_t async_arg_size;
+ void *async_arg_ptr;
+};
+
+/*
* 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
@@ -1211,8 +1295,14 @@ union ccb {
struct ccb_debug cdbg;
struct ccb_ataio ataio;
struct ccb_dev_advinfo cdai;
+ struct ccb_async casync;
+ struct ccb_nvmeio nvmeio;
};
+#define CCB_CLEAR_ALL_EXCEPT_HDR(ccbp) \
+ bzero((char *)(ccbp) + sizeof((ccbp)->ccb_h), \
+ sizeof(*(ccbp)) - sizeof((ccbp)->ccb_h))
+
__BEGIN_DECLS
static __inline void
cam_fill_csio(struct ccb_scsiio *csio, u_int32_t retries,
@@ -1223,6 +1313,12 @@ cam_fill_csio(struct ccb_scsiio *csio, u_int32_t retries,
u_int32_t timeout);
static __inline void
+cam_fill_nvmeio(struct ccb_nvmeio *nvmeio, u_int32_t retries,
+ void (*cbfcnp)(struct cam_periph *, union ccb *),
+ u_int32_t flags, u_int8_t *data_ptr, u_int32_t dxfer_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,
@@ -1253,6 +1349,7 @@ cam_fill_csio(struct ccb_scsiio *csio, u_int32_t retries,
{
csio->ccb_h.func_code = XPT_SCSI_IO;
csio->ccb_h.flags = flags;
+ csio->ccb_h.xflags = 0;
csio->ccb_h.retry_count = retries;
csio->ccb_h.cbfcnp = cbfcnp;
csio->ccb_h.timeout = timeout;
@@ -1272,6 +1369,7 @@ cam_fill_ctio(struct ccb_scsiio *csio, u_int32_t retries,
{
csio->ccb_h.func_code = XPT_CONT_TARGET_IO;
csio->ccb_h.flags = flags;
+ csio->ccb_h.xflags = 0;
csio->ccb_h.retry_count = retries;
csio->ccb_h.cbfcnp = cbfcnp;
csio->ccb_h.timeout = timeout;
@@ -1286,7 +1384,7 @@ cam_fill_ctio(struct ccb_scsiio *csio, u_int32_t retries,
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_int32_t flags, u_int tag_action __unused,
u_int8_t *data_ptr, u_int32_t dxfer_len,
u_int32_t timeout)
{
@@ -1297,7 +1395,7 @@ cam_fill_ataio(struct ccb_ataio *ataio, u_int32_t retries,
ataio->ccb_h.timeout = timeout;
ataio->data_ptr = data_ptr;
ataio->dxfer_len = dxfer_len;
- ataio->tag_action = tag_action;
+ ataio->ata_flags = 0;
}
static __inline void
@@ -1341,6 +1439,20 @@ cam_ccb_status(union ccb *ccb)
void cam_calc_geometry(struct ccb_calc_geometry *ccg, int extended);
+static __inline void
+cam_fill_nvmeio(struct ccb_nvmeio *nvmeio, u_int32_t retries,
+ void (*cbfcnp)(struct cam_periph *, union ccb *),
+ u_int32_t flags, u_int8_t *data_ptr, u_int32_t dxfer_len,
+ u_int32_t timeout)
+{
+ nvmeio->ccb_h.func_code = XPT_NVME_IO;
+ nvmeio->ccb_h.flags = flags;
+ nvmeio->ccb_h.retry_count = retries;
+ nvmeio->ccb_h.cbfcnp = cbfcnp;
+ nvmeio->ccb_h.timeout = timeout;
+ nvmeio->data_ptr = data_ptr;
+ nvmeio->dxfer_len = dxfer_len;
+}
__END_DECLS
#endif /* _CAM_CAM_CCB_H */
diff --git a/freebsd/sys/cam/cam_periph.h b/freebsd/sys/cam/cam_periph.h
index a58ec947..e28d5b11 100644
--- a/freebsd/sys/cam/cam_periph.h
+++ b/freebsd/sys/cam/cam_periph.h
@@ -35,6 +35,7 @@
#include <cam/cam_sim.h>
#ifdef _KERNEL
+#include <sys/taskqueue.h>
#include <cam/cam_xpt.h>
@@ -90,7 +91,7 @@ typedef enum {
CAM_PERIPH_BIO
} cam_periph_type;
-/* Generically usefull offsets into the peripheral private area */
+/* Generically useful 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
@@ -103,7 +104,6 @@ typedef cam_status periph_ctor_t (struct cam_periph *periph,
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;
@@ -120,15 +120,20 @@ struct cam_periph {
#define CAM_PERIPH_INVALID 0x08
#define CAM_PERIPH_NEW_DEV_FOUND 0x10
#define CAM_PERIPH_RECOVERY_INPROG 0x20
+#define CAM_PERIPH_RUN_TASK 0x40
#define CAM_PERIPH_FREE 0x80
#define CAM_PERIPH_ANNOUNCED 0x100
- u_int32_t immediate_priority;
+ uint32_t scheduled_priority;
+ uint32_t immediate_priority;
+ int periph_allocating;
+ int periph_allocated;
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;
+ struct task periph_run_task;
};
#define CAM_PERIPH_MAXMAPS 2
@@ -147,6 +152,7 @@ cam_status cam_periph_alloc(periph_ctor_t *periph_ctor,
struct cam_periph *cam_periph_find(struct cam_path *path, char *name);
int cam_periph_list(struct cam_path *, struct sbuf *);
cam_status cam_periph_acquire(struct cam_periph *periph);
+void cam_periph_doacquire(struct cam_periph *periph);
void cam_periph_release(struct cam_periph *periph);
void cam_periph_release_locked(struct cam_periph *periph);
void cam_periph_release_locked_buses(struct cam_periph *periph);
@@ -154,7 +160,8 @@ 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);
+ struct cam_periph_map_info *mapinfo,
+ u_int maxmap);
void cam_periph_unmapmem(union ccb *ccb,
struct cam_periph_map_info *mapinfo);
union ccb *cam_periph_getccb(struct cam_periph *periph,
@@ -185,30 +192,26 @@ void cam_periph_freeze_after_event(struct cam_periph *periph,
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)
+static __inline struct mtx *
+cam_periph_mtx(struct cam_periph *periph)
{
- mtx_lock(periph->sim->mtx);
+ return (xpt_path_mtx(periph->path));
}
-static __inline void
-cam_periph_unlock(struct cam_periph *periph)
-{
- mtx_unlock(periph->sim->mtx);
-}
+#define cam_periph_owned(periph) \
+ mtx_owned(xpt_path_mtx((periph)->path))
-static __inline int
-cam_periph_owned(struct cam_periph *periph)
-{
- return (mtx_owned(periph->sim->mtx));
-}
+#define cam_periph_lock(periph) \
+ mtx_lock(xpt_path_mtx((periph)->path))
-static __inline int
-cam_periph_sleep(struct cam_periph *periph, void *chan, int priority,
- const char *wmesg, int timo)
-{
- return (msleep(chan, periph->sim->mtx, priority, wmesg, timo));
-}
+#define cam_periph_unlock(periph) \
+ mtx_unlock(xpt_path_mtx((periph)->path))
+
+#define cam_periph_assert(periph, what) \
+ mtx_assert(xpt_path_mtx((periph)->path), (what))
+
+#define cam_periph_sleep(periph, chan, priority, wmesg, timo) \
+ xpt_path_sleep((periph)->path, (chan), (priority), (wmesg), (timo))
static inline struct cam_periph *
cam_periph_acquire_first(struct periph_driver *driver)
@@ -230,7 +233,7 @@ cam_periph_acquire_next(struct cam_periph *pperiph)
{
struct cam_periph *periph = pperiph;
- mtx_assert(pperiph->sim->mtx, MA_NOTOWNED);
+ cam_periph_assert(pperiph, MA_NOTOWNED);
xpt_lock_buses();
do {
periph = TAILQ_NEXT(periph, unit_links);
diff --git a/freebsd/sys/cam/cam_sim.h b/freebsd/sys/cam/cam_sim.h
index ba0ac18f..7309e97c 100644
--- a/freebsd/sys/cam/cam_sim.h
+++ b/freebsd/sys/cam/cam_sim.h
@@ -145,24 +145,10 @@ struct cam_sim {
u_int32_t flags;
#define CAM_SIM_REL_TIMEOUT_PENDING 0x01
#define CAM_SIM_MPSAFE 0x02
-#define CAM_SIM_ON_DONEQ 0x04
-#define CAM_SIM_POLLED 0x08
-#define CAM_SIM_BATCH 0x10
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)
diff --git a/freebsd/sys/cam/cam_xpt.h b/freebsd/sys/cam/cam_xpt.h
index 97933b98..ba5c924a 100644
--- a/freebsd/sys/cam/cam_xpt.h
+++ b/freebsd/sys/cam/cam_xpt.h
@@ -56,6 +56,7 @@ struct cam_path;
struct async_node {
SLIST_ENTRY(async_node) links;
u_int32_t event_enable; /* Async Event enables */
+ u_int32_t event_lock; /* Take SIM lock for handlers. */
void (*callback)(void *arg, u_int32_t code,
struct cam_path *path, void *args);
void *callback_arg;
@@ -69,6 +70,10 @@ 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_flags(struct ccb_hdr *ccb_h,
+ struct cam_path *path,
+ u_int32_t priority,
+ u_int32_t flags);
void xpt_setup_ccb(struct ccb_hdr *ccb_h,
struct cam_path *path,
u_int32_t priority);
@@ -100,7 +105,6 @@ int xpt_path_string(struct cam_path *path, char *str,
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);
-int xpt_path_legacy_ata_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,
@@ -110,6 +114,13 @@ void xpt_hold_boot(void);
void xpt_release_boot(void);
void xpt_lock_buses(void);
void xpt_unlock_buses(void);
+struct mtx * xpt_path_mtx(struct cam_path *path);
+#define xpt_path_lock(path) mtx_lock(xpt_path_mtx(path))
+#define xpt_path_unlock(path) mtx_unlock(xpt_path_mtx(path))
+#define xpt_path_assert(path, what) mtx_assert(xpt_path_mtx(path), (what))
+#define xpt_path_owned(path) mtx_owned(xpt_path_mtx(path))
+#define xpt_path_sleep(path, chan, priority, wmesg, timo) \
+ msleep((chan), xpt_path_mtx(path), (priority), (wmesg), (timo))
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,
@@ -117,6 +128,10 @@ cam_status xpt_compile_path(struct cam_path *new_path,
path_id_t path_id,
target_id_t target_id,
lun_id_t lun_id);
+cam_status xpt_clone_path(struct cam_path **new_path,
+ struct cam_path *path);
+void xpt_copy_path(struct cam_path *new_path,
+ struct cam_path *path);
void xpt_release_path(struct cam_path *path);
diff --git a/freebsd/sys/cam/cam_xpt_sim.h b/freebsd/sys/cam/cam_xpt_sim.h
index 62ded090..c3575deb 100644
--- a/freebsd/sys/cam/cam_xpt_sim.h
+++ b/freebsd/sys/cam/cam_xpt_sim.h
@@ -49,10 +49,8 @@ u_int32_t xpt_freeze_devq(struct cam_path *path, u_int count);
#endif /* __rtems__ */
void xpt_release_devq(struct cam_path *path,
u_int count, int run_queue);
-int xpt_sim_opened(struct cam_sim *sim);
void xpt_done(union ccb *done_ccb);
-void xpt_batch_start(struct cam_sim *sim);
-void xpt_batch_done(struct cam_sim *sim);
+void xpt_done_direct(union ccb *done_ccb);
#endif
#endif /* _CAM_CAM_XPT_SIM_H */
diff --git a/freebsd/sys/cam/nvme/nvme_all.h b/freebsd/sys/cam/nvme/nvme_all.h
new file mode 100644
index 00000000..3cff74d3
--- /dev/null
+++ b/freebsd/sys/cam/nvme/nvme_all.h
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 2015 Netflix, Inc
+ * 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_NVME_NVME_ALL_H
+#define CAM_NVME_NVME_ALL_H 1
+
+#include <dev/nvme/nvme.h>
+
+struct ccb_nvmeio;
+
+#define NVME_REV_1 1 /* Supports NVMe 1.2 or earlier */
+
+void nvme_ns_cmd(struct ccb_nvmeio *nvmeio, uint8_t cmd, uint32_t nsid,
+ uint32_t cdw10, uint32_t cdw11, uint32_t cdw12, uint32_t cdw13,
+ uint32_t cdw14, uint32_t cdw15);
+
+int nvme_identify_match(caddr_t identbuffer, caddr_t table_entry);
+
+void nvme_print_ident(const struct nvme_controller_data *, const struct nvme_namespace_data *);
+const char *nvme_op_string(const struct nvme_command *);
+const char *nvme_cmd_string(const struct nvme_command *, char *, size_t);
+
+#endif /* CAM_NVME_NVME_ALL_H */
diff --git a/freebsd/sys/cam/scsi/scsi_all.c b/freebsd/sys/cam/scsi/scsi_all.c
index 7bb0425d..0cb7118a 100644
--- a/freebsd/sys/cam/scsi/scsi_all.c
+++ b/freebsd/sys/cam/scsi/scsi_all.c
@@ -50,11 +50,13 @@ __FBSDID("$FreeBSD$");
#include <sys/malloc.h>
#include <sys/mutex.h>
#include <sys/sysctl.h>
+#include <sys/ctype.h>
#else
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <ctype.h>
#endif
#include <cam/cam.h>
@@ -116,6 +118,7 @@ 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);
@@ -159,7 +162,7 @@ static struct scsi_op_quirk_entry scsi_op_quirk_table[] = {
* 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),
+ nitems(plextor_cd_ops),
plextor_cd_ops
}
};
@@ -180,7 +183,7 @@ static struct op_table_entry scsi_op_codes[] = {
*
* SCSI Operation Codes
* Numeric Sorted Listing
- * as of 3/11/08
+ * as of 5/26/15
*
* D - DIRECT ACCESS DEVICE (SBC-2) device column key
* .T - SEQUENTIAL ACCESS DEVICE (SSC-2) -----------------
@@ -478,7 +481,8 @@ static struct op_table_entry scsi_op_codes[] = {
*/
/* 88 MM O O O READ(16) */
{ 0x88, D | T | W | O | B, "READ(16)" },
- /* 89 */
+ /* 89 O COMPARE AND WRITE*/
+ { 0x89, D, "COMPARE AND WRITE" },
/* 8A OM O O O WRITE(16) */
{ 0x8A, D | T | W | O | B, "WRITE(16)" },
/* 8B O ORWRITE */
@@ -505,20 +509,25 @@ static struct op_table_entry scsi_op_codes[] = {
{ 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] */
+ /* 94 O ZBC OUT */
+ { 0x94, ALL, "ZBC OUT" },
+ /* 95 O ZBC IN */
+ { 0x95, ALL, "ZBC IN" },
+ /* 96 */
+ /* 97 */
/* 98 */
/* 99 */
- /* 9A */
- /* 9B */
- /* 9C */
- /* 9D */
+ /* 9A O WRITE STREAM(16) */
+ { 0x9A, D, "WRITE STREAM(16)" },
+ /* 9B OOOOOOOOOO OOO READ BUFFER(16) */
+ { 0x9B, ALL & ~(B) , "READ BUFFER(16)" },
+ /* 9C O WRITE ATOMIC(16) */
+ { 0x9C, D, "WRITE ATOMIC(16)" },
+ /* 9D SERVICE ACTION BIDIRECTIONAL */
+ { 0x9D, ALL, "SERVICE ACTION BIDIRECTIONAL" },
/* 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 */
@@ -643,8 +652,7 @@ scsi_op_desc(u_int16_t opcode, struct scsi_inquiry_data *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),
+ nitems(scsi_op_quirk_table),
sizeof(*scsi_op_quirk_table),
scsi_inquiry_match);
}
@@ -653,7 +661,7 @@ scsi_op_desc(u_int16_t opcode, struct scsi_inquiry_data *inq_data)
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_ops[1] = nitems(scsi_op_codes);
num_tables = 2;
} else {
/*
@@ -664,7 +672,7 @@ scsi_op_desc(u_int16_t opcode, struct scsi_inquiry_data *inq_data)
return("Vendor Specific Command");
table[0] = scsi_op_codes;
- num_ops[0] = sizeof(scsi_op_codes)/sizeof(scsi_op_codes[0]);
+ num_ops[0] = nitems(scsi_op_codes);
num_tables = 1;
}
@@ -672,6 +680,12 @@ scsi_op_desc(u_int16_t opcode, struct scsi_inquiry_data *inq_data)
if (pd_type == T_RBC)
pd_type = T_DIRECT;
+ /*
+ * Host managed drives are direct access for the most part.
+ */
+ if (pd_type == T_ZBC_HM)
+ pd_type = T_DIRECT;
+
/* Map NODEVICE to Direct Access Device to handle REPORT LUNS, etc. */
if (pd_type == T_NODEVICE)
pd_type = T_DIRECT;
@@ -735,9 +749,6 @@ const struct sense_key_table_entry sense_key_table[] =
{ SSD_KEY_COMPLETED, SS_NOP, "COMPLETED" }
};
-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") }
@@ -922,7 +933,7 @@ static struct scsi_sense_quirk_entry sense_quirk_table[] = {
*/
{T_DIRECT, SIP_MEDIA_FIXED, "QUANTUM", "FIREBALL S*", "*"},
/*num_sense_keys*/0,
- sizeof(quantum_fireball_entries)/sizeof(struct asc_table_entry),
+ nitems(quantum_fireball_entries),
/*sense key entries*/NULL,
quantum_fireball_entries
},
@@ -933,7 +944,7 @@ static struct scsi_sense_quirk_entry sense_quirk_table[] = {
*/
{T_DIRECT, SIP_MEDIA_REMOVABLE, "SONY", "SMO-*", "*"},
/*num_sense_keys*/0,
- sizeof(sony_mo_entries)/sizeof(struct asc_table_entry),
+ nitems(sony_mo_entries),
/*sense key entries*/NULL,
sony_mo_entries
},
@@ -943,7 +954,7 @@ static struct scsi_sense_quirk_entry sense_quirk_table[] = {
*/
{T_DIRECT, SIP_MEDIA_FIXED, "HGST", "*", "*"},
/*num_sense_keys*/0,
- sizeof(hgst_entries)/sizeof(struct asc_table_entry),
+ nitems(hgst_entries),
/*sense key entries*/NULL,
hgst_entries
},
@@ -953,14 +964,13 @@ static struct scsi_sense_quirk_entry sense_quirk_table[] = {
*/
{T_DIRECT, SIP_MEDIA_FIXED, "SEAGATE", "*", "*"},
/*num_sense_keys*/0,
- sizeof(seagate_entries)/sizeof(struct asc_table_entry),
+ nitems(seagate_entries),
/*sense key entries*/NULL,
seagate_entries
}
};
-const int sense_quirk_table_size =
- sizeof(sense_quirk_table)/sizeof(sense_quirk_table[0]);
+const u_int sense_quirk_table_size = nitems(sense_quirk_table);
static struct asc_table_entry asc_table[] = {
/*
@@ -972,7 +982,7 @@ static struct asc_table_entry asc_table[] = {
*
* SCSI ASC/ASCQ Assignments
* Numeric Sorted Listing
- * as of 5/20/12
+ * as of 8/12/15
*
* D - DIRECT ACCESS DEVICE (SBC-2) device column key
* .T - SEQUENTIAL ACCESS DEVICE (SSC) -------------------
@@ -1064,6 +1074,9 @@ static struct asc_table_entry asc_table[] = {
/* DT P B */
{ SST(0x00, 0x20, SS_RDEF, /* XXX TBD */
"Extended copy information available") },
+ /* D */
+ { SST(0x00, 0x21, SS_RDEF, /* XXX TBD */
+ "Atomic command aborted due to ACA") },
/* D W O BK */
{ SST(0x01, 0x00, SS_RDEF,
"No index/sector signal") },
@@ -1083,7 +1096,7 @@ static struct asc_table_entry asc_table[] = {
{ SST(0x04, 0x00, SS_RDEF,
"Logical unit not ready, cause not reportable") },
/* DTLPWROMAEBKVF */
- { SST(0x04, 0x01, SS_TUR | SSQ_MANY | SSQ_DECREMENT_COUNT | EBUSY,
+ { SST(0x04, 0x01, SS_WAIT | EBUSY,
"Logical unit is in process of becoming ready") },
/* DTLPWROMAEBKVF */
{ SST(0x04, 0x02, SS_START | SSQ_DECREMENT_COUNT | ENXIO,
@@ -1110,7 +1123,7 @@ static struct asc_table_entry asc_table[] = {
{ SST(0x04, 0x09, SS_RDEF, /* XXX TBD */
"Logical unit not ready, self-test in progress") },
/* DTLPWROMAEBKVF */
- { SST(0x04, 0x0A, SS_TUR | SSQ_MANY | SSQ_DECREMENT_COUNT | ENXIO,
+ { SST(0x04, 0x0A, SS_WAIT | ENXIO,
"Logical unit not accessible, asymmetric access state transition")},
/* DTLPWROMAEBKVF */
{ SST(0x04, 0x0B, SS_FATAL | ENXIO,
@@ -1121,11 +1134,14 @@ static struct asc_table_entry asc_table[] = {
/* F */
{ SST(0x04, 0x0D, SS_RDEF, /* XXX TBD */
"Logical unit not ready, structure check required") },
+ /* DTL WR MAEBKVF */
+ { SST(0x04, 0x0E, SS_RDEF, /* XXX TBD */
+ "Logical unit not ready, security session in progress") },
/* 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_TUR | SSQ_MANY | SSQ_DECREMENT_COUNT | EBUSY,
+ { SST(0x04, 0x11, SS_WAIT | EBUSY,
"Logical unit not ready, notify (enable spinup) required") },
/* M V */
{ SST(0x04, 0x12, SS_RDEF, /* XXX TBD */
@@ -1160,6 +1176,24 @@ static struct asc_table_entry asc_table[] = {
/* DT MAEB */
{ SST(0x04, 0x1C, SS_RDEF, /* XXX TBD */
"Logical unit not ready, additional power use not yet granted") },
+ /* D */
+ { SST(0x04, 0x1D, SS_RDEF, /* XXX TBD */
+ "Logical unit not ready, configuration in progress") },
+ /* D */
+ { SST(0x04, 0x1E, SS_FATAL | ENXIO,
+ "Logical unit not ready, microcode activation required") },
+ /* DTLPWROMAEBKVF */
+ { SST(0x04, 0x1F, SS_FATAL | ENXIO,
+ "Logical unit not ready, microcode download required") },
+ /* DTLPWROMAEBKVF */
+ { SST(0x04, 0x20, SS_RDEF, /* XXX TBD */
+ "Logical unit not ready, logical unit reset required") },
+ /* DTLPWROMAEBKVF */
+ { SST(0x04, 0x21, SS_RDEF, /* XXX TBD */
+ "Logical unit not ready, hard reset required") },
+ /* DTLPWROMAEBKVF */
+ { SST(0x04, 0x22, SS_RDEF, /* XXX TBD */
+ "Logical unit not ready, power cycle required") },
/* DTL WROMAEBKVF */
{ SST(0x05, 0x00, SS_RDEF,
"Logical unit does not respond to selection") },
@@ -1199,6 +1233,9 @@ static struct asc_table_entry asc_table[] = {
/* DT WRO B */
{ SST(0x09, 0x04, SS_RDEF,
"Head select fault") },
+ /* DT RO B */
+ { SST(0x09, 0x05, SS_RDEF,
+ "Vibration induced tracking error") },
/* DTLPWROMAEBKVF */
{ SST(0x0A, 0x00, SS_FATAL | ENOSPC,
"Error log overflow") },
@@ -1232,6 +1269,30 @@ static struct asc_table_entry asc_table[] = {
/* D */
{ SST(0x0B, 0x09, SS_RDEF, /* XXX TBD */
"Warning - device statistics notification available") },
+ /* DTLPWROMAEBKVF */
+ { SST(0x0B, 0x0A, SS_RDEF, /* XXX TBD */
+ "Warning - High critical temperature limit exceeded") },
+ /* DTLPWROMAEBKVF */
+ { SST(0x0B, 0x0B, SS_RDEF, /* XXX TBD */
+ "Warning - Low critical temperature limit exceeded") },
+ /* DTLPWROMAEBKVF */
+ { SST(0x0B, 0x0C, SS_RDEF, /* XXX TBD */
+ "Warning - High operating temperature limit exceeded") },
+ /* DTLPWROMAEBKVF */
+ { SST(0x0B, 0x0D, SS_RDEF, /* XXX TBD */
+ "Warning - Low operating temperature limit exceeded") },
+ /* DTLPWROMAEBKVF */
+ { SST(0x0B, 0x0E, SS_RDEF, /* XXX TBD */
+ "Warning - High citical humidity limit exceeded") },
+ /* DTLPWROMAEBKVF */
+ { SST(0x0B, 0x0F, SS_RDEF, /* XXX TBD */
+ "Warning - Low citical humidity limit exceeded") },
+ /* DTLPWROMAEBKVF */
+ { SST(0x0B, 0x10, SS_RDEF, /* XXX TBD */
+ "Warning - High operating humidity limit exceeded") },
+ /* DTLPWROMAEBKVF */
+ { SST(0x0B, 0x11, SS_RDEF, /* XXX TBD */
+ "Warning - Low operating humidity limit exceeded") },
/* T R */
{ SST(0x0C, 0x00, SS_RDEF,
"Write error") },
@@ -1280,6 +1341,15 @@ static struct asc_table_entry asc_table[] = {
/* R */
{ SST(0x0C, 0x0F, SS_RDEF, /* XXX TBD */
"Defects in error window") },
+ /* D */
+ { SST(0x0C, 0x10, SS_RDEF, /* XXX TBD */
+ "Incomplete multiple atomic write operations") },
+ /* D */
+ { SST(0x0C, 0x11, SS_RDEF, /* XXX TBD */
+ "Write error - recovery scan needed") },
+ /* D */
+ { SST(0x0C, 0x12, SS_RDEF, /* XXX TBD */
+ "Write error - insufficient zone resources") },
/* DTLPWRO A K */
{ SST(0x0D, 0x00, SS_RDEF, /* XXX TBD */
"Error detected by third party temporary initiator") },
@@ -1391,6 +1461,9 @@ static struct asc_table_entry asc_table[] = {
/* D */
{ SST(0x11, 0x14, SS_RDEF, /* XXX TBD */
"Read error - LBA marked bad by application client") },
+ /* D */
+ { SST(0x11, 0x15, SS_RDEF, /* XXX TBD */
+ "Write after sanitize required") },
/* D W O BK */
{ SST(0x12, 0x00, SS_RDEF,
"Address mark not found for ID field") },
@@ -1593,40 +1666,52 @@ static struct asc_table_entry asc_table[] = {
{ SST(0x21, 0x03, SS_RDEF, /* XXX TBD */
"Invalid write crossing layer jump") },
/* D */
+ { SST(0x21, 0x04, SS_RDEF, /* XXX TBD */
+ "Unaligned write command") },
+ /* D */
+ { SST(0x21, 0x05, SS_RDEF, /* XXX TBD */
+ "Write boundary violation") },
+ /* D */
+ { SST(0x21, 0x06, SS_RDEF, /* XXX TBD */
+ "Attempt to read invalid data") },
+ /* D */
+ { SST(0x21, 0x07, SS_RDEF, /* XXX TBD */
+ "Read boundary violation") },
+ /* D */
{ SST(0x22, 0x00, SS_FATAL | EINVAL,
"Illegal function (use 20 00, 24 00, or 26 00)") },
/* DT P B */
- { SST(0x23, 0x00, SS_RDEF, /* XXX TBD */
+ { SST(0x23, 0x00, SS_FATAL | EINVAL,
"Invalid token operation, cause not reportable") },
/* DT P B */
- { SST(0x23, 0x01, SS_RDEF, /* XXX TBD */
+ { SST(0x23, 0x01, SS_FATAL | EINVAL,
"Invalid token operation, unsupported token type") },
/* DT P B */
- { SST(0x23, 0x02, SS_RDEF, /* XXX TBD */
+ { SST(0x23, 0x02, SS_FATAL | EINVAL,
"Invalid token operation, remote token usage not supported") },
/* DT P B */
- { SST(0x23, 0x03, SS_RDEF, /* XXX TBD */
+ { SST(0x23, 0x03, SS_FATAL | EINVAL,
"Invalid token operation, remote ROD token creation not supported") },
/* DT P B */
- { SST(0x23, 0x04, SS_RDEF, /* XXX TBD */
+ { SST(0x23, 0x04, SS_FATAL | EINVAL,
"Invalid token operation, token unknown") },
/* DT P B */
- { SST(0x23, 0x05, SS_RDEF, /* XXX TBD */
+ { SST(0x23, 0x05, SS_FATAL | EINVAL,
"Invalid token operation, token corrupt") },
/* DT P B */
- { SST(0x23, 0x06, SS_RDEF, /* XXX TBD */
+ { SST(0x23, 0x06, SS_FATAL | EINVAL,
"Invalid token operation, token revoked") },
/* DT P B */
- { SST(0x23, 0x07, SS_RDEF, /* XXX TBD */
+ { SST(0x23, 0x07, SS_FATAL | EINVAL,
"Invalid token operation, token expired") },
/* DT P B */
- { SST(0x23, 0x08, SS_RDEF, /* XXX TBD */
+ { SST(0x23, 0x08, SS_FATAL | EINVAL,
"Invalid token operation, token cancelled") },
/* DT P B */
- { SST(0x23, 0x09, SS_RDEF, /* XXX TBD */
+ { SST(0x23, 0x09, SS_FATAL | EINVAL,
"Invalid token operation, token deleted") },
/* DT P B */
- { SST(0x23, 0x0A, SS_RDEF, /* XXX TBD */
+ { SST(0x23, 0x0A, SS_FATAL | EINVAL,
"Invalid token operation, invalid token length") },
/* DTLPWROMAEBKVF */
{ SST(0x24, 0x00, SS_FATAL | EINVAL,
@@ -1677,28 +1762,28 @@ static struct asc_table_entry asc_table[] = {
{ SST(0x26, 0x05, SS_RDEF, /* XXX TBD */
"Data decryption error") },
/* DTLPWRO K */
- { SST(0x26, 0x06, SS_RDEF, /* XXX TBD */
+ { SST(0x26, 0x06, SS_FATAL | EINVAL,
"Too many target descriptors") },
/* DTLPWRO K */
- { SST(0x26, 0x07, SS_RDEF, /* XXX TBD */
+ { SST(0x26, 0x07, SS_FATAL | EINVAL,
"Unsupported target descriptor type code") },
/* DTLPWRO K */
- { SST(0x26, 0x08, SS_RDEF, /* XXX TBD */
+ { SST(0x26, 0x08, SS_FATAL | EINVAL,
"Too many segment descriptors") },
/* DTLPWRO K */
- { SST(0x26, 0x09, SS_RDEF, /* XXX TBD */
+ { SST(0x26, 0x09, SS_FATAL | EINVAL,
"Unsupported segment descriptor type code") },
/* DTLPWRO K */
- { SST(0x26, 0x0A, SS_RDEF, /* XXX TBD */
+ { SST(0x26, 0x0A, SS_FATAL | EINVAL,
"Unexpected inexact segment") },
/* DTLPWRO K */
- { SST(0x26, 0x0B, SS_RDEF, /* XXX TBD */
+ { SST(0x26, 0x0B, SS_FATAL | EINVAL,
"Inline data length exceeded") },
/* DTLPWRO K */
- { SST(0x26, 0x0C, SS_RDEF, /* XXX TBD */
+ { SST(0x26, 0x0C, SS_FATAL | EINVAL,
"Invalid operation for copy source or destination") },
/* DTLPWRO K */
- { SST(0x26, 0x0D, SS_RDEF, /* XXX TBD */
+ { SST(0x26, 0x0D, SS_FATAL | EINVAL,
"Copy segment granularity violation") },
/* DT PWROMAEBK */
{ SST(0x26, 0x0E, SS_RDEF, /* XXX TBD */
@@ -1715,6 +1800,9 @@ static struct asc_table_entry asc_table[] = {
/* T */
{ SST(0x26, 0x12, SS_RDEF, /* XXX TBD */
"Vendor specific key reference not found") },
+ /* D */
+ { SST(0x26, 0x13, SS_RDEF, /* XXX TBD */
+ "Application tag mode page is invalid") },
/* DT WRO BK */
{ SST(0x27, 0x00, SS_FATAL | EACCES,
"Write protected") },
@@ -1737,8 +1825,11 @@ static struct asc_table_entry asc_table[] = {
{ SST(0x27, 0x06, SS_RDEF, /* XXX TBD */
"Conditional write protect") },
/* D B */
- { SST(0x27, 0x07, SS_RDEF, /* XXX TBD */
+ { SST(0x27, 0x07, SS_FATAL | ENOSPC,
"Space allocation failed write protect") },
+ /* D */
+ { SST(0x27, 0x08, SS_FATAL | EACCES,
+ "Zone is read only") },
/* DTLPWROMAEBKVF */
{ SST(0x28, 0x00, SS_FATAL | ENXIO,
"Not ready to ready change, medium may have changed") },
@@ -1882,12 +1973,33 @@ static struct asc_table_entry asc_table[] = {
/* D */
{ SST(0x2C, 0x0C, SS_RDEF, /* XXX TBD */
"ORWRITE generation does not match") },
+ /* D */
+ { SST(0x2C, 0x0D, SS_RDEF, /* XXX TBD */
+ "Reset write pointer not allowed") },
+ /* D */
+ { SST(0x2C, 0x0E, SS_RDEF, /* XXX TBD */
+ "Zone is offline") },
+ /* D */
+ { SST(0x2C, 0x0F, SS_RDEF, /* XXX TBD */
+ "Stream not open") },
+ /* D */
+ { SST(0x2C, 0x10, SS_RDEF, /* XXX TBD */
+ "Unwritten data in zone") },
/* T */
{ SST(0x2D, 0x00, SS_RDEF,
"Overwrite error on update in place") },
/* R */
{ SST(0x2E, 0x00, SS_RDEF, /* XXX TBD */
"Insufficient time for operation") },
+ /* D */
+ { SST(0x2E, 0x01, SS_RDEF, /* XXX TBD */
+ "Command timeout before processing") },
+ /* D */
+ { SST(0x2E, 0x02, SS_RDEF, /* XXX TBD */
+ "Command timeout during processing") },
+ /* D */
+ { SST(0x2E, 0x03, SS_RDEF, /* XXX TBD */
+ "Command timeout during processing due to error recovery") },
/* DTLPWROMAEBKVF */
{ SST(0x2F, 0x00, SS_RDEF,
"Commands cleared by another initiator") },
@@ -1897,6 +2009,9 @@ static struct asc_table_entry asc_table[] = {
/* DTLPWROMAEBKVF */
{ SST(0x2F, 0x02, SS_RDEF, /* XXX TBD */
"Commands cleared by device server") },
+ /* DTLPWROMAEBKVF */
+ { SST(0x2F, 0x03, SS_RDEF, /* XXX TBD */
+ "Some commands cleared by queuing layer event") },
/* DT WROM BK */
{ SST(0x30, 0x00, SS_RDEF,
"Incompatible medium installed") },
@@ -2194,6 +2309,15 @@ static struct asc_table_entry asc_table[] = {
/* DTLPWR MAEBK F */
{ SST(0x3F, 0x14, SS_RDEF, /* XXX TBD */
"iSCSI IP address changed") },
+ /* DTLPWR MAEBK */
+ { SST(0x3F, 0x15, SS_RDEF, /* XXX TBD */
+ "Inspect referrals sense descriptors") },
+ /* DTLPWROMAEBKVF */
+ { SST(0x3F, 0x16, SS_RDEF, /* XXX TBD */
+ "Microcode has been changed without reset") },
+ /* D */
+ { SST(0x3F, 0x17, SS_RDEF, /* XXX TBD */
+ "Zone transition to full") },
/* D */
{ SST(0x40, 0x00, SS_RDEF,
"RAM failure") }, /* deprecated - use 40 NN instead */
@@ -2303,6 +2427,30 @@ static struct asc_table_entry asc_table[] = {
/* DT PWROMAEBK F */
{ SST(0x4B, 0x0D, SS_RDEF, /* XXX TBD */
"Data-out buffer error") },
+ /* DT PWROMAEBK F */
+ { SST(0x4B, 0x0E, SS_RDEF, /* XXX TBD */
+ "PCIe fabric error") },
+ /* DT PWROMAEBK F */
+ { SST(0x4B, 0x0F, SS_RDEF, /* XXX TBD */
+ "PCIe completion timeout") },
+ /* DT PWROMAEBK F */
+ { SST(0x4B, 0x10, SS_RDEF, /* XXX TBD */
+ "PCIe completer abort") },
+ /* DT PWROMAEBK F */
+ { SST(0x4B, 0x11, SS_RDEF, /* XXX TBD */
+ "PCIe poisoned TLP received") },
+ /* DT PWROMAEBK F */
+ { SST(0x4B, 0x12, SS_RDEF, /* XXX TBD */
+ "PCIe ECRC check failed") },
+ /* DT PWROMAEBK F */
+ { SST(0x4B, 0x13, SS_RDEF, /* XXX TBD */
+ "PCIe unsupported request") },
+ /* DT PWROMAEBK F */
+ { SST(0x4B, 0x14, SS_RDEF, /* XXX TBD */
+ "PCIe ACS violation") },
+ /* DT PWROMAEBK F */
+ { SST(0x4B, 0x15, SS_RDEF, /* XXX TBD */
+ "PCIe TLP prefix blocket") },
/* DTLPWROMAEBKVF */
{ SST(0x4C, 0x00, SS_RDEF,
"Logical unit failed self-configuration") },
@@ -2360,6 +2508,21 @@ static struct asc_table_entry asc_table[] = {
/* M */
{ SST(0x53, 0x08, SS_RDEF, /* XXX TBD */
"Element status unknown") },
+ /* M */
+ { SST(0x53, 0x09, SS_RDEF, /* XXX TBD */
+ "Data transfer device error - load failed") },
+ /* M */
+ { SST(0x53, 0x0A, SS_RDEF, /* XXX TBD */
+ "Data transfer device error - unload failed") },
+ /* M */
+ { SST(0x53, 0x0B, SS_RDEF, /* XXX TBD */
+ "Data transfer device error - unload missing") },
+ /* M */
+ { SST(0x53, 0x0C, SS_RDEF, /* XXX TBD */
+ "Data transfer device error - eject failed") },
+ /* M */
+ { SST(0x53, 0x0D, SS_RDEF, /* XXX TBD */
+ "Data transfer device error - library communication failed") },
/* P */
{ SST(0x54, 0x00, SS_RDEF,
"SCSI to host system interface failure") },
@@ -2405,6 +2568,15 @@ static struct asc_table_entry asc_table[] = {
/* DT P B */
{ SST(0x55, 0x0D, SS_RDEF, /* XXX TBD */
"Insufficient resources to create ROD token") },
+ /* D */
+ { SST(0x55, 0x0E, SS_RDEF, /* XXX TBD */
+ "Insufficient zone resources") },
+ /* D */
+ { SST(0x55, 0x0F, SS_RDEF, /* XXX TBD */
+ "Insufficient zone resources to complete write") },
+ /* D */
+ { SST(0x55, 0x10, SS_RDEF, /* XXX TBD */
+ "Maximum number of streams open") },
/* R */
{ SST(0x57, 0x00, SS_RDEF,
"Unable to recover table-of-contents") },
@@ -2825,6 +2997,9 @@ static struct asc_table_entry asc_table[] = {
/* A */
{ SST(0x68, 0x00, SS_RDEF,
"Logical unit not configured") },
+ /* D */
+ { SST(0x68, 0x01, SS_RDEF,
+ "Subsidiary logical unit not configured") },
/* A */
{ SST(0x69, 0x00, SS_RDEF,
"Data loss on logical unit") },
@@ -3031,7 +3206,7 @@ static struct asc_table_entry asc_table[] = {
"Security conflict in translated device") }
};
-const int asc_table_size = sizeof(asc_table)/sizeof(asc_table[0]);
+const u_int asc_table_size = nitems(asc_table);
struct asc_key
{
@@ -3124,14 +3299,14 @@ fetchtableentries(int sense_key, int asc, int ascq,
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;
+ sense_tables_size[1] = nitems(sense_key_table);
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;
+ sense_tables_size[0] = nitems(sense_key_table);
num_sense_tables = 1;
}
@@ -3297,14 +3472,32 @@ scsi_error_action(struct ccb_scsiio *csio, struct scsi_inquiry_data *inq_data,
char *
scsi_cdb_string(u_int8_t *cdb_ptr, char *cdb_string, size_t len)
{
+ struct sbuf sb;
+ int error;
+
+ if (len == 0)
+ return ("");
+
+ sbuf_new(&sb, cdb_string, len, SBUF_FIXEDLEN);
+
+ scsi_cdb_sbuf(cdb_ptr, &sb);
+
+ /* ENOMEM just means that the fixed buffer is full, OK to ignore */
+ error = sbuf_finish(&sb);
+ if (error != 0 && error != ENOMEM)
+ return ("");
+
+ return(sbuf_data(&sb));
+}
+
+void
+scsi_cdb_sbuf(u_int8_t *cdb_ptr, struct sbuf *sb)
+{
u_int8_t cdb_len;
int i;
if (cdb_ptr == NULL)
- return("");
-
- /* Silence warnings */
- cdb_len = 0;
+ return;
/*
* This is taken from the SCSI-3 draft spec.
@@ -3341,12 +3534,11 @@ scsi_cdb_string(u_int8_t *cdb_ptr, char *cdb_string, size_t len)
cdb_len = 12;
break;
}
- *cdb_string = '\0';
+
for (i = 0; i < cdb_len; i++)
- snprintf(cdb_string + strlen(cdb_string),
- len - strlen(cdb_string), "%02hhx ", cdb_ptr[i]);
+ sbuf_printf(sb, "%02hhx ", cdb_ptr[i]);
- return(cdb_string);
+ return;
}
const char *
@@ -3395,7 +3587,6 @@ scsi_command_string(struct cam_device *device, struct ccb_scsiio *csio,
#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 */
@@ -3428,15 +3619,13 @@ scsi_command_string(struct cam_device *device, struct ccb_scsiio *csio,
#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)));
+ sbuf_printf(sb, "%s. CDB: ",
+ scsi_op_desc(csio->cdb_io.cdb_ptr[0], inq_data));
+ scsi_cdb_sbuf(csio->cdb_io.cdb_ptr, sb);
} 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)));
+ sbuf_printf(sb, "%s. CDB: ",
+ scsi_op_desc(csio->cdb_io.cdb_bytes[0], inq_data));
+ scsi_cdb_sbuf(csio->cdb_io.cdb_bytes, sb);
}
#ifdef _KERNEL
@@ -3468,7 +3657,7 @@ scsi_desc_iterate(struct scsi_sense_data_desc *sense, u_int sense_len,
/*
* The length of data actually returned may be different than the
- * extra_len recorded in the sturcture.
+ * extra_len recorded in the structure.
*/
desc_len = sense_len -offsetof(struct scsi_sense_data_desc, sense_desc);
@@ -3808,8 +3997,6 @@ scsi_set_sense_data_va(struct scsi_sense_data *sense_data,
*/
sense->extra_len = 10;
sense_len = (int)va_arg(ap, int);
- len_to_copy = MIN(sense_len, SSD_EXTRA_MAX -
- sense->extra_len);
data = (uint8_t *)va_arg(ap, uint8_t *);
switch (elem_type) {
@@ -3827,10 +4014,14 @@ scsi_set_sense_data_va(struct scsi_sense_data *sense_data,
uint8_t *data_dest;
int i;
- if (elem_type == SSD_ELEM_COMMAND)
+ if (elem_type == SSD_ELEM_COMMAND) {
data_dest = &sense->cmd_spec_info[0];
- else {
+ len_to_copy = MIN(sense_len,
+ sizeof(sense->cmd_spec_info));
+ } else {
data_dest = &sense->info[0];
+ len_to_copy = MIN(sense_len,
+ sizeof(sense->info));
/*
* We're setting the info field, so
* set the valid bit.
@@ -4083,6 +4274,7 @@ scsi_get_block_info(struct scsi_sense_data *sense_data, u_int sense_len,
switch (SID_TYPE(inq_data)) {
case T_DIRECT:
case T_RBC:
+ case T_ZBC_HM:
break;
default:
goto bailout;
@@ -4524,10 +4716,9 @@ scsi_sense_desc_sbuf(struct sbuf *sb, struct scsi_sense_data *sense,
struct scsi_inquiry_data *inq_data,
struct scsi_sense_desc_header *header)
{
- int i;
+ u_int i;
- for (i = 0; i < (sizeof(scsi_sense_printers) /
- sizeof(scsi_sense_printers[0])); i++) {
+ for (i = 0; i < nitems(scsi_sense_printers); i++) {
struct scsi_sense_desc_printer *printer;
printer = &scsi_sense_printers[i];
@@ -5236,6 +5427,9 @@ scsi_print_inquiry(struct scsi_inquiry_data *inq_data)
case T_ADC:
dtype = "Automation/Drive Interface";
break;
+ case T_ZBC_HM:
+ dtype = "Host Managed Zoned Block";
+ break;
case T_NODEVICE:
dtype = "Uninstalled";
break;
@@ -5304,8 +5498,8 @@ static struct {
u_int
scsi_calc_syncsrate(u_int period_factor)
{
- int i;
- int num_syncrates;
+ u_int i;
+ u_int num_syncrates;
/*
* It's a bug if period is zero, but if it is anyway, don't
@@ -5316,7 +5510,7 @@ scsi_calc_syncsrate(u_int period_factor)
return (3300);
}
- num_syncrates = sizeof(scsi_syncrates) / sizeof(scsi_syncrates[0]);
+ num_syncrates = nitems(scsi_syncrates);
/* See if the period is in the "exception" table */
for (i = 0; i < num_syncrates; i++) {
@@ -5334,21 +5528,21 @@ scsi_calc_syncsrate(u_int period_factor)
}
/*
- * Return the SCSI sync parameter that corresponsd to
+ * Return the SCSI sync parameter that corresponds to
* the passed in period in 10ths of ns.
*/
u_int
scsi_calc_syncparam(u_int period)
{
- int i;
- int num_syncrates;
+ u_int i;
+ u_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]);
+ num_syncrates = nitems(scsi_syncrates);
/* See if the period is in the "exception" table */
for (i = 0; i < num_syncrates; i++) {
@@ -5450,33 +5644,1853 @@ scsi_devid_is_lun_name(uint8_t *bufp)
return 1;
}
+int
+scsi_devid_is_port_naa(uint8_t *bufp)
+{
+ struct scsi_vpd_id_descriptor *descr;
+
+ descr = (struct scsi_vpd_id_descriptor *)bufp;
+ if ((descr->id_type & SVPD_ID_ASSOC_MASK) != SVPD_ID_ASSOC_PORT)
+ return 0;
+ if ((descr->id_type & SVPD_ID_TYPE_MASK) != SVPD_ID_TYPE_NAA)
+ return 0;
+ return 1;
+}
+
struct scsi_vpd_id_descriptor *
-scsi_get_devid(struct scsi_vpd_device_id *id, uint32_t page_len,
+scsi_get_devid_desc(struct scsi_vpd_id_descriptor *desc, uint32_t len,
scsi_devid_checkfn_t ck_fn)
{
- struct scsi_vpd_id_descriptor *desc;
- uint8_t *page_end;
uint8_t *desc_buf_end;
- page_end = (uint8_t *)id + page_len;
- if (page_end < id->desc_list)
- return (NULL);
-
- desc_buf_end = MIN(id->desc_list + scsi_2btoul(id->length), page_end);
+ desc_buf_end = (uint8_t *)desc + len;
- for (desc = (struct scsi_vpd_id_descriptor *)id->desc_list;
- desc->identifier <= desc_buf_end
- && desc->identifier + desc->length <= desc_buf_end;
- desc = (struct scsi_vpd_id_descriptor *)(desc->identifier
+ for (; desc->identifier <= desc_buf_end &&
+ desc->identifier + desc->length <= desc_buf_end;
+ desc = (struct scsi_vpd_id_descriptor *)(desc->identifier
+ desc->length)) {
if (ck_fn == NULL || ck_fn((uint8_t *)desc) != 0)
return (desc);
}
+ return (NULL);
+}
+
+struct scsi_vpd_id_descriptor *
+scsi_get_devid(struct scsi_vpd_device_id *id, uint32_t page_len,
+ scsi_devid_checkfn_t ck_fn)
+{
+ uint32_t len;
+
+ if (page_len < sizeof(*id))
+ return (NULL);
+ len = MIN(scsi_2btoul(id->length), page_len - sizeof(*id));
+ return (scsi_get_devid_desc((struct scsi_vpd_id_descriptor *)
+ id->desc_list, len, ck_fn));
+}
+
+int
+scsi_transportid_sbuf(struct sbuf *sb, struct scsi_transportid_header *hdr,
+ uint32_t valid_len)
+{
+ switch (hdr->format_protocol & SCSI_TRN_PROTO_MASK) {
+ case SCSI_PROTO_FC: {
+ struct scsi_transportid_fcp *fcp;
+ uint64_t n_port_name;
+
+ fcp = (struct scsi_transportid_fcp *)hdr;
+
+ n_port_name = scsi_8btou64(fcp->n_port_name);
+
+ sbuf_printf(sb, "FCP address: 0x%.16jx",(uintmax_t)n_port_name);
+ break;
+ }
+ case SCSI_PROTO_SPI: {
+ struct scsi_transportid_spi *spi;
+
+ spi = (struct scsi_transportid_spi *)hdr;
+
+ sbuf_printf(sb, "SPI address: %u,%u",
+ scsi_2btoul(spi->scsi_addr),
+ scsi_2btoul(spi->rel_trgt_port_id));
+ break;
+ }
+ case SCSI_PROTO_SSA:
+ /*
+ * XXX KDM there is no transport ID defined in SPC-4 for
+ * SSA.
+ */
+ break;
+ case SCSI_PROTO_1394: {
+ struct scsi_transportid_1394 *sbp;
+ uint64_t eui64;
+
+ sbp = (struct scsi_transportid_1394 *)hdr;
+
+ eui64 = scsi_8btou64(sbp->eui64);
+ sbuf_printf(sb, "SBP address: 0x%.16jx", (uintmax_t)eui64);
+ break;
+ }
+ case SCSI_PROTO_RDMA: {
+ struct scsi_transportid_rdma *rdma;
+ unsigned int i;
+
+ rdma = (struct scsi_transportid_rdma *)hdr;
+
+ sbuf_printf(sb, "RDMA address: 0x");
+ for (i = 0; i < sizeof(rdma->initiator_port_id); i++)
+ sbuf_printf(sb, "%02x", rdma->initiator_port_id[i]);
+ break;
+ }
+ case SCSI_PROTO_ISCSI: {
+ uint32_t add_len, i;
+ uint8_t *iscsi_name = NULL;
+ int nul_found = 0;
+
+ sbuf_printf(sb, "iSCSI address: ");
+ if ((hdr->format_protocol & SCSI_TRN_FORMAT_MASK) ==
+ SCSI_TRN_ISCSI_FORMAT_DEVICE) {
+ struct scsi_transportid_iscsi_device *dev;
+
+ dev = (struct scsi_transportid_iscsi_device *)hdr;
+
+ /*
+ * Verify how much additional data we really have.
+ */
+ add_len = scsi_2btoul(dev->additional_length);
+ add_len = MIN(add_len, valid_len -
+ __offsetof(struct scsi_transportid_iscsi_device,
+ iscsi_name));
+ iscsi_name = &dev->iscsi_name[0];
+
+ } else if ((hdr->format_protocol & SCSI_TRN_FORMAT_MASK) ==
+ SCSI_TRN_ISCSI_FORMAT_PORT) {
+ struct scsi_transportid_iscsi_port *port;
+
+ port = (struct scsi_transportid_iscsi_port *)hdr;
+
+ add_len = scsi_2btoul(port->additional_length);
+ add_len = MIN(add_len, valid_len -
+ __offsetof(struct scsi_transportid_iscsi_port,
+ iscsi_name));
+ iscsi_name = &port->iscsi_name[0];
+ } else {
+ sbuf_printf(sb, "unknown format %x",
+ (hdr->format_protocol &
+ SCSI_TRN_FORMAT_MASK) >>
+ SCSI_TRN_FORMAT_SHIFT);
+ break;
+ }
+ if (add_len == 0) {
+ sbuf_printf(sb, "not enough data");
+ break;
+ }
+ /*
+ * This is supposed to be a NUL-terminated ASCII
+ * string, but you never know. So we're going to
+ * check. We need to do this because there is no
+ * sbuf equivalent of strncat().
+ */
+ for (i = 0; i < add_len; i++) {
+ if (iscsi_name[i] == '\0') {
+ nul_found = 1;
+ break;
+ }
+ }
+ /*
+ * If there is a NUL in the name, we can just use
+ * sbuf_cat(). Otherwise we need to use sbuf_bcat().
+ */
+ if (nul_found != 0)
+ sbuf_cat(sb, iscsi_name);
+ else
+ sbuf_bcat(sb, iscsi_name, add_len);
+ break;
+ }
+ case SCSI_PROTO_SAS: {
+ struct scsi_transportid_sas *sas;
+ uint64_t sas_addr;
+
+ sas = (struct scsi_transportid_sas *)hdr;
+
+ sas_addr = scsi_8btou64(sas->sas_address);
+ sbuf_printf(sb, "SAS address: 0x%.16jx", (uintmax_t)sas_addr);
+ break;
+ }
+ case SCSI_PROTO_ADITP:
+ case SCSI_PROTO_ATA:
+ case SCSI_PROTO_UAS:
+ /*
+ * No Transport ID format for ADI, ATA or USB is defined in
+ * SPC-4.
+ */
+ sbuf_printf(sb, "No known Transport ID format for protocol "
+ "%#x", hdr->format_protocol & SCSI_TRN_PROTO_MASK);
+ break;
+ case SCSI_PROTO_SOP: {
+ struct scsi_transportid_sop *sop;
+ struct scsi_sop_routing_id_norm *rid;
+
+ sop = (struct scsi_transportid_sop *)hdr;
+ rid = (struct scsi_sop_routing_id_norm *)sop->routing_id;
+
+ /*
+ * Note that there is no alternate format specified in SPC-4
+ * for the PCIe routing ID, so we don't really have a way
+ * to know whether the second byte of the routing ID is
+ * a device and function or just a function. So we just
+ * assume bus,device,function.
+ */
+ sbuf_printf(sb, "SOP Routing ID: %u,%u,%u",
+ rid->bus, rid->devfunc >> SCSI_TRN_SOP_DEV_SHIFT,
+ rid->devfunc & SCSI_TRN_SOP_FUNC_NORM_MAX);
+ break;
+ }
+ case SCSI_PROTO_NONE:
+ default:
+ sbuf_printf(sb, "Unknown protocol %#x",
+ hdr->format_protocol & SCSI_TRN_PROTO_MASK);
+ break;
+ }
+
+ return (0);
+}
+
+struct scsi_nv scsi_proto_map[] = {
+ { "fcp", SCSI_PROTO_FC },
+ { "spi", SCSI_PROTO_SPI },
+ { "ssa", SCSI_PROTO_SSA },
+ { "sbp", SCSI_PROTO_1394 },
+ { "1394", SCSI_PROTO_1394 },
+ { "srp", SCSI_PROTO_RDMA },
+ { "rdma", SCSI_PROTO_RDMA },
+ { "iscsi", SCSI_PROTO_ISCSI },
+ { "iqn", SCSI_PROTO_ISCSI },
+ { "sas", SCSI_PROTO_SAS },
+ { "aditp", SCSI_PROTO_ADITP },
+ { "ata", SCSI_PROTO_ATA },
+ { "uas", SCSI_PROTO_UAS },
+ { "usb", SCSI_PROTO_UAS },
+ { "sop", SCSI_PROTO_SOP }
+};
+
+const char *
+scsi_nv_to_str(struct scsi_nv *table, int num_table_entries, uint64_t value)
+{
+ int i;
+
+ for (i = 0; i < num_table_entries; i++) {
+ if (table[i].value == value)
+ return (table[i].name);
+ }
return (NULL);
}
+/*
+ * Given a name/value table, find a value matching the given name.
+ * Return values:
+ * SCSI_NV_FOUND - match found
+ * SCSI_NV_AMBIGUOUS - more than one match, none of them exact
+ * SCSI_NV_NOT_FOUND - no match found
+ */
+scsi_nv_status
+scsi_get_nv(struct scsi_nv *table, int num_table_entries,
+ char *name, int *table_entry, scsi_nv_flags flags)
+{
+ int i, num_matches = 0;
+
+ for (i = 0; i < num_table_entries; i++) {
+ size_t table_len, name_len;
+
+ table_len = strlen(table[i].name);
+ name_len = strlen(name);
+
+ if ((((flags & SCSI_NV_FLAG_IG_CASE) != 0)
+ && (strncasecmp(table[i].name, name, name_len) == 0))
+ || (((flags & SCSI_NV_FLAG_IG_CASE) == 0)
+ && (strncmp(table[i].name, name, name_len) == 0))) {
+ *table_entry = i;
+
+ /*
+ * Check for an exact match. If we have the same
+ * number of characters in the table as the argument,
+ * and we already know they're the same, we have
+ * an exact match.
+ */
+ if (table_len == name_len)
+ return (SCSI_NV_FOUND);
+
+ /*
+ * Otherwise, bump up the number of matches. We'll
+ * see later how many we have.
+ */
+ num_matches++;
+ }
+ }
+
+ if (num_matches > 1)
+ return (SCSI_NV_AMBIGUOUS);
+ else if (num_matches == 1)
+ return (SCSI_NV_FOUND);
+ else
+ return (SCSI_NV_NOT_FOUND);
+}
+
+/*
+ * Parse transport IDs for Fibre Channel, 1394 and SAS. Since these are
+ * all 64-bit numbers, the code is similar.
+ */
+int
+scsi_parse_transportid_64bit(int proto_id, char *id_str,
+ struct scsi_transportid_header **hdr,
+ unsigned int *alloc_len,
+#ifdef _KERNEL
+ struct malloc_type *type, int flags,
+#endif
+ char *error_str, int error_str_len)
+{
+ uint64_t value;
+ char *endptr;
+ int retval;
+ size_t alloc_size;
+
+ retval = 0;
+
+ value = strtouq(id_str, &endptr, 0);
+ if (*endptr != '\0') {
+ if (error_str != NULL) {
+ snprintf(error_str, error_str_len, "%s: error "
+ "parsing ID %s, 64-bit number required",
+ __func__, id_str);
+ }
+ retval = 1;
+ goto bailout;
+ }
+
+ switch (proto_id) {
+ case SCSI_PROTO_FC:
+ alloc_size = sizeof(struct scsi_transportid_fcp);
+ break;
+ case SCSI_PROTO_1394:
+ alloc_size = sizeof(struct scsi_transportid_1394);
+ break;
+ case SCSI_PROTO_SAS:
+ alloc_size = sizeof(struct scsi_transportid_sas);
+ break;
+ default:
+ if (error_str != NULL) {
+ snprintf(error_str, error_str_len, "%s: unsupported "
+ "protocol %d", __func__, proto_id);
+ }
+ retval = 1;
+ goto bailout;
+ break; /* NOTREACHED */
+ }
+#ifdef _KERNEL
+ *hdr = malloc(alloc_size, type, flags);
+#else /* _KERNEL */
+ *hdr = malloc(alloc_size);
+#endif /*_KERNEL */
+ if (*hdr == NULL) {
+ if (error_str != NULL) {
+ snprintf(error_str, error_str_len, "%s: unable to "
+ "allocate %zu bytes", __func__, alloc_size);
+ }
+ retval = 1;
+ goto bailout;
+ }
+
+ *alloc_len = alloc_size;
+
+ bzero(*hdr, alloc_size);
+
+ switch (proto_id) {
+ case SCSI_PROTO_FC: {
+ struct scsi_transportid_fcp *fcp;
+
+ fcp = (struct scsi_transportid_fcp *)(*hdr);
+ fcp->format_protocol = SCSI_PROTO_FC |
+ SCSI_TRN_FCP_FORMAT_DEFAULT;
+ scsi_u64to8b(value, fcp->n_port_name);
+ break;
+ }
+ case SCSI_PROTO_1394: {
+ struct scsi_transportid_1394 *sbp;
+
+ sbp = (struct scsi_transportid_1394 *)(*hdr);
+ sbp->format_protocol = SCSI_PROTO_1394 |
+ SCSI_TRN_1394_FORMAT_DEFAULT;
+ scsi_u64to8b(value, sbp->eui64);
+ break;
+ }
+ case SCSI_PROTO_SAS: {
+ struct scsi_transportid_sas *sas;
+
+ sas = (struct scsi_transportid_sas *)(*hdr);
+ sas->format_protocol = SCSI_PROTO_SAS |
+ SCSI_TRN_SAS_FORMAT_DEFAULT;
+ scsi_u64to8b(value, sas->sas_address);
+ break;
+ }
+ default:
+ break;
+ }
+bailout:
+ return (retval);
+}
+
+/*
+ * Parse a SPI (Parallel SCSI) address of the form: id,rel_tgt_port
+ */
+int
+scsi_parse_transportid_spi(char *id_str, struct scsi_transportid_header **hdr,
+ unsigned int *alloc_len,
+#ifdef _KERNEL
+ struct malloc_type *type, int flags,
+#endif
+ char *error_str, int error_str_len)
+{
+ unsigned long scsi_addr, target_port;
+ struct scsi_transportid_spi *spi;
+ char *tmpstr, *endptr;
+ int retval;
+
+ retval = 0;
+
+ tmpstr = strsep(&id_str, ",");
+ if (tmpstr == NULL) {
+ if (error_str != NULL) {
+ snprintf(error_str, error_str_len,
+ "%s: no ID found", __func__);
+ }
+ retval = 1;
+ goto bailout;
+ }
+ scsi_addr = strtoul(tmpstr, &endptr, 0);
+ if (*endptr != '\0') {
+ if (error_str != NULL) {
+ snprintf(error_str, error_str_len, "%s: error "
+ "parsing SCSI ID %s, number required",
+ __func__, tmpstr);
+ }
+ retval = 1;
+ goto bailout;
+ }
+
+ if (id_str == NULL) {
+ if (error_str != NULL) {
+ snprintf(error_str, error_str_len, "%s: no relative "
+ "target port found", __func__);
+ }
+ retval = 1;
+ goto bailout;
+ }
+
+ target_port = strtoul(id_str, &endptr, 0);
+ if (*endptr != '\0') {
+ if (error_str != NULL) {
+ snprintf(error_str, error_str_len, "%s: error "
+ "parsing relative target port %s, number "
+ "required", __func__, id_str);
+ }
+ retval = 1;
+ goto bailout;
+ }
+#ifdef _KERNEL
+ spi = malloc(sizeof(*spi), type, flags);
+#else
+ spi = malloc(sizeof(*spi));
+#endif
+ if (spi == NULL) {
+ if (error_str != NULL) {
+ snprintf(error_str, error_str_len, "%s: unable to "
+ "allocate %zu bytes", __func__,
+ sizeof(*spi));
+ }
+ retval = 1;
+ goto bailout;
+ }
+ *alloc_len = sizeof(*spi);
+ bzero(spi, sizeof(*spi));
+
+ spi->format_protocol = SCSI_PROTO_SPI | SCSI_TRN_SPI_FORMAT_DEFAULT;
+ scsi_ulto2b(scsi_addr, spi->scsi_addr);
+ scsi_ulto2b(target_port, spi->rel_trgt_port_id);
+
+ *hdr = (struct scsi_transportid_header *)spi;
+bailout:
+ return (retval);
+}
+
+/*
+ * Parse an RDMA/SRP Initiator Port ID string. This is 32 hexadecimal digits,
+ * optionally prefixed by "0x" or "0X".
+ */
+int
+scsi_parse_transportid_rdma(char *id_str, struct scsi_transportid_header **hdr,
+ unsigned int *alloc_len,
+#ifdef _KERNEL
+ struct malloc_type *type, int flags,
+#endif
+ char *error_str, int error_str_len)
+{
+ struct scsi_transportid_rdma *rdma;
+ int retval;
+ size_t id_len, rdma_id_size;
+ uint8_t rdma_id[SCSI_TRN_RDMA_PORT_LEN];
+ char *tmpstr;
+ unsigned int i, j;
+
+ retval = 0;
+ id_len = strlen(id_str);
+ rdma_id_size = SCSI_TRN_RDMA_PORT_LEN;
+
+ /*
+ * Check the size. It needs to be either 32 or 34 characters long.
+ */
+ if ((id_len != (rdma_id_size * 2))
+ && (id_len != ((rdma_id_size * 2) + 2))) {
+ if (error_str != NULL) {
+ snprintf(error_str, error_str_len, "%s: RDMA ID "
+ "must be 32 hex digits (0x prefix "
+ "optional), only %zu seen", __func__, id_len);
+ }
+ retval = 1;
+ goto bailout;
+ }
+
+ tmpstr = id_str;
+ /*
+ * If the user gave us 34 characters, the string needs to start
+ * with '0x'.
+ */
+ if (id_len == ((rdma_id_size * 2) + 2)) {
+ if ((tmpstr[0] == '0')
+ && ((tmpstr[1] == 'x') || (tmpstr[1] == 'X'))) {
+ tmpstr += 2;
+ } else {
+ if (error_str != NULL) {
+ snprintf(error_str, error_str_len, "%s: RDMA "
+ "ID prefix, if used, must be \"0x\", "
+ "got %s", __func__, tmpstr);
+ }
+ retval = 1;
+ goto bailout;
+ }
+ }
+ bzero(rdma_id, sizeof(rdma_id));
+
+ /*
+ * Convert ASCII hex into binary bytes. There is no standard
+ * 128-bit integer type, and so no strtou128t() routine to convert
+ * from hex into a large integer. In the end, we're not going to
+ * an integer, but rather to a byte array, so that and the fact
+ * that we require the user to give us 32 hex digits simplifies the
+ * logic.
+ */
+ for (i = 0; i < (rdma_id_size * 2); i++) {
+ int cur_shift;
+ unsigned char c;
+
+ /* Increment the byte array one for every 2 hex digits */
+ j = i >> 1;
+
+ /*
+ * The first digit in every pair is the most significant
+ * 4 bits. The second is the least significant 4 bits.
+ */
+ if ((i % 2) == 0)
+ cur_shift = 4;
+ else
+ cur_shift = 0;
+
+ c = tmpstr[i];
+ /* Convert the ASCII hex character into a number */
+ if (isdigit(c))
+ c -= '0';
+ else if (isalpha(c))
+ c -= isupper(c) ? 'A' - 10 : 'a' - 10;
+ else {
+ if (error_str != NULL) {
+ snprintf(error_str, error_str_len, "%s: "
+ "RDMA ID must be hex digits, got "
+ "invalid character %c", __func__,
+ tmpstr[i]);
+ }
+ retval = 1;
+ goto bailout;
+ }
+ /*
+ * The converted number can't be less than 0; the type is
+ * unsigned, and the subtraction logic will not give us
+ * a negative number. So we only need to make sure that
+ * the value is not greater than 0xf. (i.e. make sure the
+ * user didn't give us a value like "0x12jklmno").
+ */
+ if (c > 0xf) {
+ if (error_str != NULL) {
+ snprintf(error_str, error_str_len, "%s: "
+ "RDMA ID must be hex digits, got "
+ "invalid character %c", __func__,
+ tmpstr[i]);
+ }
+ retval = 1;
+ goto bailout;
+ }
+
+ rdma_id[j] |= c << cur_shift;
+ }
+
+#ifdef _KERNEL
+ rdma = malloc(sizeof(*rdma), type, flags);
+#else
+ rdma = malloc(sizeof(*rdma));
+#endif
+ if (rdma == NULL) {
+ if (error_str != NULL) {
+ snprintf(error_str, error_str_len, "%s: unable to "
+ "allocate %zu bytes", __func__,
+ sizeof(*rdma));
+ }
+ retval = 1;
+ goto bailout;
+ }
+ *alloc_len = sizeof(*rdma);
+ bzero(rdma, *alloc_len);
+
+ rdma->format_protocol = SCSI_PROTO_RDMA | SCSI_TRN_RDMA_FORMAT_DEFAULT;
+ bcopy(rdma_id, rdma->initiator_port_id, SCSI_TRN_RDMA_PORT_LEN);
+
+ *hdr = (struct scsi_transportid_header *)rdma;
+
+bailout:
+ return (retval);
+}
+
+/*
+ * Parse an iSCSI name. The format is either just the name:
+ *
+ * iqn.2012-06.com.example:target0
+ * or the name, separator and initiator session ID:
+ *
+ * iqn.2012-06.com.example:target0,i,0x123
+ *
+ * The separator format is exact.
+ */
+int
+scsi_parse_transportid_iscsi(char *id_str, struct scsi_transportid_header **hdr,
+ unsigned int *alloc_len,
+#ifdef _KERNEL
+ struct malloc_type *type, int flags,
+#endif
+ char *error_str, int error_str_len)
+{
+ size_t id_len, sep_len, id_size, name_len;
+ int retval;
+ unsigned int i, sep_pos, sep_found;
+ const char *sep_template = ",i,0x";
+ const char *iqn_prefix = "iqn.";
+ struct scsi_transportid_iscsi_device *iscsi;
+
+ retval = 0;
+ sep_found = 0;
+
+ id_len = strlen(id_str);
+ sep_len = strlen(sep_template);
+
+ /*
+ * The separator is defined as exactly ',i,0x'. Any other commas,
+ * or any other form, is an error. So look for a comma, and once
+ * we find that, the next few characters must match the separator
+ * exactly. Once we get through the separator, there should be at
+ * least one character.
+ */
+ for (i = 0, sep_pos = 0; i < id_len; i++) {
+ if (sep_pos == 0) {
+ if (id_str[i] == sep_template[sep_pos])
+ sep_pos++;
+
+ continue;
+ }
+ if (sep_pos < sep_len) {
+ if (id_str[i] == sep_template[sep_pos]) {
+ sep_pos++;
+ continue;
+ }
+ if (error_str != NULL) {
+ snprintf(error_str, error_str_len, "%s: "
+ "invalid separator in iSCSI name "
+ "\"%s\"",
+ __func__, id_str);
+ }
+ retval = 1;
+ goto bailout;
+ } else {
+ sep_found = 1;
+ break;
+ }
+ }
+
+ /*
+ * Check to see whether we have a separator but no digits after it.
+ */
+ if ((sep_pos != 0)
+ && (sep_found == 0)) {
+ if (error_str != NULL) {
+ snprintf(error_str, error_str_len, "%s: no digits "
+ "found after separator in iSCSI name \"%s\"",
+ __func__, id_str);
+ }
+ retval = 1;
+ goto bailout;
+ }
+
+ /*
+ * The incoming ID string has the "iqn." prefix stripped off. We
+ * need enough space for the base structure (the structures are the
+ * same for the two iSCSI forms), the prefix, the ID string and a
+ * terminating NUL.
+ */
+ id_size = sizeof(*iscsi) + strlen(iqn_prefix) + id_len + 1;
+
+#ifdef _KERNEL
+ iscsi = malloc(id_size, type, flags);
+#else
+ iscsi = malloc(id_size);
+#endif
+ if (iscsi == NULL) {
+ if (error_str != NULL) {
+ snprintf(error_str, error_str_len, "%s: unable to "
+ "allocate %zu bytes", __func__, id_size);
+ }
+ retval = 1;
+ goto bailout;
+ }
+ *alloc_len = id_size;
+ bzero(iscsi, id_size);
+
+ iscsi->format_protocol = SCSI_PROTO_ISCSI;
+ if (sep_found == 0)
+ iscsi->format_protocol |= SCSI_TRN_ISCSI_FORMAT_DEVICE;
+ else
+ iscsi->format_protocol |= SCSI_TRN_ISCSI_FORMAT_PORT;
+ name_len = id_size - sizeof(*iscsi);
+ scsi_ulto2b(name_len, iscsi->additional_length);
+ snprintf(iscsi->iscsi_name, name_len, "%s%s", iqn_prefix, id_str);
+
+ *hdr = (struct scsi_transportid_header *)iscsi;
+
+bailout:
+ return (retval);
+}
+
+/*
+ * Parse a SCSI over PCIe (SOP) identifier. The Routing ID can either be
+ * of the form 'bus,device,function' or 'bus,function'.
+ */
+int
+scsi_parse_transportid_sop(char *id_str, struct scsi_transportid_header **hdr,
+ unsigned int *alloc_len,
+#ifdef _KERNEL
+ struct malloc_type *type, int flags,
+#endif
+ char *error_str, int error_str_len)
+{
+ struct scsi_transportid_sop *sop;
+ unsigned long bus, device, function;
+ char *tmpstr, *endptr;
+ int retval, device_spec;
+
+ retval = 0;
+ device_spec = 0;
+ device = 0;
+
+ tmpstr = strsep(&id_str, ",");
+ if ((tmpstr == NULL)
+ || (*tmpstr == '\0')) {
+ if (error_str != NULL) {
+ snprintf(error_str, error_str_len, "%s: no ID found",
+ __func__);
+ }
+ retval = 1;
+ goto bailout;
+ }
+ bus = strtoul(tmpstr, &endptr, 0);
+ if (*endptr != '\0') {
+ if (error_str != NULL) {
+ snprintf(error_str, error_str_len, "%s: error "
+ "parsing PCIe bus %s, number required",
+ __func__, tmpstr);
+ }
+ retval = 1;
+ goto bailout;
+ }
+ if ((id_str == NULL)
+ || (*id_str == '\0')) {
+ if (error_str != NULL) {
+ snprintf(error_str, error_str_len, "%s: no PCIe "
+ "device or function found", __func__);
+ }
+ retval = 1;
+ goto bailout;
+ }
+ tmpstr = strsep(&id_str, ",");
+ function = strtoul(tmpstr, &endptr, 0);
+ if (*endptr != '\0') {
+ if (error_str != NULL) {
+ snprintf(error_str, error_str_len, "%s: error "
+ "parsing PCIe device/function %s, number "
+ "required", __func__, tmpstr);
+ }
+ retval = 1;
+ goto bailout;
+ }
+ /*
+ * Check to see whether the user specified a third value. If so,
+ * the second is the device.
+ */
+ if (id_str != NULL) {
+ if (*id_str == '\0') {
+ if (error_str != NULL) {
+ snprintf(error_str, error_str_len, "%s: "
+ "no PCIe function found", __func__);
+ }
+ retval = 1;
+ goto bailout;
+ }
+ device = function;
+ device_spec = 1;
+ function = strtoul(id_str, &endptr, 0);
+ if (*endptr != '\0') {
+ if (error_str != NULL) {
+ snprintf(error_str, error_str_len, "%s: "
+ "error parsing PCIe function %s, "
+ "number required", __func__, id_str);
+ }
+ retval = 1;
+ goto bailout;
+ }
+ }
+ if (bus > SCSI_TRN_SOP_BUS_MAX) {
+ if (error_str != NULL) {
+ snprintf(error_str, error_str_len, "%s: bus value "
+ "%lu greater than maximum %u", __func__,
+ bus, SCSI_TRN_SOP_BUS_MAX);
+ }
+ retval = 1;
+ goto bailout;
+ }
+
+ if ((device_spec != 0)
+ && (device > SCSI_TRN_SOP_DEV_MASK)) {
+ if (error_str != NULL) {
+ snprintf(error_str, error_str_len, "%s: device value "
+ "%lu greater than maximum %u", __func__,
+ device, SCSI_TRN_SOP_DEV_MAX);
+ }
+ retval = 1;
+ goto bailout;
+ }
+
+ if (((device_spec != 0)
+ && (function > SCSI_TRN_SOP_FUNC_NORM_MAX))
+ || ((device_spec == 0)
+ && (function > SCSI_TRN_SOP_FUNC_ALT_MAX))) {
+ if (error_str != NULL) {
+ snprintf(error_str, error_str_len, "%s: function value "
+ "%lu greater than maximum %u", __func__,
+ function, (device_spec == 0) ?
+ SCSI_TRN_SOP_FUNC_ALT_MAX :
+ SCSI_TRN_SOP_FUNC_NORM_MAX);
+ }
+ retval = 1;
+ goto bailout;
+ }
+
+#ifdef _KERNEL
+ sop = malloc(sizeof(*sop), type, flags);
+#else
+ sop = malloc(sizeof(*sop));
+#endif
+ if (sop == NULL) {
+ if (error_str != NULL) {
+ snprintf(error_str, error_str_len, "%s: unable to "
+ "allocate %zu bytes", __func__, sizeof(*sop));
+ }
+ retval = 1;
+ goto bailout;
+ }
+ *alloc_len = sizeof(*sop);
+ bzero(sop, sizeof(*sop));
+ sop->format_protocol = SCSI_PROTO_SOP | SCSI_TRN_SOP_FORMAT_DEFAULT;
+ if (device_spec != 0) {
+ struct scsi_sop_routing_id_norm rid;
+
+ rid.bus = bus;
+ rid.devfunc = (device << SCSI_TRN_SOP_DEV_SHIFT) | function;
+ bcopy(&rid, sop->routing_id, MIN(sizeof(rid),
+ sizeof(sop->routing_id)));
+ } else {
+ struct scsi_sop_routing_id_alt rid;
+
+ rid.bus = bus;
+ rid.function = function;
+ bcopy(&rid, sop->routing_id, MIN(sizeof(rid),
+ sizeof(sop->routing_id)));
+ }
+
+ *hdr = (struct scsi_transportid_header *)sop;
+bailout:
+ return (retval);
+}
+
+/*
+ * transportid_str: NUL-terminated string with format: protcol,id
+ * The ID is protocol specific.
+ * hdr: Storage will be allocated for the transport ID.
+ * alloc_len: The amount of memory allocated is returned here.
+ * type: Malloc bucket (kernel only).
+ * flags: Malloc flags (kernel only).
+ * error_str: If non-NULL, it will contain error information (without
+ * a terminating newline) if an error is returned.
+ * error_str_len: Allocated length of the error string.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+int
+scsi_parse_transportid(char *transportid_str,
+ struct scsi_transportid_header **hdr,
+ unsigned int *alloc_len,
+#ifdef _KERNEL
+ struct malloc_type *type, int flags,
+#endif
+ char *error_str, int error_str_len)
+{
+ char *tmpstr;
+ scsi_nv_status status;
+ u_int num_proto_entries;
+ int retval, table_entry;
+
+ retval = 0;
+ table_entry = 0;
+
+ /*
+ * We do allow a period as well as a comma to separate the protocol
+ * from the ID string. This is to accommodate iSCSI names, which
+ * start with "iqn.".
+ */
+ tmpstr = strsep(&transportid_str, ",.");
+ if (tmpstr == NULL) {
+ if (error_str != NULL) {
+ snprintf(error_str, error_str_len,
+ "%s: transportid_str is NULL", __func__);
+ }
+ retval = 1;
+ goto bailout;
+ }
+
+ num_proto_entries = nitems(scsi_proto_map);
+ status = scsi_get_nv(scsi_proto_map, num_proto_entries, tmpstr,
+ &table_entry, SCSI_NV_FLAG_IG_CASE);
+ if (status != SCSI_NV_FOUND) {
+ if (error_str != NULL) {
+ snprintf(error_str, error_str_len, "%s: %s protocol "
+ "name %s", __func__,
+ (status == SCSI_NV_AMBIGUOUS) ? "ambiguous" :
+ "invalid", tmpstr);
+ }
+ retval = 1;
+ goto bailout;
+ }
+ switch (scsi_proto_map[table_entry].value) {
+ case SCSI_PROTO_FC:
+ case SCSI_PROTO_1394:
+ case SCSI_PROTO_SAS:
+ retval = scsi_parse_transportid_64bit(
+ scsi_proto_map[table_entry].value, transportid_str, hdr,
+ alloc_len,
+#ifdef _KERNEL
+ type, flags,
+#endif
+ error_str, error_str_len);
+ break;
+ case SCSI_PROTO_SPI:
+ retval = scsi_parse_transportid_spi(transportid_str, hdr,
+ alloc_len,
+#ifdef _KERNEL
+ type, flags,
+#endif
+ error_str, error_str_len);
+ break;
+ case SCSI_PROTO_RDMA:
+ retval = scsi_parse_transportid_rdma(transportid_str, hdr,
+ alloc_len,
+#ifdef _KERNEL
+ type, flags,
+#endif
+ error_str, error_str_len);
+ break;
+ case SCSI_PROTO_ISCSI:
+ retval = scsi_parse_transportid_iscsi(transportid_str, hdr,
+ alloc_len,
+#ifdef _KERNEL
+ type, flags,
+#endif
+ error_str, error_str_len);
+ break;
+ case SCSI_PROTO_SOP:
+ retval = scsi_parse_transportid_sop(transportid_str, hdr,
+ alloc_len,
+#ifdef _KERNEL
+ type, flags,
+#endif
+ error_str, error_str_len);
+ break;
+ case SCSI_PROTO_SSA:
+ case SCSI_PROTO_ADITP:
+ case SCSI_PROTO_ATA:
+ case SCSI_PROTO_UAS:
+ case SCSI_PROTO_NONE:
+ default:
+ /*
+ * There is no format defined for a Transport ID for these
+ * protocols. So even if the user gives us something, we
+ * have no way to turn it into a standard SCSI Transport ID.
+ */
+ retval = 1;
+ if (error_str != NULL) {
+ snprintf(error_str, error_str_len, "%s: no Transport "
+ "ID format exists for protocol %s",
+ __func__, tmpstr);
+ }
+ goto bailout;
+ break; /* NOTREACHED */
+ }
+bailout:
+ return (retval);
+}
+
+struct scsi_attrib_table_entry scsi_mam_attr_table[] = {
+ { SMA_ATTR_REM_CAP_PARTITION, SCSI_ATTR_FLAG_NONE,
+ "Remaining Capacity in Partition",
+ /*suffix*/ "MB", /*to_str*/ scsi_attrib_int_sbuf,/*parse_str*/ NULL },
+ { SMA_ATTR_MAX_CAP_PARTITION, SCSI_ATTR_FLAG_NONE,
+ "Maximum Capacity in Partition",
+ /*suffix*/"MB", /*to_str*/ scsi_attrib_int_sbuf, /*parse_str*/ NULL },
+ { SMA_ATTR_TAPEALERT_FLAGS, SCSI_ATTR_FLAG_HEX,
+ "TapeAlert Flags",
+ /*suffix*/NULL, /*to_str*/ scsi_attrib_int_sbuf, /*parse_str*/ NULL },
+ { SMA_ATTR_LOAD_COUNT, SCSI_ATTR_FLAG_NONE,
+ "Load Count",
+ /*suffix*/NULL, /*to_str*/ scsi_attrib_int_sbuf, /*parse_str*/ NULL },
+ { SMA_ATTR_MAM_SPACE_REMAINING, SCSI_ATTR_FLAG_NONE,
+ "MAM Space Remaining",
+ /*suffix*/"bytes", /*to_str*/ scsi_attrib_int_sbuf,
+ /*parse_str*/ NULL },
+ { SMA_ATTR_DEV_ASSIGNING_ORG, SCSI_ATTR_FLAG_NONE,
+ "Assigning Organization",
+ /*suffix*/NULL, /*to_str*/ scsi_attrib_ascii_sbuf,
+ /*parse_str*/ NULL },
+ { SMA_ATTR_FORMAT_DENSITY_CODE, SCSI_ATTR_FLAG_HEX,
+ "Format Density Code",
+ /*suffix*/NULL, /*to_str*/ scsi_attrib_int_sbuf, /*parse_str*/ NULL },
+ { SMA_ATTR_INITIALIZATION_COUNT, SCSI_ATTR_FLAG_NONE,
+ "Initialization Count",
+ /*suffix*/NULL, /*to_str*/ scsi_attrib_int_sbuf, /*parse_str*/ NULL },
+ { SMA_ATTR_VOLUME_ID, SCSI_ATTR_FLAG_NONE,
+ "Volume Identifier",
+ /*suffix*/NULL, /*to_str*/ scsi_attrib_ascii_sbuf,
+ /*parse_str*/ NULL },
+ { SMA_ATTR_VOLUME_CHANGE_REF, SCSI_ATTR_FLAG_HEX,
+ "Volume Change Reference",
+ /*suffix*/NULL, /*to_str*/ scsi_attrib_int_sbuf,
+ /*parse_str*/ NULL },
+ { SMA_ATTR_DEV_SERIAL_LAST_LOAD, SCSI_ATTR_FLAG_NONE,
+ "Device Vendor/Serial at Last Load",
+ /*suffix*/NULL, /*to_str*/ scsi_attrib_vendser_sbuf,
+ /*parse_str*/ NULL },
+ { SMA_ATTR_DEV_SERIAL_LAST_LOAD_1, SCSI_ATTR_FLAG_NONE,
+ "Device Vendor/Serial at Last Load - 1",
+ /*suffix*/NULL, /*to_str*/ scsi_attrib_vendser_sbuf,
+ /*parse_str*/ NULL },
+ { SMA_ATTR_DEV_SERIAL_LAST_LOAD_2, SCSI_ATTR_FLAG_NONE,
+ "Device Vendor/Serial at Last Load - 2",
+ /*suffix*/NULL, /*to_str*/ scsi_attrib_vendser_sbuf,
+ /*parse_str*/ NULL },
+ { SMA_ATTR_DEV_SERIAL_LAST_LOAD_3, SCSI_ATTR_FLAG_NONE,
+ "Device Vendor/Serial at Last Load - 3",
+ /*suffix*/NULL, /*to_str*/ scsi_attrib_vendser_sbuf,
+ /*parse_str*/ NULL },
+ { SMA_ATTR_TOTAL_MB_WRITTEN_LT, SCSI_ATTR_FLAG_NONE,
+ "Total MB Written in Medium Life",
+ /*suffix*/ "MB", /*to_str*/ scsi_attrib_int_sbuf,
+ /*parse_str*/ NULL },
+ { SMA_ATTR_TOTAL_MB_READ_LT, SCSI_ATTR_FLAG_NONE,
+ "Total MB Read in Medium Life",
+ /*suffix*/ "MB", /*to_str*/ scsi_attrib_int_sbuf,
+ /*parse_str*/ NULL },
+ { SMA_ATTR_TOTAL_MB_WRITTEN_CUR, SCSI_ATTR_FLAG_NONE,
+ "Total MB Written in Current/Last Load",
+ /*suffix*/ "MB", /*to_str*/ scsi_attrib_int_sbuf,
+ /*parse_str*/ NULL },
+ { SMA_ATTR_TOTAL_MB_READ_CUR, SCSI_ATTR_FLAG_NONE,
+ "Total MB Read in Current/Last Load",
+ /*suffix*/ "MB", /*to_str*/ scsi_attrib_int_sbuf,
+ /*parse_str*/ NULL },
+ { SMA_ATTR_FIRST_ENC_BLOCK, SCSI_ATTR_FLAG_NONE,
+ "Logical Position of First Encrypted Block",
+ /*suffix*/ NULL, /*to_str*/ scsi_attrib_int_sbuf,
+ /*parse_str*/ NULL },
+ { SMA_ATTR_NEXT_UNENC_BLOCK, SCSI_ATTR_FLAG_NONE,
+ "Logical Position of First Unencrypted Block after First "
+ "Encrypted Block",
+ /*suffix*/ NULL, /*to_str*/ scsi_attrib_int_sbuf,
+ /*parse_str*/ NULL },
+ { SMA_ATTR_MEDIUM_USAGE_HIST, SCSI_ATTR_FLAG_NONE,
+ "Medium Usage History",
+ /*suffix*/ NULL, /*to_str*/ NULL,
+ /*parse_str*/ NULL },
+ { SMA_ATTR_PART_USAGE_HIST, SCSI_ATTR_FLAG_NONE,
+ "Partition Usage History",
+ /*suffix*/ NULL, /*to_str*/ NULL,
+ /*parse_str*/ NULL },
+ { SMA_ATTR_MED_MANUF, SCSI_ATTR_FLAG_NONE,
+ "Medium Manufacturer",
+ /*suffix*/NULL, /*to_str*/ scsi_attrib_ascii_sbuf,
+ /*parse_str*/ NULL },
+ { SMA_ATTR_MED_SERIAL, SCSI_ATTR_FLAG_NONE,
+ "Medium Serial Number",
+ /*suffix*/NULL, /*to_str*/ scsi_attrib_ascii_sbuf,
+ /*parse_str*/ NULL },
+ { SMA_ATTR_MED_LENGTH, SCSI_ATTR_FLAG_NONE,
+ "Medium Length",
+ /*suffix*/"m", /*to_str*/ scsi_attrib_int_sbuf,
+ /*parse_str*/ NULL },
+ { SMA_ATTR_MED_WIDTH, SCSI_ATTR_FLAG_FP | SCSI_ATTR_FLAG_DIV_10 |
+ SCSI_ATTR_FLAG_FP_1DIGIT,
+ "Medium Width",
+ /*suffix*/"mm", /*to_str*/ scsi_attrib_int_sbuf,
+ /*parse_str*/ NULL },
+ { SMA_ATTR_MED_ASSIGNING_ORG, SCSI_ATTR_FLAG_NONE,
+ "Assigning Organization",
+ /*suffix*/NULL, /*to_str*/ scsi_attrib_ascii_sbuf,
+ /*parse_str*/ NULL },
+ { SMA_ATTR_MED_DENSITY_CODE, SCSI_ATTR_FLAG_HEX,
+ "Medium Density Code",
+ /*suffix*/NULL, /*to_str*/ scsi_attrib_int_sbuf,
+ /*parse_str*/ NULL },
+ { SMA_ATTR_MED_MANUF_DATE, SCSI_ATTR_FLAG_NONE,
+ "Medium Manufacture Date",
+ /*suffix*/NULL, /*to_str*/ scsi_attrib_ascii_sbuf,
+ /*parse_str*/ NULL },
+ { SMA_ATTR_MAM_CAPACITY, SCSI_ATTR_FLAG_NONE,
+ "MAM Capacity",
+ /*suffix*/"bytes", /*to_str*/ scsi_attrib_int_sbuf,
+ /*parse_str*/ NULL },
+ { SMA_ATTR_MED_TYPE, SCSI_ATTR_FLAG_HEX,
+ "Medium Type",
+ /*suffix*/NULL, /*to_str*/ scsi_attrib_int_sbuf,
+ /*parse_str*/ NULL },
+ { SMA_ATTR_MED_TYPE_INFO, SCSI_ATTR_FLAG_HEX,
+ "Medium Type Information",
+ /*suffix*/NULL, /*to_str*/ scsi_attrib_int_sbuf,
+ /*parse_str*/ NULL },
+ { SMA_ATTR_MED_SERIAL_NUM, SCSI_ATTR_FLAG_NONE,
+ "Medium Serial Number",
+ /*suffix*/NULL, /*to_str*/ scsi_attrib_int_sbuf,
+ /*parse_str*/ NULL },
+ { SMA_ATTR_APP_VENDOR, SCSI_ATTR_FLAG_NONE,
+ "Application Vendor",
+ /*suffix*/NULL, /*to_str*/ scsi_attrib_ascii_sbuf,
+ /*parse_str*/ NULL },
+ { SMA_ATTR_APP_NAME, SCSI_ATTR_FLAG_NONE,
+ "Application Name",
+ /*suffix*/NULL, /*to_str*/ scsi_attrib_ascii_sbuf,
+ /*parse_str*/ NULL },
+ { SMA_ATTR_APP_VERSION, SCSI_ATTR_FLAG_NONE,
+ "Application Version",
+ /*suffix*/NULL, /*to_str*/ scsi_attrib_ascii_sbuf,
+ /*parse_str*/ NULL },
+ { SMA_ATTR_USER_MED_TEXT_LABEL, SCSI_ATTR_FLAG_NONE,
+ "User Medium Text Label",
+ /*suffix*/NULL, /*to_str*/ scsi_attrib_text_sbuf,
+ /*parse_str*/ NULL },
+ { SMA_ATTR_LAST_WRITTEN_TIME, SCSI_ATTR_FLAG_NONE,
+ "Date and Time Last Written",
+ /*suffix*/NULL, /*to_str*/ scsi_attrib_ascii_sbuf,
+ /*parse_str*/ NULL },
+ { SMA_ATTR_TEXT_LOCAL_ID, SCSI_ATTR_FLAG_HEX,
+ "Text Localization Identifier",
+ /*suffix*/NULL, /*to_str*/ scsi_attrib_int_sbuf,
+ /*parse_str*/ NULL },
+ { SMA_ATTR_BARCODE, SCSI_ATTR_FLAG_NONE,
+ "Barcode",
+ /*suffix*/NULL, /*to_str*/ scsi_attrib_ascii_sbuf,
+ /*parse_str*/ NULL },
+ { SMA_ATTR_HOST_OWNER_NAME, SCSI_ATTR_FLAG_NONE,
+ "Owning Host Textual Name",
+ /*suffix*/NULL, /*to_str*/ scsi_attrib_text_sbuf,
+ /*parse_str*/ NULL },
+ { SMA_ATTR_MEDIA_POOL, SCSI_ATTR_FLAG_NONE,
+ "Media Pool",
+ /*suffix*/NULL, /*to_str*/ scsi_attrib_text_sbuf,
+ /*parse_str*/ NULL },
+ { SMA_ATTR_PART_USER_LABEL, SCSI_ATTR_FLAG_NONE,
+ "Partition User Text Label",
+ /*suffix*/NULL, /*to_str*/ scsi_attrib_ascii_sbuf,
+ /*parse_str*/ NULL },
+ { SMA_ATTR_LOAD_UNLOAD_AT_PART, SCSI_ATTR_FLAG_NONE,
+ "Load/Unload at Partition",
+ /*suffix*/NULL, /*to_str*/ scsi_attrib_int_sbuf,
+ /*parse_str*/ NULL },
+ { SMA_ATTR_APP_FORMAT_VERSION, SCSI_ATTR_FLAG_NONE,
+ "Application Format Version",
+ /*suffix*/NULL, /*to_str*/ scsi_attrib_ascii_sbuf,
+ /*parse_str*/ NULL },
+ { SMA_ATTR_VOL_COHERENCY_INFO, SCSI_ATTR_FLAG_NONE,
+ "Volume Coherency Information",
+ /*suffix*/NULL, /*to_str*/ scsi_attrib_volcoh_sbuf,
+ /*parse_str*/ NULL },
+ { 0x0ff1, SCSI_ATTR_FLAG_NONE,
+ "Spectra MLM Creation",
+ /*suffix*/NULL, /*to_str*/ scsi_attrib_hexdump_sbuf,
+ /*parse_str*/ NULL },
+ { 0x0ff2, SCSI_ATTR_FLAG_NONE,
+ "Spectra MLM C3",
+ /*suffix*/NULL, /*to_str*/ scsi_attrib_hexdump_sbuf,
+ /*parse_str*/ NULL },
+ { 0x0ff3, SCSI_ATTR_FLAG_NONE,
+ "Spectra MLM RW",
+ /*suffix*/NULL, /*to_str*/ scsi_attrib_hexdump_sbuf,
+ /*parse_str*/ NULL },
+ { 0x0ff4, SCSI_ATTR_FLAG_NONE,
+ "Spectra MLM SDC List",
+ /*suffix*/NULL, /*to_str*/ scsi_attrib_hexdump_sbuf,
+ /*parse_str*/ NULL },
+ { 0x0ff7, SCSI_ATTR_FLAG_NONE,
+ "Spectra MLM Post Scan",
+ /*suffix*/NULL, /*to_str*/ scsi_attrib_hexdump_sbuf,
+ /*parse_str*/ NULL },
+ { 0x0ffe, SCSI_ATTR_FLAG_NONE,
+ "Spectra MLM Checksum",
+ /*suffix*/NULL, /*to_str*/ scsi_attrib_hexdump_sbuf,
+ /*parse_str*/ NULL },
+ { 0x17f1, SCSI_ATTR_FLAG_NONE,
+ "Spectra MLM Creation",
+ /*suffix*/NULL, /*to_str*/ scsi_attrib_hexdump_sbuf,
+ /*parse_str*/ NULL },
+ { 0x17f2, SCSI_ATTR_FLAG_NONE,
+ "Spectra MLM C3",
+ /*suffix*/NULL, /*to_str*/ scsi_attrib_hexdump_sbuf,
+ /*parse_str*/ NULL },
+ { 0x17f3, SCSI_ATTR_FLAG_NONE,
+ "Spectra MLM RW",
+ /*suffix*/NULL, /*to_str*/ scsi_attrib_hexdump_sbuf,
+ /*parse_str*/ NULL },
+ { 0x17f4, SCSI_ATTR_FLAG_NONE,
+ "Spectra MLM SDC List",
+ /*suffix*/NULL, /*to_str*/ scsi_attrib_hexdump_sbuf,
+ /*parse_str*/ NULL },
+ { 0x17f7, SCSI_ATTR_FLAG_NONE,
+ "Spectra MLM Post Scan",
+ /*suffix*/NULL, /*to_str*/ scsi_attrib_hexdump_sbuf,
+ /*parse_str*/ NULL },
+ { 0x17ff, SCSI_ATTR_FLAG_NONE,
+ "Spectra MLM Checksum",
+ /*suffix*/NULL, /*to_str*/ scsi_attrib_hexdump_sbuf,
+ /*parse_str*/ NULL },
+};
+
+/*
+ * Print out Volume Coherency Information (Attribute 0x080c).
+ * This field has two variable length members, including one at the
+ * beginning, so it isn't practical to have a fixed structure definition.
+ * This is current as of SSC4r03 (see section 4.2.21.3), dated March 25,
+ * 2013.
+ */
+int
+scsi_attrib_volcoh_sbuf(struct sbuf *sb, struct scsi_mam_attribute_header *hdr,
+ uint32_t valid_len, uint32_t flags,
+ uint32_t output_flags, char *error_str,
+ int error_str_len)
+{
+ size_t avail_len;
+ uint32_t field_size;
+ uint64_t tmp_val;
+ uint8_t *cur_ptr;
+ int retval;
+ int vcr_len, as_len;
+
+ retval = 0;
+ tmp_val = 0;
+
+ field_size = scsi_2btoul(hdr->length);
+ avail_len = valid_len - sizeof(*hdr);
+ if (field_size > avail_len) {
+ if (error_str != NULL) {
+ snprintf(error_str, error_str_len, "Available "
+ "length of attribute ID 0x%.4x %zu < field "
+ "length %u", scsi_2btoul(hdr->id), avail_len,
+ field_size);
+ }
+ retval = 1;
+ goto bailout;
+ } else if (field_size == 0) {
+ /*
+ * It isn't clear from the spec whether a field length of
+ * 0 is invalid here. It probably is, but be lenient here
+ * to avoid inconveniencing the user.
+ */
+ goto bailout;
+ }
+ cur_ptr = hdr->attribute;
+ vcr_len = *cur_ptr;
+ cur_ptr++;
+
+ sbuf_printf(sb, "\n\tVolume Change Reference Value:");
+
+ switch (vcr_len) {
+ case 0:
+ if (error_str != NULL) {
+ snprintf(error_str, error_str_len, "Volume Change "
+ "Reference value has length of 0");
+ }
+ retval = 1;
+ goto bailout;
+ break; /*NOTREACHED*/
+ case 1:
+ tmp_val = *cur_ptr;
+ break;
+ case 2:
+ tmp_val = scsi_2btoul(cur_ptr);
+ break;
+ case 3:
+ tmp_val = scsi_3btoul(cur_ptr);
+ break;
+ case 4:
+ tmp_val = scsi_4btoul(cur_ptr);
+ break;
+ case 8:
+ tmp_val = scsi_8btou64(cur_ptr);
+ break;
+ default:
+ sbuf_printf(sb, "\n");
+ sbuf_hexdump(sb, cur_ptr, vcr_len, NULL, 0);
+ break;
+ }
+ if (vcr_len <= 8)
+ sbuf_printf(sb, " 0x%jx\n", (uintmax_t)tmp_val);
+
+ cur_ptr += vcr_len;
+ tmp_val = scsi_8btou64(cur_ptr);
+ sbuf_printf(sb, "\tVolume Coherency Count: %ju\n", (uintmax_t)tmp_val);
+
+ cur_ptr += sizeof(tmp_val);
+ tmp_val = scsi_8btou64(cur_ptr);
+ sbuf_printf(sb, "\tVolume Coherency Set Identifier: 0x%jx\n",
+ (uintmax_t)tmp_val);
+
+ /*
+ * Figure out how long the Application Client Specific Information
+ * is and produce a hexdump.
+ */
+ cur_ptr += sizeof(tmp_val);
+ as_len = scsi_2btoul(cur_ptr);
+ cur_ptr += sizeof(uint16_t);
+ sbuf_printf(sb, "\tApplication Client Specific Information: ");
+ if (((as_len == SCSI_LTFS_VER0_LEN)
+ || (as_len == SCSI_LTFS_VER1_LEN))
+ && (strncmp(cur_ptr, SCSI_LTFS_STR_NAME, SCSI_LTFS_STR_LEN) == 0)) {
+ sbuf_printf(sb, "LTFS\n");
+ cur_ptr += SCSI_LTFS_STR_LEN + 1;
+ if (cur_ptr[SCSI_LTFS_UUID_LEN] != '\0')
+ cur_ptr[SCSI_LTFS_UUID_LEN] = '\0';
+ sbuf_printf(sb, "\tLTFS UUID: %s\n", cur_ptr);
+ cur_ptr += SCSI_LTFS_UUID_LEN + 1;
+ /* XXX KDM check the length */
+ sbuf_printf(sb, "\tLTFS Version: %d\n", *cur_ptr);
+ } else {
+ sbuf_printf(sb, "Unknown\n");
+ sbuf_hexdump(sb, cur_ptr, as_len, NULL, 0);
+ }
+
+bailout:
+ return (retval);
+}
+
+int
+scsi_attrib_vendser_sbuf(struct sbuf *sb, struct scsi_mam_attribute_header *hdr,
+ uint32_t valid_len, uint32_t flags,
+ uint32_t output_flags, char *error_str,
+ int error_str_len)
+{
+ size_t avail_len;
+ uint32_t field_size;
+ struct scsi_attrib_vendser *vendser;
+ cam_strvis_flags strvis_flags;
+ int retval = 0;
+
+ field_size = scsi_2btoul(hdr->length);
+ avail_len = valid_len - sizeof(*hdr);
+ if (field_size > avail_len) {
+ if (error_str != NULL) {
+ snprintf(error_str, error_str_len, "Available "
+ "length of attribute ID 0x%.4x %zu < field "
+ "length %u", scsi_2btoul(hdr->id), avail_len,
+ field_size);
+ }
+ retval = 1;
+ goto bailout;
+ } else if (field_size == 0) {
+ /*
+ * A field size of 0 doesn't make sense here. The device
+ * can at least give you the vendor ID, even if it can't
+ * give you the serial number.
+ */
+ if (error_str != NULL) {
+ snprintf(error_str, error_str_len, "The length of "
+ "attribute ID 0x%.4x is 0",
+ scsi_2btoul(hdr->id));
+ }
+ retval = 1;
+ goto bailout;
+ }
+ vendser = (struct scsi_attrib_vendser *)hdr->attribute;
+
+ switch (output_flags & SCSI_ATTR_OUTPUT_NONASCII_MASK) {
+ case SCSI_ATTR_OUTPUT_NONASCII_TRIM:
+ strvis_flags = CAM_STRVIS_FLAG_NONASCII_TRIM;
+ break;
+ case SCSI_ATTR_OUTPUT_NONASCII_RAW:
+ strvis_flags = CAM_STRVIS_FLAG_NONASCII_RAW;
+ break;
+ case SCSI_ATTR_OUTPUT_NONASCII_ESC:
+ default:
+ strvis_flags = CAM_STRVIS_FLAG_NONASCII_ESC;
+ break;;
+ }
+ cam_strvis_sbuf(sb, vendser->vendor, sizeof(vendser->vendor),
+ strvis_flags);
+ sbuf_putc(sb, ' ');
+ cam_strvis_sbuf(sb, vendser->serial_num, sizeof(vendser->serial_num),
+ strvis_flags);
+bailout:
+ return (retval);
+}
+
+int
+scsi_attrib_hexdump_sbuf(struct sbuf *sb, struct scsi_mam_attribute_header *hdr,
+ uint32_t valid_len, uint32_t flags,
+ uint32_t output_flags, char *error_str,
+ int error_str_len)
+{
+ uint32_t field_size;
+ ssize_t avail_len;
+ uint32_t print_len;
+ uint8_t *num_ptr;
+ int retval = 0;
+
+ field_size = scsi_2btoul(hdr->length);
+ avail_len = valid_len - sizeof(*hdr);
+ print_len = MIN(avail_len, field_size);
+ num_ptr = hdr->attribute;
+
+ if (print_len > 0) {
+ sbuf_printf(sb, "\n");
+ sbuf_hexdump(sb, num_ptr, print_len, NULL, 0);
+ }
+
+ return (retval);
+}
+
+int
+scsi_attrib_int_sbuf(struct sbuf *sb, struct scsi_mam_attribute_header *hdr,
+ uint32_t valid_len, uint32_t flags,
+ uint32_t output_flags, char *error_str,
+ int error_str_len)
+{
+ uint64_t print_number;
+ size_t avail_len;
+ uint32_t number_size;
+ int retval = 0;
+
+ number_size = scsi_2btoul(hdr->length);
+
+ avail_len = valid_len - sizeof(*hdr);
+ if (avail_len < number_size) {
+ if (error_str != NULL) {
+ snprintf(error_str, error_str_len, "Available "
+ "length of attribute ID 0x%.4x %zu < field "
+ "length %u", scsi_2btoul(hdr->id), avail_len,
+ number_size);
+ }
+ retval = 1;
+ goto bailout;
+ }
+
+ switch (number_size) {
+ case 0:
+ /*
+ * We don't treat this as an error, since there may be
+ * scenarios where a device reports a field but then gives
+ * a length of 0. See the note in scsi_attrib_ascii_sbuf().
+ */
+ goto bailout;
+ break; /*NOTREACHED*/
+ case 1:
+ print_number = hdr->attribute[0];
+ break;
+ case 2:
+ print_number = scsi_2btoul(hdr->attribute);
+ break;
+ case 3:
+ print_number = scsi_3btoul(hdr->attribute);
+ break;
+ case 4:
+ print_number = scsi_4btoul(hdr->attribute);
+ break;
+ case 8:
+ print_number = scsi_8btou64(hdr->attribute);
+ break;
+ default:
+ /*
+ * If we wind up here, the number is too big to print
+ * normally, so just do a hexdump.
+ */
+ retval = scsi_attrib_hexdump_sbuf(sb, hdr, valid_len,
+ flags, output_flags,
+ error_str, error_str_len);
+ goto bailout;
+ break;
+ }
+
+ if (flags & SCSI_ATTR_FLAG_FP) {
+#ifndef _KERNEL
+ long double num_float;
+
+ num_float = (long double)print_number;
+
+ if (flags & SCSI_ATTR_FLAG_DIV_10)
+ num_float /= 10;
+
+ sbuf_printf(sb, "%.*Lf", (flags & SCSI_ATTR_FLAG_FP_1DIGIT) ?
+ 1 : 0, num_float);
+#else /* _KERNEL */
+ sbuf_printf(sb, "%ju", (flags & SCSI_ATTR_FLAG_DIV_10) ?
+ (print_number / 10) : print_number);
+#endif /* _KERNEL */
+ } else if (flags & SCSI_ATTR_FLAG_HEX) {
+ sbuf_printf(sb, "0x%jx", (uintmax_t)print_number);
+ } else
+ sbuf_printf(sb, "%ju", (uintmax_t)print_number);
+
+bailout:
+ return (retval);
+}
+
+int
+scsi_attrib_ascii_sbuf(struct sbuf *sb, struct scsi_mam_attribute_header *hdr,
+ uint32_t valid_len, uint32_t flags,
+ uint32_t output_flags, char *error_str,
+ int error_str_len)
+{
+ size_t avail_len;
+ uint32_t field_size, print_size;
+ int retval = 0;
+
+ avail_len = valid_len - sizeof(*hdr);
+ field_size = scsi_2btoul(hdr->length);
+ print_size = MIN(avail_len, field_size);
+
+ if (print_size > 0) {
+ cam_strvis_flags strvis_flags;
+
+ switch (output_flags & SCSI_ATTR_OUTPUT_NONASCII_MASK) {
+ case SCSI_ATTR_OUTPUT_NONASCII_TRIM:
+ strvis_flags = CAM_STRVIS_FLAG_NONASCII_TRIM;
+ break;
+ case SCSI_ATTR_OUTPUT_NONASCII_RAW:
+ strvis_flags = CAM_STRVIS_FLAG_NONASCII_RAW;
+ break;
+ case SCSI_ATTR_OUTPUT_NONASCII_ESC:
+ default:
+ strvis_flags = CAM_STRVIS_FLAG_NONASCII_ESC;
+ break;
+ }
+ cam_strvis_sbuf(sb, hdr->attribute, print_size, strvis_flags);
+ } else if (avail_len < field_size) {
+ /*
+ * We only report an error if the user didn't allocate
+ * enough space to hold the full value of this field. If
+ * the field length is 0, that is allowed by the spec.
+ * e.g. in SPC-4r37, section 7.4.2.2.5, VOLUME IDENTIFIER
+ * "This attribute indicates the current volume identifier
+ * (see SMC-3) of the medium. If the device server supports
+ * this attribute but does not have access to the volume
+ * identifier, the device server shall report this attribute
+ * with an attribute length value of zero."
+ */
+ if (error_str != NULL) {
+ snprintf(error_str, error_str_len, "Available "
+ "length of attribute ID 0x%.4x %zu < field "
+ "length %u", scsi_2btoul(hdr->id), avail_len,
+ field_size);
+ }
+ retval = 1;
+ }
+
+ return (retval);
+}
+
+int
+scsi_attrib_text_sbuf(struct sbuf *sb, struct scsi_mam_attribute_header *hdr,
+ uint32_t valid_len, uint32_t flags,
+ uint32_t output_flags, char *error_str,
+ int error_str_len)
+{
+ size_t avail_len;
+ uint32_t field_size, print_size;
+ int retval = 0;
+ int esc_text = 1;
+
+ avail_len = valid_len - sizeof(*hdr);
+ field_size = scsi_2btoul(hdr->length);
+ print_size = MIN(avail_len, field_size);
+
+ if ((output_flags & SCSI_ATTR_OUTPUT_TEXT_MASK) ==
+ SCSI_ATTR_OUTPUT_TEXT_RAW)
+ esc_text = 0;
+
+ if (print_size > 0) {
+ uint32_t i;
+
+ for (i = 0; i < print_size; i++) {
+ if (hdr->attribute[i] == '\0')
+ continue;
+ else if (((unsigned char)hdr->attribute[i] < 0x80)
+ || (esc_text == 0))
+ sbuf_putc(sb, hdr->attribute[i]);
+ else
+ sbuf_printf(sb, "%%%02x",
+ (unsigned char)hdr->attribute[i]);
+ }
+ } else if (avail_len < field_size) {
+ /*
+ * We only report an error if the user didn't allocate
+ * enough space to hold the full value of this field.
+ */
+ if (error_str != NULL) {
+ snprintf(error_str, error_str_len, "Available "
+ "length of attribute ID 0x%.4x %zu < field "
+ "length %u", scsi_2btoul(hdr->id), avail_len,
+ field_size);
+ }
+ retval = 1;
+ }
+
+ return (retval);
+}
+
+struct scsi_attrib_table_entry *
+scsi_find_attrib_entry(struct scsi_attrib_table_entry *table,
+ size_t num_table_entries, uint32_t id)
+{
+ uint32_t i;
+
+ for (i = 0; i < num_table_entries; i++) {
+ if (table[i].id == id)
+ return (&table[i]);
+ }
+
+ return (NULL);
+}
+
+struct scsi_attrib_table_entry *
+scsi_get_attrib_entry(uint32_t id)
+{
+ return (scsi_find_attrib_entry(scsi_mam_attr_table,
+ nitems(scsi_mam_attr_table), id));
+}
+
+int
+scsi_attrib_value_sbuf(struct sbuf *sb, uint32_t valid_len,
+ struct scsi_mam_attribute_header *hdr, uint32_t output_flags,
+ char *error_str, size_t error_str_len)
+{
+ int retval;
+
+ switch (hdr->byte2 & SMA_FORMAT_MASK) {
+ case SMA_FORMAT_ASCII:
+ retval = scsi_attrib_ascii_sbuf(sb, hdr, valid_len,
+ SCSI_ATTR_FLAG_NONE, output_flags, error_str,error_str_len);
+ break;
+ case SMA_FORMAT_BINARY:
+ if (scsi_2btoul(hdr->length) <= 8)
+ retval = scsi_attrib_int_sbuf(sb, hdr, valid_len,
+ SCSI_ATTR_FLAG_NONE, output_flags, error_str,
+ error_str_len);
+ else
+ retval = scsi_attrib_hexdump_sbuf(sb, hdr, valid_len,
+ SCSI_ATTR_FLAG_NONE, output_flags, error_str,
+ error_str_len);
+ break;
+ case SMA_FORMAT_TEXT:
+ retval = scsi_attrib_text_sbuf(sb, hdr, valid_len,
+ SCSI_ATTR_FLAG_NONE, output_flags, error_str,
+ error_str_len);
+ break;
+ default:
+ if (error_str != NULL) {
+ snprintf(error_str, error_str_len, "Unknown attribute "
+ "format 0x%x", hdr->byte2 & SMA_FORMAT_MASK);
+ }
+ retval = 1;
+ goto bailout;
+ break; /*NOTREACHED*/
+ }
+
+ sbuf_trim(sb);
+
+bailout:
+
+ return (retval);
+}
+
+void
+scsi_attrib_prefix_sbuf(struct sbuf *sb, uint32_t output_flags,
+ struct scsi_mam_attribute_header *hdr,
+ uint32_t valid_len, const char *desc)
+{
+ int need_space = 0;
+ uint32_t len;
+ uint32_t id;
+
+ /*
+ * We can't do anything if we don't have enough valid data for the
+ * header.
+ */
+ if (valid_len < sizeof(*hdr))
+ return;
+
+ id = scsi_2btoul(hdr->id);
+ /*
+ * Note that we print out the value of the attribute listed in the
+ * header, regardless of whether we actually got that many bytes
+ * back from the device through the controller. A truncated result
+ * could be the result of a failure to ask for enough data; the
+ * header indicates how many bytes are allocated for this attribute
+ * in the MAM.
+ */
+ len = scsi_2btoul(hdr->length);
+
+ if ((output_flags & SCSI_ATTR_OUTPUT_FIELD_MASK) ==
+ SCSI_ATTR_OUTPUT_FIELD_NONE)
+ return;
+
+ if ((output_flags & SCSI_ATTR_OUTPUT_FIELD_DESC)
+ && (desc != NULL)) {
+ sbuf_printf(sb, "%s", desc);
+ need_space = 1;
+ }
+
+ if (output_flags & SCSI_ATTR_OUTPUT_FIELD_NUM) {
+ sbuf_printf(sb, "%s(0x%.4x)", (need_space) ? " " : "", id);
+ need_space = 0;
+ }
+
+ if (output_flags & SCSI_ATTR_OUTPUT_FIELD_SIZE) {
+ sbuf_printf(sb, "%s[%d]", (need_space) ? " " : "", len);
+ need_space = 0;
+ }
+ if (output_flags & SCSI_ATTR_OUTPUT_FIELD_RW) {
+ sbuf_printf(sb, "%s(%s)", (need_space) ? " " : "",
+ (hdr->byte2 & SMA_READ_ONLY) ? "RO" : "RW");
+ }
+ sbuf_printf(sb, ": ");
+}
+
+int
+scsi_attrib_sbuf(struct sbuf *sb, struct scsi_mam_attribute_header *hdr,
+ uint32_t valid_len, struct scsi_attrib_table_entry *user_table,
+ size_t num_user_entries, int prefer_user_table,
+ uint32_t output_flags, char *error_str, int error_str_len)
+{
+ int retval;
+ struct scsi_attrib_table_entry *table1 = NULL, *table2 = NULL;
+ struct scsi_attrib_table_entry *entry = NULL;
+ size_t table1_size = 0, table2_size = 0;
+ uint32_t id;
+
+ retval = 0;
+
+ if (valid_len < sizeof(*hdr)) {
+ retval = 1;
+ goto bailout;
+ }
+
+ id = scsi_2btoul(hdr->id);
+
+ if (user_table != NULL) {
+ if (prefer_user_table != 0) {
+ table1 = user_table;
+ table1_size = num_user_entries;
+ table2 = scsi_mam_attr_table;
+ table2_size = nitems(scsi_mam_attr_table);
+ } else {
+ table1 = scsi_mam_attr_table;
+ table1_size = nitems(scsi_mam_attr_table);
+ table2 = user_table;
+ table2_size = num_user_entries;
+ }
+ } else {
+ table1 = scsi_mam_attr_table;
+ table1_size = nitems(scsi_mam_attr_table);
+ }
+
+ entry = scsi_find_attrib_entry(table1, table1_size, id);
+ if (entry != NULL) {
+ scsi_attrib_prefix_sbuf(sb, output_flags, hdr, valid_len,
+ entry->desc);
+ if (entry->to_str == NULL)
+ goto print_default;
+ retval = entry->to_str(sb, hdr, valid_len, entry->flags,
+ output_flags, error_str, error_str_len);
+ goto bailout;
+ }
+ if (table2 != NULL) {
+ entry = scsi_find_attrib_entry(table2, table2_size, id);
+ if (entry != NULL) {
+ if (entry->to_str == NULL)
+ goto print_default;
+
+ scsi_attrib_prefix_sbuf(sb, output_flags, hdr,
+ valid_len, entry->desc);
+ retval = entry->to_str(sb, hdr, valid_len, entry->flags,
+ output_flags, error_str,
+ error_str_len);
+ goto bailout;
+ }
+ }
+
+ scsi_attrib_prefix_sbuf(sb, output_flags, hdr, valid_len, NULL);
+
+print_default:
+ retval = scsi_attrib_value_sbuf(sb, valid_len, hdr, output_flags,
+ error_str, error_str_len);
+bailout:
+ if (retval == 0) {
+ if ((entry != NULL)
+ && (entry->suffix != NULL))
+ sbuf_printf(sb, " %s", entry->suffix);
+
+ sbuf_trim(sb);
+ sbuf_printf(sb, "\n");
+ }
+
+ return (retval);
+}
+
void
scsi_test_unit_ready(struct ccb_scsiio *csio, u_int32_t retries,
void (*cbfcnp)(struct cam_periph *, union ccb *),
@@ -5500,7 +7514,6 @@ scsi_test_unit_ready(struct ccb_scsiio *csio, u_int32_t retries,
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 *),
@@ -5525,7 +7538,6 @@ scsi_request_sense(struct ccb_scsiio *csio, u_int32_t retries,
scsi_cmd->opcode = REQUEST_SENSE;
scsi_cmd->length = dxfer_len;
}
-#endif /* __rtems__ */
void
scsi_inquiry(struct ccb_scsiio *csio, u_int32_t retries,
@@ -5557,7 +7569,6 @@ scsi_inquiry(struct ccb_scsiio *csio, u_int32_t retries,
scsi_ulto2b(inq_len, scsi_cmd->length);
}
-#ifndef __rtems__
void
scsi_mode_sense(struct ccb_scsiio *csio, u_int32_t retries,
void (*cbfcnp)(struct cam_periph *, union ccb *),
@@ -5790,7 +7801,6 @@ scsi_prevent(struct ccb_scsiio *csio, u_int32_t retries,
scsi_cmd->opcode = PREVENT_ALLOW;
scsi_cmd->how = action;
}
-#endif /* __rtems__ */
/* XXX allow specification of address and PMI bit and LBA */
void
@@ -5823,8 +7833,8 @@ 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)
+ uint8_t *rcap_buf, int rcap_buf_len, uint8_t sense_len,
+ uint32_t timeout)
{
struct scsi_read_capacity_16 *scsi_cmd;
@@ -5835,7 +7845,7 @@ scsi_read_capacity_16(struct ccb_scsiio *csio, uint32_t retries,
/*flags*/CAM_DIR_IN,
tag_action,
/*data_ptr*/(u_int8_t *)rcap_buf,
- /*dxfer_len*/sizeof(*rcap_buf),
+ /*dxfer_len*/rcap_buf_len,
sense_len,
sizeof(*scsi_cmd),
timeout);
@@ -5844,7 +7854,7 @@ scsi_read_capacity_16(struct ccb_scsiio *csio, uint32_t retries,
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);
+ scsi_ulto4b(rcap_buf_len, scsi_cmd->alloc_len);
if (pmi)
reladr |= SRC16_PMI;
if (reladr)
@@ -6152,23 +8162,30 @@ scsi_ata_identify(struct ccb_scsiio *csio, u_int32_t retries,
u_int16_t dxfer_len, u_int8_t sense_len,
u_int32_t timeout)
{
- scsi_ata_pass_16(csio,
- retries,
- cbfcnp,
- /*flags*/CAM_DIR_IN,
- tag_action,
- /*protocol*/AP_PROTO_PIO_IN,
- /*ata_flags*/AP_FLAG_TDIR_FROM_DEV|
- AP_FLAG_BYT_BLOK_BYTES|AP_FLAG_TLEN_SECT_CNT,
- /*features*/0,
- /*sector_count*/dxfer_len,
- /*lba*/0,
- /*command*/ATA_ATA_IDENTIFY,
- /*control*/0,
- data_ptr,
- dxfer_len,
- sense_len,
- timeout);
+ scsi_ata_pass(csio,
+ retries,
+ cbfcnp,
+ /*flags*/CAM_DIR_IN,
+ tag_action,
+ /*protocol*/AP_PROTO_PIO_IN,
+ /*ata_flags*/AP_FLAG_TDIR_FROM_DEV |
+ AP_FLAG_BYT_BLOK_BYTES |
+ AP_FLAG_TLEN_SECT_CNT,
+ /*features*/0,
+ /*sector_count*/dxfer_len,
+ /*lba*/0,
+ /*command*/ATA_ATA_IDENTIFY,
+ /*device*/ 0,
+ /*icc*/ 0,
+ /*auxiliary*/ 0,
+ /*control*/0,
+ data_ptr,
+ dxfer_len,
+ /*cdb_storage*/ NULL,
+ /*cdb_storage_len*/ 0,
+ /*minimum_cmd_size*/ 0,
+ sense_len,
+ timeout);
}
void
@@ -6196,6 +8213,248 @@ scsi_ata_trim(struct ccb_scsiio *csio, u_int32_t retries,
timeout);
}
+int
+scsi_ata_read_log(struct ccb_scsiio *csio, uint32_t retries,
+ void (*cbfcnp)(struct cam_periph *, union ccb *),
+ uint8_t tag_action, uint32_t log_address,
+ uint32_t page_number, uint16_t block_count,
+ uint8_t protocol, uint8_t *data_ptr, uint32_t dxfer_len,
+ uint8_t sense_len, uint32_t timeout)
+{
+ uint8_t command, protocol_out;
+ uint16_t count_out;
+ uint64_t lba;
+ int retval;
+
+ retval = 0;
+
+ switch (protocol) {
+ case AP_PROTO_DMA:
+ count_out = block_count;
+ command = ATA_READ_LOG_DMA_EXT;
+ protocol_out = AP_PROTO_DMA;
+ break;
+ case AP_PROTO_PIO_IN:
+ default:
+ count_out = block_count;
+ command = ATA_READ_LOG_EXT;
+ protocol_out = AP_PROTO_PIO_IN;
+ break;
+ }
+
+ lba = (((uint64_t)page_number & 0xff00) << 32) |
+ ((page_number & 0x00ff) << 8) |
+ (log_address & 0xff);
+
+ protocol_out |= AP_EXTEND;
+
+ retval = scsi_ata_pass(csio,
+ retries,
+ cbfcnp,
+ /*flags*/CAM_DIR_IN,
+ tag_action,
+ /*protocol*/ protocol_out,
+ /*ata_flags*/AP_FLAG_TLEN_SECT_CNT |
+ AP_FLAG_BYT_BLOK_BLOCKS |
+ AP_FLAG_TDIR_FROM_DEV,
+ /*feature*/ 0,
+ /*sector_count*/ count_out,
+ /*lba*/ lba,
+ /*command*/ command,
+ /*device*/ 0,
+ /*icc*/ 0,
+ /*auxiliary*/ 0,
+ /*control*/0,
+ data_ptr,
+ dxfer_len,
+ /*cdb_storage*/ NULL,
+ /*cdb_storage_len*/ 0,
+ /*minimum_cmd_size*/ 0,
+ sense_len,
+ timeout);
+
+ return (retval);
+}
+
+/*
+ * Note! This is an unusual CDB building function because it can return
+ * an error in the event that the command in question requires a variable
+ * length CDB, but the caller has not given storage space for one or has not
+ * given enough storage space. If there is enough space available in the
+ * standard SCSI CCB CDB bytes, we'll prefer that over passed in storage.
+ */
+int
+scsi_ata_pass(struct ccb_scsiio *csio, uint32_t retries,
+ void (*cbfcnp)(struct cam_periph *, union ccb *),
+ uint32_t flags, uint8_t tag_action,
+ uint8_t protocol, uint8_t ata_flags, uint16_t features,
+ uint16_t sector_count, uint64_t lba, uint8_t command,
+ uint8_t device, uint8_t icc, uint32_t auxiliary,
+ uint8_t control, u_int8_t *data_ptr, uint32_t dxfer_len,
+ uint8_t *cdb_storage, size_t cdb_storage_len,
+ int minimum_cmd_size, u_int8_t sense_len, u_int32_t timeout)
+{
+ uint32_t cam_flags;
+ uint8_t *cdb_ptr;
+ int cmd_size;
+ int retval;
+ uint8_t cdb_len;
+
+ retval = 0;
+ cam_flags = flags;
+
+ /*
+ * Round the user's request to the nearest command size that is at
+ * least as big as what he requested.
+ */
+ if (minimum_cmd_size <= 12)
+ cmd_size = 12;
+ else if (minimum_cmd_size > 16)
+ cmd_size = 32;
+ else
+ cmd_size = 16;
+
+ /*
+ * If we have parameters that require a 48-bit ATA command, we have to
+ * use the 16 byte ATA PASS-THROUGH command at least.
+ */
+ if (((lba > ATA_MAX_28BIT_LBA)
+ || (sector_count > 255)
+ || (features > 255)
+ || (protocol & AP_EXTEND))
+ && ((cmd_size < 16)
+ || ((protocol & AP_EXTEND) == 0))) {
+ if (cmd_size < 16)
+ cmd_size = 16;
+ protocol |= AP_EXTEND;
+ }
+
+ /*
+ * The icc and auxiliary ATA registers are only supported in the
+ * 32-byte version of the ATA PASS-THROUGH command.
+ */
+ if ((icc != 0)
+ || (auxiliary != 0)) {
+ cmd_size = 32;
+ protocol |= AP_EXTEND;
+ }
+
+
+ if ((cmd_size > sizeof(csio->cdb_io.cdb_bytes))
+ && ((cdb_storage == NULL)
+ || (cdb_storage_len < cmd_size))) {
+ retval = 1;
+ goto bailout;
+ }
+
+ /*
+ * At this point we know we have enough space to store the command
+ * in one place or another. We prefer the built-in array, but used
+ * the passed in storage if necessary.
+ */
+ if (cmd_size <= sizeof(csio->cdb_io.cdb_bytes))
+ cdb_ptr = csio->cdb_io.cdb_bytes;
+ else {
+ cdb_ptr = cdb_storage;
+ cam_flags |= CAM_CDB_POINTER;
+ }
+
+ if (cmd_size <= 12) {
+ struct ata_pass_12 *cdb;
+
+ cdb = (struct ata_pass_12 *)cdb_ptr;
+ cdb_len = sizeof(*cdb);
+ bzero(cdb, cdb_len);
+
+ cdb->opcode = ATA_PASS_12;
+ cdb->protocol = protocol;
+ cdb->flags = ata_flags;
+ cdb->features = features;
+ cdb->sector_count = sector_count;
+ cdb->lba_low = lba & 0xff;
+ cdb->lba_mid = (lba >> 8) & 0xff;
+ cdb->lba_high = (lba >> 16) & 0xff;
+ cdb->device = ((lba >> 24) & 0xf) | ATA_DEV_LBA;
+ cdb->command = command;
+ cdb->control = control;
+ } else if (cmd_size <= 16) {
+ struct ata_pass_16 *cdb;
+
+ cdb = (struct ata_pass_16 *)cdb_ptr;
+ cdb_len = sizeof(*cdb);
+ bzero(cdb, cdb_len);
+
+ cdb->opcode = ATA_PASS_16;
+ cdb->protocol = protocol;
+ cdb->flags = ata_flags;
+ cdb->features = features & 0xff;
+ cdb->sector_count = sector_count & 0xff;
+ cdb->lba_low = lba & 0xff;
+ cdb->lba_mid = (lba >> 8) & 0xff;
+ cdb->lba_high = (lba >> 16) & 0xff;
+ /*
+ * If AP_EXTEND is set, we're sending a 48-bit command.
+ * Otherwise it's a 28-bit command.
+ */
+ if (protocol & AP_EXTEND) {
+ cdb->lba_low_ext = (lba >> 24) & 0xff;
+ cdb->lba_mid_ext = (lba >> 32) & 0xff;
+ cdb->lba_high_ext = (lba >> 40) & 0xff;
+ cdb->features_ext = (features >> 8) & 0xff;
+ cdb->sector_count_ext = (sector_count >> 8) & 0xff;
+ cdb->device = device | ATA_DEV_LBA;
+ } else {
+ cdb->lba_low_ext = (lba >> 24) & 0xf;
+ cdb->device = ((lba >> 24) & 0xf) | ATA_DEV_LBA;
+ }
+ cdb->command = command;
+ cdb->control = control;
+ } else {
+ struct ata_pass_32 *cdb;
+ uint8_t tmp_lba[8];
+
+ cdb = (struct ata_pass_32 *)cdb_ptr;
+ cdb_len = sizeof(*cdb);
+ bzero(cdb, cdb_len);
+ cdb->opcode = VARIABLE_LEN_CDB;
+ cdb->control = control;
+ cdb->length = sizeof(*cdb) - __offsetof(struct ata_pass_32,
+ service_action);
+ scsi_ulto2b(ATA_PASS_32_SA, cdb->service_action);
+ cdb->protocol = protocol;
+ cdb->flags = ata_flags;
+
+ if ((protocol & AP_EXTEND) == 0) {
+ lba &= 0x0fffffff;
+ cdb->device = ((lba >> 24) & 0xf) | ATA_DEV_LBA;
+ features &= 0xff;
+ sector_count &= 0xff;
+ } else {
+ cdb->device = device | ATA_DEV_LBA;
+ }
+ scsi_u64to8b(lba, tmp_lba);
+ bcopy(&tmp_lba[2], cdb->lba, sizeof(cdb->lba));
+ scsi_ulto2b(features, cdb->features);
+ scsi_ulto2b(sector_count, cdb->count);
+ cdb->command = command;
+ cdb->icc = icc;
+ scsi_ulto4b(auxiliary, cdb->auxiliary);
+ }
+
+ cam_fill_csio(csio,
+ retries,
+ cbfcnp,
+ cam_flags,
+ tag_action,
+ data_ptr,
+ dxfer_len,
+ sense_len,
+ cmd_size,
+ timeout);
+bailout:
+ return (retval);
+}
+
void
scsi_ata_pass_16(struct ccb_scsiio *csio, u_int32_t retries,
void (*cbfcnp)(struct cam_periph *, union ccb *),
@@ -6434,6 +8693,229 @@ scsi_start_stop(struct ccb_scsiio *csio, u_int32_t retries,
timeout);
}
+void
+scsi_read_attribute(struct ccb_scsiio *csio, u_int32_t retries,
+ void (*cbfcnp)(struct cam_periph *, union ccb *),
+ u_int8_t tag_action, u_int8_t service_action,
+ uint32_t element, u_int8_t elem_type, int logical_volume,
+ int partition, u_int32_t first_attribute, int cache,
+ u_int8_t *data_ptr, u_int32_t length, int sense_len,
+ u_int32_t timeout)
+{
+ struct scsi_read_attribute *scsi_cmd;
+
+ scsi_cmd = (struct scsi_read_attribute *)&csio->cdb_io.cdb_bytes;
+ bzero(scsi_cmd, sizeof(*scsi_cmd));
+
+ scsi_cmd->opcode = READ_ATTRIBUTE;
+ scsi_cmd->service_action = service_action;
+ scsi_ulto2b(element, scsi_cmd->element);
+ scsi_cmd->elem_type = elem_type;
+ scsi_cmd->logical_volume = logical_volume;
+ scsi_cmd->partition = partition;
+ scsi_ulto2b(first_attribute, scsi_cmd->first_attribute);
+ scsi_ulto4b(length, scsi_cmd->length);
+ if (cache != 0)
+ scsi_cmd->cache |= SRA_CACHE;
+
+ cam_fill_csio(csio,
+ retries,
+ cbfcnp,
+ /*flags*/CAM_DIR_IN,
+ tag_action,
+ /*data_ptr*/data_ptr,
+ /*dxfer_len*/length,
+ sense_len,
+ sizeof(*scsi_cmd),
+ timeout);
+}
+
+void
+scsi_write_attribute(struct ccb_scsiio *csio, u_int32_t retries,
+ void (*cbfcnp)(struct cam_periph *, union ccb *),
+ u_int8_t tag_action, uint32_t element, int logical_volume,
+ int partition, int wtc, u_int8_t *data_ptr,
+ u_int32_t length, int sense_len, u_int32_t timeout)
+{
+ struct scsi_write_attribute *scsi_cmd;
+
+ scsi_cmd = (struct scsi_write_attribute *)&csio->cdb_io.cdb_bytes;
+ bzero(scsi_cmd, sizeof(*scsi_cmd));
+
+ scsi_cmd->opcode = WRITE_ATTRIBUTE;
+ if (wtc != 0)
+ scsi_cmd->byte2 = SWA_WTC;
+ scsi_ulto3b(element, scsi_cmd->element);
+ scsi_cmd->logical_volume = logical_volume;
+ scsi_cmd->partition = partition;
+ scsi_ulto4b(length, scsi_cmd->length);
+
+ cam_fill_csio(csio,
+ retries,
+ cbfcnp,
+ /*flags*/CAM_DIR_OUT,
+ tag_action,
+ /*data_ptr*/data_ptr,
+ /*dxfer_len*/length,
+ sense_len,
+ sizeof(*scsi_cmd),
+ timeout);
+}
+
+void
+scsi_persistent_reserve_in(struct ccb_scsiio *csio, uint32_t retries,
+ void (*cbfcnp)(struct cam_periph *, union ccb *),
+ uint8_t tag_action, int service_action,
+ uint8_t *data_ptr, uint32_t dxfer_len, int sense_len,
+ int timeout)
+{
+ struct scsi_per_res_in *scsi_cmd;
+
+ scsi_cmd = (struct scsi_per_res_in *)&csio->cdb_io.cdb_bytes;
+ bzero(scsi_cmd, sizeof(*scsi_cmd));
+
+ scsi_cmd->opcode = PERSISTENT_RES_IN;
+ scsi_cmd->action = service_action;
+ scsi_ulto2b(dxfer_len, scsi_cmd->length);
+
+ cam_fill_csio(csio,
+ retries,
+ cbfcnp,
+ /*flags*/CAM_DIR_IN,
+ tag_action,
+ data_ptr,
+ dxfer_len,
+ sense_len,
+ sizeof(*scsi_cmd),
+ timeout);
+}
+
+void
+scsi_persistent_reserve_out(struct ccb_scsiio *csio, uint32_t retries,
+ void (*cbfcnp)(struct cam_periph *, union ccb *),
+ uint8_t tag_action, int service_action,
+ int scope, int res_type, uint8_t *data_ptr,
+ uint32_t dxfer_len, int sense_len, int timeout)
+{
+ struct scsi_per_res_out *scsi_cmd;
+
+ scsi_cmd = (struct scsi_per_res_out *)&csio->cdb_io.cdb_bytes;
+ bzero(scsi_cmd, sizeof(*scsi_cmd));
+
+ scsi_cmd->opcode = PERSISTENT_RES_OUT;
+ scsi_cmd->action = service_action;
+ scsi_cmd->scope_type = scope | res_type;
+ scsi_ulto4b(dxfer_len, scsi_cmd->length);
+
+ cam_fill_csio(csio,
+ retries,
+ cbfcnp,
+ /*flags*/CAM_DIR_OUT,
+ tag_action,
+ /*data_ptr*/data_ptr,
+ /*dxfer_len*/dxfer_len,
+ sense_len,
+ sizeof(*scsi_cmd),
+ timeout);
+}
+
+void
+scsi_security_protocol_in(struct ccb_scsiio *csio, uint32_t retries,
+ void (*cbfcnp)(struct cam_periph *, union ccb *),
+ uint8_t tag_action, uint32_t security_protocol,
+ uint32_t security_protocol_specific, int byte4,
+ uint8_t *data_ptr, uint32_t dxfer_len, int sense_len,
+ int timeout)
+{
+ struct scsi_security_protocol_in *scsi_cmd;
+
+ scsi_cmd = (struct scsi_security_protocol_in *)&csio->cdb_io.cdb_bytes;
+ bzero(scsi_cmd, sizeof(*scsi_cmd));
+
+ scsi_cmd->opcode = SECURITY_PROTOCOL_IN;
+
+ scsi_cmd->security_protocol = security_protocol;
+ scsi_ulto2b(security_protocol_specific,
+ scsi_cmd->security_protocol_specific);
+ scsi_cmd->byte4 = byte4;
+ scsi_ulto4b(dxfer_len, scsi_cmd->length);
+
+ cam_fill_csio(csio,
+ retries,
+ cbfcnp,
+ /*flags*/CAM_DIR_IN,
+ tag_action,
+ data_ptr,
+ dxfer_len,
+ sense_len,
+ sizeof(*scsi_cmd),
+ timeout);
+}
+
+void
+scsi_security_protocol_out(struct ccb_scsiio *csio, uint32_t retries,
+ void (*cbfcnp)(struct cam_periph *, union ccb *),
+ uint8_t tag_action, uint32_t security_protocol,
+ uint32_t security_protocol_specific, int byte4,
+ uint8_t *data_ptr, uint32_t dxfer_len, int sense_len,
+ int timeout)
+{
+ struct scsi_security_protocol_out *scsi_cmd;
+
+ scsi_cmd = (struct scsi_security_protocol_out *)&csio->cdb_io.cdb_bytes;
+ bzero(scsi_cmd, sizeof(*scsi_cmd));
+
+ scsi_cmd->opcode = SECURITY_PROTOCOL_OUT;
+
+ scsi_cmd->security_protocol = security_protocol;
+ scsi_ulto2b(security_protocol_specific,
+ scsi_cmd->security_protocol_specific);
+ scsi_cmd->byte4 = byte4;
+ scsi_ulto4b(dxfer_len, scsi_cmd->length);
+
+ cam_fill_csio(csio,
+ retries,
+ cbfcnp,
+ /*flags*/CAM_DIR_OUT,
+ tag_action,
+ data_ptr,
+ dxfer_len,
+ sense_len,
+ sizeof(*scsi_cmd),
+ timeout);
+}
+
+void
+scsi_report_supported_opcodes(struct ccb_scsiio *csio, uint32_t retries,
+ void (*cbfcnp)(struct cam_periph *, union ccb *),
+ uint8_t tag_action, int options, int req_opcode,
+ int req_service_action, uint8_t *data_ptr,
+ uint32_t dxfer_len, int sense_len, int timeout)
+{
+ struct scsi_report_supported_opcodes *scsi_cmd;
+
+ scsi_cmd = (struct scsi_report_supported_opcodes *)
+ &csio->cdb_io.cdb_bytes;
+ bzero(scsi_cmd, sizeof(*scsi_cmd));
+
+ scsi_cmd->opcode = MAINTENANCE_IN;
+ scsi_cmd->service_action = REPORT_SUPPORTED_OPERATION_CODES;
+ scsi_cmd->options = options;
+ scsi_cmd->requested_opcode = req_opcode;
+ scsi_ulto2b(req_service_action, scsi_cmd->requested_service_action);
+ scsi_ulto4b(dxfer_len, scsi_cmd->length);
+
+ cam_fill_csio(csio,
+ retries,
+ cbfcnp,
+ /*flags*/CAM_DIR_IN,
+ tag_action,
+ data_ptr,
+ dxfer_len,
+ sense_len,
+ sizeof(*scsi_cmd),
+ timeout);
+}
/*
* Try make as good a match as possible with
@@ -6500,7 +8982,7 @@ scsi_static_inquiry_match(caddr_t inqbuffer, caddr_t table_entry)
* \return 0 on a match, -1 otherwise.
*
* Treat rhs and lhs as arrays of vpd device id descriptors. Walk lhs matching
- * agains each element in rhs until all data are exhausted or we have found
+ * against each element in rhs until all data are exhausted or we have found
* a match.
*/
int
diff --git a/freebsd/sys/cam/scsi/scsi_all.h b/freebsd/sys/cam/scsi/scsi_all.h
index 326ce990..1fd45405 100644
--- a/freebsd/sys/cam/scsi/scsi_all.h
+++ b/freebsd/sys/cam/scsi/scsi_all.h
@@ -103,6 +103,9 @@ typedef enum {
/* The retyable, error action, with table specified error code */
#define SS_RET SS_RETRY|SSQ_DECREMENT_COUNT|SSQ_PRINT_SENSE
+/* Wait for transient error status to change */
+#define SS_WAIT SS_TUR|SSQ_MANY|SSQ_DECREMENT_COUNT|SSQ_PRINT_SENSE
+
/* Fatal error action, with table specified error code */
#define SS_FATAL SS_FAIL|SSQ_PRINT_SENSE
@@ -278,6 +281,7 @@ struct scsi_per_res_in
#define SPRI_RS 0x03
u_int8_t reserved[5];
u_int8_t length[2];
+#define SPRI_MAX_LEN 0xffff
u_int8_t control;
};
@@ -302,13 +306,22 @@ struct scsi_per_res_cap
{
uint8_t length[2];
uint8_t flags1;
-#define SPRI_CRH 0x10
-#define SPRI_SIP_C 0x08
-#define SPRI_ATP_C 0x04
-#define SPRI_PTPL_C 0x01
+#define SPRI_RLR_C 0x80
+#define SPRI_CRH 0x10
+#define SPRI_SIP_C 0x08
+#define SPRI_ATP_C 0x04
+#define SPRI_PTPL_C 0x01
uint8_t flags2;
-#define SPRI_TMV 0x80
-#define SPRI_PTPL_A 0x01
+#define SPRI_TMV 0x80
+#define SPRI_ALLOW_CMD_MASK 0x70
+#define SPRI_ALLOW_CMD_SHIFT 4
+#define SPRI_ALLOW_NA 0x00
+#define SPRI_ALLOW_1 0x10
+#define SPRI_ALLOW_2 0x20
+#define SPRI_ALLOW_3 0x30
+#define SPRI_ALLOW_4 0x40
+#define SPRI_ALLOW_5 0x50
+#define SPRI_PTPL_A 0x01
uint8_t type_mask[2];
#define SPRI_TM_WR_EX_AR 0x8000
#define SPRI_TM_EX_AC_RO 0x4000
@@ -322,7 +335,7 @@ struct scsi_per_res_cap
struct scsi_per_res_in_rsrv_data
{
uint8_t reservation[8];
- uint8_t obsolete1[4];
+ uint8_t scope_addr[4];
uint8_t reserved;
uint8_t scopetype;
#define SPRT_WE 0x01
@@ -331,7 +344,7 @@ struct scsi_per_res_in_rsrv_data
#define SPRT_EARO 0x06
#define SPRT_WEAR 0x07
#define SPRT_EAAR 0x08
- uint8_t obsolete2[2];
+ uint8_t extent_length[2];
};
struct scsi_per_res_in_rsrv
@@ -340,6 +353,26 @@ struct scsi_per_res_in_rsrv
struct scsi_per_res_in_rsrv_data data;
};
+struct scsi_per_res_in_full_desc
+{
+ struct scsi_per_res_key res_key;
+ uint8_t reserved1[4];
+ uint8_t flags;
+#define SPRI_FULL_ALL_TG_PT 0x02
+#define SPRI_FULL_R_HOLDER 0x01
+ uint8_t scopetype;
+ uint8_t reserved2[4];
+ uint8_t rel_trgt_port_id[2];
+ uint8_t additional_length[4];
+ uint8_t transport_id[];
+};
+
+struct scsi_per_res_in_full
+{
+ struct scsi_per_res_in_header header;
+ struct scsi_per_res_in_full_desc desc[];
+};
+
struct scsi_per_res_out
{
u_int8_t opcode;
@@ -352,13 +385,20 @@ struct scsi_per_res_out
#define SPRO_PRE_ABO 0x05
#define SPRO_REG_IGNO 0x06
#define SPRO_REG_MOVE 0x07
+#define SPRO_REPL_LOST_RES 0x08
#define SPRO_ACTION_MASK 0x1f
u_int8_t scope_type;
#define SPR_SCOPE_MASK 0xf0
+#define SPR_SCOPE_SHIFT 4
#define SPR_LU_SCOPE 0x00
+#define SPR_EXTENT_SCOPE 0x10
+#define SPR_ELEMENT_SCOPE 0x20
#define SPR_TYPE_MASK 0x0f
+#define SPR_TYPE_RD_SHARED 0x00
#define SPR_TYPE_WR_EX 0x01
+#define SPR_TYPE_RD_EX 0x02
#define SPR_TYPE_EX_AC 0x03
+#define SPR_TYPE_SHARED 0x04
#define SPR_TYPE_WR_EX_RO 0x05
#define SPR_TYPE_EX_AC_RO 0x06
#define SPR_TYPE_WR_EX_AR 0x07
@@ -372,15 +412,139 @@ struct scsi_per_res_out_parms
{
struct scsi_per_res_key res_key;
u_int8_t serv_act_res_key[8];
- u_int8_t obsolete1[4];
+ u_int8_t scope_spec_address[4];
u_int8_t flags;
#define SPR_SPEC_I_PT 0x08
#define SPR_ALL_TG_PT 0x04
#define SPR_APTPL 0x01
u_int8_t reserved1;
- u_int8_t obsolete2[2];
+ u_int8_t extent_length[2];
+ u_int8_t transport_id_list[];
+};
+
+struct scsi_per_res_out_trans_ids {
+ u_int8_t additional_length[4];
+ u_int8_t transport_ids[];
+};
+
+/*
+ * Used with REGISTER AND MOVE serivce action of the PERSISTENT RESERVE OUT
+ * command.
+ */
+struct scsi_per_res_reg_move
+{
+ struct scsi_per_res_key res_key;
+ u_int8_t serv_act_res_key[8];
+ u_int8_t reserved;
+ u_int8_t flags;
+#define SPR_REG_MOVE_UNREG 0x02
+#define SPR_REG_MOVE_APTPL 0x01
+ u_int8_t rel_trgt_port_id[2];
+ u_int8_t transport_id_length[4];
+ u_int8_t transport_id[];
};
+struct scsi_transportid_header
+{
+ uint8_t format_protocol;
+#define SCSI_TRN_FORMAT_MASK 0xc0
+#define SCSI_TRN_FORMAT_SHIFT 6
+#define SCSI_TRN_PROTO_MASK 0x0f
+};
+
+struct scsi_transportid_fcp
+{
+ uint8_t format_protocol;
+#define SCSI_TRN_FCP_FORMAT_DEFAULT 0x00
+ uint8_t reserved1[7];
+ uint8_t n_port_name[8];
+ uint8_t reserved2[8];
+};
+
+struct scsi_transportid_spi
+{
+ uint8_t format_protocol;
+#define SCSI_TRN_SPI_FORMAT_DEFAULT 0x00
+ uint8_t reserved1;
+ uint8_t scsi_addr[2];
+ uint8_t obsolete[2];
+ uint8_t rel_trgt_port_id[2];
+ uint8_t reserved2[16];
+};
+
+struct scsi_transportid_1394
+{
+ uint8_t format_protocol;
+#define SCSI_TRN_1394_FORMAT_DEFAULT 0x00
+ uint8_t reserved1[7];
+ uint8_t eui64[8];
+ uint8_t reserved2[8];
+};
+
+struct scsi_transportid_rdma
+{
+ uint8_t format_protocol;
+#define SCSI_TRN_RDMA_FORMAT_DEFAULT 0x00
+ uint8_t reserved[7];
+#define SCSI_TRN_RDMA_PORT_LEN 16
+ uint8_t initiator_port_id[SCSI_TRN_RDMA_PORT_LEN];
+};
+
+struct scsi_transportid_iscsi_device
+{
+ uint8_t format_protocol;
+#define SCSI_TRN_ISCSI_FORMAT_DEVICE 0x00
+ uint8_t reserved;
+ uint8_t additional_length[2];
+ uint8_t iscsi_name[];
+};
+
+struct scsi_transportid_iscsi_port
+{
+ uint8_t format_protocol;
+#define SCSI_TRN_ISCSI_FORMAT_PORT 0x40
+ uint8_t reserved;
+ uint8_t additional_length[2];
+ uint8_t iscsi_name[];
+ /*
+ * Followed by a separator and iSCSI initiator session ID
+ */
+};
+
+struct scsi_transportid_sas
+{
+ uint8_t format_protocol;
+#define SCSI_TRN_SAS_FORMAT_DEFAULT 0x00
+ uint8_t reserved1[3];
+ uint8_t sas_address[8];
+ uint8_t reserved2[12];
+};
+
+struct scsi_sop_routing_id_norm {
+ uint8_t bus;
+ uint8_t devfunc;
+#define SCSI_TRN_SOP_BUS_MAX 0xff
+#define SCSI_TRN_SOP_DEV_MAX 0x1f
+#define SCSI_TRN_SOP_DEV_MASK 0xf8
+#define SCSI_TRN_SOP_DEV_SHIFT 3
+#define SCSI_TRN_SOP_FUNC_NORM_MASK 0x07
+#define SCSI_TRN_SOP_FUNC_NORM_MAX 0x07
+};
+
+struct scsi_sop_routing_id_alt {
+ uint8_t bus;
+ uint8_t function;
+#define SCSI_TRN_SOP_FUNC_ALT_MAX 0xff
+};
+
+struct scsi_transportid_sop
+{
+ uint8_t format_protocol;
+#define SCSI_TRN_SOP_FORMAT_DEFAULT 0x00
+ uint8_t reserved1;
+ uint8_t routing_id[2];
+ uint8_t reserved2[20];
+};
struct scsi_log_sense
{
@@ -390,7 +554,7 @@ struct scsi_log_sense
#define SLS_PPC 0x02
u_int8_t page;
#define SLS_PAGE_CODE 0x3F
-#define SLS_ALL_PAGES_PAGE 0x00
+#define SLS_SUPPORTED_PAGES_PAGE 0x00
#define SLS_OVERRUN_PAGE 0x01
#define SLS_ERROR_WRITE_PAGE 0x02
#define SLS_ERROR_READ_PAGE 0x03
@@ -398,14 +562,18 @@ struct scsi_log_sense
#define SLS_ERROR_VERIFY_PAGE 0x05
#define SLS_ERROR_NONMEDIUM_PAGE 0x06
#define SLS_ERROR_LASTN_PAGE 0x07
+#define SLS_LOGICAL_BLOCK_PROVISIONING 0x0c
#define SLS_SELF_TEST_PAGE 0x10
+#define SLS_STAT_AND_PERF 0x19
#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 subpage;
+#define SLS_SUPPORTED_SUBPAGES_SUBPAGE 0xff
+ u_int8_t reserved;
u_int8_t paramptr[2];
u_int8_t length[2];
u_int8_t control;
@@ -431,7 +599,10 @@ struct scsi_log_select
struct scsi_log_header
{
u_int8_t page;
- u_int8_t reserved;
+#define SL_PAGE_CODE 0x3F
+#define SL_SPF 0x40
+#define SL_DS 0x80
+ u_int8_t subpage;
u_int8_t datalen[2];
};
@@ -452,6 +623,45 @@ struct scsi_log_param_header {
u_int8_t param_len;
};
+struct scsi_log_stat_and_perf {
+ struct scsi_log_param_header hdr;
+#define SLP_SAP 0x0001
+ uint8_t read_num[8];
+ uint8_t write_num[8];
+ uint8_t recvieved_lba[8];
+ uint8_t transmitted_lba[8];
+ uint8_t read_int[8];
+ uint8_t write_int[8];
+ uint8_t weighted_num[8];
+ uint8_t weighted_int[8];
+};
+
+struct scsi_log_idle_time {
+ struct scsi_log_param_header hdr;
+#define SLP_IT 0x0002
+ uint8_t idle_int[8];
+};
+
+struct scsi_log_time_interval {
+ struct scsi_log_param_header hdr;
+#define SLP_TI 0x0003
+ uint8_t exponent[4];
+ uint8_t integer[4];
+};
+
+struct scsi_log_fua_stat_and_perf {
+ struct scsi_log_param_header hdr;
+#define SLP_FUA_SAP 0x0004
+ uint8_t fua_read_num[8];
+ uint8_t fua_write_num[8];
+ uint8_t fuanv_read_num[8];
+ uint8_t fuanv_write_num[8];
+ uint8_t fua_read_int[8];
+ uint8_t fua_write_int[8];
+ uint8_t fuanv_read_int[8];
+ uint8_t fuanv_write_int[8];
+};
+
struct scsi_control_page {
u_int8_t page_code;
u_int8_t page_length;
@@ -470,15 +680,37 @@ struct scsi_control_page {
#define SCP_QUEUE_ALG_MASK 0xF0
#define SCP_QUEUE_ALG_RESTRICTED 0x00
#define SCP_QUEUE_ALG_UNRESTRICTED 0x10
+#define SCP_NUAR 0x08 /*No UA on release*/
#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_RAC 0x40 /*Report a check*/
+#define SCP_SWP 0x08 /*Software Write Protect*/
#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 flags4;
+#define SCP_ATO 0x80 /*Application tag owner*/
+#define SCP_TAS 0x40 /*Task aborted status*/
+#define SCP_ATMPE 0x20 /*Application tag mode page*/
+#define SCP_RWWP 0x10 /*Reject write without prot*/
u_int8_t aen_holdoff_period[2];
+ u_int8_t busy_timeout_period[2];
+ u_int8_t extended_selftest_completion_time[2];
+};
+
+struct scsi_control_ext_page {
+ uint8_t page_code;
+ uint8_t subpage_code;
+ uint8_t page_length[2];
+ uint8_t flags;
+#define SCEP_TCMOS 0x04 /* Timestamp Changeable by */
+#define SCEP_SCSIP 0x02 /* SCSI Precedence (clock) */
+#define SCEP_IALUAE 0x01 /* Implicit ALUA Enabled */
+ uint8_t prio;
+ uint8_t max_sense;
+ uint8_t reserve[25];
};
struct scsi_cache_page {
@@ -534,40 +766,6 @@ struct scsi_caching_page {
/*
* XXX KDM move this off to a vendor shim.
*/
-struct copan_power_subpage {
- uint8_t page_code;
-#define PWR_PAGE_CODE 0x00
- uint8_t subpage;
-#define PWR_SUBPAGE_CODE 0x02
- uint8_t page_length[2];
- uint8_t page_version;
-#define PWR_VERSION 0x01
- uint8_t total_luns;
- uint8_t max_active_luns;
-#define PWR_DFLT_MAX_LUNS 0x07
- uint8_t reserved[25];
-};
-
-/*
- * XXX KDM move this off to a vendor shim.
- */
-struct copan_aps_subpage {
- uint8_t page_code;
-#define APS_PAGE_CODE 0x00
- uint8_t subpage;
-#define APS_SUBPAGE_CODE 0x03
- uint8_t page_length[2];
- uint8_t page_version;
-#define APS_VERSION 0x00
- uint8_t lock_active;
-#define APS_LOCK_ACTIVE 0x01
-#define APS_LOCK_INACTIVE 0x00
- uint8_t reserved[26];
-};
-
-/*
- * XXX KDM move this off to a vendor shim.
- */
struct copan_debugconf_subpage {
uint8_t page_code;
#define DBGCNF_PAGE_CODE 0x00
@@ -597,21 +795,63 @@ struct scsi_info_exceptions_page {
u_int8_t report_count[4];
};
+struct scsi_logical_block_provisioning_page_descr {
+ uint8_t flags;
+#define SLBPPD_ENABLED 0x80
+#define SLBPPD_TYPE_MASK 0x38
+#define SLBPPD_ARMING_MASK 0x07
+#define SLBPPD_ARMING_DEC 0x02
+#define SLBPPD_ARMING_INC 0x01
+ uint8_t resource;
+ uint8_t reserved[2];
+ uint8_t count[4];
+};
+
+struct scsi_logical_block_provisioning_page {
+ uint8_t page_code;
+ uint8_t subpage_code;
+ uint8_t page_length[2];
+ uint8_t flags;
+#define SLBPP_SITUA 0x01
+ uint8_t reserved[11];
+ struct scsi_logical_block_provisioning_page_descr descr[0];
+};
+
+/*
+ * SCSI protocol identifier values, current as of SPC4r36l.
+ */
+#define SCSI_PROTO_FC 0x00 /* Fibre Channel */
+#define SCSI_PROTO_SPI 0x01 /* Parallel SCSI */
+#define SCSI_PROTO_SSA 0x02 /* Serial Storage Arch. */
+#define SCSI_PROTO_1394 0x03 /* IEEE 1394 (Firewire) */
+#define SCSI_PROTO_RDMA 0x04 /* SCSI RDMA Protocol */
+#define SCSI_PROTO_ISCSI 0x05 /* Internet SCSI */
+#define SCSI_PROTO_iSCSI 0x05 /* Internet SCSI */
+#define SCSI_PROTO_SAS 0x06 /* SAS Serial SCSI Protocol */
+#define SCSI_PROTO_ADT 0x07 /* Automation/Drive Int. Trans. Prot.*/
+#define SCSI_PROTO_ADITP 0x07 /* Automation/Drive Int. Trans. Prot.*/
+#define SCSI_PROTO_ATA 0x08 /* AT Attachment Interface */
+#define SCSI_PROTO_UAS 0x09 /* USB Atached SCSI */
+#define SCSI_PROTO_SOP 0x0a /* SCSI over PCI Express */
+#define SCSI_PROTO_NONE 0x0f /* No specific protocol */
+
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
+#define SPSP_PROTO_FC SCSI_PROTO_FC
+#define SPSP_PROTO_SPI SCSI_PROTO_SPI
+#define SPSP_PROTO_SSA SCSI_PROTO_SSA
+#define SPSP_PROTO_1394 SCSI_PROTO_1394
+#define SPSP_PROTO_RDMA SCSI_PROTO_RDMA
+#define SPSP_PROTO_ISCSI SCSI_PROTO_ISCSI
+#define SPSP_PROTO_SAS SCSI_PROTO_SAS
+#define SPSP_PROTO_ADT SCSI_PROTO_ADITP
+#define SPSP_PROTO_ATA SCSI_PROTO_ATA
+#define SPSP_PROTO_UAS SCSI_PROTO_UAS
+#define SPSP_PROTO_SOP SCSI_PROTO_SOP
+#define SPSP_PROTO_NONE SCSI_PROTO_NONE
};
struct scsi_reserve
@@ -746,18 +986,32 @@ struct scsi_read_buffer
{
u_int8_t opcode;
u_int8_t byte2;
-#define RWB_MODE 0x07
+#define RWB_MODE 0x1F
#define RWB_MODE_HDR_DATA 0x00
#define RWB_MODE_VENDOR 0x01
#define RWB_MODE_DATA 0x02
+#define RWB_MODE_DESCR 0x03
#define RWB_MODE_DOWNLOAD 0x04
#define RWB_MODE_DOWNLOAD_SAVE 0x05
+#define RWB_MODE_ECHO 0x0A
+#define RWB_MODE_ECHO_DESCR 0x0B
+#define RWB_MODE_ERROR_HISTORY 0x1C
u_int8_t buffer_id;
u_int8_t offset[3];
u_int8_t length[3];
u_int8_t control;
};
+struct scsi_read_buffer_16
+{
+ uint8_t opcode;
+ uint8_t byte2;
+ uint8_t offset[8];
+ uint8_t length[4];
+ uint8_t buffer_id;
+ uint8_t control;
+};
+
struct scsi_write_buffer
{
u_int8_t opcode;
@@ -768,6 +1022,216 @@ struct scsi_write_buffer
u_int8_t control;
};
+struct scsi_read_attribute
+{
+ u_int8_t opcode;
+ u_int8_t service_action;
+#define SRA_SA_ATTR_VALUES 0x00
+#define SRA_SA_ATTR_LIST 0x01
+#define SRA_SA_LOG_VOL_LIST 0x02
+#define SRA_SA_PART_LIST 0x03
+#define SRA_SA_RESTRICTED 0x04
+#define SRA_SA_SUPPORTED_ATTRS 0x05
+#define SRA_SA_MASK 0x1f
+ u_int8_t element[2];
+ u_int8_t elem_type;
+ u_int8_t logical_volume;
+ u_int8_t reserved1;
+ u_int8_t partition;
+ u_int8_t first_attribute[2];
+ u_int8_t length[4];
+ u_int8_t cache;
+#define SRA_CACHE 0x01
+ u_int8_t control;
+};
+
+struct scsi_write_attribute
+{
+ u_int8_t opcode;
+ u_int8_t byte2;
+#define SWA_WTC 0x01
+ u_int8_t element[3];
+ u_int8_t logical_volume;
+ u_int8_t reserved1;
+ u_int8_t partition;
+ u_int8_t reserved2[2];
+ u_int8_t length[4];
+ u_int8_t reserved3;
+ u_int8_t control;
+};
+
+
+struct scsi_read_attribute_values
+{
+ u_int8_t length[4];
+ u_int8_t attribute_0[0];
+};
+
+struct scsi_mam_attribute_header
+{
+ u_int8_t id[2];
+ /*
+ * Attributes obtained from SPC-4r36g (section 7.4.2.2) and
+ * SSC-4r03 (section 4.2.21).
+ */
+#define SMA_ATTR_ID_DEVICE_MIN 0x0000
+
+#define SMA_ATTR_REM_CAP_PARTITION 0x0000
+#define SMA_ATTR_MAX_CAP_PARTITION 0x0001
+#define SMA_ATTR_TAPEALERT_FLAGS 0x0002
+#define SMA_ATTR_LOAD_COUNT 0x0003
+#define SMA_ATTR_MAM_SPACE_REMAINING 0x0004
+
+#define SMA_ATTR_DEV_ASSIGNING_ORG 0x0005
+#define SMA_ATTR_FORMAT_DENSITY_CODE 0x0006
+#define SMA_ATTR_INITIALIZATION_COUNT 0x0007
+#define SMA_ATTR_VOLUME_ID 0x0008
+#define SMA_ATTR_VOLUME_CHANGE_REF 0x0009
+
+#define SMA_ATTR_DEV_SERIAL_LAST_LOAD 0x020a
+#define SMA_ATTR_DEV_SERIAL_LAST_LOAD_1 0x020b
+#define SMA_ATTR_DEV_SERIAL_LAST_LOAD_2 0x020c
+#define SMA_ATTR_DEV_SERIAL_LAST_LOAD_3 0x020d
+
+#define SMA_ATTR_TOTAL_MB_WRITTEN_LT 0x0220
+#define SMA_ATTR_TOTAL_MB_READ_LT 0x0221
+#define SMA_ATTR_TOTAL_MB_WRITTEN_CUR 0x0222
+#define SMA_ATTR_TOTAL_MB_READ_CUR 0x0223
+#define SMA_ATTR_FIRST_ENC_BLOCK 0x0224
+#define SMA_ATTR_NEXT_UNENC_BLOCK 0x0225
+
+#define SMA_ATTR_MEDIUM_USAGE_HIST 0x0340
+#define SMA_ATTR_PART_USAGE_HIST 0x0341
+
+#define SMA_ATTR_ID_DEVICE_MAX 0x03ff
+
+#define SMA_ATTR_ID_MEDIUM_MIN 0x0400
+
+#define SMA_ATTR_MED_MANUF 0x0400
+#define SMA_ATTR_MED_SERIAL 0x0401
+
+#define SMA_ATTR_MED_LENGTH 0x0402
+#define SMA_ATTR_MED_WIDTH 0x0403
+#define SMA_ATTR_MED_ASSIGNING_ORG 0x0404
+#define SMA_ATTR_MED_DENSITY_CODE 0x0405
+
+#define SMA_ATTR_MED_MANUF_DATE 0x0406
+#define SMA_ATTR_MAM_CAPACITY 0x0407
+#define SMA_ATTR_MED_TYPE 0x0408
+#define SMA_ATTR_MED_TYPE_INFO 0x0409
+#define SMA_ATTR_MED_SERIAL_NUM 0x040a
+
+#define SMA_ATTR_ID_MEDIUM_MAX 0x07ff
+
+#define SMA_ATTR_ID_HOST_MIN 0x0800
+
+#define SMA_ATTR_APP_VENDOR 0x0800
+#define SMA_ATTR_APP_NAME 0x0801
+#define SMA_ATTR_APP_VERSION 0x0802
+#define SMA_ATTR_USER_MED_TEXT_LABEL 0x0803
+#define SMA_ATTR_LAST_WRITTEN_TIME 0x0804
+#define SMA_ATTR_TEXT_LOCAL_ID 0x0805
+#define SMA_ATTR_BARCODE 0x0806
+#define SMA_ATTR_HOST_OWNER_NAME 0x0807
+#define SMA_ATTR_MEDIA_POOL 0x0808
+#define SMA_ATTR_PART_USER_LABEL 0x0809
+#define SMA_ATTR_LOAD_UNLOAD_AT_PART 0x080a
+#define SMA_ATTR_APP_FORMAT_VERSION 0x080b
+#define SMA_ATTR_VOL_COHERENCY_INFO 0x080c
+
+#define SMA_ATTR_ID_HOST_MAX 0x0bff
+
+#define SMA_ATTR_VENDOR_DEVICE_MIN 0x0c00
+#define SMA_ATTR_VENDOR_DEVICE_MAX 0x0fff
+#define SMA_ATTR_VENDOR_MEDIUM_MIN 0x1000
+#define SMA_ATTR_VENDOR_MEDIUM_MAX 0x13ff
+#define SMA_ATTR_VENDOR_HOST_MIN 0x1400
+#define SMA_ATTR_VENDOR_HOST_MAX 0x17ff
+ u_int8_t byte2;
+#define SMA_FORMAT_BINARY 0x00
+#define SMA_FORMAT_ASCII 0x01
+#define SMA_FORMAT_TEXT 0x02
+#define SMA_FORMAT_MASK 0x03
+#define SMA_READ_ONLY 0x80
+ u_int8_t length[2];
+ u_int8_t attribute[0];
+};
+
+struct scsi_attrib_list_header {
+ u_int8_t length[4];
+ u_int8_t first_attr_0[0];
+};
+
+struct scsi_attrib_lv_list {
+ u_int8_t length[2];
+ u_int8_t first_lv_number;
+ u_int8_t num_logical_volumes;
+};
+
+struct scsi_attrib_vendser {
+ uint8_t vendor[8];
+ uint8_t serial_num[32];
+};
+
+/*
+ * These values are used to decode the Volume Coherency Information
+ * Attribute (0x080c) for LTFS-format coherency information.
+ * Although the Application Client Specific lengths are different for
+ * Version 0 and Version 1, the data is in fact the same. The length
+ * difference was due to a code bug.
+ */
+#define SCSI_LTFS_VER0_LEN 42
+#define SCSI_LTFS_VER1_LEN 43
+#define SCSI_LTFS_UUID_LEN 36
+#define SCSI_LTFS_STR_NAME "LTFS"
+#define SCSI_LTFS_STR_LEN 4
+
+typedef enum {
+ SCSI_ATTR_FLAG_NONE = 0x00,
+ SCSI_ATTR_FLAG_HEX = 0x01,
+ SCSI_ATTR_FLAG_FP = 0x02,
+ SCSI_ATTR_FLAG_DIV_10 = 0x04,
+ SCSI_ATTR_FLAG_FP_1DIGIT = 0x08
+} scsi_attrib_flags;
+
+typedef enum {
+ SCSI_ATTR_OUTPUT_NONE = 0x00,
+ SCSI_ATTR_OUTPUT_TEXT_MASK = 0x03,
+ SCSI_ATTR_OUTPUT_TEXT_RAW = 0x00,
+ SCSI_ATTR_OUTPUT_TEXT_ESC = 0x01,
+ SCSI_ATTR_OUTPUT_TEXT_RSV1 = 0x02,
+ SCSI_ATTR_OUTPUT_TEXT_RSV2 = 0x03,
+ SCSI_ATTR_OUTPUT_NONASCII_MASK = 0x0c,
+ SCSI_ATTR_OUTPUT_NONASCII_TRIM = 0x00,
+ SCSI_ATTR_OUTPUT_NONASCII_ESC = 0x04,
+ SCSI_ATTR_OUTPUT_NONASCII_RAW = 0x08,
+ SCSI_ATTR_OUTPUT_NONASCII_RSV1 = 0x0c,
+ SCSI_ATTR_OUTPUT_FIELD_MASK = 0xf0,
+ SCSI_ATTR_OUTPUT_FIELD_ALL = 0xf0,
+ SCSI_ATTR_OUTPUT_FIELD_NONE = 0x00,
+ SCSI_ATTR_OUTPUT_FIELD_DESC = 0x10,
+ SCSI_ATTR_OUTPUT_FIELD_NUM = 0x20,
+ SCSI_ATTR_OUTPUT_FIELD_SIZE = 0x40,
+ SCSI_ATTR_OUTPUT_FIELD_RW = 0x80
+} scsi_attrib_output_flags;
+
+struct sbuf;
+
+struct scsi_attrib_table_entry
+{
+ u_int32_t id;
+ u_int32_t flags;
+ const char *desc;
+ const char *suffix;
+ int (*to_str)(struct sbuf *sb, struct scsi_mam_attribute_header *hdr,
+ uint32_t valid_len, uint32_t flags,
+ uint32_t output_flags, char *error_str,
+ int error_str_len);
+ int (*parse_str)(char *str, struct scsi_mam_attribute_header *hdr,
+ uint32_t alloc_len, uint32_t flags, char *error_str,
+ int error_str_len);
+};
+
struct scsi_rw_6
{
u_int8_t opcode;
@@ -819,6 +1283,17 @@ struct scsi_rw_16
u_int8_t control;
};
+struct scsi_write_atomic_16
+{
+ uint8_t opcode;
+ uint8_t byte2;
+ uint8_t addr[8];
+ uint8_t boundary[2];
+ uint8_t length[2];
+ uint8_t group;
+ uint8_t control;
+};
+
struct scsi_write_same_10
{
uint8_t opcode;
@@ -837,6 +1312,7 @@ struct scsi_write_same_16
{
uint8_t opcode;
uint8_t byte2;
+#define SWS_NDOB 0x01
uint8_t addr[8];
uint8_t length[4];
uint8_t group;
@@ -854,6 +1330,20 @@ struct scsi_unmap
uint8_t control;
};
+struct scsi_unmap_header
+{
+ uint8_t length[2];
+ uint8_t desc_length[2];
+ uint8_t reserved[4];
+};
+
+struct scsi_unmap_desc
+{
+ uint8_t lba[8];
+ uint8_t length[4];
+ uint8_t reserved[4];
+};
+
struct scsi_write_verify_10
{
uint8_t opcode;
@@ -924,6 +1414,7 @@ struct ata_pass_12 {
#define AP_PROTO_UDMA_OUT (0x0b << 1)
#define AP_PROTO_FPDMA (0x0c << 1)
#define AP_PROTO_RESP_INFO (0x0f << 1)
+#define AP_PROTO_MASK 0x1e
#define AP_MULTI 0xe0
u_int8_t flags;
#define AP_T_LEN 0x03
@@ -954,6 +1445,488 @@ struct scsi_maintenance_in
uint8_t control;
};
+struct scsi_report_supported_opcodes
+{
+ uint8_t opcode;
+ uint8_t service_action;
+ uint8_t options;
+#define RSO_RCTD 0x80
+#define RSO_OPTIONS_MASK 0x07
+#define RSO_OPTIONS_ALL 0x00
+#define RSO_OPTIONS_OC 0x01
+#define RSO_OPTIONS_OC_SA 0x02
+ uint8_t requested_opcode;
+ uint8_t requested_service_action[2];
+ uint8_t length[4];
+ uint8_t reserved1;
+ uint8_t control;
+};
+
+struct scsi_report_supported_opcodes_timeout
+{
+ uint8_t length[2];
+ uint8_t reserved;
+ uint8_t cmd_specific;
+ uint8_t nominal_time[4];
+ uint8_t recommended_time[4];
+};
+
+struct scsi_report_supported_opcodes_descr
+{
+ uint8_t opcode;
+ uint8_t reserved;
+ uint8_t service_action[2];
+ uint8_t reserved2;
+ uint8_t flags;
+#define RSO_SERVACTV 0x01
+#define RSO_CTDP 0x02
+ uint8_t cdb_length[2];
+ struct scsi_report_supported_opcodes_timeout timeout[0];
+};
+
+struct scsi_report_supported_opcodes_all
+{
+ uint8_t length[4];
+ struct scsi_report_supported_opcodes_descr descr[0];
+};
+
+struct scsi_report_supported_opcodes_one
+{
+ uint8_t reserved;
+ uint8_t support;
+#define RSO_ONE_CTDP 0x80
+#define RSO_ONE_SUP_MASK 0x07
+#define RSO_ONE_SUP_UNAVAIL 0x00
+#define RSO_ONE_SUP_NOT_SUP 0x01
+#define RSO_ONE_SUP_AVAIL 0x03
+#define RSO_ONE_SUP_VENDOR 0x05
+ uint8_t cdb_length[2];
+ uint8_t cdb_usage[];
+};
+
+struct scsi_report_supported_tmf
+{
+ uint8_t opcode;
+ uint8_t service_action;
+ uint8_t reserved[4];
+ uint8_t length[4];
+ uint8_t reserved1;
+ uint8_t control;
+};
+
+struct scsi_report_supported_tmf_data
+{
+ uint8_t byte1;
+#define RST_WAKES 0x01
+#define RST_TRS 0x02
+#define RST_QTS 0x04
+#define RST_LURS 0x08
+#define RST_CTSS 0x10
+#define RST_CACAS 0x20
+#define RST_ATSS 0x40
+#define RST_ATS 0x80
+ uint8_t byte2;
+#define RST_ITNRS 0x01
+#define RST_QTSS 0x02
+#define RST_QAES 0x04
+ uint8_t reserved[2];
+};
+
+struct scsi_report_timestamp
+{
+ uint8_t opcode;
+ uint8_t service_action;
+ uint8_t reserved[4];
+ uint8_t length[4];
+ uint8_t reserved1;
+ uint8_t control;
+};
+
+struct scsi_report_timestamp_data
+{
+ uint8_t length[2];
+ uint8_t origin;
+#define RTS_ORIG_MASK 0x00
+#define RTS_ORIG_ZERO 0x00
+#define RTS_ORIG_SET 0x02
+#define RTS_ORIG_OUTSIDE 0x03
+ uint8_t reserved;
+ uint8_t timestamp[6];
+ uint8_t reserve2[2];
+};
+
+struct scsi_receive_copy_status_lid1
+{
+ uint8_t opcode;
+ uint8_t service_action;
+#define RCS_RCS_LID1 0x00
+ uint8_t list_identifier;
+ uint8_t reserved[7];
+ uint8_t length[4];
+ uint8_t reserved1;
+ uint8_t control;
+};
+
+struct scsi_receive_copy_status_lid1_data
+{
+ uint8_t available_data[4];
+ uint8_t copy_command_status;
+#define RCS_CCS_INPROG 0x00
+#define RCS_CCS_COMPLETED 0x01
+#define RCS_CCS_ERROR 0x02
+ uint8_t segments_processed[2];
+ uint8_t transfer_count_units;
+#define RCS_TC_BYTES 0x00
+#define RCS_TC_KBYTES 0x01
+#define RCS_TC_MBYTES 0x02
+#define RCS_TC_GBYTES 0x03
+#define RCS_TC_TBYTES 0x04
+#define RCS_TC_PBYTES 0x05
+#define RCS_TC_EBYTES 0x06
+#define RCS_TC_LBAS 0xf1
+ uint8_t transfer_count[4];
+};
+
+struct scsi_receive_copy_failure_details
+{
+ uint8_t opcode;
+ uint8_t service_action;
+#define RCS_RCFD 0x04
+ uint8_t list_identifier;
+ uint8_t reserved[7];
+ uint8_t length[4];
+ uint8_t reserved1;
+ uint8_t control;
+};
+
+struct scsi_receive_copy_failure_details_data
+{
+ uint8_t available_data[4];
+ uint8_t reserved[52];
+ uint8_t copy_command_status;
+ uint8_t reserved2;
+ uint8_t sense_data_length[2];
+ uint8_t sense_data[];
+};
+
+struct scsi_receive_copy_status_lid4
+{
+ uint8_t opcode;
+ uint8_t service_action;
+#define RCS_RCS_LID4 0x05
+ uint8_t list_identifier[4];
+ uint8_t reserved[4];
+ uint8_t length[4];
+ uint8_t reserved1;
+ uint8_t control;
+};
+
+struct scsi_receive_copy_status_lid4_data
+{
+ uint8_t available_data[4];
+ uint8_t response_to_service_action;
+ uint8_t copy_command_status;
+#define RCS_CCS_COMPLETED_PROD 0x03
+#define RCS_CCS_COMPLETED_RESID 0x04
+#define RCS_CCS_INPROG_FGBG 0x10
+#define RCS_CCS_INPROG_FG 0x11
+#define RCS_CCS_INPROG_BG 0x12
+#define RCS_CCS_ABORTED 0x60
+ uint8_t operation_counter[2];
+ uint8_t estimated_status_update_delay[4];
+ uint8_t extended_copy_completion_status;
+ uint8_t length_of_the_sense_data_field;
+ uint8_t sense_data_length;
+ uint8_t transfer_count_units;
+ uint8_t transfer_count[8];
+ uint8_t segments_processed[2];
+ uint8_t reserved[6];
+ uint8_t sense_data[];
+};
+
+struct scsi_receive_copy_operating_parameters
+{
+ uint8_t opcode;
+ uint8_t service_action;
+#define RCS_RCOP 0x03
+ uint8_t reserved[8];
+ uint8_t length[4];
+ uint8_t reserved1;
+ uint8_t control;
+};
+
+struct scsi_receive_copy_operating_parameters_data
+{
+ uint8_t length[4];
+ uint8_t snlid;
+#define RCOP_SNLID 0x01
+ uint8_t reserved[3];
+ uint8_t maximum_cscd_descriptor_count[2];
+ uint8_t maximum_segment_descriptor_count[2];
+ uint8_t maximum_descriptor_list_length[4];
+ uint8_t maximum_segment_length[4];
+ uint8_t maximum_inline_data_length[4];
+ uint8_t held_data_limit[4];
+ uint8_t maximum_stream_device_transfer_size[4];
+ uint8_t reserved2[2];
+ uint8_t total_concurrent_copies[2];
+ uint8_t maximum_concurrent_copies;
+ uint8_t data_segment_granularity;
+ uint8_t inline_data_granularity;
+ uint8_t held_data_granularity;
+ uint8_t reserved3[3];
+ uint8_t implemented_descriptor_list_length;
+ uint8_t list_of_implemented_descriptor_type_codes[0];
+};
+
+struct scsi_extended_copy
+{
+ uint8_t opcode;
+ uint8_t service_action;
+#define EC_EC_LID1 0x00
+#define EC_EC_LID4 0x01
+ uint8_t reserved[8];
+ uint8_t length[4];
+ uint8_t reserved1;
+ uint8_t control;
+};
+
+struct scsi_ec_cscd_dtsp
+{
+ uint8_t flags;
+#define EC_CSCD_FIXED 0x01
+#define EC_CSCD_PAD 0x04
+ uint8_t block_length[3];
+};
+
+struct scsi_ec_cscd
+{
+ uint8_t type_code;
+#define EC_CSCD_EXT 0xff
+ uint8_t luidt_pdt;
+#define EC_NUL 0x20
+#define EC_LUIDT_MASK 0xc0
+#define EC_LUIDT_LUN 0x00
+#define EC_LUIDT_PROXY_TOKEN 0x40
+ uint8_t relative_initiator_port[2];
+ uint8_t cscd_params[24];
+ struct scsi_ec_cscd_dtsp dtsp;
+};
+
+struct scsi_ec_cscd_id
+{
+ uint8_t type_code;
+#define EC_CSCD_ID 0xe4
+ uint8_t luidt_pdt;
+ uint8_t relative_initiator_port[2];
+ uint8_t codeset;
+ uint8_t id_type;
+ uint8_t reserved;
+ uint8_t length;
+ uint8_t designator[20];
+ struct scsi_ec_cscd_dtsp dtsp;
+};
+
+struct scsi_ec_segment
+{
+ uint8_t type_code;
+ uint8_t flags;
+#define EC_SEG_DC 0x02
+#define EC_SEG_CAT 0x01
+ uint8_t descr_length[2];
+ uint8_t params[];
+};
+
+struct scsi_ec_segment_b2b
+{
+ uint8_t type_code;
+#define EC_SEG_B2B 0x02
+ uint8_t flags;
+ uint8_t descr_length[2];
+ uint8_t src_cscd[2];
+ uint8_t dst_cscd[2];
+ uint8_t reserved[2];
+ uint8_t number_of_blocks[2];
+ uint8_t src_lba[8];
+ uint8_t dst_lba[8];
+};
+
+struct scsi_ec_segment_verify
+{
+ uint8_t type_code;
+#define EC_SEG_VERIFY 0x07
+ uint8_t reserved;
+ uint8_t descr_length[2];
+ uint8_t src_cscd[2];
+ uint8_t reserved2[2];
+ uint8_t tur;
+ uint8_t reserved3[3];
+};
+
+struct scsi_ec_segment_register_key
+{
+ uint8_t type_code;
+#define EC_SEG_REGISTER_KEY 0x14
+ uint8_t reserved;
+ uint8_t descr_length[2];
+ uint8_t reserved2[2];
+ uint8_t dst_cscd[2];
+ uint8_t res_key[8];
+ uint8_t sa_res_key[8];
+ uint8_t reserved3[4];
+};
+
+struct scsi_extended_copy_lid1_data
+{
+ uint8_t list_identifier;
+ uint8_t flags;
+#define EC_PRIORITY 0x07
+#define EC_LIST_ID_USAGE_MASK 0x18
+#define EC_LIST_ID_USAGE_FULL 0x08
+#define EC_LIST_ID_USAGE_NOHOLD 0x10
+#define EC_LIST_ID_USAGE_NONE 0x18
+#define EC_STR 0x20
+ uint8_t cscd_list_length[2];
+ uint8_t reserved[4];
+ uint8_t segment_list_length[4];
+ uint8_t inline_data_length[4];
+ uint8_t data[];
+};
+
+struct scsi_extended_copy_lid4_data
+{
+ uint8_t list_format;
+#define EC_LIST_FORMAT 0x01
+ uint8_t flags;
+ uint8_t header_cscd_list_length[2];
+ uint8_t reserved[11];
+ uint8_t flags2;
+#define EC_IMMED 0x01
+#define EC_G_SENSE 0x02
+ uint8_t header_cscd_type_code;
+ uint8_t reserved2[3];
+ uint8_t list_identifier[4];
+ uint8_t reserved3[18];
+ uint8_t cscd_list_length[2];
+ uint8_t segment_list_length[2];
+ uint8_t inline_data_length[2];
+ uint8_t data[];
+};
+
+struct scsi_copy_operation_abort
+{
+ uint8_t opcode;
+ uint8_t service_action;
+#define EC_COA 0x1c
+ uint8_t list_identifier[4];
+ uint8_t reserved[9];
+ uint8_t control;
+};
+
+struct scsi_populate_token
+{
+ uint8_t opcode;
+ uint8_t service_action;
+#define EC_PT 0x10
+ uint8_t reserved[4];
+ uint8_t list_identifier[4];
+ uint8_t length[4];
+ uint8_t group_number;
+ uint8_t control;
+};
+
+struct scsi_range_desc
+{
+ uint8_t lba[8];
+ uint8_t length[4];
+ uint8_t reserved[4];
+};
+
+struct scsi_populate_token_data
+{
+ uint8_t length[2];
+ uint8_t flags;
+#define EC_PT_IMMED 0x01
+#define EC_PT_RTV 0x02
+ uint8_t reserved;
+ uint8_t inactivity_timeout[4];
+ uint8_t rod_type[4];
+ uint8_t reserved2[2];
+ uint8_t range_descriptor_length[2];
+ struct scsi_range_desc desc[];
+};
+
+struct scsi_write_using_token
+{
+ uint8_t opcode;
+ uint8_t service_action;
+#define EC_WUT 0x11
+ uint8_t reserved[4];
+ uint8_t list_identifier[4];
+ uint8_t length[4];
+ uint8_t group_number;
+ uint8_t control;
+};
+
+struct scsi_write_using_token_data
+{
+ uint8_t length[2];
+ uint8_t flags;
+#define EC_WUT_IMMED 0x01
+#define EC_WUT_DEL_TKN 0x02
+ uint8_t reserved[5];
+ uint8_t offset_into_rod[8];
+ uint8_t rod_token[512];
+ uint8_t reserved2[6];
+ uint8_t range_descriptor_length[2];
+ struct scsi_range_desc desc[];
+};
+
+struct scsi_receive_rod_token_information
+{
+ uint8_t opcode;
+ uint8_t service_action;
+#define RCS_RRTI 0x07
+ uint8_t list_identifier[4];
+ uint8_t reserved[4];
+ uint8_t length[4];
+ uint8_t reserved2;
+ uint8_t control;
+};
+
+struct scsi_token
+{
+ uint8_t type[4];
+#define ROD_TYPE_INTERNAL 0x00000000
+#define ROD_TYPE_AUR 0x00010000
+#define ROD_TYPE_PIT_DEF 0x00800000
+#define ROD_TYPE_PIT_VULN 0x00800001
+#define ROD_TYPE_PIT_PERS 0x00800002
+#define ROD_TYPE_PIT_ANY 0x0080FFFF
+#define ROD_TYPE_BLOCK_ZERO 0xFFFF0001
+ uint8_t reserved[2];
+ uint8_t length[2];
+ uint8_t body[0];
+};
+
+struct scsi_report_all_rod_tokens
+{
+ uint8_t opcode;
+ uint8_t service_action;
+#define RCS_RART 0x08
+ uint8_t reserved[8];
+ uint8_t length[4];
+ uint8_t reserved2;
+ uint8_t control;
+};
+
+struct scsi_report_all_rod_tokens_data
+{
+ uint8_t available_data[4];
+ uint8_t reserved[4];
+ uint8_t rod_management_token_list[];
+};
+
struct ata_pass_16 {
u_int8_t opcode;
u_int8_t protocol;
@@ -983,6 +1956,27 @@ struct ata_pass_16 {
u_int8_t control;
};
+struct ata_pass_32 {
+ uint8_t opcode;
+ uint8_t control;
+ uint8_t reserved1[5];
+ uint8_t length;
+ uint8_t service_action[2];
+#define ATA_PASS_32_SA 0x1ff0
+ uint8_t protocol;
+ uint8_t flags;
+ uint8_t reserved2[2];
+ uint8_t lba[6];
+ uint8_t features[2];
+ uint8_t count[2];
+ uint8_t device;
+ uint8_t command;
+ uint8_t reserved3;
+ uint8_t icc;
+ uint8_t auxiliary[4];
+};
+
+
#define SC_SCSI_1 0x01
#define SC_SCSI_2 0x03
@@ -1025,21 +2019,34 @@ struct ata_pass_16 {
#define MODE_SENSE_10 0x5A
#define PERSISTENT_RES_IN 0x5E
#define PERSISTENT_RES_OUT 0x5F
+#define EXTENDED_CDB 0x7E
+#define VARIABLE_LEN_CDB 0x7F
+#define EXTENDED_COPY 0x83
+#define RECEIVE_COPY_STATUS 0x84
#define ATA_PASS_16 0x85
#define READ_16 0x88
+#define COMPARE_AND_WRITE 0x89
#define WRITE_16 0x8A
+#define READ_ATTRIBUTE 0x8C
+#define WRITE_ATTRIBUTE 0x8D
#define WRITE_VERIFY_16 0x8E
+#define VERIFY_16 0x8F
#define SYNCHRONIZE_CACHE_16 0x91
#define WRITE_SAME_16 0x93
+#define READ_BUFFER_16 0x9B
+#define WRITE_ATOMIC_16 0x9C
#define SERVICE_ACTION_IN 0x9E
#define REPORT_LUNS 0xA0
#define ATA_PASS_12 0xA1
+#define SECURITY_PROTOCOL_IN 0xA2
#define MAINTENANCE_IN 0xA3
#define MAINTENANCE_OUT 0xA4
#define MOVE_MEDIUM 0xA5
#define READ_12 0xA8
#define WRITE_12 0xAA
#define WRITE_VERIFY_12 0xAE
+#define VERIFY_12 0xAF
+#define SECURITY_PROTOCOL_OUT 0xB5
#define READ_ELEMENT_STATUS 0xB8
#define READ_CD 0xBE
@@ -1081,6 +2088,7 @@ struct ata_pass_16 {
#define T_OCRW 0x0f
#define T_OSD 0x11
#define T_ADC 0x12
+#define T_ZBC_HM 0x14
#define T_NODEVICE 0x1f
#define T_ANY 0xff /* Used in Quirk table matches */
@@ -1135,7 +2143,9 @@ struct scsi_inquiry_data
#define SID_QUAL_IS_VENDOR_UNIQUE(inq_data) ((SID_QUAL(inq_data) & 0x04) != 0)
u_int8_t dev_qual2;
#define SID_QUAL2 0x7F
-#define SID_IS_REMOVABLE(inq_data) (((inq_data)->dev_qual2 & 0x80) != 0)
+#define SID_LU_CONG 0x40
+#define SID_RMB 0x80
+#define SID_IS_REMOVABLE(inq_data) (((inq_data)->dev_qual2 & SID_RMB) != 0)
u_int8_t version;
#define SID_ANSI_REV(inq_data) ((inq_data)->version & 0x07)
#define SCSI_REV_0 0
@@ -1283,15 +2293,9 @@ struct scsi_vpd_device_id
struct scsi_vpd_id_descriptor
{
u_int8_t proto_codeset;
-#define SCSI_PROTO_FC 0x00
-#define SCSI_PROTO_SPI 0x01
-#define SCSI_PROTO_SSA 0x02
-#define SCSI_PROTO_1394 0x03
-#define SCSI_PROTO_RDMA 0x04
-#define SCSI_PROTO_iSCSI 0x05
-#define SCSI_PROTO_SAS 0x06
-#define SCSI_PROTO_ADT 0x07
-#define SCSI_PROTO_ATA 0x08
+ /*
+ * See the SCSI_PROTO definitions above for the protocols.
+ */
#define SVPD_ID_PROTO_SHIFT 4
#define SVPD_ID_CODESET_BINARY 0x01
#define SVPD_ID_CODESET_ASCII 0x02
@@ -1312,6 +2316,8 @@ struct scsi_vpd_id_descriptor
#define SVPD_ID_TYPE_LUNGRP 0x06
#define SVPD_ID_TYPE_MD5_LUN_ID 0x07
#define SVPD_ID_TYPE_SCSI_NAME 0x08
+#define SVPD_ID_TYPE_PROTO 0x09
+#define SVPD_ID_TYPE_UUID 0x0a
#define SVPD_ID_TYPE_MASK 0x0f
u_int8_t reserved;
u_int8_t length;
@@ -1426,6 +2432,90 @@ struct scsi_service_action_in
uint8_t control;
};
+struct scsi_vpd_extended_inquiry_data
+{
+ uint8_t device;
+ uint8_t page_code;
+#define SVPD_EXTENDED_INQUIRY_DATA 0x86
+ uint8_t page_length[2];
+ uint8_t flags1;
+
+ /* These values are for direct access devices */
+#define SVPD_EID_AM_MASK 0xC0
+#define SVPD_EID_AM_DEFER 0x80
+#define SVPD_EID_AM_IMMED 0x40
+#define SVPD_EID_AM_UNDEFINED 0x00
+#define SVPD_EID_AM_RESERVED 0xc0
+#define SVPD_EID_SPT 0x38
+#define SVPD_EID_SPT_1 0x00
+#define SVPD_EID_SPT_12 0x08
+#define SVPD_EID_SPT_2 0x10
+#define SVPD_EID_SPT_13 0x18
+#define SVPD_EID_SPT_3 0x20
+#define SVPD_EID_SPT_23 0x28
+#define SVPD_EID_SPT_123 0x38
+
+ /* These values are for sequential access devices */
+#define SVPD_EID_SA_SPT_LBP 0x08
+
+#define SVPD_EID_GRD_CHK 0x04
+#define SVPD_EID_APP_CHK 0x02
+#define SVPD_EID_REF_CHK 0x01
+
+ uint8_t flags2;
+#define SVPD_EID_UASK_SUP 0x20
+#define SVPD_EID_GROUP_SUP 0x10
+#define SVPD_EID_PRIOR_SUP 0x08
+#define SVPD_EID_HEADSUP 0x04
+#define SVPD_EID_ORDSUP 0x02
+#define SVPD_EID_SIMPSUP 0x01
+ uint8_t flags3;
+#define SVPD_EID_WU_SUP 0x08
+#define SVPD_EID_CRD_SUP 0x04
+#define SVPD_EID_NV_SUP 0x02
+#define SVPD_EID_V_SUP 0x01
+ uint8_t flags4;
+#define SVPD_EID_P_I_I_SUP 0x10
+#define SVPD_EID_LUICLT 0x01
+ uint8_t flags5;
+#define SVPD_EID_R_SUP 0x10
+#define SVPD_EID_CBCS 0x01
+ uint8_t flags6;
+#define SVPD_EID_MULTI_I_T_FW 0x0F
+#define SVPD_EID_MC_VENDOR_SPEC 0x00
+#define SVPD_EID_MC_MODE_1 0x01
+#define SVPD_EID_MC_MODE_2 0x02
+#define SVPD_EID_MC_MODE_3 0x03
+ uint8_t est[2];
+ uint8_t flags7;
+#define SVPD_EID_POA_SUP 0x80
+#define SVPD_EID_HRA_SUP 0x80
+#define SVPD_EID_VSA_SUP 0x80
+ uint8_t max_sense_length;
+ uint8_t reserved2[50];
+};
+
+struct scsi_vpd_mode_page_policy_descr
+{
+ uint8_t page_code;
+ uint8_t subpage_code;
+ uint8_t policy;
+#define SVPD_MPP_SHARED 0x00
+#define SVPD_MPP_PORT 0x01
+#define SVPD_MPP_I_T 0x03
+#define SVPD_MPP_MLUS 0x80
+ uint8_t reserved;
+};
+
+struct scsi_vpd_mode_page_policy
+{
+ uint8_t device;
+ uint8_t page_code;
+#define SVPD_MODE_PAGE_POLICY 0x87
+ uint8_t page_length[2];
+ struct scsi_vpd_mode_page_policy_descr descr[0];
+};
+
struct scsi_diag_page {
uint8_t page_code;
uint8_t page_specific_flags;
@@ -1433,12 +2523,179 @@ struct scsi_diag_page {
uint8_t params[0];
};
+struct scsi_vpd_port_designation
+{
+ uint8_t reserved[2];
+ uint8_t relative_port_id[2];
+ uint8_t reserved2[2];
+ uint8_t initiator_transportid_length[2];
+ uint8_t initiator_transportid[0];
+};
+
+struct scsi_vpd_port_designation_cont
+{
+ uint8_t reserved[2];
+ uint8_t target_port_descriptors_length[2];
+ struct scsi_vpd_id_descriptor target_port_descriptors[0];
+};
+
+struct scsi_vpd_scsi_ports
+{
+ u_int8_t device;
+ u_int8_t page_code;
+#define SVPD_SCSI_PORTS 0x88
+ u_int8_t page_length[2];
+ struct scsi_vpd_port_designation design[];
+};
+
/*
* ATA Information VPD Page based on
* T10/2126-D Revision 04
*/
#define SVPD_ATA_INFORMATION 0x89
+
+struct scsi_vpd_tpc_descriptor
+{
+ uint8_t desc_type[2];
+ uint8_t desc_length[2];
+ uint8_t parameters[];
+};
+
+struct scsi_vpd_tpc_descriptor_bdrl
+{
+ uint8_t desc_type[2];
+#define SVPD_TPC_BDRL 0x0000
+ uint8_t desc_length[2];
+ uint8_t vendor_specific[6];
+ uint8_t maximum_ranges[2];
+ uint8_t maximum_inactivity_timeout[4];
+ uint8_t default_inactivity_timeout[4];
+ uint8_t maximum_token_transfer_size[8];
+ uint8_t optimal_transfer_count[8];
+};
+
+struct scsi_vpd_tpc_descriptor_sc_descr
+{
+ uint8_t opcode;
+ uint8_t sa_length;
+ uint8_t supported_service_actions[0];
+};
+
+struct scsi_vpd_tpc_descriptor_sc
+{
+ uint8_t desc_type[2];
+#define SVPD_TPC_SC 0x0001
+ uint8_t desc_length[2];
+ uint8_t list_length;
+ struct scsi_vpd_tpc_descriptor_sc_descr descr[];
+};
+
+struct scsi_vpd_tpc_descriptor_pd
+{
+ uint8_t desc_type[2];
+#define SVPD_TPC_PD 0x0004
+ uint8_t desc_length[2];
+ uint8_t reserved[4];
+ uint8_t maximum_cscd_descriptor_count[2];
+ uint8_t maximum_segment_descriptor_count[2];
+ uint8_t maximum_descriptor_list_length[4];
+ uint8_t maximum_inline_data_length[4];
+ uint8_t reserved2[12];
+};
+
+struct scsi_vpd_tpc_descriptor_sd
+{
+ uint8_t desc_type[2];
+#define SVPD_TPC_SD 0x0008
+ uint8_t desc_length[2];
+ uint8_t list_length;
+ uint8_t supported_descriptor_codes[];
+};
+
+struct scsi_vpd_tpc_descriptor_sdid
+{
+ uint8_t desc_type[2];
+#define SVPD_TPC_SDID 0x000C
+ uint8_t desc_length[2];
+ uint8_t list_length[2];
+ uint8_t supported_descriptor_ids[];
+};
+
+struct scsi_vpd_tpc_descriptor_rtf_block
+{
+ uint8_t type_format;
+#define SVPD_TPC_RTF_BLOCK 0x00
+ uint8_t reserved;
+ uint8_t desc_length[2];
+ uint8_t reserved2[2];
+ uint8_t optimal_length_granularity[2];
+ uint8_t maximum_bytes[8];
+ uint8_t optimal_bytes[8];
+ uint8_t optimal_bytes_to_token_per_segment[8];
+ uint8_t optimal_bytes_from_token_per_segment[8];
+ uint8_t reserved3[8];
+};
+
+struct scsi_vpd_tpc_descriptor_rtf
+{
+ uint8_t desc_type[2];
+#define SVPD_TPC_RTF 0x0106
+ uint8_t desc_length[2];
+ uint8_t remote_tokens;
+ uint8_t reserved[11];
+ uint8_t minimum_token_lifetime[4];
+ uint8_t maximum_token_lifetime[4];
+ uint8_t maximum_token_inactivity_timeout[4];
+ uint8_t reserved2[18];
+ uint8_t type_specific_features_length[2];
+ uint8_t type_specific_features[0];
+};
+
+struct scsi_vpd_tpc_descriptor_srtd
+{
+ uint8_t rod_type[4];
+ uint8_t flags;
+#define SVPD_TPC_SRTD_TOUT 0x01
+#define SVPD_TPC_SRTD_TIN 0x02
+#define SVPD_TPC_SRTD_ECPY 0x80
+ uint8_t reserved;
+ uint8_t preference_indicator[2];
+ uint8_t reserved2[56];
+};
+
+struct scsi_vpd_tpc_descriptor_srt
+{
+ uint8_t desc_type[2];
+#define SVPD_TPC_SRT 0x0108
+ uint8_t desc_length[2];
+ uint8_t reserved[2];
+ uint8_t rod_type_descriptors_length[2];
+ uint8_t rod_type_descriptors[0];
+};
+
+struct scsi_vpd_tpc_descriptor_gco
+{
+ uint8_t desc_type[2];
+#define SVPD_TPC_GCO 0x8001
+ uint8_t desc_length[2];
+ uint8_t total_concurrent_copies[4];
+ uint8_t maximum_identified_concurrent_copies[4];
+ uint8_t maximum_segment_length[4];
+ uint8_t data_segment_granularity;
+ uint8_t inline_data_granularity;
+ uint8_t reserved[18];
+};
+
+struct scsi_vpd_tpc
+{
+ uint8_t device;
+ uint8_t page_code;
+#define SVPD_SCSI_TPC 0x8F
+ uint8_t page_length[2];
+ struct scsi_vpd_tpc_descriptor descr[];
+};
+
/*
* Block Device Characteristics VPD Page based on
* T10/1799-D Revision 31
@@ -1451,7 +2708,7 @@ struct scsi_vpd_block_characteristics
u_int8_t page_length[2];
u_int8_t medium_rotation_rate[2];
#define SVPD_BDC_RATE_NOT_REPORTED 0x00
-#define SVPD_BDC_RATE_NONE_ROTATING 0x01
+#define SVPD_BDC_RATE_NON_ROTATING 0x01
u_int8_t reserved1;
u_int8_t nominal_form_factor;
#define SVPD_BDC_FORM_NOT_REPORTED 0x00
@@ -1464,6 +2721,34 @@ struct scsi_vpd_block_characteristics
};
/*
+ * Block Device Characteristics VPD Page
+ */
+struct scsi_vpd_block_device_characteristics
+{
+ uint8_t device;
+ uint8_t page_code;
+#define SVPD_BDC 0xB1
+ uint8_t page_length[2];
+ uint8_t medium_rotation_rate[2];
+#define SVPD_NOT_REPORTED 0x0000
+#define SVPD_NON_ROTATING 0x0001
+ uint8_t product_type;
+ uint8_t wab_wac_ff;
+ uint8_t flags;
+#define SVPD_VBULS 0x01
+#define SVPD_FUAB 0x02
+#define SVPD_ZBC_NR 0x00 /* Not Reported */
+#define SVPD_HAW_ZBC 0x10 /* Host Aware */
+#define SVPD_DM_ZBC 0x20 /* Drive Managed */
+#define SVPD_ZBC_MASK 0x30 /* Zoned mask */
+ uint8_t reserved[55];
+};
+
+#define SBDC_IS_PRESENT(bdc, length, field) \
+ ((length >= offsetof(struct scsi_vpd_block_device_characteristics, \
+ field) + sizeof(bdc->field)) ? 1 : 0)
+
+/*
* Logical Block Provisioning VPD Page based on
* T10/1799-D Revision 31
*/
@@ -1493,8 +2778,7 @@ struct scsi_vpd_logical_block_prov
};
/*
- * Block Limits VDP Page based on
- * T10/1799-D Revision 31
+ * Block Limits VDP Page based on SBC-4 Revision 2
*/
struct scsi_vpd_block_limits
{
@@ -1515,7 +2799,33 @@ struct scsi_vpd_block_limits
u_int8_t opt_unmap_grain[4];
u_int8_t unmap_grain_align[4];
u_int8_t max_write_same_length[8];
- u_int8_t reserved2[20];
+ u_int8_t max_atomic_transfer_length[4];
+ u_int8_t atomic_alignment[4];
+ u_int8_t atomic_transfer_length_granularity[4];
+ u_int8_t max_atomic_transfer_length_with_atomic_boundary[4];
+ u_int8_t max_atomic_boundary_size[4];
+};
+
+/*
+ * Zoned Block Device Characacteristics VPD page.
+ * From ZBC-r04, dated August 12, 2015.
+ */
+struct scsi_vpd_zoned_bdc {
+ uint8_t device;
+ uint8_t page_code;
+#define SVPD_ZONED_BDC 0xB6
+ uint8_t page_length[2];
+#define SVPD_ZBDC_PL 0x3C
+ uint8_t flags;
+#define SVPD_ZBDC_URSWRZ 0x01
+ uint8_t reserved1[3];
+ uint8_t optimal_seq_zones[4];
+#define SVPD_ZBDC_OPT_SEQ_NR 0xffffffff
+ uint8_t optimal_nonseq_zones[4];
+#define SVPD_ZBDC_OPT_NONSEQ_NR 0xffffffff
+ uint8_t max_seq_req_zones[4];
+#define SVPD_ZBDC_MAX_SEQ_UNLIMITED 0xffffffff
+ uint8_t reserved2[44];
};
struct scsi_read_capacity
@@ -1574,6 +2884,33 @@ struct scsi_read_capacity_data_long
#define SRC16_LBPRZ_A 0x4000
#define SRC16_LBPME_A 0x8000
uint8_t lalba_lbp[2];
+ uint8_t reserved[16];
+};
+
+struct scsi_get_lba_status
+{
+ uint8_t opcode;
+#define SGLS_SERVICE_ACTION 0x12
+ uint8_t service_action;
+ uint8_t addr[8];
+ uint8_t alloc_len[4];
+ uint8_t reserved;
+ uint8_t control;
+};
+
+struct scsi_get_lba_status_data_descr
+{
+ uint8_t addr[8];
+ uint8_t length[4];
+ uint8_t status;
+ uint8_t reserved[3];
+};
+
+struct scsi_get_lba_status_data
+{
+ uint8_t length[4];
+ uint8_t reserved[4];
+ struct scsi_get_lba_status_data_descr descr[];
};
struct scsi_report_luns
@@ -1583,6 +2920,9 @@ struct scsi_report_luns
#define RPL_REPORT_DEFAULT 0x00
#define RPL_REPORT_WELLKNOWN 0x01
#define RPL_REPORT_ALL 0x02
+#define RPL_REPORT_ADMIN 0x10
+#define RPL_REPORT_NONSUBSID 0x11
+#define RPL_REPORT_CONGLOM 0x12
uint8_t select_report;
uint8_t reserved2[3];
uint8_t length[4];
@@ -1622,8 +2962,9 @@ struct scsi_target_group
{
uint8_t opcode;
uint8_t service_action;
+#define STG_PDF_MASK 0xe0
#define STG_PDF_LENGTH 0x00
-#define RPL_PDF_EXTENDED 0x20
+#define STG_PDF_EXTENDED 0x20
uint8_t reserved1[4];
uint8_t length[4];
uint8_t reserved2;
@@ -1673,12 +3014,47 @@ struct scsi_target_group_data {
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 format_type; /* STG_PDF_LENGTH or STG_PDF_EXTENDED */
uint8_t implicit_transition_time;
uint8_t reserved[2];
struct scsi_target_port_group_descriptor groups[];
};
+struct scsi_security_protocol_in
+{
+ uint8_t opcode;
+ uint8_t security_protocol;
+#define SPI_PROT_INFORMATION 0x00
+#define SPI_PROT_CBCS 0x07
+#define SPI_PROT_TAPE_DATA_ENC 0x20
+#define SPI_PROT_DATA_ENC_CONFIG 0x21
+#define SPI_PROT_SA_CREATE_CAP 0x40
+#define SPI_PROT_IKEV2_SCSI 0x41
+#define SPI_PROT_JEDEC_UFS 0xEC
+#define SPI_PROT_SDCARD_TFSSS 0xED
+#define SPI_PROT_AUTH_HOST_TRANSIENT 0xEE
+#define SPI_PROT_ATA_DEVICE_PASSWORD 0xEF
+ uint8_t security_protocol_specific[2];
+ uint8_t byte4;
+#define SPI_INC_512 0x80
+ uint8_t reserved1;
+ uint8_t length[4];
+ uint8_t reserved2;
+ uint8_t control;
+};
+
+struct scsi_security_protocol_out
+{
+ uint8_t opcode;
+ uint8_t security_protocol;
+ uint8_t security_protocol_specific[2];
+ uint8_t byte4;
+#define SPO_INC_512 0x80
+ uint8_t reserved1;
+ uint8_t length[4];
+ uint8_t reserved2;
+ uint8_t control;
+};
typedef enum {
SSD_TYPE_NONE,
@@ -1824,7 +3200,7 @@ struct scsi_sense_info
/*
* Command-specific information depends on the command for which the
- * reported condition occured.
+ * reported condition occurred.
*
* Note that any changes to the field names or positions in this structure,
* even reserved fields, should be accompanied by an examination of the
@@ -2023,6 +3399,29 @@ struct scsi_sense_osd_attr_id
};
/*
+ * ATA Return descriptor, used for the SCSI ATA PASS-THROUGH(12), (16) and
+ * (32) commands. Described in SAT-4r05.
+ */
+struct scsi_sense_ata_ret_desc
+{
+ uint8_t desc_type;
+#define SSD_DESC_ATA 0x09
+ uint8_t length;
+ uint8_t flags;
+#define SSD_DESC_ATA_FLAG_EXTEND 0x01
+ uint8_t error;
+ uint8_t count_15_8;
+ uint8_t count_7_0;
+ uint8_t lba_31_24;
+ uint8_t lba_7_0;
+ uint8_t lba_39_32;
+ uint8_t lba_15_8;
+ uint8_t lba_47_40;
+ uint8_t lba_23_16;
+ uint8_t device;
+ uint8_t status;
+};
+/*
* Used with Sense keys No Sense (0x00) and Not Ready (0x02).
*
* Maximum descriptors allowed: 32 (as of SPC-4)
@@ -2059,7 +3458,7 @@ struct scsi_sense_forwarded
/*
* Vendor-specific sense descriptor. The desc_type field will be in the
- * range bewteen MIN and MAX inclusive.
+ * range between MIN and MAX inclusive.
*/
struct scsi_sense_vendor
{
@@ -2187,6 +3586,22 @@ typedef enum {
SSS_FLAG_PRINT_COMMAND = 0x01
} scsi_sense_string_flags;
+struct scsi_nv {
+ const char *name;
+ uint64_t value;
+};
+
+typedef enum {
+ SCSI_NV_FOUND,
+ SCSI_NV_AMBIGUOUS,
+ SCSI_NV_NOT_FOUND
+} scsi_nv_status;
+
+typedef enum {
+ SCSI_NV_FLAG_NONE = 0x00,
+ SCSI_NV_FLAG_IG_CASE = 0x01 /* Case insensitive comparison */
+} scsi_nv_flags;
+
struct ccb_scsiio;
struct cam_periph;
union ccb;
@@ -2196,8 +3611,6 @@ struct cam_device;
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,
@@ -2310,6 +3723,7 @@ 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_cdb_sbuf(u_int8_t *cdb_ptr, struct sbuf *sb);
void scsi_print_inquiry(struct scsi_inquiry_data *inq_data);
void scsi_print_inquiry_short(struct scsi_inquiry_data *inq_data);
@@ -2324,9 +3738,128 @@ int scsi_devid_is_lun_eui64(uint8_t *bufp);
int scsi_devid_is_lun_naa(uint8_t *bufp);
int scsi_devid_is_lun_name(uint8_t *bufp);
int scsi_devid_is_lun_t10(uint8_t *bufp);
+int scsi_devid_is_port_naa(uint8_t *bufp);
struct scsi_vpd_id_descriptor *
scsi_get_devid(struct scsi_vpd_device_id *id, uint32_t len,
scsi_devid_checkfn_t ck_fn);
+struct scsi_vpd_id_descriptor *
+ scsi_get_devid_desc(struct scsi_vpd_id_descriptor *desc, uint32_t len,
+ scsi_devid_checkfn_t ck_fn);
+
+int scsi_transportid_sbuf(struct sbuf *sb,
+ struct scsi_transportid_header *hdr,
+ uint32_t valid_len);
+
+const char * scsi_nv_to_str(struct scsi_nv *table, int num_table_entries,
+ uint64_t value);
+
+scsi_nv_status scsi_get_nv(struct scsi_nv *table, int num_table_entries,
+ char *name, int *table_entry, scsi_nv_flags flags);
+
+int scsi_parse_transportid_64bit(int proto_id, char *id_str,
+ struct scsi_transportid_header **hdr,
+ unsigned int *alloc_len,
+#ifdef _KERNEL
+ struct malloc_type *type, int flags,
+#endif
+ char *error_str, int error_str_len);
+
+int scsi_parse_transportid_spi(char *id_str,
+ struct scsi_transportid_header **hdr,
+ unsigned int *alloc_len,
+#ifdef _KERNEL
+ struct malloc_type *type, int flags,
+#endif
+ char *error_str, int error_str_len);
+
+int scsi_parse_transportid_rdma(char *id_str,
+ struct scsi_transportid_header **hdr,
+ unsigned int *alloc_len,
+#ifdef _KERNEL
+ struct malloc_type *type, int flags,
+#endif
+ char *error_str, int error_str_len);
+
+int scsi_parse_transportid_iscsi(char *id_str,
+ struct scsi_transportid_header **hdr,
+ unsigned int *alloc_len,
+#ifdef _KERNEL
+ struct malloc_type *type, int flags,
+#endif
+ char *error_str,int error_str_len);
+
+int scsi_parse_transportid_sop(char *id_str,
+ struct scsi_transportid_header **hdr,
+ unsigned int *alloc_len,
+#ifdef _KERNEL
+ struct malloc_type *type, int flags,
+#endif
+ char *error_str,int error_str_len);
+
+int scsi_parse_transportid(char *transportid_str,
+ struct scsi_transportid_header **hdr,
+ unsigned int *alloc_len,
+#ifdef _KERNEL
+ struct malloc_type *type, int flags,
+#endif
+ char *error_str, int error_str_len);
+
+
+int scsi_attrib_volcoh_sbuf(struct sbuf *sb,
+ struct scsi_mam_attribute_header *hdr,
+ uint32_t valid_len, uint32_t flags,
+ uint32_t output_flags, char *error_str,
+ int error_str_len);
+
+int scsi_attrib_vendser_sbuf(struct sbuf *sb,
+ struct scsi_mam_attribute_header *hdr,
+ uint32_t valid_len, uint32_t flags,
+ uint32_t output_flags, char *error_str,
+ int error_str_len);
+
+int scsi_attrib_hexdump_sbuf(struct sbuf *sb,
+ struct scsi_mam_attribute_header *hdr,
+ uint32_t valid_len, uint32_t flags,
+ uint32_t output_flags, char *error_str,
+ int error_str_len);
+
+int scsi_attrib_int_sbuf(struct sbuf *sb, struct scsi_mam_attribute_header *hdr,
+ uint32_t valid_len, uint32_t flags,
+ uint32_t output_flags, char *error_str,
+ int error_str_len);
+
+int scsi_attrib_ascii_sbuf(struct sbuf *sb,
+ struct scsi_mam_attribute_header *hdr,
+ uint32_t valid_len, uint32_t flags,
+ uint32_t output_flags, char *error_str,
+ int error_str_len);
+
+int scsi_attrib_text_sbuf(struct sbuf *sb,
+ struct scsi_mam_attribute_header *hdr,
+ uint32_t valid_len, uint32_t flags,
+ uint32_t output_flags, char *error_str,
+ int error_str_len);
+
+struct scsi_attrib_table_entry *scsi_find_attrib_entry(
+ struct scsi_attrib_table_entry *table,
+ size_t num_table_entries, uint32_t id);
+
+struct scsi_attrib_table_entry *scsi_get_attrib_entry(uint32_t id);
+
+int scsi_attrib_value_sbuf(struct sbuf *sb, uint32_t valid_len,
+ struct scsi_mam_attribute_header *hdr,
+ uint32_t output_flags, char *error_str,
+ size_t error_str_len);
+
+void scsi_attrib_prefix_sbuf(struct sbuf *sb, uint32_t output_flags,
+ struct scsi_mam_attribute_header *hdr,
+ uint32_t valid_len, const char *desc);
+
+int scsi_attrib_sbuf(struct sbuf *sb, struct scsi_mam_attribute_header *hdr,
+ uint32_t valid_len,
+ struct scsi_attrib_table_entry *user_table,
+ size_t num_user_entries, int prefer_user_table,
+ uint32_t output_flags, char *error_str, int error_str_len);
void scsi_test_unit_ready(struct ccb_scsiio *csio, u_int32_t retries,
void (*cbfcnp)(struct cam_periph *,
@@ -2410,9 +3943,8 @@ 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);
+ uint8_t *rcap_buf, int rcap_buf_len,
+ uint8_t sense_len, uint32_t timeout);
void scsi_report_luns(struct ccb_scsiio *csio, u_int32_t retries,
void (*cbfcnp)(struct cam_periph *,
@@ -2505,6 +4037,23 @@ void scsi_ata_trim(struct ccb_scsiio *csio, u_int32_t retries,
u_int8_t *data_ptr, u_int16_t dxfer_len,
u_int8_t sense_len, u_int32_t timeout);
+int scsi_ata_read_log(struct ccb_scsiio *csio, uint32_t retries,
+ void (*cbfcnp)(struct cam_periph *, union ccb *),
+ uint8_t tag_action, uint32_t log_address,
+ uint32_t page_number, uint16_t block_count,
+ uint8_t protocol, uint8_t *data_ptr, uint32_t dxfer_len,
+ uint8_t sense_len, uint32_t timeout);
+
+int scsi_ata_pass(struct ccb_scsiio *csio, uint32_t retries,
+ void (*cbfcnp)(struct cam_periph *, union ccb *),
+ uint32_t flags, uint8_t tag_action,
+ uint8_t protocol, uint8_t ata_flags, uint16_t features,
+ uint16_t sector_count, uint64_t lba, uint8_t command,
+ uint8_t device, uint8_t icc, uint32_t auxiliary,
+ uint8_t control, u_int8_t *data_ptr, uint32_t dxfer_len,
+ uint8_t *cdb_storage, size_t cdb_storage_len,
+ int minimum_cmd_size, u_int8_t sense_len, u_int32_t timeout);
+
void scsi_ata_pass_16(struct ccb_scsiio *csio, u_int32_t retries,
void (*cbfcnp)(struct cam_periph *, union ccb *),
u_int32_t flags, u_int8_t tag_action,
@@ -2523,6 +4072,54 @@ 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);
+void scsi_read_attribute(struct ccb_scsiio *csio, u_int32_t retries,
+ void (*cbfcnp)(struct cam_periph *, union ccb *),
+ u_int8_t tag_action, u_int8_t service_action,
+ uint32_t element, u_int8_t elem_type,
+ int logical_volume, int partition,
+ u_int32_t first_attribute, int cache, u_int8_t *data_ptr,
+ u_int32_t length, int sense_len, u_int32_t timeout);
+void scsi_write_attribute(struct ccb_scsiio *csio, u_int32_t retries,
+ void (*cbfcnp)(struct cam_periph *, union ccb *),
+ u_int8_t tag_action, uint32_t element,
+ int logical_volume, int partition, int wtc, u_int8_t *data_ptr,
+ u_int32_t length, int sense_len, u_int32_t timeout);
+
+void scsi_security_protocol_in(struct ccb_scsiio *csio, uint32_t retries,
+ void (*cbfcnp)(struct cam_periph *, union ccb *),
+ uint8_t tag_action, uint32_t security_protocol,
+ uint32_t security_protocol_specific, int byte4,
+ uint8_t *data_ptr, uint32_t dxfer_len,
+ int sense_len, int timeout);
+
+void scsi_security_protocol_out(struct ccb_scsiio *csio, uint32_t retries,
+ void (*cbfcnp)(struct cam_periph *,union ccb *),
+ uint8_t tag_action, uint32_t security_protocol,
+ uint32_t security_protocol_specific, int byte4,
+ uint8_t *data_ptr, uint32_t dxfer_len,
+ int sense_len, int timeout);
+
+void scsi_persistent_reserve_in(struct ccb_scsiio *csio, uint32_t retries,
+ void (*cbfcnp)(struct cam_periph *,union ccb *),
+ uint8_t tag_action, int service_action,
+ uint8_t *data_ptr, uint32_t dxfer_len,
+ int sense_len, int timeout);
+
+void scsi_persistent_reserve_out(struct ccb_scsiio *csio, uint32_t retries,
+ void (*cbfcnp)(struct cam_periph *,
+ union ccb *),
+ uint8_t tag_action, int service_action,
+ int scope, int res_type, uint8_t *data_ptr,
+ uint32_t dxfer_len, int sense_len,
+ int timeout);
+
+void scsi_report_supported_opcodes(struct ccb_scsiio *csio, uint32_t retries,
+ void (*cbfcnp)(struct cam_periph *,
+ union ccb *),
+ uint8_t tag_action, int options,
+ int req_opcode, int req_service_action,
+ uint8_t *data_ptr, uint32_t dxfer_len,
+ int sense_len, int timeout);
int scsi_inquiry_match(caddr_t inqbuffer, caddr_t table_entry);
int scsi_static_inquiry_match(caddr_t inqbuffer,
diff --git a/freebsd/sys/cam/scsi/scsi_da.h b/freebsd/sys/cam/scsi/scsi_da.h
index 4fbd7256..e6eb95f1 100644
--- a/freebsd/sys/cam/scsi/scsi_da.h
+++ b/freebsd/sys/cam/scsi/scsi_da.h
@@ -92,28 +92,23 @@ struct scsi_reassign_blocks
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;
+ uint8_t opcode;
+ uint8_t byte2;
#define SRDD10_GLIST 0x08
#define SRDD10_PLIST 0x10
#define SRDD10_DLIST_FORMAT_MASK 0x07
#define SRDD10_BLOCK_FORMAT 0x00
+#define SRDD10_EXT_BFI_FORMAT 0x01
+#define SRDD10_EXT_PHYS_FORMAT 0x02
+#define SRDD10_LONG_BLOCK_FORMAT 0x03
#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];
+#define SRDD10_VENDOR_FORMAT 0x06
+ uint8_t format;
+ uint8_t reserved[4];
+ uint8_t alloc_length[2];
#define SRDD10_MAX_LENGTH 0xffff
-
- u_int8_t control;
+ uint8_t control;
};
struct scsi_sanitize
@@ -143,31 +138,99 @@ struct scsi_sanitize_parameter_list
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;
-
+ uint8_t opcode;
#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;
+#define SRDD12_BLOCK_FORMAT SRDD10_BLOCK_FORMAT
+#define SRDD12_BYTES_FROM_INDEX_FORMAT SRDD10_BYTES_FROM_INDEX_FORMAT
+#define SRDD12_PHYSICAL_SECTOR_FORMAT SRDD10_PHYSICAL_SECTOR_FORMAT
+ uint8_t format;
+ uint8_t address_descriptor_index[4];
+ uint8_t alloc_length[4];
+#define SRDD12_MAX_LENGTH 0xffffffff
+ uint8_t reserved;
+ uint8_t control;
+};
- u_int8_t reserved[4];
+struct scsi_zbc_out
+{
+ uint8_t opcode;
+ uint8_t service_action;
+#define ZBC_OUT_SA_CLOSE 0x01
+#define ZBC_OUT_SA_FINISH 0x02
+#define ZBC_OUT_SA_OPEN 0x03
+#define ZBC_OUT_SA_RWP 0x04
+ uint8_t zone_id[8];
+ uint8_t reserved[4];
+ uint8_t zone_flags;
+#define ZBC_OUT_ALL 0x01
+ uint8_t control;
+};
- u_int8_t alloc_length[4];
+struct scsi_zbc_in
+{
+ uint8_t opcode;
+ uint8_t service_action;
+#define ZBC_IN_SA_REPORT_ZONES 0x00
+ uint8_t zone_start_lba[8];
+ uint8_t length[4];
+ uint8_t zone_options;
+#define ZBC_IN_PARTIAL 0x80
+#define ZBC_IN_REP_ALL_ZONES 0x00
+#define ZBC_IN_REP_EMPTY 0x01
+#define ZBC_IN_REP_IMP_OPEN 0x02
+#define ZBC_IN_REP_EXP_OPEN 0x03
+#define ZBC_IN_REP_CLOSED 0x04
+#define ZBC_IN_REP_FULL 0x05
+#define ZBC_IN_REP_READONLY 0x06
+#define ZBC_IN_REP_OFFLINE 0x07
+#define ZBC_IN_REP_RESET 0x10
+#define ZBC_IN_REP_NON_SEQ 0x11
+#define ZBC_IN_REP_NON_WP 0x3f
+#define ZBC_IN_REP_MASK 0x3f
+ uint8_t control;
+};
- u_int8_t control;
-
+struct scsi_report_zones_desc {
+ uint8_t zone_type;
+#define SRZ_TYPE_CONVENTIONAL 0x01
+#define SRZ_TYPE_SEQ_REQUIRED 0x02
+#define SRZ_TYPE_SEQ_PREFERRED 0x03
+#define SRZ_TYPE_MASK 0x0f
+ uint8_t zone_flags;
+#define SRZ_ZONE_COND_SHIFT 4
+#define SRZ_ZONE_COND_MASK 0xf0
+#define SRZ_ZONE_COND_NWP 0x00
+#define SRZ_ZONE_COND_EMPTY 0x10
+#define SRZ_ZONE_COND_IMP_OPEN 0x20
+#define SRZ_ZONE_COND_EXP_OPEN 0x30
+#define SRZ_ZONE_COND_CLOSED 0x40
+#define SRZ_ZONE_COND_READONLY 0xd0
+#define SRZ_ZONE_COND_FULL 0xe0
+#define SRZ_ZONE_COND_OFFLINE 0xf0
+#define SRZ_ZONE_NON_SEQ 0x02
+#define SRZ_ZONE_RESET 0x01
+ uint8_t reserved[6];
+ uint8_t zone_length[8];
+ uint8_t zone_start_lba[8];
+ uint8_t write_pointer_lba[8];
+ uint8_t reserved2[32];
};
+struct scsi_report_zones_hdr {
+ uint8_t length[4];
+ uint8_t byte4;
+#define SRZ_SAME_ALL_DIFFERENT 0x00 /* Lengths and types vary */
+#define SRZ_SAME_ALL_SAME 0x01 /* Lengths and types the same */
+#define SRZ_SAME_LAST_DIFFERENT 0x02 /* Types same, last length varies */
+#define SRZ_SAME_TYPES_DIFFERENT 0x03 /* Types vary, length the same */
+#define SRZ_SAME_MASK 0x0f
+ uint8_t reserved[3];
+ uint8_t maximum_lba[8];
+ uint8_t reserved2[48];
+ struct scsi_report_zones_desc desc_list[];
+};
/*
* Opcodes
@@ -182,6 +245,8 @@ struct scsi_read_defect_data_12
#define VERIFY 0x2f
#define READ_DEFECT_DATA_10 0x37
#define SANITIZE 0x48
+#define ZBC_OUT 0x94
+#define ZBC_IN 0x95
#define READ_DEFECT_DATA_12 0xb7
struct format_defect_list_header
@@ -222,18 +287,49 @@ struct scsi_read_format_capacities
uint8_t reserved1[3];
};
-struct scsi_verify
+struct scsi_verify_10
{
- uint8_t opcode; /* VERIFY */
+ uint8_t opcode; /* VERIFY(10) */
uint8_t byte2;
#define SVFY_LUN_MASK 0xE0
#define SVFY_RELADR 0x01
-#define SVFY_BYTECHK 0x02
+#define SVFY_BYTCHK 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];
+ uint8_t group;
+ uint8_t length[2]; /* number of blocks to verify */
+ uint8_t control;
+};
+
+struct scsi_verify_12
+{
+ uint8_t opcode; /* VERIFY(12) */
+ uint8_t byte2;
+ uint8_t addr[4]; /* LBA to begin verification at */
+ uint8_t length[4]; /* number of blocks to verify */
+ uint8_t group;
+ uint8_t control;
+};
+
+struct scsi_verify_16
+{
+ uint8_t opcode; /* VERIFY(16) */
+ uint8_t byte2;
+ uint8_t addr[8]; /* LBA to begin verification at */
+ uint8_t length[4]; /* number of blocks to verify */
+ uint8_t group;
+ uint8_t control;
+};
+
+struct scsi_compare_and_write
+{
+ uint8_t opcode; /* COMPARE AND WRITE */
+ uint8_t byte2;
+ uint8_t addr[8]; /* LBA to begin verification at */
+ uint8_t reserved[3];
+ uint8_t length; /* number of blocks */
+ uint8_t group;
+ uint8_t control;
};
struct scsi_write_and_verify
@@ -314,6 +410,8 @@ struct scsi_read_defect_data_hdr_10
#define SRDDH10_PHYSICAL_SECTOR_FORMAT 0x05
u_int8_t format;
u_int8_t length[2];
+#define SRDDH10_MAX_LENGTH SRDD10_MAX_LENGTH - \
+ sizeof(struct scsi_read_defect_data_hdr_10)
};
struct scsi_defect_desc_block
@@ -321,10 +419,18 @@ struct scsi_defect_desc_block
u_int8_t address[4];
};
+struct scsi_defect_desc_long_block
+{
+ u_int8_t address[8];
+};
+
struct scsi_defect_desc_bytes_from_index
{
u_int8_t cylinder[3];
u_int8_t head;
+#define SDD_EXT_BFI_MADS 0x80000000
+#define SDD_EXT_BFI_FLAG_MASK 0xf0000000
+#define SDD_EXT_BFI_ENTIRE_TRACK 0x0fffffff
u_int8_t bytes_from_index[4];
};
@@ -332,6 +438,9 @@ struct scsi_defect_desc_phys_sector
{
u_int8_t cylinder[3];
u_int8_t head;
+#define SDD_EXT_PHYS_MADS 0x80000000
+#define SDD_EXT_PHYS_FLAG_MASK 0xf0000000
+#define SDD_EXT_PHYS_ENTIRE_TRACK 0x0fffffff
u_int8_t sector[4];
};
@@ -345,7 +454,10 @@ struct scsi_read_defect_data_hdr_12
#define SRDDH12_BYTES_FROM_INDEX_FORMAT 0x04
#define SRDDH12_PHYSICAL_SECTOR_FORMAT 0x05
u_int8_t format;
+ u_int8_t generation[2];
u_int8_t length[4];
+#define SRDDH12_MAX_LENGTH SRDD12_MAX_LENGTH - \
+ sizeof(struct scsi_read_defect_data_hdr_12)
};
union disk_pages /* this is the structure copied from osf */
@@ -515,7 +627,8 @@ struct scsi_da_rw_recovery_page {
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 byte8;
+#define SMS_RWER_LBPERE 0x80
u_int8_t write_retry_count;
u_int8_t reserved2;
u_int8_t recovery_time_limit[2];
@@ -523,9 +636,9 @@ struct scsi_da_rw_recovery_page {
__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.
+ * XXX These are only left out of the kernel build to silence warnings. If,
+ * for some reason these functions are used in the kernel, the ifdefs should
+ * be moved so they are included both in the kernel and userland.
*/
#ifndef _KERNEL
void scsi_format_unit(struct ccb_scsiio *csio, u_int32_t retries,
@@ -534,6 +647,13 @@ void scsi_format_unit(struct ccb_scsiio *csio, u_int32_t retries,
u_int8_t *data_ptr, u_int32_t dxfer_len,
u_int8_t sense_len, u_int32_t timeout);
+void scsi_read_defects(struct ccb_scsiio *csio, uint32_t retries,
+ void (*cbfcnp)(struct cam_periph *, union ccb *),
+ uint8_t tag_action, uint8_t list_format,
+ uint32_t addr_desc_index, uint8_t *data_ptr,
+ uint32_t dxfer_len, int minimum_cmd_size,
+ uint8_t sense_len, uint32_t timeout);
+
void scsi_sanitize(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 control,
@@ -541,6 +661,38 @@ void scsi_sanitize(struct ccb_scsiio *csio, u_int32_t retries,
u_int32_t timeout);
#endif /* !_KERNEL */
+
+void scsi_zbc_out(struct ccb_scsiio *csio, uint32_t retries,
+ void (*cbfcnp)(struct cam_periph *, union ccb *),
+ uint8_t tag_action, uint8_t service_action, uint64_t zone_id,
+ uint8_t zone_flags, uint8_t *data_ptr, uint32_t dxfer_len,
+ uint8_t sense_len, uint32_t timeout);
+
+void scsi_zbc_in(struct ccb_scsiio *csio, uint32_t retries,
+ void (*cbfcnp)(struct cam_periph *, union ccb *),
+ uint8_t tag_action, uint8_t service_action,
+ uint64_t zone_start_lba, uint8_t zone_options,
+ uint8_t *data_ptr, uint32_t dxfer_len, uint8_t sense_len,
+ uint32_t timeout);
+
+int scsi_ata_zac_mgmt_out(struct ccb_scsiio *csio, uint32_t retries,
+ void (*cbfcnp)(struct cam_periph *, union ccb *),
+ uint8_t tag_action, int use_ncq,
+ uint8_t zm_action, uint64_t zone_id,
+ uint8_t zone_flags, uint8_t *data_ptr,
+ uint32_t dxfer_len, uint8_t *cdb_storage,
+ size_t cdb_storage_len, uint8_t sense_len,
+ uint32_t timeout);
+
+int scsi_ata_zac_mgmt_in(struct ccb_scsiio *csio, uint32_t retries,
+ void (*cbfcnp)(struct cam_periph *, union ccb *),
+ uint8_t tag_action, int use_ncq,
+ uint8_t zm_action, uint64_t zone_id,
+ uint8_t zone_flags, uint8_t *data_ptr,
+ uint32_t dxfer_len, uint8_t *cdb_storage,
+ size_t cdb_storage_len, uint8_t sense_len,
+ uint32_t timeout);
+
__END_DECLS
#endif /* _SCSI_SCSI_DA_H */