summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/cam
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2013-11-06 16:20:21 +0100
committerSebastian Huber <sebastian.huber@embedded-brains.de>2013-11-11 10:08:08 +0100
commit66659ff1ad6831b0ea7425fa6ecd8a8687523658 (patch)
tree48e22b475fa8854128e0861a33fed6f78c8094b5 /freebsd/sys/cam
parentDefine __GLOBL1() and __GLOBL() (diff)
downloadrtems-libbsd-66659ff1ad6831b0ea7425fa6ecd8a8687523658.tar.bz2
Update to FreeBSD 9.2
Diffstat (limited to 'freebsd/sys/cam')
-rw-r--r--freebsd/sys/cam/ata/ata_all.h40
-rw-r--r--freebsd/sys/cam/cam.c50
-rw-r--r--freebsd/sys/cam/cam.h19
-rw-r--r--freebsd/sys/cam/cam_ccb.h143
-rw-r--r--freebsd/sys/cam/cam_periph.h48
-rw-r--r--freebsd/sys/cam/cam_sim.h9
-rw-r--r--freebsd/sys/cam/cam_xpt.h2
-rw-r--r--freebsd/sys/cam/cam_xpt_sim.h4
-rw-r--r--freebsd/sys/cam/scsi/scsi_all.c2466
-rw-r--r--freebsd/sys/cam/scsi/scsi_all.h1392
-rw-r--r--freebsd/sys/cam/scsi/scsi_da.h51
11 files changed, 3953 insertions, 271 deletions
diff --git a/freebsd/sys/cam/ata/ata_all.h b/freebsd/sys/cam/ata/ata_all.h
index 526fc194..25732b60 100644
--- a/freebsd/sys/cam/ata/ata_all.h
+++ b/freebsd/sys/cam/ata/ata_all.h
@@ -35,7 +35,9 @@ struct ccb_ataio;
struct cam_periph;
union ccb;
-#define SID_DMA 0x10 /* Abuse inq_flags bit to track enabled DMA. */
+#define SID_DMA48 0x01 /* Abuse inq_flags bit to track enabled DMA48. */
+#define SID_AEN 0x04 /* Abuse inq_flags bit to track enabled AEN. */
+#define SID_DMA 0x10 /* Abuse inq_flags bit to track enabled DMA. */
struct ata_cmd {
u_int8_t flags; /* ATA command flags */
@@ -83,6 +85,20 @@ struct ata_res {
u_int8_t sector_count_exp;
};
+struct sep_identify_data {
+ uint8_t length; /* Enclosure descriptor length */
+ uint8_t subenc_id; /* Sub-enclosure identifier */
+ uint8_t logical_id[8]; /* Enclosure logical identifier (WWN) */
+ uint8_t vendor_id[8]; /* Vendor identification string */
+ uint8_t product_id[16]; /* Product identification string */
+ uint8_t product_rev[4]; /* Product revision string */
+ uint8_t channel_id; /* Channel identifier */
+ uint8_t firmware_rev[4];/* Firmware revision */
+ uint8_t interface_id[6];/* Interface spec ("S-E-S "/"SAF-TE")*/
+ uint8_t interface_rev[4];/* Interface spec revision */
+ uint8_t vend_spec[11]; /* Vendor specific information */
+};
+
int ata_version(int ver);
char * ata_op_string(struct ata_cmd *cmd);
@@ -126,4 +142,26 @@ int ata_speed2revision(u_int speed);
int ata_identify_match(caddr_t identbuffer, caddr_t table_entry);
int ata_static_identify_match(caddr_t identbuffer, caddr_t table_entry);
+void semb_print_ident(struct sep_identify_data *ident_data);
+
+void semb_receive_diagnostic_results(struct ccb_ataio *ataio,
+ u_int32_t retries, void (*cbfcnp)(struct cam_periph *, union ccb*),
+ uint8_t tag_action, int pcv, uint8_t page_code,
+ uint8_t *data_ptr, uint16_t allocation_length, uint32_t timeout);
+
+void semb_send_diagnostic(struct ccb_ataio *ataio,
+ u_int32_t retries, void (*cbfcnp)(struct cam_periph *, union ccb *),
+ uint8_t tag_action, uint8_t *data_ptr, uint16_t param_list_length,
+ uint32_t timeout);
+
+void semb_read_buffer(struct ccb_ataio *ataio,
+ u_int32_t retries, void (*cbfcnp)(struct cam_periph *, union ccb*),
+ uint8_t tag_action, uint8_t page_code,
+ uint8_t *data_ptr, uint16_t allocation_length, uint32_t timeout);
+
+void semb_write_buffer(struct ccb_ataio *ataio,
+ u_int32_t retries, void (*cbfcnp)(struct cam_periph *, union ccb *),
+ uint8_t tag_action, uint8_t *data_ptr, uint16_t param_list_length,
+ uint32_t timeout);
+
#endif
diff --git a/freebsd/sys/cam/cam.c b/freebsd/sys/cam/cam.c
index 6d22945a..18628cd0 100644
--- a/freebsd/sys/cam/cam.c
+++ b/freebsd/sys/cam/cam.c
@@ -39,18 +39,23 @@ __FBSDID("$FreeBSD$");
#else /* _KERNEL */
#include <stdlib.h>
#include <stdio.h>
+#include <string.h>
#include <camlib.h>
#endif /* _KERNEL */
#include <cam/cam.h>
#include <cam/cam_ccb.h>
#include <cam/scsi/scsi_all.h>
+#include <cam/scsi/smp_all.h>
#include <sys/sbuf.h>
#ifdef _KERNEL
#include <sys/libkern.h>
#include <cam/cam_queue.h>
#include <cam/cam_xpt.h>
+
+FEATURE(scbus, "SCSI devices support");
+
#endif
static int camstatusentrycomp(const void *key, const void *member);
@@ -85,6 +90,8 @@ const struct cam_status_entry cam_status_table[] = {
{ CAM_REQ_TOO_BIG, "The request was too large for this host" },
{ CAM_REQUEUE_REQ, "Unconditionally Re-queue Request", },
{ CAM_ATA_STATUS_ERROR, "ATA Status Error" },
+ { CAM_SCSI_IT_NEXUS_LOST,"Initiator/Target Nexus Lost" },
+ { CAM_SMP_STATUS_ERROR, "SMP Status Error" },
{ CAM_IDE, "Initiator Detected Error Message Received" },
{ CAM_RESRC_UNAVAIL, "Resource Unavailable" },
{ CAM_UNACKED_EVENT, "Unacknowledged Event by Host" },
@@ -105,6 +112,15 @@ const int num_cam_status_entries =
#ifdef _KERNEL
SYSCTL_NODE(_kern, OID_AUTO, cam, CTLFLAG_RD, 0, "CAM Subsystem");
+
+#ifndef CAM_DEFAULT_SORT_IO_QUEUES
+#define CAM_DEFAULT_SORT_IO_QUEUES 1
+#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
void
@@ -266,6 +282,21 @@ cam_error_string(struct cam_device *device, union ccb *ccb, char *str,
break;
}
break;
+ case XPT_SMP_IO:
+ switch (proto_flags & CAM_EPF_LEVEL_MASK) {
+ case CAM_EPF_NONE:
+ break;
+ case CAM_EPF_ALL:
+ proto_flags |= CAM_ESMF_PRINT_FULL_CMD;
+ /* FALLTHROUGH */
+ case CAM_EPF_NORMAL:
+ case CAM_EPF_MINIMAL:
+ proto_flags |= CAM_ESMF_PRINT_STATUS;
+ /* FALLTHROUGH */
+ default:
+ break;
+ }
+ break;
default:
break;
}
@@ -292,6 +323,12 @@ cam_error_string(struct cam_device *device, union ccb *ccb, char *str,
#endif /* _KERNEL/!_KERNEL */
sbuf_printf(&sb, "\n");
break;
+ case XPT_SMP_IO:
+ smp_command_sbuf(&ccb->smpio, &sb, path_str, 79 -
+ strlen(path_str), (proto_flags &
+ CAM_ESMF_PRINT_FULL_CMD) ? 79 : 0);
+ sbuf_printf(&sb, "\n");
+ break;
default:
break;
}
@@ -358,6 +395,19 @@ cam_error_string(struct cam_device *device, union ccb *ccb, char *str,
#endif /* _KERNEL/!_KERNEL */
}
break;
+ case XPT_SMP_IO:
+ if ((ccb->ccb_h.status & CAM_STATUS_MASK) !=
+ CAM_SMP_STATUS_ERROR)
+ break;
+
+ if (proto_flags & CAM_ESF_PRINT_STATUS) {
+ sbuf_cat(&sb, path_str);
+ sbuf_printf(&sb, "SMP status: %s (%#x)\n",
+ smp_error_desc(ccb->smpio.smp_response[2]),
+ ccb->smpio.smp_response[2]);
+ }
+ /* There is no SMP equivalent to SCSI sense. */
+ break;
default:
break;
}
diff --git a/freebsd/sys/cam/cam.h b/freebsd/sys/cam/cam.h
index 8ea1d04c..af57f1a6 100644
--- a/freebsd/sys/cam/cam.h
+++ b/freebsd/sys/cam/cam.h
@@ -113,6 +113,15 @@ typedef enum {
CAM_RETRY_SELTO = 0x02 /* Retry Selection Timeouts */
} cam_flags;
+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_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. */
+};
+
/* CAM Status field values */
typedef enum {
CAM_REQ_INPROG, /* CCB request is in progress */
@@ -152,6 +161,7 @@ typedef enum {
*/
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 */
@@ -203,6 +213,12 @@ typedef enum {
} cam_error_scsi_flags;
typedef enum {
+ CAM_ESMF_PRINT_NONE = 0x00,
+ CAM_ESMF_PRINT_STATUS = 0x10,
+ CAM_ESMF_PRINT_FULL_CMD = 0x20,
+} cam_error_smp_flags;
+
+typedef enum {
CAM_EAF_PRINT_NONE = 0x00,
CAM_EAF_PRINT_STATUS = 0x10,
CAM_EAF_PRINT_RESULT = 0x20
@@ -216,6 +232,9 @@ struct cam_status_entry
extern const struct cam_status_entry cam_status_table[];
extern const int num_cam_status_entries;
+#ifdef _KERNEL
+extern int cam_sort_io_queues;
+#endif
union ccb;
#ifdef SYSCTL_DECL /* from sysctl.h */
diff --git a/freebsd/sys/cam/cam_ccb.h b/freebsd/sys/cam/cam_ccb.h
index ced8cca1..893c6469 100644
--- a/freebsd/sys/cam/cam_ccb.h
+++ b/freebsd/sys/cam/cam_ccb.h
@@ -67,13 +67,19 @@ typedef enum {
* Perform transport negotiation
* with this command.
*/
- CAM_SCATTER_VALID = 0x00000010,/* Scatter/gather list is valid */
+ CAM_DATA_ISPHYS = 0x00200000,/* Data type with physical addrs */
CAM_DIS_AUTOSENSE = 0x00000020,/* Disable autosense feature */
- CAM_DIR_RESV = 0x00000000,/* Data direction (00:reserved) */
+ CAM_DIR_BOTH = 0x00000000,/* Data direction (00:IN/OUT) */
CAM_DIR_IN = 0x00000040,/* Data direction (01:DATA IN) */
CAM_DIR_OUT = 0x00000080,/* Data direction (10:DATA OUT) */
CAM_DIR_NONE = 0x000000C0,/* Data direction (11:no data) */
CAM_DIR_MASK = 0x000000C0,/* Data direction Mask */
+ CAM_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_MASK = 0x00240010,/* Data type mask */
CAM_SOFT_RST_OP = 0x00000100,/* Use Soft reset alternative */
CAM_ENG_SYNC = 0x00000200,/* Flush resid bytes on complete */
CAM_DEV_QFRZDIS = 0x00000400,/* Disable DEV Q freezing */
@@ -84,13 +90,16 @@ typedef enum {
CAM_TAG_ACTION_VALID = 0x00008000,/* Use the tag action in this ccb*/
CAM_PASS_ERR_RECOVER = 0x00010000,/* Pass driver does err. recovery*/
CAM_DIS_DISCONNECT = 0x00020000,/* Disable disconnect */
- CAM_SG_LIST_PHYS = 0x00040000,/* SG list has physical addrs. */
CAM_MSG_BUF_PHYS = 0x00080000,/* Message buffer ptr is physical*/
CAM_SNS_BUF_PHYS = 0x00100000,/* Autosense data ptr is physical*/
- CAM_DATA_PHYS = 0x00200000,/* SG/Buffer data ptrs are phys. */
CAM_CDB_PHYS = 0x00400000,/* CDB poiner is physical */
CAM_ENG_SGLIST = 0x00800000,/* SG list is for the HBA engine */
+/* 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 */
@@ -99,7 +108,7 @@ typedef enum {
CAM_MSGB_VALID = 0x10000000,/* Message buffer valid */
CAM_STATUS_VALID = 0x20000000,/* Status buffer valid */
CAM_DATAB_VALID = 0x40000000,/* Data buffer valid */
-
+
/* Host target Mode flags */
CAM_SEND_SENSE = 0x08000000,/* Send sense data with status */
CAM_TERM_IO = 0x10000000,/* Terminate I/O Message sup. */
@@ -147,6 +156,8 @@ typedef enum {
/* Device statistics (error counts, etc.) */
XPT_FREEZE_QUEUE = 0x0d,
/* Freeze device queue */
+ XPT_DEV_ADVINFO = 0x0e,
+ /* Get/Set Device advanced information */
/* SCSI Control Functions: 0x10->0x1F */
XPT_ABORT = 0x10,
/* Abort the specified CCB */
@@ -188,6 +199,9 @@ typedef enum {
* Set SIM specific knob values.
*/
+ XPT_SMP_IO = 0x1b | XPT_FC_DEV_QUEUED,
+ /* Serial Management Protocol */
+
XPT_SCAN_TGT = 0x1E | XPT_FC_QUEUED | XPT_FC_USER_CCB
| XPT_FC_XPT_ONLY,
/* Scan Target */
@@ -240,6 +254,7 @@ typedef enum {
PROTO_ATA, /* AT Attachment */
PROTO_ATAPI, /* AT Attachment Packetized Interface */
PROTO_SATAPM, /* SATA Port Multiplier */
+ PROTO_SEMB, /* SATA Enclosure Management Bridge */
} cam_proto;
typedef enum {
@@ -399,15 +414,24 @@ typedef enum {
DEV_MATCH_TARGET = 0x002,
DEV_MATCH_LUN = 0x004,
DEV_MATCH_INQUIRY = 0x008,
+ DEV_MATCH_DEVID = 0x010,
DEV_MATCH_ANY = 0x00f
} dev_pattern_flags;
+struct device_id_match_pattern {
+ uint8_t id_len;
+ uint8_t id[256];
+};
+
struct device_match_pattern {
- path_id_t path_id;
- target_id_t target_id;
- lun_id_t target_lun;
- struct scsi_static_inquiry_pattern inq_pat;
- dev_pattern_flags flags;
+ path_id_t path_id;
+ target_id_t target_id;
+ lun_id_t target_lun;
+ dev_pattern_flags flags;
+ union {
+ struct scsi_static_inquiry_pattern inq_pat;
+ struct device_id_match_pattern devid_pat;
+ } data;
};
typedef enum {
@@ -538,7 +562,7 @@ struct ccb_dev_match {
/*
* Definitions for the path inquiry CCB fields.
*/
-#define CAM_VERSION 0x15 /* Hex value for current version */
+#define CAM_VERSION 0x17 /* Hex value for current version */
typedef enum {
PI_MDP_ABLE = 0x80, /* Supports MDP message */
@@ -566,7 +590,8 @@ typedef enum {
PIM_NOINITIATOR = 0x20, /* Initiator role not supported. */
PIM_NOBUSRESET = 0x10, /* User has disabled initial BUS RESET */
PIM_NO_6_BYTE = 0x08, /* Do not send 6-byte commands */
- PIM_SEQSCAN = 0x04 /* Do bus scans sequentially, not in parallel */
+ PIM_SEQSCAN = 0x04, /* Do bus scans sequentially, not in parallel */
+ PIM_UNMAPPED = 0x02,
} pi_miscflag;
/* Path Inquiry CCB */
@@ -617,6 +642,10 @@ struct ccb_pathinq {
char ccb_pathinq_settings_opaque[PATHINQ_SETTINGS_SIZE];
} xport_specific;
u_int maxio; /* Max supported I/O size, in bytes. */
+ u_int16_t hba_vendor; /* HBA vendor ID */
+ u_int16_t hba_device; /* HBA device ID */
+ u_int16_t hba_subvendor; /* HBA subvendor ID */
+ u_int16_t hba_subdevice; /* HBA subdevice ID */
};
/* Path Statistics CCB */
@@ -625,6 +654,32 @@ struct ccb_pathstats {
struct timeval last_reset; /* Time of last bus reset/loop init */
};
+typedef enum {
+ SMP_FLAG_NONE = 0x00,
+ SMP_FLAG_REQ_SG = 0x01,
+ SMP_FLAG_RSP_SG = 0x02
+} ccb_smp_pass_flags;
+
+/*
+ * Serial Management Protocol CCB
+ * XXX Currently the semantics for this CCB are that it is executed either
+ * by the addressed device, or that device's parent (i.e. an expander for
+ * any device on an expander) if the addressed device doesn't support SMP.
+ * Later, once we have the ability to probe SMP-only devices and put them
+ * in CAM's topology, the CCB will only be executed by the addressed device
+ * if possible.
+ */
+struct ccb_smpio {
+ struct ccb_hdr ccb_h;
+ uint8_t *smp_request;
+ int smp_request_len;
+ uint16_t smp_request_sglist_cnt;
+ uint8_t *smp_response;
+ int smp_response_len;
+ uint16_t smp_response_sglist_cnt;
+ ccb_smp_pass_flags flags;
+};
+
typedef union {
u_int8_t *sense_ptr; /*
* Pointer to storage
@@ -729,6 +784,8 @@ struct ccb_relsim {
* Definitions for the asynchronous callback CCB fields.
*/
typedef enum {
+ AC_UNIT_ATTENTION = 0x4000,/* Device reported UNIT ATTENTION */
+ AC_ADVINFO_CHANGED = 0x2000,/* Advance info might have changes */
AC_CONTRACT = 0x1000,/* A contractual callback */
AC_GETDEV_CHANGED = 0x800,/* Getdev info might have changed */
AC_INQ_CHANGED = 0x400,/* Inquiry info might have changed */
@@ -868,9 +925,14 @@ struct ccb_trans_settings_pata {
#define CTS_ATA_VALID_MODE 0x01
#define CTS_ATA_VALID_BYTECOUNT 0x02
#define CTS_ATA_VALID_ATAPI 0x20
+#define CTS_ATA_VALID_CAPS 0x40
int mode; /* Mode */
u_int bytecount; /* Length of PIO transaction */
u_int atapi; /* Length of ATAPI CDB */
+ u_int caps; /* Device and host SATA caps. */
+#define CTS_ATA_CAPS_H 0x0000ffff
+#define CTS_ATA_CAPS_H_DMA48 0x00000001 /* 48-bit DMA */
+#define CTS_ATA_CAPS_D 0xffff0000
};
struct ccb_trans_settings_sata {
@@ -1091,6 +1153,28 @@ struct ccb_eng_exec { /* This structure must match SCSIIO size */
#define XPT_CCB_INVALID -1 /* for signaling a bad CCB to free */
/*
+ * CCB for working with advanced device information. This operates in a fashion
+ * similar to XPT_GDEV_TYPE. Specify the target in ccb_h, the buffer
+ * type requested, and provide a buffer size/buffer to write to. If the
+ * buffer is too small, provsiz will be larger than bufsiz.
+ */
+struct ccb_dev_advinfo {
+ struct ccb_hdr ccb_h;
+ uint32_t flags;
+#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 */
+#define CDAI_TYPE_SCSI_DEVID 1
+#define CDAI_TYPE_SERIAL_NUM 2
+#define CDAI_TYPE_PHYS_PATH 3
+#define CDAI_TYPE_RCAPLONG 4
+ 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 */
+ uint8_t *buf; /* IN/OUT: Buffer for requested data */
+};
+
+/*
* 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
@@ -1124,9 +1208,11 @@ union ccb {
struct ccb_notify_acknowledge cna2;
struct ccb_eng_inq cei;
struct ccb_eng_exec cee;
+ struct ccb_smpio smpio;
struct ccb_rescan crcn;
struct ccb_debug cdbg;
struct ccb_ataio ataio;
+ struct ccb_dev_advinfo cdai;
};
__BEGIN_DECLS
@@ -1153,6 +1239,13 @@ cam_fill_ataio(struct ccb_ataio *ataio, u_int32_t retries,
u_int32_t timeout);
static __inline void
+cam_fill_smpio(struct ccb_smpio *smpio, uint32_t retries,
+ void (*cbfcnp)(struct cam_periph *, union ccb *), uint32_t flags,
+ uint8_t *smp_request, int smp_request_len,
+ uint8_t *smp_response, int smp_response_len,
+ uint32_t timeout);
+
+static __inline void
cam_fill_csio(struct ccb_scsiio *csio, u_int32_t retries,
void (*cbfcnp)(struct cam_periph *, union ccb *),
u_int32_t flags, u_int8_t tag_action,
@@ -1209,6 +1302,32 @@ cam_fill_ataio(struct ccb_ataio *ataio, u_int32_t retries,
ataio->tag_action = tag_action;
}
+static __inline void
+cam_fill_smpio(struct ccb_smpio *smpio, uint32_t retries,
+ void (*cbfcnp)(struct cam_periph *, union ccb *), uint32_t flags,
+ uint8_t *smp_request, int smp_request_len,
+ uint8_t *smp_response, int smp_response_len,
+ uint32_t timeout)
+{
+#ifdef _KERNEL
+ KASSERT((flags & CAM_DIR_MASK) == CAM_DIR_BOTH,
+ ("direction != CAM_DIR_BOTH"));
+ KASSERT((smp_request != NULL) && (smp_response != NULL),
+ ("need valid request and response buffers"));
+ KASSERT((smp_request_len != 0) && (smp_response_len != 0),
+ ("need non-zero request and response lengths"));
+#endif /*_KERNEL*/
+ smpio->ccb_h.func_code = XPT_SMP_IO;
+ smpio->ccb_h.flags = flags;
+ smpio->ccb_h.retry_count = retries;
+ smpio->ccb_h.cbfcnp = cbfcnp;
+ smpio->ccb_h.timeout = timeout;
+ smpio->smp_request = smp_request;
+ smpio->smp_request_len = smp_request_len;
+ smpio->smp_response = smp_response;
+ smpio->smp_response_len = smp_response_len;
+}
+
void cam_calc_geometry(struct ccb_calc_geometry *ccg, int extended);
__END_DECLS
diff --git a/freebsd/sys/cam/cam_periph.h b/freebsd/sys/cam/cam_periph.h
index c68fc9ba..102dc3c3 100644
--- a/freebsd/sys/cam/cam_periph.h
+++ b/freebsd/sys/cam/cam_periph.h
@@ -36,6 +36,8 @@
#ifdef _KERNEL
+#include <cam/cam_xpt.h>
+
struct devstat;
extern struct cam_periph *xpt_periph;
@@ -118,7 +120,6 @@ struct cam_periph {
#define CAM_PERIPH_INVALID 0x08
#define CAM_PERIPH_NEW_DEV_FOUND 0x10
#define CAM_PERIPH_RECOVERY_INPROG 0x20
-#define CAM_PERIPH_SENSE_INPROG 0x40
#define CAM_PERIPH_FREE 0x80
u_int32_t immediate_priority;
u_int32_t refcount;
@@ -143,6 +144,7 @@ cam_status cam_periph_alloc(periph_ctor_t *periph_ctor,
char *name, cam_periph_type type, struct cam_path *,
ac_callback_t *, ac_code, void *arg);
struct cam_periph *cam_periph_find(struct cam_path *path, char *name);
+int cam_periph_list(struct cam_path *, struct sbuf *);
cam_status cam_periph_acquire(struct cam_periph *periph);
void cam_periph_release(struct cam_periph *periph);
void cam_periph_release_locked(struct cam_periph *periph);
@@ -202,5 +204,49 @@ cam_periph_owned(struct cam_periph *periph)
return (mtx_owned(periph->sim->mtx));
}
+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));
+}
+
+static inline struct cam_periph *
+cam_periph_acquire_first(struct periph_driver *driver)
+{
+ struct cam_periph *periph;
+
+ xpt_lock_buses();
+ periph = TAILQ_FIRST(&driver->units);
+ while (periph != NULL && (periph->flags & CAM_PERIPH_INVALID) != 0)
+ periph = TAILQ_NEXT(periph, unit_links);
+ if (periph != NULL)
+ periph->refcount++;
+ xpt_unlock_buses();
+ return (periph);
+}
+
+static inline struct cam_periph *
+cam_periph_acquire_next(struct cam_periph *pperiph)
+{
+ struct cam_periph *periph = pperiph;
+
+ mtx_assert(pperiph->sim->mtx, MA_NOTOWNED);
+ xpt_lock_buses();
+ do {
+ periph = TAILQ_NEXT(periph, unit_links);
+ } while (periph != NULL && (periph->flags & CAM_PERIPH_INVALID) != 0);
+ if (periph != NULL)
+ periph->refcount++;
+ xpt_unlock_buses();
+ cam_periph_release(pperiph);
+ return (periph);
+}
+
+#define CAM_PERIPH_FOREACH(periph, driver) \
+ for ((periph) = cam_periph_acquire_first(driver); \
+ (periph) != NULL; \
+ (periph) = cam_periph_acquire_next(periph))
+
#endif /* _KERNEL */
#endif /* _CAM_CAM_PERIPH_H */
diff --git a/freebsd/sys/cam/cam_sim.h b/freebsd/sys/cam/cam_sim.h
index ce6b38fc..ba0ac18f 100644
--- a/freebsd/sys/cam/cam_sim.h
+++ b/freebsd/sys/cam/cam_sim.h
@@ -32,6 +32,11 @@
#define _CAM_CAM_SIM_H 1
#ifdef _KERNEL
+#ifdef __rtems__
+#include <rtems/bsd/sys/param.h>
+#include <sys/proc.h>
+#include <sys/condvar.h>
+#endif /* __rtems__ */
/*
* The sim driver creates a sim for each controller. The sim device
@@ -160,8 +165,8 @@ struct cam_sim {
};
-#define CAM_SIM_LOCK(sim) mtx_lock((sim)->mtx);
-#define CAM_SIM_UNLOCK(sim) mtx_unlock((sim)->mtx);
+#define CAM_SIM_LOCK(sim) mtx_lock((sim)->mtx)
+#define CAM_SIM_UNLOCK(sim) mtx_unlock((sim)->mtx)
static __inline u_int32_t
cam_sim_path(struct cam_sim *sim)
diff --git a/freebsd/sys/cam/cam_xpt.h b/freebsd/sys/cam/cam_xpt.h
index c716a6ec..492fa3a4 100644
--- a/freebsd/sys/cam/cam_xpt.h
+++ b/freebsd/sys/cam/cam_xpt.h
@@ -81,6 +81,8 @@ cam_status xpt_create_path_unlocked(struct cam_path **new_path_ptr,
struct cam_periph *perph,
path_id_t path_id,
target_id_t target_id, lun_id_t lun_id);
+int xpt_getattr(char *buf, size_t len, const char *attr,
+ struct cam_path *path);
void xpt_free_path(struct cam_path *path);
void xpt_path_counts(struct cam_path *path, uint32_t *bus_ref,
uint32_t *periph_ref, uint32_t *target_ref,
diff --git a/freebsd/sys/cam/cam_xpt_sim.h b/freebsd/sys/cam/cam_xpt_sim.h
index 67b895f2..d32eea71 100644
--- a/freebsd/sys/cam/cam_xpt_sim.h
+++ b/freebsd/sys/cam/cam_xpt_sim.h
@@ -42,7 +42,11 @@ int32_t xpt_bus_register(struct cam_sim *sim, device_t parent,
int32_t xpt_bus_deregister(path_id_t path_id);
u_int32_t xpt_freeze_simq(struct cam_sim *sim, u_int count);
void xpt_release_simq(struct cam_sim *sim, int run_queue);
+#ifndef __rtems__
u_int32_t xpt_freeze_devq(struct cam_path *path, u_int count);
+#else /* __rtems__ */
+#define xpt_freeze_devq(path, count) do { } while (0)
+#endif /* __rtems__ */
u_int32_t xpt_freeze_devq_rl(struct cam_path *path, cam_rl rl,
u_int count);
void xpt_release_devq(struct cam_path *path,
diff --git a/freebsd/sys/cam/scsi/scsi_all.c b/freebsd/sys/cam/scsi/scsi_all.c
index 151ebb10..5b504010 100644
--- a/freebsd/sys/cam/scsi/scsi_all.c
+++ b/freebsd/sys/cam/scsi/scsi_all.c
@@ -33,6 +33,8 @@
__FBSDID("$FreeBSD$");
#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/types.h>
+#include <sys/stdint.h>
#ifdef _KERNEL
#ifndef __rtems__
@@ -44,6 +46,9 @@ __FBSDID("$FreeBSD$");
#include <sys/systm.h>
#include <sys/libkern.h>
#include <sys/kernel.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
#include <sys/sysctl.h>
#else
#include <errno.h>
@@ -57,9 +62,17 @@ __FBSDID("$FreeBSD$");
#include <cam/cam_queue.h>
#include <cam/cam_xpt.h>
#include <cam/scsi/scsi_all.h>
+#include <sys/ata.h>
#include <sys/sbuf.h>
-#ifndef _KERNEL
+
+#ifdef _KERNEL
+#include <cam/cam_periph.h>
+#include <cam/cam_xpt_sim.h>
+#include <cam/cam_xpt_periph.h>
+#include <cam/cam_xpt_internal.h>
+#else
#include <camlib.h>
+#include <stddef.h>
#ifndef FALSE
#define FALSE 0
@@ -368,6 +381,8 @@ static struct op_table_entry scsi_op_codes[] = {
{ 0x40, D | T | L | P | W | R | O | M | S | C, "CHANGE DEFINITION" },
/* 41 O WRITE SAME(10) */
{ 0x41, D, "WRITE SAME(10)" },
+ /* 42 O UNMAP */
+ { 0x42, D, "UNMAP" },
/* 42 O READ SUB-CHANNEL */
{ 0x42, R, "READ SUB-CHANNEL" },
/* 43 O READ TOC/PMA/ATIP */
@@ -615,14 +630,24 @@ scsi_op_desc(u_int16_t opcode, struct scsi_inquiry_data *inq_data)
struct op_table_entry *table[2];
int num_tables;
- pd_type = SID_TYPE(inq_data);
+ /*
+ * If we've got inquiry data, use it to determine what type of
+ * device we're dealing with here. Otherwise, assume direct
+ * access.
+ */
+ if (inq_data == NULL) {
+ pd_type = T_DIRECT;
+ match = NULL;
+ } else {
+ pd_type = SID_TYPE(inq_data);
- match = cam_quirkmatch((caddr_t)inq_data,
- (caddr_t)scsi_op_quirk_table,
- sizeof(scsi_op_quirk_table)/
- sizeof(*scsi_op_quirk_table),
- sizeof(*scsi_op_quirk_table),
- scsi_inquiry_match);
+ match = cam_quirkmatch((caddr_t)inq_data,
+ (caddr_t)scsi_op_quirk_table,
+ sizeof(scsi_op_quirk_table)/
+ sizeof(*scsi_op_quirk_table),
+ sizeof(*scsi_op_quirk_table),
+ scsi_inquiry_match);
+ }
if (match != NULL) {
table[0] = ((struct scsi_op_quirk_entry *)match)->op_table;
@@ -690,10 +715,7 @@ const struct sense_key_table_entry sense_key_table[] =
{
{ SSD_KEY_NO_SENSE, SS_NOP, "NO SENSE" },
{ SSD_KEY_RECOVERED_ERROR, SS_NOP|SSQ_PRINT_SENSE, "RECOVERED ERROR" },
- {
- SSD_KEY_NOT_READY, SS_TUR|SSQ_MANY|SSQ_DECREMENT_COUNT|EBUSY,
- "NOT READY"
- },
+ { SSD_KEY_NOT_READY, SS_RDEF, "NOT READY" },
{ SSD_KEY_MEDIUM_ERROR, SS_RDEF, "MEDIUM ERROR" },
{ SSD_KEY_HARDWARE_ERROR, SS_RDEF, "HARDWARE FAILURE" },
{ SSD_KEY_ILLEGAL_REQUEST, SS_FATAL|EINVAL, "ILLEGAL REQUEST" },
@@ -706,7 +728,7 @@ const struct sense_key_table_entry sense_key_table[] =
{ SSD_KEY_EQUAL, SS_NOP, "EQUAL" },
{ SSD_KEY_VOLUME_OVERFLOW, SS_FATAL|EIO, "VOLUME OVERFLOW" },
{ SSD_KEY_MISCOMPARE, SS_NOP, "MISCOMPARE" },
- { SSD_KEY_RESERVED, SS_FATAL|EIO, "RESERVED" }
+ { SSD_KEY_COMPLETED, SS_NOP, "COMPLETED" }
};
const int sense_key_table_size =
@@ -722,6 +744,172 @@ static struct asc_table_entry sony_mo_entries[] = {
"Logical unit not ready, cause not reportable") }
};
+static struct asc_table_entry hgst_entries[] = {
+ { SST(0x04, 0xF0, SS_RDEF,
+ "Vendor Unique - Logical Unit Not Ready") },
+ { SST(0x0A, 0x01, SS_RDEF,
+ "Unrecovered Super Certification Log Write Error") },
+ { SST(0x0A, 0x02, SS_RDEF,
+ "Unrecovered Super Certification Log Read Error") },
+ { SST(0x15, 0x03, SS_RDEF,
+ "Unrecovered Sector Error") },
+ { SST(0x3E, 0x04, SS_RDEF,
+ "Unrecovered Self-Test Hard-Cache Test Fail") },
+ { SST(0x3E, 0x05, SS_RDEF,
+ "Unrecovered Self-Test OTF-Cache Fail") },
+ { SST(0x40, 0x00, SS_RDEF,
+ "Unrecovered SAT No Buffer Overflow Error") },
+ { SST(0x40, 0x01, SS_RDEF,
+ "Unrecovered SAT Buffer Overflow Error") },
+ { SST(0x40, 0x02, SS_RDEF,
+ "Unrecovered SAT No Buffer Overflow With ECS Fault") },
+ { SST(0x40, 0x03, SS_RDEF,
+ "Unrecovered SAT Buffer Overflow With ECS Fault") },
+ { SST(0x40, 0x81, SS_RDEF,
+ "DRAM Failure") },
+ { SST(0x44, 0x0B, SS_RDEF,
+ "Vendor Unique - Internal Target Failure") },
+ { SST(0x44, 0xF2, SS_RDEF,
+ "Vendor Unique - Internal Target Failure") },
+ { SST(0x44, 0xF6, SS_RDEF,
+ "Vendor Unique - Internal Target Failure") },
+ { SST(0x44, 0xF9, SS_RDEF,
+ "Vendor Unique - Internal Target Failure") },
+ { SST(0x44, 0xFA, SS_RDEF,
+ "Vendor Unique - Internal Target Failure") },
+ { SST(0x5D, 0x22, SS_RDEF,
+ "Extreme Over-Temperature Warning") },
+ { SST(0x5D, 0x50, SS_RDEF,
+ "Load/Unload cycle Count Warning") },
+ { SST(0x81, 0x00, SS_RDEF,
+ "Vendor Unique - Internal Logic Error") },
+ { SST(0x85, 0x00, SS_RDEF,
+ "Vendor Unique - Internal Key Seed Error") },
+};
+
+static struct asc_table_entry seagate_entries[] = {
+ { SST(0x04, 0xF0, SS_RDEF,
+ "Logical Unit Not Ready, super certify in Progress") },
+ { SST(0x08, 0x86, SS_RDEF,
+ "Write Fault Data Corruption") },
+ { SST(0x09, 0x0D, SS_RDEF,
+ "Tracking Failure") },
+ { SST(0x09, 0x0E, SS_RDEF,
+ "ETF Failure") },
+ { SST(0x0B, 0x5D, SS_RDEF,
+ "Pre-SMART Warning") },
+ { SST(0x0B, 0x85, SS_RDEF,
+ "5V Voltage Warning") },
+ { SST(0x0B, 0x8C, SS_RDEF,
+ "12V Voltage Warning") },
+ { SST(0x0C, 0xFF, SS_RDEF,
+ "Write Error - Too many error recovery revs") },
+ { SST(0x11, 0xFF, SS_RDEF,
+ "Unrecovered Read Error - Too many error recovery revs") },
+ { SST(0x19, 0x0E, SS_RDEF,
+ "Fewer than 1/2 defect list copies") },
+ { SST(0x20, 0xF3, SS_RDEF,
+ "Illegal CDB linked to skip mask cmd") },
+ { SST(0x24, 0xF0, SS_RDEF,
+ "Illegal byte in CDB, LBA not matching") },
+ { SST(0x24, 0xF1, SS_RDEF,
+ "Illegal byte in CDB, LEN not matching") },
+ { SST(0x24, 0xF2, SS_RDEF,
+ "Mask not matching transfer length") },
+ { SST(0x24, 0xF3, SS_RDEF,
+ "Drive formatted without plist") },
+ { SST(0x26, 0x95, SS_RDEF,
+ "Invalid Field Parameter - CAP File") },
+ { SST(0x26, 0x96, SS_RDEF,
+ "Invalid Field Parameter - RAP File") },
+ { SST(0x26, 0x97, SS_RDEF,
+ "Invalid Field Parameter - TMS Firmware Tag") },
+ { SST(0x26, 0x98, SS_RDEF,
+ "Invalid Field Parameter - Check Sum") },
+ { SST(0x26, 0x99, SS_RDEF,
+ "Invalid Field Parameter - Firmware Tag") },
+ { SST(0x29, 0x08, SS_RDEF,
+ "Write Log Dump data") },
+ { SST(0x29, 0x09, SS_RDEF,
+ "Write Log Dump data") },
+ { SST(0x29, 0x0A, SS_RDEF,
+ "Reserved disk space") },
+ { SST(0x29, 0x0B, SS_RDEF,
+ "SDBP") },
+ { SST(0x29, 0x0C, SS_RDEF,
+ "SDBP") },
+ { SST(0x31, 0x91, SS_RDEF,
+ "Format Corrupted World Wide Name (WWN) is Invalid") },
+ { SST(0x32, 0x03, SS_RDEF,
+ "Defect List - Length exceeds Command Allocated Length") },
+ { SST(0x33, 0x00, SS_RDEF,
+ "Flash not ready for access") },
+ { SST(0x3F, 0x70, SS_RDEF,
+ "Invalid RAP block") },
+ { SST(0x3F, 0x71, SS_RDEF,
+ "RAP/ETF mismatch") },
+ { SST(0x3F, 0x90, SS_RDEF,
+ "Invalid CAP block") },
+ { SST(0x3F, 0x91, SS_RDEF,
+ "World Wide Name (WWN) Mismatch") },
+ { SST(0x40, 0x01, SS_RDEF,
+ "DRAM Parity Error") },
+ { SST(0x40, 0x02, SS_RDEF,
+ "DRAM Parity Error") },
+ { SST(0x42, 0x0A, SS_RDEF,
+ "Loopback Test") },
+ { SST(0x42, 0x0B, SS_RDEF,
+ "Loopback Test") },
+ { SST(0x44, 0xF2, SS_RDEF,
+ "Compare error during data integrity check") },
+ { SST(0x44, 0xF6, SS_RDEF,
+ "Unrecoverable error during data integrity check") },
+ { SST(0x47, 0x80, SS_RDEF,
+ "Fibre Channel Sequence Error") },
+ { SST(0x4E, 0x01, SS_RDEF,
+ "Information Unit Too Short") },
+ { SST(0x80, 0x00, SS_RDEF,
+ "General Firmware Error / Command Timeout") },
+ { SST(0x80, 0x01, SS_RDEF,
+ "Command Timeout") },
+ { SST(0x80, 0x02, SS_RDEF,
+ "Command Timeout") },
+ { SST(0x80, 0x80, SS_RDEF,
+ "FC FIFO Error During Read Transfer") },
+ { SST(0x80, 0x81, SS_RDEF,
+ "FC FIFO Error During Write Transfer") },
+ { SST(0x80, 0x82, SS_RDEF,
+ "DISC FIFO Error During Read Transfer") },
+ { SST(0x80, 0x83, SS_RDEF,
+ "DISC FIFO Error During Write Transfer") },
+ { SST(0x80, 0x84, SS_RDEF,
+ "LBA Seeded LRC Error on Read") },
+ { SST(0x80, 0x85, SS_RDEF,
+ "LBA Seeded LRC Error on Write") },
+ { SST(0x80, 0x86, SS_RDEF,
+ "IOEDC Error on Read") },
+ { SST(0x80, 0x87, SS_RDEF,
+ "IOEDC Error on Write") },
+ { SST(0x80, 0x88, SS_RDEF,
+ "Host Parity Check Failed") },
+ { SST(0x80, 0x89, SS_RDEF,
+ "IOEDC error on read detected by formatter") },
+ { SST(0x80, 0x8A, SS_RDEF,
+ "Host Parity Errors / Host FIFO Initialization Failed") },
+ { SST(0x80, 0x8B, SS_RDEF,
+ "Host Parity Errors") },
+ { SST(0x80, 0x8C, SS_RDEF,
+ "Host Parity Errors") },
+ { SST(0x80, 0x8D, SS_RDEF,
+ "Host Parity Errors") },
+ { SST(0x81, 0x00, SS_RDEF,
+ "LA Check Failed") },
+ { SST(0x82, 0x00, SS_RDEF,
+ "Internal client detected insufficient buffer") },
+ { SST(0x84, 0x00, SS_RDEF,
+ "Scheduled Diagnostic And Repair") },
+};
+
static struct scsi_sense_quirk_entry sense_quirk_table[] = {
{
/*
@@ -744,6 +932,26 @@ static struct scsi_sense_quirk_entry sense_quirk_table[] = {
sizeof(sony_mo_entries)/sizeof(struct asc_table_entry),
/*sense key entries*/NULL,
sony_mo_entries
+ },
+ {
+ /*
+ * HGST vendor-specific error codes
+ */
+ {T_DIRECT, SIP_MEDIA_FIXED, "HGST", "*", "*"},
+ /*num_sense_keys*/0,
+ sizeof(hgst_entries)/sizeof(struct asc_table_entry),
+ /*sense key entries*/NULL,
+ hgst_entries
+ },
+ {
+ /*
+ * SEAGATE vendor-specific error codes
+ */
+ {T_DIRECT, SIP_MEDIA_FIXED, "SEAGATE", "*", "*"},
+ /*num_sense_keys*/0,
+ sizeof(seagate_entries)/sizeof(struct asc_table_entry),
+ /*sense key entries*/NULL,
+ seagate_entries
}
};
@@ -868,7 +1076,7 @@ static struct asc_table_entry asc_table[] = {
{ SST(0x03, 0x02, SS_RDEF,
"Excessive write errors") },
/* DTLPWROMAEBKVF */
- { SST(0x04, 0x00, SS_TUR | SSQ_MANY | SSQ_DECREMENT_COUNT | EIO,
+ { SST(0x04, 0x00, SS_RDEF,
"Logical unit not ready, cause not reportable") },
/* DTLPWROMAEBKVF */
{ SST(0x04, 0x01, SS_TUR | SSQ_MANY | SSQ_DECREMENT_COUNT | EBUSY,
@@ -1117,25 +1325,25 @@ static struct asc_table_entry asc_table[] = {
{ SST(0x10, 0x05, SS_RDEF, /* XXX TBD */
"Logical block protection method error") },
/* DT WRO BK */
- { SST(0x11, 0x00, SS_RDEF,
+ { SST(0x11, 0x00, SS_FATAL|EIO,
"Unrecovered read error") },
/* DT WRO BK */
- { SST(0x11, 0x01, SS_RDEF,
+ { SST(0x11, 0x01, SS_FATAL|EIO,
"Read retries exhausted") },
/* DT WRO BK */
- { SST(0x11, 0x02, SS_RDEF,
+ { SST(0x11, 0x02, SS_FATAL|EIO,
"Error too long to correct") },
/* DT W O BK */
- { SST(0x11, 0x03, SS_RDEF,
+ { SST(0x11, 0x03, SS_FATAL|EIO,
"Multiple read errors") },
/* D W O BK */
- { SST(0x11, 0x04, SS_RDEF,
+ { SST(0x11, 0x04, SS_FATAL|EIO,
"Unrecovered read error - auto reallocate failed") },
/* WRO B */
- { SST(0x11, 0x05, SS_RDEF,
+ { SST(0x11, 0x05, SS_FATAL|EIO,
"L-EC uncorrectable error") },
/* WRO B */
- { SST(0x11, 0x06, SS_RDEF,
+ { SST(0x11, 0x06, SS_FATAL|EIO,
"CIRC unrecovered error") },
/* W O B */
{ SST(0x11, 0x07, SS_RDEF,
@@ -1150,10 +1358,10 @@ static struct asc_table_entry asc_table[] = {
{ SST(0x11, 0x0A, SS_RDEF,
"Miscorrected error") },
/* D W O BK */
- { SST(0x11, 0x0B, SS_RDEF,
+ { SST(0x11, 0x0B, SS_FATAL|EIO,
"Unrecovered read error - recommend reassignment") },
/* D W O BK */
- { SST(0x11, 0x0C, SS_RDEF,
+ { SST(0x11, 0x0C, SS_FATAL|EIO,
"Unrecovered read error - recommend rewrite the data") },
/* DT WRO B */
{ SST(0x11, 0x0D, SS_RDEF,
@@ -2968,7 +3176,10 @@ scsi_sense_desc(int sense_key, int asc, int ascq,
&sense_entry,
&asc_entry);
- *sense_key_desc = sense_entry->desc;
+ if (sense_entry != NULL)
+ *sense_key_desc = sense_entry->desc;
+ else
+ *sense_key_desc = "Invalid Sense Key";
if (asc_entry != NULL)
*asc_desc = asc_entry->desc;
@@ -2994,10 +3205,11 @@ scsi_error_action(struct ccb_scsiio *csio, struct scsi_inquiry_data *inq_data,
int error_code, sense_key, asc, ascq;
scsi_sense_action action;
- scsi_extract_sense(&csio->sense_data, &error_code,
- &sense_key, &asc, &ascq);
-
- if (error_code == SSD_DEFERRED_ERROR) {
+ if (!scsi_extract_sense_ccb((union ccb *)csio,
+ &error_code, &sense_key, &asc, &ascq)) {
+ action = SS_RETRY | SSQ_DECREMENT_COUNT | SSQ_PRINT_SENSE | EIO;
+ } else if ((error_code == SSD_DEFERRED_ERROR)
+ || (error_code == SSD_DESC_DEFERRED_ERROR)) {
/*
* XXX dufault@FreeBSD.org
* This error doesn't relate to the command associated
@@ -3035,8 +3247,10 @@ scsi_error_action(struct ccb_scsiio *csio, struct scsi_inquiry_data *inq_data,
if (asc_entry != NULL
&& (asc != 0 || ascq != 0))
action = asc_entry->action;
- else
+ else if (sense_entry != NULL)
action = sense_entry->action;
+ else
+ action = SS_RETRY|SSQ_DECREMENT_COUNT|SSQ_PRINT_SENSE;
if (sense_key == SSD_KEY_RECOVERED_ERROR) {
/*
@@ -3058,10 +3272,15 @@ scsi_error_action(struct ccb_scsiio *csio, struct scsi_inquiry_data *inq_data,
}
}
}
-#ifdef _KERNEL
- if (bootverbose)
- sense_flags |= SF_PRINT_ALWAYS;
-#endif
+ if ((action & SS_MASK) >= SS_START &&
+ (sense_flags & SF_NO_RECOVERY)) {
+ action &= ~SS_MASK;
+ action |= SS_FAIL;
+ } else if ((action & SS_MASK) == SS_RETRY &&
+ (sense_flags & SF_NO_RETRY)) {
+ action &= ~SS_MASK;
+ action |= SS_FAIL;
+ }
if ((sense_flags & SF_PRINT_ALWAYS) != 0)
action |= SSQ_PRINT_SENSE;
else if ((sense_flags & SF_NO_PRINT) != 0)
@@ -3120,7 +3339,7 @@ scsi_cdb_string(u_int8_t *cdb_ptr, char *cdb_string, size_t len)
*cdb_string = '\0';
for (i = 0; i < cdb_len; i++)
snprintf(cdb_string + strlen(cdb_string),
- len - strlen(cdb_string), "%x ", cdb_ptr[i]);
+ len - strlen(cdb_string), "%02hhx ", cdb_ptr[i]);
return(cdb_string);
}
@@ -3222,6 +3441,1348 @@ scsi_command_string(struct cam_device *device, struct ccb_scsiio *csio,
return(0);
}
+/*
+ * Iterate over sense descriptors. Each descriptor is passed into iter_func().
+ * If iter_func() returns 0, list traversal continues. If iter_func()
+ * returns non-zero, list traversal is stopped.
+ */
+void
+scsi_desc_iterate(struct scsi_sense_data_desc *sense, u_int sense_len,
+ int (*iter_func)(struct scsi_sense_data_desc *sense,
+ u_int, struct scsi_sense_desc_header *,
+ void *), void *arg)
+{
+ int cur_pos;
+ int desc_len;
+
+ /*
+ * First make sure the extra length field is present.
+ */
+ if (SSD_DESC_IS_PRESENT(sense, sense_len, extra_len) == 0)
+ return;
+
+ /*
+ * The length of data actually returned may be different than the
+ * extra_len recorded in the sturcture.
+ */
+ desc_len = sense_len -offsetof(struct scsi_sense_data_desc, sense_desc);
+
+ /*
+ * Limit this further by the extra length reported, and the maximum
+ * allowed extra length.
+ */
+ desc_len = MIN(desc_len, MIN(sense->extra_len, SSD_EXTRA_MAX));
+
+ /*
+ * Subtract the size of the header from the descriptor length.
+ * This is to ensure that we have at least the header left, so we
+ * don't have to check that inside the loop. This can wind up
+ * being a negative value.
+ */
+ desc_len -= sizeof(struct scsi_sense_desc_header);
+
+ for (cur_pos = 0; cur_pos < desc_len;) {
+ struct scsi_sense_desc_header *header;
+
+ header = (struct scsi_sense_desc_header *)
+ &sense->sense_desc[cur_pos];
+
+ /*
+ * Check to make sure we have the entire descriptor. We
+ * don't call iter_func() unless we do.
+ *
+ * Note that although cur_pos is at the beginning of the
+ * descriptor, desc_len already has the header length
+ * subtracted. So the comparison of the length in the
+ * header (which does not include the header itself) to
+ * desc_len - cur_pos is correct.
+ */
+ if (header->length > (desc_len - cur_pos))
+ break;
+
+ if (iter_func(sense, sense_len, header, arg) != 0)
+ break;
+
+ cur_pos += sizeof(*header) + header->length;
+ }
+}
+
+struct scsi_find_desc_info {
+ uint8_t desc_type;
+ struct scsi_sense_desc_header *header;
+};
+
+static int
+scsi_find_desc_func(struct scsi_sense_data_desc *sense, u_int sense_len,
+ struct scsi_sense_desc_header *header, void *arg)
+{
+ struct scsi_find_desc_info *desc_info;
+
+ desc_info = (struct scsi_find_desc_info *)arg;
+
+ if (header->desc_type == desc_info->desc_type) {
+ desc_info->header = header;
+
+ /* We found the descriptor, tell the iterator to stop. */
+ return (1);
+ } else
+ return (0);
+}
+
+/*
+ * Given a descriptor type, return a pointer to it if it is in the sense
+ * data and not truncated. Avoiding truncating sense data will simplify
+ * things significantly for the caller.
+ */
+uint8_t *
+scsi_find_desc(struct scsi_sense_data_desc *sense, u_int sense_len,
+ uint8_t desc_type)
+{
+ struct scsi_find_desc_info desc_info;
+
+ desc_info.desc_type = desc_type;
+ desc_info.header = NULL;
+
+ scsi_desc_iterate(sense, sense_len, scsi_find_desc_func, &desc_info);
+
+ return ((uint8_t *)desc_info.header);
+}
+#endif /* __rtems__ */
+
+/*
+ * Fill in SCSI sense data with the specified parameters. This routine can
+ * fill in either fixed or descriptor type sense data.
+ */
+void
+scsi_set_sense_data_va(struct scsi_sense_data *sense_data,
+ scsi_sense_data_type sense_format, int current_error,
+ int sense_key, int asc, int ascq, va_list ap)
+{
+ int descriptor_sense;
+ scsi_sense_elem_type elem_type;
+
+ /*
+ * Determine whether to return fixed or descriptor format sense
+ * data. If the user specifies SSD_TYPE_NONE for some reason,
+ * they'll just get fixed sense data.
+ */
+ if (sense_format == SSD_TYPE_DESC)
+ descriptor_sense = 1;
+ else
+ descriptor_sense = 0;
+
+ /*
+ * Zero the sense data, so that we don't pass back any garbage data
+ * to the user.
+ */
+ memset(sense_data, 0, sizeof(*sense_data));
+
+ if (descriptor_sense != 0) {
+ struct scsi_sense_data_desc *sense;
+
+ sense = (struct scsi_sense_data_desc *)sense_data;
+ /*
+ * The descriptor sense format eliminates the use of the
+ * valid bit.
+ */
+ if (current_error != 0)
+ sense->error_code = SSD_DESC_CURRENT_ERROR;
+ else
+ sense->error_code = SSD_DESC_DEFERRED_ERROR;
+ sense->sense_key = sense_key;
+ sense->add_sense_code = asc;
+ sense->add_sense_code_qual = ascq;
+ /*
+ * Start off with no extra length, since the above data
+ * fits in the standard descriptor sense information.
+ */
+ sense->extra_len = 0;
+ while ((elem_type = (scsi_sense_elem_type)va_arg(ap,
+ scsi_sense_elem_type)) != SSD_ELEM_NONE) {
+ int sense_len, len_to_copy;
+ uint8_t *data;
+
+ if (elem_type >= SSD_ELEM_MAX) {
+ printf("%s: invalid sense type %d\n", __func__,
+ elem_type);
+ break;
+ }
+
+ 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 *);
+
+ /*
+ * We've already consumed the arguments for this one.
+ */
+ if (elem_type == SSD_ELEM_SKIP)
+ continue;
+
+ switch (elem_type) {
+ case SSD_ELEM_DESC: {
+
+ /*
+ * This is a straight descriptor. All we
+ * need to do is copy the data in.
+ */
+ bcopy(data, &sense->sense_desc[
+ sense->extra_len], len_to_copy);
+ sense->extra_len += len_to_copy;
+ break;
+ }
+ case SSD_ELEM_SKS: {
+ struct scsi_sense_sks sks;
+
+ bzero(&sks, sizeof(sks));
+
+ /*
+ * This is already-formatted sense key
+ * specific data. We just need to fill out
+ * the header and copy everything in.
+ */
+ bcopy(data, &sks.sense_key_spec,
+ MIN(len_to_copy,
+ sizeof(sks.sense_key_spec)));
+
+ sks.desc_type = SSD_DESC_SKS;
+ sks.length = sizeof(sks) -
+ offsetof(struct scsi_sense_sks, reserved1);
+ bcopy(&sks,&sense->sense_desc[sense->extra_len],
+ sizeof(sks));
+ sense->extra_len += sizeof(sks);
+ break;
+ }
+ case SSD_ELEM_INFO:
+ case SSD_ELEM_COMMAND: {
+ struct scsi_sense_command cmd;
+ struct scsi_sense_info info;
+ uint8_t *data_dest;
+ uint8_t *descriptor;
+ int descriptor_size, i, copy_len;
+
+ bzero(&cmd, sizeof(cmd));
+ bzero(&info, sizeof(info));
+
+ /*
+ * Command or information data. The
+ * operate in pretty much the same way.
+ */
+ if (elem_type == SSD_ELEM_COMMAND) {
+ len_to_copy = MIN(len_to_copy,
+ sizeof(cmd.command_info));
+ descriptor = (uint8_t *)&cmd;
+ descriptor_size = sizeof(cmd);
+ data_dest =(uint8_t *)&cmd.command_info;
+ cmd.desc_type = SSD_DESC_COMMAND;
+ cmd.length = sizeof(cmd) -
+ offsetof(struct scsi_sense_command,
+ reserved);
+ } else {
+ len_to_copy = MIN(len_to_copy,
+ sizeof(info.info));
+ descriptor = (uint8_t *)&info;
+ descriptor_size = sizeof(cmd);
+ data_dest = (uint8_t *)&info.info;
+ info.desc_type = SSD_DESC_INFO;
+ info.byte2 = SSD_INFO_VALID;
+ info.length = sizeof(info) -
+ offsetof(struct scsi_sense_info,
+ byte2);
+ }
+
+ /*
+ * Copy this in reverse because the spec
+ * (SPC-4) says that when 4 byte quantities
+ * are stored in this 8 byte field, the
+ * first four bytes shall be 0.
+ *
+ * So we fill the bytes in from the end, and
+ * if we have less than 8 bytes to copy,
+ * the initial, most significant bytes will
+ * be 0.
+ */
+ for (i = sense_len - 1; i >= 0 &&
+ len_to_copy > 0; i--, len_to_copy--)
+ data_dest[len_to_copy - 1] = data[i];
+
+ /*
+ * This calculation looks much like the
+ * initial len_to_copy calculation, but
+ * we have to do it again here, because
+ * we're looking at a larger amount that
+ * may or may not fit. It's not only the
+ * data the user passed in, but also the
+ * rest of the descriptor.
+ */
+ copy_len = MIN(descriptor_size,
+ SSD_EXTRA_MAX - sense->extra_len);
+ bcopy(descriptor, &sense->sense_desc[
+ sense->extra_len], copy_len);
+ sense->extra_len += copy_len;
+ break;
+ }
+ case SSD_ELEM_FRU: {
+ struct scsi_sense_fru fru;
+ int copy_len;
+
+ bzero(&fru, sizeof(fru));
+
+ fru.desc_type = SSD_DESC_FRU;
+ fru.length = sizeof(fru) -
+ offsetof(struct scsi_sense_fru, reserved);
+ fru.fru = *data;
+
+ copy_len = MIN(sizeof(fru), SSD_EXTRA_MAX -
+ sense->extra_len);
+ bcopy(&fru, &sense->sense_desc[
+ sense->extra_len], copy_len);
+ sense->extra_len += copy_len;
+ break;
+ }
+ case SSD_ELEM_STREAM: {
+ struct scsi_sense_stream stream_sense;
+ int copy_len;
+
+ bzero(&stream_sense, sizeof(stream_sense));
+ stream_sense.desc_type = SSD_DESC_STREAM;
+ stream_sense.length = sizeof(stream_sense) -
+ offsetof(struct scsi_sense_stream, reserved);
+ stream_sense.byte3 = *data;
+
+ copy_len = MIN(sizeof(stream_sense),
+ SSD_EXTRA_MAX - sense->extra_len);
+ bcopy(&stream_sense, &sense->sense_desc[
+ sense->extra_len], copy_len);
+ sense->extra_len += copy_len;
+ break;
+ }
+ default:
+ /*
+ * We shouldn't get here, but if we do, do
+ * nothing. We've already consumed the
+ * arguments above.
+ */
+ break;
+ }
+ }
+ } else {
+ struct scsi_sense_data_fixed *sense;
+
+ sense = (struct scsi_sense_data_fixed *)sense_data;
+
+ if (current_error != 0)
+ sense->error_code = SSD_CURRENT_ERROR;
+ else
+ sense->error_code = SSD_DEFERRED_ERROR;
+
+ sense->flags = sense_key;
+ sense->add_sense_code = asc;
+ sense->add_sense_code_qual = ascq;
+ /*
+ * We've set the ASC and ASCQ, so we have 6 more bytes of
+ * valid data. If we wind up setting any of the other
+ * fields, we'll bump this to 10 extra bytes.
+ */
+ sense->extra_len = 6;
+
+ while ((elem_type = (scsi_sense_elem_type)va_arg(ap,
+ scsi_sense_elem_type)) != SSD_ELEM_NONE) {
+ int sense_len, len_to_copy;
+ uint8_t *data;
+
+ if (elem_type >= SSD_ELEM_MAX) {
+ printf("%s: invalid sense type %d\n", __func__,
+ elem_type);
+ break;
+ }
+ /*
+ * If we get in here, just bump the extra length to
+ * 10 bytes. That will encompass anything we're
+ * going to set here.
+ */
+ 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) {
+ case SSD_ELEM_SKS:
+ /*
+ * The user passed in pre-formatted sense
+ * key specific data.
+ */
+ bcopy(data, &sense->sense_key_spec[0],
+ MIN(sizeof(sense->sense_key_spec),
+ sense_len));
+ break;
+ case SSD_ELEM_INFO:
+ case SSD_ELEM_COMMAND: {
+ uint8_t *data_dest;
+ int i;
+
+ if (elem_type == SSD_ELEM_COMMAND)
+ data_dest = &sense->cmd_spec_info[0];
+ else {
+ data_dest = &sense->info[0];
+ /*
+ * We're setting the info field, so
+ * set the valid bit.
+ */
+ sense->error_code |= SSD_ERRCODE_VALID;
+ }
+
+ /*
+ * Copy this in reverse so that if we have
+ * less than 4 bytes to fill, the least
+ * significant bytes will be at the end.
+ * If we have more than 4 bytes, only the
+ * least significant bytes will be included.
+ */
+ for (i = sense_len - 1; i >= 0 &&
+ len_to_copy > 0; i--, len_to_copy--)
+ data_dest[len_to_copy - 1] = data[i];
+
+ break;
+ }
+ case SSD_ELEM_FRU:
+ sense->fru = *data;
+ break;
+ case SSD_ELEM_STREAM:
+ sense->flags |= *data;
+ break;
+ case SSD_ELEM_DESC:
+ default:
+
+ /*
+ * If the user passes in descriptor sense,
+ * we can't handle that in fixed format.
+ * So just skip it, and any unknown argument
+ * types.
+ */
+ break;
+ }
+ }
+ }
+}
+
+void
+scsi_set_sense_data(struct scsi_sense_data *sense_data,
+ scsi_sense_data_type sense_format, int current_error,
+ int sense_key, int asc, int ascq, ...)
+{
+ va_list ap;
+
+ va_start(ap, ascq);
+ scsi_set_sense_data_va(sense_data, sense_format, current_error,
+ sense_key, asc, ascq, ap);
+ va_end(ap);
+}
+
+#ifndef __rtems__
+/*
+ * Get sense information for three similar sense data types.
+ */
+int
+scsi_get_sense_info(struct scsi_sense_data *sense_data, u_int sense_len,
+ uint8_t info_type, uint64_t *info, int64_t *signed_info)
+{
+ scsi_sense_data_type sense_type;
+
+ if (sense_len == 0)
+ goto bailout;
+
+ sense_type = scsi_sense_type(sense_data);
+
+ switch (sense_type) {
+ case SSD_TYPE_DESC: {
+ struct scsi_sense_data_desc *sense;
+ uint8_t *desc;
+
+ sense = (struct scsi_sense_data_desc *)sense_data;
+
+ desc = scsi_find_desc(sense, sense_len, info_type);
+ if (desc == NULL)
+ goto bailout;
+
+ switch (info_type) {
+ case SSD_DESC_INFO: {
+ struct scsi_sense_info *info_desc;
+
+ info_desc = (struct scsi_sense_info *)desc;
+ *info = scsi_8btou64(info_desc->info);
+ if (signed_info != NULL)
+ *signed_info = *info;
+ break;
+ }
+ case SSD_DESC_COMMAND: {
+ struct scsi_sense_command *cmd_desc;
+
+ cmd_desc = (struct scsi_sense_command *)desc;
+
+ *info = scsi_8btou64(cmd_desc->command_info);
+ if (signed_info != NULL)
+ *signed_info = *info;
+ break;
+ }
+ case SSD_DESC_FRU: {
+ struct scsi_sense_fru *fru_desc;
+
+ fru_desc = (struct scsi_sense_fru *)desc;
+
+ *info = fru_desc->fru;
+ if (signed_info != NULL)
+ *signed_info = (int8_t)fru_desc->fru;
+ break;
+ }
+ default:
+ goto bailout;
+ break;
+ }
+ break;
+ }
+ case SSD_TYPE_FIXED: {
+ struct scsi_sense_data_fixed *sense;
+
+ sense = (struct scsi_sense_data_fixed *)sense_data;
+
+ switch (info_type) {
+ case SSD_DESC_INFO: {
+ uint32_t info_val;
+
+ if ((sense->error_code & SSD_ERRCODE_VALID) == 0)
+ goto bailout;
+
+ if (SSD_FIXED_IS_PRESENT(sense, sense_len, info) == 0)
+ goto bailout;
+
+ info_val = scsi_4btoul(sense->info);
+
+ *info = info_val;
+ if (signed_info != NULL)
+ *signed_info = (int32_t)info_val;
+ break;
+ }
+ case SSD_DESC_COMMAND: {
+ uint32_t cmd_val;
+
+ if ((SSD_FIXED_IS_PRESENT(sense, sense_len,
+ cmd_spec_info) == 0)
+ || (SSD_FIXED_IS_FILLED(sense, cmd_spec_info) == 0))
+ goto bailout;
+
+ cmd_val = scsi_4btoul(sense->cmd_spec_info);
+ if (cmd_val == 0)
+ goto bailout;
+
+ *info = cmd_val;
+ if (signed_info != NULL)
+ *signed_info = (int32_t)cmd_val;
+ break;
+ }
+ case SSD_DESC_FRU:
+ if ((SSD_FIXED_IS_PRESENT(sense, sense_len, fru) == 0)
+ || (SSD_FIXED_IS_FILLED(sense, fru) == 0))
+ goto bailout;
+
+ if (sense->fru == 0)
+ goto bailout;
+
+ *info = sense->fru;
+ if (signed_info != NULL)
+ *signed_info = (int8_t)sense->fru;
+ break;
+ default:
+ goto bailout;
+ break;
+ }
+ break;
+ }
+ default:
+ goto bailout;
+ break;
+ }
+
+ return (0);
+bailout:
+ return (1);
+}
+
+int
+scsi_get_sks(struct scsi_sense_data *sense_data, u_int sense_len, uint8_t *sks)
+{
+ scsi_sense_data_type sense_type;
+
+ if (sense_len == 0)
+ goto bailout;
+
+ sense_type = scsi_sense_type(sense_data);
+
+ switch (sense_type) {
+ case SSD_TYPE_DESC: {
+ struct scsi_sense_data_desc *sense;
+ struct scsi_sense_sks *desc;
+
+ sense = (struct scsi_sense_data_desc *)sense_data;
+
+ desc = (struct scsi_sense_sks *)scsi_find_desc(sense, sense_len,
+ SSD_DESC_SKS);
+ if (desc == NULL)
+ goto bailout;
+
+ /*
+ * No need to check the SKS valid bit for descriptor sense.
+ * If the descriptor is present, it is valid.
+ */
+ bcopy(desc->sense_key_spec, sks, sizeof(desc->sense_key_spec));
+ break;
+ }
+ case SSD_TYPE_FIXED: {
+ struct scsi_sense_data_fixed *sense;
+
+ sense = (struct scsi_sense_data_fixed *)sense_data;
+
+ if ((SSD_FIXED_IS_PRESENT(sense, sense_len, sense_key_spec)== 0)
+ || (SSD_FIXED_IS_FILLED(sense, sense_key_spec) == 0))
+ goto bailout;
+
+ if ((sense->sense_key_spec[0] & SSD_SCS_VALID) == 0)
+ goto bailout;
+
+ bcopy(sense->sense_key_spec, sks,sizeof(sense->sense_key_spec));
+ break;
+ }
+ default:
+ goto bailout;
+ break;
+ }
+ return (0);
+bailout:
+ return (1);
+}
+
+/*
+ * Provide a common interface for fixed and descriptor sense to detect
+ * whether we have block-specific sense information. It is clear by the
+ * presence of the block descriptor in descriptor mode, but we have to
+ * infer from the inquiry data and ILI bit in fixed mode.
+ */
+int
+scsi_get_block_info(struct scsi_sense_data *sense_data, u_int sense_len,
+ struct scsi_inquiry_data *inq_data, uint8_t *block_bits)
+{
+ scsi_sense_data_type sense_type;
+
+ if (inq_data != NULL) {
+ switch (SID_TYPE(inq_data)) {
+ case T_DIRECT:
+ case T_RBC:
+ break;
+ default:
+ goto bailout;
+ break;
+ }
+ }
+
+ sense_type = scsi_sense_type(sense_data);
+
+ switch (sense_type) {
+ case SSD_TYPE_DESC: {
+ struct scsi_sense_data_desc *sense;
+ struct scsi_sense_block *block;
+
+ sense = (struct scsi_sense_data_desc *)sense_data;
+
+ block = (struct scsi_sense_block *)scsi_find_desc(sense,
+ sense_len, SSD_DESC_BLOCK);
+ if (block == NULL)
+ goto bailout;
+
+ *block_bits = block->byte3;
+ break;
+ }
+ case SSD_TYPE_FIXED: {
+ struct scsi_sense_data_fixed *sense;
+
+ sense = (struct scsi_sense_data_fixed *)sense_data;
+
+ if (SSD_FIXED_IS_PRESENT(sense, sense_len, flags) == 0)
+ goto bailout;
+
+ if ((sense->flags & SSD_ILI) == 0)
+ goto bailout;
+
+ *block_bits = sense->flags & SSD_ILI;
+ break;
+ }
+ default:
+ goto bailout;
+ break;
+ }
+ return (0);
+bailout:
+ return (1);
+}
+
+int
+scsi_get_stream_info(struct scsi_sense_data *sense_data, u_int sense_len,
+ struct scsi_inquiry_data *inq_data, uint8_t *stream_bits)
+{
+ scsi_sense_data_type sense_type;
+
+ if (inq_data != NULL) {
+ switch (SID_TYPE(inq_data)) {
+ case T_SEQUENTIAL:
+ break;
+ default:
+ goto bailout;
+ break;
+ }
+ }
+
+ sense_type = scsi_sense_type(sense_data);
+
+ switch (sense_type) {
+ case SSD_TYPE_DESC: {
+ struct scsi_sense_data_desc *sense;
+ struct scsi_sense_stream *stream;
+
+ sense = (struct scsi_sense_data_desc *)sense_data;
+
+ stream = (struct scsi_sense_stream *)scsi_find_desc(sense,
+ sense_len, SSD_DESC_STREAM);
+ if (stream == NULL)
+ goto bailout;
+
+ *stream_bits = stream->byte3;
+ break;
+ }
+ case SSD_TYPE_FIXED: {
+ struct scsi_sense_data_fixed *sense;
+
+ sense = (struct scsi_sense_data_fixed *)sense_data;
+
+ if (SSD_FIXED_IS_PRESENT(sense, sense_len, flags) == 0)
+ goto bailout;
+
+ if ((sense->flags & (SSD_ILI|SSD_EOM|SSD_FILEMARK)) == 0)
+ goto bailout;
+
+ *stream_bits = sense->flags & (SSD_ILI|SSD_EOM|SSD_FILEMARK);
+ break;
+ }
+ default:
+ goto bailout;
+ break;
+ }
+ return (0);
+bailout:
+ return (1);
+}
+
+void
+scsi_info_sbuf(struct sbuf *sb, uint8_t *cdb, int cdb_len,
+ struct scsi_inquiry_data *inq_data, uint64_t info)
+{
+ sbuf_printf(sb, "Info: %#jx", info);
+}
+
+void
+scsi_command_sbuf(struct sbuf *sb, uint8_t *cdb, int cdb_len,
+ struct scsi_inquiry_data *inq_data, uint64_t csi)
+{
+ sbuf_printf(sb, "Command Specific Info: %#jx", csi);
+}
+
+
+void
+scsi_progress_sbuf(struct sbuf *sb, uint16_t progress)
+{
+ sbuf_printf(sb, "Progress: %d%% (%d/%d) complete",
+ (progress * 100) / SSD_SKS_PROGRESS_DENOM,
+ progress, SSD_SKS_PROGRESS_DENOM);
+}
+
+/*
+ * Returns 1 for failure (i.e. SKS isn't valid) and 0 for success.
+ */
+int
+scsi_sks_sbuf(struct sbuf *sb, int sense_key, uint8_t *sks)
+{
+ if ((sks[0] & SSD_SKS_VALID) == 0)
+ return (1);
+
+ switch (sense_key) {
+ case SSD_KEY_ILLEGAL_REQUEST: {
+ struct scsi_sense_sks_field *field;
+ int bad_command;
+ char tmpstr[40];
+
+ /*Field Pointer*/
+ field = (struct scsi_sense_sks_field *)sks;
+
+ if (field->byte0 & SSD_SKS_FIELD_CMD)
+ bad_command = 1;
+ else
+ bad_command = 0;
+
+ tmpstr[0] = '\0';
+
+ /* Bit pointer is valid */
+ if (field->byte0 & SSD_SKS_BPV)
+ snprintf(tmpstr, sizeof(tmpstr), "bit %d ",
+ field->byte0 & SSD_SKS_BIT_VALUE);
+
+ sbuf_printf(sb, "%s byte %d %sis invalid",
+ bad_command ? "Command" : "Data",
+ scsi_2btoul(field->field), tmpstr);
+ break;
+ }
+ case SSD_KEY_UNIT_ATTENTION: {
+ struct scsi_sense_sks_overflow *overflow;
+
+ overflow = (struct scsi_sense_sks_overflow *)sks;
+
+ /*UA Condition Queue Overflow*/
+ sbuf_printf(sb, "Unit Attention Condition Queue %s",
+ (overflow->byte0 & SSD_SKS_OVERFLOW_SET) ?
+ "Overflowed" : "Did Not Overflow??");
+ break;
+ }
+ case SSD_KEY_RECOVERED_ERROR:
+ case SSD_KEY_HARDWARE_ERROR:
+ case SSD_KEY_MEDIUM_ERROR: {
+ struct scsi_sense_sks_retry *retry;
+
+ /*Actual Retry Count*/
+ retry = (struct scsi_sense_sks_retry *)sks;
+
+ sbuf_printf(sb, "Actual Retry Count: %d",
+ scsi_2btoul(retry->actual_retry_count));
+ break;
+ }
+ case SSD_KEY_NO_SENSE:
+ case SSD_KEY_NOT_READY: {
+ struct scsi_sense_sks_progress *progress;
+ int progress_val;
+
+ /*Progress Indication*/
+ progress = (struct scsi_sense_sks_progress *)sks;
+ progress_val = scsi_2btoul(progress->progress);
+
+ scsi_progress_sbuf(sb, progress_val);
+ break;
+ }
+ case SSD_KEY_COPY_ABORTED: {
+ struct scsi_sense_sks_segment *segment;
+ char tmpstr[40];
+
+ /*Segment Pointer*/
+ segment = (struct scsi_sense_sks_segment *)sks;
+
+ tmpstr[0] = '\0';
+
+ if (segment->byte0 & SSD_SKS_SEGMENT_BPV)
+ snprintf(tmpstr, sizeof(tmpstr), "bit %d ",
+ segment->byte0 & SSD_SKS_SEGMENT_BITPTR);
+
+ sbuf_printf(sb, "%s byte %d %sis invalid", (segment->byte0 &
+ SSD_SKS_SEGMENT_SD) ? "Segment" : "Data",
+ scsi_2btoul(segment->field), tmpstr);
+ break;
+ }
+ default:
+ sbuf_printf(sb, "Sense Key Specific: %#x,%#x", sks[0],
+ scsi_2btoul(&sks[1]));
+ break;
+ }
+
+ return (0);
+}
+
+void
+scsi_fru_sbuf(struct sbuf *sb, uint64_t fru)
+{
+ sbuf_printf(sb, "Field Replaceable Unit: %d", (int)fru);
+}
+
+void
+scsi_stream_sbuf(struct sbuf *sb, uint8_t stream_bits, uint64_t info)
+{
+ int need_comma;
+
+ need_comma = 0;
+ /*
+ * XXX KDM this needs more descriptive decoding.
+ */
+ if (stream_bits & SSD_DESC_STREAM_FM) {
+ sbuf_printf(sb, "Filemark");
+ need_comma = 1;
+ }
+
+ if (stream_bits & SSD_DESC_STREAM_EOM) {
+ sbuf_printf(sb, "%sEOM", (need_comma) ? "," : "");
+ need_comma = 1;
+ }
+
+ if (stream_bits & SSD_DESC_STREAM_ILI)
+ sbuf_printf(sb, "%sILI", (need_comma) ? "," : "");
+
+ sbuf_printf(sb, ": Info: %#jx", (uintmax_t) info);
+}
+
+void
+scsi_block_sbuf(struct sbuf *sb, uint8_t block_bits, uint64_t info)
+{
+ if (block_bits & SSD_DESC_BLOCK_ILI)
+ sbuf_printf(sb, "ILI: residue %#jx", (uintmax_t) info);
+}
+
+void
+scsi_sense_info_sbuf(struct sbuf *sb, struct scsi_sense_data *sense,
+ u_int sense_len, uint8_t *cdb, int cdb_len,
+ struct scsi_inquiry_data *inq_data,
+ struct scsi_sense_desc_header *header)
+{
+ struct scsi_sense_info *info;
+
+ info = (struct scsi_sense_info *)header;
+
+ scsi_info_sbuf(sb, cdb, cdb_len, inq_data, scsi_8btou64(info->info));
+}
+
+void
+scsi_sense_command_sbuf(struct sbuf *sb, struct scsi_sense_data *sense,
+ u_int sense_len, uint8_t *cdb, int cdb_len,
+ struct scsi_inquiry_data *inq_data,
+ struct scsi_sense_desc_header *header)
+{
+ struct scsi_sense_command *command;
+
+ command = (struct scsi_sense_command *)header;
+
+ scsi_command_sbuf(sb, cdb, cdb_len, inq_data,
+ scsi_8btou64(command->command_info));
+}
+
+void
+scsi_sense_sks_sbuf(struct sbuf *sb, struct scsi_sense_data *sense,
+ u_int sense_len, uint8_t *cdb, int cdb_len,
+ struct scsi_inquiry_data *inq_data,
+ struct scsi_sense_desc_header *header)
+{
+ struct scsi_sense_sks *sks;
+ int error_code, sense_key, asc, ascq;
+
+ sks = (struct scsi_sense_sks *)header;
+
+ scsi_extract_sense_len(sense, sense_len, &error_code, &sense_key,
+ &asc, &ascq, /*show_errors*/ 1);
+
+ scsi_sks_sbuf(sb, sense_key, sks->sense_key_spec);
+}
+
+void
+scsi_sense_fru_sbuf(struct sbuf *sb, struct scsi_sense_data *sense,
+ u_int sense_len, uint8_t *cdb, int cdb_len,
+ struct scsi_inquiry_data *inq_data,
+ struct scsi_sense_desc_header *header)
+{
+ struct scsi_sense_fru *fru;
+
+ fru = (struct scsi_sense_fru *)header;
+
+ scsi_fru_sbuf(sb, (uint64_t)fru->fru);
+}
+
+void
+scsi_sense_stream_sbuf(struct sbuf *sb, struct scsi_sense_data *sense,
+ u_int sense_len, uint8_t *cdb, int cdb_len,
+ struct scsi_inquiry_data *inq_data,
+ struct scsi_sense_desc_header *header)
+{
+ struct scsi_sense_stream *stream;
+ uint64_t info;
+
+ stream = (struct scsi_sense_stream *)header;
+ info = 0;
+
+ scsi_get_sense_info(sense, sense_len, SSD_DESC_INFO, &info, NULL);
+
+ scsi_stream_sbuf(sb, stream->byte3, info);
+}
+
+void
+scsi_sense_block_sbuf(struct sbuf *sb, struct scsi_sense_data *sense,
+ u_int sense_len, uint8_t *cdb, int cdb_len,
+ struct scsi_inquiry_data *inq_data,
+ struct scsi_sense_desc_header *header)
+{
+ struct scsi_sense_block *block;
+ uint64_t info;
+
+ block = (struct scsi_sense_block *)header;
+ info = 0;
+
+ scsi_get_sense_info(sense, sense_len, SSD_DESC_INFO, &info, NULL);
+
+ scsi_block_sbuf(sb, block->byte3, info);
+}
+
+void
+scsi_sense_progress_sbuf(struct sbuf *sb, struct scsi_sense_data *sense,
+ u_int sense_len, uint8_t *cdb, int cdb_len,
+ struct scsi_inquiry_data *inq_data,
+ struct scsi_sense_desc_header *header)
+{
+ struct scsi_sense_progress *progress;
+ const char *sense_key_desc;
+ const char *asc_desc;
+ int progress_val;
+
+ progress = (struct scsi_sense_progress *)header;
+
+ /*
+ * Get descriptions for the sense key, ASC, and ASCQ in the
+ * progress descriptor. These could be different than the values
+ * in the overall sense data.
+ */
+ scsi_sense_desc(progress->sense_key, progress->add_sense_code,
+ progress->add_sense_code_qual, inq_data,
+ &sense_key_desc, &asc_desc);
+
+ progress_val = scsi_2btoul(progress->progress);
+
+ /*
+ * The progress indicator is for the operation described by the
+ * sense key, ASC, and ASCQ in the descriptor.
+ */
+ sbuf_cat(sb, sense_key_desc);
+ sbuf_printf(sb, " asc:%x,%x (%s): ", progress->add_sense_code,
+ progress->add_sense_code_qual, asc_desc);
+ scsi_progress_sbuf(sb, progress_val);
+}
+
+/*
+ * Generic sense descriptor printing routine. This is used when we have
+ * not yet implemented a specific printing routine for this descriptor.
+ */
+void
+scsi_sense_generic_sbuf(struct sbuf *sb, struct scsi_sense_data *sense,
+ u_int sense_len, uint8_t *cdb, int cdb_len,
+ struct scsi_inquiry_data *inq_data,
+ struct scsi_sense_desc_header *header)
+{
+ int i;
+ uint8_t *buf_ptr;
+
+ sbuf_printf(sb, "Descriptor %#x:", header->desc_type);
+
+ buf_ptr = (uint8_t *)&header[1];
+
+ for (i = 0; i < header->length; i++, buf_ptr++)
+ sbuf_printf(sb, " %02x", *buf_ptr);
+}
+
+/*
+ * Keep this list in numeric order. This speeds the array traversal.
+ */
+struct scsi_sense_desc_printer {
+ uint8_t desc_type;
+ /*
+ * The function arguments here are the superset of what is needed
+ * to print out various different descriptors. Command and
+ * information descriptors need inquiry data and command type.
+ * Sense key specific descriptors need the sense key.
+ *
+ * The sense, cdb, and inquiry data arguments may be NULL, but the
+ * information printed may not be fully decoded as a result.
+ */
+ void (*print_func)(struct sbuf *sb, struct scsi_sense_data *sense,
+ u_int sense_len, uint8_t *cdb, int cdb_len,
+ struct scsi_inquiry_data *inq_data,
+ struct scsi_sense_desc_header *header);
+} scsi_sense_printers[] = {
+ {SSD_DESC_INFO, scsi_sense_info_sbuf},
+ {SSD_DESC_COMMAND, scsi_sense_command_sbuf},
+ {SSD_DESC_SKS, scsi_sense_sks_sbuf},
+ {SSD_DESC_FRU, scsi_sense_fru_sbuf},
+ {SSD_DESC_STREAM, scsi_sense_stream_sbuf},
+ {SSD_DESC_BLOCK, scsi_sense_block_sbuf},
+ {SSD_DESC_PROGRESS, scsi_sense_progress_sbuf}
+};
+
+void
+scsi_sense_desc_sbuf(struct sbuf *sb, struct scsi_sense_data *sense,
+ u_int sense_len, uint8_t *cdb, int cdb_len,
+ struct scsi_inquiry_data *inq_data,
+ struct scsi_sense_desc_header *header)
+{
+ int i;
+
+ for (i = 0; i < (sizeof(scsi_sense_printers) /
+ sizeof(scsi_sense_printers[0])); i++) {
+ struct scsi_sense_desc_printer *printer;
+
+ printer = &scsi_sense_printers[i];
+
+ /*
+ * The list is sorted, so quit if we've passed our
+ * descriptor number.
+ */
+ if (printer->desc_type > header->desc_type)
+ break;
+
+ if (printer->desc_type != header->desc_type)
+ continue;
+
+ printer->print_func(sb, sense, sense_len, cdb, cdb_len,
+ inq_data, header);
+
+ return;
+ }
+
+ /*
+ * No specific printing routine, so use the generic routine.
+ */
+ scsi_sense_generic_sbuf(sb, sense, sense_len, cdb, cdb_len,
+ inq_data, header);
+}
+
+scsi_sense_data_type
+scsi_sense_type(struct scsi_sense_data *sense_data)
+{
+ switch (sense_data->error_code & SSD_ERRCODE) {
+ case SSD_DESC_CURRENT_ERROR:
+ case SSD_DESC_DEFERRED_ERROR:
+ return (SSD_TYPE_DESC);
+ break;
+ case SSD_CURRENT_ERROR:
+ case SSD_DEFERRED_ERROR:
+ return (SSD_TYPE_FIXED);
+ break;
+ default:
+ break;
+ }
+
+ return (SSD_TYPE_NONE);
+}
+
+struct scsi_print_sense_info {
+ struct sbuf *sb;
+ char *path_str;
+ uint8_t *cdb;
+ int cdb_len;
+ struct scsi_inquiry_data *inq_data;
+};
+
+static int
+scsi_print_desc_func(struct scsi_sense_data_desc *sense, u_int sense_len,
+ struct scsi_sense_desc_header *header, void *arg)
+{
+ struct scsi_print_sense_info *print_info;
+
+ print_info = (struct scsi_print_sense_info *)arg;
+
+ switch (header->desc_type) {
+ case SSD_DESC_INFO:
+ case SSD_DESC_FRU:
+ case SSD_DESC_COMMAND:
+ case SSD_DESC_SKS:
+ case SSD_DESC_BLOCK:
+ case SSD_DESC_STREAM:
+ /*
+ * We have already printed these descriptors, if they are
+ * present.
+ */
+ break;
+ default: {
+ sbuf_printf(print_info->sb, "%s", print_info->path_str);
+ scsi_sense_desc_sbuf(print_info->sb,
+ (struct scsi_sense_data *)sense, sense_len,
+ print_info->cdb, print_info->cdb_len,
+ print_info->inq_data, header);
+ sbuf_printf(print_info->sb, "\n");
+ break;
+ }
+ }
+
+ /*
+ * Tell the iterator that we want to see more descriptors if they
+ * are present.
+ */
+ return (0);
+}
+
+void
+scsi_sense_only_sbuf(struct scsi_sense_data *sense, u_int sense_len,
+ struct sbuf *sb, char *path_str,
+ struct scsi_inquiry_data *inq_data, uint8_t *cdb,
+ int cdb_len)
+{
+ int error_code, sense_key, asc, ascq;
+
+ sbuf_cat(sb, path_str);
+
+ scsi_extract_sense_len(sense, sense_len, &error_code, &sense_key,
+ &asc, &ascq, /*show_errors*/ 1);
+
+ sbuf_printf(sb, "SCSI sense: ");
+ switch (error_code) {
+ case SSD_DEFERRED_ERROR:
+ case SSD_DESC_DEFERRED_ERROR:
+ sbuf_printf(sb, "Deferred error: ");
+
+ /* FALLTHROUGH */
+ case SSD_CURRENT_ERROR:
+ case SSD_DESC_CURRENT_ERROR:
+ {
+ struct scsi_sense_data_desc *desc_sense;
+ struct scsi_print_sense_info print_info;
+ const char *sense_key_desc;
+ const char *asc_desc;
+ uint8_t sks[3];
+ uint64_t val;
+ int info_valid;
+
+ /*
+ * Get descriptions for the sense key, ASC, and ASCQ. If
+ * these aren't present in the sense data (i.e. the sense
+ * data isn't long enough), the -1 values that
+ * scsi_extract_sense_len() returns will yield default
+ * or error descriptions.
+ */
+ scsi_sense_desc(sense_key, asc, ascq, inq_data,
+ &sense_key_desc, &asc_desc);
+
+ /*
+ * We first print the sense key and ASC/ASCQ.
+ */
+ sbuf_cat(sb, sense_key_desc);
+ sbuf_printf(sb, " asc:%x,%x (%s)\n", asc, ascq, asc_desc);
+
+ /*
+ * Get the info field if it is valid.
+ */
+ if (scsi_get_sense_info(sense, sense_len, SSD_DESC_INFO,
+ &val, NULL) == 0)
+ info_valid = 1;
+ else
+ info_valid = 0;
+
+ if (info_valid != 0) {
+ uint8_t bits;
+
+ /*
+ * Determine whether we have any block or stream
+ * device-specific information.
+ */
+ if (scsi_get_block_info(sense, sense_len, inq_data,
+ &bits) == 0) {
+ sbuf_cat(sb, path_str);
+ scsi_block_sbuf(sb, bits, val);
+ sbuf_printf(sb, "\n");
+ } else if (scsi_get_stream_info(sense, sense_len,
+ inq_data, &bits) == 0) {
+ sbuf_cat(sb, path_str);
+ scsi_stream_sbuf(sb, bits, val);
+ sbuf_printf(sb, "\n");
+ } else if (val != 0) {
+ /*
+ * The information field can be valid but 0.
+ * If the block or stream bits aren't set,
+ * and this is 0, it isn't terribly useful
+ * to print it out.
+ */
+ sbuf_cat(sb, path_str);
+ scsi_info_sbuf(sb, cdb, cdb_len, inq_data, val);
+ sbuf_printf(sb, "\n");
+ }
+ }
+
+ /*
+ * Print the FRU.
+ */
+ if (scsi_get_sense_info(sense, sense_len, SSD_DESC_FRU,
+ &val, NULL) == 0) {
+ sbuf_cat(sb, path_str);
+ scsi_fru_sbuf(sb, val);
+ sbuf_printf(sb, "\n");
+ }
+
+ /*
+ * Print any command-specific information.
+ */
+ if (scsi_get_sense_info(sense, sense_len, SSD_DESC_COMMAND,
+ &val, NULL) == 0) {
+ sbuf_cat(sb, path_str);
+ scsi_command_sbuf(sb, cdb, cdb_len, inq_data, val);
+ sbuf_printf(sb, "\n");
+ }
+
+ /*
+ * Print out any sense-key-specific information.
+ */
+ if (scsi_get_sks(sense, sense_len, sks) == 0) {
+ sbuf_cat(sb, path_str);
+ scsi_sks_sbuf(sb, sense_key, sks);
+ sbuf_printf(sb, "\n");
+ }
+
+ /*
+ * If this is fixed sense, we're done. If we have
+ * descriptor sense, we might have more information
+ * available.
+ */
+ if (scsi_sense_type(sense) != SSD_TYPE_DESC)
+ break;
+
+ desc_sense = (struct scsi_sense_data_desc *)sense;
+
+ print_info.sb = sb;
+ print_info.path_str = path_str;
+ print_info.cdb = cdb;
+ print_info.cdb_len = cdb_len;
+ print_info.inq_data = inq_data;
+
+ /*
+ * Print any sense descriptors that we have not already printed.
+ */
+ scsi_desc_iterate(desc_sense, sense_len, scsi_print_desc_func,
+ &print_info);
+ break;
+
+ }
+ case -1:
+ /*
+ * scsi_extract_sense_len() sets values to -1 if the
+ * show_errors flag is set and they aren't present in the
+ * sense data. This means that sense_len is 0.
+ */
+ sbuf_printf(sb, "No sense data present\n");
+ break;
+ default: {
+ sbuf_printf(sb, "Error code 0x%x", error_code);
+ if (sense->error_code & SSD_ERRCODE_VALID) {
+ struct scsi_sense_data_fixed *fixed_sense;
+
+ fixed_sense = (struct scsi_sense_data_fixed *)sense;
+
+ if (SSD_FIXED_IS_PRESENT(fixed_sense, sense_len, info)){
+ uint32_t info;
+
+ info = scsi_4btoul(fixed_sense->info);
+
+ sbuf_printf(sb, " at block no. %d (decimal)",
+ info);
+ }
+ }
+ sbuf_printf(sb, "\n");
+ break;
+ }
+ }
+}
/*
* scsi_sense_sbuf() returns 0 for success and -1 for failure.
@@ -3241,11 +4802,8 @@ scsi_sense_sbuf(struct cam_device *device, struct ccb_scsiio *csio,
#ifdef _KERNEL
struct ccb_getdev *cgd;
#endif /* _KERNEL */
- u_int32_t info;
- int error_code;
- int sense_key;
- int asc, ascq;
char path_str[64];
+ uint8_t *cdb;
#ifndef _KERNEL
if (device == NULL)
@@ -3343,129 +4901,14 @@ scsi_sense_sbuf(struct cam_device *device, struct ccb_scsiio *csio,
sense = &csio->sense_data;
}
+ if (csio->ccb_h.flags & CAM_CDB_POINTER)
+ cdb = csio->cdb_io.cdb_ptr;
+ else
+ cdb = csio->cdb_io.cdb_bytes;
- sbuf_cat(sb, path_str);
-
- error_code = sense->error_code & SSD_ERRCODE;
- sense_key = sense->flags & SSD_KEY;
-
- sbuf_printf(sb, "SCSI sense: ");
- switch (error_code) {
- case SSD_DEFERRED_ERROR:
- sbuf_printf(sb, "Deferred error: ");
-
- /* FALLTHROUGH */
- case SSD_CURRENT_ERROR:
- {
- const char *sense_key_desc;
- const char *asc_desc;
-
- asc = (sense->extra_len >= 5) ? sense->add_sense_code : 0;
- ascq = (sense->extra_len >= 6) ? sense->add_sense_code_qual : 0;
- scsi_sense_desc(sense_key, asc, ascq, inq_data,
- &sense_key_desc, &asc_desc);
- sbuf_cat(sb, sense_key_desc);
-
- info = scsi_4btoul(sense->info);
-
- if (sense->error_code & SSD_ERRCODE_VALID) {
-
- switch (sense_key) {
- case SSD_KEY_NOT_READY:
- case SSD_KEY_ILLEGAL_REQUEST:
- case SSD_KEY_UNIT_ATTENTION:
- case SSD_KEY_DATA_PROTECT:
- break;
- case SSD_KEY_BLANK_CHECK:
- sbuf_printf(sb, " req sz: %d (decimal)", info);
- break;
- default:
- if (info) {
- if (sense->flags & SSD_ILI) {
- sbuf_printf(sb, " ILI (length "
- "mismatch): %d", info);
-
- } else {
- sbuf_printf(sb, " info:%x",
- info);
- }
- }
- }
- } else if (info) {
- sbuf_printf(sb, " info?:%x", info);
- }
-
- if (sense->extra_len >= 4) {
- if (bcmp(sense->cmd_spec_info, "\0\0\0\0", 4)) {
- sbuf_printf(sb, " csi:%x,%x,%x,%x",
- sense->cmd_spec_info[0],
- sense->cmd_spec_info[1],
- sense->cmd_spec_info[2],
- sense->cmd_spec_info[3]);
- }
- }
-
- sbuf_printf(sb, " asc:%x,%x (%s)", asc, ascq, asc_desc);
-
- if (sense->extra_len >= 7 && sense->fru) {
- sbuf_printf(sb, " field replaceable unit: %x",
- sense->fru);
- }
-
- if ((sense->extra_len >= 10)
- && (sense->sense_key_spec[0] & SSD_SCS_VALID) != 0) {
- switch(sense_key) {
- case SSD_KEY_ILLEGAL_REQUEST: {
- int bad_command;
- char tmpstr2[40];
-
- if (sense->sense_key_spec[0] & 0x40)
- bad_command = 1;
- else
- bad_command = 0;
-
- tmpstr2[0] = '\0';
-
- /* Bit pointer is valid */
- if (sense->sense_key_spec[0] & 0x08)
- snprintf(tmpstr2, sizeof(tmpstr2),
- "bit %d ",
- sense->sense_key_spec[0] & 0x7);
- sbuf_printf(sb, ": %s byte %d %sis invalid",
- bad_command ? "Command" : "Data",
- scsi_2btoul(
- &sense->sense_key_spec[1]),
- tmpstr2);
- break;
- }
- case SSD_KEY_RECOVERED_ERROR:
- case SSD_KEY_HARDWARE_ERROR:
- case SSD_KEY_MEDIUM_ERROR:
- sbuf_printf(sb, " actual retry count: %d",
- scsi_2btoul(
- &sense->sense_key_spec[1]));
- break;
- default:
- sbuf_printf(sb, " sks:%#x,%#x",
- sense->sense_key_spec[0],
- scsi_2btoul(
- &sense->sense_key_spec[1]));
- break;
- }
- }
- break;
-
- }
- default:
- sbuf_printf(sb, "Error code 0x%x", sense->error_code);
- if (sense->error_code & SSD_ERRCODE_VALID) {
- sbuf_printf(sb, " at block no. %d (decimal)",
- info = scsi_4btoul(sense->info));
- }
- }
-
- sbuf_printf(sb, "\n");
-
+ scsi_sense_only_sbuf(sense, csio->sense_len - csio->sense_resid, sb,
+ path_str, inq_data, cdb, csio->cdb_len);
+
#ifdef _KERNEL
xpt_free_ccb((union ccb*)cgd);
#endif /* _KERNEL/!_KERNEL */
@@ -3535,6 +4978,167 @@ scsi_sense_print(struct cam_device *device, struct ccb_scsiio *csio,
}
#endif /* _KERNEL/!_KERNEL */
+
+/*
+ * Extract basic sense information. This is backward-compatible with the
+ * previous implementation. For new implementations,
+ * scsi_extract_sense_len() is recommended.
+ */
+void
+scsi_extract_sense(struct scsi_sense_data *sense_data, int *error_code,
+ int *sense_key, int *asc, int *ascq)
+{
+ scsi_extract_sense_len(sense_data, sizeof(*sense_data), error_code,
+ sense_key, asc, ascq, /*show_errors*/ 0);
+}
+
+/*
+ * Extract basic sense information from SCSI I/O CCB structure.
+ */
+int
+scsi_extract_sense_ccb(union ccb *ccb,
+ int *error_code, int *sense_key, int *asc, int *ascq)
+{
+ struct scsi_sense_data *sense_data;
+
+ /* Make sure there are some sense data we can access. */
+ if (ccb->ccb_h.func_code != XPT_SCSI_IO ||
+ (ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_SCSI_STATUS_ERROR ||
+ (ccb->csio.scsi_status != SCSI_STATUS_CHECK_COND) ||
+ (ccb->ccb_h.status & CAM_AUTOSNS_VALID) == 0 ||
+ (ccb->ccb_h.flags & CAM_SENSE_PHYS))
+ return (0);
+
+ if (ccb->ccb_h.flags & CAM_SENSE_PTR)
+ bcopy(&ccb->csio.sense_data, &sense_data,
+ sizeof(struct scsi_sense_data *));
+ else
+ sense_data = &ccb->csio.sense_data;
+ scsi_extract_sense_len(sense_data,
+ ccb->csio.sense_len - ccb->csio.sense_resid,
+ error_code, sense_key, asc, ascq, 1);
+ if (*error_code == -1)
+ return (0);
+ return (1);
+}
+#endif /* __rtems__ */
+
+/*
+ * Extract basic sense information. If show_errors is set, sense values
+ * will be set to -1 if they are not present.
+ */
+void
+scsi_extract_sense_len(struct scsi_sense_data *sense_data, u_int sense_len,
+ int *error_code, int *sense_key, int *asc, int *ascq,
+ int show_errors)
+{
+ /*
+ * If we have no length, we have no sense.
+ */
+ if (sense_len == 0) {
+ if (show_errors == 0) {
+ *error_code = 0;
+ *sense_key = 0;
+ *asc = 0;
+ *ascq = 0;
+ } else {
+ *error_code = -1;
+ *sense_key = -1;
+ *asc = -1;
+ *ascq = -1;
+ }
+ return;
+ }
+
+ *error_code = sense_data->error_code & SSD_ERRCODE;
+
+ switch (*error_code) {
+ case SSD_DESC_CURRENT_ERROR:
+ case SSD_DESC_DEFERRED_ERROR: {
+ struct scsi_sense_data_desc *sense;
+
+ sense = (struct scsi_sense_data_desc *)sense_data;
+
+ if (SSD_DESC_IS_PRESENT(sense, sense_len, sense_key))
+ *sense_key = sense->sense_key & SSD_KEY;
+ else
+ *sense_key = (show_errors) ? -1 : 0;
+
+ if (SSD_DESC_IS_PRESENT(sense, sense_len, add_sense_code))
+ *asc = sense->add_sense_code;
+ else
+ *asc = (show_errors) ? -1 : 0;
+
+ if (SSD_DESC_IS_PRESENT(sense, sense_len, add_sense_code_qual))
+ *ascq = sense->add_sense_code_qual;
+ else
+ *ascq = (show_errors) ? -1 : 0;
+ break;
+ }
+ case SSD_CURRENT_ERROR:
+ case SSD_DEFERRED_ERROR:
+ default: {
+ struct scsi_sense_data_fixed *sense;
+
+ sense = (struct scsi_sense_data_fixed *)sense_data;
+
+ if (SSD_FIXED_IS_PRESENT(sense, sense_len, flags))
+ *sense_key = sense->flags & SSD_KEY;
+ else
+ *sense_key = (show_errors) ? -1 : 0;
+
+ if ((SSD_FIXED_IS_PRESENT(sense, sense_len, add_sense_code))
+ && (SSD_FIXED_IS_FILLED(sense, add_sense_code)))
+ *asc = sense->add_sense_code;
+ else
+ *asc = (show_errors) ? -1 : 0;
+
+ if ((SSD_FIXED_IS_PRESENT(sense, sense_len,add_sense_code_qual))
+ && (SSD_FIXED_IS_FILLED(sense, add_sense_code_qual)))
+ *ascq = sense->add_sense_code_qual;
+ else
+ *ascq = (show_errors) ? -1 : 0;
+ break;
+ }
+ }
+}
+
+int
+scsi_get_sense_key(struct scsi_sense_data *sense_data, u_int sense_len,
+ int show_errors)
+{
+ int error_code, sense_key, asc, ascq;
+
+ scsi_extract_sense_len(sense_data, sense_len, &error_code,
+ &sense_key, &asc, &ascq, show_errors);
+
+ return (sense_key);
+}
+
+#ifndef __rtems__
+int
+scsi_get_asc(struct scsi_sense_data *sense_data, u_int sense_len,
+ int show_errors)
+{
+ int error_code, sense_key, asc, ascq;
+
+ scsi_extract_sense_len(sense_data, sense_len, &error_code,
+ &sense_key, &asc, &ascq, show_errors);
+
+ return (asc);
+}
+
+int
+scsi_get_ascq(struct scsi_sense_data *sense_data, u_int sense_len,
+ int show_errors)
+{
+ int error_code, sense_key, asc, ascq;
+
+ scsi_extract_sense_len(sense_data, sense_len, &error_code,
+ &sense_key, &asc, &ascq, show_errors);
+
+ return (ascq);
+}
#endif /* __rtems__ */
/*
@@ -3737,6 +5341,117 @@ scsi_calc_syncparam(u_int period)
}
#endif /* __rtems__ */
+int
+scsi_devid_is_naa_ieee_reg(uint8_t *bufp)
+{
+ struct scsi_vpd_id_descriptor *descr;
+ struct scsi_vpd_id_naa_basic *naa;
+
+ descr = (struct scsi_vpd_id_descriptor *)bufp;
+ naa = (struct scsi_vpd_id_naa_basic *)descr->identifier;
+ if ((descr->id_type & SVPD_ID_TYPE_MASK) != SVPD_ID_TYPE_NAA)
+ return 0;
+ if (descr->length < sizeof(struct scsi_vpd_id_naa_ieee_reg))
+ return 0;
+ if ((naa->naa >> SVPD_ID_NAA_NAA_SHIFT) != SVPD_ID_NAA_IEEE_REG)
+ return 0;
+ return 1;
+}
+
+int
+scsi_devid_is_sas_target(uint8_t *bufp)
+{
+ struct scsi_vpd_id_descriptor *descr;
+
+ descr = (struct scsi_vpd_id_descriptor *)bufp;
+ if (!scsi_devid_is_naa_ieee_reg(bufp))
+ return 0;
+ if ((descr->id_type & SVPD_ID_PIV) == 0) /* proto field reserved */
+ return 0;
+ if ((descr->proto_codeset >> SVPD_ID_PROTO_SHIFT) != SCSI_PROTO_SAS)
+ return 0;
+ return 1;
+}
+
+int
+scsi_devid_is_lun_eui64(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_LUN)
+ return 0;
+ if ((descr->id_type & SVPD_ID_TYPE_MASK) != SVPD_ID_TYPE_EUI64)
+ return 0;
+ return 1;
+}
+
+int
+scsi_devid_is_lun_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_LUN)
+ return 0;
+ if ((descr->id_type & SVPD_ID_TYPE_MASK) != SVPD_ID_TYPE_NAA)
+ return 0;
+ return 1;
+}
+
+int
+scsi_devid_is_lun_t10(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_LUN)
+ return 0;
+ if ((descr->id_type & SVPD_ID_TYPE_MASK) != SVPD_ID_TYPE_T10)
+ return 0;
+ return 1;
+}
+
+int
+scsi_devid_is_lun_name(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_LUN)
+ return 0;
+ if ((descr->id_type & SVPD_ID_TYPE_MASK) != SVPD_ID_TYPE_SCSI_NAME)
+ return 0;
+ return 1;
+}
+
+struct scsi_vpd_id_descriptor *
+scsi_get_devid(struct scsi_vpd_device_id *id, uint32_t page_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);
+
+ 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
+ + desc->length)) {
+
+ if (ck_fn == NULL || ck_fn((uint8_t *)desc) != 0)
+ return (desc);
+ }
+
+ return (NULL);
+}
+
void
scsi_test_unit_ready(struct ccb_scsiio *csio, u_int32_t retries,
void (*cbfcnp)(struct cam_periph *, union ccb *),
@@ -3814,14 +5529,7 @@ scsi_inquiry(struct ccb_scsiio *csio, u_int32_t retries,
scsi_cmd->byte2 |= SI_EVPD;
scsi_cmd->page_code = page_code;
}
- /*
- * A 'transfer units' count of 256 is coded as
- * zero for all commands with a single byte count
- * field.
- */
- if (inq_len == 256)
- inq_len = 0;
- scsi_cmd->length = inq_len;
+ scsi_ulto2b(inq_len, scsi_cmd->length);
}
#ifndef __rtems__
@@ -4236,7 +5944,11 @@ scsi_read_write(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)
{
+ int read;
u_int8_t cdb_len;
+
+ read = (readop & SCSI_RW_DIRMASK) == SCSI_RW_READ;
+
/*
* Use the smallest possible command to perform the operation
* as some legacy hardware does not support the 10 byte commands.
@@ -4253,7 +5965,7 @@ scsi_read_write(struct ccb_scsiio *csio, u_int32_t retries,
struct scsi_rw_6 *scsi_cmd;
scsi_cmd = (struct scsi_rw_6 *)&csio->cdb_io.cdb_bytes;
- scsi_cmd->opcode = readop ? READ_6 : WRITE_6;
+ scsi_cmd->opcode = read ? READ_6 : WRITE_6;
scsi_ulto3b(lba, scsi_cmd->addr);
scsi_cmd->length = block_count & 0xff;
scsi_cmd->control = 0;
@@ -4272,7 +5984,7 @@ scsi_read_write(struct ccb_scsiio *csio, u_int32_t retries,
struct scsi_rw_10 *scsi_cmd;
scsi_cmd = (struct scsi_rw_10 *)&csio->cdb_io.cdb_bytes;
- scsi_cmd->opcode = readop ? READ_10 : WRITE_10;
+ scsi_cmd->opcode = read ? READ_10 : WRITE_10;
scsi_cmd->byte2 = byte2;
scsi_ulto4b(lba, scsi_cmd->addr);
scsi_cmd->reserved = 0;
@@ -4295,7 +6007,7 @@ scsi_read_write(struct ccb_scsiio *csio, u_int32_t retries,
struct scsi_rw_12 *scsi_cmd;
scsi_cmd = (struct scsi_rw_12 *)&csio->cdb_io.cdb_bytes;
- scsi_cmd->opcode = readop ? READ_12 : WRITE_12;
+ scsi_cmd->opcode = read ? READ_12 : WRITE_12;
scsi_cmd->byte2 = byte2;
scsi_ulto4b(lba, scsi_cmd->addr);
scsi_cmd->reserved = 0;
@@ -4317,7 +6029,7 @@ scsi_read_write(struct ccb_scsiio *csio, u_int32_t retries,
struct scsi_rw_16 *scsi_cmd;
scsi_cmd = (struct scsi_rw_16 *)&csio->cdb_io.cdb_bytes;
- scsi_cmd->opcode = readop ? READ_16 : WRITE_16;
+ scsi_cmd->opcode = read ? READ_16 : WRITE_16;
scsi_cmd->byte2 = byte2;
scsi_u64to8b(lba, scsi_cmd->addr);
scsi_cmd->reserved = 0;
@@ -4328,7 +6040,77 @@ scsi_read_write(struct ccb_scsiio *csio, u_int32_t retries,
cam_fill_csio(csio,
retries,
cbfcnp,
- /*flags*/readop ? CAM_DIR_IN : CAM_DIR_OUT,
+ (read ? CAM_DIR_IN : CAM_DIR_OUT) |
+ ((readop & SCSI_RW_BIO) != 0 ? CAM_DATA_BIO : 0),
+ tag_action,
+ data_ptr,
+ dxfer_len,
+ sense_len,
+ cdb_len,
+ timeout);
+}
+
+void
+scsi_write_same(struct ccb_scsiio *csio, u_int32_t retries,
+ void (*cbfcnp)(struct cam_periph *, union ccb *),
+ u_int8_t tag_action, u_int8_t byte2,
+ int minimum_cmd_size, u_int64_t lba, u_int32_t block_count,
+ u_int8_t *data_ptr, u_int32_t dxfer_len, u_int8_t sense_len,
+ u_int32_t timeout)
+{
+ u_int8_t cdb_len;
+ if ((minimum_cmd_size < 16) &&
+ ((block_count & 0xffff) == block_count) &&
+ ((lba & 0xffffffff) == lba)) {
+ /*
+ * Need a 10 byte cdb.
+ */
+ struct scsi_write_same_10 *scsi_cmd;
+
+ scsi_cmd = (struct scsi_write_same_10 *)&csio->cdb_io.cdb_bytes;
+ scsi_cmd->opcode = WRITE_SAME_10;
+ scsi_cmd->byte2 = byte2;
+ scsi_ulto4b(lba, scsi_cmd->addr);
+ scsi_cmd->group = 0;
+ scsi_ulto2b(block_count, scsi_cmd->length);
+ scsi_cmd->control = 0;
+ cdb_len = sizeof(*scsi_cmd);
+
+ CAM_DEBUG(csio->ccb_h.path, CAM_DEBUG_SUBTRACE,
+ ("10byte: %x%x%x%x:%x%x: %d\n", scsi_cmd->addr[0],
+ scsi_cmd->addr[1], scsi_cmd->addr[2],
+ scsi_cmd->addr[3], scsi_cmd->length[0],
+ scsi_cmd->length[1], dxfer_len));
+ } else {
+ /*
+ * 16 byte CDB. We'll only get here if the LBA is larger
+ * than 2^32, or if the user asks for a 16 byte command.
+ */
+ struct scsi_write_same_16 *scsi_cmd;
+
+ scsi_cmd = (struct scsi_write_same_16 *)&csio->cdb_io.cdb_bytes;
+ scsi_cmd->opcode = WRITE_SAME_16;
+ scsi_cmd->byte2 = byte2;
+ scsi_u64to8b(lba, scsi_cmd->addr);
+ scsi_ulto4b(block_count, scsi_cmd->length);
+ scsi_cmd->group = 0;
+ scsi_cmd->control = 0;
+ cdb_len = sizeof(*scsi_cmd);
+
+ CAM_DEBUG(csio->ccb_h.path, CAM_DEBUG_SUBTRACE,
+ ("16byte: %x%x%x%x%x%x%x%x:%x%x%x%x: %d\n",
+ scsi_cmd->addr[0], scsi_cmd->addr[1],
+ scsi_cmd->addr[2], scsi_cmd->addr[3],
+ scsi_cmd->addr[4], scsi_cmd->addr[5],
+ scsi_cmd->addr[6], scsi_cmd->addr[7],
+ scsi_cmd->length[0], scsi_cmd->length[1],
+ scsi_cmd->length[2], scsi_cmd->length[3],
+ dxfer_len));
+ }
+ cam_fill_csio(csio,
+ retries,
+ cbfcnp,
+ /*flags*/CAM_DIR_OUT,
tag_action,
data_ptr,
dxfer_len,
@@ -4338,6 +6120,261 @@ scsi_read_write(struct ccb_scsiio *csio, u_int32_t retries,
}
#ifndef __rtems__
+void
+scsi_ata_identify(struct ccb_scsiio *csio, u_int32_t retries,
+ void (*cbfcnp)(struct cam_periph *, union ccb *),
+ u_int8_t tag_action, u_int8_t *data_ptr,
+ 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);
+}
+
+void
+scsi_ata_trim(struct ccb_scsiio *csio, u_int32_t retries,
+ void (*cbfcnp)(struct cam_periph *, union ccb *),
+ u_int8_t tag_action, u_int16_t block_count,
+ u_int8_t *data_ptr, u_int16_t dxfer_len, u_int8_t sense_len,
+ u_int32_t timeout)
+{
+ scsi_ata_pass_16(csio,
+ retries,
+ cbfcnp,
+ /*flags*/CAM_DIR_OUT,
+ tag_action,
+ /*protocol*/AP_EXTEND|AP_PROTO_DMA,
+ /*ata_flags*/AP_FLAG_TLEN_SECT_CNT|AP_FLAG_BYT_BLOK_BLOCKS,
+ /*features*/ATA_DSM_TRIM,
+ /*sector_count*/block_count,
+ /*lba*/0,
+ /*command*/ATA_DATA_SET_MANAGEMENT,
+ /*control*/0,
+ data_ptr,
+ dxfer_len,
+ sense_len,
+ 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,
+ u_int8_t protocol, u_int8_t ata_flags, u_int16_t features,
+ u_int16_t sector_count, uint64_t lba, u_int8_t command,
+ u_int8_t control, u_int8_t *data_ptr, u_int16_t dxfer_len,
+ u_int8_t sense_len, u_int32_t timeout)
+{
+ struct ata_pass_16 *ata_cmd;
+
+ ata_cmd = (struct ata_pass_16 *)&csio->cdb_io.cdb_bytes;
+ ata_cmd->opcode = ATA_PASS_16;
+ ata_cmd->protocol = protocol;
+ ata_cmd->flags = ata_flags;
+ ata_cmd->features_ext = features >> 8;
+ ata_cmd->features = features;
+ ata_cmd->sector_count_ext = sector_count >> 8;
+ ata_cmd->sector_count = sector_count;
+ ata_cmd->lba_low = lba;
+ ata_cmd->lba_mid = lba >> 8;
+ ata_cmd->lba_high = lba >> 16;
+ ata_cmd->device = ATA_DEV_LBA;
+ if (protocol & AP_EXTEND) {
+ ata_cmd->lba_low_ext = lba >> 24;
+ ata_cmd->lba_mid_ext = lba >> 32;
+ ata_cmd->lba_high_ext = lba >> 40;
+ } else
+ ata_cmd->device |= (lba >> 24) & 0x0f;
+ ata_cmd->command = command;
+ ata_cmd->control = control;
+
+ cam_fill_csio(csio,
+ retries,
+ cbfcnp,
+ flags,
+ tag_action,
+ data_ptr,
+ dxfer_len,
+ sense_len,
+ sizeof(*ata_cmd),
+ timeout);
+}
+
+void
+scsi_unmap(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_int8_t *data_ptr, u_int16_t dxfer_len, u_int8_t sense_len,
+ u_int32_t timeout)
+{
+ struct scsi_unmap *scsi_cmd;
+
+ scsi_cmd = (struct scsi_unmap *)&csio->cdb_io.cdb_bytes;
+ scsi_cmd->opcode = UNMAP;
+ scsi_cmd->byte2 = byte2;
+ scsi_ulto4b(0, scsi_cmd->reserved);
+ scsi_cmd->group = 0;
+ scsi_ulto2b(dxfer_len, scsi_cmd->length);
+ scsi_cmd->control = 0;
+
+ cam_fill_csio(csio,
+ retries,
+ cbfcnp,
+ /*flags*/CAM_DIR_OUT,
+ tag_action,
+ data_ptr,
+ dxfer_len,
+ sense_len,
+ sizeof(*scsi_cmd),
+ timeout);
+}
+
+void
+scsi_receive_diagnostic_results(struct ccb_scsiio *csio, u_int32_t retries,
+ void (*cbfcnp)(struct cam_periph *, union ccb*),
+ uint8_t tag_action, int pcv, uint8_t page_code,
+ uint8_t *data_ptr, uint16_t allocation_length,
+ uint8_t sense_len, uint32_t timeout)
+{
+ struct scsi_receive_diag *scsi_cmd;
+
+ scsi_cmd = (struct scsi_receive_diag *)&csio->cdb_io.cdb_bytes;
+ memset(scsi_cmd, 0, sizeof(*scsi_cmd));
+ scsi_cmd->opcode = RECEIVE_DIAGNOSTIC;
+ if (pcv) {
+ scsi_cmd->byte2 |= SRD_PCV;
+ scsi_cmd->page_code = page_code;
+ }
+ scsi_ulto2b(allocation_length, scsi_cmd->length);
+
+ cam_fill_csio(csio,
+ retries,
+ cbfcnp,
+ /*flags*/CAM_DIR_IN,
+ tag_action,
+ data_ptr,
+ allocation_length,
+ sense_len,
+ sizeof(*scsi_cmd),
+ timeout);
+}
+
+void
+scsi_send_diagnostic(struct ccb_scsiio *csio, u_int32_t retries,
+ void (*cbfcnp)(struct cam_periph *, union ccb *),
+ uint8_t tag_action, int unit_offline, int device_offline,
+ int self_test, int page_format, int self_test_code,
+ uint8_t *data_ptr, uint16_t param_list_length,
+ uint8_t sense_len, uint32_t timeout)
+{
+ struct scsi_send_diag *scsi_cmd;
+
+ scsi_cmd = (struct scsi_send_diag *)&csio->cdb_io.cdb_bytes;
+ memset(scsi_cmd, 0, sizeof(*scsi_cmd));
+ scsi_cmd->opcode = SEND_DIAGNOSTIC;
+
+ /*
+ * The default self-test mode control and specific test
+ * control are mutually exclusive.
+ */
+ if (self_test)
+ self_test_code = SSD_SELF_TEST_CODE_NONE;
+
+ scsi_cmd->byte2 = ((self_test_code << SSD_SELF_TEST_CODE_SHIFT)
+ & SSD_SELF_TEST_CODE_MASK)
+ | (unit_offline ? SSD_UNITOFFL : 0)
+ | (device_offline ? SSD_DEVOFFL : 0)
+ | (self_test ? SSD_SELFTEST : 0)
+ | (page_format ? SSD_PF : 0);
+ scsi_ulto2b(param_list_length, scsi_cmd->length);
+
+ cam_fill_csio(csio,
+ retries,
+ cbfcnp,
+ /*flags*/param_list_length ? CAM_DIR_OUT : CAM_DIR_NONE,
+ tag_action,
+ data_ptr,
+ param_list_length,
+ sense_len,
+ sizeof(*scsi_cmd),
+ timeout);
+}
+
+void
+scsi_read_buffer(struct ccb_scsiio *csio, u_int32_t retries,
+ void (*cbfcnp)(struct cam_periph *, union ccb*),
+ uint8_t tag_action, int mode,
+ uint8_t buffer_id, u_int32_t offset,
+ uint8_t *data_ptr, uint32_t allocation_length,
+ uint8_t sense_len, uint32_t timeout)
+{
+ struct scsi_read_buffer *scsi_cmd;
+
+ scsi_cmd = (struct scsi_read_buffer *)&csio->cdb_io.cdb_bytes;
+ memset(scsi_cmd, 0, sizeof(*scsi_cmd));
+ scsi_cmd->opcode = READ_BUFFER;
+ scsi_cmd->byte2 = mode;
+ scsi_cmd->buffer_id = buffer_id;
+ scsi_ulto3b(offset, scsi_cmd->offset);
+ scsi_ulto3b(allocation_length, scsi_cmd->length);
+
+ cam_fill_csio(csio,
+ retries,
+ cbfcnp,
+ /*flags*/CAM_DIR_IN,
+ tag_action,
+ data_ptr,
+ allocation_length,
+ sense_len,
+ sizeof(*scsi_cmd),
+ timeout);
+}
+
+void
+scsi_write_buffer(struct ccb_scsiio *csio, u_int32_t retries,
+ void (*cbfcnp)(struct cam_periph *, union ccb *),
+ uint8_t tag_action, int mode,
+ uint8_t buffer_id, u_int32_t offset,
+ uint8_t *data_ptr, uint32_t param_list_length,
+ uint8_t sense_len, uint32_t timeout)
+{
+ struct scsi_write_buffer *scsi_cmd;
+
+ scsi_cmd = (struct scsi_write_buffer *)&csio->cdb_io.cdb_bytes;
+ memset(scsi_cmd, 0, sizeof(*scsi_cmd));
+ scsi_cmd->opcode = WRITE_BUFFER;
+ scsi_cmd->byte2 = mode;
+ scsi_cmd->buffer_id = buffer_id;
+ scsi_ulto3b(offset, scsi_cmd->offset);
+ scsi_ulto3b(param_list_length, scsi_cmd->length);
+
+ cam_fill_csio(csio,
+ retries,
+ cbfcnp,
+ /*flags*/param_list_length ? CAM_DIR_OUT : CAM_DIR_NONE,
+ tag_action,
+ data_ptr,
+ param_list_length,
+ sense_len,
+ sizeof(*scsi_cmd),
+ timeout);
+}
+
void
scsi_start_stop(struct ccb_scsiio *csio, u_int32_t retries,
void (*cbfcnp)(struct cam_periph *, union ccb *),
@@ -4370,7 +6407,6 @@ scsi_start_stop(struct ccb_scsiio *csio, u_int32_t retries,
sense_len,
sizeof(*scsi_cmd),
timeout);
-
}
@@ -4428,7 +6464,89 @@ scsi_static_inquiry_match(caddr_t inqbuffer, caddr_t table_entry)
return (-1);
}
+/**
+ * Compare two buffers of vpd device descriptors for a match.
+ *
+ * \param lhs Pointer to first buffer of descriptors to compare.
+ * \param lhs_len The length of the first buffer.
+ * \param rhs Pointer to second buffer of descriptors to compare.
+ * \param rhs_len The length of the second buffer.
+ *
+ * \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
+ * a match.
+ */
+int
+scsi_devid_match(uint8_t *lhs, size_t lhs_len, uint8_t *rhs, size_t rhs_len)
+{
+ struct scsi_vpd_id_descriptor *lhs_id;
+ struct scsi_vpd_id_descriptor *lhs_last;
+ struct scsi_vpd_id_descriptor *rhs_last;
+ uint8_t *lhs_end;
+ uint8_t *rhs_end;
+
+ lhs_end = lhs + lhs_len;
+ rhs_end = rhs + rhs_len;
+
+ /*
+ * rhs_last and lhs_last are the last posible position of a valid
+ * descriptor assuming it had a zero length identifier. We use
+ * these variables to insure we can safely dereference the length
+ * field in our loop termination tests.
+ */
+ lhs_last = (struct scsi_vpd_id_descriptor *)
+ (lhs_end - __offsetof(struct scsi_vpd_id_descriptor, identifier));
+ rhs_last = (struct scsi_vpd_id_descriptor *)
+ (rhs_end - __offsetof(struct scsi_vpd_id_descriptor, identifier));
+
+ lhs_id = (struct scsi_vpd_id_descriptor *)lhs;
+ while (lhs_id <= lhs_last
+ && (lhs_id->identifier + lhs_id->length) <= lhs_end) {
+ struct scsi_vpd_id_descriptor *rhs_id;
+
+ rhs_id = (struct scsi_vpd_id_descriptor *)rhs;
+ while (rhs_id <= rhs_last
+ && (rhs_id->identifier + rhs_id->length) <= rhs_end) {
+
+ if (rhs_id->length == lhs_id->length
+ && memcmp(rhs_id->identifier, lhs_id->identifier,
+ rhs_id->length) == 0)
+ return (0);
+
+ rhs_id = (struct scsi_vpd_id_descriptor *)
+ (rhs_id->identifier + rhs_id->length);
+ }
+ lhs_id = (struct scsi_vpd_id_descriptor *)
+ (lhs_id->identifier + lhs_id->length);
+ }
+ return (-1);
+}
+
#ifdef _KERNEL
+int
+scsi_vpd_supported_page(struct cam_periph *periph, uint8_t page_id)
+{
+ struct cam_ed *device;
+ struct scsi_vpd_supported_pages *vpds;
+ int i, num_pages;
+
+ device = periph->path->device;
+ vpds = (struct scsi_vpd_supported_pages *)device->supported_vpds;
+
+ if (vpds != NULL) {
+ num_pages = device->supported_vpds_len -
+ SVPD_SUPPORTED_PAGES_HDR_LEN;
+ for (i = 0; i < num_pages; i++) {
+ if (vpds->page_list[i] == page_id)
+ return (1);
+ }
+ }
+
+ return (0);
+}
+
static void
init_scsi_delay(void)
{
diff --git a/freebsd/sys/cam/scsi/scsi_all.h b/freebsd/sys/cam/scsi/scsi_all.h
index f6608056..4fe0b1dd 100644
--- a/freebsd/sys/cam/scsi/scsi_all.h
+++ b/freebsd/sys/cam/scsi/scsi_all.h
@@ -25,6 +25,7 @@
#define _SCSI_SCSI_ALL_H 1
#include <sys/cdefs.h>
+#include <machine/stdarg.h>
#ifdef _KERNEL
/*
@@ -73,9 +74,6 @@ typedef enum {
SS_TUR = 0x040000, /* Send a Test Unit Ready command to the
* device, then retry the original command.
*/
- SS_REQSENSE = 0x050000, /* Send a RequestSense command to the
- * device, then retry the original command.
- */
SS_MASK = 0xff0000
} scsi_sense_action;
@@ -115,6 +113,7 @@ struct scsi_request_sense
{
u_int8_t opcode;
u_int8_t byte2;
+#define SRS_DESC 0x01
u_int8_t unused[2];
u_int8_t length;
u_int8_t control;
@@ -128,17 +127,33 @@ struct scsi_test_unit_ready
u_int8_t control;
};
-struct scsi_send_diag
-{
- u_int8_t opcode;
- u_int8_t byte2;
-#define SSD_UOL 0x01
-#define SSD_DOL 0x02
-#define SSD_SELFTEST 0x04
-#define SSD_PF 0x10
- u_int8_t unused[1];
- u_int8_t paramlen[2];
- u_int8_t control;
+struct scsi_receive_diag {
+ uint8_t opcode;
+ uint8_t byte2;
+#define SRD_PCV 0x01
+ uint8_t page_code;
+ uint8_t length[2];
+ uint8_t control;
+};
+
+struct scsi_send_diag {
+ uint8_t opcode;
+ uint8_t byte2;
+#define SSD_UNITOFFL 0x01
+#define SSD_DEVOFFL 0x02
+#define SSD_SELFTEST 0x04
+#define SSD_PF 0x10
+#define SSD_SELF_TEST_CODE_MASK 0xE0
+#define SSD_SELF_TEST_CODE_SHIFT 5
+#define SSD_SELF_TEST_CODE_NONE 0x00
+#define SSD_SELF_TEST_CODE_BG_SHORT 0x01
+#define SSD_SELF_TEST_CODE_BG_EXTENDED 0x02
+#define SSD_SELF_TEST_CODE_BG_ABORT 0x04
+#define SSD_SELF_TEST_CODE_FG_SHORT 0x05
+#define SSD_SELF_TEST_CODE_FG_EXTENDED 0x06
+ uint8_t reserved;
+ uint8_t length[2];
+ uint8_t control;
};
struct scsi_sense
@@ -154,10 +169,10 @@ struct scsi_inquiry
{
u_int8_t opcode;
u_int8_t byte2;
-#define SI_EVPD 0x01
+#define SI_EVPD 0x01
+#define SI_CMDDT 0x02
u_int8_t page_code;
- u_int8_t reserved;
- u_int8_t length;
+ u_int8_t length[2];
u_int8_t control;
};
@@ -183,7 +198,9 @@ struct scsi_mode_sense_6
#define SMS_PAGE_CTRL_CHANGEABLE 0x40
#define SMS_PAGE_CTRL_DEFAULT 0x80
#define SMS_PAGE_CTRL_SAVED 0xC0
- u_int8_t unused;
+ u_int8_t subpage;
+#define SMS_SUBPAGE_PAGE_0 0x00
+#define SMS_SUBPAGE_ALL 0xff
u_int8_t length;
u_int8_t control;
};
@@ -192,8 +209,10 @@ struct scsi_mode_sense_10
{
u_int8_t opcode;
u_int8_t byte2; /* same bits as small version */
+#define SMS10_LLBAA 0x10
u_int8_t page; /* same bits as small version */
- u_int8_t unused[4];
+ u_int8_t subpage;
+ u_int8_t unused[3];
u_int8_t length[2];
u_int8_t control;
};
@@ -246,6 +265,120 @@ struct scsi_mode_block_descr
u_int8_t block_len[3];
};
+struct scsi_per_res_in
+{
+ u_int8_t opcode;
+ u_int8_t action;
+#define SPRI_RK 0x00
+#define SPRI_RR 0x01
+#define SPRI_RC 0x02
+#define SPRI_RS 0x03
+ u_int8_t reserved[5];
+ u_int8_t length[2];
+ u_int8_t control;
+};
+
+struct scsi_per_res_in_header
+{
+ u_int8_t generation[4];
+ u_int8_t length[4];
+};
+
+struct scsi_per_res_key
+{
+ u_int8_t key[8];
+};
+
+struct scsi_per_res_in_keys
+{
+ struct scsi_per_res_in_header header;
+ struct scsi_per_res_key keys[0];
+};
+
+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
+ uint8_t flags2;
+#define SPRI_TMV 0x80
+#define SPRI_PTPL_A 0x01
+ uint8_t type_mask[2];
+#define SPRI_TM_WR_EX_AR 0x8000
+#define SPRI_TM_EX_AC_RO 0x4000
+#define SPRI_TM_WR_EX_RO 0x2000
+#define SPRI_TM_EX_AC 0x0800
+#define SPRI_TM_WR_EX 0x0200
+#define SPRI_TM_EX_AC_AR 0x0001
+ uint8_t reserved[2];
+};
+
+struct scsi_per_res_in_rsrv_data
+{
+ uint8_t reservation[8];
+ uint8_t obsolete1[4];
+ uint8_t reserved;
+ uint8_t scopetype;
+#define SPRT_WE 0x01
+#define SPRT_EA 0x03
+#define SPRT_WERO 0x05
+#define SPRT_EARO 0x06
+#define SPRT_WEAR 0x07
+#define SPRT_EAAR 0x08
+ uint8_t obsolete2[2];
+};
+
+struct scsi_per_res_in_rsrv
+{
+ struct scsi_per_res_in_header header;
+ struct scsi_per_res_in_rsrv_data data;
+};
+
+struct scsi_per_res_out
+{
+ u_int8_t opcode;
+ u_int8_t action;
+#define SPRO_REGISTER 0x00
+#define SPRO_RESERVE 0x01
+#define SPRO_RELEASE 0x02
+#define SPRO_CLEAR 0x03
+#define SPRO_PREEMPT 0x04
+#define SPRO_PRE_ABO 0x05
+#define SPRO_REG_IGNO 0x06
+#define SPRO_REG_MOVE 0x07
+#define SPRO_ACTION_MASK 0x1f
+ u_int8_t scope_type;
+#define SPR_SCOPE_MASK 0xf0
+#define SPR_LU_SCOPE 0x00
+#define SPR_TYPE_MASK 0x0f
+#define SPR_TYPE_WR_EX 0x01
+#define SPR_TYPE_EX_AC 0x03
+#define SPR_TYPE_WR_EX_RO 0x05
+#define SPR_TYPE_EX_AC_RO 0x06
+#define SPR_TYPE_WR_EX_AR 0x07
+#define SPR_TYPE_EX_AC_AR 0x08
+ u_int8_t reserved[2];
+ u_int8_t length[4];
+ u_int8_t control;
+};
+
+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 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];
+};
+
+
struct scsi_log_sense
{
u_int8_t opcode;
@@ -320,7 +453,16 @@ struct scsi_control_page {
u_int8_t page_code;
u_int8_t page_length;
u_int8_t rlec;
-#define SCB_RLEC 0x01 /*Report Log Exception Cond*/
+#define SCP_RLEC 0x01 /*Report Log Exception Cond*/
+#define SCP_GLTSD 0x02 /*Global Logging target
+ save disable */
+#define SCP_DSENSE 0x04 /*Descriptor Sense */
+#define SCP_DPICZ 0x08 /*Disable Prot. Info Check
+ if Prot. Field is Zero */
+#define SCP_TMF_ONLY 0x10 /*TM Functions Only*/
+#define SCP_TST_MASK 0xE0 /*Task Set Type Mask*/
+#define SCP_TST_ONE 0x00 /*One Task Set*/
+#define SCP_TST_SEPARATE 0x20 /*Separate Task Sets*/
u_int8_t queue_flags;
#define SCP_QUEUE_ALG_MASK 0xF0
#define SCP_QUEUE_ALG_RESTRICTED 0x00
@@ -351,6 +493,90 @@ struct scsi_cache_page {
u_int8_t max_prefetch_ceil[2];
};
+/*
+ * XXX KDM
+ * Updated version of the cache page, as of SBC. Update this to SBC-3 and
+ * rationalize the two.
+ */
+struct scsi_caching_page {
+ uint8_t page_code;
+#define SMS_CACHING_PAGE 0x08
+ uint8_t page_length;
+ uint8_t flags1;
+#define SCP_IC 0x80
+#define SCP_ABPF 0x40
+#define SCP_CAP 0x20
+#define SCP_DISC 0x10
+#define SCP_SIZE 0x08
+#define SCP_WCE 0x04
+#define SCP_MF 0x02
+#define SCP_RCD 0x01
+ uint8_t ret_priority;
+ uint8_t disable_pf_transfer_len[2];
+ uint8_t min_prefetch[2];
+ uint8_t max_prefetch[2];
+ uint8_t max_pf_ceiling[2];
+ uint8_t flags2;
+#define SCP_FSW 0x80
+#define SCP_LBCSS 0x40
+#define SCP_DRA 0x20
+#define SCP_VS1 0x10
+#define SCP_VS2 0x08
+ uint8_t cache_segments;
+ uint8_t cache_seg_size[2];
+ uint8_t reserved;
+ uint8_t non_cache_seg_size[3];
+};
+
+/*
+ * 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
+ uint8_t subpage;
+#define DBGCNF_SUBPAGE_CODE 0xF0
+ uint8_t page_length[2];
+ uint8_t page_version;
+#define DBGCNF_VERSION 0x00
+ uint8_t ctl_time_io_secs[2];
+};
+
+
struct scsi_info_exceptions_page {
u_int8_t page_code;
#define SIEP_PAGE_SAVABLE 0x80 /* Page is savable */
@@ -389,20 +615,49 @@ struct scsi_reserve
{
u_int8_t opcode;
u_int8_t byte2;
- u_int8_t unused[2];
- u_int8_t length;
+#define SR_EXTENT 0x01
+#define SR_ID_MASK 0x0e
+#define SR_3RDPTY 0x10
+#define SR_LUN_MASK 0xe0
+ u_int8_t resv_id;
+ u_int8_t length[2];
u_int8_t control;
};
+struct scsi_reserve_10 {
+ uint8_t opcode;
+ uint8_t byte2;
+#define SR10_3RDPTY 0x10
+#define SR10_LONGID 0x02
+#define SR10_EXTENT 0x01
+ uint8_t resv_id;
+ uint8_t thirdparty_id;
+ uint8_t reserved[3];
+ uint8_t length[2];
+ uint8_t control;
+};
+
+
struct scsi_release
{
u_int8_t opcode;
u_int8_t byte2;
- u_int8_t unused[2];
+ u_int8_t resv_id;
+ u_int8_t unused[1];
u_int8_t length;
u_int8_t control;
};
+struct scsi_release_10 {
+ uint8_t opcode;
+ uint8_t byte2;
+ uint8_t resv_id;
+ uint8_t thirdparty_id;
+ uint8_t reserved[3];
+ uint8_t length[2];
+ uint8_t control;
+};
+
struct scsi_prevent
{
u_int8_t opcode;
@@ -418,12 +673,60 @@ struct scsi_sync_cache
{
u_int8_t opcode;
u_int8_t byte2;
+#define SSC_IMMED 0x02
+#define SSC_RELADR 0x01
u_int8_t begin_lba[4];
u_int8_t reserved;
u_int8_t lb_count[2];
u_int8_t control;
};
+struct scsi_sync_cache_16
+{
+ uint8_t opcode;
+ uint8_t byte2;
+ uint8_t begin_lba[8];
+ uint8_t lb_count[4];
+ uint8_t reserved;
+ uint8_t control;
+};
+
+struct scsi_format {
+ uint8_t opcode;
+ uint8_t byte2;
+#define SF_LONGLIST 0x20
+#define SF_FMTDATA 0x10
+#define SF_CMPLIST 0x08
+#define SF_FORMAT_MASK 0x07
+#define SF_FORMAT_BLOCK 0x00
+#define SF_FORMAT_LONG_BLOCK 0x03
+#define SF_FORMAT_BFI 0x04
+#define SF_FORMAT_PHYS 0x05
+ uint8_t vendor;
+ uint8_t interleave[2];
+ uint8_t control;
+};
+
+struct scsi_format_header_short {
+ uint8_t reserved;
+#define SF_DATA_FOV 0x80
+#define SF_DATA_DPRY 0x40
+#define SF_DATA_DCRT 0x20
+#define SF_DATA_STPF 0x10
+#define SF_DATA_IP 0x08
+#define SF_DATA_DSP 0x04
+#define SF_DATA_IMMED 0x02
+#define SF_DATA_VS 0x01
+ uint8_t byte2;
+ uint8_t defect_list_len[2];
+};
+
+struct scsi_format_header_long {
+ uint8_t reserved;
+ uint8_t byte2;
+ uint8_t reserved2[2];
+ uint8_t defect_list_len[4];
+};
struct scsi_changedef
{
@@ -442,6 +745,7 @@ struct scsi_read_buffer
u_int8_t byte2;
#define RWB_MODE 0x07
#define RWB_MODE_HDR_DATA 0x00
+#define RWB_MODE_VENDOR 0x01
#define RWB_MODE_DATA 0x02
#define RWB_MODE_DOWNLOAD 0x04
#define RWB_MODE_DOWNLOAD_SAVE 0x05
@@ -512,6 +816,75 @@ struct scsi_rw_16
u_int8_t control;
};
+struct scsi_write_same_10
+{
+ uint8_t opcode;
+ uint8_t byte2;
+#define SWS_LBDATA 0x02
+#define SWS_PBDATA 0x04
+#define SWS_UNMAP 0x08
+#define SWS_ANCHOR 0x10
+ uint8_t addr[4];
+ uint8_t group;
+ uint8_t length[2];
+ uint8_t control;
+};
+
+struct scsi_write_same_16
+{
+ uint8_t opcode;
+ uint8_t byte2;
+ uint8_t addr[8];
+ uint8_t length[4];
+ uint8_t group;
+ uint8_t control;
+};
+
+struct scsi_unmap
+{
+ uint8_t opcode;
+ uint8_t byte2;
+#define SU_ANCHOR 0x01
+ uint8_t reserved[4];
+ uint8_t group;
+ uint8_t length[2];
+ uint8_t control;
+};
+
+struct scsi_write_verify_10
+{
+ uint8_t opcode;
+ uint8_t byte2;
+#define SWV_BYTCHK 0x02
+#define SWV_DPO 0x10
+#define SWV_WRPROECT_MASK 0xe0
+ uint8_t addr[4];
+ uint8_t group;
+ uint8_t length[2];
+ uint8_t control;
+};
+
+struct scsi_write_verify_12
+{
+ uint8_t opcode;
+ uint8_t byte2;
+ uint8_t addr[4];
+ uint8_t length[4];
+ uint8_t group;
+ uint8_t control;
+};
+
+struct scsi_write_verify_16
+{
+ uint8_t opcode;
+ uint8_t byte2;
+ uint8_t addr[8];
+ uint8_t length[4];
+ uint8_t group;
+ uint8_t control;
+};
+
+
struct scsi_start_stop_unit
{
u_int8_t opcode;
@@ -521,12 +894,33 @@ struct scsi_start_stop_unit
u_int8_t how;
#define SSS_START 0x01
#define SSS_LOEJ 0x02
+#define SSS_PC_MASK 0xf0
+#define SSS_PC_START_VALID 0x00
+#define SSS_PC_ACTIVE 0x10
+#define SSS_PC_IDLE 0x20
+#define SSS_PC_STANDBY 0x30
+#define SSS_PC_LU_CONTROL 0x70
+#define SSS_PC_FORCE_IDLE_0 0xa0
+#define SSS_PC_FORCE_STANDBY_0 0xb0
u_int8_t control;
};
struct ata_pass_12 {
u_int8_t opcode;
u_int8_t protocol;
+#define AP_PROTO_HARD_RESET (0x00 << 1)
+#define AP_PROTO_SRST (0x01 << 1)
+#define AP_PROTO_NON_DATA (0x03 << 1)
+#define AP_PROTO_PIO_IN (0x04 << 1)
+#define AP_PROTO_PIO_OUT (0x05 << 1)
+#define AP_PROTO_DMA (0x06 << 1)
+#define AP_PROTO_DMA_QUEUED (0x07 << 1)
+#define AP_PROTO_DEVICE_DIAG (0x08 << 1)
+#define AP_PROTO_DEVICE_RESET (0x09 << 1)
+#define AP_PROTO_UDMA_IN (0x0a << 1)
+#define AP_PROTO_UDMA_OUT (0x0b << 1)
+#define AP_PROTO_FPDMA (0x0c << 1)
+#define AP_PROTO_RESP_INFO (0x0f << 1)
#define AP_MULTI 0xe0
u_int8_t flags;
#define AP_T_LEN 0x03
@@ -545,11 +939,32 @@ struct ata_pass_12 {
u_int8_t control;
};
+struct scsi_maintenance_in
+{
+ uint8_t opcode;
+ uint8_t byte2;
+#define SERVICE_ACTION_MASK 0x1f
+#define SA_RPRT_TRGT_GRP 0x0a
+ uint8_t reserved[4];
+ uint8_t length[4];
+ uint8_t reserved1;
+ uint8_t control;
+};
+
struct ata_pass_16 {
u_int8_t opcode;
u_int8_t protocol;
#define AP_EXTEND 0x01
u_int8_t flags;
+#define AP_FLAG_TLEN_NO_DATA (0 << 0)
+#define AP_FLAG_TLEN_FEAT (1 << 0)
+#define AP_FLAG_TLEN_SECT_CNT (2 << 0)
+#define AP_FLAG_TLEN_STPSIU (3 << 0)
+#define AP_FLAG_BYT_BLOK_BYTES (0 << 2)
+#define AP_FLAG_BYT_BLOK_BLOCKS (1 << 2)
+#define AP_FLAG_TDIR_TO_DEV (0 << 3)
+#define AP_FLAG_TDIR_FROM_DEV (1 << 3)
+#define AP_FLAG_CHK_COND (1 << 5)
u_int8_t features_ext;
u_int8_t features;
u_int8_t sector_count_ext;
@@ -590,18 +1005,29 @@ struct ata_pass_16 {
#define READ_10 0x28
#define WRITE_10 0x2A
#define POSITION_TO_ELEMENT 0x2B
+#define WRITE_VERIFY_10 0x2E
+#define VERIFY_10 0x2F
#define SYNCHRONIZE_CACHE 0x35
#define READ_DEFECT_DATA_10 0x37
#define WRITE_BUFFER 0x3B
#define READ_BUFFER 0x3C
#define CHANGE_DEFINITION 0x40
+#define WRITE_SAME_10 0x41
+#define UNMAP 0x42
#define LOG_SELECT 0x4C
#define LOG_SENSE 0x4D
#define MODE_SELECT_10 0x55
+#define RESERVE_10 0x56
+#define RELEASE_10 0x57
#define MODE_SENSE_10 0x5A
+#define PERSISTENT_RES_IN 0x5E
+#define PERSISTENT_RES_OUT 0x5F
#define ATA_PASS_16 0x85
#define READ_16 0x88
#define WRITE_16 0x8A
+#define WRITE_VERIFY_16 0x8E
+#define SYNCHRONIZE_CACHE_16 0x91
+#define WRITE_SAME_16 0x93
#define SERVICE_ACTION_IN 0x9E
#define REPORT_LUNS 0xA0
#define ATA_PASS_12 0xA1
@@ -610,6 +1036,7 @@ struct ata_pass_16 {
#define MOVE_MEDIUM 0xA5
#define READ_12 0xA8
#define WRITE_12 0xAA
+#define WRITE_VERIFY_12 0xAE
#define READ_ELEMENT_STATUS 0xB8
#define READ_CD 0xBE
@@ -659,7 +1086,7 @@ struct ata_pass_16 {
/*
* This length is the initial inquiry length used by the probe code, as
- * well as the legnth necessary for scsi_print_inquiry() to function
+ * well as the length necessary for scsi_print_inquiry() to function
* correctly. If either use requires a different length in the future,
* the two values should be de-coupled.
*/
@@ -721,10 +1148,12 @@ struct scsi_inquiry_data
u_int8_t response_format;
#define SID_AENC 0x80
#define SID_TrmIOP 0x40
+#define SID_NormACA 0x20
+#define SID_HiSup 0x10
u_int8_t additional_length;
#define SID_ADDITIONAL_LENGTH(iqd) \
((iqd)->additional_length + \
- offsetof(struct scsi_inquiry_data, additional_length) + 1)
+ __offsetof(struct scsi_inquiry_data, additional_length) + 1)
u_int8_t spc3_flags;
#define SPC3_SID_PROTECT 0x01
#define SPC3_SID_3PC 0x08
@@ -734,6 +1163,7 @@ struct scsi_inquiry_data
#define SPC3_SID_ACC 0x40
#define SPC3_SID_SCCS 0x80
u_int8_t spc2_flags;
+#define SPC2_SID_ADDR16 0x01
#define SPC2_SID_MChngr 0x08
#define SPC2_SID_MultiP 0x10
#define SPC2_SID_EncServ 0x40
@@ -793,17 +1223,37 @@ struct scsi_inquiry_data
u_int8_t vendor_specific1[SID_VENDOR_SPECIFIC_1_SIZE];
};
+/*
+ * This structure is more suited to initiator operation, because the
+ * maximum number of supported pages is already allocated.
+ */
struct scsi_vpd_supported_page_list
{
u_int8_t device;
u_int8_t page_code;
-#define SVPD_SUPPORTED_PAGE_LIST 0x00
+#define SVPD_SUPPORTED_PAGE_LIST 0x00
+#define SVPD_SUPPORTED_PAGES_HDR_LEN 4
u_int8_t reserved;
u_int8_t length; /* number of VPD entries */
#define SVPD_SUPPORTED_PAGES_SIZE 251
u_int8_t list[SVPD_SUPPORTED_PAGES_SIZE];
};
+/*
+ * This structure is more suited to target operation, because the
+ * number of supported pages is left to the user to allocate.
+ */
+struct scsi_vpd_supported_pages
+{
+ u_int8_t device;
+ u_int8_t page_code;
+ u_int8_t reserved;
+#define SVPD_SUPPORTED_PAGES 0x00
+ u_int8_t length;
+ u_int8_t page_list[0];
+};
+
+
struct scsi_vpd_unit_serial_number
{
u_int8_t device;
@@ -815,12 +1265,265 @@ struct scsi_vpd_unit_serial_number
u_int8_t serial_num[SVPD_SERIAL_NUM_SIZE];
};
+struct scsi_vpd_device_id
+{
+ u_int8_t device;
+ u_int8_t page_code;
+#define SVPD_DEVICE_ID 0x83
+#define SVPD_DEVICE_ID_MAX_SIZE 252
+#define SVPD_DEVICE_ID_HDR_LEN \
+ __offsetof(struct scsi_vpd_device_id, desc_list)
+ u_int8_t length[2];
+ u_int8_t desc_list[];
+};
+
+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
+#define SVPD_ID_PROTO_SHIFT 4
+#define SVPD_ID_CODESET_BINARY 0x01
+#define SVPD_ID_CODESET_ASCII 0x02
+#define SVPD_ID_CODESET_UTF8 0x03
+#define SVPD_ID_CODESET_MASK 0x0f
+ u_int8_t id_type;
+#define SVPD_ID_PIV 0x80
+#define SVPD_ID_ASSOC_LUN 0x00
+#define SVPD_ID_ASSOC_PORT 0x10
+#define SVPD_ID_ASSOC_TARGET 0x20
+#define SVPD_ID_ASSOC_MASK 0x30
+#define SVPD_ID_TYPE_VENDOR 0x00
+#define SVPD_ID_TYPE_T10 0x01
+#define SVPD_ID_TYPE_EUI64 0x02
+#define SVPD_ID_TYPE_NAA 0x03
+#define SVPD_ID_TYPE_RELTARG 0x04
+#define SVPD_ID_TYPE_TPORTGRP 0x05
+#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_MASK 0x0f
+ u_int8_t reserved;
+ u_int8_t length;
+#define SVPD_DEVICE_ID_DESC_HDR_LEN \
+ __offsetof(struct scsi_vpd_id_descriptor, identifier)
+ u_int8_t identifier[];
+};
+
+struct scsi_vpd_id_t10
+{
+ u_int8_t vendor[8];
+ u_int8_t vendor_spec_id[0];
+};
+
+struct scsi_vpd_id_eui64
+{
+ u_int8_t ieee_company_id[3];
+ u_int8_t extension_id[5];
+};
+
+struct scsi_vpd_id_naa_basic
+{
+ uint8_t naa;
+ /* big endian, packed:
+ uint8_t naa : 4;
+ uint8_t naa_desig : 4;
+ */
+#define SVPD_ID_NAA_NAA_SHIFT 4
+#define SVPD_ID_NAA_IEEE_EXT 0x02
+#define SVPD_ID_NAA_LOCAL_REG 0x03
+#define SVPD_ID_NAA_IEEE_REG 0x05
+#define SVPD_ID_NAA_IEEE_REG_EXT 0x06
+ uint8_t naa_data[];
+};
+
+struct scsi_vpd_id_naa_ieee_extended_id
+{
+ uint8_t naa;
+ uint8_t vendor_specific_id_a;
+ uint8_t ieee_company_id[3];
+ uint8_t vendor_specific_id_b[4];
+};
+
+struct scsi_vpd_id_naa_local_reg
+{
+ uint8_t naa;
+ uint8_t local_value[7];
+};
+
+struct scsi_vpd_id_naa_ieee_reg
+{
+ uint8_t naa;
+ uint8_t reg_value[7];
+ /* big endian, packed:
+ uint8_t naa_basic : 4;
+ uint8_t ieee_company_id_0 : 4;
+ uint8_t ieee_company_id_1[2];
+ uint8_t ieee_company_id_2 : 4;
+ uint8_t vendor_specific_id_0 : 4;
+ uint8_t vendor_specific_id_1[4];
+ */
+};
+
+struct scsi_vpd_id_naa_ieee_reg_extended
+{
+ uint8_t naa;
+ uint8_t reg_value[15];
+ /* big endian, packed:
+ uint8_t naa_basic : 4;
+ uint8_t ieee_company_id_0 : 4;
+ uint8_t ieee_company_id_1[2];
+ uint8_t ieee_company_id_2 : 4;
+ uint8_t vendor_specific_id_0 : 4;
+ uint8_t vendor_specific_id_1[4];
+ uint8_t vendor_specific_id_ext[8];
+ */
+};
+
+struct scsi_vpd_id_rel_trgt_port_id
+{
+ uint8_t obsolete[2];
+ uint8_t rel_trgt_port_id[2];
+};
+
+struct scsi_vpd_id_trgt_port_grp_id
+{
+ uint8_t reserved[2];
+ uint8_t trgt_port_grp[2];
+};
+
+struct scsi_vpd_id_lun_grp_id
+{
+ uint8_t reserved[2];
+ uint8_t log_unit_grp[2];
+};
+
+struct scsi_vpd_id_md5_lun_id
+{
+ uint8_t lun_id[16];
+};
+
+struct scsi_vpd_id_scsi_name
+{
+ uint8_t name_string[256];
+};
+
+struct scsi_service_action_in
+{
+ uint8_t opcode;
+ uint8_t service_action;
+ uint8_t action_dependent[13];
+ uint8_t control;
+};
+
+struct scsi_diag_page {
+ uint8_t page_code;
+ uint8_t page_specific_flags;
+ uint8_t length[2];
+ uint8_t params[0];
+};
+
+/*
+ * ATA Information VPD Page based on
+ * T10/2126-D Revision 04
+ */
+#define SVPD_ATA_INFORMATION 0x89
+
+/*
+ * Block Device Characteristics VPD Page based on
+ * T10/1799-D Revision 31
+ */
+struct scsi_vpd_block_characteristics
+{
+ u_int8_t device;
+ u_int8_t page_code;
+#define SVPD_BDC 0xB1
+ 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
+ u_int8_t reserved1;
+ u_int8_t nominal_form_factor;
+#define SVPD_BDC_FORM_NOT_REPORTED 0x00
+#define SVPD_BDC_FORM_5_25INCH 0x01
+#define SVPD_BDC_FORM_3_5INCH 0x02
+#define SVPD_BDC_FORM_2_5INCH 0x03
+#define SVPD_BDC_FORM_1_5INCH 0x04
+#define SVPD_BDC_FORM_LESSTHAN_1_5INCH 0x05
+ u_int8_t reserved2[56];
+};
+
+/*
+ * Logical Block Provisioning VPD Page based on
+ * T10/1799-D Revision 31
+ */
+struct scsi_vpd_logical_block_prov
+{
+ u_int8_t device;
+ u_int8_t page_code;
+#define SVPD_LBP 0xB2
+ u_int8_t page_length[2];
+#define SVPD_LBP_PL_BASIC 0x04
+ u_int8_t threshold_exponent;
+ u_int8_t flags;
+#define SVPD_LBP_UNMAP 0x80
+#define SVPD_LBP_WS16 0x40
+#define SVPD_LBP_WS10 0x20
+#define SVPD_LBP_RZ 0x04
+#define SVPD_LBP_ANC_SUP 0x02
+#define SVPD_LBP_DP 0x01
+ u_int8_t prov_type;
+#define SVPD_LBP_RESOURCE 0x01
+#define SVPD_LBP_THIN 0x02
+ u_int8_t reserved;
+ /*
+ * Provisioning Group Descriptor can be here if SVPD_LBP_DP is set
+ * Its size can be determined from page_length - 4
+ */
+};
+
+/*
+ * Block Limits VDP Page based on
+ * T10/1799-D Revision 31
+ */
+struct scsi_vpd_block_limits
+{
+ u_int8_t device;
+ u_int8_t page_code;
+#define SVPD_BLOCK_LIMITS 0xB0
+ u_int8_t page_length[2];
+#define SVPD_BL_PL_BASIC 0x10
+#define SVPD_BL_PL_TP 0x3C
+ u_int8_t reserved1;
+ u_int8_t max_cmp_write_len;
+ u_int8_t opt_txfer_len_grain[2];
+ u_int8_t max_txfer_len[4];
+ u_int8_t opt_txfer_len[4];
+ u_int8_t max_prefetch[4];
+ u_int8_t max_unmap_lba_cnt[4];
+ u_int8_t max_unmap_blk_cnt[4];
+ 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];
+};
+
struct scsi_read_capacity
{
u_int8_t opcode;
u_int8_t byte2;
+#define SRC_RELADR 0x01
u_int8_t addr[4];
- u_int8_t unused[3];
+ u_int8_t unused[2];
+ u_int8_t pmi;
+#define SRC_PMI 0x01
u_int8_t control;
};
@@ -849,14 +1552,24 @@ struct scsi_read_capacity_data_long
uint8_t length[4];
#define SRC16_PROT_EN 0x01
#define SRC16_P_TYPE 0x0e
+#define SRC16_PTYPE_1 0x00
+#define SRC16_PTYPE_2 0x02
+#define SRC16_PTYPE_3 0x04
uint8_t prot;
#define SRC16_LBPPBE 0x0f
#define SRC16_PI_EXPONENT 0xf0
#define SRC16_PI_EXPONENT_SHIFT 4
uint8_t prot_lbppbe;
-#define SRC16_LALBA 0x3fff
-#define SRC16_LBPRZ 0x4000
-#define SRC16_LBPME 0x8000
+#define SRC16_LALBA 0x3f
+#define SRC16_LBPRZ 0x40
+#define SRC16_LBPME 0x80
+/*
+ * Alternate versions of these macros that are intended for use on a 16-bit
+ * version of the lalba_lbp field instead of the array of 2 8 bit numbers.
+ */
+#define SRC16_LALBA_A 0x3fff
+#define SRC16_LBPRZ_A 0x4000
+#define SRC16_LBPME_A 0x8000
uint8_t lalba_lbp[2];
};
@@ -874,18 +1587,11 @@ struct scsi_report_luns
uint8_t control;
};
-struct scsi_report_luns_data {
- u_int8_t length[4]; /* length of LUN inventory, in bytes */
- u_int8_t reserved[4]; /* unused */
- /*
- * LUN inventory- we only support the type zero form for now.
- */
- struct {
- u_int8_t lundata[8];
- } luns[0];
-};
+struct scsi_report_luns_lundata {
+ uint8_t lundata[8];
#define RPL_LUNDATA_PERIPH_BUS_MASK 0x3f
#define RPL_LUNDATA_FLAT_LUN_MASK 0x3f
+#define RPL_LUNDATA_FLAT_LUN_BITS 0x06
#define RPL_LUNDATA_LUN_TARG_MASK 0x3f
#define RPL_LUNDATA_LUN_BUS_MASK 0xe0
#define RPL_LUNDATA_LUN_LUN_MASK 0x1f
@@ -898,6 +1604,16 @@ struct scsi_report_luns_data {
#define RPL_LUNDATA_ATYP_FLAT 0x40
#define RPL_LUNDATA_ATYP_LUN 0x80
#define RPL_LUNDATA_ATYP_EXTLUN 0xc0
+};
+
+struct scsi_report_luns_data {
+ u_int8_t length[4]; /* length of LUN inventory, in bytes */
+ u_int8_t reserved[4]; /* unused */
+ /*
+ * LUN inventory- we only support the type zero form for now.
+ */
+ struct scsi_report_luns_lundata luns[0];
+};
struct scsi_target_group
{
@@ -939,6 +1655,9 @@ struct scsi_target_port_group_descriptor {
uint8_t target_port_group[2];
uint8_t reserved;
uint8_t status;
+#define TPG_UNAVLBL 0
+#define TPG_SET_BY_STPG 0x01
+#define TPG_IMPLICIT 0x02
uint8_t vendor_specific;
uint8_t target_port_count;
struct scsi_target_port_descriptor descriptors[];
@@ -958,8 +1677,49 @@ struct scsi_target_group_data_extended {
};
+typedef enum {
+ SSD_TYPE_NONE,
+ SSD_TYPE_FIXED,
+ SSD_TYPE_DESC
+} scsi_sense_data_type;
+
+typedef enum {
+ SSD_ELEM_NONE,
+ SSD_ELEM_SKIP,
+ SSD_ELEM_DESC,
+ SSD_ELEM_SKS,
+ SSD_ELEM_COMMAND,
+ SSD_ELEM_INFO,
+ SSD_ELEM_FRU,
+ SSD_ELEM_STREAM,
+ SSD_ELEM_MAX
+} scsi_sense_elem_type;
+
+
struct scsi_sense_data
{
+ uint8_t error_code;
+ /*
+ * SPC-4 says that the maximum length of sense data is 252 bytes.
+ * So this structure is exactly 252 bytes log.
+ */
+#define SSD_FULL_SIZE 252
+ uint8_t sense_buf[SSD_FULL_SIZE - 1];
+ /*
+ * XXX KDM is this still a reasonable minimum size?
+ */
+#define SSD_MIN_SIZE 18
+ /*
+ * Maximum value for the extra_len field in the sense data.
+ */
+#define SSD_EXTRA_MAX 244
+};
+
+/*
+ * Fixed format sense data.
+ */
+struct scsi_sense_data_fixed
+{
u_int8_t error_code;
#define SSD_ERRCODE 0x7F
#define SSD_CURRENT_ERROR 0x70
@@ -983,7 +1743,7 @@ struct scsi_sense_data
#define SSD_KEY_EQUAL 0x0c
#define SSD_KEY_VOLUME_OVERFLOW 0x0d
#define SSD_KEY_MISCOMPARE 0x0e
-#define SSD_KEY_RESERVED 0x0f
+#define SSD_KEY_COMPLETED 0x0f
#define SSD_ILI 0x20
#define SSD_EOM 0x40
#define SSD_FILEMARK 0x80
@@ -998,9 +1758,313 @@ struct scsi_sense_data
#define SSD_FIELDPTR_CMD 0x40
#define SSD_BITPTR_VALID 0x08
#define SSD_BITPTR_VALUE 0x07
-#define SSD_MIN_SIZE 18
u_int8_t extra_bytes[14];
-#define SSD_FULL_SIZE sizeof(struct scsi_sense_data)
+#define SSD_FIXED_IS_PRESENT(sense, length, field) \
+ ((length >= (offsetof(struct scsi_sense_data_fixed, field) + \
+ sizeof(sense->field))) ? 1 :0)
+#define SSD_FIXED_IS_FILLED(sense, field) \
+ ((((offsetof(struct scsi_sense_data_fixed, field) + \
+ sizeof(sense->field)) - \
+ (offsetof(struct scsi_sense_data_fixed, extra_len) + \
+ sizeof(sense->extra_len))) <= sense->extra_len) ? 1 : 0)
+};
+
+/*
+ * Descriptor format sense data definitions.
+ * Introduced in SPC-3.
+ */
+struct scsi_sense_data_desc
+{
+ uint8_t error_code;
+#define SSD_DESC_CURRENT_ERROR 0x72
+#define SSD_DESC_DEFERRED_ERROR 0x73
+ uint8_t sense_key;
+ uint8_t add_sense_code;
+ uint8_t add_sense_code_qual;
+ uint8_t reserved[3];
+ /*
+ * Note that SPC-4, section 4.5.2.1 says that the extra_len field
+ * must be less than or equal to 244.
+ */
+ uint8_t extra_len;
+ uint8_t sense_desc[0];
+#define SSD_DESC_IS_PRESENT(sense, length, field) \
+ ((length >= (offsetof(struct scsi_sense_data_desc, field) + \
+ sizeof(sense->field))) ? 1 :0)
+};
+
+struct scsi_sense_desc_header
+{
+ uint8_t desc_type;
+ uint8_t length;
+};
+/*
+ * The information provide in the Information descriptor is device type or
+ * command specific information, and defined in a command standard.
+ *
+ * Note that any changes to the field names or positions in this structure,
+ * even reserved fields, should be accompanied by an examination of the
+ * code in ctl_set_sense() that uses them.
+ *
+ * Maximum descriptors allowed: 1 (as of SPC-4)
+ */
+struct scsi_sense_info
+{
+ uint8_t desc_type;
+#define SSD_DESC_INFO 0x00
+ uint8_t length;
+ uint8_t byte2;
+#define SSD_INFO_VALID 0x80
+ uint8_t reserved;
+ uint8_t info[8];
+};
+
+/*
+ * Command-specific information depends on the command for which the
+ * reported condition occured.
+ *
+ * Note that any changes to the field names or positions in this structure,
+ * even reserved fields, should be accompanied by an examination of the
+ * code in ctl_set_sense() that uses them.
+ *
+ * Maximum descriptors allowed: 1 (as of SPC-4)
+ */
+struct scsi_sense_command
+{
+ uint8_t desc_type;
+#define SSD_DESC_COMMAND 0x01
+ uint8_t length;
+ uint8_t reserved[2];
+ uint8_t command_info[8];
+};
+
+/*
+ * Sense key specific descriptor. The sense key specific data format
+ * depends on the sense key in question.
+ *
+ * Maximum descriptors allowed: 1 (as of SPC-4)
+ */
+struct scsi_sense_sks
+{
+ uint8_t desc_type;
+#define SSD_DESC_SKS 0x02
+ uint8_t length;
+ uint8_t reserved1[2];
+ uint8_t sense_key_spec[3];
+#define SSD_SKS_VALID 0x80
+ uint8_t reserved2;
+};
+
+/*
+ * This is used for the Illegal Request sense key (0x05) only.
+ */
+struct scsi_sense_sks_field
+{
+ uint8_t byte0;
+#define SSD_SKS_FIELD_VALID 0x80
+#define SSD_SKS_FIELD_CMD 0x40
+#define SSD_SKS_BPV 0x08
+#define SSD_SKS_BIT_VALUE 0x07
+ uint8_t field[2];
+};
+
+
+/*
+ * This is used for the Hardware Error (0x04), Medium Error (0x03) and
+ * Recovered Error (0x01) sense keys.
+ */
+struct scsi_sense_sks_retry
+{
+ uint8_t byte0;
+#define SSD_SKS_RETRY_VALID 0x80
+ uint8_t actual_retry_count[2];
+};
+
+/*
+ * Used with the NO Sense (0x00) or Not Ready (0x02) sense keys.
+ */
+struct scsi_sense_sks_progress
+{
+ uint8_t byte0;
+#define SSD_SKS_PROGRESS_VALID 0x80
+ uint8_t progress[2];
+#define SSD_SKS_PROGRESS_DENOM 0x10000
+};
+
+/*
+ * Used with the Copy Aborted (0x0a) sense key.
+ */
+struct scsi_sense_sks_segment
+{
+ uint8_t byte0;
+#define SSD_SKS_SEGMENT_VALID 0x80
+#define SSD_SKS_SEGMENT_SD 0x20
+#define SSD_SKS_SEGMENT_BPV 0x08
+#define SSD_SKS_SEGMENT_BITPTR 0x07
+ uint8_t field[2];
+};
+
+/*
+ * Used with the Unit Attention (0x06) sense key.
+ *
+ * This is currently used to indicate that the unit attention condition
+ * queue has overflowed (when the overflow bit is set).
+ */
+struct scsi_sense_sks_overflow
+{
+ uint8_t byte0;
+#define SSD_SKS_OVERFLOW_VALID 0x80
+#define SSD_SKS_OVERFLOW_SET 0x01
+ uint8_t reserved[2];
+};
+
+/*
+ * This specifies which component is associated with the sense data. There
+ * is no standard meaning for the fru value.
+ *
+ * Maximum descriptors allowed: 1 (as of SPC-4)
+ */
+struct scsi_sense_fru
+{
+ uint8_t desc_type;
+#define SSD_DESC_FRU 0x03
+ uint8_t length;
+ uint8_t reserved;
+ uint8_t fru;
+};
+
+/*
+ * Used for Stream commands, defined in SSC-4.
+ *
+ * Maximum descriptors allowed: 1 (as of SPC-4)
+ */
+
+struct scsi_sense_stream
+{
+ uint8_t desc_type;
+#define SSD_DESC_STREAM 0x04
+ uint8_t length;
+ uint8_t reserved;
+ uint8_t byte3;
+#define SSD_DESC_STREAM_FM 0x80
+#define SSD_DESC_STREAM_EOM 0x40
+#define SSD_DESC_STREAM_ILI 0x20
+};
+
+/*
+ * Used for Block commands, defined in SBC-3.
+ *
+ * This is currently (as of SBC-3) only used for the Incorrect Length
+ * Indication (ILI) bit, which says that the data length requested in the
+ * READ LONG or WRITE LONG command did not match the length of the logical
+ * block.
+ *
+ * Maximum descriptors allowed: 1 (as of SPC-4)
+ */
+struct scsi_sense_block
+{
+ uint8_t desc_type;
+#define SSD_DESC_BLOCK 0x05
+ uint8_t length;
+ uint8_t reserved;
+ uint8_t byte3;
+#define SSD_DESC_BLOCK_ILI 0x20
+};
+
+/*
+ * Used for Object-Based Storage Devices (OSD-3).
+ *
+ * Maximum descriptors allowed: 1 (as of SPC-4)
+ */
+struct scsi_sense_osd_objid
+{
+ uint8_t desc_type;
+#define SSD_DESC_OSD_OBJID 0x06
+ uint8_t length;
+ uint8_t reserved[6];
+ /*
+ * XXX KDM provide the bit definitions here? There are a lot of
+ * them, and we don't have an OSD driver yet.
+ */
+ uint8_t not_init_cmds[4];
+ uint8_t completed_cmds[4];
+ uint8_t partition_id[8];
+ uint8_t object_id[8];
+};
+
+/*
+ * Used for Object-Based Storage Devices (OSD-3).
+ *
+ * Maximum descriptors allowed: 1 (as of SPC-4)
+ */
+struct scsi_sense_osd_integrity
+{
+ uint8_t desc_type;
+#define SSD_DESC_OSD_INTEGRITY 0x07
+ uint8_t length;
+ uint8_t integ_check_val[32];
+};
+
+/*
+ * Used for Object-Based Storage Devices (OSD-3).
+ *
+ * Maximum descriptors allowed: 1 (as of SPC-4)
+ */
+struct scsi_sense_osd_attr_id
+{
+ uint8_t desc_type;
+#define SSD_DESC_OSD_ATTR_ID 0x08
+ uint8_t length;
+ uint8_t reserved[2];
+ uint8_t attr_desc[0];
+};
+
+/*
+ * Used with Sense keys No Sense (0x00) and Not Ready (0x02).
+ *
+ * Maximum descriptors allowed: 32 (as of SPC-4)
+ */
+struct scsi_sense_progress
+{
+ uint8_t desc_type;
+#define SSD_DESC_PROGRESS 0x0a
+ uint8_t length;
+ uint8_t sense_key;
+ uint8_t add_sense_code;
+ uint8_t add_sense_code_qual;
+ uint8_t reserved;
+ uint8_t progress[2];
+};
+
+/*
+ * This is typically forwarded as the result of an EXTENDED COPY command.
+ *
+ * Maximum descriptors allowed: 2 (as of SPC-4)
+ */
+struct scsi_sense_forwarded
+{
+ uint8_t desc_type;
+#define SSD_DESC_FORWARDED 0x0c
+ uint8_t length;
+ uint8_t byte2;
+#define SSD_FORWARDED_FSDT 0x80
+#define SSD_FORWARDED_SDS_MASK 0x0f
+#define SSD_FORWARDED_SDS_UNK 0x00
+#define SSD_FORWARDED_SDS_EXSRC 0x01
+#define SSD_FORWARDED_SDS_EXDST 0x02
+};
+
+/*
+ * Vendor-specific sense descriptor. The desc_type field will be in the
+ * range bewteen MIN and MAX inclusive.
+ */
+struct scsi_sense_vendor
+{
+ uint8_t desc_type;
+#define SSD_DESC_VENDOR_MIN 0x80
+#define SSD_DESC_VENDOR_MAX 0xff
+ uint8_t length;
+ uint8_t data[0];
};
struct scsi_mode_header_6
@@ -1023,9 +2087,20 @@ struct scsi_mode_header_10
struct scsi_mode_page_header
{
u_int8_t page_code;
+#define SMPH_PS 0x80
+#define SMPH_SPF 0x40
+#define SMPH_PC_MASK 0x3f
u_int8_t page_length;
};
+struct scsi_mode_page_header_sp
+{
+ uint8_t page_code;
+ uint8_t subpage;
+ uint8_t page_length[2];
+};
+
+
struct scsi_mode_blk_desc
{
u_int8_t density;
@@ -1128,6 +2203,84 @@ scsi_sense_action scsi_error_action(struct ccb_scsiio* csio,
struct scsi_inquiry_data *inq_data,
u_int32_t sense_flags);
const char * scsi_status_string(struct ccb_scsiio *csio);
+
+void scsi_desc_iterate(struct scsi_sense_data_desc *sense, u_int sense_len,
+ int (*iter_func)(struct scsi_sense_data_desc *sense,
+ u_int, struct scsi_sense_desc_header *,
+ void *), void *arg);
+uint8_t *scsi_find_desc(struct scsi_sense_data_desc *sense, u_int sense_len,
+ uint8_t desc_type);
+void scsi_set_sense_data(struct scsi_sense_data *sense_data,
+ scsi_sense_data_type sense_format, int current_error,
+ int sense_key, int asc, int ascq, ...) ;
+void scsi_set_sense_data_va(struct scsi_sense_data *sense_data,
+ scsi_sense_data_type sense_format,
+ int current_error, int sense_key, int asc,
+ int ascq, va_list ap);
+int scsi_get_sense_info(struct scsi_sense_data *sense_data, u_int sense_len,
+ uint8_t info_type, uint64_t *info,
+ int64_t *signed_info);
+int scsi_get_sks(struct scsi_sense_data *sense_data, u_int sense_len,
+ uint8_t *sks);
+int scsi_get_block_info(struct scsi_sense_data *sense_data, u_int sense_len,
+ struct scsi_inquiry_data *inq_data,
+ uint8_t *block_bits);
+int scsi_get_stream_info(struct scsi_sense_data *sense_data, u_int sense_len,
+ struct scsi_inquiry_data *inq_data,
+ uint8_t *stream_bits);
+void scsi_info_sbuf(struct sbuf *sb, uint8_t *cdb, int cdb_len,
+ struct scsi_inquiry_data *inq_data, uint64_t info);
+void scsi_command_sbuf(struct sbuf *sb, uint8_t *cdb, int cdb_len,
+ struct scsi_inquiry_data *inq_data, uint64_t csi);
+void scsi_progress_sbuf(struct sbuf *sb, uint16_t progress);
+int scsi_sks_sbuf(struct sbuf *sb, int sense_key, uint8_t *sks);
+void scsi_fru_sbuf(struct sbuf *sb, uint64_t fru);
+void scsi_stream_sbuf(struct sbuf *sb, uint8_t stream_bits, uint64_t info);
+void scsi_block_sbuf(struct sbuf *sb, uint8_t block_bits, uint64_t info);
+void scsi_sense_info_sbuf(struct sbuf *sb, struct scsi_sense_data *sense,
+ u_int sense_len, uint8_t *cdb, int cdb_len,
+ struct scsi_inquiry_data *inq_data,
+ struct scsi_sense_desc_header *header);
+
+void scsi_sense_command_sbuf(struct sbuf *sb, struct scsi_sense_data *sense,
+ u_int sense_len, uint8_t *cdb, int cdb_len,
+ struct scsi_inquiry_data *inq_data,
+ struct scsi_sense_desc_header *header);
+void scsi_sense_sks_sbuf(struct sbuf *sb, struct scsi_sense_data *sense,
+ u_int sense_len, uint8_t *cdb, int cdb_len,
+ struct scsi_inquiry_data *inq_data,
+ struct scsi_sense_desc_header *header);
+void scsi_sense_fru_sbuf(struct sbuf *sb, struct scsi_sense_data *sense,
+ u_int sense_len, uint8_t *cdb, int cdb_len,
+ struct scsi_inquiry_data *inq_data,
+ struct scsi_sense_desc_header *header);
+void scsi_sense_stream_sbuf(struct sbuf *sb, struct scsi_sense_data *sense,
+ u_int sense_len, uint8_t *cdb, int cdb_len,
+ struct scsi_inquiry_data *inq_data,
+ struct scsi_sense_desc_header *header);
+void scsi_sense_block_sbuf(struct sbuf *sb, struct scsi_sense_data *sense,
+ u_int sense_len, uint8_t *cdb, int cdb_len,
+ struct scsi_inquiry_data *inq_data,
+ struct scsi_sense_desc_header *header);
+void scsi_sense_progress_sbuf(struct sbuf *sb, struct scsi_sense_data *sense,
+ u_int sense_len, uint8_t *cdb, int cdb_len,
+ struct scsi_inquiry_data *inq_data,
+ struct scsi_sense_desc_header *header);
+void scsi_sense_generic_sbuf(struct sbuf *sb, struct scsi_sense_data *sense,
+ u_int sense_len, uint8_t *cdb, int cdb_len,
+ struct scsi_inquiry_data *inq_data,
+ struct scsi_sense_desc_header *header);
+void scsi_sense_desc_sbuf(struct sbuf *sb, struct scsi_sense_data *sense,
+ u_int sense_len, uint8_t *cdb, int cdb_len,
+ struct scsi_inquiry_data *inq_data,
+ struct scsi_sense_desc_header *header);
+scsi_sense_data_type scsi_sense_type(struct scsi_sense_data *sense_data);
+
+void scsi_sense_only_sbuf(struct scsi_sense_data *sense, u_int sense_len,
+ struct sbuf *sb, char *path_str,
+ struct scsi_inquiry_data *inq_data, uint8_t *cdb,
+ int cdb_len);
+
#ifdef _KERNEL
int scsi_command_string(struct ccb_scsiio *csio, struct sbuf *sb);
int scsi_sense_sbuf(struct ccb_scsiio *csio, struct sbuf *sb,
@@ -1135,6 +2288,8 @@ int scsi_sense_sbuf(struct ccb_scsiio *csio, struct sbuf *sb,
char * scsi_sense_string(struct ccb_scsiio *csio,
char *str, int str_len);
void scsi_sense_print(struct ccb_scsiio *csio);
+int scsi_vpd_supported_page(struct cam_periph *periph,
+ uint8_t page_id);
#else /* _KERNEL */
int scsi_command_string(struct cam_device *device,
struct ccb_scsiio *csio, struct sbuf *sb);
@@ -1148,12 +2303,6 @@ void scsi_sense_print(struct cam_device *device,
struct ccb_scsiio *csio, FILE *ofile);
#endif /* _KERNEL */
-#define SF_RETRY_UA 0x01
-#define SF_NO_PRINT 0x02
-#define SF_QUIET_IR 0x04 /* Be quiet about Illegal Request reponses */
-#define SF_PRINT_ALWAYS 0x08
-
-
const char * scsi_op_desc(u_int16_t opcode,
struct scsi_inquiry_data *inq_data);
char * scsi_cdb_string(u_int8_t *cdb_ptr, char *cdb_string,
@@ -1163,7 +2312,18 @@ void scsi_print_inquiry(struct scsi_inquiry_data *inq_data);
u_int scsi_calc_syncsrate(u_int period_factor);
u_int scsi_calc_syncparam(u_int period);
-
+
+typedef int (*scsi_devid_checkfn_t)(uint8_t *);
+int scsi_devid_is_naa_ieee_reg(uint8_t *bufp);
+int scsi_devid_is_sas_target(uint8_t *bufp);
+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);
+struct scsi_vpd_id_descriptor *
+ scsi_get_devid(struct scsi_vpd_device_id *id, uint32_t len,
+ scsi_devid_checkfn_t ck_fn);
+
void scsi_test_unit_ready(struct ccb_scsiio *csio, u_int32_t retries,
void (*cbfcnp)(struct cam_periph *,
union ccb *),
@@ -1279,6 +2439,40 @@ void scsi_synchronize_cache(struct ccb_scsiio *csio,
u_int32_t begin_lba, u_int16_t lb_count,
u_int8_t sense_len, u_int32_t timeout);
+void scsi_receive_diagnostic_results(struct ccb_scsiio *csio, u_int32_t retries,
+ void (*cbfcnp)(struct cam_periph *,
+ union ccb*),
+ uint8_t tag_action, int pcv,
+ uint8_t page_code, uint8_t *data_ptr,
+ uint16_t allocation_length,
+ uint8_t sense_len, uint32_t timeout);
+
+void scsi_send_diagnostic(struct ccb_scsiio *csio, u_int32_t retries,
+ void (*cbfcnp)(struct cam_periph *, union ccb *),
+ uint8_t tag_action, int unit_offline,
+ int device_offline, int self_test, int page_format,
+ int self_test_code, uint8_t *data_ptr,
+ uint16_t param_list_length, uint8_t sense_len,
+ uint32_t timeout);
+
+void scsi_read_buffer(struct ccb_scsiio *csio, u_int32_t retries,
+ void (*cbfcnp)(struct cam_periph *, union ccb*),
+ uint8_t tag_action, int mode,
+ uint8_t buffer_id, u_int32_t offset,
+ uint8_t *data_ptr, uint32_t allocation_length,
+ uint8_t sense_len, uint32_t timeout);
+
+void scsi_write_buffer(struct ccb_scsiio *csio, u_int32_t retries,
+ void (*cbfcnp)(struct cam_periph *, union ccb *),
+ uint8_t tag_action, int mode,
+ uint8_t buffer_id, u_int32_t offset,
+ uint8_t *data_ptr, uint32_t param_list_length,
+ uint8_t sense_len, uint32_t timeout);
+
+#define SCSI_RW_READ 0x0001
+#define SCSI_RW_WRITE 0x0002
+#define SCSI_RW_DIRMASK 0x0003
+#define SCSI_RW_BIO 0x1000
void scsi_read_write(struct ccb_scsiio *csio, u_int32_t retries,
void (*cbfcnp)(struct cam_periph *, union ccb *),
u_int8_t tag_action, int readop, u_int8_t byte2,
@@ -1287,6 +2481,40 @@ void scsi_read_write(struct ccb_scsiio *csio, u_int32_t retries,
u_int32_t dxfer_len, u_int8_t sense_len,
u_int32_t timeout);
+void scsi_write_same(struct ccb_scsiio *csio, u_int32_t retries,
+ void (*cbfcnp)(struct cam_periph *, union ccb *),
+ u_int8_t tag_action, u_int8_t byte2,
+ int minimum_cmd_size, u_int64_t lba,
+ u_int32_t block_count, u_int8_t *data_ptr,
+ u_int32_t dxfer_len, u_int8_t sense_len,
+ u_int32_t timeout);
+
+void scsi_ata_identify(struct ccb_scsiio *csio, u_int32_t retries,
+ void (*cbfcnp)(struct cam_periph *, union ccb *),
+ u_int8_t tag_action, u_int8_t *data_ptr,
+ u_int16_t dxfer_len, u_int8_t sense_len,
+ u_int32_t timeout);
+
+void scsi_ata_trim(struct ccb_scsiio *csio, u_int32_t retries,
+ void (*cbfcnp)(struct cam_periph *, union ccb *),
+ u_int8_t tag_action, u_int16_t block_count,
+ u_int8_t *data_ptr, u_int16_t dxfer_len,
+ 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,
+ u_int8_t protocol, u_int8_t ata_flags, u_int16_t features,
+ u_int16_t sector_count, uint64_t lba, u_int8_t command,
+ u_int8_t control, u_int8_t *data_ptr, u_int16_t dxfer_len,
+ u_int8_t sense_len, u_int32_t timeout);
+
+void scsi_unmap(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_int8_t *data_ptr, u_int16_t dxfer_len,
+ u_int8_t sense_len, u_int32_t timeout);
+
void scsi_start_stop(struct ccb_scsiio *csio, u_int32_t retries,
void (*cbfcnp)(struct cam_periph *, union ccb *),
u_int8_t tag_action, int start, int load_eject,
@@ -1295,32 +2523,34 @@ void scsi_start_stop(struct ccb_scsiio *csio, u_int32_t retries,
int scsi_inquiry_match(caddr_t inqbuffer, caddr_t table_entry);
int scsi_static_inquiry_match(caddr_t inqbuffer,
caddr_t table_entry);
-
-static __inline void scsi_extract_sense(struct scsi_sense_data *sense,
- int *error_code, int *sense_key,
- int *asc, int *ascq);
+int scsi_devid_match(uint8_t *rhs, size_t rhs_len,
+ uint8_t *lhs, size_t lhs_len);
+
+void scsi_extract_sense(struct scsi_sense_data *sense, int *error_code,
+ int *sense_key, int *asc, int *ascq);
+int scsi_extract_sense_ccb(union ccb *ccb, int *error_code, int *sense_key,
+ int *asc, int *ascq);
+void scsi_extract_sense_len(struct scsi_sense_data *sense,
+ u_int sense_len, int *error_code, int *sense_key,
+ int *asc, int *ascq, int show_errors);
+int scsi_get_sense_key(struct scsi_sense_data *sense, u_int sense_len,
+ int show_errors);
+int scsi_get_asc(struct scsi_sense_data *sense, u_int sense_len,
+ int show_errors);
+int scsi_get_ascq(struct scsi_sense_data *sense, u_int sense_len,
+ int show_errors);
static __inline void scsi_ulto2b(u_int32_t val, u_int8_t *bytes);
static __inline void scsi_ulto3b(u_int32_t val, u_int8_t *bytes);
static __inline void scsi_ulto4b(u_int32_t val, u_int8_t *bytes);
static __inline void scsi_u64to8b(u_int64_t val, u_int8_t *bytes);
-static __inline u_int32_t scsi_2btoul(u_int8_t *bytes);
-static __inline u_int32_t scsi_3btoul(u_int8_t *bytes);
-static __inline int32_t scsi_3btol(u_int8_t *bytes);
-static __inline u_int32_t scsi_4btoul(u_int8_t *bytes);
-static __inline u_int64_t scsi_8btou64(u_int8_t *bytes);
+static __inline uint32_t scsi_2btoul(const uint8_t *bytes);
+static __inline uint32_t scsi_3btoul(const uint8_t *bytes);
+static __inline int32_t scsi_3btol(const uint8_t *bytes);
+static __inline uint32_t scsi_4btoul(const uint8_t *bytes);
+static __inline uint64_t scsi_8btou64(const uint8_t *bytes);
static __inline void *find_mode_page_6(struct scsi_mode_header_6 *mode_header);
static __inline void *find_mode_page_10(struct scsi_mode_header_10 *mode_header);
-static __inline void scsi_extract_sense(struct scsi_sense_data *sense,
- int *error_code, int *sense_key,
- int *asc, int *ascq)
-{
- *error_code = sense->error_code & SSD_ERRCODE;
- *sense_key = sense->flags & SSD_KEY;
- *asc = (sense->extra_len >= 5) ? sense->add_sense_code : 0;
- *ascq = (sense->extra_len >= 6) ? sense->add_sense_code_qual : 0;
-}
-
static __inline void
scsi_ulto2b(u_int32_t val, u_int8_t *bytes)
{
@@ -1362,20 +2592,20 @@ scsi_u64to8b(u_int64_t val, u_int8_t *bytes)
bytes[7] = val & 0xff;
}
-static __inline u_int32_t
-scsi_2btoul(u_int8_t *bytes)
+static __inline uint32_t
+scsi_2btoul(const uint8_t *bytes)
{
- u_int32_t rv;
+ uint32_t rv;
rv = (bytes[0] << 8) |
bytes[1];
return (rv);
}
-static __inline u_int32_t
-scsi_3btoul(u_int8_t *bytes)
+static __inline uint32_t
+scsi_3btoul(const uint8_t *bytes)
{
- u_int32_t rv;
+ uint32_t rv;
rv = (bytes[0] << 16) |
(bytes[1] << 8) |
@@ -1384,9 +2614,9 @@ scsi_3btoul(u_int8_t *bytes)
}
static __inline int32_t
-scsi_3btol(u_int8_t *bytes)
+scsi_3btol(const uint8_t *bytes)
{
- u_int32_t rc = scsi_3btoul(bytes);
+ uint32_t rc = scsi_3btoul(bytes);
if (rc & 0x00800000)
rc |= 0xff000000;
@@ -1394,10 +2624,10 @@ scsi_3btol(u_int8_t *bytes)
return (int32_t) rc;
}
-static __inline u_int32_t
-scsi_4btoul(u_int8_t *bytes)
+static __inline uint32_t
+scsi_4btoul(const uint8_t *bytes)
{
- u_int32_t rv;
+ uint32_t rv;
rv = (bytes[0] << 24) |
(bytes[1] << 16) |
@@ -1407,7 +2637,7 @@ scsi_4btoul(u_int8_t *bytes)
}
static __inline uint64_t
-scsi_8btou64(uint8_t *bytes)
+scsi_8btou64(const uint8_t *bytes)
{
uint64_t rv;
diff --git a/freebsd/sys/cam/scsi/scsi_da.h b/freebsd/sys/cam/scsi/scsi_da.h
index da099f69..57992381 100644
--- a/freebsd/sys/cam/scsi/scsi_da.h
+++ b/freebsd/sys/cam/scsi/scsi_da.h
@@ -111,6 +111,7 @@ struct scsi_read_defect_data_10
u_int8_t reserved[4];
u_int8_t alloc_length[2];
+#define SRDD10_MAX_LENGTH 0xffff
u_int8_t control;
};
@@ -421,6 +422,56 @@ union disk_pages /* this is the structure copied from osf */
} flexible_disk;
};
+/*
+ * XXX KDM
+ * Here for CTL compatibility, reconcile this.
+ */
+struct scsi_format_page {
+ uint8_t page_code;
+ uint8_t page_length;
+ uint8_t tracks_per_zone[2];
+ uint8_t alt_sectors_per_zone[2];
+ uint8_t alt_tracks_per_zone[2];
+ uint8_t alt_tracks_per_lun[2];
+ uint8_t sectors_per_track[2];
+ uint8_t bytes_per_sector[2];
+ uint8_t interleave[2];
+ uint8_t track_skew[2];
+ uint8_t cylinder_skew[2];
+ uint8_t flags;
+#define SFP_SSEC 0x80
+#define SFP_HSEC 0x40
+#define SFP_RMB 0x20
+#define SFP_SURF 0x10
+ uint8_t reserved[3];
+};
+
+/*
+ * XXX KDM
+ * Here for CTL compatibility, reconcile this.
+ */
+struct scsi_rigid_disk_page {
+ uint8_t page_code;
+#define SMS_RIGID_DISK_PAGE 0x04
+ uint8_t page_length;
+ uint8_t cylinders[3];
+ uint8_t heads;
+ uint8_t start_write_precomp[3];
+ uint8_t start_reduced_current[3];
+ uint8_t step_rate[2];
+ uint8_t landing_zone_cylinder[3];
+ uint8_t rpl;
+#define SRDP_RPL_DISABLED 0x00
+#define SRDP_RPL_SLAVE 0x01
+#define SRDP_RPL_MASTER 0x02
+#define SRDP_RPL_MASTER_CONTROL 0x03
+ uint8_t rotational_offset;
+ uint8_t reserved1;
+ uint8_t rotation_rate[2];
+ uint8_t reserved2[2];
+};
+
+
struct scsi_da_rw_recovery_page {
u_int8_t page_code;
#define SMS_RW_ERROR_RECOVERY_PAGE 0x01