diff options
author | ken <ken@FreeBSD.org> | 2001-03-27 05:45:52 +0000 |
---|---|---|
committer | ken <ken@FreeBSD.org> | 2001-03-27 05:45:52 +0000 |
commit | 24c4b1e75b8af36f530a3eabf2d1a17810637a5f (patch) | |
tree | 922f780aaaef7c90e6112b8537c9a1b7abb5b0c7 /sys | |
parent | 37504f69c9fd5f7dee2b8de312ee783f169777a9 (diff) | |
download | FreeBSD-src-24c4b1e75b8af36f530a3eabf2d1a17810637a5f.zip FreeBSD-src-24c4b1e75b8af36f530a3eabf2d1a17810637a5f.tar.gz |
Rewrite of the CAM error recovery code.
Some of the major changes include:
- The SCSI error handling portion of cam_periph_error() has
been broken out into a number of subfunctions to better
modularize the code that handles the hierarchy of SCSI errors.
As a result, the code is now much easier to read.
- String handling and error printing has been significantly
revamped. We now use sbufs to do string formatting instead
of using printfs (for the kernel) and snprintf/strncat (for
userland) as before.
There is a new catchall error printing routine,
cam_error_print() and its string-based counterpart,
cam_error_string() that allow the kernel and userland
applications to pass in a CCB and have errors printed out
properly, whether or not they're SCSI errors. Among other
things, this helped eliminate a fair amount of duplicate code
in camcontrol.
We now print out more information than before, including
the CAM status and SCSI status and the error recovery action
taken to remedy the problem.
- sbufs are now available in userland, via libsbuf. This
change was necessary since most of the error printing code
is shared between libcam and the kernel.
- A new transfer settings interface is included in this checkin.
This code is #ifdef'ed out, and is primarily intended to aid
discussion with HBA driver authors on the final form the
interface should take. There is example code in the ahc(4)
driver that implements the HBA driver side of the new
interface. The new transfer settings code won't be enabled
until we're ready to switch all HBA drivers over to the new
interface.
src/Makefile.inc1,
lib/Makefile: Add libsbuf. It must be built before libcam,
since libcam uses sbuf routines.
libcam/Makefile: libcam now depends on libsbuf.
libsbuf/Makefile: Add a makefile for libsbuf. This pulls in the
sbuf sources from sys/kern.
bsd.libnames.mk: Add LIBSBUF.
camcontrol/Makefile: Add -lsbuf. Since camcontrol is statically
linked, we can't depend on the dynamic linker
to pull in libsbuf.
camcontrol.c: Use cam_error_print() instead of checking for
CAM_SCSI_STATUS_ERROR on every failed CCB.
sbuf.9: Change the prototypes for sbuf_cat() and
sbuf_cpy() so that the source string is now a
const char *. This is more in line wth the
standard system string functions, and helps
eliminate warnings when dealing with a const
source buffer.
Fix a typo.
cam.c: Add description strings for the various CAM
error status values, as well as routines to
look up those strings.
Add new cam_error_string() and
cam_error_print() routines for userland and
the kernel.
cam.h: Add a new CAM flag, CAM_RETRY_SELTO.
Add enumerated types for the various options
available with cam_error_print() and
cam_error_string().
cam_ccb.h: Add new transfer negotiation structures/types.
Change inq_len in the ccb_getdev structure to
be "reserved". This field has never been
filled in, and will be removed when we next
bump the CAM version.
cam_debug.h: Fix typo.
cam_periph.c: Modularize cam_periph_error(). The SCSI error
handling part of cam_periph_error() is now
in camperiphscsistatuserror() and
camperiphscsisenseerror().
In cam_periph_lock(), increase the reference
count on the periph while we wait for our lock
attempt to succeed so that the periph won't go
away while we're sleeping.
cam_xpt.c: Add new transfer negotiation code. (ifdefed
out)
Add a new function, xpt_path_string(). This
is a string/sbuf analog to xpt_print_path().
scsi_all.c: Revamp string handing and error printing code.
We now use sbufs for much of the string
formatting code. More of that code is shared
between userland the kernel.
scsi_all.h: Get rid of SS_TURSTART, it wasn't terribly
useful in the first place.
Add a new error action, SS_REQSENSE. (Send a
request sense and then retry the command.)
This is useful when the controller hasn't
performed autosense for some reason.
Change the default actions around a bit.
scsi_cd.c,
scsi_da.c,
scsi_pt.c,
scsi_ses.c: SF_RETRY_SELTO -> CAM_RETRY_SELTO. Selection
timeouts shouldn't be covered by a sense flag.
scsi_pass.[ch]: SF_RETRY_SELTO -> CAM_RETRY_SELTO.
Get rid of the last vestiges of a read/write
interface.
libkern/bsearch.c,
sys/libkern.h,
conf/files: Add bsearch.c, which is needed for some of the
new table lookup routines.
aic7xxx_freebsd.c: Define AHC_NEW_TRAN_SETTINGS if
CAM_NEW_TRAN_CODE is defined.
sbuf.h,
subr_sbuf.c: Add the appropriate #ifdefs so sbufs can
compile and run in userland.
Change sbuf_printf() to use vsnprintf()
instead of kvprintf(), which is only available
in the kernel.
Change the source string for sbuf_cpy() and
sbuf_cat() to be a const char *.
Add __BEGIN_DECLS and __END_DECLS around
function prototypes since they're now exported
to userland.
kdump/mkioctls: Include stdio.h before cam.h since cam.h now
includes a function with a FILE * argument.
Submitted by: gibbs (mostly)
Reviewed by: jdp, marcel (libsbuf makefile changes)
Reviewed by: des (sbuf changes)
Reviewed by: ken
Diffstat (limited to 'sys')
-rw-r--r-- | sys/cam/cam.c | 244 | ||||
-rw-r--r-- | sys/cam/cam.h | 58 | ||||
-rw-r--r-- | sys/cam/cam_ccb.h | 119 | ||||
-rw-r--r-- | sys/cam/cam_debug.h | 2 | ||||
-rw-r--r-- | sys/cam/cam_periph.c | 918 | ||||
-rw-r--r-- | sys/cam/cam_xpt.c | 636 | ||||
-rw-r--r-- | sys/cam/cam_xpt.h | 2 | ||||
-rw-r--r-- | sys/cam/scsi/scsi_all.c | 1834 | ||||
-rw-r--r-- | sys/cam/scsi/scsi_all.h | 94 | ||||
-rw-r--r-- | sys/cam/scsi/scsi_cd.c | 86 | ||||
-rw-r--r-- | sys/cam/scsi/scsi_ch.c | 55 | ||||
-rw-r--r-- | sys/cam/scsi/scsi_da.c | 119 | ||||
-rw-r--r-- | sys/cam/scsi/scsi_pass.c | 229 | ||||
-rw-r--r-- | sys/cam/scsi/scsi_pass.h | 4 | ||||
-rw-r--r-- | sys/cam/scsi/scsi_pt.c | 5 | ||||
-rw-r--r-- | sys/cam/scsi/scsi_sa.c | 12 | ||||
-rw-r--r-- | sys/cam/scsi/scsi_ses.c | 5 | ||||
-rw-r--r-- | sys/conf/files | 1 | ||||
-rw-r--r-- | sys/dev/aic7xxx/aic7xxx_freebsd.h | 3 | ||||
-rw-r--r-- | sys/dev/aic7xxx/aic7xxx_osm.h | 3 | ||||
-rw-r--r-- | sys/kern/subr_sbuf.c | 55 | ||||
-rw-r--r-- | sys/libkern/bsearch.c | 83 | ||||
-rw-r--r-- | sys/sys/libkern.h | 2 | ||||
-rw-r--r-- | sys/sys/sbuf.h | 6 |
24 files changed, 2669 insertions, 1906 deletions
diff --git a/sys/cam/cam.c b/sys/cam/cam.c index 4c28e42..3f410bb 100644 --- a/sys/cam/cam.c +++ b/sys/cam/cam.c @@ -29,7 +29,71 @@ */ #include <sys/param.h> +#ifdef _KERNEL +#include <sys/systm.h> +#else /* _KERNEL */ +#include <stdlib.h> +#include <stdio.h> +#endif /* _KERNEL */ + #include <cam/cam.h> +#include <cam/cam_ccb.h> +#include <cam/scsi/scsi_all.h> +#include <sys/sbuf.h> + +#ifdef _KERNEL +#include <sys/libkern.h> +#include <cam/cam_xpt.h> +#endif + +static int camstatusentrycomp(const void *key, const void *member); + +const struct cam_status_entry cam_status_table[] = { + { CAM_REQ_INPROG, "CCB request is in progress" }, + { CAM_REQ_CMP, "CCB request completed without error" }, + { CAM_REQ_ABORTED, "CCB request aborted by the host" }, + { CAM_UA_ABORT, "Unable to abort CCB request" }, + { CAM_REQ_CMP_ERR, "CCB request completed with an error" }, + { CAM_BUSY, "CAM subsytem is busy" }, + { CAM_REQ_INVALID, "CCB request was invalid" }, + { CAM_PATH_INVALID, "Supplied Path ID is invalid" }, + { CAM_DEV_NOT_THERE, "Device Not Present" }, + { CAM_UA_TERMIO, "Unable to terminate I/O CCB request" }, + { CAM_SEL_TIMEOUT, "Selection Timeout" }, + { CAM_CMD_TIMEOUT, "Command timeout" }, + { CAM_SCSI_STATUS_ERROR, "SCSI Status Error" }, + { CAM_MSG_REJECT_REC, "Message Reject Reveived" }, + { CAM_SCSI_BUS_RESET, "SCSI Bus Reset Sent/Received" }, + { CAM_UNCOR_PARITY, "Uncorrectable parity/CRC error" }, + { CAM_AUTOSENSE_FAIL, "Auto-Sense Retrieval Failed" }, + { CAM_NO_HBA, "No HBA Detected" }, + { CAM_DATA_RUN_ERR, "Data Overrun error" }, + { CAM_UNEXP_BUSFREE, "Unexpected Bus Free" }, + { CAM_SEQUENCE_FAIL, "Target Bus Phase Sequence Failure" }, + { CAM_CCB_LEN_ERR, "CCB length supplied is inadequate" }, + { CAM_PROVIDE_FAIL, "Unable to provide requested capability" }, + { CAM_BDR_SENT, "SCSI BDR Message Sent" }, + { CAM_REQ_TERMIO, "CCB request terminated by the host" }, + { CAM_UNREC_HBA_ERROR, "Unrecoverable Host Bus Adapter Error" }, + { CAM_REQ_TOO_BIG, "The request was too large for this host" }, + { CAM_REQUEUE_REQ, "Unconditionally Re-queue Request", }, + { CAM_IDE, "Initiator Detected Error Message Received" }, + { CAM_RESRC_UNAVAIL, "Resource Unavailable" }, + { CAM_UNACKED_EVENT, "Unacknowledged Event by Host" }, + { CAM_MESSAGE_RECV, "Message Received in Host Target Mode" }, + { CAM_INVALID_CDB, "Invalid CDB received in Host Target Mode" }, + { CAM_LUN_INVALID, "Invalid Lun" }, + { CAM_TID_INVALID, "Invalid Target ID" }, + { CAM_FUNC_NOTAVAIL, "Function Not Available" }, + { CAM_NO_NEXUS, "Nexus Not Established" }, + { CAM_IID_INVALID, "Invalid Initiator ID" }, + { CAM_CDB_RECVD, "CDB Received" }, + { CAM_LUN_ALRDY_ENA, "LUN Already Enabled for Target Mode" }, + { CAM_SCSI_BUSY, "SCSI Bus Busy" }, +}; + +const int num_cam_status_entries = + sizeof(cam_status_table)/sizeof(*cam_status_table); void cam_strvis(u_int8_t *dst, const u_int8_t *src, int srclen, int dstlen) @@ -107,3 +171,183 @@ cam_quirkmatch(caddr_t target, caddr_t quirk_table, int num_entries, } return (NULL); } + +const struct cam_status_entry* +cam_fetch_status_entry(cam_status status) +{ + status &= CAM_STATUS_MASK; + return (bsearch(&status, &cam_status_table, + num_cam_status_entries, + sizeof(*cam_status_table), + camstatusentrycomp)); +} + +static int +camstatusentrycomp(const void *key, const void *member) +{ + cam_status status; + const struct cam_status_entry *table_entry; + + status = *(const cam_status *)key; + table_entry = (const struct cam_status_entry *)member; + + return (status - table_entry->status_code); +} + + +#ifdef _KERNEL +char * +cam_error_string(union ccb *ccb, char *str, int str_len, + cam_error_string_flags flags, + cam_error_proto_flags proto_flags) +#else /* !_KERNEL */ +char * +cam_error_string(struct cam_device *device, union ccb *ccb, char *str, + int str_len, cam_error_string_flags flags, + cam_error_proto_flags proto_flags) +#endif /* _KERNEL/!_KERNEL */ +{ + char path_str[64]; + struct sbuf sb; + + if ((ccb == NULL) + || (str == NULL) + || (str_len <= 0)) + return(NULL); + + if (flags == CAM_ESF_NONE) + return(NULL); + + switch (ccb->ccb_h.func_code) { + case XPT_SCSI_IO: + switch (proto_flags & CAM_EPF_LEVEL_MASK) { + case CAM_EPF_NONE: + break; + case CAM_EPF_ALL: + case CAM_EPF_NORMAL: + proto_flags |= CAM_ESF_PRINT_SENSE; + /* FALLTHROUGH */ + case CAM_EPF_MINIMAL: + proto_flags |= CAM_ESF_PRINT_STATUS; + default: + break; + } + break; + default: + break; + } +#ifdef _KERNEL + xpt_path_string(ccb->csio.ccb_h.path, path_str, sizeof(path_str)); +#else /* !_KERNEL */ + cam_path_string(device, path_str, sizeof(path_str)); +#endif /* _KERNEL/!_KERNEL */ + + sbuf_new(&sb, str, str_len, 0); + + if (flags & CAM_ESF_COMMAND) { + + sbuf_cat(&sb, path_str); + + switch (ccb->ccb_h.func_code) { + case XPT_SCSI_IO: +#ifdef _KERNEL + scsi_command_string(&ccb->csio, &sb); +#else /* !_KERNEL */ + scsi_command_string(device, &ccb->csio, &sb); +#endif /* _KERNEL/!_KERNEL */ + sbuf_printf(&sb, "\n"); + + break; + default: + break; + } + } + + if (flags & CAM_ESF_CAM_STATUS) { + cam_status status; + const struct cam_status_entry *entry; + + sbuf_cat(&sb, path_str); + + status = ccb->ccb_h.status & CAM_STATUS_MASK; + + entry = cam_fetch_status_entry(status); + + if (entry == NULL) + sbuf_printf(&sb, "CAM Status: Unknown (%#x)\n", + ccb->ccb_h.status); + else + sbuf_printf(&sb, "CAM Status: %s\n", + entry->status_text); + } + + if (flags & CAM_ESF_PROTO_STATUS) { + + switch (ccb->ccb_h.func_code) { + case XPT_SCSI_IO: + if ((ccb->ccb_h.status & CAM_STATUS_MASK) != + CAM_SCSI_STATUS_ERROR) + break; + + if (proto_flags & CAM_ESF_PRINT_STATUS) { + sbuf_cat(&sb, path_str); + /* + * Print out the SCSI status byte as long as + * the user wants some protocol output. + */ + sbuf_printf(&sb, "SCSI Status: %s\n", + scsi_status_string(&ccb->csio)); + } + + if ((proto_flags & CAM_ESF_PRINT_SENSE) + && (ccb->csio.scsi_status == SCSI_STATUS_CHECK_COND) + && (ccb->ccb_h.status & CAM_AUTOSNS_VALID)) { + +#ifdef _KERNEL + scsi_sense_sbuf(&ccb->csio, &sb, + SSS_FLAG_NONE); +#else /* !_KERNEL */ + scsi_sense_sbuf(device, &ccb->csio, &sb, + SSS_FLAG_NONE); +#endif /* _KERNEL/!_KERNEL */ + } + break; + default: + break; + } + } + + sbuf_finish(&sb); + + return(sbuf_data(&sb)); +} + +#ifdef _KERNEL + +void +cam_error_print(union ccb *ccb, cam_error_string_flags flags, + cam_error_proto_flags proto_flags) +{ + char str[512]; + + printf("%s", cam_error_string(ccb, str, sizeof(str), flags, + proto_flags)); +} + +#else /* !_KERNEL */ + +void +cam_error_print(struct cam_device *device, union ccb *ccb, + cam_error_string_flags flags, cam_error_proto_flags proto_flags, + FILE *ofile) +{ + char str[512]; + + if ((device == NULL) || (ccb == NULL) || (ofile == NULL)) + return; + + fprintf(ofile, "%s", cam_error_string(device, ccb, str, sizeof(str), + flags, proto_flags)); +} + +#endif /* _KERNEL/!_KERNEL */ diff --git a/sys/cam/cam.h b/sys/cam/cam.h index 37e67fd..4aad13a 100644 --- a/sys/cam/cam.h +++ b/sys/cam/cam.h @@ -85,10 +85,11 @@ typedef struct { */ #define GENERATIONCMP(x, op, y) ((int32_t)((x) - (y)) op 0) -/* CAM flags */ +/* CAM flags XXX Move to cam_periph.h ??? */ typedef enum { CAM_FLAG_NONE = 0x00, - CAM_EXPECT_INQ_CHANGE = 0x01 + CAM_EXPECT_INQ_CHANGE = 0x01, + CAM_RETRY_SELTO = 0x02 /* Retry Selection Timeouts */ } cam_flags; /* CAM Status field values */ @@ -139,7 +140,7 @@ typedef enum { CAM_NO_NEXUS, /* Nexus is not established */ CAM_IID_INVALID, /* The initiator ID is invalid */ CAM_CDB_RECVD, /* The SCSI CDB has been received */ - CAM_LUN_ALRDY_ENA, /* The LUN is already eanbeld for target mode */ + CAM_LUN_ALRDY_ENA, /* The LUN is already enabled for target mode */ CAM_SCSI_BUSY, /* SCSI Bus Busy */ CAM_DEV_QFRZN = 0x40, /* The DEV queue is frozen w/this err */ @@ -155,6 +156,39 @@ typedef enum { CAM_SENT_SENSE = 0x40000000 /* sent sense with status */ } cam_status; +typedef enum { + CAM_ESF_NONE = 0x00, + CAM_ESF_COMMAND = 0x01, + CAM_ESF_CAM_STATUS = 0x02, + CAM_ESF_PROTO_STATUS = 0x04, + CAM_ESF_ALL = 0xff +} cam_error_string_flags; + +typedef enum { + CAM_EPF_NONE = 0x00, + CAM_EPF_MINIMAL = 0x01, + CAM_EPF_NORMAL = 0x02, + CAM_EPF_ALL = 0x03, + CAM_EPF_LEVEL_MASK = 0x0f + /* All bits above bit 3 are protocol-specific */ +} cam_error_proto_flags; + +typedef enum { + CAM_ESF_PRINT_NONE = 0x00, + CAM_ESF_PRINT_STATUS = 0x10, + CAM_ESF_PRINT_SENSE = 0x20 +} cam_error_scsi_flags; + +struct cam_status_entry +{ + cam_status status_code; + const char *status_text; +}; + +extern const struct cam_status_entry cam_status_table[]; +extern const int num_cam_status_entries; +union ccb; + __BEGIN_DECLS typedef int (cam_quirkmatch_t)(caddr_t, caddr_t); @@ -164,6 +198,24 @@ caddr_t cam_quirkmatch(caddr_t target, caddr_t quirk_table, int num_entries, void cam_strvis(u_int8_t *dst, const u_int8_t *src, int srclen, int dstlen); int cam_strmatch(const u_int8_t *str, const u_int8_t *pattern, int str_len); +const struct cam_status_entry* + cam_fetch_status_entry(cam_status status); +#ifdef _KERNEL +char * cam_error_string(union ccb *ccb, char *str, int str_len, + cam_error_string_flags flags, + cam_error_proto_flags proto_flags); +void cam_error_print(union ccb *ccb, cam_error_string_flags flags, + cam_error_proto_flags proto_flags); +#else /* _KERNEL */ +struct cam_device; + +char * cam_error_string(struct cam_device *device, union ccb *ccb, char *str, + int str_len, cam_error_string_flags flags, + cam_error_proto_flags proto_flags); +void cam_error_print(struct cam_device *device, union ccb *ccb, + cam_error_string_flags flags, + cam_error_proto_flags proto_flags, FILE *ofile); +#endif /* _KERNEL */ __END_DECLS #ifdef _KERNEL diff --git a/sys/cam/cam_ccb.h b/sys/cam/cam_ccb.h index 2184465..3a52f97 100644 --- a/sys/cam/cam_ccb.h +++ b/sys/cam/cam_ccb.h @@ -34,6 +34,9 @@ #include <sys/queue.h> #include <sys/cdefs.h> #include <sys/time.h> +#ifdef CAM_NEW_TRAN_CODE +#include <machine/limits.h> +#endif /* CAM_NEW_TRAN_CODE */ #ifndef _KERNEL #include <sys/callout.h> #endif @@ -172,7 +175,7 @@ typedef enum { /* HBA engine commands 0x20->0x2F */ XPT_ENG_INQ = 0x20 | XPT_FC_XPT_ONLY, /* HBA engine feature inquiry */ - XPT_ENG_EXEC = 0x21 | XPT_FC_DEV_QUEUED | XPT_FC_XPT_ONLY, + XPT_ENG_EXEC = 0x21 | XPT_FC_DEV_QUEUED, /* HBA execute engine request */ /* Target mode commands: 0x30->0x3F */ @@ -205,6 +208,33 @@ typedef enum { (((ccb)->ccb_h.func_code & XPT_FC_DEV_QUEUED) == XPT_FC_DEV_QUEUED) #define XPT_FC_IS_QUEUED(ccb) \ (((ccb)->ccb_h.func_code & XPT_FC_QUEUED) != 0) + +#ifdef CAM_NEW_TRAN_CODE +typedef enum { + PROTO_UNKNOWN, + PROTO_UNSPECIFIED, + PROTO_SCSI, /* Small Computer System Interface */ + PROTO_ATA, /* AT Attachment */ + PROTO_ATAPI, /* AT Attachment Packetized Interface */ +} cam_proto; + +typedef enum { + XPORT_UNKNOWN, + XPORT_UNSPECIFIED, + XPORT_SPI, /* SCSI Parallel Interface */ + XPORT_FC, /* Fiber Channel */ + XPORT_SSA, /* Serial Storage Architecture */ + XPORT_USB, /* Universal Serial Bus */ + XPORT_PPB, /* Parallel Port Bus */ + XPORT_ATA /* AT Attachment */ +} cam_xport; + +#define PROTO_VERSION_UNKNOWN (UINT_MAX - 1) +#define PROTO_VERSION_UNSPECIFIED UINT_MAX +#define XPORT_VERSION_UNKNOWN (UINT_MAX - 1) +#define XPORT_VERSION_UNSPECIFIED UINT_MAX +#endif /* CAM_NEW_TRAN_CODE */ + typedef union { LIST_ENTRY(ccb_hdr) le; SLIST_ENTRY(ccb_hdr) sle; @@ -257,7 +287,7 @@ struct ccb_getdev { struct ccb_hdr ccb_h; struct scsi_inquiry_data inq_data; u_int8_t serial_num[252]; - u_int8_t inq_len; + u_int8_t reserved; u_int8_t serial_num_len; }; @@ -486,7 +516,13 @@ typedef enum { PIM_NOBUSRESET = 0x10 /* User has disabled initial BUS RESET */ } pi_miscflag; +#ifdef CAM_NEW_TRAN_CODE /* Path Inquiry CCB */ +struct ccb_pathinq_settings_spi { + u_int8_t ppr_options; +}; +#endif /* CAM_NEW_TRAN_CODE */ + struct ccb_pathinq { struct ccb_hdr ccb_h; u_int8_t version_num; /* Version number for the SIM/HBA */ @@ -507,6 +543,15 @@ struct ccb_pathinq { u_int32_t unit_number; /* Unit number for SIM */ u_int32_t bus_id; /* Bus ID for SIM */ u_int32_t base_transfer_speed;/* Base bus speed in KB/sec */ +#ifdef CAM_NEW_TRAN_CODE + cam_proto protocol; + u_int protocol_version; + cam_xport transport; + u_int transport_version; + union { + struct ccb_pathinq_settings_spi spi; + } xport_specific; +#endif /* CAM_NEW_TRAN_CODE */ }; /* Path Statistics CCB */ @@ -644,25 +689,77 @@ struct ccb_termio { union ccb *termio_ccb; /* Pointer to CCB to terminate */ }; +#ifndef CAM_NEW_TRAN_CODE /* Get/Set transfer rate/width/disconnection/tag queueing settings */ struct ccb_trans_settings { struct ccb_hdr ccb_h; + u_int valid; /* Which fields to honor */ +#define CCB_TRANS_SYNC_RATE_VALID 0x01 +#define CCB_TRANS_SYNC_OFFSET_VALID 0x02 +#define CCB_TRANS_BUS_WIDTH_VALID 0x04 +#define CCB_TRANS_DISC_VALID 0x08 +#define CCB_TRANS_TQ_VALID 0x10 + u_int flags; +#define CCB_TRANS_CURRENT_SETTINGS 0x01 +#define CCB_TRANS_USER_SETTINGS 0x02 +#define CCB_TRANS_DISC_ENB 0x04 +#define CCB_TRANS_TAG_ENB 0x08 + u_int sync_period; + u_int sync_offset; + u_int bus_width; +}; + +#else /* CAM_NEW_TRAN_CODE */ +typedef enum { + CTS_TYPE_CURRENT_SETTINGS, + CTS_TYPE_USER_SETTINGS +} cts_type; + +struct ccb_trans_settings_scsi +{ u_int valid; /* Which fields to honor */ -#define CCB_TRANS_SYNC_RATE_VALID 0x01 -#define CCB_TRANS_SYNC_OFFSET_VALID 0x02 -#define CCB_TRANS_BUS_WIDTH_VALID 0x04 -#define CCB_TRANS_DISC_VALID 0x08 -#define CCB_TRANS_TQ_VALID 0x10 +#define CTS_SCSI_VALID_TQ 0x01 + u_int flags; +#define CTS_SCSI_FLAGS_TAG_ENB 0x01 +}; + +struct ccb_trans_settings_spi +{ + u_int valid; /* Which fields to honor */ +#define CTS_SPI_VALID_SYNC_RATE 0x01 +#define CTS_SPI_VALID_SYNC_OFFSET 0x02 +#define CTS_SPI_VALID_BUS_WIDTH 0x04 +#define CTS_SPI_VALID_DISC 0x08 +#define CTS_SPI_VALID_PPR_OPTIONS 0x10 u_int flags; -#define CCB_TRANS_CURRENT_SETTINGS 0x01 -#define CCB_TRANS_USER_SETTINGS 0x02 -#define CCB_TRANS_DISC_ENB 0x04 -#define CCB_TRANS_TAG_ENB 0x08 +#define CTS_SPI_FLAGS_DISC_ENB 0x01 +#define CTS_SPI_FLAGS_TAG_ENB 0x02 u_int sync_period; u_int sync_offset; u_int bus_width; + u_int ppr_options; }; +/* Get/Set transfer rate/width/disconnection/tag queueing settings */ +struct ccb_trans_settings { + struct ccb_hdr ccb_h; + cts_type type; /* Current or User settings */ + cam_proto protocol; + u_int protocol_version; + cam_xport transport; + u_int transport_version; + union { + u_int valid; /* Which fields to honor */ + struct ccb_trans_settings_scsi scsi; + } proto_specific; + union { + u_int valid; /* Which fields to honor */ + struct ccb_trans_settings_spi spi; + } xport_specific; +}; + +#endif /* CAM_NEW_TRAN_CODE */ + /* * Calculate the geometry parameters for a device * give the block size and volume size in blocks. diff --git a/sys/cam/cam_debug.h b/sys/cam/cam_debug.h index 22c56c6..b393f76 100644 --- a/sys/cam/cam_debug.h +++ b/sys/cam/cam_debug.h @@ -53,7 +53,7 @@ typedef enum { extern struct cam_path *cam_dpath; /* Current debug levels set */ extern u_int32_t cam_dflags; -/* Printf delay value (to prevent scrolling */ +/* Printf delay value (to prevent scrolling) */ extern u_int32_t cam_debug_delay; /* Debugging macros. */ diff --git a/sys/cam/cam_periph.c b/sys/cam/cam_periph.c index eba1787..ee6eace 100644 --- a/sys/cam/cam_periph.c +++ b/sys/cam/cam_periph.c @@ -62,6 +62,20 @@ static u_int camperiphunit(struct periph_driver *p_drv, static void camperiphdone(struct cam_periph *periph, union ccb *done_ccb); static void camperiphfree(struct cam_periph *periph); +static int camperiphscsistatuserror(union ccb *ccb, + cam_flags camflags, + u_int32_t sense_flags, + union ccb *save_ccb, + int *openings, + u_int32_t *relsim_flags, + u_int32_t *timeout); +static int camperiphscsisenseerror(union ccb *ccb, + cam_flags camflags, + u_int32_t sense_flags, + union ccb *save_ccb, + int *openings, + u_int32_t *relsim_flags, + u_int32_t *timeout); static int nperiph_drivers; struct periph_driver **periph_drivers; @@ -473,15 +487,23 @@ cam_periph_lock(struct cam_periph *periph, int priority) { int error; + /* + * Increment the reference count on the peripheral + * while we wait for our lock attempt to succeed + * to ensure the peripheral doesn't dissappear + * out from under us while we sleep. + */ + if (cam_periph_acquire(periph) != CAM_REQ_CMP) + return(ENXIO); + while ((periph->flags & CAM_PERIPH_LOCKED) != 0) { periph->flags |= CAM_PERIPH_LOCK_WANTED; - if ((error = tsleep(periph, priority, "caplck", 0)) != 0) + if ((error = tsleep(periph, priority, "caplck", 0)) != 0) { + cam_periph_release(periph); return error; + } } - if (cam_periph_acquire(periph) != CAM_REQ_CMP) - return(ENXIO); - periph->flags |= CAM_PERIPH_LOCKED; return 0; } @@ -891,13 +913,16 @@ cam_release_devq(struct cam_path *path, u_int32_t relsim_flags, static void camperiphdone(struct cam_periph *periph, union ccb *done_ccb) { + union ccb *saved_ccb; cam_status status; int frozen; int sense; struct scsi_start_stop_unit *scsi_cmd; u_int32_t relsim_flags, timeout; u_int32_t qfrozen_cnt; + int xpt_done_ccb; + xpt_done_ccb = FALSE; status = done_ccb->ccb_h.status; frozen = (status & CAM_DEV_QFRZN) != 0; sense = (status & CAM_AUTOSNS_VALID) != 0; @@ -905,6 +930,7 @@ camperiphdone(struct cam_periph *periph, union ccb *done_ccb) timeout = 0; relsim_flags = 0; + saved_ccb = (union ccb *)done_ccb->ccb_h.saved_ccb_ptr; /* * Unfreeze the queue once if it is already frozen.. @@ -918,15 +944,19 @@ camperiphdone(struct cam_periph *periph, union ccb *done_ccb) } switch (status) { - case CAM_REQ_CMP: - + { /* * If we have successfully taken a device from the not - * ready to ready state, re-scan the device and re-get the - * inquiry information. Many devices (mostly disks) don't - * properly report their inquiry information unless they - * are spun up. + * ready to ready state, re-scan the device and re-get + * the inquiry information. Many devices (mostly disks) + * don't properly report their inquiry information unless + * they are spun up. + * + * If we manually retrieved sense into a CCB and got + * something other than "NO SENSE" send the updated CCB + * back to the client via xpt_done() to be processed via + * the error recovery code again. */ if (done_ccb->ccb_h.func_code == XPT_SCSI_IO) { scsi_cmd = (struct scsi_start_stop_unit *) @@ -935,15 +965,35 @@ camperiphdone(struct cam_periph *periph, union ccb *done_ccb) if (scsi_cmd->opcode == START_STOP_UNIT) xpt_async(AC_INQ_CHANGED, done_ccb->ccb_h.path, NULL); + if (scsi_cmd->opcode == REQUEST_SENSE) { + u_int sense_key; + + sense_key = saved_ccb->csio.sense_data.flags; + sense_key &= SSD_KEY; + if (sense_key != SSD_KEY_NO_SENSE) { + saved_ccb->ccb_h.flags |= + CAM_AUTOSNS_VALID; + xpt_print_path(saved_ccb->ccb_h.path); + printf("Recovered Sense\n"); +#if 0 + scsi_sense_print(&saved_ccb->csio); +#endif + cam_error_print(saved_ccb, CAM_ESF_ALL, + CAM_EPF_ALL); + xpt_done_ccb = TRUE; + } + } } bcopy(done_ccb->ccb_h.saved_ccb_ptr, done_ccb, sizeof(union ccb)); periph->flags &= ~CAM_PERIPH_RECOVERY_INPROG; - xpt_action(done_ccb); + if (xpt_done_ccb == FALSE) + xpt_action(done_ccb); break; + } case CAM_SCSI_STATUS_ERROR: scsi_cmd = (struct scsi_start_stop_unit *) &done_ccb->csio.cdb_io.cdb_bytes; @@ -982,7 +1032,7 @@ camperiphdone(struct cam_periph *periph, union ccb *done_ccb) xpt_action(done_ccb); - } else if (done_ccb->ccb_h.retry_count > 0) { + } else if (done_ccb->ccb_h.retry_count > 1) { /* * In this case, the error recovery * command failed, but we've got @@ -1001,8 +1051,9 @@ camperiphdone(struct cam_periph *periph, union ccb *done_ccb) } else { /* - * Copy the original CCB back and - * send it back to the caller. + * Perform the final retry with the original + * CCB so that final error processing is + * performed by the owner of the CCB. */ bcopy(done_ccb->ccb_h.saved_ccb_ptr, done_ccb, sizeof(union ccb)); @@ -1039,6 +1090,13 @@ camperiphdone(struct cam_periph *periph, union ccb *done_ccb) } /* decrement the retry count */ + /* + * XXX This isn't appropriate in all cases. Restructure, + * so that the retry count is only decremented on an + * actual retry. Remeber that the orignal ccb had its + * retry count dropped before entering recovery, so + * doing it again is a bug. + */ if (done_ccb->ccb_h.retry_count > 0) done_ccb->ccb_h.retry_count--; @@ -1047,6 +1105,8 @@ camperiphdone(struct cam_periph *periph, union ccb *done_ccb) /*openings*/0, /*timeout*/timeout, /*getcount_only*/0); + if (xpt_done_ccb == TRUE) + (*done_ccb->ccb_h.cbfcnp)(periph, done_ccb); } /* @@ -1113,469 +1173,370 @@ cam_periph_freeze_after_event(struct cam_periph *periph, } -/* - * Generic error handler. Peripheral drivers usually filter - * out the errors that they handle in a unique mannor, then - * call this function. - */ -int -cam_periph_error(union ccb *ccb, cam_flags camflags, - u_int32_t sense_flags, union ccb *save_ccb) +static int +camperiphscsistatuserror(union ccb *ccb, cam_flags camflags, + u_int32_t sense_flags, union ccb *save_ccb, + int *openings, u_int32_t *relsim_flags, + u_int32_t *timeout) { - cam_status status; - int frozen; - int sense; - int error; - int openings; - int retry; - u_int32_t relsim_flags; - u_int32_t timeout; - - status = ccb->ccb_h.status; - frozen = (status & CAM_DEV_QFRZN) != 0; - sense = (status & CAM_AUTOSNS_VALID) != 0; - status &= CAM_STATUS_MASK; - relsim_flags = 0; + int error; - switch (status) { - case CAM_REQ_CMP: - /* decrement the number of retries */ - retry = ccb->ccb_h.retry_count > 0; - if (retry) - ccb->ccb_h.retry_count--; + switch (ccb->csio.scsi_status) { + case SCSI_STATUS_OK: + case SCSI_STATUS_COND_MET: + case SCSI_STATUS_INTERMED: + case SCSI_STATUS_INTERMED_COND_MET: error = 0; break; - case CAM_AUTOSENSE_FAIL: - case CAM_SCSI_STATUS_ERROR: + case SCSI_STATUS_CMD_TERMINATED: + case SCSI_STATUS_CHECK_COND: + error = camperiphscsisenseerror(ccb, + camflags, + sense_flags, + save_ccb, + openings, + relsim_flags, + timeout); + break; + case SCSI_STATUS_QUEUE_FULL: + { + /* no decrement */ + struct ccb_getdevstats cgds; - switch (ccb->csio.scsi_status) { - case SCSI_STATUS_OK: - case SCSI_STATUS_COND_MET: - case SCSI_STATUS_INTERMED: - case SCSI_STATUS_INTERMED_COND_MET: - error = 0; - break; - case SCSI_STATUS_CMD_TERMINATED: - case SCSI_STATUS_CHECK_COND: - if (sense != 0) { - struct scsi_sense_data *sense; - int error_code, sense_key, asc, ascq; - struct cam_periph *periph; - scsi_sense_action err_action; - struct ccb_getdev cgd; - - sense = &ccb->csio.sense_data; - scsi_extract_sense(sense, &error_code, - &sense_key, &asc, &ascq); - periph = xpt_path_periph(ccb->ccb_h.path); + /* + * First off, find out what the current + * transaction counts are. + */ + xpt_setup_ccb(&cgds.ccb_h, + ccb->ccb_h.path, + /*priority*/1); + cgds.ccb_h.func_code = XPT_GDEV_STATS; + xpt_action((union ccb *)&cgds); + + /* + * If we were the only transaction active, treat + * the QUEUE FULL as if it were a BUSY condition. + */ + if (cgds.dev_active != 0) { + int total_openings; + /* + * Reduce the number of openings to + * be 1 less than the amount it took + * to get a queue full bounded by the + * minimum allowed tag count for this + * device. + */ + total_openings = cgds.dev_active + cgds.dev_openings; + *openings = cgds.dev_active; + if (*openings < cgds.mintags) + *openings = cgds.mintags; + if (*openings < total_openings) + *relsim_flags = RELSIM_ADJUST_OPENINGS; + else { /* - * Grab the inquiry data for this device. + * Some devices report queue full for + * temporary resource shortages. For + * this reason, we allow a minimum + * tag count to be entered via a + * quirk entry to prevent the queue + * count on these devices from falling + * to a pessimisticly low value. We + * still wait for the next successful + * completion, however, before queueing + * more transactions to the device. */ - xpt_setup_ccb(&cgd.ccb_h, ccb->ccb_h.path, - /*priority*/ 1); - cgd.ccb_h.func_code = XPT_GDEV_TYPE; - xpt_action((union ccb *)&cgd); + *relsim_flags = RELSIM_RELEASE_AFTER_CMDCMPLT; + } + *timeout = 0; + error = ERESTART; + break; + } + /* FALLTHROUGH */ + } + case SCSI_STATUS_BUSY: + /* + * Restart the queue after either another + * command completes or a 1 second timeout. + */ + if (ccb->ccb_h.retry_count > 0) { + ccb->ccb_h.retry_count--; + error = ERESTART; + *relsim_flags = RELSIM_RELEASE_AFTER_TIMEOUT + | RELSIM_RELEASE_AFTER_CMDCMPLT; + *timeout = 1000; + } else { + error = EIO; + } + break; + case SCSI_STATUS_RESERV_CONFLICT: + error = EIO; + break; + default: + error = EIO; + break; + } + return (error); +} - err_action = scsi_error_action(asc, ascq, - &cgd.inq_data); +static int +camperiphscsisenseerror(union ccb *ccb, cam_flags camflags, + u_int32_t sense_flags, union ccb *save_ccb, + int *openings, u_int32_t *relsim_flags, + u_int32_t *timeout) +{ + struct cam_periph *periph; + int error; - /* - * Send a Test Unit Ready to the device. - * If the 'many' flag is set, we send 120 - * test unit ready commands, one every half - * second. Otherwise, we just send one TUR. - * We only want to do this if the retry - * count has not been exhausted. - */ - if (((err_action & SS_MASK) == SS_TUR) - && save_ccb != NULL - && ccb->ccb_h.retry_count > 0) { - - /* - * Since error recovery is already - * in progress, don't attempt to - * process this error. It is probably - * related to the error that caused - * the currently active error recovery - * action. Also, we only have - * space for one saved CCB, so if we - * had two concurrent error recovery - * actions, we would end up - * over-writing one error recovery - * CCB with another one. - */ - if (periph->flags & - CAM_PERIPH_RECOVERY_INPROG) { - error = ERESTART; - break; - } - - periph->flags |= - CAM_PERIPH_RECOVERY_INPROG; - - /* decrement the number of retries */ - if ((err_action & - SSQ_DECREMENT_COUNT) != 0) { - retry = 1; - ccb->ccb_h.retry_count--; - } - - bcopy(ccb, save_ccb, sizeof(*save_ccb)); - - /* - * We retry this one every half - * second for a minute. If the - * device hasn't become ready in a - * minute's time, it's unlikely to - * ever become ready. If the table - * doesn't specify SSQ_MANY, we can - * only try this once. Oh well. - */ - if ((err_action & SSQ_MANY) != 0) - scsi_test_unit_ready(&ccb->csio, - /*retries*/120, - camperiphdone, - MSG_SIMPLE_Q_TAG, - SSD_FULL_SIZE, - /*timeout*/5000); - else - scsi_test_unit_ready(&ccb->csio, - /*retries*/1, - camperiphdone, - MSG_SIMPLE_Q_TAG, - SSD_FULL_SIZE, - /*timeout*/5000); - - /* release the queue after .5 sec. */ - relsim_flags = - RELSIM_RELEASE_AFTER_TIMEOUT; - timeout = 500; - /* - * Drop the priority to 0 so that - * we are the first to execute. Also - * freeze the queue after this command - * is sent so that we can restore the - * old csio and have it queued in the - * proper order before we let normal - * transactions go to the drive. - */ - ccb->ccb_h.pinfo.priority = 0; - ccb->ccb_h.flags |= CAM_DEV_QFREEZE; - - /* - * Save a pointer to the original - * CCB in the new CCB. - */ - ccb->ccb_h.saved_ccb_ptr = save_ccb; - - error = ERESTART; - } - /* - * Send a start unit command to the device, - * and then retry the command. We only - * want to do this if the retry count has - * not been exhausted. If the user - * specified 0 retries, then we follow - * their request and do not retry. - */ - else if (((err_action & SS_MASK) == SS_START) - && save_ccb != NULL - && ccb->ccb_h.retry_count > 0) { - int le; - - /* - * Only one error recovery action - * at a time. See above. - */ - if (periph->flags & - CAM_PERIPH_RECOVERY_INPROG) { - error = ERESTART; - break; - } - - periph->flags |= - CAM_PERIPH_RECOVERY_INPROG; - - /* decrement the number of retries */ - retry = 1; - ccb->ccb_h.retry_count--; - - /* - * Check for removable media and - * set load/eject flag - * appropriately. - */ - if (SID_IS_REMOVABLE(&cgd.inq_data)) - le = TRUE; - else - le = FALSE; - - /* - * Attempt to start the drive up. - * - * Save the current ccb so it can - * be restored and retried once the - * drive is started up. - */ - bcopy(ccb, save_ccb, sizeof(*save_ccb)); - - scsi_start_stop(&ccb->csio, - /*retries*/1, - camperiphdone, - MSG_SIMPLE_Q_TAG, - /*start*/TRUE, - /*load/eject*/le, - /*immediate*/FALSE, - SSD_FULL_SIZE, - /*timeout*/50000); - /* - * Drop the priority to 0 so that - * we are the first to execute. Also - * freeze the queue after this command - * is sent so that we can restore the - * old csio and have it queued in the - * proper order before we let normal - * transactions go to the drive. - */ - ccb->ccb_h.pinfo.priority = 0; - ccb->ccb_h.flags |= CAM_DEV_QFREEZE; - - /* - * Save a pointer to the original - * CCB in the new CCB. - */ - ccb->ccb_h.saved_ccb_ptr = save_ccb; - - error = ERESTART; - } else if ((sense_flags & SF_RETRY_UA) != 0) { - /* - * XXX KDM this is a *horrible* - * hack. - */ - error = scsi_interpret_sense(ccb, - sense_flags, - &relsim_flags, - &openings, - &timeout, - err_action); - } + periph = xpt_path_periph(ccb->ccb_h.path); + if (periph->flags & CAM_PERIPH_RECOVERY_INPROG) { - /* - * Theoretically, this code should send a - * test unit ready to the given device, and - * if it returns and error, send a start - * unit command. Since we don't yet have - * the capability to do two-command error - * recovery, just send a start unit. - * XXX KDM fix this! - */ - else if (((err_action & SS_MASK) == SS_TURSTART) - && save_ccb != NULL - && ccb->ccb_h.retry_count > 0) { - int le; - - /* - * Only one error recovery action - * at a time. See above. - */ - if (periph->flags & - CAM_PERIPH_RECOVERY_INPROG) { - error = ERESTART; - break; - } - - periph->flags |= - CAM_PERIPH_RECOVERY_INPROG; - - /* decrement the number of retries */ - retry = 1; - ccb->ccb_h.retry_count--; - - /* - * Check for removable media and - * set load/eject flag - * appropriately. - */ - if (SID_IS_REMOVABLE(&cgd.inq_data)) - le = TRUE; - else - le = FALSE; - - /* - * Attempt to start the drive up. - * - * Save the current ccb so it can - * be restored and retried once the - * drive is started up. - */ - bcopy(ccb, save_ccb, sizeof(*save_ccb)); - - scsi_start_stop(&ccb->csio, - /*retries*/1, - camperiphdone, - MSG_SIMPLE_Q_TAG, - /*start*/TRUE, - /*load/eject*/le, - /*immediate*/FALSE, - SSD_FULL_SIZE, - /*timeout*/50000); - - /* release the queue after .5 sec. */ - relsim_flags = - RELSIM_RELEASE_AFTER_TIMEOUT; - timeout = 500; - /* - * Drop the priority to 0 so that - * we are the first to execute. Also - * freeze the queue after this command - * is sent so that we can restore the - * old csio and have it queued in the - * proper order before we let normal - * transactions go to the drive. - */ - ccb->ccb_h.pinfo.priority = 0; - ccb->ccb_h.flags |= CAM_DEV_QFREEZE; - - /* - * Save a pointer to the original - * CCB in the new CCB. - */ - ccb->ccb_h.saved_ccb_ptr = save_ccb; - - error = ERESTART; - } else { - error = scsi_interpret_sense(ccb, - sense_flags, - &relsim_flags, - &openings, - &timeout, - err_action); - } - } else if (ccb->csio.scsi_status == - SCSI_STATUS_CHECK_COND - && status != CAM_AUTOSENSE_FAIL) { - /* no point in decrementing the retry count */ - panic("cam_periph_error: scsi status of " - "CHECK COND returned but no sense " - "information is availible. " - "Controller should have returned " - "CAM_AUTOSENSE_FAILED"); - /* NOTREACHED */ - error = EIO; - } else if (ccb->ccb_h.retry_count == 0) { - /* - * XXX KDM shouldn't there be a better - * argument to return?? - */ - error = EIO; - } else { - /* decrement the number of retries */ - retry = ccb->ccb_h.retry_count > 0; - if (retry) - ccb->ccb_h.retry_count--; - /* - * If it was aborted with no - * clue as to the reason, just - * retry it again. - */ - error = ERESTART; + /* + * If error recovery is already in progress, don't attempt + * to process this error, but requeue it unconditionally + * and attempt to process it once error recovery has + * completed. This failed command is probably related to + * the error that caused the currently active error recovery + * action so our current recovery efforts should also + * address this command. Be aware that the error recovery + * code assumes that only one recovery action is in progress + * on a particular peripheral instance at any given time + * (e.g. only one saved CCB for error recovery) so it is + * imperitive that we don't violate this assumption. + */ + error = ERESTART; + } else { + scsi_sense_action err_action; + struct ccb_getdev cgd; + const char *action_string; + union ccb* print_ccb; + + /* A description of the error recovery action performed */ + action_string = NULL; + + /* + * The location of the orignal ccb + * for sense printing purposes. + */ + print_ccb = ccb; + + /* + * Grab the inquiry data for this device. + */ + xpt_setup_ccb(&cgd.ccb_h, ccb->ccb_h.path, /*priority*/ 1); + cgd.ccb_h.func_code = XPT_GDEV_TYPE; + xpt_action((union ccb *)&cgd); + + if ((ccb->ccb_h.status & CAM_AUTOSNS_VALID) != 0) + err_action = scsi_error_action(&ccb->csio, + &cgd.inq_data, + sense_flags); + else if ((ccb->ccb_h.flags & CAM_DIS_AUTOSENSE) == 0) + err_action = SS_REQSENSE; + else + err_action = SS_RETRY|SSQ_DECREMENT_COUNT|EIO; + + error = err_action & SS_ERRMASK; + + /* + * If the recovery action will consume a retry, + * make sure we actually have retries available. + */ + if ((err_action & SSQ_DECREMENT_COUNT) != 0) { + if (ccb->ccb_h.retry_count > 0) + ccb->ccb_h.retry_count--; + else { + action_string = "Retries Exhausted"; + goto sense_error_done; + } + } + + if ((err_action & SS_MASK) >= SS_START) { + /* + * Do common portions of commands that + * use recovery CCBs. + */ + if (save_ccb == NULL) { + action_string = "No recovery CCB supplied"; + goto sense_error_done; } + bcopy(ccb, save_ccb, sizeof(*save_ccb)); + print_ccb = save_ccb; + periph->flags |= CAM_PERIPH_RECOVERY_INPROG; + } + + switch (err_action & SS_MASK) { + case SS_NOP: + case SS_RETRY: + action_string = "Retrying Command"; + error = ERESTART; break; - case SCSI_STATUS_QUEUE_FULL: + case SS_FAIL: + action_string = "Unretryable error"; + break; + case SS_START: { - /* no decrement */ - struct ccb_getdevstats cgds; + int le; /* - * First off, find out what the current - * transaction counts are. + * Send a start unit command to the device, and + * then retry the command. */ - xpt_setup_ccb(&cgds.ccb_h, - ccb->ccb_h.path, - /*priority*/1); - cgds.ccb_h.func_code = XPT_GDEV_STATS; - xpt_action((union ccb *)&cgds); + action_string = "Attempting to Start Unit"; /* - * If we were the only transaction active, treat - * the QUEUE FULL as if it were a BUSY condition. + * Check for removable media and set + * load/eject flag appropriately. */ - if (cgds.dev_active != 0) { - int total_openings; - - /* - * Reduce the number of openings to - * be 1 less than the amount it took - * to get a queue full bounded by the - * minimum allowed tag count for this - * device. - */ - total_openings = - cgds.dev_active+cgds.dev_openings; - openings = cgds.dev_active; - if (openings < cgds.mintags) - openings = cgds.mintags; - if (openings < total_openings) - relsim_flags = RELSIM_ADJUST_OPENINGS; - else { - /* - * Some devices report queue full for - * temporary resource shortages. For - * this reason, we allow a minimum - * tag count to be entered via a - * quirk entry to prevent the queue - * count on these devices from falling - * to a pessimisticly low value. We - * still wait for the next successful - * completion, however, before queueing - * more transactions to the device. - */ - relsim_flags = - RELSIM_RELEASE_AFTER_CMDCMPLT; - } - timeout = 0; - error = ERESTART; - break; - } - /* FALLTHROUGH */ + if (SID_IS_REMOVABLE(&cgd.inq_data)) + le = TRUE; + else + le = FALSE; + + scsi_start_stop(&ccb->csio, + /*retries*/1, + camperiphdone, + MSG_SIMPLE_Q_TAG, + /*start*/TRUE, + /*load/eject*/le, + /*immediate*/FALSE, + SSD_FULL_SIZE, + /*timeout*/50000); + break; } - case SCSI_STATUS_BUSY: + case SS_TUR: + { /* - * Restart the queue after either another - * command completes or a 1 second timeout. - * If we have any retries left, that is. + * Send a Test Unit Ready to the device. + * If the 'many' flag is set, we send 120 + * test unit ready commands, one every half + * second. Otherwise, we just send one TUR. + * We only want to do this if the retry + * count has not been exhausted. */ - retry = ccb->ccb_h.retry_count > 0; - if (retry) { - ccb->ccb_h.retry_count--; - error = ERESTART; - relsim_flags = RELSIM_RELEASE_AFTER_TIMEOUT - | RELSIM_RELEASE_AFTER_CMDCMPLT; - timeout = 1000; + int retries; + + if ((err_action & SSQ_MANY) != 0) { + action_string = "Polling device for readiness"; + retries = 120; } else { - error = EIO; + action_string = "Testing device for readiness"; + retries = 1; } + scsi_test_unit_ready(&ccb->csio, + retries, + camperiphdone, + MSG_SIMPLE_Q_TAG, + SSD_FULL_SIZE, + /*timeout*/5000); + + /* + * Accomplish our 500ms delay by deferring + * the release of our device queue appropriately. + */ + *relsim_flags = RELSIM_RELEASE_AFTER_TIMEOUT; + *timeout = 500; break; - case SCSI_STATUS_RESERV_CONFLICT: - error = EIO; + } + case SS_REQSENSE: + { + /* + * Send a Request Sense to the device. We + * assume that we are in a contingent allegiance + * condition so we do not tag this request. + */ + scsi_request_sense(&ccb->csio, /*retries*/1, + camperiphdone, + &save_ccb->csio.sense_data, + sizeof(save_ccb->csio.sense_data), + CAM_TAG_ACTION_NONE, + /*sense_len*/SSD_FULL_SIZE, + /*timeout*/5000); break; + } default: - error = EIO; - break; + panic("Unhandled error action %x\n", err_action); + } + + if ((err_action & SS_MASK) >= SS_START) { + /* + * Drop the priority to 0 so that the recovery + * CCB is the first to execute. Freeze the queue + * after this command is sent so that we can + * restore the old csio and have it queued in + * the proper order before we release normal + * transactions to the device. + */ + ccb->ccb_h.pinfo.priority = 0; + ccb->ccb_h.flags |= CAM_DEV_QFREEZE; + ccb->ccb_h.saved_ccb_ptr = save_ccb; + error = ERESTART; } + +sense_error_done: + if ((err_action & SSQ_PRINT_SENSE) != 0 + && (ccb->ccb_h.status & CAM_AUTOSNS_VALID) != 0) { +#if 0 + scsi_sense_print(&print_ccb->csio); +#endif + cam_error_print(print_ccb, CAM_ESF_ALL, CAM_EPF_ALL); + xpt_print_path(ccb->ccb_h.path); + printf("%s\n", action_string); + } + } + return (error); +} + +/* + * Generic error handler. Peripheral drivers usually filter + * out the errors that they handle in a unique mannor, then + * call this function. + */ +int +cam_periph_error(union ccb *ccb, cam_flags camflags, + u_int32_t sense_flags, union ccb *save_ccb) +{ + const char *action_string; + cam_status status; + int frozen; + int error; + int openings; + u_int32_t relsim_flags; + u_int32_t timeout; + + action_string = NULL; + status = ccb->ccb_h.status; + frozen = (status & CAM_DEV_QFRZN) != 0; + status &= CAM_STATUS_MASK; + relsim_flags = 0; + + switch (status) { + case CAM_REQ_CMP: + error = 0; break; + case CAM_SCSI_STATUS_ERROR: + error = camperiphscsistatuserror(ccb, + camflags, + sense_flags, + save_ccb, + &openings, + &relsim_flags, + &timeout); + break; + case CAM_AUTOSENSE_FAIL: + xpt_print_path(ccb->ccb_h.path); + printf("AutoSense Failed\n"); case CAM_REQ_CMP_ERR: case CAM_CMD_TIMEOUT: case CAM_UNEXP_BUSFREE: case CAM_UNCOR_PARITY: case CAM_DATA_RUN_ERR: /* decrement the number of retries */ - retry = ccb->ccb_h.retry_count > 0; - if (retry) { + if (ccb->ccb_h.retry_count > 0) { ccb->ccb_h.retry_count--; error = ERESTART; } else { + action_string = "Retries Exausted"; error = EIO; } break; @@ -1587,46 +1548,37 @@ cam_periph_error(union ccb *ccb, cam_flags camflags, break; case CAM_SEL_TIMEOUT: { - /* - * XXX - * A single selection timeout should not be enough - * to invalidate a device. We should retry for multiple - * seconds assuming this isn't a probe. We'll probably - * need a special flag for that. - */ -#if 0 struct cam_path *newpath; + if ((camflags & CAM_RETRY_SELTO) != 0) { + if (ccb->ccb_h.retry_count > 0) { + + ccb->ccb_h.retry_count--; + error = ERESTART; + + /* + * Wait a second to give the device + * time to recover before we try again. + */ + relsim_flags = RELSIM_RELEASE_AFTER_TIMEOUT; + timeout = 1000; + break; + } + } + error = ENXIO; /* Should we do more if we can't create the path?? */ if (xpt_create_path(&newpath, xpt_path_periph(ccb->ccb_h.path), xpt_path_path_id(ccb->ccb_h.path), xpt_path_target_id(ccb->ccb_h.path), CAM_LUN_WILDCARD) != CAM_REQ_CMP) break; + /* * Let peripheral drivers know that this device has gone * away. */ xpt_async(AC_LOST_DEVICE, newpath, NULL); xpt_free_path(newpath); -#endif - if ((sense_flags & SF_RETRY_SELTO) != 0) { - retry = ccb->ccb_h.retry_count > 0; - if (retry) { - ccb->ccb_h.retry_count--; - error = ERESTART; - /* - * Wait half a second to give the device - * time to recover before we try again. - */ - relsim_flags = RELSIM_RELEASE_AFTER_TIMEOUT; - timeout = 500; - } else { - error = ENXIO; - } - } else { - error = ENXIO; - } break; } case CAM_REQ_INVALID: @@ -1634,13 +1586,22 @@ cam_periph_error(union ccb *ccb, cam_flags camflags, case CAM_DEV_NOT_THERE: case CAM_NO_HBA: case CAM_PROVIDE_FAIL: - case CAM_REQ_TOO_BIG: + case CAM_REQ_TOO_BIG: error = EINVAL; break; case CAM_SCSI_BUS_RESET: - case CAM_BDR_SENT: + case CAM_BDR_SENT: + /* + * Commands that repeatedly timeout and cause these + * kinds of error recovery actions, should return + * CAM_CMD_TIMEOUT, which allows us to safely assume + * that this command was an innocent bystander to + * these events and should be unconditionally + * retried. + */ + /* FALLTHROUGH */ case CAM_REQUEUE_REQ: - /* Unconditional requeue, dammit */ + /* Unconditional requeue */ error = ERESTART; break; case CAM_RESRC_UNAVAIL: @@ -1648,13 +1609,12 @@ cam_periph_error(union ccb *ccb, cam_flags camflags, /* timeout??? */ default: /* decrement the number of retries */ - retry = ccb->ccb_h.retry_count > 0; - if (retry) { + if (ccb->ccb_h.retry_count > 0) { ccb->ccb_h.retry_count--; error = ERESTART; } else { - /* Check the sense codes */ error = EIO; + action_string = "Retries Exhausted"; } break; } @@ -1664,18 +1624,30 @@ cam_periph_error(union ccb *ccb, cam_flags camflags, if (frozen != 0) ccb->ccb_h.status &= ~CAM_DEV_QFRZN; - if (error == ERESTART) + if (error == ERESTART) { + action_string = "Retrying Command"; xpt_action(ccb); + } - if (frozen != 0) { + if (frozen != 0) cam_release_devq(ccb->ccb_h.path, relsim_flags, openings, timeout, /*getcount_only*/0); - } } + if (error != 0 && bootverbose) { + + if (action_string == NULL) + action_string = "Unretryable Error"; + if (error != ERESTART) { + xpt_print_path(ccb->ccb_h.path); + printf("error %d\n", error); + } + xpt_print_path(ccb->ccb_h.path); + printf("%s\n", action_string); + } return (error); } diff --git a/sys/cam/cam_xpt.c b/sys/cam/cam_xpt.c index 5163d20..d1ddf2a 100644 --- a/sys/cam/cam_xpt.c +++ b/sys/cam/cam_xpt.c @@ -40,6 +40,7 @@ #include <sys/md5.h> #include <sys/devicestat.h> #include <sys/interrupt.h> +#include <sys/sbuf.h> #ifdef PC98 #include <pc98/pc98/pc98_machdep.h> /* geometry translation */ @@ -122,7 +123,13 @@ struct cam_ed { struct cam_periph *owner; /* Peripheral driver's ownership tag */ struct xpt_quirk_entry *quirk; /* Oddities about this device */ /* Storage for the inquiry data */ - struct scsi_inquiry_data inq_data; +#ifdef CAM_NEW_TRAN_CODE + cam_proto protocol; + u_int protocol_version; + cam_xport transport; + u_int transport_version; +#endif /* CAM_NEW_TRAN_CODE */ + struct scsi_inquiry_data inq_data; u_int8_t inq_flags; /* * Current settings for inquiry flags. * This allows us to override settings @@ -131,7 +138,7 @@ struct cam_ed { */ u_int8_t queue_flags; /* Queue flags from the control page */ u_int8_t serial_num_len; - u_int8_t *serial_num; + u_int8_t *serial_num; u_int32_t qfrozen_cnt; u_int32_t flags; #define CAM_DEV_UNCONFIGURED 0x01 @@ -718,11 +725,12 @@ static void xptasync(struct cam_periph *periph, u_int32_t code, cam_path *path); #endif static dev_match_ret xptbusmatch(struct dev_match_pattern *patterns, - int num_patterns, struct cam_eb *bus); + u_int num_patterns, struct cam_eb *bus); static dev_match_ret xptdevicematch(struct dev_match_pattern *patterns, - int num_patterns, struct cam_ed *device); + u_int num_patterns, + struct cam_ed *device); static dev_match_ret xptperiphmatch(struct dev_match_pattern *patterns, - int num_patterns, + u_int num_patterns, struct cam_periph *periph); static xpt_busfunc_t xptedtbusfunc; static xpt_targetfunc_t xptedttargetfunc; @@ -776,6 +784,9 @@ static void proberequestdefaultnegotiation(struct cam_periph *periph); static void probedone(struct cam_periph *periph, union ccb *done_ccb); static void probecleanup(struct cam_periph *periph); static void xpt_find_quirk(struct cam_ed *device); +#ifdef CAM_NEW_TRAN_CODE +static void xpt_devise_transport(struct cam_path *path); +#endif /* CAM_NEW_TRAN_CODE */ static void xpt_set_transfer_settings(struct ccb_trans_settings *cts, struct cam_ed *device, int async_update); @@ -1129,8 +1140,8 @@ xptioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) struct cam_periph *periph; struct periph_driver **p_drv; char *name; - int unit; - int cur_generation; + u_int unit; + u_int cur_generation; int base_periph_found; int splbreaknum; int s; @@ -1464,6 +1475,118 @@ xpt_remove_periph(struct cam_periph *periph) } +#ifdef CAM_NEW_TRAN_CODE + +void +xpt_announce_periph(struct cam_periph *periph, char *announce_string) +{ + struct ccb_pathinq cpi; + struct ccb_trans_settings cts; + struct cam_path *path; + u_int speed; + u_int freq; + u_int mb; + int s; + + path = periph->path; + /* + * To ensure that this is printed in one piece, + * mask out CAM interrupts. + */ + s = splsoftcam(); + printf("%s%d at %s%d bus %d target %d lun %d\n", + periph->periph_name, periph->unit_number, + path->bus->sim->sim_name, + path->bus->sim->unit_number, + path->bus->sim->bus_id, + path->target->target_id, + path->device->lun_id); + printf("%s%d: ", periph->periph_name, periph->unit_number); + scsi_print_inquiry(&path->device->inq_data); + if ((bootverbose) + && (path->device->serial_num_len > 0)) { + /* Don't wrap the screen - print only the first 60 chars */ + printf("%s%d: Serial Number %.60s\n", periph->periph_name, + periph->unit_number, path->device->serial_num); + } + xpt_setup_ccb(&cts.ccb_h, path, /*priority*/1); + cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; + cts.type = CTS_TYPE_CURRENT_SETTINGS; + xpt_action((union ccb*)&cts); + + /* Ask the SIM for its base transfer speed */ + xpt_setup_ccb(&cpi.ccb_h, path, /*priority*/1); + cpi.ccb_h.func_code = XPT_PATH_INQ; + xpt_action((union ccb *)&cpi); + + speed = cpi.base_transfer_speed; + freq = 0; + if (cts.ccb_h.status == CAM_REQ_CMP + && cts.transport == XPORT_SPI) { + struct ccb_trans_settings_spi *spi; + + spi = &cts.xport_specific.spi; + if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0 + && spi->sync_offset != 0) { + freq = scsi_calc_syncsrate(spi->sync_period); + speed = freq; + } + + if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) + speed *= (0x01 << spi->bus_width); + } + + mb = speed / 1000; + if (mb > 0) + printf("%s%d: %d.%03dMB/s transfers", + periph->periph_name, periph->unit_number, + mb, speed % 1000); + else + printf("%s%d: %dKB/s transfers", periph->periph_name, + periph->unit_number, speed); + /* Report additional information about SPI connections */ + if (cts.ccb_h.status == CAM_REQ_CMP + && cts.transport == XPORT_SPI) { + struct ccb_trans_settings_spi *spi; + + spi = &cts.xport_specific.spi; + if (freq != 0) { + printf(" (%d.%03dMHz%s, offset %d", freq / 1000, + freq % 1000, + (spi->ppr_options & MSG_EXT_PPR_DT_REQ) != 0 + ? " DT" : "", + spi->sync_offset); + } + if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0 + && spi->bus_width > 0) { + if (freq != 0) { + printf(", "); + } else { + printf(" ("); + } + printf("%dbit)", 8 * (0x01 << spi->bus_width)); + } else if (freq != 0) { + printf(")"); + } + } + + if (path->device->inq_flags & SID_CmdQue + || path->device->flags & CAM_DEV_TAG_AFTER_COUNT) { + printf("\n%s%d: Tagged Queueing Enabled", + periph->periph_name, periph->unit_number); + } + printf("\n"); + + /* + * We only want to print the caller's announce string if they've + * passed one in.. + */ + if (announce_string != NULL) + printf("%s%d: %s\n", periph->periph_name, + periph->unit_number, announce_string); + splx(s); +} +#else /* CAM_NEW_TRAN_CODE */ void xpt_announce_periph(struct cam_periph *periph, char *announce_string) { @@ -1567,9 +1690,10 @@ xpt_announce_periph(struct cam_periph *periph, char *announce_string) splx(s); } +#endif /* CAM_NEW_TRAN_CODE */ static dev_match_ret -xptbusmatch(struct dev_match_pattern *patterns, int num_patterns, +xptbusmatch(struct dev_match_pattern *patterns, u_int num_patterns, struct cam_eb *bus) { dev_match_ret retval; @@ -1681,7 +1805,7 @@ xptbusmatch(struct dev_match_pattern *patterns, int num_patterns, } static dev_match_ret -xptdevicematch(struct dev_match_pattern *patterns, int num_patterns, +xptdevicematch(struct dev_match_pattern *patterns, u_int num_patterns, struct cam_ed *device) { dev_match_ret retval; @@ -1797,7 +1921,7 @@ xptdevicematch(struct dev_match_pattern *patterns, int num_patterns, * Match a single peripheral against any number of match patterns. */ static dev_match_ret -xptperiphmatch(struct dev_match_pattern *patterns, int num_patterns, +xptperiphmatch(struct dev_match_pattern *patterns, u_int num_patterns, struct cam_periph *periph) { dev_match_ret retval; @@ -2778,6 +2902,9 @@ xpt_action(union ccb *start_ccb) switch (start_ccb->ccb_h.func_code) { case XPT_SCSI_IO: { +#ifdef CAM_NEW_TRAN_CODE + struct cam_ed *device; +#endif /* CAM_NEW_TRAN_CODE */ #ifdef CAMDEBUG char cdb_str[(SCSI_MAX_CDBLEN * 3) + 1]; struct cam_path *path; @@ -2801,7 +2928,12 @@ xpt_action(union ccb *start_ccb) * This means that this code will be exercised while probing * devices with an ANSI revision greater than 2. */ +#ifdef CAM_NEW_TRAN_CODE + device = start_ccb->ccb_h.path->device; + if (device->protocol_version <= SCSI_REV_2 +#else /* CAM_NEW_TRAN_CODE */ if (SID_ANSI_REV(&start_ccb->ccb_h.path->device->inq_data) <= 2 +#endif /* CAM_NEW_TRAN_CODE */ && start_ccb->ccb_h.target_lun < 8 && (start_ccb->ccb_h.flags & CAM_CDB_POINTER) == 0) { @@ -3023,7 +3155,7 @@ xpt_action(union ccb *start_ccb) struct cam_periph *nperiph; struct periph_list *periph_head; struct ccb_getdevlist *cgdl; - int i; + u_int i; int s; struct cam_ed *device; int found; @@ -3115,7 +3247,7 @@ xpt_action(union ccb *start_ccb) if (cdm->pos.position_type != CAM_DEV_POS_NONE) position_type = cdm->pos.position_type; else { - int i; + u_int i; position_type = CAM_DEV_POS_NONE; @@ -3980,6 +4112,44 @@ xpt_print_path(struct cam_path *path) } } +int +xpt_path_string(struct cam_path *path, char *str, size_t str_len) +{ + struct sbuf sb; + + sbuf_new(&sb, str, str_len, 0); + + if (path == NULL) + sbuf_printf(&sb, "(nopath): "); + else { + if (path->periph != NULL) + sbuf_printf(&sb, "(%s%d:", path->periph->periph_name, + path->periph->unit_number); + else + sbuf_printf(&sb, "(noperiph:"); + + if (path->bus != NULL) + sbuf_printf(&sb, "%s%d:%d:", path->bus->sim->sim_name, + path->bus->sim->unit_number, + path->bus->sim->bus_id); + else + sbuf_printf(&sb, "nobus:"); + + if (path->target != NULL) + sbuf_printf(&sb, "%d:", path->target->target_id); + else + sbuf_printf(&sb, "X:"); + + if (path->device != NULL) + sbuf_printf(&sb, "%d): ", path->device->lun_id); + else + sbuf_printf(&sb, "X): "); + } + sbuf_finish(&sb); + + return(sbuf_len(&sb)); +} + path_id_t xpt_path_path_id(struct cam_path *path) { @@ -4115,7 +4285,7 @@ xpt_bus_register(struct cam_sim *sim, u_int32_t bus) xpt_setup_ccb(&cpi.ccb_h, &path, /*priority*/1); cpi.ccb_h.func_code = XPT_PATH_INQ; xpt_action((union ccb *)&cpi); - xpt_async(AC_PATH_REGISTERED, xpt_periph->path, &cpi); + xpt_async(AC_PATH_REGISTERED, &path, &cpi); xpt_release_path(&path); } return (CAM_SUCCESS); @@ -4693,6 +4863,9 @@ xpt_release_target(struct cam_eb *bus, struct cam_et *target) static struct cam_ed * xpt_alloc_device(struct cam_eb *bus, struct cam_et *target, lun_id_t lun_id) { +#ifdef CAM_NEW_TRAN_CODE + struct cam_path path; +#endif /* CAM_NEW_TRAN_CODE */ struct cam_ed *device; struct cam_devq *devq; cam_status status; @@ -4769,6 +4942,17 @@ xpt_alloc_device(struct cam_eb *bus, struct cam_et *target, lun_id_t lun_id) TAILQ_INSERT_TAIL(&target->ed_entries, device, links); } target->generation++; +#ifdef CAM_NEW_TRAN_CODE + if (lun_id != CAM_LUN_WILDCARD) { + xpt_compile_path(&path, + NULL, + bus->path_id, + target->target_id, + lun_id); + xpt_devise_transport(&path); + xpt_release_path(&path); + } +#endif /* CAM_NEW_TRAN_CODE */ } return (device); } @@ -4964,10 +5148,6 @@ xpt_scan_bus(struct cam_periph *periph, union ccb *request_ccb) work_ccb->ccb_h.cbfcnp = xpt_scan_bus; work_ccb->ccb_h.ppriv_ptr0 = scan_info; work_ccb->crcn.flags = request_ccb->crcn.flags; -#if 0 - printf("xpt_scan_bus: probing %d:%d:%d\n", - request_ccb->ccb_h.path_id, i, 0); -#endif xpt_action(work_ccb); } break; @@ -4990,11 +5170,6 @@ xpt_scan_bus(struct cam_periph *periph, union ccb *request_ccb) lun_id = request_ccb->ccb_h.target_lun; xpt_action(request_ccb); -#if 0 - printf("xpt_scan_bus: got back probe from %d:%d:%d\n", - path_id, target_id, lun_id); -#endif - if (request_ccb->ccb_h.status != CAM_REQ_CMP) { struct cam_ed *device; struct cam_et *target; @@ -5087,10 +5262,6 @@ xpt_scan_bus(struct cam_periph *periph, union ccb *request_ccb) request_ccb->ccb_h.ppriv_ptr0 = scan_info; request_ccb->crcn.flags = scan_info->request_ccb->crcn.flags; -#if 0 - xpt_print_path(path); - printf("xpt_scan bus probing\n"); -#endif xpt_action(request_ccb); } break; @@ -5468,11 +5639,19 @@ proberequestdefaultnegotiation(struct cam_periph *periph) xpt_setup_ccb(&cts.ccb_h, periph->path, /*priority*/1); cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; +#ifdef CAM_NEW_TRAN_CODE + cts.type = CTS_TYPE_USER_SETTINGS; +#else /* CAM_NEW_TRAN_CODE */ cts.flags = CCB_TRANS_USER_SETTINGS; +#endif /* CAM_NEW_TRAN_CODE */ xpt_action((union ccb *)&cts); cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; +#ifdef CAM_NEW_TRAN_CODE + cts.type = CTS_TYPE_CURRENT_SETTINGS; +#else /* CAM_NEW_TRAN_CODE */ cts.flags &= ~CCB_TRANS_USER_SETTINGS; cts.flags |= CCB_TRANS_CURRENT_SETTINGS; +#endif /* CAM_NEW_TRAN_CODE */ xpt_action((union ccb *)&cts); } @@ -5550,6 +5729,9 @@ probedone(struct cam_periph *periph, union ccb *done_ccb) xpt_find_quirk(path->device); +#ifdef CAM_NEW_TRAN_CODE + xpt_devise_transport(path); +#endif /* CAM_NEW_TRAN_CODE */ if ((inq_buf->flags & SID_CmdQue) != 0) softc->action = PROBE_MODE_SENSE; @@ -5788,6 +5970,379 @@ xpt_find_quirk(struct cam_ed *device) device->quirk = (struct xpt_quirk_entry *)match; } +#ifdef CAM_NEW_TRAN_CODE + +static void +xpt_devise_transport(struct cam_path *path) +{ + struct ccb_pathinq cpi; + struct ccb_trans_settings cts; + struct scsi_inquiry_data *inq_buf; + + /* Get transport information from the SIM */ + xpt_setup_ccb(&cpi.ccb_h, path, /*priority*/1); + cpi.ccb_h.func_code = XPT_PATH_INQ; + xpt_action((union ccb *)&cpi); + + inq_buf = NULL; + if ((path->device->flags & CAM_DEV_INQUIRY_DATA_VALID) != 0) + inq_buf = &path->device->inq_data; + path->device->protocol = PROTO_SCSI; + path->device->protocol_version = + inq_buf != NULL ? SID_ANSI_REV(inq_buf) : cpi.protocol_version; + path->device->transport = cpi.transport; + path->device->transport_version = cpi.transport_version; + + /* + * Any device not using SPI3 features should + * be considered SPI2 or lower. + */ + if (inq_buf != NULL) { + if (path->device->transport == XPORT_SPI + && (inq_buf->spi3data & SID_SPI_MASK) == 0 + && path->device->transport_version > 2) + path->device->transport_version = 2; + } else { + struct cam_ed* otherdev; + + for (otherdev = TAILQ_FIRST(&path->target->ed_entries); + otherdev != NULL; + otherdev = TAILQ_NEXT(otherdev, links)) { + if (otherdev != path->device) + break; + } + + if (otherdev != NULL) { + /* + * Initially assume the same versioning as + * prior luns for this target. + */ + path->device->protocol_version = + otherdev->protocol_version; + path->device->transport_version = + otherdev->transport_version; + } else { + /* Until we know better, opt for safty */ + path->device->protocol_version = 2; + if (path->device->transport == XPORT_SPI) + path->device->transport_version = 2; + else + path->device->transport_version = 0; + } + } + + /* + * XXX + * For a device compliant with SPC-2 we should be able + * to determine the transport version supported by + * scrutinizing the version descriptors in the + * inquiry buffer. + */ + + /* Tell the controller what we think */ + xpt_setup_ccb(&cts.ccb_h, path, /*priority*/1); + cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; + cts.type = CTS_TYPE_CURRENT_SETTINGS; + cts.transport = path->device->transport; + cts.transport_version = path->device->transport_version; + cts.protocol = path->device->protocol; + cts.protocol_version = path->device->protocol_version; + cts.proto_specific.valid = 0; + cts.xport_specific.valid = 0; + xpt_action((union ccb *)&cts); +} + +static void +xpt_set_transfer_settings(struct ccb_trans_settings *cts, struct cam_ed *device, + int async_update) +{ + struct ccb_pathinq cpi; + struct ccb_trans_settings cur_cts; + struct ccb_trans_settings_scsi *scsi; + struct ccb_trans_settings_scsi *cur_scsi; + struct cam_sim *sim; + struct scsi_inquiry_data *inq_data; + + if (device == NULL) { + cts->ccb_h.status = CAM_PATH_INVALID; + xpt_done((union ccb *)cts); + return; + } + + if (cts->protocol == PROTO_UNKNOWN + || cts->protocol == PROTO_UNSPECIFIED) { + cts->protocol = device->protocol; + cts->protocol_version = device->protocol_version; + } + + if (cts->protocol_version == PROTO_VERSION_UNKNOWN + || cts->protocol_version == PROTO_VERSION_UNSPECIFIED) + cts->protocol_version = device->protocol_version; + + if (cts->protocol != device->protocol) { + xpt_print_path(cts->ccb_h.path); + printf("Uninitialized Protocol %x:%x?\n", + cts->protocol, device->protocol); + cts->protocol = device->protocol; + } + + if (cts->protocol_version > device->protocol_version) { + if (bootverbose) { + xpt_print_path(cts->ccb_h.path); + printf("Down reving Protocol Version from %d to %d?\n", + cts->protocol_version, device->protocol_version); + } + cts->protocol_version = device->protocol_version; + } + + if (cts->transport == XPORT_UNKNOWN + || cts->transport == XPORT_UNSPECIFIED) { + cts->transport = device->transport; + cts->transport_version = device->transport_version; + } + + if (cts->transport_version == XPORT_VERSION_UNKNOWN + || cts->transport_version == XPORT_VERSION_UNSPECIFIED) + cts->transport_version = device->transport_version; + + if (cts->transport != device->transport) { + xpt_print_path(cts->ccb_h.path); + printf("Uninitialized Transport %x:%x?\n", + cts->transport, device->transport); + cts->transport = device->transport; + } + + if (cts->transport_version > device->transport_version) { + if (bootverbose) { + xpt_print_path(cts->ccb_h.path); + printf("Down reving Transport Version from %d to %d?\n", + cts->transport_version, + device->transport_version); + } + cts->transport_version = device->transport_version; + } + + sim = cts->ccb_h.path->bus->sim; + + /* + * Nothing more of interest to do unless + * this is a device connected via the + * SCSI protocol. + */ + if (cts->protocol != PROTO_SCSI) { + if (async_update == FALSE) + (*(sim->sim_action))(sim, (union ccb *)cts); + return; + } + + inq_data = &device->inq_data; + scsi = &cts->proto_specific.scsi; + xpt_setup_ccb(&cpi.ccb_h, cts->ccb_h.path, /*priority*/1); + cpi.ccb_h.func_code = XPT_PATH_INQ; + xpt_action((union ccb *)&cpi); + + /* SCSI specific sanity checking */ + if ((cpi.hba_inquiry & PI_TAG_ABLE) == 0 + || (inq_data->flags & SID_CmdQue) == 0 + || (device->queue_flags & SCP_QUEUE_DQUE) != 0 + || (device->quirk->mintags == 0)) { + /* + * Can't tag on hardware that doesn't support tags, + * doesn't have it enabled, or has broken tag support. + */ + scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; + } + + if (async_update == FALSE) { + /* + * Perform sanity checking against what the + * controller and device can do. + */ + xpt_setup_ccb(&cur_cts.ccb_h, cts->ccb_h.path, /*priority*/1); + cur_cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; + cur_cts.type = cts->type; + xpt_action((union ccb *)&cur_cts); + + cur_scsi = &cur_cts.proto_specific.scsi; + if ((scsi->valid & CTS_SCSI_VALID_TQ) == 0) { + scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; + scsi->flags |= cur_scsi->flags & CTS_SCSI_FLAGS_TAG_ENB; + } + if ((cur_scsi->valid & CTS_SCSI_VALID_TQ) == 0) + scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; + } + + /* SPI specific sanity checking */ + if (cts->transport == XPORT_SPI + && async_update == FALSE) { + u_int spi3caps; + struct ccb_trans_settings_spi *spi; + struct ccb_trans_settings_spi *cur_spi; + + spi = &cts->xport_specific.spi; + + cur_spi = &cur_cts.xport_specific.spi; + + /* Fill in any gaps in what the user gave us */ + if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) == 0) + spi->sync_period = cur_spi->sync_period; + if ((cur_spi->valid & CTS_SPI_VALID_SYNC_RATE) == 0) + spi->sync_period = 0; + if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) == 0) + spi->sync_offset = cur_spi->sync_offset; + if ((cur_spi->valid & CTS_SPI_VALID_SYNC_OFFSET) == 0) + spi->sync_offset = 0; + if ((spi->valid & CTS_SPI_VALID_PPR_OPTIONS) == 0) + spi->ppr_options = cur_spi->ppr_options; + if ((cur_spi->valid & CTS_SPI_VALID_PPR_OPTIONS) == 0) + spi->ppr_options = 0; + if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) == 0) + spi->bus_width = cur_spi->bus_width; + if ((cur_spi->valid & CTS_SPI_VALID_BUS_WIDTH) == 0) + spi->bus_width = 0; + if ((spi->valid & CTS_SPI_VALID_DISC) == 0) { + spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB; + spi->flags |= cur_spi->flags & CTS_SPI_FLAGS_DISC_ENB; + } + if ((cur_spi->valid & CTS_SPI_VALID_DISC) == 0) + spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB; + if (((device->flags & CAM_DEV_INQUIRY_DATA_VALID) != 0 + && (inq_data->flags & SID_Sync) == 0 + && cts->type == CTS_TYPE_CURRENT_SETTINGS) + || ((cpi.hba_inquiry & PI_SDTR_ABLE) == 0) + || (cts->sync_offset == 0) + || (cts->sync_period == 0)) { + /* Force async */ + spi->sync_period = 0; + spi->sync_offset = 0; + } + + switch (spi->bus_width) { + case MSG_EXT_WDTR_BUS_32_BIT: + if (((device->flags & CAM_DEV_INQUIRY_DATA_VALID) == 0 + || (inq_data->flags & SID_WBus32) != 0 + || cts->type == CTS_TYPE_USER_SETTINGS) + && (cpi.hba_inquiry & PI_WIDE_32) != 0) + break; + /* Fall Through to 16-bit */ + case MSG_EXT_WDTR_BUS_16_BIT: + if (((device->flags & CAM_DEV_INQUIRY_DATA_VALID) == 0 + || (inq_data->flags & SID_WBus16) != 0 + || cts->type == CTS_TYPE_USER_SETTINGS) + && (cpi.hba_inquiry & PI_WIDE_16) != 0) { + spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT; + break; + } + /* Fall Through to 8-bit */ + default: /* New bus width?? */ + case MSG_EXT_WDTR_BUS_8_BIT: + /* All targets can do this */ + spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT; + break; + } + + spi3caps = cpi.xport_specific.spi.ppr_options; + if ((device->flags & CAM_DEV_INQUIRY_DATA_VALID) != 0 + && cts->type == CTS_TYPE_CURRENT_SETTINGS) + spi3caps &= inq_data->spi3data; + + if ((spi3caps & SID_SPI_CLOCK_DT) == 0) + spi->ppr_options &= ~MSG_EXT_PPR_DT_REQ; + + if ((spi3caps & SID_SPI_IUS) == 0) + spi->ppr_options &= ~MSG_EXT_PPR_IU_REQ; + + if ((spi3caps & SID_SPI_QAS) == 0) + spi->ppr_options &= ~MSG_EXT_PPR_QAS_REQ; + + /* No SPI Transfer settings are allowed unless we are wide */ + if (spi->bus_width == 0) + spi->ppr_options = 0; + + if ((spi->flags & CTS_SPI_FLAGS_DISC_ENB) == 0) { + /* + * Can't tag queue without disconnection. + */ + scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; + scsi->valid |= CTS_SCSI_VALID_TQ; + } + + /* + * If we are currently performing tagged transactions to + * this device and want to change its negotiation parameters, + * go non-tagged for a bit to give the controller a chance to + * negotiate unhampered by tag messages. + */ + if (cts->type == CTS_TYPE_CURRENT_SETTINGS + && (device->inq_flags & SID_CmdQue) != 0 + && (scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0 + && (spi->flags & (CTS_SPI_VALID_SYNC_RATE| + CTS_SPI_VALID_SYNC_OFFSET| + CTS_SPI_VALID_BUS_WIDTH)) != 0) + xpt_toggle_tags(cts->ccb_h.path); + } + + if (cts->type == CTS_TYPE_CURRENT_SETTINGS + && (scsi->valid & CTS_SCSI_VALID_TQ) != 0) { + int device_tagenb; + + /* + * If we are transitioning from tags to no-tags or + * vice-versa, we need to carefully freeze and restart + * the queue so that we don't overlap tagged and non-tagged + * commands. We also temporarily stop tags if there is + * a change in transfer negotiation settings to allow + * "tag-less" negotiation. + */ + if ((device->flags & CAM_DEV_TAG_AFTER_COUNT) != 0 + || (device->inq_flags & SID_CmdQue) != 0) + device_tagenb = TRUE; + else + device_tagenb = FALSE; + + if (((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0 + && device_tagenb == FALSE) + || ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) == 0 + && device_tagenb == TRUE)) { + + if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0) { + /* + * Delay change to use tags until after a + * few commands have gone to this device so + * the controller has time to perform transfer + * negotiations without tagged messages getting + * in the way. + */ + device->tag_delay_count = CAM_TAG_DELAY_COUNT; + device->flags |= CAM_DEV_TAG_AFTER_COUNT; + } else { + struct ccb_relsim crs; + + xpt_freeze_devq(cts->ccb_h.path, /*count*/1); + device->inq_flags &= ~SID_CmdQue; + xpt_dev_ccbq_resize(cts->ccb_h.path, + sim->max_dev_openings); + device->flags &= ~CAM_DEV_TAG_AFTER_COUNT; + device->tag_delay_count = 0; + + xpt_setup_ccb(&crs.ccb_h, cts->ccb_h.path, + /*priority*/1); + crs.ccb_h.func_code = XPT_REL_SIMQ; + crs.release_flags = RELSIM_RELEASE_AFTER_QEMPTY; + crs.openings + = crs.release_timeout + = crs.qfrozen_cnt + = 0; + xpt_action((union ccb *)&crs); + } + } + } + if (async_update == FALSE) + (*(sim->sim_action))(sim, (union ccb *)cts); +} + +#else /* CAM_NEW_TRAN_CODE */ + static void xpt_set_transfer_settings(struct ccb_trans_settings *cts, struct cam_ed *device, int async_update) @@ -5972,6 +6527,9 @@ xpt_set_transfer_settings(struct ccb_trans_settings *cts, struct cam_ed *device, } } + +#endif /* CAM_NEW_TRAN_CODE */ + static void xpt_toggle_tags(struct cam_path *path) { @@ -5991,11 +6549,24 @@ xpt_toggle_tags(struct cam_path *path) struct ccb_trans_settings cts; xpt_setup_ccb(&cts.ccb_h, path, 1); +#ifdef CAM_NEW_TRAN_CODE + cts.protocol = PROTO_SCSI; + cts.protocol_version = PROTO_VERSION_UNSPECIFIED; + cts.transport = XPORT_UNSPECIFIED; + cts.transport_version = XPORT_VERSION_UNSPECIFIED; + cts.proto_specific.scsi.flags = 0; + cts.proto_specific.scsi.valid = CTS_SCSI_VALID_TQ; +#else /* CAM_NEW_TRAN_CODE */ cts.flags = 0; cts.valid = CCB_TRANS_TQ_VALID; +#endif /* CAM_NEW_TRAN_CODE */ xpt_set_transfer_settings(&cts, path->device, /*async_update*/TRUE); +#ifdef CAM_NEW_TRAN_CODE + cts.proto_specific.scsi.flags = CTS_SCSI_FLAGS_TAG_ENB; +#else /* CAM_NEW_TRAN_CODE */ cts.flags = CCB_TRANS_TAG_ENB; +#endif /* CAM_NEW_TRAN_CODE */ xpt_set_transfer_settings(&cts, path->device, /*async_update*/TRUE); } @@ -6111,7 +6682,9 @@ xptconfigfunc(struct cam_eb *bus, void *arg) static void xpt_config(void *arg) { - /* Now that interrupts are enabled, go find our devices */ + /* + * Now that interrupts are enabled, go find our devices + */ #ifdef CAMDEBUG /* Setup debugging flags and path */ @@ -6252,6 +6825,12 @@ xptaction(struct cam_sim *sim, union ccb *work_ccb) cpi->unit_number = sim->unit_number; cpi->bus_id = sim->bus_id; cpi->base_transfer_speed = 0; +#ifdef CAM_NEW_TRAN_CODE + cpi->protocol = PROTO_UNSPECIFIED; + cpi->protocol_version = PROTO_VERSION_UNSPECIFIED; + cpi->transport = XPORT_UNSPECIFIED; + cpi->transport_version = XPORT_VERSION_UNSPECIFIED; +#endif /* CAM_NEW_TRAN_CODE */ cpi->ccb_h.status = CAM_REQ_CMP; xpt_done(work_ccb); break; @@ -6330,7 +6909,8 @@ camisr(void *V_queue) ccb_h->path->bus->sim->devq->send_openings++; splx(s); - if ((dev->flags & CAM_DEV_REL_ON_COMPLETE) != 0 + if (((dev->flags & CAM_DEV_REL_ON_COMPLETE) != 0 + && (ccb_h->status&CAM_STATUS_MASK) != CAM_REQUEUE_REQ) || ((dev->flags & CAM_DEV_REL_ON_QUEUE_EMPTY) != 0 && (dev->ccbq.dev_active == 0))) { diff --git a/sys/cam/cam_xpt.h b/sys/cam/cam_xpt.h index 8eb77e0..f233381 100644 --- a/sys/cam/cam_xpt.h +++ b/sys/cam/cam_xpt.h @@ -62,6 +62,8 @@ void xpt_free_path(struct cam_path *path); int xpt_path_comp(struct cam_path *path1, struct cam_path *path2); void xpt_print_path(struct cam_path *path); +int xpt_path_string(struct cam_path *path, char *str, + size_t str_len); path_id_t xpt_path_path_id(struct cam_path *path); target_id_t xpt_path_target_id(struct cam_path *path); lun_id_t xpt_path_lun_id(struct cam_path *path); diff --git a/sys/cam/scsi/scsi_all.c b/sys/cam/scsi/scsi_all.c index cd74165..cb0f9d6 100644 --- a/sys/cam/scsi/scsi_all.c +++ b/sys/cam/scsi/scsi_all.c @@ -1,7 +1,7 @@ /* * Implementation of Utility functions for all SCSI device types. * - * Copyright (c) 1997, 1998 Justin T. Gibbs. + * Copyright (c) 1997, 1998, 1999 Justin T. Gibbs. * Copyright (c) 1997, 1998 Kenneth D. Merry. * All rights reserved. * @@ -35,9 +35,11 @@ #include <opt_scsi.h> #include <sys/systm.h> +#include <sys/libkern.h> #else #include <errno.h> #include <stdio.h> +#include <stdlib.h> #include <string.h> #endif @@ -45,6 +47,7 @@ #include <cam/cam_ccb.h> #include <cam/cam_xpt.h> #include <cam/scsi/scsi_all.h> +#include <sys/sbuf.h> #ifndef _KERNEL #include <camlib.h> @@ -58,25 +61,12 @@ #define EJUSTRETURN -2 /* don't modify regs, just return */ #endif /* !_KERNEL */ -const char *scsi_sense_key_text[] = -{ - "NO SENSE", - "RECOVERED ERROR", - "NOT READY", - "MEDIUM ERROR", - "HARDWARE FAILURE", - "ILLEGAL REQUEST", - "UNIT ATTENTION", - "DATA PROTECT", - "BLANK CHECK", - "Vendor Specific", - "COPY ABORTED", - "ABORTED COMMAND", - "EQUAL", - "VOLUME OVERFLOW", - "MISCOMPARE", - "RESERVED" -}; +static int ascentrycomp(const void *key, const void *member); +static int senseentrycomp(const void *key, const void *member); +static void fetchtableentries(int sense_key, int asc, int ascq, + struct scsi_inquiry_data *, + const struct sense_key_table_entry **, + const struct asc_table_entry **); #if !defined(SCSI_NO_OP_STRINGS) @@ -95,10 +85,6 @@ const char *scsi_sense_key_text[] = #define ALL 0xFFF -/* - * WARNING: You must update the num_ops field below for this quirk table - * entry if you add more entries. - */ static struct op_table_entry plextor_cd_ops[] = { {0xD8, R, "CD-DA READ"} }; @@ -115,7 +101,7 @@ static struct scsi_op_quirk_entry scsi_op_quirk_table[] = { * feel free to change this quirk entry. */ {T_CDROM, SIP_MEDIA_REMOVABLE, "PLEXTOR", "CD-ROM PX*", "*"}, - 1, /* number of vendor-specific opcodes for this entry */ + sizeof(plextor_cd_ops)/sizeof(struct op_table_entry), plextor_cd_ops } }; @@ -701,27 +687,48 @@ scsi_op_desc(u_int16_t opcode, struct scsi_inquiry_data *inq_data) #include <sys/param.h> - #if !defined(SCSI_NO_SENSE_STRINGS) #define SST(asc, ascq, action, desc) \ asc, ascq, action, desc #else +const char empty_string[] = ""; + #define SST(asc, ascq, action, desc) \ - asc, ascq, action + asc, ascq, action, empty_string #endif static const char quantum[] = "QUANTUM"; -/* - * WARNING: You must update the num_ascs field below for this quirk table - * entry if you add more entries. - */ +const struct sense_key_table_entry sense_key_table[] = +{ + { SSD_KEY_NO_SENSE, SS_NOP, "NO SENSE" }, + { SSD_KEY_RECOVERED_ERROR, SS_NOP|SSQ_PRINT_SENSE, "RECOVERED ERROR" }, + { + SSD_KEY_NOT_READY, SS_TUR|SSQ_MANY|SSQ_DECREMENT_COUNT|EBUSY, + "NOT READY" + }, + { SSD_KEY_MEDIUM_ERROR, SS_RDEF, "MEDIUM ERROR" }, + { SSD_KEY_HARDWARE_ERROR, SS_RDEF, "HARDWARE FAILURE" }, + { SSD_KEY_ILLEGAL_REQUEST, SS_FATAL|EINVAL, "ILLEGAL REQUEST" }, + { SSD_KEY_UNIT_ATTENTION, SS_FATAL|ENXIO, "UNIT ATTENTION" }, + { SSD_KEY_Vendor_Specific, SS_FATAL|EIO, "Vendor Specific" }, + { SSD_KEY_COPY_ABORTED, SS_FATAL|EIO, "COPY ABORTED" }, + { SSD_KEY_ABORTED_COMMAND, SS_RDEF, "ABORTED COMMAND" }, + { SSD_KEY_EQUAL, SS_NOP, "EQUAL" }, + { SSD_KEY_VOLUME_OVERFLOW, SS_FATAL|EIO, "VOLUME OVERFLOW" }, + { SSD_KEY_MISCOMPARE, SS_NOP, "MISCOMPARE" }, + { SSD_KEY_RESERVED, SS_FATAL|EIO, "RESERVED" } +}; + +const int sense_key_table_size = + sizeof(sense_key_table)/sizeof(sense_key_table[0]); + static struct asc_table_entry quantum_fireball_entries[] = { {SST(0x04, 0x0b, SS_START|SSQ_DECREMENT_COUNT|ENXIO, "Logical unit not ready, initializing cmd. required")} }; -static struct scsi_sense_quirk_entry asc_quirk_table[] = { +static struct scsi_sense_quirk_entry sense_quirk_table[] = { { /* * The Quantum Fireball ST and SE like to return 0x04 0x0b when @@ -730,12 +737,17 @@ static struct scsi_sense_quirk_entry asc_quirk_table[] = { * hardware manual for these drives. */ {T_DIRECT, SIP_MEDIA_FIXED, "QUANTUM", "FIREBALL S*", "*"}, - 1, /* number of vendor-specific sense codes for this entry */ + /*num_sense_keys*/0, + sizeof(quantum_fireball_entries)/sizeof(struct asc_table_entry), + /*sense key entries*/NULL, quantum_fireball_entries } }; -static struct asc_table_entry asc_text[] = { +const int sense_quirk_table_size = + sizeof(sense_quirk_table)/sizeof(sense_quirk_table[0]); + +static struct asc_table_entry asc_table[] = { /* * From File: ASC-NUM.TXT * SCSI ASC/ASCQ Assignments @@ -756,43 +768,43 @@ static struct asc_table_entry asc_text[] = { * . . . . E - ENCLOSURE SERVICES DEVICE (SES) * DTLPWRSOMCAE ASC ASCQ Action Description * ------------ ---- ---- ------ -----------------------------------*/ -/* DTLPWRSOMCAE */{SST(0x00, 0x00, SS_NEPDEF, +/* DTLPWRSOMCAE */{SST(0x00, 0x00, SS_NOP, "No additional sense information") }, -/* T S */{SST(0x00, 0x01, SS_DEF, +/* T S */{SST(0x00, 0x01, SS_RDEF, "Filemark detected") }, -/* T S */{SST(0x00, 0x02, SS_DEF, +/* T S */{SST(0x00, 0x02, SS_RDEF, "End-of-partition/medium detected") }, -/* T */{SST(0x00, 0x03, SS_DEF, +/* T */{SST(0x00, 0x03, SS_RDEF, "Setmark detected") }, -/* T S */{SST(0x00, 0x04, SS_DEF, +/* T S */{SST(0x00, 0x04, SS_RDEF, "Beginning-of-partition/medium detected") }, -/* T S */{SST(0x00, 0x05, SS_DEF, +/* T S */{SST(0x00, 0x05, SS_RDEF, "End-of-data detected") }, -/* DTLPWRSOMCAE */{SST(0x00, 0x06, SS_DEF, +/* DTLPWRSOMCAE */{SST(0x00, 0x06, SS_RDEF, "I/O process terminated") }, -/* R */{SST(0x00, 0x11, SS_NEDEF|EBUSY, +/* R */{SST(0x00, 0x11, SS_FATAL|EBUSY, "Audio play operation in progress") }, -/* R */{SST(0x00, 0x12, SS_NEDEF, +/* R */{SST(0x00, 0x12, SS_NOP, "Audio play operation paused") }, -/* R */{SST(0x00, 0x13, SS_NEDEF, +/* R */{SST(0x00, 0x13, SS_NOP, "Audio play operation successfully completed") }, -/* R */{SST(0x00, 0x14, SS_DEF, +/* R */{SST(0x00, 0x14, SS_RDEF, "Audio play operation stopped due to error") }, -/* R */{SST(0x00, 0x15, SS_DEF, +/* R */{SST(0x00, 0x15, SS_NOP, "No current audio status to return") }, -/* DTLPWRSOMCAE */{SST(0x00, 0x16, SS_NEDEF|EBUSY, +/* DTLPWRSOMCAE */{SST(0x00, 0x16, SS_FATAL|EBUSY, "Operation in progress") }, -/* DTL WRSOM AE */{SST(0x00, 0x17, SS_DEF, +/* DTL WRSOM AE */{SST(0x00, 0x17, SS_RDEF, "Cleaning requested") }, -/* D W O */{SST(0x01, 0x00, SS_DEF, +/* D W O */{SST(0x01, 0x00, SS_RDEF, "No index/sector signal") }, -/* D WR OM */{SST(0x02, 0x00, SS_DEF, +/* D WR OM */{SST(0x02, 0x00, SS_RDEF, "No seek complete") }, -/* DTL W SO */{SST(0x03, 0x00, SS_DEF, +/* DTL W SO */{SST(0x03, 0x00, SS_RDEF, "Peripheral device write fault") }, -/* T */{SST(0x03, 0x01, SS_DEF, +/* T */{SST(0x03, 0x01, SS_RDEF, "No write current") }, -/* T */{SST(0x03, 0x02, SS_DEF, +/* T */{SST(0x03, 0x02, SS_RDEF, "Excessive write errors") }, /* DTLPWRSOMCAE */{SST(0x04, 0x00, SS_TUR|SSQ_MANY|SSQ_DECREMENT_COUNT|EIO, "Logical unit not ready, cause not reportable") }, @@ -800,754 +812,864 @@ static struct asc_table_entry asc_text[] = { "Logical unit is in process of becoming ready") }, /* DTLPWRSOMCAE */{SST(0x04, 0x02, SS_START|SSQ_DECREMENT_COUNT|ENXIO, "Logical unit not ready, initializing cmd. required") }, -/* DTLPWRSOMCAE */{SST(0x04, 0x03, SS_NEDEF|ENXIO, +/* DTLPWRSOMCAE */{SST(0x04, 0x03, SS_FATAL|ENXIO, "Logical unit not ready, manual intervention required")}, -/* DTL O */{SST(0x04, 0x04, SS_NEDEF|EBUSY, +/* DTL O */{SST(0x04, 0x04, SS_FATAL|EBUSY, "Logical unit not ready, format in progress") }, -/* DT W OMCA */{SST(0x04, 0x05, SS_NEDEF|EBUSY, +/* DT W OMCA */{SST(0x04, 0x05, SS_FATAL|EBUSY, "Logical unit not ready, rebuild in progress") }, -/* DT W OMCA */{SST(0x04, 0x06, SS_NEDEF|EBUSY, +/* DT W OMCA */{SST(0x04, 0x06, SS_FATAL|EBUSY, "Logical unit not ready, recalculation in progress") }, -/* DTLPWRSOMCAE */{SST(0x04, 0x07, SS_NEDEF|EBUSY, +/* DTLPWRSOMCAE */{SST(0x04, 0x07, SS_FATAL|EBUSY, "Logical unit not ready, operation in progress") }, -/* R */{SST(0x04, 0x08, SS_NEDEF|EBUSY, +/* R */{SST(0x04, 0x08, SS_FATAL|EBUSY, "Logical unit not ready, long write in progress") }, -/* DTL WRSOMCAE */{SST(0x05, 0x00, SS_DEF, +/* DTL WRSOMCAE */{SST(0x05, 0x00, SS_RDEF, "Logical unit does not respond to selection") }, -/* D WR OM */{SST(0x06, 0x00, SS_DEF, +/* D WR OM */{SST(0x06, 0x00, SS_RDEF, "No reference position found") }, -/* DTL WRSOM */{SST(0x07, 0x00, SS_DEF, +/* DTL WRSOM */{SST(0x07, 0x00, SS_RDEF, "Multiple peripheral devices selected") }, -/* DTL WRSOMCAE */{SST(0x08, 0x00, SS_DEF, +/* DTL WRSOMCAE */{SST(0x08, 0x00, SS_RDEF, "Logical unit communication failure") }, -/* DTL WRSOMCAE */{SST(0x08, 0x01, SS_DEF, +/* DTL WRSOMCAE */{SST(0x08, 0x01, SS_RDEF, "Logical unit communication time-out") }, -/* DTL WRSOMCAE */{SST(0x08, 0x02, SS_DEF, +/* DTL WRSOMCAE */{SST(0x08, 0x02, SS_RDEF, "Logical unit communication parity error") }, -/* DT R OM */{SST(0x08, 0x03, SS_DEF, +/* DT R OM */{SST(0x08, 0x03, SS_RDEF, "Logical unit communication crc error (ultra-dma/32)")}, -/* DT WR O */{SST(0x09, 0x00, SS_DEF, +/* DT WR O */{SST(0x09, 0x00, SS_RDEF, "Track following error") }, -/* WR O */{SST(0x09, 0x01, SS_DEF, +/* WR O */{SST(0x09, 0x01, SS_RDEF, "Tracking servo failure") }, -/* WR O */{SST(0x09, 0x02, SS_DEF, +/* WR O */{SST(0x09, 0x02, SS_RDEF, "Focus servo failure") }, -/* WR O */{SST(0x09, 0x03, SS_DEF, +/* WR O */{SST(0x09, 0x03, SS_RDEF, "Spindle servo failure") }, -/* DT WR O */{SST(0x09, 0x04, SS_DEF, +/* DT WR O */{SST(0x09, 0x04, SS_RDEF, "Head select fault") }, -/* DTLPWRSOMCAE */{SST(0x0A, 0x00, SS_NEDEF|ENOSPC, +/* DTLPWRSOMCAE */{SST(0x0A, 0x00, SS_FATAL|ENOSPC, "Error log overflow") }, -/* DTLPWRSOMCAE */{SST(0x0B, 0x00, SS_DEF, +/* DTLPWRSOMCAE */{SST(0x0B, 0x00, SS_RDEF, "Warning") }, -/* DTLPWRSOMCAE */{SST(0x0B, 0x01, SS_DEF, +/* DTLPWRSOMCAE */{SST(0x0B, 0x01, SS_RDEF, "Specified temperature exceeded") }, -/* DTLPWRSOMCAE */{SST(0x0B, 0x02, SS_DEF, +/* DTLPWRSOMCAE */{SST(0x0B, 0x02, SS_RDEF, "Enclosure degraded") }, -/* T RS */{SST(0x0C, 0x00, SS_DEF, +/* T RS */{SST(0x0C, 0x00, SS_RDEF, "Write error") }, -/* D W O */{SST(0x0C, 0x01, SS_NEDEF, +/* D W O */{SST(0x0C, 0x01, SS_NOP|SSQ_PRINT_SENSE, "Write error - recovered with auto reallocation") }, -/* D W O */{SST(0x0C, 0x02, SS_DEF, +/* D W O */{SST(0x0C, 0x02, SS_RDEF, "Write error - auto reallocation failed") }, -/* D W O */{SST(0x0C, 0x03, SS_DEF, +/* D W O */{SST(0x0C, 0x03, SS_RDEF, "Write error - recommend reassignment") }, -/* DT W O */{SST(0x0C, 0x04, SS_NEPDEF, +/* DT W O */{SST(0x0C, 0x04, SS_RDEF, "Compression check miscompare error") }, -/* DT W O */{SST(0x0C, 0x05, SS_DEF, +/* DT W O */{SST(0x0C, 0x05, SS_RDEF, "Data expansion occurred during compression") }, -/* DT W O */{SST(0x0C, 0x06, SS_DEF, +/* DT W O */{SST(0x0C, 0x06, SS_RDEF, "Block not compressible") }, -/* R */{SST(0x0C, 0x07, SS_DEF, +/* R */{SST(0x0C, 0x07, SS_RDEF, "Write error - recovery needed") }, -/* R */{SST(0x0C, 0x08, SS_DEF, +/* R */{SST(0x0C, 0x08, SS_RDEF, "Write error - recovery failed") }, -/* R */{SST(0x0C, 0x09, SS_DEF, +/* R */{SST(0x0C, 0x09, SS_RDEF, "Write error - loss of streaming") }, -/* R */{SST(0x0C, 0x0A, SS_DEF, +/* R */{SST(0x0C, 0x0A, SS_RDEF, "Write error - padding blocks added") }, -/* D W O */{SST(0x10, 0x00, SS_DEF, +/* D W O */{SST(0x10, 0x00, SS_RDEF, "ID CRC or ECC error") }, -/* DT WRSO */{SST(0x11, 0x00, SS_DEF, +/* DT WRSO */{SST(0x11, 0x00, SS_RDEF, "Unrecovered read error") }, -/* DT W SO */{SST(0x11, 0x01, SS_DEF, +/* DT W SO */{SST(0x11, 0x01, SS_RDEF, "Read retries exhausted") }, -/* DT W SO */{SST(0x11, 0x02, SS_DEF, +/* DT W SO */{SST(0x11, 0x02, SS_RDEF, "Error too long to correct") }, -/* DT W SO */{SST(0x11, 0x03, SS_DEF, +/* DT W SO */{SST(0x11, 0x03, SS_RDEF, "Multiple read errors") }, -/* D W O */{SST(0x11, 0x04, SS_DEF, +/* D W O */{SST(0x11, 0x04, SS_RDEF, "Unrecovered read error - auto reallocate failed") }, -/* WR O */{SST(0x11, 0x05, SS_DEF, +/* WR O */{SST(0x11, 0x05, SS_RDEF, "L-EC uncorrectable error") }, -/* WR O */{SST(0x11, 0x06, SS_DEF, +/* WR O */{SST(0x11, 0x06, SS_RDEF, "CIRC unrecovered error") }, -/* W O */{SST(0x11, 0x07, SS_DEF, +/* W O */{SST(0x11, 0x07, SS_RDEF, "Data re-synchronization error") }, -/* T */{SST(0x11, 0x08, SS_DEF, +/* T */{SST(0x11, 0x08, SS_RDEF, "Incomplete block read") }, -/* T */{SST(0x11, 0x09, SS_DEF, +/* T */{SST(0x11, 0x09, SS_RDEF, "No gap found") }, -/* DT O */{SST(0x11, 0x0A, SS_DEF, +/* DT O */{SST(0x11, 0x0A, SS_RDEF, "Miscorrected error") }, -/* D W O */{SST(0x11, 0x0B, SS_DEF, +/* D W O */{SST(0x11, 0x0B, SS_RDEF, "Unrecovered read error - recommend reassignment") }, -/* D W O */{SST(0x11, 0x0C, SS_DEF, +/* D W O */{SST(0x11, 0x0C, SS_RDEF, "Unrecovered read error - recommend rewrite the data")}, -/* DT WR O */{SST(0x11, 0x0D, SS_DEF, +/* DT WR O */{SST(0x11, 0x0D, SS_RDEF, "De-compression CRC error") }, -/* DT WR O */{SST(0x11, 0x0E, SS_DEF, +/* DT WR O */{SST(0x11, 0x0E, SS_RDEF, "Cannot decompress using declared algorithm") }, -/* R */{SST(0x11, 0x0F, SS_DEF, +/* R */{SST(0x11, 0x0F, SS_RDEF, "Error reading UPC/EAN number") }, -/* R */{SST(0x11, 0x10, SS_DEF, +/* R */{SST(0x11, 0x10, SS_RDEF, "Error reading ISRC number") }, -/* R */{SST(0x11, 0x11, SS_DEF, +/* R */{SST(0x11, 0x11, SS_RDEF, "Read error - loss of streaming") }, -/* D W O */{SST(0x12, 0x00, SS_DEF, +/* D W O */{SST(0x12, 0x00, SS_RDEF, "Address mark not found for id field") }, -/* D W O */{SST(0x13, 0x00, SS_DEF, +/* D W O */{SST(0x13, 0x00, SS_RDEF, "Address mark not found for data field") }, -/* DTL WRSO */{SST(0x14, 0x00, SS_DEF, +/* DTL WRSO */{SST(0x14, 0x00, SS_RDEF, "Recorded entity not found") }, -/* DT WR O */{SST(0x14, 0x01, SS_DEF, +/* DT WR O */{SST(0x14, 0x01, SS_RDEF, "Record not found") }, -/* T */{SST(0x14, 0x02, SS_DEF, +/* T */{SST(0x14, 0x02, SS_RDEF, "Filemark or setmark not found") }, -/* T */{SST(0x14, 0x03, SS_DEF, +/* T */{SST(0x14, 0x03, SS_RDEF, "End-of-data not found") }, -/* T */{SST(0x14, 0x04, SS_DEF, +/* T */{SST(0x14, 0x04, SS_RDEF, "Block sequence error") }, -/* DT W O */{SST(0x14, 0x05, SS_DEF, +/* DT W O */{SST(0x14, 0x05, SS_RDEF, "Record not found - recommend reassignment") }, -/* DT W O */{SST(0x14, 0x06, SS_DEF, +/* DT W O */{SST(0x14, 0x06, SS_RDEF, "Record not found - data auto-reallocated") }, -/* DTL WRSOM */{SST(0x15, 0x00, SS_DEF, +/* DTL WRSOM */{SST(0x15, 0x00, SS_RDEF, "Random positioning error") }, -/* DTL WRSOM */{SST(0x15, 0x01, SS_DEF, +/* DTL WRSOM */{SST(0x15, 0x01, SS_RDEF, "Mechanical positioning error") }, -/* DT WR O */{SST(0x15, 0x02, SS_DEF, +/* DT WR O */{SST(0x15, 0x02, SS_RDEF, "Positioning error detected by read of medium") }, -/* D W O */{SST(0x16, 0x00, SS_DEF, +/* D W O */{SST(0x16, 0x00, SS_RDEF, "Data synchronization mark error") }, -/* D W O */{SST(0x16, 0x01, SS_DEF, +/* D W O */{SST(0x16, 0x01, SS_RDEF, "Data sync error - data rewritten") }, -/* D W O */{SST(0x16, 0x02, SS_DEF, +/* D W O */{SST(0x16, 0x02, SS_RDEF, "Data sync error - recommend rewrite") }, -/* D W O */{SST(0x16, 0x03, SS_NEDEF, +/* D W O */{SST(0x16, 0x03, SS_NOP|SSQ_PRINT_SENSE, "Data sync error - data auto-reallocated") }, -/* D W O */{SST(0x16, 0x04, SS_DEF, +/* D W O */{SST(0x16, 0x04, SS_RDEF, "Data sync error - recommend reassignment") }, -/* DT WRSO */{SST(0x17, 0x00, SS_NEDEF, +/* DT WRSO */{SST(0x17, 0x00, SS_NOP|SSQ_PRINT_SENSE, "Recovered data with no error correction applied") }, -/* DT WRSO */{SST(0x17, 0x01, SS_NEDEF, +/* DT WRSO */{SST(0x17, 0x01, SS_NOP|SSQ_PRINT_SENSE, "Recovered data with retries") }, -/* DT WR O */{SST(0x17, 0x02, SS_NEDEF, +/* DT WR O */{SST(0x17, 0x02, SS_NOP|SSQ_PRINT_SENSE, "Recovered data with positive head offset") }, -/* DT WR O */{SST(0x17, 0x03, SS_NEDEF, +/* DT WR O */{SST(0x17, 0x03, SS_NOP|SSQ_PRINT_SENSE, "Recovered data with negative head offset") }, -/* WR O */{SST(0x17, 0x04, SS_NEDEF, +/* WR O */{SST(0x17, 0x04, SS_NOP|SSQ_PRINT_SENSE, "Recovered data with retries and/or CIRC applied") }, -/* D WR O */{SST(0x17, 0x05, SS_NEDEF, +/* D WR O */{SST(0x17, 0x05, SS_NOP|SSQ_PRINT_SENSE, "Recovered data using previous sector id") }, -/* D W O */{SST(0x17, 0x06, SS_NEDEF, +/* D W O */{SST(0x17, 0x06, SS_NOP|SSQ_PRINT_SENSE, "Recovered data without ECC - data auto-reallocated") }, -/* D W O */{SST(0x17, 0x07, SS_NEDEF, +/* D W O */{SST(0x17, 0x07, SS_NOP|SSQ_PRINT_SENSE, "Recovered data without ECC - recommend reassignment")}, -/* D W O */{SST(0x17, 0x08, SS_NEDEF, +/* D W O */{SST(0x17, 0x08, SS_NOP|SSQ_PRINT_SENSE, "Recovered data without ECC - recommend rewrite") }, -/* D W O */{SST(0x17, 0x09, SS_NEDEF, +/* D W O */{SST(0x17, 0x09, SS_NOP|SSQ_PRINT_SENSE, "Recovered data without ECC - data rewritten") }, -/* D W O */{SST(0x18, 0x00, SS_NEDEF, +/* D W O */{SST(0x18, 0x00, SS_NOP|SSQ_PRINT_SENSE, "Recovered data with error correction applied") }, -/* D WR O */{SST(0x18, 0x01, SS_NEDEF, +/* D WR O */{SST(0x18, 0x01, SS_NOP|SSQ_PRINT_SENSE, "Recovered data with error corr. & retries applied") }, -/* D WR O */{SST(0x18, 0x02, SS_NEDEF, +/* D WR O */{SST(0x18, 0x02, SS_NOP|SSQ_PRINT_SENSE, "Recovered data - data auto-reallocated") }, -/* R */{SST(0x18, 0x03, SS_NEDEF, +/* R */{SST(0x18, 0x03, SS_NOP|SSQ_PRINT_SENSE, "Recovered data with CIRC") }, -/* R */{SST(0x18, 0x04, SS_NEDEF, +/* R */{SST(0x18, 0x04, SS_NOP|SSQ_PRINT_SENSE, "Recovered data with L-EC") }, -/* D WR O */{SST(0x18, 0x05, SS_NEDEF, +/* D WR O */{SST(0x18, 0x05, SS_NOP|SSQ_PRINT_SENSE, "Recovered data - recommend reassignment") }, -/* D WR O */{SST(0x18, 0x06, SS_NEDEF, +/* D WR O */{SST(0x18, 0x06, SS_NOP|SSQ_PRINT_SENSE, "Recovered data - recommend rewrite") }, -/* D W O */{SST(0x18, 0x07, SS_NEDEF, +/* D W O */{SST(0x18, 0x07, SS_NOP|SSQ_PRINT_SENSE, "Recovered data with ECC - data rewritten") }, -/* D O */{SST(0x19, 0x00, SS_DEF, +/* D O */{SST(0x19, 0x00, SS_RDEF, "Defect list error") }, -/* D O */{SST(0x19, 0x01, SS_DEF, +/* D O */{SST(0x19, 0x01, SS_RDEF, "Defect list not available") }, -/* D O */{SST(0x19, 0x02, SS_DEF, +/* D O */{SST(0x19, 0x02, SS_RDEF, "Defect list error in primary list") }, -/* D O */{SST(0x19, 0x03, SS_DEF, +/* D O */{SST(0x19, 0x03, SS_RDEF, "Defect list error in grown list") }, -/* DTLPWRSOMCAE */{SST(0x1A, 0x00, SS_DEF, +/* DTLPWRSOMCAE */{SST(0x1A, 0x00, SS_RDEF, "Parameter list length error") }, -/* DTLPWRSOMCAE */{SST(0x1B, 0x00, SS_DEF, +/* DTLPWRSOMCAE */{SST(0x1B, 0x00, SS_RDEF, "Synchronous data transfer error") }, -/* D O */{SST(0x1C, 0x00, SS_DEF, +/* D O */{SST(0x1C, 0x00, SS_RDEF, "Defect list not found") }, -/* D O */{SST(0x1C, 0x01, SS_DEF, +/* D O */{SST(0x1C, 0x01, SS_RDEF, "Primary defect list not found") }, -/* D O */{SST(0x1C, 0x02, SS_DEF, +/* D O */{SST(0x1C, 0x02, SS_RDEF, "Grown defect list not found") }, -/* D W O */{SST(0x1D, 0x00, SS_NEPDEF, +/* D W O */{SST(0x1D, 0x00, SS_FATAL, "Miscompare during verify operation" )}, -/* D W O */{SST(0x1E, 0x00, SS_NEDEF, +/* D W O */{SST(0x1E, 0x00, SS_NOP|SSQ_PRINT_SENSE, "Recovered id with ecc correction") }, -/* D O */{SST(0x1F, 0x00, SS_DEF, +/* D O */{SST(0x1F, 0x00, SS_RDEF, "Partial defect list transfer") }, -/* DTLPWRSOMCAE */{SST(0x20, 0x00, SS_DEF, +/* DTLPWRSOMCAE */{SST(0x20, 0x00, SS_FATAL|EINVAL, "Invalid command operation code") }, -/* DT WR OM */{SST(0x21, 0x00, SS_DEF, +/* DT WR OM */{SST(0x21, 0x00, SS_FATAL|EINVAL, "Logical block address out of range" )}, -/* DT WR OM */{SST(0x21, 0x01, SS_DEF, +/* DT WR OM */{SST(0x21, 0x01, SS_FATAL|EINVAL, "Invalid element address") }, -/* D */{SST(0x22, 0x00, SS_DEF, +/* D */{SST(0x22, 0x00, SS_FATAL|EINVAL, "Illegal function") }, /* Deprecated. Use 20 00, 24 00, or 26 00 instead */ -/* DTLPWRSOMCAE */{SST(0x24, 0x00, SS_NEDEF|EINVAL, +/* DTLPWRSOMCAE */{SST(0x24, 0x00, SS_FATAL|EINVAL, "Invalid field in CDB") }, -/* DTLPWRSOMCAE */{SST(0x25, 0x00, SS_NEDEF|ENXIO, +/* DTLPWRSOMCAE */{SST(0x25, 0x00, SS_FATAL|ENXIO, "Logical unit not supported") }, -/* DTLPWRSOMCAE */{SST(0x26, 0x00, SS_NEDEF|EINVAL, +/* DTLPWRSOMCAE */{SST(0x26, 0x00, SS_FATAL|EINVAL, "Invalid field in parameter list") }, -/* DTLPWRSOMCAE */{SST(0x26, 0x01, SS_NEDEF|EINVAL, +/* DTLPWRSOMCAE */{SST(0x26, 0x01, SS_FATAL|EINVAL, "Parameter not supported") }, -/* DTLPWRSOMCAE */{SST(0x26, 0x02, SS_NEDEF|EINVAL, +/* DTLPWRSOMCAE */{SST(0x26, 0x02, SS_FATAL|EINVAL, "Parameter value invalid") }, -/* DTLPWRSOMCAE */{SST(0x26, 0x03, SS_DEF, +/* DTLPWRSOMCAE */{SST(0x26, 0x03, SS_FATAL|EINVAL, "Threshold parameters not supported") }, -/* DTLPWRSOMCAE */{SST(0x26, 0x04, SS_DEF, +/* DTLPWRSOMCAE */{SST(0x26, 0x04, SS_FATAL|EINVAL, "Invalid release of active persistent reservation") }, -/* DT W O */{SST(0x27, 0x00, SS_NEDEF|EACCES, +/* DT W O */{SST(0x27, 0x00, SS_FATAL|EACCES, "Write protected") }, -/* DT W O */{SST(0x27, 0x01, SS_NEDEF|EACCES, +/* DT W O */{SST(0x27, 0x01, SS_FATAL|EACCES, "Hardware write protected") }, -/* DT W O */{SST(0x27, 0x02, SS_NEDEF|EACCES, +/* DT W O */{SST(0x27, 0x02, SS_FATAL|EACCES, "Logical unit software write protected") }, -/* T */{SST(0x27, 0x03, SS_NEDEF|EACCES, +/* T */{SST(0x27, 0x03, SS_FATAL|EACCES, "Associated write protect") }, -/* T */{SST(0x27, 0x04, SS_NEDEF|EACCES, +/* T */{SST(0x27, 0x04, SS_FATAL|EACCES, "Persistent write protect") }, -/* T */{SST(0x27, 0x05, SS_NEDEF|EACCES, +/* T */{SST(0x27, 0x05, SS_FATAL|EACCES, "Permanent write protect") }, -/* DTLPWRSOMCAE */{SST(0x28, 0x00, SS_NEDEF|ENXIO, +/* DTLPWRSOMCAE */{SST(0x28, 0x00, SS_FATAL|ENXIO, "Not ready to ready change, medium may have changed") }, -/* DT WR OM */{SST(0x28, 0x01, SS_DEF, +/* DTLPWRSOMCAE */{SST(0x28, 0x01, SS_FATAL|ENXIO, "Import or export element accessed") }, -/* DTLPWRSOMCAE */{SST(0x29, 0x00, SS_NEDEF|ENXIO, +/* + * XXX JGibbs - All of these should use the same errno, but I don't think + * ENXIO is the correct choice. Should we borrow from the networking + * errnos? ECONNRESET anyone? + */ +/* DTLPWRSOMCAE */{SST(0x29, 0x00, SS_FATAL|ENXIO, "Power on, reset, or bus device reset occurred") }, -/* DTLPWRSOMCAE */{SST(0x29, 0x01, SS_DEF, +/* DTLPWRSOMCAE */{SST(0x29, 0x01, SS_RDEF, "Power on occurred") }, -/* DTLPWRSOMCAE */{SST(0x29, 0x02, SS_DEF, +/* DTLPWRSOMCAE */{SST(0x29, 0x02, SS_RDEF, "Scsi bus reset occurred") }, -/* DTLPWRSOMCAE */{SST(0x29, 0x03, SS_DEF, +/* DTLPWRSOMCAE */{SST(0x29, 0x03, SS_RDEF, "Bus device reset function occurred") }, -/* DTLPWRSOMCAE */{SST(0x29, 0x04, SS_DEF, +/* DTLPWRSOMCAE */{SST(0x29, 0x04, SS_RDEF, "Device internal reset") }, -/* DTLPWRSOMCAE */{SST(0x29, 0x05, SS_DEF, +/* DTLPWRSOMCAE */{SST(0x29, 0x05, SS_RDEF, "Transceiver mode changed to single-ended") }, -/* DTLPWRSOMCAE */{SST(0x29, 0x06, SS_DEF, +/* DTLPWRSOMCAE */{SST(0x29, 0x06, SS_RDEF, "Transceiver mode changed to LVD") }, -/* DTL WRSOMCAE */{SST(0x2A, 0x00, SS_DEF, +/* DTL WRSOMCAE */{SST(0x2A, 0x00, SS_RDEF, "Parameters changed") }, -/* DTL WRSOMCAE */{SST(0x2A, 0x01, SS_DEF, +/* DTL WRSOMCAE */{SST(0x2A, 0x01, SS_RDEF, "Mode parameters changed") }, -/* DTL WRSOMCAE */{SST(0x2A, 0x02, SS_DEF, +/* DTL WRSOMCAE */{SST(0x2A, 0x02, SS_RDEF, "Log parameters changed") }, -/* DTLPWRSOMCAE */{SST(0x2A, 0x03, SS_DEF, +/* DTLPWRSOMCAE */{SST(0x2A, 0x03, SS_RDEF, "Reservations preempted") }, -/* DTLPWRSO C */{SST(0x2B, 0x00, SS_DEF, +/* DTLPWRSO C */{SST(0x2B, 0x00, SS_RDEF, "Copy cannot execute since host cannot disconnect") }, -/* DTLPWRSOMCAE */{SST(0x2C, 0x00, SS_DEF, +/* DTLPWRSOMCAE */{SST(0x2C, 0x00, SS_RDEF, "Command sequence error") }, -/* S */{SST(0x2C, 0x01, SS_DEF, +/* S */{SST(0x2C, 0x01, SS_RDEF, "Too many windows specified") }, -/* S */{SST(0x2C, 0x02, SS_DEF, +/* S */{SST(0x2C, 0x02, SS_RDEF, "Invalid combination of windows specified") }, -/* R */{SST(0x2C, 0x03, SS_DEF, +/* R */{SST(0x2C, 0x03, SS_RDEF, "Current program area is not empty") }, -/* R */{SST(0x2C, 0x04, SS_DEF, +/* R */{SST(0x2C, 0x04, SS_RDEF, "Current program area is empty") }, -/* T */{SST(0x2D, 0x00, SS_DEF, +/* T */{SST(0x2D, 0x00, SS_RDEF, "Overwrite error on update in place") }, -/* DTLPWRSOMCAE */{SST(0x2F, 0x00, SS_DEF, +/* DTLPWRSOMCAE */{SST(0x2F, 0x00, SS_RDEF, "Commands cleared by another initiator") }, -/* DT WR OM */{SST(0x30, 0x00, SS_DEF, +/* DT WR OM */{SST(0x30, 0x00, SS_RDEF, "Incompatible medium installed") }, -/* DT WR O */{SST(0x30, 0x01, SS_DEF, +/* DT WR O */{SST(0x30, 0x01, SS_RDEF, "Cannot read medium - unknown format") }, -/* DT WR O */{SST(0x30, 0x02, SS_DEF, +/* DT WR O */{SST(0x30, 0x02, SS_RDEF, "Cannot read medium - incompatible format") }, -/* DT */{SST(0x30, 0x03, SS_DEF, +/* DT */{SST(0x30, 0x03, SS_RDEF, "Cleaning cartridge installed") }, -/* DT WR O */{SST(0x30, 0x04, SS_DEF, +/* DT WR O */{SST(0x30, 0x04, SS_RDEF, "Cannot write medium - unknown format") }, -/* DT WR O */{SST(0x30, 0x05, SS_DEF, +/* DT WR O */{SST(0x30, 0x05, SS_RDEF, "Cannot write medium - incompatible format") }, -/* DT W O */{SST(0x30, 0x06, SS_DEF, +/* DT W O */{SST(0x30, 0x06, SS_RDEF, "Cannot format medium - incompatible medium") }, -/* DTL WRSOM AE */{SST(0x30, 0x07, SS_DEF, +/* DTL WRSOM AE */{SST(0x30, 0x07, SS_RDEF, "Cleaning failure") }, -/* R */{SST(0x30, 0x08, SS_DEF, +/* R */{SST(0x30, 0x08, SS_RDEF, "Cannot write - application code mismatch") }, -/* R */{SST(0x30, 0x09, SS_DEF, +/* R */{SST(0x30, 0x09, SS_RDEF, "Current session not fixated for append") }, -/* DT WR O */{SST(0x31, 0x00, SS_DEF, +/* DT WR O */{SST(0x31, 0x00, SS_RDEF, "Medium format corrupted") }, -/* D L R O */{SST(0x31, 0x01, SS_DEF, +/* D L R O */{SST(0x31, 0x01, SS_RDEF, "Format command failed") }, -/* D W O */{SST(0x32, 0x00, SS_DEF, +/* D W O */{SST(0x32, 0x00, SS_RDEF, "No defect spare location available") }, -/* D W O */{SST(0x32, 0x01, SS_DEF, +/* D W O */{SST(0x32, 0x01, SS_RDEF, "Defect list update failure") }, -/* T */{SST(0x33, 0x00, SS_DEF, +/* T */{SST(0x33, 0x00, SS_RDEF, "Tape length error") }, -/* DTLPWRSOMCAE */{SST(0x34, 0x00, SS_DEF, +/* DTLPWRSOMCAE */{SST(0x34, 0x00, SS_RDEF, "Enclosure failure") }, -/* DTLPWRSOMCAE */{SST(0x35, 0x00, SS_DEF, +/* DTLPWRSOMCAE */{SST(0x35, 0x00, SS_RDEF, "Enclosure services failure") }, -/* DTLPWRSOMCAE */{SST(0x35, 0x01, SS_DEF, +/* DTLPWRSOMCAE */{SST(0x35, 0x01, SS_RDEF, "Unsupported enclosure function") }, -/* DTLPWRSOMCAE */{SST(0x35, 0x02, SS_DEF, +/* DTLPWRSOMCAE */{SST(0x35, 0x02, SS_RDEF, "Enclosure services unavailable") }, -/* DTLPWRSOMCAE */{SST(0x35, 0x03, SS_DEF, +/* DTLPWRSOMCAE */{SST(0x35, 0x03, SS_RDEF, "Enclosure services transfer failure") }, -/* DTLPWRSOMCAE */{SST(0x35, 0x04, SS_DEF, +/* DTLPWRSOMCAE */{SST(0x35, 0x04, SS_RDEF, "Enclosure services transfer refused") }, -/* L */{SST(0x36, 0x00, SS_DEF, +/* L */{SST(0x36, 0x00, SS_RDEF, "Ribbon, ink, or toner failure") }, -/* DTL WRSOMCAE */{SST(0x37, 0x00, SS_DEF, +/* DTL WRSOMCAE */{SST(0x37, 0x00, SS_RDEF, "Rounded parameter") }, -/* DTL WRSOMCAE */{SST(0x39, 0x00, SS_DEF, +/* DTL WRSOMCAE */{SST(0x39, 0x00, SS_RDEF, "Saving parameters not supported") }, -/* DTL WRSOM */{SST(0x3A, 0x00, SS_NEDEF|ENXIO, +/* DTL WRSOM */{SST(0x3A, 0x00, SS_FATAL|ENXIO, "Medium not present") }, -/* DT WR OM */{SST(0x3A, 0x01, SS_NEDEF|ENXIO, +/* DT WR OM */{SST(0x3A, 0x01, SS_FATAL|ENXIO, "Medium not present - tray closed") }, -/* DT WR OM */{SST(0x3A, 0x02, SS_NEDEF|ENXIO, +/* DT WR OM */{SST(0x3A, 0x02, SS_FATAL|ENXIO, "Medium not present - tray open") }, -/* TL */{SST(0x3B, 0x00, SS_DEF, +/* TL */{SST(0x3B, 0x00, SS_RDEF, "Sequential positioning error") }, -/* T */{SST(0x3B, 0x01, SS_DEF, +/* T */{SST(0x3B, 0x01, SS_RDEF, "Tape position error at beginning-of-medium") }, -/* T */{SST(0x3B, 0x02, SS_DEF, +/* T */{SST(0x3B, 0x02, SS_RDEF, "Tape position error at end-of-medium") }, -/* L */{SST(0x3B, 0x03, SS_DEF, +/* L */{SST(0x3B, 0x03, SS_RDEF, "Tape or electronic vertical forms unit not ready") }, -/* L */{SST(0x3B, 0x04, SS_DEF, +/* L */{SST(0x3B, 0x04, SS_RDEF, "Slew failure") }, -/* L */{SST(0x3B, 0x05, SS_DEF, +/* L */{SST(0x3B, 0x05, SS_RDEF, "Paper jam") }, -/* L */{SST(0x3B, 0x06, SS_DEF, +/* L */{SST(0x3B, 0x06, SS_RDEF, "Failed to sense top-of-form") }, -/* L */{SST(0x3B, 0x07, SS_DEF, +/* L */{SST(0x3B, 0x07, SS_RDEF, "Failed to sense bottom-of-form") }, -/* T */{SST(0x3B, 0x08, SS_DEF, +/* T */{SST(0x3B, 0x08, SS_RDEF, "Reposition error") }, -/* S */{SST(0x3B, 0x09, SS_DEF, +/* S */{SST(0x3B, 0x09, SS_RDEF, "Read past end of medium") }, -/* S */{SST(0x3B, 0x0A, SS_DEF, +/* S */{SST(0x3B, 0x0A, SS_RDEF, "Read past beginning of medium") }, -/* S */{SST(0x3B, 0x0B, SS_DEF, +/* S */{SST(0x3B, 0x0B, SS_RDEF, "Position past end of medium") }, -/* T S */{SST(0x3B, 0x0C, SS_DEF, +/* T S */{SST(0x3B, 0x0C, SS_RDEF, "Position past beginning of medium") }, -/* DT WR OM */{SST(0x3B, 0x0D, SS_NEDEF|ENOSPC, +/* DT WR OM */{SST(0x3B, 0x0D, SS_FATAL|ENOSPC, "Medium destination element full") }, -/* DT WR OM */{SST(0x3B, 0x0E, SS_DEF, +/* DT WR OM */{SST(0x3B, 0x0E, SS_RDEF, "Medium source element empty") }, -/* R */{SST(0x3B, 0x0F, SS_DEF, +/* R */{SST(0x3B, 0x0F, SS_RDEF, "End of medium reached") }, -/* DT WR OM */{SST(0x3B, 0x11, SS_DEF, +/* DT WR OM */{SST(0x3B, 0x11, SS_RDEF, "Medium magazine not accessible") }, -/* DT WR OM */{SST(0x3B, 0x12, SS_DEF, +/* DT WR OM */{SST(0x3B, 0x12, SS_RDEF, "Medium magazine removed") }, -/* DT WR OM */{SST(0x3B, 0x13, SS_DEF, +/* DT WR OM */{SST(0x3B, 0x13, SS_RDEF, "Medium magazine inserted") }, -/* DT WR OM */{SST(0x3B, 0x14, SS_DEF, +/* DT WR OM */{SST(0x3B, 0x14, SS_RDEF, "Medium magazine locked") }, -/* DT WR OM */{SST(0x3B, 0x15, SS_DEF, +/* DT WR OM */{SST(0x3B, 0x15, SS_RDEF, "Medium magazine unlocked") }, -/* DTLPWRSOMCAE */{SST(0x3D, 0x00, SS_DEF, +/* DTLPWRSOMCAE */{SST(0x3D, 0x00, SS_RDEF, "Invalid bits in identify message") }, -/* DTLPWRSOMCAE */{SST(0x3E, 0x00, SS_DEF, +/* DTLPWRSOMCAE */{SST(0x3E, 0x00, SS_RDEF, "Logical unit has not self-configured yet") }, -/* DTLPWRSOMCAE */{SST(0x3E, 0x01, SS_DEF, +/* DTLPWRSOMCAE */{SST(0x3E, 0x01, SS_RDEF, "Logical unit failure") }, -/* DTLPWRSOMCAE */{SST(0x3E, 0x02, SS_DEF, +/* DTLPWRSOMCAE */{SST(0x3E, 0x02, SS_RDEF, "Timeout on logical unit") }, -/* DTLPWRSOMCAE */{SST(0x3F, 0x00, SS_DEF, +/* DTLPWRSOMCAE */{SST(0x3F, 0x00, SS_RDEF, "Target operating conditions have changed") }, -/* DTLPWRSOMCAE */{SST(0x3F, 0x01, SS_DEF, +/* DTLPWRSOMCAE */{SST(0x3F, 0x01, SS_RDEF, "Microcode has been changed") }, -/* DTLPWRSOMC */{SST(0x3F, 0x02, SS_DEF, +/* DTLPWRSOMC */{SST(0x3F, 0x02, SS_RDEF, "Changed operating definition") }, -/* DTLPWRSOMCAE */{SST(0x3F, 0x03, SS_DEF, +/* DTLPWRSOMCAE */{SST(0x3F, 0x03, SS_RDEF, "Inquiry data has changed") }, -/* DT WR OMCAE */{SST(0x3F, 0x04, SS_DEF, +/* DT WR OMCAE */{SST(0x3F, 0x04, SS_RDEF, "Component device attached") }, -/* DT WR OMCAE */{SST(0x3F, 0x05, SS_DEF, +/* DT WR OMCAE */{SST(0x3F, 0x05, SS_RDEF, "Device identifier changed") }, -/* DT WR OMCAE */{SST(0x3F, 0x06, SS_DEF, +/* DT WR OMCAE */{SST(0x3F, 0x06, SS_RDEF, "Redundancy group created or modified") }, -/* DT WR OMCAE */{SST(0x3F, 0x07, SS_DEF, +/* DT WR OMCAE */{SST(0x3F, 0x07, SS_RDEF, "Redundancy group deleted") }, -/* DT WR OMCAE */{SST(0x3F, 0x08, SS_DEF, +/* DT WR OMCAE */{SST(0x3F, 0x08, SS_RDEF, "Spare created or modified") }, -/* DT WR OMCAE */{SST(0x3F, 0x09, SS_DEF, +/* DT WR OMCAE */{SST(0x3F, 0x09, SS_RDEF, "Spare deleted") }, -/* DT WR OMCAE */{SST(0x3F, 0x0A, SS_DEF, +/* DT WR OMCAE */{SST(0x3F, 0x0A, SS_RDEF, "Volume set created or modified") }, -/* DT WR OMCAE */{SST(0x3F, 0x0B, SS_DEF, +/* DT WR OMCAE */{SST(0x3F, 0x0B, SS_RDEF, "Volume set deleted") }, -/* DT WR OMCAE */{SST(0x3F, 0x0C, SS_DEF, +/* DT WR OMCAE */{SST(0x3F, 0x0C, SS_RDEF, "Volume set deassigned") }, -/* DT WR OMCAE */{SST(0x3F, 0x0D, SS_DEF, +/* DT WR OMCAE */{SST(0x3F, 0x0D, SS_RDEF, "Volume set reassigned") }, -/* D */{SST(0x40, 0x00, SS_DEF, +/* D */{SST(0x40, 0x00, SS_RDEF, "Ram failure") }, /* deprecated - use 40 NN instead */ -/* DTLPWRSOMCAE */{SST(0x40, 0x80, SS_DEF, +/* DTLPWRSOMCAE */{SST(0x40, 0x80, SS_RDEF, "Diagnostic failure: ASCQ = Component ID") }, -/* DTLPWRSOMCAE */{SST(0x40, 0xFF, SS_DEF|SSQ_RANGE, +/* DTLPWRSOMCAE */{SST(0x40, 0xFF, SS_RDEF|SSQ_RANGE, NULL) },/* Range 0x80->0xFF */ -/* D */{SST(0x41, 0x00, SS_DEF, +/* D */{SST(0x41, 0x00, SS_RDEF, "Data path failure") }, /* deprecated - use 40 NN instead */ -/* D */{SST(0x42, 0x00, SS_DEF, +/* D */{SST(0x42, 0x00, SS_RDEF, "Power-on or self-test failure") }, /* deprecated - use 40 NN instead */ -/* DTLPWRSOMCAE */{SST(0x43, 0x00, SS_DEF, +/* DTLPWRSOMCAE */{SST(0x43, 0x00, SS_RDEF, "Message error") }, -/* DTLPWRSOMCAE */{SST(0x44, 0x00, SS_DEF, +/* DTLPWRSOMCAE */{SST(0x44, 0x00, SS_RDEF, "Internal target failure") }, -/* DTLPWRSOMCAE */{SST(0x45, 0x00, SS_DEF, +/* DTLPWRSOMCAE */{SST(0x45, 0x00, SS_RDEF, "Select or reselect failure") }, -/* DTLPWRSOMC */{SST(0x46, 0x00, SS_DEF, +/* DTLPWRSOMC */{SST(0x46, 0x00, SS_RDEF, "Unsuccessful soft reset") }, -/* DTLPWRSOMCAE */{SST(0x47, 0x00, SS_DEF, +/* DTLPWRSOMCAE */{SST(0x47, 0x00, SS_RDEF, "SCSI parity error") }, -/* DTLPWRSOMCAE */{SST(0x48, 0x00, SS_DEF, +/* DTLPWRSOMCAE */{SST(0x48, 0x00, SS_RDEF, "Initiator detected error message received") }, -/* DTLPWRSOMCAE */{SST(0x49, 0x00, SS_DEF, +/* DTLPWRSOMCAE */{SST(0x49, 0x00, SS_RDEF, "Invalid message error") }, -/* DTLPWRSOMCAE */{SST(0x4A, 0x00, SS_DEF, +/* DTLPWRSOMCAE */{SST(0x4A, 0x00, SS_RDEF, "Command phase error") }, -/* DTLPWRSOMCAE */{SST(0x4B, 0x00, SS_DEF, +/* DTLPWRSOMCAE */{SST(0x4B, 0x00, SS_RDEF, "Data phase error") }, -/* DTLPWRSOMCAE */{SST(0x4C, 0x00, SS_DEF, +/* DTLPWRSOMCAE */{SST(0x4C, 0x00, SS_RDEF, "Logical unit failed self-configuration") }, -/* DTLPWRSOMCAE */{SST(0x4D, 0x00, SS_DEF, +/* DTLPWRSOMCAE */{SST(0x4D, 0x00, SS_RDEF, "Tagged overlapped commands: ASCQ = Queue tag ID") }, -/* DTLPWRSOMCAE */{SST(0x4D, 0xFF, SS_DEF|SSQ_RANGE, +/* DTLPWRSOMCAE */{SST(0x4D, 0xFF, SS_RDEF|SSQ_RANGE, NULL)}, /* Range 0x00->0xFF */ -/* DTLPWRSOMCAE */{SST(0x4E, 0x00, SS_DEF, +/* DTLPWRSOMCAE */{SST(0x4E, 0x00, SS_RDEF, "Overlapped commands attempted") }, -/* T */{SST(0x50, 0x00, SS_DEF, +/* T */{SST(0x50, 0x00, SS_RDEF, "Write append error") }, -/* T */{SST(0x50, 0x01, SS_DEF, +/* T */{SST(0x50, 0x01, SS_RDEF, "Write append position error") }, -/* T */{SST(0x50, 0x02, SS_DEF, +/* T */{SST(0x50, 0x02, SS_RDEF, "Position error related to timing") }, -/* T O */{SST(0x51, 0x00, SS_DEF, +/* T O */{SST(0x51, 0x00, SS_RDEF, "Erase failure") }, -/* T */{SST(0x52, 0x00, SS_DEF, +/* T */{SST(0x52, 0x00, SS_RDEF, "Cartridge fault") }, -/* DTL WRSOM */{SST(0x53, 0x00, SS_DEF, +/* DTL WRSOM */{SST(0x53, 0x00, SS_RDEF, "Media load or eject failed") }, -/* T */{SST(0x53, 0x01, SS_DEF, +/* T */{SST(0x53, 0x01, SS_RDEF, "Unload tape failure") }, -/* DT WR OM */{SST(0x53, 0x02, SS_DEF, +/* DT WR OM */{SST(0x53, 0x02, SS_RDEF, "Medium removal prevented") }, -/* P */{SST(0x54, 0x00, SS_DEF, +/* P */{SST(0x54, 0x00, SS_RDEF, "Scsi to host system interface failure") }, -/* P */{SST(0x55, 0x00, SS_DEF, +/* P */{SST(0x55, 0x00, SS_RDEF, "System resource failure") }, -/* D O */{SST(0x55, 0x01, SS_NEDEF|ENOSPC, +/* D O */{SST(0x55, 0x01, SS_FATAL|ENOSPC, "System buffer full") }, -/* R */{SST(0x57, 0x00, SS_DEF, +/* R */{SST(0x57, 0x00, SS_RDEF, "Unable to recover table-of-contents") }, -/* O */{SST(0x58, 0x00, SS_DEF, +/* O */{SST(0x58, 0x00, SS_RDEF, "Generation does not exist") }, -/* O */{SST(0x59, 0x00, SS_DEF, +/* O */{SST(0x59, 0x00, SS_RDEF, "Updated block read") }, -/* DTLPWRSOM */{SST(0x5A, 0x00, SS_DEF, +/* DTLPWRSOM */{SST(0x5A, 0x00, SS_RDEF, "Operator request or state change input") }, -/* DT WR OM */{SST(0x5A, 0x01, SS_DEF, +/* DT WR OM */{SST(0x5A, 0x01, SS_RDEF, "Operator medium removal request") }, -/* DT W O */{SST(0x5A, 0x02, SS_DEF, +/* DT W O */{SST(0x5A, 0x02, SS_RDEF, "Operator selected write protect") }, -/* DT W O */{SST(0x5A, 0x03, SS_DEF, +/* DT W O */{SST(0x5A, 0x03, SS_RDEF, "Operator selected write permit") }, -/* DTLPWRSOM */{SST(0x5B, 0x00, SS_DEF, +/* DTLPWRSOM */{SST(0x5B, 0x00, SS_RDEF, "Log exception") }, -/* DTLPWRSOM */{SST(0x5B, 0x01, SS_DEF, +/* DTLPWRSOM */{SST(0x5B, 0x01, SS_RDEF, "Threshold condition met") }, -/* DTLPWRSOM */{SST(0x5B, 0x02, SS_DEF, +/* DTLPWRSOM */{SST(0x5B, 0x02, SS_RDEF, "Log counter at maximum") }, -/* DTLPWRSOM */{SST(0x5B, 0x03, SS_DEF, +/* DTLPWRSOM */{SST(0x5B, 0x03, SS_RDEF, "Log list codes exhausted") }, -/* D O */{SST(0x5C, 0x00, SS_DEF, +/* D O */{SST(0x5C, 0x00, SS_RDEF, "RPL status change") }, -/* D O */{SST(0x5C, 0x01, SS_NEDEF, +/* D O */{SST(0x5C, 0x01, SS_NOP|SSQ_PRINT_SENSE, "Spindles synchronized") }, -/* D O */{SST(0x5C, 0x02, SS_DEF, +/* D O */{SST(0x5C, 0x02, SS_RDEF, "Spindles not synchronized") }, -/* DTLPWRSOMCAE */{SST(0x5D, 0x00, SS_DEF, +/* DTLPWRSOMCAE */{SST(0x5D, 0x00, SS_RDEF, "Failure prediction threshold exceeded") }, -/* DTLPWRSOMCAE */{SST(0x5D, 0xFF, SS_DEF, +/* DTLPWRSOMCAE */{SST(0x5D, 0xFF, SS_RDEF, "Failure prediction threshold exceeded (false)") }, -/* DTLPWRSO CA */{SST(0x5E, 0x00, SS_DEF, +/* DTLPWRSO CA */{SST(0x5E, 0x00, SS_RDEF, "Low power condition on") }, -/* DTLPWRSO CA */{SST(0x5E, 0x01, SS_DEF, +/* DTLPWRSO CA */{SST(0x5E, 0x01, SS_RDEF, "Idle condition activated by timer") }, -/* DTLPWRSO CA */{SST(0x5E, 0x02, SS_DEF, +/* DTLPWRSO CA */{SST(0x5E, 0x02, SS_RDEF, "Standby condition activated by timer") }, -/* DTLPWRSO CA */{SST(0x5E, 0x03, SS_DEF, +/* DTLPWRSO CA */{SST(0x5E, 0x03, SS_RDEF, "Idle condition activated by command") }, -/* DTLPWRSO CA */{SST(0x5E, 0x04, SS_DEF, +/* DTLPWRSO CA */{SST(0x5E, 0x04, SS_RDEF, "Standby condition activated by command") }, -/* S */{SST(0x60, 0x00, SS_DEF, +/* S */{SST(0x60, 0x00, SS_RDEF, "Lamp failure") }, -/* S */{SST(0x61, 0x00, SS_DEF, +/* S */{SST(0x61, 0x00, SS_RDEF, "Video acquisition error") }, -/* S */{SST(0x61, 0x01, SS_DEF, +/* S */{SST(0x61, 0x01, SS_RDEF, "Unable to acquire video") }, -/* S */{SST(0x61, 0x02, SS_DEF, +/* S */{SST(0x61, 0x02, SS_RDEF, "Out of focus") }, -/* S */{SST(0x62, 0x00, SS_DEF, +/* S */{SST(0x62, 0x00, SS_RDEF, "Scan head positioning error") }, -/* R */{SST(0x63, 0x00, SS_DEF, +/* R */{SST(0x63, 0x00, SS_RDEF, "End of user area encountered on this track") }, -/* R */{SST(0x63, 0x01, SS_NEDEF|ENOSPC, +/* R */{SST(0x63, 0x01, SS_FATAL|ENOSPC, "Packet does not fit in available space") }, -/* R */{SST(0x64, 0x00, SS_DEF, +/* R */{SST(0x64, 0x00, SS_RDEF, "Illegal mode for this track") }, -/* R */{SST(0x64, 0x01, SS_DEF, +/* R */{SST(0x64, 0x01, SS_RDEF, "Invalid packet size") }, -/* DTLPWRSOMCAE */{SST(0x65, 0x00, SS_DEF, +/* DTLPWRSOMCAE */{SST(0x65, 0x00, SS_RDEF, "Voltage fault") }, -/* S */{SST(0x66, 0x00, SS_DEF, +/* S */{SST(0x66, 0x00, SS_RDEF, "Automatic document feeder cover up") }, -/* S */{SST(0x66, 0x01, SS_DEF, +/* S */{SST(0x66, 0x01, SS_RDEF, "Automatic document feeder lift up") }, -/* S */{SST(0x66, 0x02, SS_DEF, +/* S */{SST(0x66, 0x02, SS_RDEF, "Document jam in automatic document feeder") }, -/* S */{SST(0x66, 0x03, SS_DEF, +/* S */{SST(0x66, 0x03, SS_RDEF, "Document miss feed automatic in document feeder") }, -/* A */{SST(0x67, 0x00, SS_DEF, +/* A */{SST(0x67, 0x00, SS_RDEF, "Configuration failure") }, -/* A */{SST(0x67, 0x01, SS_DEF, +/* A */{SST(0x67, 0x01, SS_RDEF, "Configuration of incapable logical units failed") }, -/* A */{SST(0x67, 0x02, SS_DEF, +/* A */{SST(0x67, 0x02, SS_RDEF, "Add logical unit failed") }, -/* A */{SST(0x67, 0x03, SS_DEF, +/* A */{SST(0x67, 0x03, SS_RDEF, "Modification of logical unit failed") }, -/* A */{SST(0x67, 0x04, SS_DEF, +/* A */{SST(0x67, 0x04, SS_RDEF, "Exchange of logical unit failed") }, -/* A */{SST(0x67, 0x05, SS_DEF, +/* A */{SST(0x67, 0x05, SS_RDEF, "Remove of logical unit failed") }, -/* A */{SST(0x67, 0x06, SS_DEF, +/* A */{SST(0x67, 0x06, SS_RDEF, "Attachment of logical unit failed") }, -/* A */{SST(0x67, 0x07, SS_DEF, +/* A */{SST(0x67, 0x07, SS_RDEF, "Creation of logical unit failed") }, -/* A */{SST(0x68, 0x00, SS_DEF, +/* A */{SST(0x68, 0x00, SS_RDEF, "Logical unit not configured") }, -/* A */{SST(0x69, 0x00, SS_DEF, +/* A */{SST(0x69, 0x00, SS_RDEF, "Data loss on logical unit") }, -/* A */{SST(0x69, 0x01, SS_DEF, +/* A */{SST(0x69, 0x01, SS_RDEF, "Multiple logical unit failures") }, -/* A */{SST(0x69, 0x02, SS_DEF, +/* A */{SST(0x69, 0x02, SS_RDEF, "Parity/data mismatch") }, -/* A */{SST(0x6A, 0x00, SS_DEF, +/* A */{SST(0x6A, 0x00, SS_RDEF, "Informational, refer to log") }, -/* A */{SST(0x6B, 0x00, SS_DEF, +/* A */{SST(0x6B, 0x00, SS_RDEF, "State change has occurred") }, -/* A */{SST(0x6B, 0x01, SS_DEF, +/* A */{SST(0x6B, 0x01, SS_RDEF, "Redundancy level got better") }, -/* A */{SST(0x6B, 0x02, SS_DEF, +/* A */{SST(0x6B, 0x02, SS_RDEF, "Redundancy level got worse") }, -/* A */{SST(0x6C, 0x00, SS_DEF, +/* A */{SST(0x6C, 0x00, SS_RDEF, "Rebuild failure occurred") }, -/* A */{SST(0x6D, 0x00, SS_DEF, +/* A */{SST(0x6D, 0x00, SS_RDEF, "Recalculate failure occurred") }, -/* A */{SST(0x6E, 0x00, SS_DEF, +/* A */{SST(0x6E, 0x00, SS_RDEF, "Command to logical unit failed") }, -/* T */{SST(0x70, 0x00, SS_DEF, +/* T */{SST(0x70, 0x00, SS_RDEF, "Decompression exception short: ASCQ = Algorithm ID") }, -/* T */{SST(0x70, 0xFF, SS_DEF|SSQ_RANGE, +/* T */{SST(0x70, 0xFF, SS_RDEF|SSQ_RANGE, NULL) }, /* Range 0x00 -> 0xFF */ -/* T */{SST(0x71, 0x00, SS_DEF, +/* T */{SST(0x71, 0x00, SS_RDEF, "Decompression exception long: ASCQ = Algorithm ID") }, -/* T */{SST(0x71, 0xFF, SS_DEF|SSQ_RANGE, +/* T */{SST(0x71, 0xFF, SS_RDEF|SSQ_RANGE, NULL) }, /* Range 0x00 -> 0xFF */ -/* R */{SST(0x72, 0x00, SS_DEF, +/* R */{SST(0x72, 0x00, SS_RDEF, "Session fixation error") }, -/* R */{SST(0x72, 0x01, SS_DEF, +/* R */{SST(0x72, 0x01, SS_RDEF, "Session fixation error writing lead-in") }, -/* R */{SST(0x72, 0x02, SS_DEF, +/* R */{SST(0x72, 0x02, SS_RDEF, "Session fixation error writing lead-out") }, -/* R */{SST(0x72, 0x03, SS_DEF, +/* R */{SST(0x72, 0x03, SS_RDEF, "Session fixation error - incomplete track in session") }, -/* R */{SST(0x72, 0x04, SS_DEF, +/* R */{SST(0x72, 0x04, SS_RDEF, "Empty or partially written reserved track") }, -/* R */{SST(0x73, 0x00, SS_DEF, +/* R */{SST(0x73, 0x00, SS_RDEF, "CD control error") }, -/* R */{SST(0x73, 0x01, SS_DEF, +/* R */{SST(0x73, 0x01, SS_RDEF, "Power calibration area almost full") }, -/* R */{SST(0x73, 0x02, SS_NEDEF|ENOSPC, +/* R */{SST(0x73, 0x02, SS_FATAL|ENOSPC, "Power calibration area is full") }, -/* R */{SST(0x73, 0x03, SS_DEF, +/* R */{SST(0x73, 0x03, SS_RDEF, "Power calibration area error") }, -/* R */{SST(0x73, 0x04, SS_DEF, +/* R */{SST(0x73, 0x04, SS_RDEF, "Program memory area update failure") }, -/* R */{SST(0x73, 0x05, SS_DEF, +/* R */{SST(0x73, 0x05, SS_RDEF, "program memory area is full") } }; -#if !defined(SCSI_NO_SENSE_STRINGS) -const char * -scsi_sense_desc(int asc, int ascq, struct scsi_inquiry_data *inq_data) +const int asc_table_size = sizeof(asc_table)/sizeof(asc_table[0]); + +struct asc_key { - int i, j; - caddr_t match; - struct asc_table_entry *table[2]; - int table_size[2]; - int num_tables; + int asc; + int ascq; +}; + +static int +ascentrycomp(const void *key, const void *member) +{ + int asc; + int ascq; + const struct asc_table_entry *table_entry; + + asc = ((const struct asc_key *)key)->asc; + ascq = ((const struct asc_key *)key)->ascq; + table_entry = (const struct asc_table_entry *)member; + + if (asc >= table_entry->asc) { + + if (asc > table_entry->asc) + return (1); + + if (ascq <= table_entry->ascq) { + /* Check for ranges */ + if (ascq == table_entry->ascq + || ((table_entry->action & SSQ_RANGE) != 0 + && ascq >= (table_entry - 1)->ascq)) + return (0); + return (-1); + } + return (1); + } + return (-1); +} - if (inq_data == NULL) - return(NULL); +static int +senseentrycomp(const void *key, const void *member) +{ + int sense_key; + const struct sense_key_table_entry *table_entry; - match = cam_quirkmatch((caddr_t)inq_data, - (caddr_t)asc_quirk_table, - sizeof(asc_quirk_table)/sizeof(*asc_quirk_table), - sizeof(*asc_quirk_table), scsi_inquiry_match); + sense_key = *((const int *)key); + table_entry = (const struct sense_key_table_entry *)member; + + if (sense_key >= table_entry->sense_key) { + if (sense_key == table_entry->sense_key) + return (0); + return (1); + } + return (-1); +} + +static void +fetchtableentries(int sense_key, int asc, int ascq, + struct scsi_inquiry_data *inq_data, + const struct sense_key_table_entry **sense_entry, + const struct asc_table_entry **asc_entry) +{ + caddr_t match; + const struct asc_table_entry *asc_tables[2]; + const struct sense_key_table_entry *sense_tables[2]; + struct asc_key asc_ascq; + size_t asc_tables_size[2]; + size_t sense_tables_size[2]; + int num_asc_tables; + int num_sense_tables; + int i; + + /* Default to failure */ + *sense_entry = NULL; + *asc_entry = NULL; + match = NULL; + if (inq_data != NULL) + match = cam_quirkmatch((caddr_t)inq_data, + (caddr_t)sense_quirk_table, + sense_quirk_table_size, + sizeof(*sense_quirk_table), + scsi_inquiry_match); if (match != NULL) { - table[0] = ((struct scsi_sense_quirk_entry *)match)->asc_info; - table_size[0] = - ((struct scsi_sense_quirk_entry *)match)->num_ascs; - table[1] = asc_text; - table_size[1] = sizeof(asc_text)/sizeof(asc_text[0]); - num_tables = 2; + struct scsi_sense_quirk_entry *quirk; + + quirk = (struct scsi_sense_quirk_entry *)match; + asc_tables[0] = quirk->asc_info; + asc_tables_size[0] = quirk->num_ascs; + asc_tables[1] = asc_table; + asc_tables_size[1] = asc_table_size; + num_asc_tables = 2; + sense_tables[0] = quirk->sense_key_info; + sense_tables_size[0] = quirk->num_sense_keys; + sense_tables[1] = sense_key_table; + sense_tables_size[1] = sense_key_table_size; + num_sense_tables = 2; } else { - table[0] = asc_text; - table_size[0] = sizeof(asc_text)/sizeof(asc_text[0]); - num_tables = 1; + asc_tables[0] = asc_table; + asc_tables_size[0] = asc_table_size; + num_asc_tables = 1; + sense_tables[0] = sense_key_table; + sense_tables_size[0] = sense_key_table_size; + num_sense_tables = 1; } - for (j = 0; j < num_tables; j++) { - for (i = 0; i < table_size[j]; i++) { - if (table[j][i].asc == asc) { + asc_ascq.asc = asc; + asc_ascq.ascq = ascq; + for (i = 0; i < num_asc_tables; i++) { + void *found_entry; - /* Check for ranges */ - if ((table[j][i].action & SSQ_RANGE) != 0) { - - if (table[j][i].ascq >= ascq - && table[j][i-1].ascq <= ascq) - return table[j][i-1].desc; + found_entry = bsearch(&asc_ascq, asc_tables[i], + asc_tables_size[i], + sizeof(**asc_tables), + ascentrycomp); - continue; - } - - if (table[j][i].ascq == ascq) - return table[j][i].desc; - } + if (found_entry) { + *asc_entry = (struct asc_table_entry *)found_entry; + break; } } - if (asc >= 0x80 && asc <= 0xff) - return "Vendor Specific ASC"; + for (i = 0; i < num_sense_tables; i++) { + void *found_entry; - if (ascq >= 0x80 && ascq <= 0xff) - return "Vendor Specific ASCQ"; + found_entry = bsearch(&sense_key, sense_tables[i], + sense_tables_size[i], + sizeof(**sense_tables), + senseentrycomp); - return "Reserved ASC/ASCQ pair"; + if (found_entry) { + *sense_entry = + (struct sense_key_table_entry *)found_entry; + break; + } + } } -#else /* SCSI_NO_SENSE_STRINGS */ -const char * -scsi_sense_desc(int asc, int ascq, struct scsi_inquiry_data *inq_data) +void +scsi_sense_desc(int sense_key, int asc, int ascq, + struct scsi_inquiry_data *inq_data, + const char **sense_key_desc, const char **asc_desc) { - return (""); + const struct asc_table_entry *asc_entry; + const struct sense_key_table_entry *sense_entry; + + fetchtableentries(sense_key, asc, ascq, + inq_data, + &sense_entry, + &asc_entry); + + *sense_key_desc = sense_entry->desc; + + if (asc_entry != NULL) + *asc_desc = asc_entry->desc; + else if (asc >= 0x80 && asc <= 0xff) + *asc_desc = "Vendor Specific ASC"; + else if (ascq >= 0x80 && ascq <= 0xff) + *asc_desc = "Vendor Specific ASCQ"; + else + *asc_desc = "Reserved ASC/ASCQ pair"; } -#endif /* - * Given a particular failed CCB and its device type information, return - * the appropriate action from either the sense code quirk table or the - * sense code table. + * Given sense and device type information, return the appropriate action. + * If we do not understand the specific error as identified by the ASC/ASCQ + * pair, fall back on the more generic actions derived from the sense key. */ scsi_sense_action -scsi_error_action(int asc, int ascq, struct scsi_inquiry_data *inq_data) +scsi_error_action(struct ccb_scsiio *csio, struct scsi_inquiry_data *inq_data, + u_int32_t sense_flags) { - caddr_t match; - struct asc_table_entry *table[2]; - int table_size[2]; - int num_tables; - int i, j; + const struct asc_table_entry *asc_entry; + const struct sense_key_table_entry *sense_entry; + int error_code, sense_key, asc, ascq; + scsi_sense_action action; - /* - * If we don't have inquiry data, we can't match against any quirk - * entries. - */ - if (inq_data != NULL) { - match = cam_quirkmatch((caddr_t)inq_data, - (caddr_t)asc_quirk_table, - sizeof(asc_quirk_table) / - sizeof(*asc_quirk_table), - sizeof(*asc_quirk_table), - scsi_inquiry_match); - } else - match = NULL; + scsi_extract_sense(&csio->sense_data, &error_code, + &sense_key, &asc, &ascq); - if (match != NULL) { - table[0] = ((struct scsi_sense_quirk_entry *)match)->asc_info; - table_size[0] = - ((struct scsi_sense_quirk_entry *)match)->num_ascs; - table[1] = asc_text; - table_size[1] = sizeof(asc_text)/sizeof(asc_text[0]); - num_tables = 2; + if (error_code == SSD_DEFERRED_ERROR) { + /* + * XXX dufault@FreeBSD.org + * This error doesn't relate to the command associated + * with this request sense. A deferred error is an error + * for a command that has already returned GOOD status + * (see SCSI2 8.2.14.2). + * + * By my reading of that section, it looks like the current + * command has been cancelled, we should now clean things up + * (hopefully recovering any lost data) and then retry the + * current command. There are two easy choices, both wrong: + * + * 1. Drop through (like we had been doing), thus treating + * this as if the error were for the current command and + * return and stop the current command. + * + * 2. Issue a retry (like I made it do) thus hopefully + * recovering the current transfer, and ignoring the + * fact that we've dropped a command. + * + * These should probably be handled in a device specific + * sense handler or punted back up to a user mode daemon + */ + action = SS_RETRY|SSQ_DECREMENT_COUNT|SSQ_PRINT_SENSE; } else { - table[0] = asc_text; - table_size[0] = sizeof(asc_text)/sizeof(asc_text[0]); - num_tables = 1; - } - - for (j = 0; j < num_tables; j++) { - for (i = 0; i < table_size[j]; i++) { - if (table[j][i].asc == asc) { - - /* Check for ranges */ - if ((table[j][i].action & SSQ_RANGE) != 0){ - - if (table[j][i].ascq >= ascq - && table[j][i-1].ascq <= ascq) - return table[j][i].action; + fetchtableentries(sense_key, asc, ascq, + inq_data, + &sense_entry, + &asc_entry); - continue; - } + /* + * Override the 'No additional Sense' entry (0,0) + * with the error action of the sense key. + */ + if (asc_entry != NULL + && (asc != 0 || ascq != 0)) + action = asc_entry->action; + else + action = sense_entry->action; - /* - * Check to see if we have a match. If the - * current ascq in the table is greater - * than our ascq, and there aren't any more - * tables to search, just return the - * default action. - */ - if (table[j][i].ascq == ascq) - return(table[j][i].action); - else if ((j == (num_tables - 1)) && - (table[j][i].ascq > ascq)) - return(SS_DEF); + if (sense_key == SSD_KEY_RECOVERED_ERROR) { + /* + * The action succeeded but the device wants + * the user to know that some recovery action + * was required. + */ + action &= ~(SS_MASK|SSQ_MASK|SS_ERRMASK); + action |= SS_NOP|SSQ_PRINT_SENSE; + } else if (sense_key == SSD_KEY_ILLEGAL_REQUEST) { + if ((sense_flags & SF_QUIET_IR) != 0) + action &= ~SSQ_PRINT_SENSE; + } else if (sense_key == SSD_KEY_UNIT_ATTENTION) { + if ((sense_flags & SF_RETRY_UA) != 0 + && (action & SS_MASK) == SS_FAIL) { + action &= ~(SS_MASK|SSQ_MASK); + action |= SS_RETRY|SSQ_DECREMENT_COUNT| + SSQ_PRINT_SENSE; } } } - /* - * If we get to this point, it's most likely a vendor specific - * ASC and we don't have a quirk entry for it. Oh well, we just - * tell the error handling code to take the default action. - */ - return(SS_DEF); +#ifdef KERNEL + if (bootverbose) + sense_flags |= SF_PRINT_ALWAYS; +#endif + if ((sense_flags & SF_PRINT_ALWAYS) != 0) + action |= SSQ_PRINT_SENSE; + else if ((sense_flags & SF_NO_PRINT) != 0) + action &= ~SSQ_PRINT_SENSE; + + return (action); } char * @@ -1600,42 +1722,63 @@ 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), "%x ", cdb_ptr[i]); return(cdb_string); } + +const char * +scsi_status_string(struct ccb_scsiio *csio) +{ + switch(csio->scsi_status) { + case SCSI_STATUS_OK: + return("OK"); + case SCSI_STATUS_CHECK_COND: + return("Check Condition"); + case SCSI_STATUS_BUSY: + return("Busy"); + case SCSI_STATUS_INTERMED: + return("Intermediate"); + case SCSI_STATUS_INTERMED_COND_MET: + return("Intermediate-Condition Met"); + case SCSI_STATUS_RESERV_CONFLICT: + return("Reservation Conflict"); + case SCSI_STATUS_CMD_TERMINATED: + return("Command Terminated"); + case SCSI_STATUS_QUEUE_FULL: + return("Queue Full"); + case SCSI_STATUS_ACA_ACTIVE: + return("ACA Active"); + case SCSI_STATUS_TASK_ABORTED: + return("Task Aborted"); + default: { + static char unkstr[64]; + snprintf(unkstr, sizeof(unkstr), "Unknown %#x", + csio->scsi_status); + return(unkstr); + } + } +} + /* - * scsi_sense_print will decode the sense data into human - * readable form. Sense handlers can use this to generate - * a report. - */ -/* - * Because scsi_sense_print() utilizes transport layer functions, it will - * only work in the kernel. + * scsi_command_string() returns 0 for success and -1 for failure. */ #ifdef _KERNEL - -void -scsi_sense_print(struct ccb_scsiio *csio) +int +scsi_command_string(struct ccb_scsiio *csio, struct sbuf *sb) +#else /* !_KERNEL */ +int +scsi_command_string(struct cam_device *device, struct ccb_scsiio *csio, + struct sbuf *sb) +#endif /* _KERNEL/!_KERNEL */ { - struct scsi_sense_data *sense; - u_int32_t info; - int error_code; - int sense_key; - int asc, ascq; - struct ccb_getdev cgd; - u_int8_t command_print; - - sense = &csio->sense_data; - - /* - * If the CDB is a physical address, we can't deal with it.. - */ - if ((csio->ccb_h.flags & CAM_CDB_PHYS) != 0) - command_print = 0; - else - command_print = 1; + struct scsi_inquiry_data *inq_data; + char cdb_str[(SCSI_MAX_CDBLEN * 3) + 1]; +#ifdef _KERNEL + struct ccb_getdev cgd; +#endif /* _KERNEL */ +#ifdef _KERNEL /* * Get the device information. */ @@ -1652,209 +1795,109 @@ scsi_sense_print(struct ccb_scsiio *csio) if (cgd.ccb_h.status == CAM_DEV_NOT_THERE) cgd.inq_data.device = T_DIRECT; - if (command_print != 0) { - char cdb_str[(SCSI_MAX_CDBLEN * 3) + 1]; - - xpt_print_path(csio->ccb_h.path); - - if ((csio->ccb_h.flags & CAM_CDB_POINTER) != 0) { - printf("%s. CDB: %s\n", - scsi_op_desc(csio->cdb_io.cdb_ptr[0], - &cgd.inq_data), - scsi_cdb_string(csio->cdb_io.cdb_ptr, cdb_str, - sizeof(cdb_str))); - } else { - printf("%s. CDB: %s\n", - scsi_op_desc(csio->cdb_io.cdb_bytes[0], - &cgd.inq_data), scsi_cdb_string( - csio->cdb_io.cdb_bytes, cdb_str, - sizeof(cdb_str))); - } - } - - /* - * If the sense data is a physical pointer, forget it. - */ - if (csio->ccb_h.flags & CAM_SENSE_PTR) { - if (csio->ccb_h.flags & CAM_SENSE_PHYS) - return; - else { - /* - * XXX KDM this is stupid, but casting the - * structure doesn't work... - */ - bcopy(&csio->sense_data, sense, - sizeof(struct scsi_sense_data *)); - } - } else { - /* - * If the physical sense flag is set, but the sense pointer - * is not also set, we assume that the user is an idiot and - * return. (Well, okay, it could be that somehow, the - * entire csio is physical, but we would have probably core - * dumped on one of the bogus pointer deferences above - * already.) - */ - if (csio->ccb_h.flags & CAM_SENSE_PHYS) - return; - else - sense = &csio->sense_data; - } - - xpt_print_path(csio->ccb_h.path); - error_code = sense->error_code & SSD_ERRCODE; - sense_key = sense->flags & SSD_KEY; - - switch (error_code) { - case SSD_DEFERRED_ERROR: - printf("Deferred Error: "); - /* FALLTHROUGH */ - case SSD_CURRENT_ERROR: - - printf("%s", scsi_sense_key_text[sense_key]); - 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: - printf(" req sz: %d (decimal)", - info); - break; - default: - if (info) { - if (sense->flags & SSD_ILI) { - printf(" ILI (length mismatch):" - " %d", info); - } else { - printf(" info:%x", info); - } - } - } - } else if (info) - printf(" info?:%x", info); - - if (sense->extra_len >= 4) { - if (bcmp(sense->cmd_spec_info, "\0\0\0\0", 4)) { - printf(" 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]); - } - } - - asc = (sense->extra_len >= 5) ? sense->add_sense_code : 0; - ascq = (sense->extra_len >= 6) ? sense->add_sense_code_qual : 0; - - if (asc || ascq) { - const char *desc = scsi_sense_desc(asc, ascq, - &cgd.inq_data); - printf(" asc:%x,%x\n", asc, ascq); + inq_data = &cgd.inq_data; - xpt_print_path(csio->ccb_h.path); - printf("%s", desc); - } +#else /* !_KERNEL */ - if (sense->extra_len >= 7 && sense->fru) { - printf(" field replaceable unit: %x", sense->fru); - } + inq_data = &device->inq_data; - if ((sense->extra_len >= 10) - && (sense->sense_key_spec[0] & SSD_SCS_VALID) != 0) { - printf(" sks:%x,%x", sense->sense_key_spec[0], - scsi_2btoul(&sense->sense_key_spec[1])); - } - break; +#endif /* _KERNEL/!_KERNEL */ - default: - printf("error code %d", - sense->error_code & SSD_ERRCODE); - if (sense->error_code & SSD_ERRCODE_VALID) { - printf(" at block no. %d (decimal)", - info = scsi_4btoul(sense->info)); - } + if ((csio->ccb_h.flags & CAM_CDB_POINTER) != 0) { + sbuf_printf(sb, "%s. CDB: %s", + scsi_op_desc(csio->cdb_io.cdb_ptr[0], inq_data), + scsi_cdb_string(csio->cdb_io.cdb_ptr, cdb_str, + sizeof(cdb_str))); + } else { + sbuf_printf(sb, "%s. CDB: %s", + scsi_op_desc(csio->cdb_io.cdb_bytes[0], inq_data), + scsi_cdb_string(csio->cdb_io.cdb_bytes, cdb_str, + sizeof(cdb_str))); } - printf("\n"); + return(0); } -#else /* !_KERNEL */ - -char * -scsi_sense_string(struct cam_device *device, struct ccb_scsiio *csio, - char *str, int str_len) +/* + * scsi_sense_sbuf() returns 0 for success and -1 for failure. + */ +#ifdef _KERNEL +int +scsi_sense_sbuf(struct ccb_scsiio *csio, struct sbuf *sb, + scsi_sense_string_flags flags) +#else /* !_KERNEL */ +int +scsi_sense_sbuf(struct cam_device *device, struct ccb_scsiio *csio, + struct sbuf *sb, scsi_sense_string_flags flags) +#endif /* _KERNEL/!_KERNEL */ { struct scsi_sense_data *sense; + struct scsi_inquiry_data *inq_data; +#ifdef _KERNEL + struct ccb_getdev cgd; +#endif /* _KERNEL */ u_int32_t info; int error_code; int sense_key; int asc, ascq; - u_int8_t command_print; char path_str[64]; - char tmpstr[2048]; - int tmpstrlen = 2048; - int cur_len = 0, tmplen = 0, retlen; - if ((device == NULL) || (csio == NULL) || (str == NULL)) - return(NULL); - - if (str_len <= 0) - return(NULL); +#ifndef _KERNEL + if (device == NULL) + return(-1); +#endif /* !_KERNEL */ + if ((csio == NULL) || (sb == NULL)) + return(-1); /* * If the CDB is a physical address, we can't deal with it.. */ if ((csio->ccb_h.flags & CAM_CDB_PHYS) != 0) - command_print = 0; - else - command_print = 1; + flags &= ~SSS_FLAG_PRINT_COMMAND; + +#ifdef _KERNEL + xpt_path_string(csio->ccb_h.path, path_str, sizeof(path_str)); +#else /* !_KERNEL */ + cam_path_string(device, path_str, sizeof(path_str)); +#endif /* _KERNEL/!_KERNEL */ + +#ifdef _KERNEL + /* + * Get the device information. + */ + xpt_setup_ccb(&cgd.ccb_h, + csio->ccb_h.path, + /*priority*/ 1); + cgd.ccb_h.func_code = XPT_GDEV_TYPE; + xpt_action((union ccb *)&cgd); + + /* + * If the device is unconfigured, just pretend that it is a hard + * drive. scsi_op_desc() needs this. + */ + if (cgd.ccb_h.status == CAM_DEV_NOT_THERE) + cgd.inq_data.device = T_DIRECT; + + inq_data = &cgd.inq_data; + +#else /* !_KERNEL */ - cam_path_string(device, path_str, 64); + inq_data = &device->inq_data; - str[0] = '\0'; +#endif /* _KERNEL/!_KERNEL */ sense = NULL; - if (command_print != 0) { - char cdb_str[(SCSI_MAX_CDBLEN * 3) + 1]; - - retlen = snprintf(tmpstr, tmpstrlen, "%s", path_str); - - if ((tmplen = str_len - cur_len - 1) < 0) - goto sst_bailout; - - strncat(str, tmpstr, tmplen); - cur_len += retlen; - str[str_len - 1] = '\0'; - - if ((csio->ccb_h.flags & CAM_CDB_POINTER) != 0) { - retlen = snprintf(tmpstr, tmpstrlen, "%s. CDB: %s\n", - scsi_op_desc(csio->cdb_io.cdb_ptr[0], - &device->inq_data), - scsi_cdb_string(csio->cdb_io.cdb_ptr, - cdb_str, - sizeof(cdb_str))); - } else { - retlen = snprintf(tmpstr, tmpstrlen, "%s. CDB: %s\n", - scsi_op_desc(csio->cdb_io.cdb_bytes[0], - &device->inq_data), scsi_cdb_string( - csio->cdb_io.cdb_bytes, cdb_str, - sizeof(cdb_str))); - } + if (flags & SSS_FLAG_PRINT_COMMAND) { - if ((tmplen = str_len - cur_len - 1) < 0) - goto sst_bailout; + sbuf_cat(sb, path_str); - strncat(str, tmpstr, tmplen); - cur_len += retlen; - str[str_len - 1] = '\0'; +#ifdef _KERNEL + scsi_command_string(csio, sb); +#else /* !_KERNEL */ + scsi_command_string(device, csio, sb); +#endif /* _KERNEL/!_KERNEL */ } /* @@ -1862,11 +1905,12 @@ scsi_sense_string(struct cam_device *device, struct ccb_scsiio *csio, */ if (csio->ccb_h.flags & CAM_SENSE_PTR) { if (csio->ccb_h.flags & CAM_SENSE_PHYS) - return(NULL); + return(-1); else { /* - * XXX KDM this is stupid, but casting the - * structure doesn't work... + * bcopy the pointer to avoid unaligned access + * errors on finicky architectures. We don't + * ensure that the sense data is pointer aligned. */ bcopy(&csio->sense_data, sense, sizeof(struct scsi_sense_data *)); @@ -1881,46 +1925,32 @@ scsi_sense_string(struct cam_device *device, struct ccb_scsiio *csio, * already.) */ if (csio->ccb_h.flags & CAM_SENSE_PHYS) - return(NULL); + return(-1); else sense = &csio->sense_data; } - retlen = snprintf(tmpstr, tmpstrlen, "%s", path_str); - - if ((tmplen = str_len - cur_len - 1) < 0) - goto sst_bailout; - - strncat(str, tmpstr, tmplen); - cur_len += retlen; - str[str_len - 1] = '\0'; + sbuf_cat(sb, path_str); error_code = sense->error_code & SSD_ERRCODE; sense_key = sense->flags & SSD_KEY; switch (error_code) { case SSD_DEFERRED_ERROR: - retlen = snprintf(tmpstr, tmpstrlen, "Deferred Error: "); - - if ((tmplen = str_len - cur_len - 1) < 0) - goto sst_bailout; + sbuf_printf(sb, "Deferred Error: "); - strncat(str, tmpstr, tmplen); - cur_len += retlen; - str[str_len - 1] = '\0'; /* FALLTHROUGH */ case SSD_CURRENT_ERROR: + { + const char *sense_key_desc; + const char *asc_desc; - retlen = snprintf(tmpstr, tmpstrlen, "%s", - scsi_sense_key_text[sense_key]); - - if ((tmplen = str_len - cur_len - 1) < 0) - goto sst_bailout; - - strncat(str, tmpstr, tmplen); - cur_len += retlen; - str[str_len - 1] = '\0'; + 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); @@ -1933,363 +1963,169 @@ scsi_sense_string(struct cam_device *device, struct ccb_scsiio *csio, case SSD_KEY_DATA_PROTECT: break; case SSD_KEY_BLANK_CHECK: - retlen = snprintf(tmpstr, tmpstrlen, - " req sz: %d (decimal)", - info); - - if ((tmplen = str_len - cur_len - 1) < 0) - goto sst_bailout; - - strncat(str, tmpstr, tmplen); - cur_len += retlen; - str[str_len - 1] = '\0'; + sbuf_printf(sb, " req sz: %d (decimal)", info); break; default: if (info) { if (sense->flags & SSD_ILI) { - retlen = snprintf (tmpstr, - tmpstrlen, - " ILI (length " + sbuf_printf(sb, " ILI (length " "mismatch): %d", info); } else { - retlen = snprintf(tmpstr, - tmpstrlen, - " info:%x", - info); + sbuf_printf(sb, " info:%x", + info); } - - if ((tmplen = str_len - cur_len -1) < 0) - goto sst_bailout; - - strncat(str, tmpstr, tmplen); - cur_len += retlen; - str[str_len - 1] = '\0'; } } } else if (info) { - retlen = snprintf(tmpstr, tmpstrlen," info?:%x", info); - - if ((tmplen = str_len - cur_len -1) < 0) - goto sst_bailout; - - strncat(str, tmpstr, tmplen); - cur_len += retlen; - str[str_len - 1] = '\0'; + sbuf_printf(sb, " info?:%x", info); } if (sense->extra_len >= 4) { if (bcmp(sense->cmd_spec_info, "\0\0\0\0", 4)) { - retlen = snprintf(tmpstr, tmpstrlen, - " 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]); - - if ((tmplen = str_len - cur_len -1) < 0) - goto sst_bailout; - - strncat(str, tmpstr, tmplen); - cur_len += retlen; - str[str_len - 1] = '\0'; + 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]); } } - asc = (sense->extra_len >= 5) ? sense->add_sense_code : 0; - ascq = (sense->extra_len >= 6) ? sense->add_sense_code_qual : 0; - if (asc || ascq) { - const char *desc = scsi_sense_desc(asc, ascq, - &device->inq_data); - retlen = snprintf(tmpstr, tmpstrlen, - " asc:%x,%x\n%s%s", asc, ascq, - path_str, desc); - - if ((tmplen = str_len - cur_len -1) < 0) - goto sst_bailout; - - strncat(str, tmpstr, tmplen); - cur_len += retlen; - str[str_len - 1] = '\0'; + sbuf_printf(sb, " asc:%x,%x\n%s%s", asc, ascq, + path_str, asc_desc); } if (sense->extra_len >= 7 && sense->fru) { - retlen = snprintf(tmpstr, tmpstrlen, - " field replaceable unit: %x", - sense->fru); - - if ((tmplen = str_len - cur_len -1) < 0) - goto sst_bailout; - - strncat(str, tmpstr, tmplen); - str[str_len - 1] = '\0'; - cur_len += retlen; + sbuf_printf(sb, " field replaceable unit: %x", + sense->fru); } if ((sense->extra_len >= 10) && (sense->sense_key_spec[0] & SSD_SCS_VALID) != 0) { - retlen = snprintf(tmpstr, tmpstrlen, " sks:%x,%x", - sense->sense_key_spec[0], - scsi_2btoul(&sense->sense_key_spec[1])); - - if ((tmplen = str_len - cur_len -1) < 0) - goto sst_bailout; - - strncat(str, tmpstr, tmplen); - str[str_len - 1] = '\0'; - cur_len += retlen; + 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 %s is 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: - retlen = snprintf(tmpstr, tmpstrlen, "error code %d", - sense->error_code & SSD_ERRCODE); - - if ((tmplen = str_len - cur_len -1) < 0) - goto sst_bailout; - - strncat(str, tmpstr, tmplen); - cur_len += retlen; - str[str_len - 1] = '\0'; + sbuf_printf(sb, "error code %d", + sense->error_code & SSD_ERRCODE); if (sense->error_code & SSD_ERRCODE_VALID) { - retlen = snprintf(tmpstr, tmpstrlen, - " at block no. %d (decimal)", - info = scsi_4btoul(sense->info)); - - if ((tmplen = str_len - cur_len -1) < 0) - goto sst_bailout; - - strncat(str, tmpstr, tmplen); - cur_len += retlen; - str[str_len - 1] = '\0'; + sbuf_printf(sb, " at block no. %d (decimal)", + info = scsi_4btoul(sense->info)); } } - retlen = snprintf(tmpstr, tmpstrlen, "\n"); - - if ((tmplen = str_len - cur_len -1) < 0) - goto sst_bailout; + sbuf_printf(sb, "\n"); - strncat(str, tmpstr, tmplen); - cur_len += retlen; - str[str_len - 1] = '\0'; + return(0); +} -sst_bailout: - return(str); -} -void -scsi_sense_print(struct cam_device *device, struct ccb_scsiio *csio, - FILE *ofile) +#ifdef _KERNEL +char * +scsi_sense_string(struct ccb_scsiio *csio, char *str, int str_len) +#else /* !_KERNEL */ +char * +scsi_sense_string(struct cam_device *device, struct ccb_scsiio *csio, + char *str, int str_len) +#endif /* _KERNEL/!_KERNEL */ { - char str[2048]; - - if ((device == NULL) || (csio == NULL) || (ofile == NULL)) - return; + struct sbuf sb; - fprintf(ofile, "%s", scsi_sense_string(device, csio, str, 2048)); -} + sbuf_new(&sb, str, str_len, 0); +#ifdef _KERNEL + scsi_sense_sbuf(csio, &sb, SSS_FLAG_PRINT_COMMAND); +#else /* !_KERNEL */ + scsi_sense_sbuf(device, csio, &sb, SSS_FLAG_PRINT_COMMAND); #endif /* _KERNEL/!_KERNEL */ + sbuf_finish(&sb); + + return(sbuf_data(&sb)); +} + #ifdef _KERNEL -int -scsi_interpret_sense(union ccb *ccb, u_int32_t sense_flags, - u_int32_t *relsim_flags, u_int32_t *openings, - u_int32_t *timeout, scsi_sense_action error_action) -#else -int -scsi_interpret_sense(struct cam_device *device, union ccb *ccb, - u_int32_t sense_flags, u_int32_t *relsim_flags, - u_int32_t *openings, u_int32_t *timeout, - scsi_sense_action error_action) -#endif +void +scsi_sense_print(struct ccb_scsiio *csio) { - struct scsi_sense_data *sense; - int error_code, sense_key, asc, ascq; - int error; - int print_sense; - struct ccb_scsiio *csio; - int retry; + struct sbuf sb; + char str[512]; - csio = &ccb->csio; - sense = &csio->sense_data; - scsi_extract_sense(sense, &error_code, &sense_key, &asc, &ascq); + sbuf_new(&sb, str, sizeof(str), 0); -#ifdef _KERNEL - if (bootverbose) { - sense_flags |= SF_PRINT_ALWAYS; - print_sense = TRUE; - } else if ((sense_flags & SF_NO_PRINT) == 0) -#else - if ((sense_flags & SF_NO_PRINT) == 0) -#endif - print_sense = TRUE; - else - print_sense = FALSE; + scsi_sense_sbuf(csio, &sb, SSS_FLAG_PRINT_COMMAND); - switch (error_code) { - case SSD_DEFERRED_ERROR: - { - /* - * XXX dufault@FreeBSD.org - * This error doesn't relate to the command associated - * with this request sense. A deferred error is an error - * for a command that has already returned GOOD status - * (see 8.2.14.2). - * - * By my reading of that section, it looks like the current - * command has been cancelled, we should now clean things up - * (hopefully recovering any lost data) and then retry the - * current command. There are two easy choices, both wrong: - * - * 1. Drop through (like we had been doing), thus treating - * this as if the error were for the current command and - * return and stop the current command. - * - * 2. Issue a retry (like I made it do) thus hopefully - * recovering the current transfer, and ignoring the - * fact that we've dropped a command. - * - * These should probably be handled in a device specific - * sense handler or punted back up to a user mode daemon - */ + sbuf_finish(&sb); - /* decrement the number of retries */ - retry = ccb->ccb_h.retry_count > 0; - if (retry) - ccb->ccb_h.retry_count--; + printf("%s", sbuf_data(&sb)); +} - error = ERESTART; - break; - } - case SSD_CURRENT_ERROR: - { - - switch (sense_key) { - case SSD_KEY_NO_SENSE: - /* Why were we called then? Well don't bail now */ - /* FALLTHROUGH */ - case SSD_KEY_EQUAL: - /* These should be filtered by the peripheral drivers */ - print_sense = FALSE; - /* FALLTHROUGH */ - case SSD_KEY_MISCOMPARE: - /* decrement the number of retries */ - retry = ccb->ccb_h.retry_count > 0; - if (retry) { - error = ERESTART; - ccb->ccb_h.retry_count--; - } else { - error = EIO; - } - case SSD_KEY_RECOVERED_ERROR: - error = 0; /* not an error */ - break; - case SSD_KEY_ILLEGAL_REQUEST: - if (((sense_flags & SF_QUIET_IR) != 0) - && ((sense_flags & SF_PRINT_ALWAYS) == 0)) - print_sense = FALSE; - error = EINVAL; - break; - case SSD_KEY_NOT_READY: - case SSD_KEY_DATA_PROTECT: - case SSD_KEY_VOLUME_OVERFLOW: - case SSD_KEY_BLANK_CHECK: /* should be filtered out by - peripheral drivers */ - retry = ccb->ccb_h.retry_count > 0; - if (retry) { - ccb->ccb_h.retry_count--; - error = ERESTART; - print_sense = FALSE; - } else { - if (((error_action & SSQ_PRINT_SENSE) == 0) - && ((sense_flags & SF_PRINT_ALWAYS) == 0)) - print_sense = FALSE; - - error = error_action & SS_ERRMASK; - } +#else /* !_KERNEL */ +void +scsi_sense_print(struct cam_device *device, struct ccb_scsiio *csio, + FILE *ofile) +{ + struct sbuf sb; + char str[512]; - break; - case SSD_KEY_UNIT_ATTENTION: - /* - * This should also be filtered out by - * peripheral drivers since each has a different - * concept of what it means to invalidate the media. - */ - if ((sense_flags & SF_RETRY_UA) != 0) { - /* don't decrement retry count */ - error = ERESTART; - print_sense = FALSE; - } else { - /* decrement the number of retries */ - retry = ccb->ccb_h.retry_count > 0; - if (retry) { - ccb->ccb_h.retry_count--; - error = ERESTART; - print_sense = FALSE; - } else { - if (((error_action & - SSQ_PRINT_SENSE) == 0) - && ((sense_flags & - SF_PRINT_ALWAYS) == 0)) - print_sense = FALSE; - - error = error_action & SS_ERRMASK; - } - } - break; - case SSD_KEY_ABORTED_COMMAND: - default: - /* decrement the number of retries */ - retry = ccb->ccb_h.retry_count > 0; - if (retry) { - ccb->ccb_h.retry_count--; - error = ERESTART; - print_sense = FALSE; - } else { - if (((error_action & SSQ_PRINT_SENSE) == 0) - && ((sense_flags & SF_PRINT_ALWAYS) == 0)) - print_sense = FALSE; - - error = error_action & SS_ERRMASK; - } - /* - * Make sure ABORTED COMMAND errors get - * printed as they're indicative of marginal - * SCSI busses that people should address. - */ - if (sense_key == SSD_KEY_ABORTED_COMMAND) - print_sense = TRUE; - } - break; - } - default: - /* decrement the number of retries */ - retry = ccb->ccb_h.retry_count > 0; - if (retry) { - ccb->ccb_h.retry_count--; - error = ERESTART; - print_sense = FALSE; - } else - error = EIO; - break; - } + if ((device == NULL) || (csio == NULL) || (ofile == NULL)) + return; - if (print_sense) { -#ifdef _KERNEL - scsi_sense_print(csio); -#else - scsi_sense_print(device, csio, stdout); -#endif - } - - return (error); + sbuf_new(&sb, str, sizeof(str), 0); + + scsi_sense_sbuf(device, csio, &sb, SSS_FLAG_PRINT_COMMAND); + + sbuf_finish(&sb); + + fprintf(ofile, "%s", sbuf_data(&sb)); } +#endif /* _KERNEL/!_KERNEL */ + /* * This function currently requires at least 36 bytes, or * SHORT_INQUIRY_LENGTH, worth of data to function properly. If this @@ -2849,7 +2685,7 @@ scsi_start_stop(struct ccb_scsiio *csio, u_int32_t retries, bzero(scsi_cmd, sizeof(*scsi_cmd)); scsi_cmd->opcode = START_STOP_UNIT; if (start != 0) { - scsi_cmd->how |= SSS_START; + scsi_cmd->how |= SS_START; /* it takes a lot of power to start a drive */ extra_flags |= CAM_HIGH_POWER; } diff --git a/sys/cam/scsi/scsi_all.h b/sys/cam/scsi/scsi_all.h index ca39b09..3c47b6e 100644 --- a/sys/cam/scsi/scsi_all.h +++ b/sys/cam/scsi/scsi_all.h @@ -92,16 +92,8 @@ typedef enum { SS_TUR = 0x040000, /* Send a Test Unit Ready command to the * device, then retry the original command. */ - SS_MANUAL = 0x050000, /* - * This error must be handled manually, - * i.e. the code must look at the asc and - * ascq values and determine the proper - * course of action. - */ - SS_TURSTART = 0x060000, /* - * Send a Test Unit Ready command to the - * device, and if that fails, send a start - * unit. + SS_REQSENSE = 0x050000, /* Send a RequestSense command to the + * device, then retry the original command. */ SS_MASK = 0xff0000 } scsi_sense_action; @@ -111,16 +103,10 @@ typedef enum { SSQ_DECREMENT_COUNT = 0x0100, /* Decrement the retry count */ SSQ_MANY = 0x0200, /* send lots of recovery commands */ SSQ_RANGE = 0x0400, /* - * Yes, this is a hack. Basically, - * if this flag is set then it - * represents an ascq range. The - * "correct" way to implement the - * ranges might be to add a special - * field to the sense code table, - * but that would take up a lot of - * additional space. This solution - * isn't as elegant, but is more - * space efficient. + * This table entry represents the + * end of a range of ASCQs that + * have identical error actions + * and text. */ SSQ_PRINT_SENSE = 0x0800, SSQ_MASK = 0xff00 @@ -129,14 +115,14 @@ typedef enum { /* Mask for error status values */ #define SS_ERRMASK 0xff -/* The default error action */ -#define SS_DEF SS_RETRY|SSQ_DECREMENT_COUNT|SSQ_PRINT_SENSE|EIO +/* The default, retyable, error action */ +#define SS_RDEF SS_RETRY|SSQ_DECREMENT_COUNT|SSQ_PRINT_SENSE|EIO -/* Default error action, without an error return value */ -#define SS_NEDEF SS_RETRY|SSQ_DECREMENT_COUNT|SSQ_PRINT_SENSE +/* The retyable, error action, with table specified error code */ +#define SS_RET SS_RETRY|SSQ_DECREMENT_COUNT|SSQ_PRINT_SENSE -/* Default error action, without sense printing or an error return value */ -#define SS_NEPDEF SS_RETRY|SSQ_DECREMENT_COUNT +/* Fatal error action, with table specified error code */ +#define SS_FATAL SS_FAIL|SSQ_PRINT_SENSE struct scsi_generic { @@ -493,7 +479,8 @@ struct scsi_inquiry_data u_int8_t device; #define SID_TYPE(inq_data) ((inq_data)->device & 0x1f) #define SID_QUAL(inq_data) (((inq_data)->device & 0xE0) >> 5) -#define SID_QUAL_LU_CONNECTED 0x00 /* The specified peripheral device +#define SID_QUAL_LU_CONNECTED 0x00 /* + * The specified peripheral device * type is currently connected to * logical unit. If the target cannot * determine whether or not a physical @@ -504,14 +491,16 @@ struct scsi_inquiry_data * does not mean that the device is * ready for access by the initiator. */ -#define SID_QUAL_LU_OFFLINE 0x01 /* The target is capable of supporting +#define SID_QUAL_LU_OFFLINE 0x01 /* + * The target is capable of supporting * the specified peripheral device type * on this logical unit; however, the * physical device is not currently * connected to this logical unit. */ #define SID_QUAL_RSVD 0x02 -#define SID_QUAL_BAD_LU 0x03 /* The target is not capable of +#define SID_QUAL_BAD_LU 0x03 /* + * The target is not capable of * supporting a physical device on * this logical unit. For this * peripheral qualifier the peripheral @@ -531,7 +520,7 @@ struct scsi_inquiry_data #define SCSI_REV_0 0 #define SCSI_REV_CCS 1 #define SCSI_REV_2 2 -#define SCSI_REV_3 3 +#define SCSI_REV_SPC 3 #define SCSI_REV_SPC2 4 #define SID_ECMA 0x38 @@ -569,6 +558,7 @@ struct scsi_inquiry_data #define SID_SPI_CLOCK_ST 0x00 #define SID_SPI_CLOCK_DT 0x04 #define SID_SPI_CLOCK_DT_ST 0x0C +#define SID_SPI_MASK 0x0F u_int8_t spi3data; u_int8_t reserved2; /* @@ -703,8 +693,10 @@ struct scsi_mode_blk_desc #define SCSI_STATUS_INTERMED 0x10 #define SCSI_STATUS_INTERMED_COND_MET 0x14 #define SCSI_STATUS_RESERV_CONFLICT 0x18 -#define SCSI_STATUS_CMD_TERMINATED 0x22 +#define SCSI_STATUS_CMD_TERMINATED 0x22 /* Obsolete in SAM-2 */ #define SCSI_STATUS_QUEUE_FULL 0x28 +#define SCSI_STATUS_ACA_ACTIVE 0x30 +#define SCSI_STATUS_TASK_ABORTED 0x40 struct scsi_inquiry_pattern { u_int8_t type; @@ -726,17 +718,23 @@ struct scsi_static_inquiry_pattern { struct scsi_sense_quirk_entry { struct scsi_inquiry_pattern inq_pat; + int num_sense_keys; int num_ascs; + struct sense_key_table_entry *sense_key_info; struct asc_table_entry *asc_info; }; +struct sense_key_table_entry { + u_int8_t sense_key; + u_int32_t action; + const char *desc; +}; + struct asc_table_entry { u_int8_t asc; u_int8_t ascq; u_int32_t action; -#if !defined(SCSI_NO_SENSE_STRINGS) const char *desc; -#endif }; struct op_table_entry { @@ -751,6 +749,10 @@ struct scsi_op_quirk_entry { struct op_table_entry *op_table; }; +typedef enum { + SSS_FLAG_NONE = 0x00, + SSS_FLAG_PRINT_COMMAND = 0x01 +} scsi_sense_string_flags; struct ccb_scsiio; struct cam_periph; @@ -761,12 +763,22 @@ struct cam_device; extern const char *scsi_sense_key_text[]; +struct sbuf; + __BEGIN_DECLS -const char * scsi_sense_desc(int asc, int ascq, - struct scsi_inquiry_data *inq_data); -scsi_sense_action scsi_error_action(int asc, int ascq, - struct scsi_inquiry_data *inq_data); +void scsi_sense_desc(int sense_key, int asc, int ascq, + struct scsi_inquiry_data *inq_data, + const char **sense_key_desc, const char **asc_desc); +scsi_sense_action scsi_error_action(struct ccb_scsiio* csio, + struct scsi_inquiry_data *inq_data, + u_int32_t sense_flags); +const char * scsi_status_string(struct ccb_scsiio *csio); #ifdef _KERNEL +int scsi_command_string(struct ccb_scsiio *csio, struct sbuf *sb); +int scsi_sense_sbuf(struct ccb_scsiio *csio, struct sbuf *sb, + scsi_sense_string_flags flags); +char * scsi_sense_string(struct ccb_scsiio *csio, + char *str, int str_len); void scsi_sense_print(struct ccb_scsiio *csio); int scsi_interpret_sense(union ccb *ccb, u_int32_t sense_flags, @@ -774,7 +786,12 @@ int scsi_interpret_sense(union ccb *ccb, u_int32_t *reduction, u_int32_t *timeout, scsi_sense_action error_action); -#else +#else /* _KERNEL */ +int scsi_command_string(struct cam_device *device, + struct ccb_scsiio *csio, struct sbuf *sb); +int scsi_sense_sbuf(struct cam_device *device, + struct ccb_scsiio *csio, struct sbuf *sb, + scsi_sense_string_flags flags); char * scsi_sense_string(struct cam_device *device, struct ccb_scsiio *csio, char *str, int str_len); @@ -793,7 +810,6 @@ int scsi_interpret_sense(struct cam_device *device, #define SF_NO_PRINT 0x02 #define SF_QUIET_IR 0x04 /* Be quiet about Illegal Request reponses */ #define SF_PRINT_ALWAYS 0x08 -#define SF_RETRY_SELTO 0x10 /* Retry selection timeouts */ const char * scsi_op_desc(u_int16_t opcode, diff --git a/sys/cam/scsi/scsi_cd.c b/sys/cam/scsi/scsi_cd.c index 40c540b..4768ff1 100644 --- a/sys/cam/scsi/scsi_cd.c +++ b/sys/cam/scsi/scsi_cd.c @@ -1557,10 +1557,8 @@ cddone(struct cam_periph *periph, union ccb *done_ccb) else sf = 0; - /* Retry selection timeouts */ - sf |= SF_RETRY_SELTO; - - if ((error = cderror(done_ccb, 0, sf)) == ERESTART) { + error = cderror(done_ccb, CAM_RETRY_SELTO, sf); + if (error == ERESTART) { /* * A retry was scheuled, so * just return. @@ -1659,8 +1657,8 @@ cddone(struct cam_periph *periph, union ccb *done_ccb) * Retry any UNIT ATTENTION type errors. They * are expected at boot. */ - error = cderror(done_ccb, 0, SF_RETRY_UA | - SF_NO_PRINT | SF_RETRY_SELTO); + error = cderror(done_ccb, CAM_RETRY_SELTO, + SF_RETRY_UA | SF_NO_PRINT); if (error == ERESTART) { /* * A retry was scheuled, so @@ -1711,15 +1709,21 @@ cddone(struct cam_periph *periph, union ccb *done_ccb) * supported" (0x25) error. */ if ((have_sense) && (asc != 0x25) - && (error_code == SSD_CURRENT_ERROR)) + && (error_code == SSD_CURRENT_ERROR)) { + const char *sense_key_desc; + const char *asc_desc; + + scsi_sense_desc(sense_key, asc, ascq, + &cgd.inq_data, + &sense_key_desc, + &asc_desc); snprintf(announce_buf, sizeof(announce_buf), "Attempt to query device " "size failed: %s, %s", - scsi_sense_key_text[sense_key], - scsi_sense_desc(asc,ascq, - &cgd.inq_data)); - else if (SID_TYPE(&cgd.inq_data) == T_CDROM) { + sense_key_desc, + asc_desc); + } else if (SID_TYPE(&cgd.inq_data) == T_CDROM) { /* * We only print out an error for * CDROM type devices. For WORM @@ -2489,8 +2493,8 @@ cdprevent(struct cam_periph *periph, int action) SSD_FULL_SIZE, /* timeout */60000); - error = cdrunccb(ccb, cderror, /*cam_flags*/0, - /*sense_flags*/SF_RETRY_UA|SF_NO_PRINT|SF_RETRY_SELTO); + error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, + /*sense_flags*/SF_RETRY_UA|SF_NO_PRINT); xpt_release_ccb(ccb); @@ -2533,8 +2537,8 @@ cdsize(dev_t dev, u_int32_t *size) SSD_FULL_SIZE, /* timeout */20000); - error = cdrunccb(ccb, cderror, /*cam_flags*/0, - /*sense_flags*/SF_RETRY_UA|SF_NO_PRINT|SF_RETRY_SELTO); + error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, + /*sense_flags*/SF_RETRY_UA|SF_NO_PRINT); xpt_release_ccb(ccb); @@ -2694,8 +2698,8 @@ cdreadtoc(struct cam_periph *periph, u_int32_t mode, u_int32_t start, scsi_cmd->op_code = READ_TOC; - error = cdrunccb(ccb, cderror, /*cam_flags*/0, - /*sense_flags*/SF_RETRY_UA|SF_RETRY_SELTO); + error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, + /*sense_flags*/SF_RETRY_UA); xpt_release_ccb(ccb); @@ -2741,8 +2745,8 @@ cdreadsubchannel(struct cam_periph *periph, u_int32_t mode, scsi_ulto2b(len, (u_int8_t *)scsi_cmd->data_len); scsi_cmd->control = 0; - error = cdrunccb(ccb, cderror, /*cam_flags*/0, - /*sense_flags*/SF_RETRY_UA|SF_RETRY_SELTO); + error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, + /*sense_flags*/SF_RETRY_UA); xpt_release_ccb(ccb); @@ -2781,8 +2785,8 @@ cdgetmode(struct cam_periph *periph, struct cd_mode_data *data, u_int32_t page) scsi_cmd->length = sizeof(*data) & 0xff; scsi_cmd->opcode = MODE_SENSE; - error = cdrunccb(ccb, cderror, /*cam_flags*/0, - /*sense_flags*/SF_RETRY_UA|SF_RETRY_SELTO); + error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, + /*sense_flags*/SF_RETRY_UA); xpt_release_ccb(ccb); @@ -2828,8 +2832,8 @@ cdsetmode(struct cam_periph *periph, struct cd_mode_data *data) */ data->header.medium_type = 0; - error = cdrunccb(ccb, cderror, /*cam_flags*/0, - /*sense_flags*/SF_RETRY_UA | SF_RETRY_SELTO); + error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, + /*sense_flags*/SF_RETRY_UA); xpt_release_ccb(ccb); @@ -2884,8 +2888,8 @@ cdplay(struct cam_periph *periph, u_int32_t blk, u_int32_t len) cdb_len, /*timeout*/50 * 1000); - error = cdrunccb(ccb, cderror, /*cam_flags*/0, - /*sense_flags*/SF_RETRY_UA | SF_RETRY_SELTO); + error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, + /*sense_flags*/SF_RETRY_UA); xpt_release_ccb(ccb); @@ -2929,8 +2933,8 @@ cdplaymsf(struct cam_periph *periph, u_int32_t startm, u_int32_t starts, scsi_cmd->end_s = ends; scsi_cmd->end_f = endf; - error = cdrunccb(ccb, cderror, /*cam_flags*/0, - /*sense_flags*/SF_RETRY_UA | SF_RETRY_SELTO); + error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, + /*sense_flags*/SF_RETRY_UA); xpt_release_ccb(ccb); @@ -2973,8 +2977,8 @@ cdplaytracks(struct cam_periph *periph, u_int32_t strack, u_int32_t sindex, scsi_cmd->end_track = etrack; scsi_cmd->end_index = eindex; - error = cdrunccb(ccb, cderror, /*cam_flags*/0, - /*sense_flags*/SF_RETRY_UA | SF_RETRY_SELTO); + error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, + /*sense_flags*/SF_RETRY_UA); xpt_release_ccb(ccb); @@ -3012,8 +3016,8 @@ cdpause(struct cam_periph *periph, u_int32_t go) scsi_cmd->op_code = PAUSE; scsi_cmd->resume = go; - error = cdrunccb(ccb, cderror, /*cam_flags*/0, - /*sense_flags*/SF_RETRY_UA |SF_RETRY_SELTO); + error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, + /*sense_flags*/SF_RETRY_UA); xpt_release_ccb(ccb); @@ -3040,8 +3044,8 @@ cdstartunit(struct cam_periph *periph) /* sense_len */ SSD_FULL_SIZE, /* timeout */ 50000); - error = cdrunccb(ccb, cderror, /*cam_flags*/0, - /*sense_flags*/SF_RETRY_UA | SF_RETRY_SELTO); + error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, + /*sense_flags*/SF_RETRY_UA); xpt_release_ccb(ccb); @@ -3068,8 +3072,8 @@ cdstopunit(struct cam_periph *periph, u_int32_t eject) /* sense_len */ SSD_FULL_SIZE, /* timeout */ 50000); - error = cdrunccb(ccb, cderror, /*cam_flags*/0, - /*sense_flags*/SF_RETRY_UA | SF_RETRY_SELTO); + error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, + /*sense_flags*/SF_RETRY_UA); xpt_release_ccb(ccb); @@ -3139,8 +3143,8 @@ cdreportkey(struct cam_periph *periph, struct dvd_authinfo *authinfo) /* sense_len */ SSD_FULL_SIZE, /* timeout */ 50000); - error = cdrunccb(ccb, cderror, /*cam_flags*/0, - /*sense_flags*/SF_RETRY_UA | SF_RETRY_SELTO); + error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, + /*sense_flags*/SF_RETRY_UA); if (error != 0) goto bailout; @@ -3316,8 +3320,8 @@ cdsendkey(struct cam_periph *periph, struct dvd_authinfo *authinfo) /* sense_len */ SSD_FULL_SIZE, /* timeout */ 50000); - error = cdrunccb(ccb, cderror, /*cam_flags*/0, - /*sense_flags*/SF_RETRY_UA | SF_RETRY_SELTO); + error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, + /*sense_flags*/SF_RETRY_UA); bailout: @@ -3448,8 +3452,8 @@ cdreaddvdstructure(struct cam_periph *periph, struct dvd_struct *dvdstruct) /* sense_len */ SSD_FULL_SIZE, /* timeout */ 50000); - error = cdrunccb(ccb, cderror, /*cam_flags*/0, - /*sense_flags*/SF_RETRY_UA | SF_RETRY_SELTO); + error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, + /*sense_flags*/SF_RETRY_UA); if (error != 0) goto bailout; diff --git a/sys/cam/scsi/scsi_ch.c b/sys/cam/scsi/scsi_ch.c index 4c8afdb..9ec85c8 100644 --- a/sys/cam/scsi/scsi_ch.c +++ b/sys/cam/scsi/scsi_ch.c @@ -617,8 +617,8 @@ chdone(struct cam_periph *periph, union ccb *done_ccb) } else { int error; - error = cherror(done_ccb, 0, SF_RETRY_UA | - SF_NO_PRINT | SF_RETRY_SELTO); + error = cherror(done_ccb, CAM_RETRY_SELTO, + SF_RETRY_UA | SF_NO_PRINT); /* * Retry any UNIT ATTENTION type errors. They * are expected at boot. @@ -868,8 +868,8 @@ chmove(struct cam_periph *periph, struct changer_move *cm) /* sense_len */ SSD_FULL_SIZE, /* timeout */ CH_TIMEOUT_MOVE_MEDIUM); - error = cam_periph_runccb(ccb, cherror, /*cam_flags*/0, - /*sense_flags*/ SF_RETRY_UA | SF_RETRY_SELTO, + error = cam_periph_runccb(ccb, cherror, /*cam_flags*/CAM_RETRY_SELTO, + /*sense_flags*/ SF_RETRY_UA, &softc->device_stats); xpt_release_ccb(ccb); @@ -931,8 +931,8 @@ chexchange(struct cam_periph *periph, struct changer_exchange *ce) /* sense_len */ SSD_FULL_SIZE, /* timeout */ CH_TIMEOUT_EXCHANGE_MEDIUM); - error = cam_periph_runccb(ccb, cherror, /*cam_flags*/0, - /*sense_flags*/ SF_RETRY_UA | SF_RETRY_SELTO, + error = cam_periph_runccb(ccb, cherror, /*cam_flags*/CAM_RETRY_SELTO, + /*sense_flags*/ SF_RETRY_UA, &softc->device_stats); xpt_release_ccb(ccb); @@ -977,8 +977,8 @@ chposition(struct cam_periph *periph, struct changer_position *cp) /* sense_len */ SSD_FULL_SIZE, /* timeout */ CH_TIMEOUT_POSITION_TO_ELEMENT); - error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ 0, - /*sense_flags*/ SF_RETRY_UA | SF_RETRY_SELTO, + error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ CAM_RETRY_SELTO, + /*sense_flags*/ SF_RETRY_UA, &softc->device_stats); xpt_release_ccb(ccb); @@ -1133,8 +1133,8 @@ chgetelemstatus(struct cam_periph *periph, /* sense_len */ SSD_FULL_SIZE, /* timeout */ CH_TIMEOUT_READ_ELEMENT_STATUS); - error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ 0, - /*sense_flags*/ SF_RETRY_UA | SF_RETRY_SELTO, + error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ CAM_RETRY_SELTO, + /*sense_flags*/ SF_RETRY_UA, &softc->device_stats); if (error) @@ -1169,8 +1169,8 @@ chgetelemstatus(struct cam_periph *periph, /* sense_len */ SSD_FULL_SIZE, /* timeout */ CH_TIMEOUT_READ_ELEMENT_STATUS); - error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ 0, - /*sense_flags*/ SF_RETRY_UA | SF_RETRY_SELTO, + error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ CAM_RETRY_SELTO, + /*sense_flags*/ SF_RETRY_UA, &softc->device_stats); if (error) @@ -1248,8 +1248,8 @@ chielem(struct cam_periph *periph, /* sense_len */ SSD_FULL_SIZE, /* timeout */ timeout); - error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ 0, - /*sense_flags*/ SF_RETRY_UA | SF_RETRY_SELTO, + error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ CAM_RETRY_SELTO, + /*sense_flags*/ SF_RETRY_UA, &softc->device_stats); xpt_release_ccb(ccb); @@ -1335,8 +1335,8 @@ chsetvoltag(struct cam_periph *periph, /* sense_len */ SSD_FULL_SIZE, /* timeout */ CH_TIMEOUT_SEND_VOLTAG); - error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ 0, - /*sense_flags*/ SF_RETRY_UA | SF_RETRY_SELTO, + error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ CAM_RETRY_SELTO, + /*sense_flags*/ SF_RETRY_UA, &softc->device_stats); xpt_release_ccb(ccb); @@ -1399,9 +1399,8 @@ chgetparams(struct cam_periph *periph) /* sense_len */ SSD_FULL_SIZE, /* timeout */ CH_TIMEOUT_MODE_SENSE); - error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ 0, - /* sense_flags */ SF_RETRY_UA | - SF_NO_PRINT | SF_RETRY_SELTO, + error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ CAM_RETRY_SELTO, + /* sense_flags */ SF_RETRY_UA|SF_NO_PRINT, &softc->device_stats); if (error) { @@ -1412,9 +1411,9 @@ chgetparams(struct cam_periph *periph) ccb->csio.cdb_io.cdb_bytes; sms->byte2 &= ~SMS_DBD; - error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ 0, - /*sense_flags*/ SF_RETRY_UA | - SF_RETRY_SELTO, + error = cam_periph_runccb(ccb, cherror, + /*cam_flags*/ CAM_RETRY_SELTO, + /*sense_flags*/ SF_RETRY_UA, &softc->device_stats); } else { /* @@ -1463,9 +1462,9 @@ chgetparams(struct cam_periph *periph) /* sense_len */ SSD_FULL_SIZE, /* timeout */ CH_TIMEOUT_MODE_SENSE); - error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ 0, - /* sense_flags */ SF_RETRY_UA | SF_NO_PRINT | - SF_RETRY_SELTO, &softc->device_stats); + error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ CAM_RETRY_SELTO, + /* sense_flags */ SF_RETRY_UA | SF_NO_PRINT, + &softc->device_stats); if (error) { if (dbd) { @@ -1475,9 +1474,9 @@ chgetparams(struct cam_periph *periph) ccb->csio.cdb_io.cdb_bytes; sms->byte2 &= ~SMS_DBD; - error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ 0, - /*sense_flags*/ SF_RETRY_UA | - SF_RETRY_SELTO, + error = cam_periph_runccb(ccb, cherror, + /*cam_flags*/ CAM_RETRY_SELTO, + /*sense_flags*/ SF_RETRY_UA, &softc->device_stats); } else { /* diff --git a/sys/cam/scsi/scsi_da.c b/sys/cam/scsi/scsi_da.c index 5b5956f..3e9246b 100644 --- a/sys/cam/scsi/scsi_da.c +++ b/sys/cam/scsi/scsi_da.c @@ -335,6 +335,8 @@ daopen(dev_t dev, int flags, int fmt, struct proc *p) struct cam_periph *periph; struct da_softc *softc; struct disklabel *label; + struct scsi_read_capacity_data *rcap; + union ccb *ccb; int unit; int part; int error; @@ -342,9 +344,12 @@ daopen(dev_t dev, int flags, int fmt, struct proc *p) unit = dkunit(dev); part = dkpart(dev); + s = splsoftcam(); periph = cam_extend_get(daperiphs, unit); - if (periph == NULL) + if (periph == NULL) { + splx(s); return (ENXIO); + } softc = (struct da_softc *)periph->softc; @@ -352,15 +357,13 @@ daopen(dev_t dev, int flags, int fmt, struct proc *p) ("daopen: dev=%s (unit %d , partition %d)\n", devtoname(dev), unit, part)); - if ((error = cam_periph_lock(periph, PRIBIO|PCATCH)) != 0) { + if ((error = cam_periph_lock(periph, PRIBIO|PCATCH)) != 0) return (error); /* error code from tsleep */ - } if (cam_periph_acquire(periph) != CAM_REQ_CMP) return(ENXIO); softc->flags |= DA_FLAG_OPEN; - s = splsoftcam(); if ((softc->flags & DA_FLAG_PACK_INVALID) != 0) { /* Invalidate our pack information. */ disk_invalidate(&softc->disk); @@ -369,37 +372,37 @@ daopen(dev_t dev, int flags, int fmt, struct proc *p) splx(s); /* Do a read capacity */ - { - struct scsi_read_capacity_data *rcap; - union ccb *ccb; - - rcap = (struct scsi_read_capacity_data *)malloc(sizeof(*rcap), - M_TEMP, - M_WAITOK); + rcap = (struct scsi_read_capacity_data *)malloc(sizeof(*rcap), + M_TEMP, + M_WAITOK); - ccb = cam_periph_getccb(periph, /*priority*/1); - scsi_read_capacity(&ccb->csio, - /*retries*/1, - /*cbfncp*/dadone, - MSG_SIMPLE_Q_TAG, - rcap, - SSD_FULL_SIZE, - /*timeout*/60000); - ccb->ccb_h.ccb_bp = NULL; - - error = cam_periph_runccb(ccb, daerror, /*cam_flags*/0, - /*sense_flags*/SF_RETRY_UA | - SF_RETRY_SELTO, - &softc->device_stats); + ccb = cam_periph_getccb(periph, /*priority*/1); + scsi_read_capacity(&ccb->csio, + /*retries*/4, + /*cbfncp*/dadone, + MSG_SIMPLE_Q_TAG, + rcap, + SSD_FULL_SIZE, + /*timeout*/60000); + ccb->ccb_h.ccb_bp = NULL; + + error = cam_periph_runccb(ccb, daerror, + /*cam_flags*/CAM_RETRY_SELTO, + /*sense_flags*/SF_RETRY_UA, + &softc->device_stats); - xpt_release_ccb(ccb); + if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) + cam_release_devq(ccb->ccb_h.path, + /*relsim_flags*/0, + /*reduction*/0, + /*timeout*/0, + /*getcount_only*/0); + xpt_release_ccb(ccb); - if (error == 0) { - dasetgeom(periph, rcap); - } + if (error == 0) + dasetgeom(periph, rcap); - free(rcap, M_TEMP); - } + free(rcap, M_TEMP); if (error == 0) { struct ccb_getdev cgd; @@ -430,10 +433,6 @@ daopen(dev_t dev, int flags, int fmt, struct proc *p) * softc->params.secs_per_track; label->d_secperunit = softc->params.sectors; - if (((softc->flags & DA_FLAG_PACK_REMOVABLE) != 0)) { - daprevent(periph, PR_PREVENT); - } - /* * Check to see whether or not the blocksize is set yet. * If it isn't, set it and then clear the blocksize @@ -445,10 +444,9 @@ daopen(dev_t dev, int flags, int fmt, struct proc *p) } } - if (error != 0) { - if ((softc->flags & DA_FLAG_PACK_REMOVABLE) != 0) { - daprevent(periph, PR_ALLOW); - } + if (error == 0) { + if ((softc->flags & DA_FLAG_PACK_REMOVABLE) != 0) + daprevent(periph, PR_PREVENT); } cam_periph_unlock(periph); return (error); @@ -1222,10 +1220,8 @@ dadone(struct cam_periph *periph, union ccb *done_ccb) else sf = 0; - /* Retry selection timeouts */ - sf |= SF_RETRY_SELTO; - - if ((error = daerror(done_ccb, 0, sf)) == ERESTART) { + error = daerror(done_ccb, CAM_RETRY_SELTO, sf); + if (error == ERESTART) { /* * A retry was scheuled, so * just return. @@ -1282,6 +1278,8 @@ dadone(struct cam_periph *periph, union ccb *done_ccb) /*timeout*/0, /*getcount_only*/0); } else { + if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) + panic("REQ_CMP with QFRZN"); bp->bio_resid = csio->resid; if (csio->resid > 0) bp->bio_flags |= BIO_ERROR; @@ -1329,8 +1327,8 @@ dadone(struct cam_periph *periph, union ccb *done_ccb) * Retry any UNIT ATTENTION type errors. They * are expected at boot. */ - error = daerror(done_ccb, 0, SF_RETRY_UA | - SF_RETRY_SELTO | SF_NO_PRINT); + error = daerror(done_ccb, CAM_RETRY_SELTO, + SF_RETRY_UA|SF_NO_PRINT); if (error == ERESTART) { /* * A retry was scheuled, so @@ -1346,13 +1344,14 @@ dadone(struct cam_periph *periph, union ccb *done_ccb) struct ccb_getdev cgd; /* Don't wedge this device's queue */ - cam_release_devq(done_ccb->ccb_h.path, - /*relsim_flags*/0, - /*reduction*/0, - /*timeout*/0, - /*getcount_only*/0); - status = done_ccb->ccb_h.status; + if ((status & CAM_DEV_QFRZN) != 0) + cam_release_devq(done_ccb->ccb_h.path, + /*relsim_flags*/0, + /*reduction*/0, + /*timeout*/0, + /*getcount_only*/0); + xpt_setup_ccb(&cgd.ccb_h, done_ccb->ccb_h.path, @@ -1380,15 +1379,21 @@ dadone(struct cam_periph *periph, union ccb *done_ccb) * unit not supported" (0x25) error. */ if ((have_sense) && (asc != 0x25) - && (error_code == SSD_CURRENT_ERROR)) + && (error_code == SSD_CURRENT_ERROR)) { + const char *sense_key_desc; + const char *asc_desc; + + scsi_sense_desc(sense_key, asc, ascq, + &cgd.inq_data, + &sense_key_desc, + &asc_desc); snprintf(announce_buf, sizeof(announce_buf), "Attempt to query device " "size failed: %s, %s", - scsi_sense_key_text[sense_key], - scsi_sense_desc(asc,ascq, - &cgd.inq_data)); - else { + sense_key_desc, + asc_desc); + } else { if (have_sense) scsi_sense_print( &done_ccb->csio); @@ -1412,7 +1417,7 @@ dadone(struct cam_periph *periph, union ccb *done_ccb) free(rdcap, M_TEMP); if (announce_buf[0] != '\0') xpt_announce_periph(periph, announce_buf); - softc->state = DA_STATE_NORMAL; + softc->state = DA_STATE_NORMAL; /* * Since our peripheral may be invalidated by an error * above or an external event, we must release our CCB diff --git a/sys/cam/scsi/scsi_pass.c b/sys/cam/scsi/scsi_pass.c index 7c47bc2..6dc25d4 100644 --- a/sys/cam/scsi/scsi_pass.c +++ b/sys/cam/scsi/scsi_pass.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 1998 Justin T. Gibbs. + * Copyright (c) 1997, 1998, 2000 Justin T. Gibbs. * Copyright (c) 1997, 1998, 1999 Kenneth D. Merry. * All rights reserved. * @@ -42,6 +42,7 @@ #include <cam/cam_ccb.h> #include <cam/cam_extend.h> #include <cam/cam_periph.h> +#include <cam/cam_queue.h> #include <cam/cam_xpt_periph.h> #include <cam/cam_debug.h> @@ -67,13 +68,12 @@ typedef enum { #define ccb_bp ppriv_ptr1 struct pass_softc { - pass_state state; - pass_flags flags; - u_int8_t pd_type; - struct bio_queue_head bio_queue; - union ccb saved_ccb; - struct devstat device_stats; - dev_t dev; + pass_state state; + pass_flags flags; + u_int8_t pd_type; + union ccb saved_ccb; + struct devstat device_stats; + dev_t dev; }; #ifndef MIN @@ -85,7 +85,6 @@ struct pass_softc { static d_open_t passopen; static d_close_t passclose; static d_ioctl_t passioctl; -static d_strategy_t passstrategy; static periph_init_t passinit; static periph_ctor_t passregister; @@ -112,12 +111,12 @@ PERIPHDRIVER_DECLARE(pass, passdriver); static struct cdevsw pass_cdevsw = { /* open */ passopen, /* close */ passclose, - /* read */ physread, - /* write */ physwrite, + /* read */ noread, + /* write */ nowrite, /* ioctl */ passioctl, /* poll */ nopoll, /* mmap */ nommap, - /* strategy */ passstrategy, + /* strategy */ nostrategy, /* name */ "pass", /* maj */ PASS_CDEV_MAJOR, /* dump */ nodump, @@ -172,9 +171,7 @@ passinit(void) static void passoninvalidate(struct cam_periph *periph) { - int s; struct pass_softc *softc; - struct bio *q_bp; struct ccb_setasync csa; softc = (struct pass_softc *)periph->softc; @@ -193,25 +190,10 @@ passoninvalidate(struct cam_periph *periph) softc->flags |= PASS_FLAG_INVALID; /* - * Although the oninvalidate() routines are always called at - * splsoftcam, we need to be at splbio() here to keep the buffer - * queue from being modified while we traverse it. - */ - s = splbio(); - - /* - * Return all queued I/O with ENXIO. + * XXX Return all queued I/O with ENXIO. * XXX Handle any transactions queued to the card * with XPT_ABORT_CCB. */ - while ((q_bp = bioq_first(&softc->bio_queue)) != NULL){ - bioq_remove(&softc->bio_queue, q_bp); - q_bp->bio_resid = q_bp->bio_bcount; - q_bp->bio_error = ENXIO; - q_bp->bio_flags |= BIO_ERROR; - biodone(q_bp); - } - splx(s); if (bootverbose) { xpt_print_path(periph->path); @@ -267,9 +249,15 @@ passasync(void *callback_arg, u_int32_t code, passasync, AC_FOUND_DEVICE, cgd); if (status != CAM_REQ_CMP - && status != CAM_REQ_INPROG) + && status != CAM_REQ_INPROG) { + const struct cam_status_entry *entry; + + entry = cam_fetch_status_entry(status); + printf("passasync: Unable to attach new device " - "due to status 0x%x\n", status); + "due to status %#x: %s\n", status, entry ? + entry->status_text : "Unknown"); + } break; } @@ -285,6 +273,7 @@ passregister(struct cam_periph *periph, void *arg) struct pass_softc *softc; struct ccb_setasync csa; struct ccb_getdev *cgd; + int no_tags; cgd = (struct ccb_getdev *)arg; if (periph == NULL) { @@ -309,18 +298,19 @@ passregister(struct cam_periph *periph, void *arg) bzero(softc, sizeof(*softc)); softc->state = PASS_STATE_NORMAL; softc->pd_type = SID_TYPE(&cgd->inq_data); - bioq_init(&softc->bio_queue); periph->softc = softc; - cam_extend_set(passperiphs, periph->unit_number, periph); + /* * We pass in 0 for a blocksize, since we don't * know what the blocksize of this device is, if * it even has a blocksize. */ - devstat_add_entry(&softc->device_stats, "pass", periph->unit_number, - 0, DEVSTAT_NO_BLOCKSIZE | DEVSTAT_NO_ORDERED_TAGS, + no_tags = (cgd->inq_data.flags & SID_CmdQue) == 0; + devstat_add_entry(&softc->device_stats, "pass", periph->unit_number, 0, + DEVSTAT_NO_BLOCKSIZE + | (no_tags ? DEVSTAT_NO_ORDERED_TAGS : 0), softc->pd_type | DEVSTAT_TYPE_IF_SCSI | DEVSTAT_TYPE_PASS, @@ -447,75 +437,6 @@ passclose(dev_t dev, int flag, int fmt, struct proc *p) return (0); } -/* - * Actually translate the requested transfer into one the physical driver - * can understand. The transfer is described by a buf and will include - * only one physical transfer. - */ -static void -passstrategy(struct bio *bp) -{ - struct cam_periph *periph; - struct pass_softc *softc; - u_int unit; - int s; - - /* - * The read/write interface for the passthrough driver doesn't - * really work right now. So, we just pass back EINVAL to tell the - * user to go away. - */ - bp->bio_error = EINVAL; - goto bad; - - /* unit = dkunit(bp->bio_dev); */ - /* XXX KDM fix this */ - unit = minor(bp->bio_dev) & 0xff; - - periph = cam_extend_get(passperiphs, unit); - if (periph == NULL) { - bp->bio_error = ENXIO; - goto bad; - } - softc = (struct pass_softc *)periph->softc; - - /* - * Odd number of bytes or negative offset - */ - /* valid request? */ - if (bp->bio_blkno < 0) { - bp->bio_error = EINVAL; - goto bad; - } - - /* - * Mask interrupts so that the pack cannot be invalidated until - * after we are in the queue. Otherwise, we might not properly - * clean up one of the buffers. - */ - s = splbio(); - - bioq_insert_tail(&softc->bio_queue, bp); - - splx(s); - - /* - * Schedule ourselves for performing the work. - */ - xpt_schedule(periph, /* XXX priority */1); - - return; -bad: - bp->bio_flags |= BIO_ERROR; - - /* - * Correctly set the buf to indicate a completed xfer - */ - bp->bio_resid = bp->bio_bcount; - biodone(bp); - return; -} - static void passstart(struct cam_periph *periph, union ccb *start_ccb) { @@ -526,53 +447,17 @@ passstart(struct cam_periph *periph, union ccb *start_ccb) switch (softc->state) { case PASS_STATE_NORMAL: - { - struct bio *bp; - s = splbio(); - bp = bioq_first(&softc->bio_queue); - if (periph->immediate_priority <= periph->pinfo.priority) { - start_ccb->ccb_h.ccb_type = PASS_CCB_WAITING; - SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h, - periph_links.sle); - periph->immediate_priority = CAM_PRIORITY_NONE; - splx(s); - wakeup(&periph->ccb_list); - } else if (bp == NULL) { - splx(s); - xpt_release_ccb(start_ccb); - } else { - - bioq_remove(&softc->bio_queue, bp); - - devstat_start_transaction(&softc->device_stats); - - /* - * XXX JGibbs - - * Interpret the contents of the bp as a CCB - * and pass it to a routine shared by our ioctl - * code and passtart. - * For now, just biodone it with EIO so we don't - * hang. - */ - bp->bio_error = EIO; - bp->bio_flags |= BIO_ERROR; - bp->bio_resid = bp->bio_bcount; - biodone(bp); - bp = bioq_first(&softc->bio_queue); - splx(s); - - xpt_action(start_ccb); - - } - if (bp != NULL) { - /* Have more work to do, so ensure we stay scheduled */ - xpt_schedule(periph, /* XXX priority */1); - } + start_ccb->ccb_h.ccb_type = PASS_CCB_WAITING; + SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h, + periph_links.sle); + periph->immediate_priority = CAM_PRIORITY_NONE; + splx(s); + wakeup(&periph->ccb_list); break; } - } } + static void passdone(struct cam_periph *periph, union ccb *done_ccb) { @@ -582,55 +467,11 @@ passdone(struct cam_periph *periph, union ccb *done_ccb) softc = (struct pass_softc *)periph->softc; csio = &done_ccb->csio; switch (csio->ccb_h.ccb_type) { - case PASS_CCB_BUFFER_IO: - { - struct bio *bp; - cam_status status; - u_int8_t scsi_status; - devstat_trans_flags ds_flags; - - status = done_ccb->ccb_h.status; - scsi_status = done_ccb->csio.scsi_status; - bp = (struct bio *)done_ccb->ccb_h.ccb_bp; - /* XXX handle errors */ - if (!(((status & CAM_STATUS_MASK) == CAM_REQ_CMP) - && (scsi_status == SCSI_STATUS_OK))) { - int error; - - if ((error = passerror(done_ccb, 0, 0)) == ERESTART) { - /* - * A retry was scheuled, so - * just return. - */ - return; - } - - /* - * XXX unfreeze the queue after we complete - * the abort process - */ - bp->bio_error = error; - bp->bio_flags |= BIO_ERROR; - } - - if ((done_ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) - ds_flags = DEVSTAT_READ; - else if ((done_ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) - ds_flags = DEVSTAT_WRITE; - else - ds_flags = DEVSTAT_NO_DATA; - - devstat_end_transaction_bio(&softc->device_stats, bp); - biodone(bp); - break; - } case PASS_CCB_WAITING: - { /* Caller will release the CCB */ wakeup(&done_ccb->ccb_h.cbfcnp); return; } - } xpt_release_ccb(done_ccb); } @@ -791,8 +632,8 @@ passsendccb(struct cam_periph *periph, union ccb *ccb, union ccb *inccb) error = cam_periph_runccb(ccb, (ccb->ccb_h.flags & CAM_PASS_ERR_RECOVER) ? passerror : NULL, - /* cam_flags */ 0, - /* sense_flags */SF_RETRY_UA | SF_RETRY_SELTO, + /* cam_flags */ CAM_RETRY_SELTO, + /* sense_flags */SF_RETRY_UA, &softc->device_stats); if (need_unmap != 0) diff --git a/sys/cam/scsi/scsi_pass.h b/sys/cam/scsi/scsi_pass.h index 39e92c3..d397659 100644 --- a/sys/cam/scsi/scsi_pass.h +++ b/sys/cam/scsi/scsi_pass.h @@ -32,6 +32,10 @@ #include <cam/cam_ccb.h> +/* + * Convert to using a pointer to a ccb in the next major version. + * This should allow us to avoid an extra copy of the CCB data. + */ #define CAMIOCOMMAND _IOWR(CAM_VERSION, 2, union ccb) #define CAMGETPASSTHRU _IOWR(CAM_VERSION, 3, union ccb) diff --git a/sys/cam/scsi/scsi_pt.c b/sys/cam/scsi/scsi_pt.c index 61b9d04..33e4c22 100644 --- a/sys/cam/scsi/scsi_pt.c +++ b/sys/cam/scsi/scsi_pt.c @@ -594,9 +594,8 @@ ptdone(struct cam_periph *periph, union ccb *done_ccb) else sf = 0; - sf |= SF_RETRY_SELTO; - - if ((error = pterror(done_ccb, 0, sf)) == ERESTART) { + error = pterror(done_ccb, CAM_RETRY_SELTO, sf); + if (error == ERESTART) { /* * A retry was scheuled, so * just return. diff --git a/sys/cam/scsi/scsi_sa.c b/sys/cam/scsi/scsi_sa.c index f288e4a..adfbbb0 100644 --- a/sys/cam/scsi/scsi_sa.c +++ b/sys/cam/scsi/scsi_sa.c @@ -1906,8 +1906,8 @@ samount(struct cam_periph *periph, int oflags, dev_t dev) QFRLS(ccb); scsi_rewind(&ccb->csio, 1, sadone, MSG_SIMPLE_Q_TAG, FALSE, SSD_FULL_SIZE, REWIND_TIMEOUT); - error = cam_periph_runccb(ccb, saerror, 0, - SF_NO_PRINT | SF_RETRY_SELTO | SF_RETRY_UA, + error = cam_periph_runccb(ccb, saerror, CAM_RETRY_SELTO, + SF_NO_PRINT | SF_RETRY_UA, &softc->device_stats); QFRLS(ccb); if (error) { @@ -1924,9 +1924,9 @@ samount(struct cam_periph *periph, int oflags, dev_t dev) scsi_read_block_limits(&ccb->csio, 5, sadone, MSG_SIMPLE_Q_TAG, rblim, SSD_FULL_SIZE, 5000); - error = cam_periph_runccb(ccb, saerror, 0, - SF_NO_PRINT | SF_RETRY_UA | SF_RETRY_SELTO, - &softc->device_stats); + error = cam_periph_runccb(ccb, saerror, CAM_RETRY_SELTO, + SF_NO_PRINT | SF_RETRY_UA, &softc->device_stats); + QFRLS(ccb); xpt_release_ccb(ccb); @@ -1940,7 +1940,7 @@ samount(struct cam_periph *periph, int oflags, dev_t dev) softc->max_blk = ~0; softc->min_blk = 0; } else { - if (softc->scsi_rev >= SCSI_REV_3) { + if (softc->scsi_rev >= SCSI_REV_SPC) { softc->blk_gran = RBL_GRAN(rblim); } else { softc->blk_gran = 0; diff --git a/sys/cam/scsi/scsi_ses.c b/sys/cam/scsi/scsi_ses.c index 7e4b818..75c41ba 100644 --- a/sys/cam/scsi/scsi_ses.c +++ b/sys/cam/scsi/scsi_ses.c @@ -669,7 +669,8 @@ sesioctl(dev_t dev, u_long cmd, caddr_t arg_addr, int flag, struct proc *p) return (error); } -#define SES_FLAGS SF_NO_PRINT | SF_RETRY_SELTO | SF_RETRY_UA +#define SES_CFLAGS CAM_RETRY_SELTO +#define SES_FLAGS SF_NO_PRINT | SF_RETRY_UA static int ses_runcmd(struct ses_softc *ssc, char *cdb, int cdbl, char *dptr, int *dlenp) { @@ -698,7 +699,7 @@ ses_runcmd(struct ses_softc *ssc, char *cdb, int cdbl, char *dptr, int *dlenp) dlen, sizeof (struct scsi_sense_data), cdbl, 60 * 1000); bcopy(cdb, ccb->csio.cdb_io.cdb_bytes, cdbl); - error = cam_periph_runccb(ccb, seserror, 0, SES_FLAGS, NULL); + error = cam_periph_runccb(ccb, seserror, SES_CFLAGS, SES_FLAGS, NULL); if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) cam_release_devq(ccb->ccb_h.path, 0, 0, 0, FALSE); if (error) { diff --git a/sys/conf/files b/sys/conf/files index e9062c1..5ee34bd 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -762,6 +762,7 @@ kern/vfs_vnops.c standard # libkern/arc4random.c standard libkern/bcd.c standard +libkern/bsearch.c standard libkern/index.c standard libkern/inet_ntoa.c standard libkern/mcount.c optional profiling-routine diff --git a/sys/dev/aic7xxx/aic7xxx_freebsd.h b/sys/dev/aic7xxx/aic7xxx_freebsd.h index 59b6e97..9e5c8f1 100644 --- a/sys/dev/aic7xxx/aic7xxx_freebsd.h +++ b/sys/dev/aic7xxx/aic7xxx_freebsd.h @@ -37,6 +37,9 @@ #ifndef _AIC7XXX_FREEBSD_H_ #define _AIC7XXX_FREEBSD_H_ +#ifdef CAM_NEW_TRAN_CODE +#define AHC_NEW_TRAN_SETTINGS +#endif /* CAM_NEW_TRAN_CODE */ #include <opt_aic7xxx.h> /* for config options */ #include <pci.h> /* for NPCI */ diff --git a/sys/dev/aic7xxx/aic7xxx_osm.h b/sys/dev/aic7xxx/aic7xxx_osm.h index 59b6e97..9e5c8f1 100644 --- a/sys/dev/aic7xxx/aic7xxx_osm.h +++ b/sys/dev/aic7xxx/aic7xxx_osm.h @@ -37,6 +37,9 @@ #ifndef _AIC7XXX_FREEBSD_H_ #define _AIC7XXX_FREEBSD_H_ +#ifdef CAM_NEW_TRAN_CODE +#define AHC_NEW_TRAN_SETTINGS +#endif /* CAM_NEW_TRAN_CODE */ #include <opt_aic7xxx.h> /* for config options */ #include <pci.h> /* for NPCI */ diff --git a/sys/kern/subr_sbuf.c b/sys/kern/subr_sbuf.c index ffe73f8..11fc64f 100644 --- a/sys/kern/subr_sbuf.c +++ b/sys/kern/subr_sbuf.c @@ -29,14 +29,27 @@ */ #include <sys/param.h> +#include <sys/sbuf.h> + +#ifdef _KERNEL #include <sys/kernel.h> #include <sys/malloc.h> -#include <sys/sbuf.h> #include <sys/systm.h> - #include <machine/stdarg.h> +#else /* _KERNEL */ +#include <stdarg.h> +#endif /* _KERNEL */ +#ifdef _KERNEL MALLOC_DEFINE(M_SBUF, "sbuf", "string buffers"); +#define SBMALLOC(size) malloc(size, M_SBUF, M_WAITOK) +#define SBFREE(buf) free(buf, M_SBUF) +#else /* _KERNEL */ +#define KASSERT(e, m) +#define SBMALLOC(size) malloc(size) +#define SBFREE(buf) free(buf) +#define min(x,y) MIN(x,y) +#endif /* _KERNEL */ /* * Predicates @@ -55,7 +68,7 @@ MALLOC_DEFINE(M_SBUF, "sbuf", "string buffers"); /* * Debugging support */ -#ifdef INVARIANTS +#if defined(_KERNEL) && defined(INVARIANTS) static void _assert_sbuf_integrity(char *fun, struct sbuf *s) { @@ -76,10 +89,10 @@ _assert_sbuf_state(char *fun, struct sbuf *s, int state) } #define assert_sbuf_integrity(s) _assert_sbuf_integrity(__FUNCTION__, (s)) #define assert_sbuf_state(s, i) _assert_sbuf_state(__FUNCTION__, (s), (i)) -#else +#else /* _KERNEL && INVARIANTS */ #define assert_sbuf_integrity(s) do { } while (0) #define assert_sbuf_state(s, i) do { } while (0) -#endif +#endif /* _KERNEL && INVARIANTS */ /* * Initialize an sbuf. @@ -102,7 +115,7 @@ sbuf_new(struct sbuf *s, char *buf, int length, int flags) s->s_buf = buf; return (0); } - s->s_buf = malloc(s->s_size, M_SBUF, M_WAITOK); + s->s_buf = (char *)SBMALLOC(s->s_size); if (s->s_buf == NULL) return (-1); SBUF_SETFLAG(s, SBUF_DYNAMIC); @@ -147,7 +160,7 @@ sbuf_setpos(struct sbuf *s, int pos) * Append a string to an sbuf. */ int -sbuf_cat(struct sbuf *s, char *str) +sbuf_cat(struct sbuf *s, const char *str) { assert_sbuf_integrity(s); assert_sbuf_state(s, 0); @@ -168,7 +181,7 @@ sbuf_cat(struct sbuf *s, char *str) * Copy a string into an sbuf. */ int -sbuf_cpy(struct sbuf *s, char *str) +sbuf_cpy(struct sbuf *s, const char *str) { assert_sbuf_integrity(s); assert_sbuf_state(s, 0); @@ -178,15 +191,6 @@ sbuf_cpy(struct sbuf *s, char *str) } /* - * PCHAR function for sbuf_printf() - */ -static void -_sbuf_pchar(int c, void *v) -{ - sbuf_putc((struct sbuf *)v, c); -} - -/* * Format the given arguments and append the resulting string to an sbuf. */ int @@ -205,9 +209,22 @@ sbuf_printf(struct sbuf *s, char *fmt, ...) return (-1); va_start(ap, fmt); - len = kvprintf(fmt, _sbuf_pchar, s, 10, ap); + len = vsnprintf(&s->s_buf[s->s_len], s->s_size - s->s_len, fmt, ap); va_end(ap); + /* + * s->s_len is the length of the string, without the terminating nul. + * When updating s->s_len, we must subtract 1 from the length that + * we passed into vsnprintf() because that length includes the + * terminating nul. + * + * vsnprintf() returns the amount that would have been copied, + * given sufficient space, hence the min() calculation below. + */ + s->s_len += min(len, s->s_size - s->s_len - 1); + if (!SBUF_HASROOM(s)) + SBUF_SETFLAG(s, SBUF_OVERFLOWED); + KASSERT(s->s_len < s->s_size, ("wrote past end of sbuf (%d >= %d)", s->s_len, s->s_size)); @@ -296,6 +313,6 @@ sbuf_delete(struct sbuf *s) /* don't care if it's finished or not */ if (SBUF_ISDYNAMIC(s)) - free(s->s_buf, M_SBUF); + SBFREE(s->s_buf); bzero(s, sizeof *s); } diff --git a/sys/libkern/bsearch.c b/sys/libkern/bsearch.c new file mode 100644 index 0000000..5b34500 --- /dev/null +++ b/sys/libkern/bsearch.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)bsearch.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ + +#include <stddef.h> +#include <stdlib.h> + +/* + * Perform a binary search. + * + * The code below is a bit sneaky. After a comparison fails, we + * divide the work in half by moving either left or right. If lim + * is odd, moving left simply involves halving lim: e.g., when lim + * is 5 we look at item 2, so we change lim to 2 so that we will + * look at items 0 & 1. If lim is even, the same applies. If lim + * is odd, moving right again involes halving lim, this time moving + * the base up one item past p: e.g., when lim is 5 we change base + * to item 3 and make lim 2 so that we will look at items 3 and 4. + * If lim is even, however, we have to shrink it by one before + * halving: e.g., when lim is 4, we still looked at item 2, so we + * have to make lim 3, then halve, obtaining 1, so that we will only + * look at item 3. + */ +void * +bsearch(key, base0, nmemb, size, compar) + register const void *key; + const void *base0; + size_t nmemb; + register size_t size; + register int (*compar) __P((const void *, const void *)); +{ + register const char *base = base0; + register size_t lim; + register int cmp; + register const void *p; + + for (lim = nmemb; lim != 0; lim >>= 1) { + p = base + (lim >> 1) * size; + cmp = (*compar)(key, p); + if (cmp == 0) + return ((void *)p); + if (cmp > 0) { /* key > p: move right */ + base = (const char *)p + size; + lim--; + } /* else move left */ + } + return (NULL); +} diff --git a/sys/sys/libkern.h b/sys/sys/libkern.h index c9a3bf3..a1008b8 100644 --- a/sys/sys/libkern.h +++ b/sys/sys/libkern.h @@ -66,6 +66,8 @@ static __inline u_long ulmin(u_long a, u_long b) { return (a < b ? a : b); } /* Prototypes for non-quad routines. */ u_int32_t arc4random __P((void)); int bcmp __P((const void *, const void *, size_t)); +void *bsearch __P((const void *, const void *, size_t, + size_t, int (*)(const void *, const void *))); #ifndef HAVE_INLINE_FFS int ffs __P((int)); #endif diff --git a/sys/sys/sbuf.h b/sys/sys/sbuf.h index 0244466..e2f0a6b 100644 --- a/sys/sys/sbuf.h +++ b/sys/sys/sbuf.h @@ -46,14 +46,15 @@ struct sbuf { int s_flags; /* flags */ }; +__BEGIN_DECLS /* * API functions */ int sbuf_new(struct sbuf *s, char *buf, int length, int flags); void sbuf_clear(struct sbuf *s); int sbuf_setpos(struct sbuf *s, int pos); -int sbuf_cat(struct sbuf *s, char *str); -int sbuf_cpy(struct sbuf *s, char *str); +int sbuf_cat(struct sbuf *s, const char *str); +int sbuf_cpy(struct sbuf *s, const char *str); int sbuf_printf(struct sbuf *s, char *fmt, ...); int sbuf_putc(struct sbuf *s, int c); int sbuf_overflowed(struct sbuf *s); @@ -61,5 +62,6 @@ void sbuf_finish(struct sbuf *s); char *sbuf_data(struct sbuf *s); int sbuf_len(struct sbuf *s); void sbuf_delete(struct sbuf *s); +__END_DECLS #endif |