diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2013-11-06 16:20:21 +0100 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2013-11-11 10:08:08 +0100 |
commit | 66659ff1ad6831b0ea7425fa6ecd8a8687523658 (patch) | |
tree | 48e22b475fa8854128e0861a33fed6f78c8094b5 /freebsd/sys/cam | |
parent | Define __GLOBL1() and __GLOBL() (diff) | |
download | rtems-libbsd-66659ff1ad6831b0ea7425fa6ecd8a8687523658.tar.bz2 |
Update to FreeBSD 9.2
Diffstat (limited to 'freebsd/sys/cam')
-rw-r--r-- | freebsd/sys/cam/ata/ata_all.h | 40 | ||||
-rw-r--r-- | freebsd/sys/cam/cam.c | 50 | ||||
-rw-r--r-- | freebsd/sys/cam/cam.h | 19 | ||||
-rw-r--r-- | freebsd/sys/cam/cam_ccb.h | 143 | ||||
-rw-r--r-- | freebsd/sys/cam/cam_periph.h | 48 | ||||
-rw-r--r-- | freebsd/sys/cam/cam_sim.h | 9 | ||||
-rw-r--r-- | freebsd/sys/cam/cam_xpt.h | 2 | ||||
-rw-r--r-- | freebsd/sys/cam/cam_xpt_sim.h | 4 | ||||
-rw-r--r-- | freebsd/sys/cam/scsi/scsi_all.c | 2466 | ||||
-rw-r--r-- | freebsd/sys/cam/scsi/scsi_all.h | 1392 | ||||
-rw-r--r-- | freebsd/sys/cam/scsi/scsi_da.h | 51 |
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 |