Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 6 Oct 2011 19:15:51 +0000 (UTC)
From:      "Kenneth D. Merry" <ken@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-9@freebsd.org
Subject:   svn commit: r226067 - in stable/9: sbin/camcontrol share/examples/scsi_target share/misc sys/cam sys/cam/scsi sys/dev/ciss sys/dev/firewire sys/dev/iir sys/dev/iscsi/initiator sys/dev/isp sys/dev/m...
Message-ID:  <201110061915.p96JFpBW074072@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: ken
Date: Thu Oct  6 19:15:51 2011
New Revision: 226067
URL: http://svn.freebsd.org/changeset/base/226067

Log:
  MFC r225950:
  
  Add descriptor sense support to CAM, and honor sense residuals properly in
  CAM.
  
  Desriptor sense is a new sense data format that originated in SPC-3.  Among
  other things, it allows for an 8-byte info field, which is necessary to
  pass back block numbers larger than 4 bytes.
  
  This change adds a number of new functions to scsi_all.c (and therefore
  libcam) that abstract out most access to sense data.
  
  This includes a bump of CAM_VERSION, because the CCB ABI has changed.
  Userland programs that use the CAM pass(4) driver will need to be
  recompiled.
  
  camcontrol.c:	Change uses of scsi_extract_sense() to use
  		scsi_extract_sense_len().
  
  		Use scsi_get_sks() instead of accessing sense key specific
  		data directly.
  
  scsi_modes:	Update the control mode page to the latest version (SPC-4).
  
  scsi_cmds.c,
  scsi_target.c:	Change references to struct scsi_sense_data to struct
  		scsi_sense_data_fixed.  This should be changed to allow the
  		user to specify fixed or descriptor sense, and then use
  		scsi_set_sense_data() to build the sense data.
  
  ps3cdrom.c:	Use scsi_set_sense_data() instead of setting sense data
  		manually.
  
  cam_periph.c:	Use scsi_extract_sense_len() instead of using
  		scsi_extract_sense() or accessing sense data directly.
  
  cam_ccb.h:	Bump the CAM_VERSION from 0x15 to 0x16.  The change of
  		struct scsi_sense_data from 32 to 252 bytes changes the
  		size of struct ccb_scsiio, but not the size of union ccb.
  		So the version must be bumped to prevent structure
  		mis-matches.
  
  scsi_all.h:	Lots of updated SCSI sense data and other structures.
  
  		Add function prototypes for the new sense data functions.
  
  		Take out the inline implementation of scsi_extract_sense().
  		It is now too large to put in a header file.
  
  		Add macros to calculate whether fields are present and
  		filled in fixed and descriptor sense data
  
  scsi_all.c:	In scsi_op_desc(), allow the user to pass in NULL inquiry
  		data, and we'll assume a direct access device in that case.
  
  		Changed the SCSI RESERVED sense key name and description
  		to COMPLETED, as it is now defined in the spec.
  
  		Change the error recovery action for a number of read errors
  		to prevent lots of retries when the drive has said that the
  		block isn't accessible.  This speeds up reconstruction of
  		the block by any RAID software running on top of the drive
  		(e.g. ZFS).
  
  		In scsi_sense_desc(), allow for invalid sense key numbers.
  		This allows calling this routine without checking the input
  		values first.
  
  		Change scsi_error_action() to use scsi_extract_sense_len(),
  		and handle things when invalid asc/ascq values are
  		encountered.
  
  		Add a new routine, scsi_desc_iterate(), that will call the
  		supplied function for every descriptor in descriptor format
  		sense data.
  
  		Add scsi_set_sense_data(), and scsi_set_sense_data_va(),
  		which build descriptor and fixed format sense data.  They
  		currently default to fixed format sense data.
  
  		Add a number of scsi_get_*() functions, which get different
  		types of sense data fields from either fixed or descriptor
  		format sense data, if the data is present.
  
  		Add a number of scsi_*_sbuf() functions, which print
  		formatted versions of various sense data fields.  These
  		functions work for either fixed or descriptor sense.
  
  		Add a number of scsi_sense_*_sbuf() functions, which have a
  		standard calling interface and print the indicated field.
  		These functions take descriptors only.
  
  		Add scsi_sense_desc_sbuf(), which will print a formatted
  		version of the given sense descriptor.
  
  		Pull out a majority of the scsi_sense_sbuf() function and
  		put it into scsi_sense_only_sbuf().  This allows callers
  		that don't use struct ccb_scsiio to easily utilize the
  		printing routines.  Revamp that function to handle
  		descriptor sense and use the new sense fetching and
  		printing routines.
  
  		Move scsi_extract_sense() into scsi_all.c, and implement it
  		in terms of the new function, scsi_extract_sense_len().
  		The _len() version takes a length (which should be the
  		sense length - residual) and can indicate which fields are
  		present and valid in the sense data.
  
  		Add a couple of new scsi_get_*() routines to get the sense
  		key, asc, and ascq only.
  
  mly.c:		Rename struct scsi_sense_data to struct
  		scsi_sense_data_fixed.
  
  sbp_targ.c:	Use the new sense fetching routines to get sense data
  		instead of accessing it directly.
  
  sbp.c:		Change the firewire/SCSI sense data transformation code to
  		use struct scsi_sense_data_fixed instead of struct
  		scsi_sense_data.  This should be changed later to use
  		scsi_set_sense_data().
  
  ciss.c:		Calculate the sense residual properly.  Use
  		scsi_get_sense_key() to fetch the sense key.
  
  mps_sas.c,
  mpt_cam.c:	Set the sense residual properly.
  
  iir.c:		Use scsi_set_sense_data() instead of building sense data by
  		hand.
  
  iscsi_subr.c:	Use scsi_extract_sense_len() instead of grabbing sense data
  		directly.
  
  umass.c:	Use scsi_set_sense_data() to build sense data.
  
  		Grab the sense key using scsi_get_sense_key().
  
  		Calculate the sense residual properly.
  
  isp_freebsd.h:	Use scsi_get_*() routines to grab asc, ascq, and sense key
  		values.
  
  		Calculate and set the sense residual.
  
  Approved by:	re (kib)
  Sponsored by:	Spectra Logic Corporation

