svn commit: r249658 - in head: bin/chio sys/cam/scsi sys/sys

Kenneth D. Merry ken at FreeBSD.org
Fri Apr 19 20:03:53 UTC 2013


Author: ken
Date: Fri Apr 19 20:03:51 2013
New Revision: 249658
URL: http://svnweb.freebsd.org/changeset/base/249658

Log:
  Update chio(1) and ch(4) to support reporting element designators.
  
  This allows mapping a tape drive in a changer (as reported by
  'chio status') to a sa(4) driver instance by comparing the
  serial numbers.
  
  The designators can be ASCII (which is printed out directly), binary
  (which is printed in hex format) or UTF-8, which is printed in either
  native UTF-8 format if the terminal can support it, or in %XX notation
  for non-ASCII characters.  Thanks to Hiroki Sato <hrs@> for the
  explaining UTF-8 printing and example UTF-8 printing code.
  
  chio.h:		Modify the changer_element_status structure to add new
  		fields and definitions from the SMC3r16 spec.
  
  		Rename the original CHIOGSTATUS ioctl to OCHIOGTATUS and
  		define a new CHIOGSTATUS ioctl.
  
  		Clean up some tab/space issues.
  
  chio.c: 	For the 'status' subcommand, print the designator field
  		if it is supplied by a device.
  
  scsi_ch.h:	Add new flags for DVCID and CURDATA to the READ
  		ELEMENT STATUS command structure.
  
  		Add a read_element_status_device_id structure
  		for the data fields in the new standard. Add new
  		unions, dt_or_obsolete and voltage_devid, to hold
  		and address data from either SCSI-2 or newer devices.
  
  scsi_ch.c:	Implement support for fetching device IDs with READ
  		ELEMENT STATUS data.
  
  		Add new arguments to scsi_read_element_status() to
  		allow the user to request the DVCID and CURDATA bits.
  		This isn't compiled into libcam (it's only an internal
  		kernel interface), so we don't need any special
  		handling for the API change.
  
  		If the user issues the new CHIOGSTATUS ioctl, copy all of
  		the available element status data out.  If he issues the
  		OCHIOGSTATUS ioctl, we don't copy the new fields in the
  		structure.
  
  		Fix a bug in chopen() that would result in the peripheral
  		never getting unheld if chgetparams() failed.
  
  Sponsored by:	Spectra Logic
  Submitted by:	Po-Li Soong
  MFC After:	1 week

Modified:
  head/bin/chio/chio.c
  head/sys/cam/scsi/scsi_ch.c
  head/sys/cam/scsi/scsi_ch.h
  head/sys/sys/chio.h

Modified: head/bin/chio/chio.c
==============================================================================
--- head/bin/chio/chio.c	Fri Apr 19 19:45:00 2013	(r249657)
+++ head/bin/chio/chio.c	Fri Apr 19 20:03:51 2013	(r249658)
@@ -54,6 +54,8 @@ __FBSDID("$FreeBSD$");
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <langinfo.h>
+#include <locale.h>
 
 #include "defs.h"
 #include "pathnames.h"
@@ -81,6 +83,7 @@ static	int do_status(const char *, int, 
 static	int do_ielem(const char *, int, char **);
 static	int do_return(const char *, int, char **);
 static	int do_voltag(const char *, int, char **);
+static	void print_designator(const char *, u_int8_t, u_int8_t);
 
 #ifndef CHET_VT
 #define	CHET_VT		10			/* Completely Arbitrary */
@@ -723,6 +726,10 @@ do_status(const char *cname, int argc, c
 					putchar('?');
 				putchar('>');
 			}
+			if (ces->ces_designator_length > 0)
+				print_designator(ces->ces_designator,
+						 ces->ces_code_set,
+						 ces->ces_designator_length);
 			putchar('\n');
 		}
 
@@ -1177,3 +1184,66 @@ usage(void)
 		"arg1 arg2 [arg3 [...]]\n", getprogname());
 	exit(1);
 }
