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_ */
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to