aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.inc16
-rw-r--r--lib/Makefile3
-rw-r--r--lib/libcam/Makefile71
-rw-r--r--lib/libsbuf/Makefile11
-rw-r--r--sbin/camcontrol/Makefile4
-rw-r--r--sbin/camcontrol/camcontrol.c196
-rw-r--r--share/man/man9/sbuf.96
-rw-r--r--share/mk/bsd.libnames.mk1
-rw-r--r--sys/cam/cam.c244
-rw-r--r--sys/cam/cam.h58
-rw-r--r--sys/cam/cam_ccb.h119
-rw-r--r--sys/cam/cam_debug.h2
-rw-r--r--sys/cam/cam_periph.c918
-rw-r--r--sys/cam/cam_xpt.c636
-rw-r--r--sys/cam/cam_xpt.h2
-rw-r--r--sys/cam/scsi/scsi_all.c1834
-rw-r--r--sys/cam/scsi/scsi_all.h94
-rw-r--r--sys/cam/scsi/scsi_cd.c86
-rw-r--r--sys/cam/scsi/scsi_ch.c55
-rw-r--r--sys/cam/scsi/scsi_da.c119
-rw-r--r--sys/cam/scsi/scsi_pass.c229
-rw-r--r--sys/cam/scsi/scsi_pass.h4
-rw-r--r--sys/cam/scsi/scsi_pt.c5
-rw-r--r--sys/cam/scsi/scsi_sa.c12
-rw-r--r--sys/cam/scsi/scsi_ses.c5
-rw-r--r--sys/conf/files1
-rw-r--r--sys/dev/aic7xxx/aic7xxx_freebsd.h3
-rw-r--r--sys/dev/aic7xxx/aic7xxx_osm.h3
-rw-r--r--sys/kern/subr_sbuf.c55
-rw-r--r--sys/libkern/bsearch.c83
-rw-r--r--sys/sys/libkern.h2
-rw-r--r--sys/sys/sbuf.h6
-rw-r--r--usr.bin/kdump/mkioctls2
33 files changed, 2815 insertions, 2060 deletions
diff --git a/Makefile.inc1 b/Makefile.inc1
index b1938d7460b9..c376fe6a711d 100644
--- a/Makefile.inc1
+++ b/Makefile.inc1
@@ -695,6 +695,7 @@ includes:
cd ${.CURDIR}/lib/libpcap; ${MAKE} beforeinstall
cd ${.CURDIR}/lib/libradius; ${MAKE} beforeinstall
cd ${.CURDIR}/lib/librpcsvc; ${MAKE} beforeinstall
+ cd ${.CURDIR}/lib/libsbuf; ${MAKE} beforeinstall
cd ${.CURDIR}/lib/libskey; ${MAKE} beforeinstall
cd ${.CURDIR}/lib/libstand; ${MAKE} beforeinstall
cd ${.CURDIR}/lib/libtacplus; ${MAKE} beforeinstall
@@ -713,6 +714,7 @@ includes:
#
# lib*: csu libgcc_pic
# libatm: libmd
+# libcam: libsbuf
# libcrypt: libmd
# libdialog: libncurses
# libedit: libncurses
@@ -774,8 +776,8 @@ libraries:
.for _lib in ${_csu} gnu/lib/csu gnu/lib/libgcc lib/libmd lib/libcrypt \
${_secure_lib} ${_kerberosIV_lib} \
${_kerberos5_lib} lib/libcom_err ${_libm} lib/libncurses \
- lib/libopie lib/libradius lib/libskey lib/libtacplus lib/libutil \
- lib/libz lib gnu/lib ${_libperl} usr.bin/lex/lib ${_libkeycap}
+ lib/libopie lib/libradius lib/libsbuf lib/libskey lib/libtacplus \
+ lib/libutil lib/libz lib gnu/lib ${_libperl} usr.bin/lex/lib ${_libkeycap}
.if exists(${.CURDIR}/${_lib})
cd ${.CURDIR}/${_lib}; \
${MAKE} depend; \
diff --git a/lib/Makefile b/lib/Makefile
index 1ff9da177c69..6dfc7a3d40da 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -16,11 +16,12 @@
# libskey must be built before libpam.
# libtacplus must be built before libpam.
# libutil must be built before libpam.
+# libsbuf must be built before libcam.
#
# Otherwise, the SUBDIR list should be in alphabetical order.
SUBDIR= ${_csu} libcom_err libcrypt msun libmd \
- libncurses libradius libskey libtacplus libutil \
+ libncurses libradius libskey libtacplus libutil libsbuf \
${_compat} libalias libatm ${_libbind} libc ${_libc_r} libcalendar \
libcam libcompat libdevstat libdisk libedit libfetch libform \
libftpio libgnumalloc ${_libio} libipsec libipx libisc libkvm libmenu \
diff --git a/lib/libcam/Makefile b/lib/libcam/Makefile
index a66251092481..c201f771d96b 100644
--- a/lib/libcam/Makefile
+++ b/lib/libcam/Makefile
@@ -2,39 +2,42 @@
MAINTAINER=ken@FreeBSD.ORG
-LIB= cam
-SRCS= camlib.c scsi_cmdparse.c scsi_all.c scsi_da.c scsi_sa.c cam.c
-INCS= camlib.h
-
-MAN3= cam.3 cam_cdbparse.3
-
-
-MLINKS+=cam.3 cam_open_device.3 \
- cam.3 cam_open_spec_device.3 \
- cam.3 cam_open_btl.3 \
- cam.3 cam_open_pass.3 \
- cam.3 cam_close_device.3 \
- cam.3 cam_close_spec_device.3 \
- cam.3 cam_getccb.3 \
- cam.3 cam_send_ccb.3 \
- cam.3 cam_freeccb.3 \
- cam.3 cam_path_string.3 \
- cam.3 cam_device_dup.3 \
- cam.3 cam_device_copy.3 \
- cam.3 cam_get_device.3 \
- cam_cdbparse.3 csio_build.3 \
- cam_cdbparse.3 csio_build_visit.3 \
- cam_cdbparse.3 csio_decode.3 \
- cam_cdbparse.3 csio_decode_visit.3 \
- cam_cdbparse.3 buff_decode.3 \
- cam_cdbparse.3 buff_decode_visit.3 \
- cam_cdbparse.3 csio_encode.3 \
- cam_cdbparse.3 csio_encode_visit.3 \
- cam_cdbparse.3 buff_encode_visit.3
-
-.PATH: ${.CURDIR}/../../sys/cam/scsi ${.CURDIR}/../../sys/cam
-
-SDIR= ${.CURDIR}/../../sys
-CFLAGS+=-I${.CURDIR} -I${SDIR}
+LIB= cam
+SRCS= camlib.c scsi_cmdparse.c scsi_all.c scsi_da.c scsi_sa.c cam.c
+INCS= camlib.h
+
+DPADD+= ${LIBSBUF}
+LDADD+= -lsbuf
+
+MAN3= cam.3 cam_cdbparse.3
+
+
+MLINKS+= cam.3 cam_open_device.3 \
+ cam.3 cam_open_spec_device.3 \
+ cam.3 cam_open_btl.3 \
+ cam.3 cam_open_pass.3 \
+ cam.3 cam_close_device.3 \
+ cam.3 cam_close_spec_device.3 \
+ cam.3 cam_getccb.3 \
+ cam.3 cam_send_ccb.3 \
+ cam.3 cam_freeccb.3 \
+ cam.3 cam_path_string.3 \
+ cam.3 cam_device_dup.3 \
+ cam.3 cam_device_copy.3 \
+ cam.3 cam_get_device.3 \
+ cam_cdbparse.3 csio_build.3 \
+ cam_cdbparse.3 csio_build_visit.3 \
+ cam_cdbparse.3 csio_decode.3 \
+ cam_cdbparse.3 csio_decode_visit.3 \
+ cam_cdbparse.3 buff_decode.3 \
+ cam_cdbparse.3 buff_decode_visit.3 \
+ cam_cdbparse.3 csio_encode.3 \
+ cam_cdbparse.3 csio_encode_visit.3 \
+ cam_cdbparse.3 buff_encode_visit.3
+
+.PATH: ${.CURDIR}/../../sys/cam/scsi ${.CURDIR}/../../sys/cam
+
+SDIR= ${.CURDIR}/../../sys
+CFLAGS+= -I${.CURDIR} -I${SDIR}
.include <bsd.lib.mk>
diff --git a/lib/libsbuf/Makefile b/lib/libsbuf/Makefile
new file mode 100644
index 000000000000..a443545ca6f4
--- /dev/null
+++ b/lib/libsbuf/Makefile
@@ -0,0 +1,11 @@
+# $FreeBSD$
+
+LIB= sbuf
+SRCS= subr_sbuf.c
+
+.PATH: ${.CURDIR}/../../sys/kern
+
+SDIR= ${.CURDIR}/../../sys
+CFLAGS+=-I${SDIR}
+
+.include <bsd.lib.mk>
diff --git a/sbin/camcontrol/Makefile b/sbin/camcontrol/Makefile
index c9afb13468a0..8b047d3f0cf0 100644
--- a/sbin/camcontrol/Makefile
+++ b/sbin/camcontrol/Makefile
@@ -7,7 +7,7 @@ MAN= camcontrol.8
SDIR= ${.CURDIR}/../../sys
CFLAGS+= -I${SDIR}
-DPADD= ${LIBCAM}
-LDADD+= -lcam
+DPADD= ${LIBCAM} ${LIBSBUF}
+LDADD+= -lcam -lsbuf
.include <bsd.prog.mk>
diff --git a/sbin/camcontrol/camcontrol.c b/sbin/camcontrol/camcontrol.c
index 87e6fb9a9235..5d6dfc2192be 100644
--- a/sbin/camcontrol/camcontrol.c
+++ b/sbin/camcontrol/camcontrol.c
@@ -451,12 +451,8 @@ testunitready(struct cam_device *device, int retry_count, int timeout,
perror("error sending test unit ready");
if (arglist & CAM_ARG_VERBOSE) {
- if ((ccb->ccb_h.status & CAM_STATUS_MASK) ==
- CAM_SCSI_STATUS_ERROR)
- scsi_sense_print(device, &ccb->csio, stderr);
- else
- fprintf(stderr, "CAM status is %#x\n",
- ccb->ccb_h.status);
+ cam_error_print(device, ccb, CAM_ESF_ALL,
+ CAM_EPF_ALL, stderr);
}
cam_freeccb(ccb);
@@ -472,12 +468,8 @@ testunitready(struct cam_device *device, int retry_count, int timeout,
error = 1;
if (arglist & CAM_ARG_VERBOSE) {
- if ((ccb->ccb_h.status & CAM_STATUS_MASK) ==
- CAM_SCSI_STATUS_ERROR)
- scsi_sense_print(device, &ccb->csio, stderr);
- else
- fprintf(stderr, "CAM status is %#x\n",
- ccb->ccb_h.status);
+ cam_error_print(device, ccb, CAM_ESF_ALL,
+ CAM_EPF_ALL, stderr);
}
}
@@ -522,12 +514,8 @@ scsistart(struct cam_device *device, int startstop, int loadeject,
perror("error sending start unit");
if (arglist & CAM_ARG_VERBOSE) {
- if ((ccb->ccb_h.status & CAM_STATUS_MASK) ==
- CAM_SCSI_STATUS_ERROR)
- scsi_sense_print(device, &ccb->csio, stderr);
- else
- fprintf(stderr, "CAM status is %#x\n",
- ccb->ccb_h.status);
+ cam_error_print(device, ccb, CAM_ESF_ALL,
+ CAM_EPF_ALL, stderr);
}
cam_freeccb(ccb);
@@ -558,12 +546,8 @@ scsistart(struct cam_device *device, int startstop, int loadeject,
"Error received from stop unit command\n");
if (arglist & CAM_ARG_VERBOSE) {
- if ((ccb->ccb_h.status & CAM_STATUS_MASK) ==
- CAM_SCSI_STATUS_ERROR)
- scsi_sense_print(device, &ccb->csio, stderr);
- else
- fprintf(stderr, "CAM status is %#x\n",
- ccb->ccb_h.status);
+ cam_error_print(device, ccb, CAM_ESF_ALL,
+ CAM_EPF_ALL, stderr);
}
}
@@ -702,12 +686,8 @@ scsiinquiry(struct cam_device *device, int retry_count, int timeout)
perror("error sending SCSI inquiry");
if (arglist & CAM_ARG_VERBOSE) {
- if ((ccb->ccb_h.status & CAM_STATUS_MASK) ==
- CAM_SCSI_STATUS_ERROR)
- scsi_sense_print(device, &ccb->csio, stderr);
- else
- fprintf(stderr, "CAM status is %#x\n",
- ccb->ccb_h.status);
+ cam_error_print(device, ccb, CAM_ESF_ALL,
+ CAM_EPF_ALL, stderr);
}
cam_freeccb(ccb);
@@ -718,12 +698,8 @@ scsiinquiry(struct cam_device *device, int retry_count, int timeout)
error = 1;
if (arglist & CAM_ARG_VERBOSE) {
- if ((ccb->ccb_h.status & CAM_STATUS_MASK) ==
- CAM_SCSI_STATUS_ERROR)
- scsi_sense_print(device, &ccb->csio, stderr);
- else
- fprintf(stderr, "CAM status is %#x\n",
- ccb->ccb_h.status);
+ cam_error_print(device, ccb, CAM_ESF_ALL,
+ CAM_EPF_ALL, stderr);
}
}
@@ -792,12 +768,8 @@ scsiserial(struct cam_device *device, int retry_count, int timeout)
warn("error getting serial number");
if (arglist & CAM_ARG_VERBOSE) {
- if ((ccb->ccb_h.status & CAM_STATUS_MASK) ==
- CAM_SCSI_STATUS_ERROR)
- scsi_sense_print(device, &ccb->csio, stderr);
- else
- fprintf(stderr, "CAM status is %#x\n",
- ccb->ccb_h.status);
+ cam_error_print(device, ccb, CAM_ESF_ALL,
+ CAM_EPF_ALL, stderr);
}
cam_freeccb(ccb);
@@ -809,12 +781,8 @@ scsiserial(struct cam_device *device, int retry_count, int timeout)
error = 1;
if (arglist & CAM_ARG_VERBOSE) {
- if ((ccb->ccb_h.status & CAM_STATUS_MASK) ==
- CAM_SCSI_STATUS_ERROR)
- scsi_sense_print(device, &ccb->csio, stderr);
- else
- fprintf(stderr, "CAM status is %#x\n",
- ccb->ccb_h.status);
+ cam_error_print(device, ccb, CAM_ESF_ALL,
+ CAM_EPF_ALL, stderr);
}
}
@@ -871,13 +839,9 @@ scsixferrate(struct cam_device *device)
else
warnx(error_string);
- /*
- * If there is an error, it won't be a SCSI error since
- * this isn't a SCSI CCB.
- */
if (arglist & CAM_ARG_VERBOSE)
- fprintf(stderr, "CAM status is %#x\n",
- ccb->ccb_h.status);
+ cam_error_print(device, ccb, CAM_ESF_ALL,
+ CAM_EPF_ALL, stderr);
retval = 1;
@@ -1265,28 +1229,23 @@ readdefects(struct cam_device *device, int argc, char **argv,
perror("error reading defect list");
if (arglist & CAM_ARG_VERBOSE) {
- if ((ccb->ccb_h.status & CAM_STATUS_MASK) ==
- CAM_SCSI_STATUS_ERROR)
- scsi_sense_print(device, &ccb->csio, stderr);
- else
- fprintf(stderr, "CAM status is %#x\n",
- ccb->ccb_h.status);
+ cam_error_print(device, ccb, CAM_ESF_ALL,
+ CAM_EPF_ALL, stderr);
}
error = 1;
goto defect_bailout;
}
- if (arglist & CAM_ARG_VERBOSE)
- scsi_sense_print(device, &ccb->csio, stderr);
-
returned_length = scsi_2btoul(((struct
scsi_read_defect_data_hdr_10 *)defect_list)->length);
returned_format = ((struct scsi_read_defect_data_hdr_10 *)
defect_list)->format;
- if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
+ if (((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_SCSI_STATUS_ERROR)
+ && (ccb->csio.scsi_status == SCSI_STATUS_CHECK_COND)
+ && ((ccb->ccb_h.status & CAM_AUTOSNS_VALID) != 0)) {
struct scsi_sense_data *sense;
int error_code, sense_key, asc, ascq;
@@ -1327,8 +1286,18 @@ readdefects(struct cam_device *device, int argc, char **argv,
} else {
error = 1;
warnx("Error returned from read defect data command");
+ if (arglist & CAM_ARG_VERBOSE)
+ cam_error_print(device, ccb, CAM_ESF_ALL,
+ CAM_EPF_ALL, stderr);
goto defect_bailout;
}
+ } else {
+ error = 1;
+ warnx("Error returned from read defect data command");
+ if (arglist & CAM_ARG_VERBOSE)
+ cam_error_print(device, ccb, CAM_ESF_ALL,
+ CAM_EPF_ALL, stderr);
+ goto defect_bailout;
}
/*
@@ -1484,12 +1453,8 @@ mode_sense(struct cam_device *device, int mode_page, int page_control,
if (((retval = cam_send_ccb(device, ccb)) < 0)
|| ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
if (arglist & CAM_ARG_VERBOSE) {
- if ((ccb->ccb_h.status & CAM_STATUS_MASK) ==
- CAM_SCSI_STATUS_ERROR)
- scsi_sense_print(device, &ccb->csio, stderr);
- else
- fprintf(stderr, "CAM status is %#x\n",
- ccb->ccb_h.status);
+ cam_error_print(device, ccb, CAM_ESF_ALL,
+ CAM_EPF_ALL, stderr);
}
cam_freeccb(ccb);
cam_close_device(device);
@@ -1537,12 +1502,8 @@ mode_select(struct cam_device *device, int save_pages, int retry_count,
if (((retval = cam_send_ccb(device, ccb)) < 0)
|| ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
if (arglist & CAM_ARG_VERBOSE) {
- if ((ccb->ccb_h.status & CAM_STATUS_MASK) ==
- CAM_SCSI_STATUS_ERROR)
- scsi_sense_print(device, &ccb->csio, stderr);
- else
- fprintf(stderr, "CAM status is %#x\n",
- ccb->ccb_h.status);
+ cam_error_print(device, ccb, CAM_ESF_ALL,
+ CAM_EPF_ALL, stderr);
}
cam_freeccb(ccb);
cam_close_device(device);
@@ -1826,12 +1787,8 @@ scsicmd(struct cam_device *device, int argc, char **argv, char *combinedopt,
warnx("error sending command");
if (arglist & CAM_ARG_VERBOSE) {
- if ((ccb->ccb_h.status & CAM_STATUS_MASK) ==
- CAM_SCSI_STATUS_ERROR)
- scsi_sense_print(device, &ccb->csio, stderr);
- else
- fprintf(stderr, "CAM status is %#x\n",
- ccb->ccb_h.status);
+ cam_error_print(device, ccb, CAM_ESF_ALL,
+ CAM_EPF_ALL, stderr);
}
error = 1;
@@ -2053,8 +2010,9 @@ tagcontrol(struct cam_device *device, int argc, char **argv,
}
if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
- warnx("XPT_REL_SIMQ CCB failed, status %#x",
- ccb->ccb_h.status);
+ warnx("XPT_REL_SIMQ CCB failed");
+ cam_error_print(device, ccb, CAM_ESF_ALL,
+ CAM_EPF_ALL, stderr);
retval = 1;
goto tagcontrol_bailout;
}
@@ -2077,8 +2035,9 @@ tagcontrol(struct cam_device *device, int argc, char **argv,
}
if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
- warnx("XPT_GDEV_STATS CCB failed, status %#x",
- ccb->ccb_h.status);
+ warnx("XPT_GDEV_STATS CCB failed");
+ cam_error_print(device, ccb, CAM_ESF_ALL,
+ CAM_EPF_ALL, stderr);
retval = 1;
goto tagcontrol_bailout;
}
@@ -2178,8 +2137,8 @@ get_cpi(struct cam_device *device, struct ccb_pathinq *cpi)
warn("get_cpi: error sending Path Inquiry CCB");
if (arglist & CAM_ARG_VERBOSE)
- fprintf(stderr, "CAM status is %#x\n",
- ccb->ccb_h.status);
+ cam_error_print(device, ccb, CAM_ESF_ALL,
+ CAM_EPF_ALL, stderr);
retval = 1;
@@ -2189,8 +2148,8 @@ get_cpi(struct cam_device *device, struct ccb_pathinq *cpi)
if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
if (arglist & CAM_ARG_VERBOSE)
- fprintf(stderr, "get_cpi: CAM status is %#x\n",
- ccb->ccb_h.status);
+ cam_error_print(device, ccb, CAM_ESF_ALL,
+ CAM_EPF_ALL, stderr);
retval = 1;
@@ -2367,13 +2326,18 @@ get_print_cts(struct cam_device *device, int user_settings, int quiet,
if (cam_send_ccb(device, ccb) < 0) {
perror("error sending XPT_GET_TRAN_SETTINGS CCB");
+ if (arglist & CAM_ARG_VERBOSE)
+ cam_error_print(device, ccb, CAM_ESF_ALL,
+ CAM_EPF_ALL, stderr);
retval = 1;
goto get_print_cts_bailout;
}
if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
- warnx("XPT_GET_TRANS_SETTINGS CCB failed, status %#x",
- ccb->ccb_h.status);
+ warnx("XPT_GET_TRANS_SETTINGS CCB failed");
+ if (arglist & CAM_ARG_VERBOSE)
+ cam_error_print(device, ccb, CAM_ESF_ALL,
+ CAM_EPF_ALL, stderr);
retval = 1;
goto get_print_cts_bailout;
}
@@ -2497,13 +2461,20 @@ ratecontrol(struct cam_device *device, int retry_count, int timeout,
if (cam_send_ccb(device, ccb) < 0) {
perror("error sending XPT_PATH_INQ CCB");
+ if (arglist & CAM_ARG_VERBOSE) {
+ cam_error_print(device, ccb, CAM_ESF_ALL,
+ CAM_EPF_ALL, stderr);
+ }
retval = 1;
goto ratecontrol_bailout;
}
if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
- warnx("XPT_PATH_INQ CCB failed, status %#x",
- ccb->ccb_h.status);
+ warnx("XPT_PATH_INQ CCB failed");
+ if (arglist & CAM_ARG_VERBOSE) {
+ cam_error_print(device, ccb, CAM_ESF_ALL,
+ CAM_EPF_ALL, stderr);
+ }
retval = 1;
goto ratecontrol_bailout;
}
@@ -2645,13 +2616,20 @@ ratecontrol(struct cam_device *device, int retry_count, int timeout,
if (cam_send_ccb(device, ccb) < 0) {
perror("error sending XPT_SET_TRAN_SETTINGS CCB");
+ if (arglist & CAM_ARG_VERBOSE) {
+ cam_error_print(device, ccb, CAM_ESF_ALL,
+ CAM_EPF_ALL, stderr);
+ }
retval = 1;
goto ratecontrol_bailout;
}
if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
- warnx("XPT_SET_TRANS_SETTINGS CCB failed, status %#x",
- ccb->ccb_h.status);
+ warnx("XPT_SET_TRANS_SETTINGS CCB failed");
+ if (arglist & CAM_ARG_VERBOSE) {
+ cam_error_print(device, ccb, CAM_ESF_ALL,
+ CAM_EPF_ALL, stderr);
+ }
retval = 1;
goto ratecontrol_bailout;
}
@@ -2850,12 +2828,8 @@ scsiformat(struct cam_device *device, int argc, char **argv,
warnx(errstr);
if (arglist & CAM_ARG_VERBOSE) {
- if ((ccb->ccb_h.status & CAM_STATUS_MASK) ==
- CAM_SCSI_STATUS_ERROR)
- scsi_sense_print(device, &ccb->csio, stderr);
- else
- fprintf(stderr, "CAM status is %#x\n",
- ccb->ccb_h.status);
+ cam_error_print(device, ccb, CAM_ESF_ALL,
+ CAM_EPF_ALL, stderr);
}
error = 1;
goto scsiformat_bailout;
@@ -2904,13 +2878,8 @@ scsiformat(struct cam_device *device, int argc, char **argv,
if (retval < 0) {
warn("error sending CAMIOCOMMAND ioctl");
if (arglist & CAM_ARG_VERBOSE) {
- if ((ccb->ccb_h.status & CAM_STATUS_MASK) ==
- CAM_SCSI_STATUS_ERROR)
- scsi_sense_print(device, &ccb->csio,
- stderr);
- else
- fprintf(stderr, "CAM status is %#x\n",
- ccb->ccb_h.status);
+ cam_error_print(device, ccb, CAM_ESF_ALL,
+ CAM_EPF_ALL, stderr);
}
error = 1;
goto scsiformat_bailout;
@@ -2919,7 +2888,8 @@ scsiformat(struct cam_device *device, int argc, char **argv,
status = ccb->ccb_h.status & CAM_STATUS_MASK;
if ((status != CAM_REQ_CMP)
- && (status == CAM_SCSI_STATUS_ERROR)) {
+ && (status == CAM_SCSI_STATUS_ERROR)
+ && ((status & CAM_AUTOSNS_VALID) != 0)) {
struct scsi_sense_data *sense;
int error_code, sense_key, asc, ascq;
@@ -2970,13 +2940,17 @@ scsiformat(struct cam_device *device, int argc, char **argv,
sleep(1);
} else {
warnx("Unexpected SCSI error during format");
- scsi_sense_print(device, &ccb->csio, stderr);
+ cam_error_print(device, ccb, CAM_ESF_ALL,
+ CAM_EPF_ALL, stderr);
error = 1;
goto scsiformat_bailout;
}
} else if (status != CAM_REQ_CMP) {
warnx("Unexpected CAM status %#x", status);
+ if (arglist & CAM_ARG_VERBOSE)
+ cam_error_print(device, ccb, CAM_ESF_ALL,
+ CAM_EPF_ALL, stderr);
error = 1;
goto scsiformat_bailout;
}
diff --git a/share/man/man9/sbuf.9 b/share/man/man9/sbuf.9
index 704d7ad8f68c..0633c44e0b6e 100644
--- a/share/man/man9/sbuf.9
+++ b/share/man/man9/sbuf.9
@@ -52,9 +52,9 @@
.Ft int
.Fn sbuf_setpos "struct sbuf *s" "int pos"
.Ft int
-.Fn sbuf_cat "struct sbuf *s" "char *str"
+.Fn sbuf_cat "struct sbuf *s" "const char *str"
.Ft int
-.Fn sbuf_cpy "struct sbuf *s" "char *str"
+.Fn sbuf_cpy "struct sbuf *s" "const char *str"
.Ft int
.Fn sbuf_printf "struct sbuf *s" "char *fmt" "..."
.Ft int
@@ -177,7 +177,7 @@ and marks it as finished, which means that it may no longer be
modified using
.Fn sbuf_setpos ,
.Fn sbuf_cat ,
-.Fn sbuf_cpu ,
+.Fn sbuf_cpy ,
.Fn sbuf_printf
or
.Fn sbuf_putc .
diff --git a/share/mk/bsd.libnames.mk b/share/mk/bsd.libnames.mk
index 36ec7fc7cbc7..b53af03ed262 100644
--- a/share/mk/bsd.libnames.mk
+++ b/share/mk/bsd.libnames.mk
@@ -80,6 +80,7 @@ LIBRADIUS?= ${DESTDIR}${LIBDIR}/libradius.a
LIBREADLINE?= ${DESTDIR}${LIBDIR}/libreadline.a
LIBRESOLV?= ${DESTDIR}${LIBDIR}/libresolv.a # XXX doesn't exist
LIBRPCSVC?= ${DESTDIR}${LIBDIR}/librpcsvc.a
+LIBSBUF?= ${DESTDIR}${LIBDIR}/libsbuf.a
LIBSCRYPT?= "don't use LIBSCRYPT, use LIBCRYPT"
LIBDESCRYPT?= "don't use LIBDESCRYPT, use LIBCRYPT"
LIBSCSI?= ${DESTDIR}${LIBDIR}/libscsi.a
diff --git a/sys/cam/cam.c b/sys/cam/cam.c
index 4c28e42954fc..3f410bb27f9c 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 37e67fd89039..4aad13a7ad5a 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 2184465bda95..3a52f9744eea 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 22c56c6e05d3..b393f7619149 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 eba178710ced..ee6eace58326 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 5163d2062360..d1ddf2aacc78 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 8eb77e0c0842..f23338104dc6 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 cd74165b05e5..cb0f9d65ef35 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 ca39b09a0516..3c47b6eab72c 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 40c540b3fe89..4768ff1677dc 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 4c8afdbe8a9d..9ec85c8e1ea7 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 5b5956f626eb..3e9246bbd540 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 7c47bc287f6f..6dc25d47d238 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 39e92c35227e..d39765977ff3 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 61b9d045ef70..33e4c224e0a2 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 f288e4a0e9af..adfbbb092dbb 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 7e4b818d6e37..75c41ba3eb3b 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 e9062c1a3c89..5ee34bdd4568 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 59b6e978c6ba..9e5c8f172976 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 59b6e978c6ba..9e5c8f172976 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 ffe73f804ed8..11fc64f25fa2 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 000000000000..5b34500ed88d
--- /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 c9a3bf34b5dd..a1008b828d60 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 0244466cf49f..e2f0a6b4e89a 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
diff --git a/usr.bin/kdump/mkioctls b/usr.bin/kdump/mkioctls
index b8e4451e07f8..143f6cff491c 100644
--- a/usr.bin/kdump/mkioctls
+++ b/usr.bin/kdump/mkioctls
@@ -57,8 +57,8 @@ BEGIN {
print "#include <netinet6/in6_var.h>"
print "#include <netinet6/nd6.h>"
print "#include <netinet6/ip6_mroute.h>"
- print "#include <cam/cam.h>"
print "#include <stdio.h>"
+ print "#include <cam/cam.h>"
print ""
print ioctl_includes
print ""