+
+#define	UTF8CODESET	"UTF-8"
+
+static void
+print_designator(const char *designator, u_int8_t code_set,
+    u_int8_t designator_length)
+{
+	printf(" serial number: <");
+	switch (code_set) {
+	case CES_CODE_SET_ASCII: {
+		/*
+		 * The driver insures that the string is always NUL terminated.
+		 */
+		printf("%s", designator);
+		break;
+	}
+	case CES_CODE_SET_UTF_8: {
+		char *cs_native;
+
+		setlocale(LC_ALL, "");
+		cs_native = nl_langinfo(CODESET);
+
+		/* See if we can natively print UTF-8 */
+		if (strcmp(cs_native, UTF8CODESET) == 0)
+			cs_native = NULL;
+
+		if (cs_native == NULL) {
+			/* We can natively print UTF-8, so use printf. */
+			printf("%s", designator);
+		} else {
+			int i;
+
+			/*
+			 * We can't natively print UTF-8.  We should
+			 * convert it to the terminal's codeset, but that
+			 * requires iconv(3) and FreeBSD doesn't have
+			 * iconv(3) in the base system yet.  So we use %XX
+			 * notation for non US-ASCII characters instead.
+			 */
+			for (i = 0; i < designator_length &&
+			    designator[i] != '\0'; i++) {
+				if ((unsigned char)designator[i] < 0x80)
+					printf("%c", designator[i]);
+				else
+					printf("%%%02x",
+					    (unsigned char)designator[i]);
+			}
+		}
+		break;
+	}
+	case CES_CODE_SET_BINARY: {
+		int i;
+
+		for (i = 0; i < designator_length; i++)
+			printf("%02X%s", designator[i],
+			    (i == designator_length - 1) ? "" : " ");
+		break;
+	}
+	default:
+		break;
+	}
+	printf(">");
+}