Modified:
  stable/9/sbin/camcontrol/camcontrol.c
  stable/9/share/examples/scsi_target/scsi_cmds.c
  stable/9/share/examples/scsi_target/scsi_target.c
  stable/9/share/misc/scsi_modes
  stable/9/sys/cam/cam_ccb.h
  stable/9/sys/cam/cam_periph.c
  stable/9/sys/cam/scsi/scsi_all.c
  stable/9/sys/cam/scsi/scsi_all.h
  stable/9/sys/cam/scsi/scsi_cd.c
  stable/9/sys/cam/scsi/scsi_da.c
  stable/9/sys/cam/scsi/scsi_low.c
  stable/9/sys/cam/scsi/scsi_sa.c
  stable/9/sys/cam/scsi/scsi_targ_bh.c
  stable/9/sys/dev/ciss/ciss.c
  stable/9/sys/dev/firewire/sbp.c
  stable/9/sys/dev/firewire/sbp_targ.c
  stable/9/sys/dev/iir/iir.c
  stable/9/sys/dev/iscsi/initiator/iscsi_subr.c
  stable/9/sys/dev/isp/isp_freebsd.h
  stable/9/sys/dev/mly/mly.c
  stable/9/sys/dev/mps/mps_sas.c
  stable/9/sys/dev/mpt/mpt_cam.c
  stable/9/sys/dev/usb/storage/umass.c
  stable/9/sys/powerpc/ps3/ps3cdrom.c
Directory Properties:
  stable/9/sbin/camcontrol/   (props changed)
  stable/9/share/examples/   (props changed)
  stable/9/share/misc/   (props changed)
  stable/9/sys/   (props changed)
  stable/9/sys/amd64/include/xen/   (props changed)
  stable/9/sys/boot/   (props changed)
  stable/9/sys/boot/i386/efi/   (props changed)
  stable/9/sys/boot/ia64/efi/   (props changed)
  stable/9/sys/boot/ia64/ski/   (props changed)
  stable/9/sys/boot/powerpc/boot1.chrp/   (props changed)
  stable/9/sys/boot/powerpc/ofw/   (props changed)
  stable/9/sys/cddl/contrib/opensolaris/   (props changed)
  stable/9/sys/conf/   (props changed)
  stable/9/sys/contrib/dev/acpica/   (props changed)
  stable/9/sys/contrib/octeon-sdk/   (props changed)
  stable/9/sys/contrib/pf/   (props changed)
  stable/9/sys/contrib/x86emu/   (props changed)

