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