Modified: head/sys/cam/scsi/scsi_ch.c
==============================================================================
--- head/sys/cam/scsi/scsi_ch.c	Fri Apr 19 19:45:00 2013	(r249657)
+++ head/sys/cam/scsi/scsi_ch.c	Fri Apr 19 20:03:51 2013	(r249658)
@@ -194,12 +194,14 @@ static	int		chexchange(struct cam_periph
 static	int		chposition(struct cam_periph *periph,
 				   struct changer_position *cp);
 static	int		chgetelemstatus(struct cam_periph *periph,
+				int scsi_version, u_long cmd,
 				struct changer_element_status_request *csr);
 static	int		chsetvoltag(struct cam_periph *periph,
 				    struct changer_set_voltag_request *csvr);
 static	int		chielem(struct cam_periph *periph, 
 				unsigned int timeout);
 static	int		chgetparams(struct cam_periph *periph);
+static	int		chscsiversion(struct cam_periph *periph);
 
 static struct periph_driver chdriver =
 {
@@ -474,6 +476,7 @@ chopen(struct cdev *dev, int flags, int 
 	 * Load information about this changer device into the softc.
 	 */
 	if ((error = chgetparams(periph)) != 0) {
+		cam_periph_unhold(periph);
 		cam_periph_release_locked(periph);
 		cam_periph_unlock(periph);
 		return(error);
@@ -772,6 +775,7 @@ chioctl(struct cdev *dev, u_long cmd, ca
 	switch (cmd) {
 	case CHIOGPICKER:
 	case CHIOGPARAMS:
+	case OCHIOGSTATUS:
 	case CHIOGSTATUS:
 		break;
 
@@ -824,10 +828,26 @@ chioctl(struct cdev *dev, u_long cmd, ca
 		error = chielem(periph, *(unsigned int *)addr);
 		break;
 
+	case OCHIOGSTATUS:
+	{
+		error = chgetelemstatus(periph, SCSI_REV_2, cmd,
+		    (struct changer_element_status_request *)addr);
+		break;
+	}
+
 	case CHIOGSTATUS:
 	{
-		error = chgetelemstatus(periph,
-			       (struct changer_element_status_request *) addr);
+		int scsi_version;
+
+		scsi_version = chscsiversion(periph);
+		if (scsi_version >= SCSI_REV_0) {
+			error = chgetelemstatus(periph, scsi_version, cmd,
+			    (struct changer_element_status_request *)addr);
+	  	}
+		else { /* unable to determine the SCSI version */
+			cam_periph_unlock(periph);
+			return (ENXIO);
+		}
 		break;
 	}
 
@@ -1034,18 +1054,20 @@ copy_voltag(struct changer_voltag *uvolt
 }
 
 /*
- * Copy an an element status descriptor to a user-mode
+ * Copy an element status descriptor to a user-mode
  * changer_element_status structure.
  */
-
-static	void
+static void
 copy_element_status(struct ch_softc *softc,
 		    u_int16_t flags,
 		    struct read_element_status_descriptor *desc,
-		    struct changer_element_status *ces)
+		    struct changer_element_status *ces,
+		    int scsi_version)
 {
 	u_int16_t eaddr = scsi_2btoul(desc->eaddr);
 	u_int16_t et;
+	struct volume_tag *pvol_tag = NULL, *avol_tag = NULL;
+	struct read_element_status_device_id *devid = NULL;
 
 	ces->ces_int_addr = eaddr;
 	/* set up logical address in element status */
@@ -1076,7 +1098,7 @@ copy_element_status(struct ch_softc *sof
 			if ((softc->sc_firsts[et] <= eaddr)
 			    && ((softc->sc_firsts[et] + softc->sc_counts[et])
 				> eaddr)) {
-				ces->ces_source_addr = 
+				ces->ces_source_addr =
 					eaddr - softc->sc_firsts[et];
 				ces->ces_source_type = et;
 				ces->ces_flags |= CES_SOURCE_VALID;
@@ -1089,27 +1111,92 @@ copy_element_status(struct ch_softc *sof
 			       "address %ud to a valid element type\n",
 			       eaddr);
 	}
-			
 
+	/*
+	 * pvoltag and avoltag are common between SCSI-2 and later versions
+	 */
 	if (flags & READ_ELEMENT_STATUS_PVOLTAG)
-		copy_voltag(&(ces->ces_pvoltag), &(desc->pvoltag));
+		pvol_tag = &desc->voltag_devid.pvoltag;
 	if (flags & READ_ELEMENT_STATUS_AVOLTAG)
-		copy_voltag(&(ces->ces_avoltag), &(desc->avoltag));
-
-	if (desc->dt_scsi_flags & READ_ELEMENT_STATUS_DT_IDVALID) {
-		ces->ces_flags |= CES_SCSIID_VALID;
-		ces->ces_scsi_id = desc->dt_scsi_addr;
-	}
+		avol_tag = (flags & READ_ELEMENT_STATUS_PVOLTAG) ?
+		    &desc->voltag_devid.voltag[1] :&desc->voltag_devid.pvoltag;
+	/*
+	 * For SCSI-3 and later, element status can carry designator and
+	 * other information.
+	 */
+	if (scsi_version >= SCSI_REV_SPC) {
+		if ((flags & READ_ELEMENT_STATUS_PVOLTAG) ^
+		    (flags & READ_ELEMENT_STATUS_AVOLTAG))
+			devid = &desc->voltag_devid.pvol_and_devid.devid;
+		else if (!(flags & READ_ELEMENT_STATUS_PVOLTAG) &&
+			 !(flags & READ_ELEMENT_STATUS_AVOLTAG))
+			devid = &desc->voltag_devid.devid;
+		else /* Have both PVOLTAG and AVOLTAG */
+			devid = &desc->voltag_devid.vol_tags_and_devid.devid;
+	}
+
+	if (pvol_tag)
+		copy_voltag(&(ces->ces_pvoltag), pvol_tag);
+	if (avol_tag)
+		copy_voltag(&(ces->ces_pvoltag), avol_tag);
+	if (devid != NULL) {
+		if (devid->designator_length > 0) {
+			bcopy((void *)devid->designator,
+			      (void *)ces->ces_designator,
+			      devid->designator_length);
+			ces->ces_designator_length = devid->designator_length;
+			/*
+			 * Make sure we are always NUL terminated.  The
+			 * buffer should be sized for the maximum
+			 * designator length plus 1, but this will make sure
+			 * there is always a NUL at the end.  This won't
+			 * matter for the binary code set, since the user
+			 * will only pay attention to the length field.
+			 */
+			ces->ces_designator[
+			    MIN(sizeof(ces->ces_designator) - 1,
+			    devid->designator_length)]= '\0';
+		}
+		if (devid->piv_assoc_designator_type &
+		    READ_ELEMENT_STATUS_PIV_SET) {
+			ces->ces_flags |= CES_PIV;
+			ces->ces_protocol_id =
+			    READ_ELEMENT_STATUS_PROTOCOL_ID(
+			    devid->prot_code_set);
+		}
+		ces->ces_code_set =
+		    READ_ELEMENT_STATUS_CODE_SET(devid->prot_code_set);
+		ces->ces_assoc = READ_ELEMENT_STATUS_ASSOCIATION(
+		    devid->piv_assoc_designator_type);
+		ces->ces_designator_type = READ_ELEMENT_STATUS_DESIGNATOR_TYPE(
+		    devid->piv_assoc_designator_type);
+	} else if (scsi_version > SCSI_REV_2) {
+		/* SCSI-SPC and No devid, no designator */
+		ces->ces_designator_length = 0;
+		ces->ces_designator[0] = '\0';
+		ces->ces_protocol_id = CES_PROTOCOL_ID_FCP_4;
+	}
+
+	if (scsi_version <= SCSI_REV_2) {
+		if (desc->dt_or_obsolete.scsi_2.dt_scsi_flags &
+		    READ_ELEMENT_STATUS_DT_IDVALID) {
+			ces->ces_flags |= CES_SCSIID_VALID;
+			ces->ces_scsi_id =
+			    desc->dt_or_obsolete.scsi_2.dt_scsi_addr;
+		}
 
-	if (desc->dt_scsi_addr & READ_ELEMENT_STATUS_DT_LUVALID) {
-		ces->ces_flags |= CES_LUN_VALID;
-		ces->ces_scsi_lun = 
-			desc->dt_scsi_flags & READ_ELEMENT_STATUS_DT_LUNMASK;
+		if (desc->dt_or_obsolete.scsi_2.dt_scsi_addr &
+		    READ_ELEMENT_STATUS_DT_LUVALID) {
+			ces->ces_flags |= CES_LUN_VALID;
+			ces->ces_scsi_lun =
+			    desc->dt_or_obsolete.scsi_2.dt_scsi_flags &
+			    READ_ELEMENT_STATUS_DT_LUNMASK;
+		}
 	}
 }
 
 static int
-chgetelemstatus(struct cam_periph *periph, 
+chgetelemstatus(struct cam_periph *periph, int scsi_version, u_long cmd,
 		struct changer_element_status_request *cesr)
 {
 	struct read_element_status_header *st_hdr;
@@ -1155,6 +1242,8 @@ chgetelemstatus(struct cam_periph *perip
 				 /* tag_action */ MSG_SIMPLE_Q_TAG,
 				 /* voltag */ want_voltags,
 				 /* sea */ softc->sc_firsts[chet],
+				 /* dvcid */ 1,
+				 /* curdata */ 1,
 				 /* count */ 1,
 				 /* data_ptr */ data,
 				 /* dxfer_len */ 1024,
@@ -1177,7 +1266,6 @@ chgetelemstatus(struct cam_periph *perip
 	size = sizeof(struct read_element_status_header) +
 	       sizeof(struct read_element_status_page_header) +
 	       (desclen * cesr->cesr_element_count);
-
 	/*
 	 * Reallocate storage for descriptors and get them from the
 	 * device.
@@ -1193,12 +1281,14 @@ chgetelemstatus(struct cam_periph *perip
 				 /* voltag */ want_voltags,
 				 /* sea */ softc->sc_firsts[chet]
 				 + cesr->cesr_element_base,
+				 /* dvcid */ 1,
+				 /* curdata */ 1,
 				 /* count */ cesr->cesr_element_count,
 				 /* data_ptr */ data,
 				 /* dxfer_len */ size,
 				 /* sense_len */ SSD_FULL_SIZE,
 				 /* timeout */ CH_TIMEOUT_READ_ELEMENT_STATUS);
-	
+
 	error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ CAM_RETRY_SELTO,
 				  /*sense_flags*/ SF_RETRY_UA,
 				  softc->device_stats);
@@ -1231,18 +1321,41 @@ chgetelemstatus(struct cam_periph *perip
 	 * Set up the individual element status structures
 	 */
 	for (i = 0; i < avail; ++i) {
-		struct changer_element_status *ces = &(user_data[i]);
+		struct changer_element_status *ces;
 
-		copy_element_status(softc, pg_hdr->flags, desc, ces);
+		/*
+		 * In the changer_element_status structure, fields from
+		 * the beginning to the field of ces_scsi_lun are common
+		 * between SCSI-2 and SCSI-3, while all the rest are new
+		 * from SCSI-3. In order to maintain backward compatibility
+		 * of the chio command, the ces pointer, below, is computed
+		 * such that it lines up with the structure boundary
+		 * corresponding to the SCSI version.
+		 */
+		ces = cmd == OCHIOGSTATUS ?
+		    (struct changer_element_status *)
+		    ((unsigned char *)user_data + i *
+		     (offsetof(struct changer_element_status,ces_scsi_lun)+1)):
+		    &user_data[i];
+
+		copy_element_status(softc, pg_hdr->flags, desc,
+				    ces, scsi_version);
 
 		desc = (struct read_element_status_descriptor *)
-		       ((uintptr_t)desc + desclen);
+		       ((unsigned char *)desc + desclen);
 	}
 
 	/* Copy element status structures out to userspace. */
-	error = copyout(user_data,
-			cesr->cesr_element_status,
-			avail * sizeof(struct changer_element_status));
+	if (cmd == OCHIOGSTATUS)
+		error = copyout(user_data,
+				cesr->cesr_element_status,
+				avail* (offsetof(struct changer_element_status,
+				ces_scsi_lun) + 1));
+	else
+		error = copyout(user_data,
+				cesr->cesr_element_status,
+				avail * sizeof(struct changer_element_status));
+
 	cam_periph_lock(periph);
 
  done:
@@ -1549,6 +1662,39 @@ chgetparams(struct cam_periph *periph)
 	return(error);
 }
 
+static int
+chscsiversion(struct cam_periph *periph)
+{
+	struct scsi_inquiry_data *inq_data;
+	struct ccb_getdev *cgd;
+	int dev_scsi_version;
+	struct cam_sim *sim;
+
+	sim = xpt_path_sim(periph->path);
+	mtx_assert(sim->mtx, MA_OWNED);
+	if ((cgd = (struct ccb_getdev *)xpt_alloc_ccb_nowait()) == NULL)
+		return (-1);
+	/*
+	 * Get the device information.
+	 */
+	xpt_setup_ccb(&cgd->ccb_h,
+		      periph->path,
+		      CAM_PRIORITY_NORMAL);
+	cgd->ccb_h.func_code = XPT_GDEV_TYPE;
+	xpt_action((union ccb *)cgd);
+
+	if (cgd->ccb_h.status != CAM_REQ_CMP) {
+		xpt_free_ccb((union ccb *)cgd);
+		return -1;
+	}
+
+	inq_data = &cgd->inq_data;
+	dev_scsi_version = inq_data->version;
+	xpt_free_ccb((union ccb *)cgd);
+
+	return dev_scsi_version;
+}
+
 void
 scsi_move_medium(struct ccb_scsiio *csio, u_int32_t retries,
 		 void (*cbfcnp)(struct cam_periph *, union ccb *),
@@ -1654,6 +1800,7 @@ void
 scsi_read_element_status(struct ccb_scsiio *csio, u_int32_t retries,
 			 void (*cbfcnp)(struct cam_periph *, union ccb *),
 			 u_int8_t tag_action, int voltag, u_int32_t sea,
+			 int curdata, int dvcid,
 			 u_int32_t count, u_int8_t *data_ptr,
 			 u_int32_t dxfer_len, u_int8_t sense_len,
 			 u_int32_t timeout)
@@ -1668,6 +1815,10 @@ scsi_read_element_status(struct ccb_scsi
 	scsi_ulto2b(sea, scsi_cmd->sea);
 	scsi_ulto2b(count, scsi_cmd->count);
 	scsi_ulto3b(dxfer_len, scsi_cmd->len);
+	if (dvcid)
+		scsi_cmd->flags |= READ_ELEMENT_STATUS_DVCID;
+	if (curdata)
+		scsi_cmd->flags |= READ_ELEMENT_STATUS_CURDATA;
 
 	if (voltag)
 		scsi_cmd->byte2 |= READ_ELEMENT_STATUS_VOLTAG;

Modified: head/sys/cam/scsi/scsi_ch.h
==============================================================================
--- head/sys/cam/scsi/scsi_ch.h	Fri Apr 19 19:45:00 2013	(r249657)
+++ head/sys/cam/scsi/scsi_ch.h	Fri Apr 19 20:03:51 2013	(r249658)
@@ -136,11 +136,14 @@ struct scsi_position_to_element {
 struct scsi_read_element_status {
 	u_int8_t	opcode;
 	u_int8_t	byte2;
-#define READ_ELEMENT_STATUS_VOLTAG	0x10	/* report volume tag info */
+#define	READ_ELEMENT_STATUS_VOLTAG	0x10	/* report volume tag info */
 	/* ...next 4 bits are an element type code... */
 	u_int8_t	sea[2];	/* starting element address */
 	u_int8_t	count[2]; /* number of elements */
-	u_int8_t	reserved0;
+	u_int8_t	flags;
+#define	READ_ELEMENT_STATUS_DVCID	0x01 /* report device serial number */
+#define	READ_ELEMENT_STATUS_CURDATA	0x02 /* allow motion during command */
+
 	u_int8_t	len[3];	/* length of data buffer */
 	u_int8_t	reserved1;
 	u_int8_t	control;
@@ -149,7 +152,7 @@ struct scsi_read_element_status {
 struct scsi_request_volume_element_address {
 	u_int8_t	opcode;
 	u_int8_t	byte2;
-#define REQUEST_VOLUME_ELEMENT_ADDRESS_VOLTAG	0x10
+#define	REQUEST_VOLUME_ELEMENT_ADDRESS_VOLTAG	0x10
 	/* ...next 4 bits are an element type code... */
 	u_int8_t	eaddr[2];	/* element address */
 	u_int8_t	count[2];	/* number of elements */
@@ -182,8 +185,8 @@ struct read_element_status_header {
 struct read_element_status_page_header {
 	u_int8_t	type;	/* element type code; see type codes below */
 	u_int8_t	flags;
-#define READ_ELEMENT_STATUS_AVOLTAG	0x40
-#define READ_ELEMENT_STATUS_PVOLTAG	0x80
+#define	READ_ELEMENT_STATUS_AVOLTAG	0x40
+#define	READ_ELEMENT_STATUS_PVOLTAG	0x80
 	u_int8_t	edl[2];	/* element descriptor length */
 	u_int8_t	reserved;
 	u_int8_t	nbytes[3]; /* byte count of all descriptors */
@@ -199,50 +202,79 @@ struct volume_tag {
 	u_int8_t	vsn[2];		/* volume sequence number */
 };
 
+struct read_element_status_device_id {
+	u_int8_t	prot_code_set;
+#define	READ_ELEMENT_STATUS_CODE_SET(p) ((p) & 0x0F)
+#define	READ_ELEMENT_STATUS_PROTOCOL_ID(p) ((p) >> 4)
+
+	u_int8_t	piv_assoc_designator_type;
+#define	READ_ELEMENT_STATUS_PIV_SET 0x80
+#define	READ_ELEMENT_STATUS_ASSOCIATION(p) ((p) >> 4)
+#define	READ_ELEMENT_STATUS_DESIGNATOR_TYPE(p) ((p) & 0x0F)
+
+	u_int8_t	reserved2;
+	u_int8_t	designator_length;
+	u_int8_t	designator[256]; /* Allocate max length */
+};
+
 struct read_element_status_descriptor {
 	u_int8_t	eaddr[2];	/* element address */
 	u_int8_t	flags1;
 
-#define READ_ELEMENT_STATUS_FULL	0x01
-#define READ_ELEMENT_STATUS_IMPEXP	0x02
-#define READ_ELEMENT_STATUS_EXCEPT	0x04
-#define READ_ELEMENT_STATUS_ACCESS	0x08
-#define READ_ELEMENT_STATUS_EXENAB	0x10
-#define READ_ELEMENT_STATUS_INENAB	0x20
-
-#define READ_ELEMENT_STATUS_MT_MASK1	0x05
-#define READ_ELEMENT_STATUS_ST_MASK1	0x0c
-#define READ_ELEMENT_STATUS_IE_MASK1	0x3f
-#define READ_ELEMENT_STATUS_DT_MASK1	0x0c
+#define	READ_ELEMENT_STATUS_FULL	0x01
+#define	READ_ELEMENT_STATUS_IMPEXP	0x02
+#define	READ_ELEMENT_STATUS_EXCEPT	0x04
+#define	READ_ELEMENT_STATUS_ACCESS	0x08
+#define	READ_ELEMENT_STATUS_EXENAB	0x10
+#define	READ_ELEMENT_STATUS_INENAB	0x20
+
+#define	READ_ELEMENT_STATUS_MT_MASK1	0x05
+#define	READ_ELEMENT_STATUS_ST_MASK1	0x0c
+#define	READ_ELEMENT_STATUS_IE_MASK1	0x3f
+#define	READ_ELEMENT_STATUS_DT_MASK1	0x0c
 
 	u_int8_t	reserved0;
 	u_int8_t	sense_code;
 	u_int8_t	sense_qual;
 
-	/*
-	 * dt_scsi_flags and dt_scsi_addr are valid only on data transport
-	 * elements.  These bytes are undefined for all other element types.
-	 */
-	u_int8_t	dt_scsi_flags;
-
-#define READ_ELEMENT_STATUS_DT_LUNMASK	0x07
-#define READ_ELEMENT_STATUS_DT_LUVALID	0x10
-#define READ_ELEMENT_STATUS_DT_IDVALID	0x20
-#define READ_ELEMENT_STATUS_DT_NOTBUS	0x80
-
-	u_int8_t	dt_scsi_addr;
-
-	u_int8_t	reserved1;
+	union {
+		struct {
+			u_int8_t	dt_scsi_flags;
+
+#define	READ_ELEMENT_STATUS_DT_LUNMASK	0x07
+#define	READ_ELEMENT_STATUS_DT_LUVALID	0x10
+#define	READ_ELEMENT_STATUS_DT_IDVALID	0x20
+#define	READ_ELEMENT_STATUS_DT_NOTBUS	0x80
+
+			u_int8_t	dt_scsi_addr;
+			u_int8_t	reserved1;
+		} scsi_2;
+
+		/* reserved and obsolete (as of SCSI-3) fields */
+		u_int8_t	reserved_or_obsolete[3];
+	} dt_or_obsolete;
 
 	u_int8_t	flags2;
-#define READ_ELEMENT_STATUS_INVERT	0x40
-#define READ_ELEMENT_STATUS_SVALID	0x80
-	u_int8_t	ssea[2];	/* source storage element address */
+#define	READ_ELEMENT_STATUS_INVERT		0x40
+#define	READ_ELEMENT_STATUS_SVALID		0x80
+#define	READ_ELEMENT_STATUS_ED			0x80
+#define	READ_ELEMENT_STATUS_MEDIA_TYPE_MASK	0x07
 
-	struct volume_tag pvoltag;	/* omitted if PVOLTAG == 0 */
-	struct volume_tag avoltag;	/* omitted if AVOLTAG == 0 */
+	u_int8_t	ssea[2];	/* source storage element address */
 
-	/* Other data may follow */
+	union {
+		struct volume_tag			pvoltag;
+		struct volume_tag 			voltag[2];
+		struct read_element_status_device_id	devid;
+		struct {
+			struct volume_tag			pvoltag;
+			struct read_element_status_device_id	devid;
+		} pvol_and_devid;
+		struct {
+			struct volume_tag			voltag[2];
+			struct read_element_status_device_id	devid;
+		} vol_tags_and_devid;
+	} voltag_devid;
 };
 
 /* XXX add data returned by REQUEST VOLUME ELEMENT ADDRESS */
@@ -457,6 +489,7 @@ void scsi_position_to_element(struct ccb
 void scsi_read_element_status(struct ccb_scsiio *csio, u_int32_t retries,
 			      void (*cbfcnp)(struct cam_periph *, union ccb *),
 			      u_int8_t tag_action, int voltag, u_int32_t sea,
+			      int curdata, int dvcid,
 			      u_int32_t count, u_int8_t *data_ptr,
 			      u_int32_t dxfer_len, u_int8_t sense_len,
 			      u_int32_t timeout);

Modified: head/sys/sys/chio.h
==============================================================================
--- head/sys/sys/chio.h	Fri Apr 19 19:45:00 2013	(r249657)
+++ head/sys/sys/chio.h	Fri Apr 19 20:03:51 2013	(r249658)
@@ -152,7 +152,8 @@ typedef enum {
 	CES_INVERT	  = 0x040,	/* invert bit */
 	CES_SOURCE_VALID  = 0x080,	/* source address (ces_source) valid */
 	CES_SCSIID_VALID  = 0x100,	/* ces_scsi_id is valid */
-	CES_LUN_VALID	  = 0x200	/* ces_scsi_lun is valid */
+	CES_LUN_VALID	  = 0x200,	/* ces_scsi_lun is valid */
+	CES_PIV		  = 0x400	/* ces_protocol_id is valid */
 } ces_status_flags;
 
 struct changer_element_status {
@@ -181,6 +182,55 @@ struct changer_element_status {
 	changer_voltag_t	ces_avoltag;	  /* alternate volume tag */
 	u_int8_t		ces_scsi_id;	  /* SCSI id of element */
 	u_int8_t		ces_scsi_lun;	  /* SCSI lun of element */
+
+	/*
+	 * Data members for SMC3 and later versions
+	 */
+	u_int8_t		ces_medium_type;
+#define	CES_MEDIUM_TYPE_UNKNOWN		0	/* Medium type unspecified */
+#define	CES_MEDIUM_TYPE_DATA		1	/* Data medium */
+#define	CES_MEDIUM_TYPE_CLEANING	2	/* Cleaning medium */
+#define	CES_MEDIUM_TYPE_DIAGNOSTIC	3	/* Diagnostic medium */
+#define	CES_MEDIUM_TYPE_WORM		4	/* WORM medium */
+#define	CES_MEDIUM_TYPE_MICROCODE	5	/* Microcode image medium */
+
+	u_int8_t		ces_protocol_id;
+#define	CES_PROTOCOL_ID_FCP_4	0	/* Fiber channel */
+#define	CES_PROTOCOL_ID_SPI_5	1	/* Parallel SCSI */
+#define	CES_PROTOCOL_ID_SSA_S3P	2	/* SSA */
+#define	CES_PROTOCOL_ID_SBP_3	3	/* IEEE 1394 */
+#define	CES_PROTOCOL_ID_SRP	4	/* SCSI Remote DMA */
+#define	CES_PROTOCOL_ID_ISCSI	5	/* iSCSI */
+#define	CES_PROTOCOL_ID_SPL	6	/* SAS */
+#define	CES_PROTOCOL_ID_ADT_2	7	/* Automation/Drive Interface */
+#define	CES_PROTOCOL_ID_ACS_2	8	/* ATA */
+
+	u_int8_t		ces_assoc;
+#define	CES_ASSOC_LOGICAL_UNIT	0
+#define	CES_ASSOC_TARGET_PORT	1
+#define	CES_ASSOC_TARGET_DEVICE	2
+
+	u_int8_t		ces_designator_type;
+#define	CES_DESIGNATOR_TYPE_VENDOR_SPECIFIC	0
+#define	CES_DESIGNATOR_TYPE_T10_VENDOR_ID	1
+#define	CES_DESIGNATOR_TYPE_EUI_64		2
+#define	CES_DESIGNATOR_TYPE_NAA			3
+#define	CES_DESIGNATOR_TYPE_TARGET_PORT_ID	4
+#define	CES_DESIGNATOR_TYPE_TARGET_PORT_GRP	5
+#define	CES_DESIGNATOR_TYPE_LOGICAL_UNIT_GRP	6
+#define	CES_DESIGNATOR_TYPE_MD5_LOGICAL_UNIT_ID	7
+#define	CES_DESIGNATOR_TYPE_SCSI_NAME_STRING	8
+
+	u_int8_t		ces_code_set;
+#define	CES_CODE_SET_RESERVED	0
+#define	CES_CODE_SET_BINARY	1
+#define	CES_CODE_SET_ASCII	2
+#define	CES_CODE_SET_UTF_8	3
+
+	u_int8_t		ces_designator_length;
+
+#define	CES_MAX_DESIGNATOR_LENGTH (1 << 8)
+	u_int8_t		ces_designator[CES_MAX_DESIGNATOR_LENGTH + 1];
 };
 
 struct changer_element_status_request {
@@ -189,7 +239,7 @@ struct changer_element_status_request {
 	u_int16_t			cesr_element_count;
 
 	u_int16_t			cesr_flags;
-#define CESR_VOLTAGS	0x01
+#define	CESR_VOLTAGS	0x01
 
 	struct changer_element_status	*cesr_element_status;
 };
@@ -200,28 +250,29 @@ struct changer_set_voltag_request {
 	u_int16_t		csvr_addr;
 
 	u_int16_t		csvr_flags;
-#define CSVR_MODE_MASK		0x0f	/* mode mask, acceptable modes below: */
+#define	CSVR_MODE_MASK		0x0f	/* mode mask, acceptable modes below: */
 #define	CSVR_MODE_SET		0x00	/* set volume tag if not set */
-#define CSVR_MODE_REPLACE	0x01	/* unconditionally replace volume tag */
-#define CSVR_MODE_CLEAR		0x02	/* clear volume tag */
+#define	CSVR_MODE_REPLACE	0x01	/* unconditionally replace volume tag */
+#define	CSVR_MODE_CLEAR		0x02	/* clear volume tag */
 
-#define CSVR_ALTERNATE		0x10	/* set to work with alternate voltag */
+#define	CSVR_ALTERNATE		0x10	/* set to work with alternate voltag */
 
 	changer_voltag_t     	csvr_voltag;
 };
 
 
-#define CESTATUS_BITS	\
+#define	CESTATUS_BITS	\
 	"\20\6INEAB\5EXENAB\4ACCESS\3EXCEPT\2IMPEXP\1FULL"
 
-#define CHIOMOVE	_IOW('c', 0x01, struct changer_move)
-#define CHIOEXCHANGE	_IOW('c', 0x02, struct changer_exchange)
-#define CHIOPOSITION	_IOW('c', 0x03, struct changer_position)
-#define CHIOGPICKER	_IOR('c', 0x04, int)
-#define CHIOSPICKER	_IOW('c', 0x05, int)
-#define CHIOGPARAMS	_IOR('c', 0x06, struct changer_params)
-#define CHIOIELEM	_IOW('c', 0x07, u_int32_t)
-#define CHIOGSTATUS	_IOW('c', 0x08, struct changer_element_status_request)
-#define CHIOSETVOLTAG	_IOW('c', 0x09, struct changer_set_voltag_request)
+#define	CHIOMOVE	_IOW('c', 0x01, struct changer_move)
+#define	CHIOEXCHANGE	_IOW('c', 0x02, struct changer_exchange)
+#define	CHIOPOSITION	_IOW('c', 0x03, struct changer_position)
+#define	CHIOGPICKER	_IOR('c', 0x04, int)
+#define	CHIOSPICKER	_IOW('c', 0x05, int)
+#define	CHIOGPARAMS	_IOR('c', 0x06, struct changer_params)
+#define	CHIOIELEM	_IOW('c', 0x07, u_int32_t)
+#define	OCHIOGSTATUS	_IOW('c', 0x08, struct changer_element_status_request)
+#define	CHIOSETVOLTAG	_IOW('c', 0x09, struct changer_set_voltag_request)
+#define	CHIOGSTATUS	_IOW('c', 0x0A, struct changer_element_status_request)
 
 #endif /* !_SYS_CHIO_H_ */


More information about the svn-src-all mailing list