Modified: stable/9/sbin/camcontrol/camcontrol.c
==============================================================================
--- stable/9/sbin/camcontrol/camcontrol.c	Thu Oct  6 17:35:38 2011	(r226066)
+++ stable/9/sbin/camcontrol/camcontrol.c	Thu Oct  6 19:15:51 2011	(r226067)
@@ -1907,7 +1907,9 @@ readdefects(struct cam_device *device, i
 		int error_code, sense_key, asc, ascq;
 
 		sense = &ccb->csio.sense_data;
-		scsi_extract_sense(sense, &error_code, &sense_key, &asc, &ascq);
+		scsi_extract_sense_len(sense, ccb->csio.sense_len -
+		    ccb->csio.sense_resid, &error_code, &sense_key, &asc,
+		    &ascq, /*show_errors*/ 1);
 
 		/*
 		 * According to the SCSI spec, if the disk doesn't support
@@ -3798,8 +3800,9 @@ doreport:
 			int error_code, sense_key, asc, ascq;
 
 			sense = &ccb->csio.sense_data;
-			scsi_extract_sense(sense, &error_code, &sense_key,
-					   &asc, &ascq);
+			scsi_extract_sense_len(sense, ccb->csio.sense_len -
+			    ccb->csio.sense_resid, &error_code, &sense_key,
+			    &asc, &ascq, /*show_errors*/ 1);
 
 			/*
 			 * According to the SCSI-2 and SCSI-3 specs, a
@@ -3810,15 +3813,15 @@ doreport:
 			 */
 			if ((sense_key == SSD_KEY_NOT_READY)
 			 && (asc == 0x04) && (ascq == 0x04)) {
-				if ((sense->extra_len >= 10)
-				 && ((sense->sense_key_spec[0] &
-				      SSD_SCS_VALID) != 0)
+				uint8_t sks[3];
+
+				if ((scsi_get_sks(sense, ccb->csio.sense_len -
+				     ccb->csio.sense_resid, sks) == 0)
 				 && (quiet == 0)) {
 					int val;
 					u_int64_t percentage;
 
-					val = scsi_2btoul(
-						&sense->sense_key_spec[1]);
+					val = scsi_2btoul(&sks[1]);
 					percentage = 10000 * val;
 
 					fprintf(stdout,

Modified: stable/9/share/examples/scsi_target/scsi_cmds.c
==============================================================================
--- stable/9/share/examples/scsi_target/scsi_cmds.c	Thu Oct  6 17:35:38 2011	(r226066)
+++ stable/9/share/examples/scsi_target/scsi_cmds.c	Thu Oct  6 19:15:51 2011	(r226067)
@@ -242,22 +242,22 @@ tcmd_sense(u_int init_id, struct ccb_scs
 	       u_int8_t asc, u_int8_t ascq)
 {
 	struct initiator_state *istate;
-	struct scsi_sense_data *sense;
+	struct scsi_sense_data_fixed *sense;
 
 	/* Set our initiator's istate */
 	istate = tcmd_get_istate(init_id);
 	if (istate == NULL)
 		return;
 	istate->pending_ca |= CA_CMD_SENSE; /* XXX set instead of or? */
-	sense = &istate->sense_data;
+	sense = (struct scsi_sense_data_fixed *)&istate->sense_data;
 	bzero(sense, sizeof(*sense));
 	sense->error_code = SSD_CURRENT_ERROR;
 	sense->flags = flags;
 	sense->add_sense_code = asc;
 	sense->add_sense_code_qual = ascq;
 	sense->extra_len =
-		offsetof(struct scsi_sense_data, sense_key_spec[2]) -
-		offsetof(struct scsi_sense_data, extra_len);
+		offsetof(struct scsi_sense_data_fixed, sense_key_spec[2]) -
+		offsetof(struct scsi_sense_data_fixed, extra_len);
 
 	/* Fill out the supplied CTIO */
 	if (ctio != NULL) {
@@ -298,7 +298,7 @@ tcmd_inquiry(struct ccb_accept_tio *atio
 	struct scsi_inquiry *inq;
 	struct atio_descr *a_descr;
 	struct initiator_state *istate;
-	struct scsi_sense_data *sense;
+	struct scsi_sense_data_fixed *sense;
 
 	a_descr = (struct atio_descr *)atio->ccb_h.targ_descr;
 	inq = (struct scsi_inquiry *)a_descr->cdb;
@@ -310,7 +310,7 @@ tcmd_inquiry(struct ccb_accept_tio *atio
 	 * complain if EVPD or CMDDT is set.
 	 */
 	istate = tcmd_get_istate(ctio->init_id);
-	sense = &istate->sense_data;
+	sense = (struct scsi_sense_data_fixed *)&istate->sense_data;
 	if ((inq->byte2 & SI_EVPD) != 0) {
 		tcmd_illegal_req(atio, ctio);
 		sense->sense_key_spec[0] = SSD_SCS_VALID | SSD_FIELDPTR_CMD |
@@ -376,7 +376,7 @@ static int
 tcmd_req_sense(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio)
 {
 	struct scsi_request_sense *rsense;
-	struct scsi_sense_data *sense;
+	struct scsi_sense_data_fixed *sense;
 	struct initiator_state *istate;
 	size_t dlen;
 	struct atio_descr *a_descr;
@@ -385,7 +385,7 @@ tcmd_req_sense(struct ccb_accept_tio *at
 	rsense = (struct scsi_request_sense *)a_descr->cdb;
 	
 	istate = tcmd_get_istate(ctio->init_id);
-	sense = &istate->sense_data;
+	sense = (struct scsi_sense_data_fixed *)&istate->sense_data;
 
 	if (debug) {
 		cdb_debug(a_descr->cdb, "REQ SENSE from %u: ", atio->init_id);
@@ -400,7 +400,7 @@ tcmd_req_sense(struct ccb_accept_tio *at
 	}
 
 	bcopy(sense, ctio->data_ptr, sizeof(struct scsi_sense_data));
-	dlen = offsetof(struct scsi_sense_data, extra_len) +
+	dlen = offsetof(struct scsi_sense_data_fixed, extra_len) +
 			sense->extra_len + 1;
 	ctio->dxfer_len = min(dlen, SCSI_CDB6_LEN(rsense->length));
 	ctio->ccb_h.flags |= CAM_DIR_IN | CAM_SEND_STATUS;
@@ -482,7 +482,7 @@ tcmd_rdwr(struct ccb_accept_tio *atio, s
 	c_descr = (struct ctio_descr *)ctio->ccb_h.targ_descr;
 
 	/* Command needs to be decoded */
-	if ((a_descr->flags & CAM_DIR_MASK) == CAM_DIR_RESV) {
+	if ((a_descr->flags & CAM_DIR_MASK) == CAM_DIR_BOTH) {
 		if (debug)
 			warnx("Calling rdwr_decode");
 		ret = tcmd_rdwr_decode(atio, ctio);

Modified: stable/9/share/examples/scsi_target/scsi_target.c
==============================================================================
--- stable/9/share/examples/scsi_target/scsi_target.c	Thu Oct  6 17:35:38 2011	(r226066)
+++ stable/9/share/examples/scsi_target/scsi_target.c	Thu Oct  6 19:15:51 2011	(r226067)
@@ -651,7 +651,7 @@ work_atio(struct ccb_accept_tio *atio)
 	 * receiving this ATIO.
 	 */
 	if (atio->sense_len != 0) {
-		struct scsi_sense_data *sense;
+		struct scsi_sense_data_fixed *sense;
 
 		if (debug) {
 			warnx("ATIO with %u bytes sense received",
@@ -825,9 +825,9 @@ work_inot(struct ccb_immed_notify *inot)
 
 	/* If there is sense data, use it */
 	if (sense != 0) {
-		struct scsi_sense_data *sense;
+		struct scsi_sense_data_fixed *sense;
 
-		sense = &inot->sense_data;
+		sense = (struct scsi_sense_data_fixed *)&inot->sense_data;
 		tcmd_sense(inot->initiator_id, NULL, sense->flags,
 			   sense->add_sense_code, sense->add_sense_code_qual);
 		if (debug)

Modified: stable/9/share/misc/scsi_modes
==============================================================================
--- stable/9/share/misc/scsi_modes	Thu Oct  6 17:35:38 2011	(r226066)
+++ stable/9/share/misc/scsi_modes	Thu Oct  6 19:15:51 2011	(r226067)
@@ -50,19 +50,32 @@
 # ALL DEVICE TYPES
 
 0x0a "Control Mode Page" {
-	{Reserved} *t7
+	{TST} t3
+	{TMF_ONLY} t1
+	{DPICZ} t1
+	{D_SENSE} t1
+	{GLTSD} t1
 	{RLEC} t1
 	{Queue Algorithm Modifier} t4
-	{Reserved} *t2
-	{QErr} t1
+	{NUAR} t1
+	{QErr} t2
 	{DQue} t1
 	{EECA} t1
-	{Reserved} *t4
+	{RAC} t1
+	{UA_INTLCK_CTRL} t2
+	{SWP} t1
 	{RAENP} t1
 	{UAAENP} t1
 	{EAENP} t1
-	{Reserved} *i1
+	{ATO} t1
+	{TAS} t1
+	{ATMPE} t1
+	{RWWP} t1
+	{Reserved} *t1
+	{Autoload Mode} t3
 	{Ready AEN Holdoff Period} i2
+	{Busy Timeout Period} i2
+	{Extended Self-Test Completion Time} i2
 }
 
 0x02 "Disconnect-Reconnect Page" {

Modified: stable/9/sys/cam/cam_ccb.h
==============================================================================
--- stable/9/sys/cam/cam_ccb.h	Thu Oct  6 17:35:38 2011	(r226066)
+++ stable/9/sys/cam/cam_ccb.h	Thu Oct  6 19:15:51 2011	(r226067)
@@ -539,7 +539,7 @@ struct ccb_dev_match {
 /*
  * Definitions for the path inquiry CCB fields.
  */
-#define CAM_VERSION	0x15	/* Hex value for current version */
+#define CAM_VERSION	0x16	/* Hex value for current version */
 
 typedef enum {
 	PI_MDP_ABLE	= 0x80,	/* Supports MDP message */

Modified: stable/9/sys/cam/cam_periph.c
==============================================================================
--- stable/9/sys/cam/cam_periph.c	Thu Oct  6 17:35:38 2011	(r226066)
+++ stable/9/sys/cam/cam_periph.c	Thu Oct  6 19:15:51 2011	(r226067)
@@ -1085,7 +1085,6 @@ camperiphsensedone(struct cam_periph *pe
 	union ccb      *saved_ccb = (union ccb *)done_ccb->ccb_h.saved_ccb_ptr;
 	cam_status	status;
 	int		frozen = 0;
-	u_int		sense_key;
 	int		depth = done_ccb->ccb_h.recovery_depth;
 
 	status = done_ccb->ccb_h.status;
@@ -1101,22 +1100,25 @@ camperiphsensedone(struct cam_periph *pe
 	switch (status) {
 	case CAM_REQ_CMP:
 	{
+		int error_code, sense_key, asc, ascq;
+
+		scsi_extract_sense_len(&saved_ccb->csio.sense_data,
+				       saved_ccb->csio.sense_len -
+				       saved_ccb->csio.sense_resid,
+				       &error_code, &sense_key, &asc, &ascq,
+				       /*show_errors*/ 1);
 		/*
 		 * 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.
 		 */
-		sense_key = saved_ccb->csio.sense_data.flags;
-		sense_key &= SSD_KEY;
-		if (sense_key != SSD_KEY_NO_SENSE) {
-			saved_ccb->ccb_h.status |=
-			    CAM_AUTOSNS_VALID;
+		if ((sense_key != -1)
+		 && (sense_key != SSD_KEY_NO_SENSE)) {
+			saved_ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
 		} else {
-			saved_ccb->ccb_h.status &=
-			    ~CAM_STATUS_MASK;
-			saved_ccb->ccb_h.status |=
-			    CAM_AUTOSENSE_FAIL;
+			saved_ccb->ccb_h.status &= ~CAM_STATUS_MASK;
+			saved_ccb->ccb_h.status |= CAM_AUTOSENSE_FAIL;
 		}
 		saved_ccb->csio.sense_resid = done_ccb->csio.resid;
 		bcopy(saved_ccb, done_ccb, sizeof(union ccb));
@@ -1198,12 +1200,15 @@ camperiphdone(struct cam_periph *periph,
 		if (status & CAM_AUTOSNS_VALID) {
 			struct ccb_getdev cgd;
 			struct scsi_sense_data *sense;
-			int    error_code, sense_key, asc, ascq;	
+			int    error_code, sense_key, asc, ascq, sense_len;
 			scsi_sense_action err_action;
 
 			sense = &done_ccb->csio.sense_data;
-			scsi_extract_sense(sense, &error_code, 
-					   &sense_key, &asc, &ascq);
+			sense_len = done_ccb->csio.sense_len -
+				    done_ccb->csio.sense_resid;
+			scsi_extract_sense_len(sense, sense_len, &error_code, 
+					       &sense_key, &asc, &ascq,
+					       /*show_errors*/ 1);
 			/*
 			 * Grab the inquiry data for this device.
 			 */

Modified: stable/9/sys/cam/scsi/scsi_all.c
==============================================================================
--- stable/9/sys/cam/scsi/scsi_all.c	Thu Oct  6 17:35:38 2011	(r226066)
+++ stable/9/sys/cam/scsi/scsi_all.c	Thu Oct  6 19:15:51 2011	(r226067)
@@ -31,6 +31,8 @@
 __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stdint.h>
 
 #ifdef _KERNEL
 #include <opt_scsi.h>
@@ -54,6 +56,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/sbuf.h>
 #ifndef _KERNEL
 #include <camlib.h>
+#include <stddef.h>
 
 #ifndef FALSE
 #define FALSE   0
@@ -608,14 +611,24 @@ scsi_op_desc(u_int16_t opcode, struct sc
 	struct op_table_entry *table[2];
 	int num_tables;
 
-	pd_type = SID_TYPE(inq_data);
+	/*
+	 * If we've got inquiry data, use it to determine what type of
+	 * device we're dealing with here.  Otherwise, assume direct
+	 * access.
+	 */
+	if (inq_data == NULL) {
+		pd_type = T_DIRECT;
+		match = NULL;
+	} else {
+		pd_type = SID_TYPE(inq_data);
 
-	match = cam_quirkmatch((caddr_t)inq_data,
-			       (caddr_t)scsi_op_quirk_table,
-			       sizeof(scsi_op_quirk_table)/
-			       sizeof(*scsi_op_quirk_table),
-			       sizeof(*scsi_op_quirk_table),
-			       scsi_inquiry_match);
+		match = cam_quirkmatch((caddr_t)inq_data,
+				       (caddr_t)scsi_op_quirk_table,
+				       sizeof(scsi_op_quirk_table)/
+				       sizeof(*scsi_op_quirk_table),
+				       sizeof(*scsi_op_quirk_table),
+				       scsi_inquiry_match);
+	}
 
 	if (match != NULL) {
 		table[0] = ((struct scsi_op_quirk_entry *)match)->op_table;
@@ -699,7 +712,7 @@ const struct sense_key_table_entry sense
 	{ SSD_KEY_EQUAL, SS_NOP, "EQUAL" },
 	{ SSD_KEY_VOLUME_OVERFLOW, SS_FATAL|EIO, "VOLUME OVERFLOW" },
 	{ SSD_KEY_MISCOMPARE, SS_NOP, "MISCOMPARE" },
-	{ SSD_KEY_RESERVED, SS_FATAL|EIO, "RESERVED" }
+	{ SSD_KEY_COMPLETED, SS_NOP, "COMPLETED" }
 };
 
 const int sense_key_table_size =
@@ -1062,25 +1075,25 @@ static struct asc_table_entry asc_table[
 	{ SST(0x10, 0x03, SS_RDEF,	/* XXX TBD */
 	    "Logical block reference tag check failed") },
 	/* DT  WRO   BK   */
-	{ SST(0x11, 0x00, SS_RDEF,
+	{ SST(0x11, 0x00, SS_FATAL|EIO,
 	    "Unrecovered read error") },
 	/* DT  WRO   BK   */
-	{ SST(0x11, 0x01, SS_RDEF,
+	{ SST(0x11, 0x01, SS_FATAL|EIO,
 	    "Read retries exhausted") },
 	/* DT  WRO   BK   */
-	{ SST(0x11, 0x02, SS_RDEF,
+	{ SST(0x11, 0x02, SS_FATAL|EIO,
 	    "Error too long to correct") },
 	/* DT  W O   BK   */
-	{ SST(0x11, 0x03, SS_RDEF,
+	{ SST(0x11, 0x03, SS_FATAL|EIO,
 	    "Multiple read errors") },
 	/* D   W O   BK   */
-	{ SST(0x11, 0x04, SS_RDEF,
+	{ SST(0x11, 0x04, SS_FATAL|EIO,
 	    "Unrecovered read error - auto reallocate failed") },
 	/*     WRO   B    */
-	{ SST(0x11, 0x05, SS_RDEF,
+	{ SST(0x11, 0x05, SS_FATAL|EIO,
 	    "L-EC uncorrectable error") },
 	/*     WRO   B    */
-	{ SST(0x11, 0x06, SS_RDEF,
+	{ SST(0x11, 0x06, SS_FATAL|EIO,
 	    "CIRC unrecovered error") },
 	/*     W O   B    */
 	{ SST(0x11, 0x07, SS_RDEF,
@@ -1095,10 +1108,10 @@ static struct asc_table_entry asc_table[
 	{ SST(0x11, 0x0A, SS_RDEF,
 	    "Miscorrected error") },
 	/* D   W O   BK   */
-	{ SST(0x11, 0x0B, SS_RDEF,
+	{ SST(0x11, 0x0B, SS_FATAL|EIO,
 	    "Unrecovered read error - recommend reassignment") },
 	/* D   W O   BK   */
-	{ SST(0x11, 0x0C, SS_RDEF,
+	{ SST(0x11, 0x0C, SS_FATAL|EIO,
 	    "Unrecovered read error - recommend rewrite the data") },
 	/* DT  WRO   B    */
 	{ SST(0x11, 0x0D, SS_RDEF,
@@ -2790,7 +2803,10 @@ scsi_sense_desc(int sense_key, int asc, 
 			  &sense_entry,
 			  &asc_entry);
 
-	*sense_key_desc = sense_entry->desc;
+	if (sense_entry != NULL)
+		*sense_key_desc = sense_entry->desc;
+	else
+		*sense_key_desc = "Invalid Sense Key";
 
 	if (asc_entry != NULL)
 		*asc_desc = asc_entry->desc;
@@ -2816,10 +2832,12 @@ scsi_error_action(struct ccb_scsiio *csi
 	int error_code, sense_key, asc, ascq;
 	scsi_sense_action action;
 
-	scsi_extract_sense(&csio->sense_data, &error_code,
-			   &sense_key, &asc, &ascq);
+	scsi_extract_sense_len(&csio->sense_data, csio->sense_len -
+			       csio->sense_resid, &error_code,
+			       &sense_key, &asc, &ascq, /*show_errors*/ 1);
 
-	if (error_code == SSD_DEFERRED_ERROR) {
+	if ((error_code == SSD_DEFERRED_ERROR)
+	 || (error_code == SSD_DESC_DEFERRED_ERROR)) {
 		/*
 		 * XXX dufault@FreeBSD.org
 		 * This error doesn't relate to the command associated
@@ -2857,8 +2875,10 @@ scsi_error_action(struct ccb_scsiio *csi
 		if (asc_entry != NULL
 		 && (asc != 0 || ascq != 0))
 			action = asc_entry->action;
-		else
+		else if (sense_entry != NULL)
 			action = sense_entry->action;
+		else
+			action = SS_RETRY|SSQ_DECREMENT_COUNT|SSQ_PRINT_SENSE; 
 
 		if (sense_key == SSD_KEY_RECOVERED_ERROR) {
 			/*
@@ -3040,308 +3060,1530 @@ scsi_command_string(struct cam_device *d
 	return(0);
 }
 
-
 /*
- * scsi_sense_sbuf() returns 0 for success and -1 for failure.
+ * Iterate over sense descriptors.  Each descriptor is passed into iter_func(). 
+ * If iter_func() returns 0, list traversal continues.  If iter_func()
+ * returns non-zero, list traversal is stopped.
  */
-#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 */
+void
+scsi_desc_iterate(struct scsi_sense_data_desc *sense, u_int sense_len,
+		  int (*iter_func)(struct scsi_sense_data_desc *sense,
+				   u_int, struct scsi_sense_desc_header *,
+				   void *), void *arg)
 {
-	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;
-	char	  path_str[64];
-
-#ifndef _KERNEL
-	if (device == NULL)
-		return(-1);
-#endif /* !_KERNEL */
-	if ((csio == NULL) || (sb == NULL))
-		return(-1);
+	int cur_pos;
+	int desc_len;
 
 	/*
-	 * If the CDB is a physical address, we can't deal with it..
+	 * First make sure the extra length field is present.
 	 */
-	if ((csio->ccb_h.flags & CAM_CDB_PHYS) != 0)
-		flags &= ~SSS_FLAG_PRINT_COMMAND;
+	if (SSD_DESC_IS_PRESENT(sense, sense_len, extra_len) == 0)
+		return;
 
-#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 */
+	/*
+	 * The length of data actually returned may be different than the
+	 * extra_len recorded in the sturcture.
+	 */
+	desc_len = sense_len -offsetof(struct scsi_sense_data_desc, sense_desc);
 
-#ifdef _KERNEL
-	if ((cgd = (struct ccb_getdev*)xpt_alloc_ccb_nowait()) == NULL)
-		return(-1);
 	/*
-	 * Get the device information.
+	 * Limit this further by the extra length reported, and the maximum
+	 * allowed extra length.
 	 */
-	xpt_setup_ccb(&cgd->ccb_h,
-		      csio->ccb_h.path,
-		      CAM_PRIORITY_NORMAL);
-	cgd->ccb_h.func_code = XPT_GDEV_TYPE;
-	xpt_action((union ccb *)cgd);
+	desc_len = MIN(desc_len, MIN(sense->extra_len, SSD_EXTRA_MAX));
 
 	/*
-	 * If the device is unconfigured, just pretend that it is a hard
-	 * drive.  scsi_op_desc() needs this.
+	 * Subtract the size of the header from the descriptor length.
+	 * This is to ensure that we have at least the header left, so we
+	 * don't have to check that inside the loop.  This can wind up
+	 * being a negative value.
 	 */
-	if (cgd->ccb_h.status == CAM_DEV_NOT_THERE)
-		cgd->inq_data.device = T_DIRECT;
+	desc_len -= sizeof(struct scsi_sense_desc_header);
 
-	inq_data = &cgd->inq_data;
+	for (cur_pos = 0; cur_pos < desc_len;) {
+		struct scsi_sense_desc_header *header;
 
-#else /* !_KERNEL */
+		header = (struct scsi_sense_desc_header *)
+			&sense->sense_desc[cur_pos];
 
-	inq_data = &device->inq_data;
+		/*
+		 * Check to make sure we have the entire descriptor.  We
+		 * don't call iter_func() unless we do.
+		 *
+		 * Note that although cur_pos is at the beginning of the
+		 * descriptor, desc_len already has the header length
+		 * subtracted.  So the comparison of the length in the
+		 * header (which does not include the header itself) to
+		 * desc_len - cur_pos is correct.
+		 */
+		if (header->length > (desc_len - cur_pos)) 
+			break;
 
-#endif /* _KERNEL/!_KERNEL */
+		if (iter_func(sense, sense_len, header, arg) != 0)
+			break;
 
-	sense = NULL;
+		cur_pos += sizeof(*header) + header->length;
+	}
+}
 
-	if (flags & SSS_FLAG_PRINT_COMMAND) {
+struct scsi_find_desc_info {
+	uint8_t desc_type;
+	struct scsi_sense_desc_header *header;
+};
 
-		sbuf_cat(sb, path_str);
+static int
+scsi_find_desc_func(struct scsi_sense_data_desc *sense, u_int sense_len,
+		    struct scsi_sense_desc_header *header, void *arg)
+{
+	struct scsi_find_desc_info *desc_info;
 
-#ifdef _KERNEL
-		scsi_command_string(csio, sb);
-#else /* !_KERNEL */
-		scsi_command_string(device, csio, sb);
-#endif /* _KERNEL/!_KERNEL */
-		sbuf_printf(sb, "\n");
-	}
+	desc_info = (struct scsi_find_desc_info *)arg;
+
+	if (header->desc_type == desc_info->desc_type) {
+		desc_info->header = header;
+
+		/* We found the descriptor, tell the iterator to stop. */
+		return (1);
+	} else
+		return (0);
+}
+
+/*
+ * Given a descriptor type, return a pointer to it if it is in the sense
+ * data and not truncated.  Avoiding truncating sense data will simplify
+ * things significantly for the caller.
+ */
+uint8_t *
+scsi_find_desc(struct scsi_sense_data_desc *sense, u_int sense_len,
+	       uint8_t desc_type)
+{
+	struct scsi_find_desc_info desc_info;
+
+	desc_info.desc_type = desc_type;
+	desc_info.header = NULL;
+
+	scsi_desc_iterate(sense, sense_len, scsi_find_desc_func, &desc_info);
+
+	return ((uint8_t *)desc_info.header);
+}
+
+/*
+ * Fill in SCSI sense data with the specified parameters.  This routine can
+ * fill in either fixed or descriptor type sense data.
+ */
+void
+scsi_set_sense_data_va(struct scsi_sense_data *sense_data,
+		      scsi_sense_data_type sense_format, int current_error,
+		      int sense_key, int asc, int ascq, va_list ap) 
+{
+	int descriptor_sense;
+	scsi_sense_elem_type elem_type;
 
 	/*
-	 * If the sense data is a physical pointer, forget it.
+	 * Determine whether to return fixed or descriptor format sense
+	 * data.  If the user specifies SSD_TYPE_NONE for some reason,
+	 * they'll just get fixed sense data.
 	 */
-	if (csio->ccb_h.flags & CAM_SENSE_PTR) {
-		if (csio->ccb_h.flags & CAM_SENSE_PHYS) {
-#ifdef _KERNEL
-			xpt_free_ccb((union ccb*)cgd);
-#endif /* _KERNEL/!_KERNEL */
-			return(-1);
-		} else {
-			/* 
-			 * 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 *));
-		}
-	} else {
+	if (sense_format == SSD_TYPE_DESC)
+		descriptor_sense = 1;
+	else
+		descriptor_sense = 0;
+
+	/*
+	 * Zero the sense data, so that we don't pass back any garbage data
+	 * to the user.
+	 */
+	memset(sense_data, 0, sizeof(*sense_data));
+
+	if (descriptor_sense != 0) {
+		struct scsi_sense_data_desc *sense;
+
+		sense = (struct scsi_sense_data_desc *)sense_data;
 		/*
-		 * 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.)
+		 * The descriptor sense format eliminates the use of the
+		 * valid bit.
 		 */
-		if (csio->ccb_h.flags & CAM_SENSE_PHYS) {
-#ifdef _KERNEL
-			xpt_free_ccb((union ccb*)cgd);
-#endif /* _KERNEL/!_KERNEL */
-			return(-1);
-		} else
-			sense = &csio->sense_data;
-	}
-
+		if (current_error != 0)
+			sense->error_code = SSD_DESC_CURRENT_ERROR;
+		else
+			sense->error_code = SSD_DESC_DEFERRED_ERROR;
+		sense->sense_key = sense_key;
+		sense->add_sense_code = asc;
+		sense->add_sense_code_qual = ascq;
+		/*
+		 * Start off with no extra length, since the above data
+		 * fits in the standard descriptor sense information.
+		 */
+		sense->extra_len = 0;
+		while ((elem_type = (scsi_sense_elem_type)va_arg(ap,
+			scsi_sense_elem_type)) != SSD_ELEM_NONE) {
+			int sense_len, len_to_copy;
+			uint8_t *data;
+
+			if (elem_type >= SSD_ELEM_MAX) {
+				printf("%s: invalid sense type %d\n", __func__,
+				       elem_type);
+				break;
+			}
 
-	sbuf_cat(sb, path_str);
+			sense_len = (int)va_arg(ap, int);
+			len_to_copy = MIN(sense_len, SSD_EXTRA_MAX -
+					  sense->extra_len);
+			data = (uint8_t *)va_arg(ap, uint8_t *);
 
-	error_code = sense->error_code & SSD_ERRCODE;
-	sense_key = sense->flags & SSD_KEY;
+			/*
+			 * We've already consumed the arguments for this one.
+			 */
+			if (elem_type == SSD_ELEM_SKIP)
+				continue;
 
-	sbuf_printf(sb, "SCSI sense: ");
-	switch (error_code) {
-	case SSD_DEFERRED_ERROR:
-		sbuf_printf(sb, "Deferred error: ");
+			switch (elem_type) {
+			case SSD_ELEM_DESC: {
 
-		/* FALLTHROUGH */
-	case SSD_CURRENT_ERROR:
-	{
-		const char *sense_key_desc;
-		const char *asc_desc;
+				/*
+				 * This is a straight descriptor.  All we
+				 * need to do is copy the data in.
+				 */
+				bcopy(data, &sense->sense_desc[
+				      sense->extra_len], len_to_copy);
+				sense->extra_len += len_to_copy;
+				break;
+			}
+			case SSD_ELEM_SKS: {
+				struct scsi_sense_sks sks;
 
-		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);
+				bzero(&sks, sizeof(sks));
 
-		info = scsi_4btoul(sense->info);
-		
-		if (sense->error_code & SSD_ERRCODE_VALID) {
+				/*
+				 * This is already-formatted sense key
+				 * specific data.  We just need to fill out
+				 * the header and copy everything in.
+				 */
+				bcopy(data, &sks.sense_key_spec,
+				      MIN(len_to_copy,
+				          sizeof(sks.sense_key_spec)));
+
+				sks.desc_type = SSD_DESC_SKS;
+				sks.length = sizeof(sks) -
+				    offsetof(struct scsi_sense_sks, reserved1);
+				bcopy(&sks,&sense->sense_desc[sense->extra_len],
+				      sizeof(sks));
+				sense->extra_len += sizeof(sks);
+				break;
+			}
+			case SSD_ELEM_INFO:
+			case SSD_ELEM_COMMAND: {
+				struct scsi_sense_command cmd;
+				struct scsi_sense_info info;
+				uint8_t *data_dest;
+				uint8_t *descriptor;
+				int descriptor_size, i, copy_len;
+
+				bzero(&cmd, sizeof(cmd));
+				bzero(&info, sizeof(info));
+
+				/*
+				 * Command or information data.  The
+				 * operate in pretty much the same way.
+				 */
+				if (elem_type == SSD_ELEM_COMMAND) {
+					len_to_copy = MIN(len_to_copy,
+					    sizeof(cmd.command_info));
+					descriptor = (uint8_t *)&cmd;
+					descriptor_size  = sizeof(cmd);
+					data_dest =(uint8_t *)&cmd.command_info;
+					cmd.desc_type = SSD_DESC_COMMAND;
+					cmd.length = sizeof(cmd) -
+					    offsetof(struct scsi_sense_command,
+						     reserved);
+				} else {
+					len_to_copy = MIN(len_to_copy,
+					    sizeof(info.info));
+					descriptor = (uint8_t *)&info;
+					descriptor_size = sizeof(cmd);
+					data_dest = (uint8_t *)&info.info;
+					info.desc_type = SSD_DESC_INFO;
+					info.byte2 = SSD_INFO_VALID;
+					info.length = sizeof(info) -
+					    offsetof(struct scsi_sense_info,
+						     byte2);
+				}
 
-			switch (sense_key) {
-			case SSD_KEY_NOT_READY:
-			case SSD_KEY_ILLEGAL_REQUEST:
-			case SSD_KEY_UNIT_ATTENTION:
-			case SSD_KEY_DATA_PROTECT:
+				/*
+				 * Copy this in reverse because the spec
+				 * (SPC-4) says that when 4 byte quantities
+				 * are stored in this 8 byte field, the
+				 * first four bytes shall be 0.
+				 *
+				 * So we fill the bytes in from the end, and
+				 * if we have less than 8 bytes to copy,
+				 * the initial, most significant bytes will
+				 * be 0.
+				 */
+				for (i = sense_len - 1; i >= 0 &&
+				     len_to_copy > 0; i--, len_to_copy--)
+					data_dest[len_to_copy - 1] = data[i];
+
+				/*
+				 * This calculation looks much like the
+				 * initial len_to_copy calculation, but
+				 * we have to do it again here, because
+				 * we're looking at a larger amount that
+				 * may or may not fit.  It's not only the
+				 * data the user passed in, but also the
+				 * rest of the descriptor.
+				 */
+				copy_len = MIN(descriptor_size,
+				    SSD_EXTRA_MAX - sense->extra_len);
+				bcopy(descriptor, &sense->sense_desc[
+				      sense->extra_len], copy_len);
+				sense->extra_len += copy_len;
+				break;
+			}
+			case SSD_ELEM_FRU: {
+				struct scsi_sense_fru fru;
+				int copy_len;
+
+				bzero(&fru, sizeof(fru));
+
+				fru.desc_type = SSD_DESC_FRU;
+				fru.length = sizeof(fru) -
+				    offsetof(struct scsi_sense_fru, reserved);
+				fru.fru = *data;
+
+				copy_len = MIN(sizeof(fru), SSD_EXTRA_MAX -
+					       sense->extra_len);
+				bcopy(&fru, &sense->sense_desc[
+				      sense->extra_len], copy_len);
+				sense->extra_len += copy_len;
 				break;
-			case SSD_KEY_BLANK_CHECK:
-				sbuf_printf(sb, " req sz: %d (decimal)", info);
+			}
+			case SSD_ELEM_STREAM: {
+				struct scsi_sense_stream stream_sense;
+				int copy_len;
+
+				bzero(&stream_sense, sizeof(stream_sense));
+				stream_sense.desc_type = SSD_DESC_STREAM;
+				stream_sense.length = sizeof(stream_sense) -
+				   offsetof(struct scsi_sense_stream, reserved);
+				stream_sense.byte3 = *data;
+
+				copy_len = MIN(sizeof(stream_sense),
+				    SSD_EXTRA_MAX - sense->extra_len);
+				bcopy(&stream_sense, &sense->sense_desc[
+				      sense->extra_len], copy_len);
+				sense->extra_len += copy_len;
 				break;
+			}
 			default:
-				if (info) {
-					if (sense->flags & SSD_ILI) {
-						sbuf_printf(sb, " ILI (length "
-							"mismatch): %d", info);
-			
-					} else {
-						sbuf_printf(sb, " info:%x", 
-							    info);
-					}
-				}
+				/*
+				 * We shouldn't get here, but if we do, do
+				 * nothing.  We've already consumed the
+				 * arguments above.
+				 */
+				break;
 			}
-		} else if (info) {
-			sbuf_printf(sb, " info?:%x", info);
 		}
+	} else {
+		struct scsi_sense_data_fixed *sense;
 
-		if (sense->extra_len >= 4) {
-			if (bcmp(sense->cmd_spec_info, "\0\0\0\0", 4)) {
-				sbuf_printf(sb, " csi:%x,%x,%x,%x",
-					    sense->cmd_spec_info[0],
-					    sense->cmd_spec_info[1],
-					    sense->cmd_spec_info[2],
-					    sense->cmd_spec_info[3]);
-			}
-		}
+		sense = (struct scsi_sense_data_fixed *)sense_data;
 
-		sbuf_printf(sb, " asc:%x,%x (%s)", asc, ascq, asc_desc);
+		if (current_error != 0)
+			sense->error_code = SSD_CURRENT_ERROR;
+		else
+			sense->error_code = SSD_DEFERRED_ERROR;
 
-		if (sense->extra_len >= 7 && sense->fru) {
-			sbuf_printf(sb, " field replaceable unit: %x", 
-				    sense->fru);
-		}
+		sense->flags = sense_key;
+		sense->add_sense_code = asc;
+		sense->add_sense_code_qual = ascq;
+		/*
+		 * We've set the ASC and ASCQ, so we have 6 more bytes of
+		 * valid data.  If we wind up setting any of the other
+		 * fields, we'll bump this to 10 extra bytes.
+		 */
+		sense->extra_len = 6;
 
-		if ((sense->extra_len >= 10)
-		 && (sense->sense_key_spec[0] & SSD_SCS_VALID) != 0) {
-			switch(sense_key) {
-			case SSD_KEY_ILLEGAL_REQUEST: {
-				int bad_command;
-				char tmpstr2[40];
-
-				if (sense->sense_key_spec[0] & 0x40)
-					bad_command = 1;
-				else
-					bad_command = 0;
-
-				tmpstr2[0] = '\0';
-
-				/* Bit pointer is valid */
-				if (sense->sense_key_spec[0] & 0x08)
-					snprintf(tmpstr2, sizeof(tmpstr2),
-						 "bit %d ",
-						sense->sense_key_spec[0] & 0x7);
-				sbuf_printf(sb, ": %s byte %d %sis invalid",
-					    bad_command ? "Command" : "Data",
-					    scsi_2btoul(
-					    &sense->sense_key_spec[1]),
-					    tmpstr2);
+		while ((elem_type = (scsi_sense_elem_type)va_arg(ap,
+			scsi_sense_elem_type)) != SSD_ELEM_NONE) {
+			int sense_len, len_to_copy;
+			uint8_t *data;
+
+			if (elem_type >= SSD_ELEM_MAX) {
+				printf("%s: invalid sense type %d\n", __func__,
+				       elem_type);
 				break;
 			}
-			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]));
+			/*
+			 * If we get in here, just bump the extra length to
+			 * 10 bytes.  That will encompass anything we're
+			 * going to set here.
+			 */
+			sense->extra_len = 10;
+			sense_len = (int)va_arg(ap, int);
+			len_to_copy = MIN(sense_len, SSD_EXTRA_MAX -
+					  sense->extra_len);
+			data = (uint8_t *)va_arg(ap, uint8_t *);
+
+			switch (elem_type) {
+			case SSD_ELEM_SKS:
+				/*
+				 * The user passed in pre-formatted sense
+				 * key specific data.
+				 */
+				bcopy(data, &sense->sense_key_spec[0],
+				      MIN(sizeof(sense->sense_key_spec),
+				      sense_len));
 				break;
-			default:
-				sbuf_printf(sb, " sks:%#x,%#x", 
-					    sense->sense_key_spec[0],
-					    scsi_2btoul(
-					    &sense->sense_key_spec[1]));
+			case SSD_ELEM_INFO:
+			case SSD_ELEM_COMMAND: {
+				uint8_t *data_dest;
+				int i;
+
+				if (elem_type == SSD_ELEM_COMMAND)
+					data_dest = &sense->cmd_spec_info[0];
+				else {
+					data_dest = &sense->info[0];
+					/*
+					 * We're setting the info field, so
+					 * set the valid bit.
+					 */
+					sense->error_code |= SSD_ERRCODE_VALID;
+				}
+
+				/*
+			 	 * Copy this in reverse so that if we have
+				 * less than 4 bytes to fill, the least
+				 * significant bytes will be at the end.
+				 * If we have more than 4 bytes, only the
+				 * least significant bytes will be included.
+				 */
+				for (i = sense_len - 1; i >= 0 &&
+				     len_to_copy > 0; i--, len_to_copy--)

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201110061915.p96JFpBW074072>