Author: mav
Date: Tue Jul 30 20:58:56 2019
New Revision: 350457
URL: https://svnweb.freebsd.org/changeset/base/350457

Log:
  Make `camcontrol modepage` to use 10 byte commands.
  
  While old devices may not support 10 byte MODE SENSE/MODE SELECT commands,
  new ones may not be able to report all mode pages with 6 byte commands.
  
  This patch makes camcontrol by default start with 10 byte commands and
  fall back to 6 byte on ILLEGAL REQUEST error, or 6 byte can be forced.
  
  MFC after:    2 weeks
  Sponsored by: iXsystems, Inc.

Modified:
  head/sbin/camcontrol/camcontrol.8
  head/sbin/camcontrol/camcontrol.c
  head/sbin/camcontrol/camcontrol.h
  head/sbin/camcontrol/modeedit.c

Modified: head/sbin/camcontrol/camcontrol.8
==============================================================================
--- head/sbin/camcontrol/camcontrol.8   Tue Jul 30 19:55:55 2019        
(r350456)
+++ head/sbin/camcontrol/camcontrol.8   Tue Jul 30 20:58:56 2019        
(r350457)
@@ -27,7 +27,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd July 25, 2019
+.Dd July 30, 2019
 .Dt CAMCONTROL 8
 .Os
 .Sh NAME
@@ -122,6 +122,7 @@
 .Ic modepage
 .Op device id
 .Op generic args
+.Op Fl 6
 .Aq Fl m Ar page[,subpage] | Fl l
 .Op Fl P Ar pgctl
 .Op Fl b | Fl e
@@ -723,6 +724,13 @@ The
 .Ic modepage
 command takes several arguments:
 .Bl -tag -width 12n
+.It Fl 6
+Use 6 byte MODE commands instead of default 10 byte.
+Old devices may not support 10 byte MODE commands, while new devices may
+not be able to report all mode pages with 6 byte commands.
+If not specified,
+.Nm
+starts with 10 byte commands and falls back to 6 byte on error.
 .It Fl d
 Disable block descriptors for mode sense.
 .It Fl b

Modified: head/sbin/camcontrol/camcontrol.c
==============================================================================
--- head/sbin/camcontrol/camcontrol.c   Tue Jul 30 19:55:55 2019        
(r350456)
+++ head/sbin/camcontrol/camcontrol.c   Tue Jul 30 20:58:56 2019        
(r350457)
@@ -221,7 +221,7 @@ static struct camcontrol_opts option_table[] = {
        {"devlist", CAM_CMD_DEVTREE, CAM_ARG_NONE, "-b"},
        {"devtype", CAM_CMD_DEVTYPE, CAM_ARG_NONE, ""},
        {"periphlist", CAM_CMD_DEVLIST, CAM_ARG_NONE, NULL},
-       {"modepage", CAM_CMD_MODE_PAGE, CAM_ARG_NONE, "bdelm:P:"},
+       {"modepage", CAM_CMD_MODE_PAGE, CAM_ARG_NONE, "6bdelm:P:"},
        {"tags", CAM_CMD_TAG, CAM_ARG_NONE, "N:q"},
        {"negotiate", CAM_CMD_RATE, CAM_ARG_NONE, negotiate_opts},
        {"rate", CAM_CMD_RATE, CAM_ARG_NONE, negotiate_opts},
@@ -4586,18 +4586,25 @@ reassignblocks(struct cam_device *device, u_int32_t *b
 #endif
 
 void
-mode_sense(struct cam_device *device, int dbd, int pc, int page, int subpage,
-          int task_attr, int retry_count, int timeout, u_int8_t *data,
-          int datalen)
+mode_sense(struct cam_device *device, int *cdb_len, int dbd, int pc, int page,
+    int subpage, int task_attr, int retry_count, int timeout, u_int8_t *data,
+    int datalen)
 {
        union ccb *ccb;
-       int retval;
+       int error_code, sense_key, asc, ascq;
 
        ccb = cam_getccb(device);
-
        if (ccb == NULL)
                errx(1, "mode_sense: couldn't allocate CCB");
 
+retry:
+       /*
+        * MODE SENSE(6) can't handle more then 255 bytes.  If there are more,
+        * device must return error, so we should not get trucated data.
+        */
+       if (*cdb_len == 6 && datalen > 255)
+               datalen = 255;
+
        CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->csio);
 
        scsi_mode_sense_subpage(&ccb->csio,
@@ -4610,36 +4617,47 @@ mode_sense(struct cam_device *device, int dbd, int pc,
                        /* subpage */ subpage,
                        /* param_buf */ data,
                        /* param_len */ datalen,
-                       /* minimum_cmd_size */ 0,
+                       /* minimum_cmd_size */ *cdb_len,
                        /* sense_len */ SSD_FULL_SIZE,
                        /* timeout */ timeout ? timeout : 5000);
 
+       /* Record what CDB size the above function really set. */
+       *cdb_len = ccb->csio.cdb_len;
+
        if (arglist & CAM_ARG_ERR_RECOVER)
                ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
 
        /* Disable freezing the device queue */
        ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
 
-       if (((retval = cam_send_ccb(device, ccb)) < 0)
-        || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
+       if (cam_send_ccb(device, ccb) < 0)
+               err(1, "error sending mode sense command");
+
+       /* In case of ILLEGEL REQUEST try to fall back to 6-byte command. */
+       if (*cdb_len != 6 &&
+           ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INVALID ||
+            (scsi_extract_sense_ccb(ccb, &error_code, &sense_key, &asc, &ascq)
+             && sense_key == SSD_KEY_ILLEGAL_REQUEST))) {
+               *cdb_len = 6;
+               goto retry;
+       }
+
+       if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
                if (arglist & CAM_ARG_VERBOSE) {
                        cam_error_print(device, ccb, CAM_ESF_ALL,
                                        CAM_EPF_ALL, stderr);
                }
                cam_freeccb(ccb);
                cam_close_device(device);
-               if (retval < 0)
-                       err(1, "error sending mode sense command");
-               else
-                       errx(1, "error sending mode sense command");
+               errx(1, "mode sense command returned error");
        }
 
        cam_freeccb(ccb);
 }
 
 void
-mode_select(struct cam_device *device, int save_pages, int task_attr,
-           int retry_count, int timeout, u_int8_t *data, int datalen)
+mode_select(struct cam_device *device, int cdb_len, int save_pages,
+    int task_attr, int retry_count, int timeout, u_int8_t *data, int datalen)
 {
        union ccb *ccb;
        int retval;
@@ -4651,7 +4669,7 @@ mode_select(struct cam_device *device, int save_pages,
 
        CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->csio);
 
-       scsi_mode_select(&ccb->csio,
+       scsi_mode_select_len(&ccb->csio,
                         /* retries */ retry_count,
                         /* cbfcnp */ NULL,
                         /* tag_action */ task_attr,
@@ -4659,6 +4677,7 @@ mode_select(struct cam_device *device, int save_pages,
                         /* save_pages */ save_pages,
                         /* param_buf */ data,
                         /* param_len */ datalen,
+                        /* minimum_cmd_size */ cdb_len,
                         /* sense_len */ SSD_FULL_SIZE,
                         /* timeout */ timeout ? timeout : 5000);
 
@@ -4693,10 +4712,13 @@ modepage(struct cam_device *device, int argc, char **a
 {
        char *str_subpage;
        int c, page = -1, subpage = -1, pc = 0;
-       int binary = 0, dbd = 0, edit = 0, list = 0;
+       int binary = 0, cdb_len = 10, dbd = 0, edit = 0, list = 0;
 
        while ((c = getopt(argc, argv, combinedopt)) != -1) {
                switch(c) {
+               case '6':
+                       cdb_len = 6;
+                       break;
                case 'b':
                        binary = 1;
                        break;
@@ -4736,11 +4758,11 @@ modepage(struct cam_device *device, int argc, char **a
                errx(1, "you must specify a mode page!");
 
        if (list != 0) {
-               mode_list(device, dbd, pc, list > 1, task_attr, retry_count,
-                         timeout);
+               mode_list(device, cdb_len, dbd, pc, list > 1, task_attr,
+                   retry_count, timeout);
        } else {
-               mode_edit(device, dbd, pc, page, subpage, edit, binary,
-                   task_attr, retry_count, timeout);
+               mode_edit(device, cdb_len, dbd, pc, page, subpage, edit,
+                   binary, task_attr, retry_count, timeout);
        }
 }
 

Modified: head/sbin/camcontrol/camcontrol.h
==============================================================================
--- head/sbin/camcontrol/camcontrol.h   Tue Jul 30 19:55:55 2019        
(r350456)
+++ head/sbin/camcontrol/camcontrol.h   Tue Jul 30 20:58:56 2019        
(r350457)
@@ -88,16 +88,17 @@ int epc(struct cam_device *device, int argc, char **ar
 int timestamp(struct cam_device *device, int argc, char **argv,
              char *combinedopt, int task_attr, int retry_count, int timeout,
              int verbosemode);
-void mode_sense(struct cam_device *device, int dbd, int pc, int page,
-               int subpage, int task_attr, int retry_count, int timeout,
-               uint8_t *data, int datalen);
-void mode_select(struct cam_device *device, int save_pages, int task_attr,
-                int retry_count, int timeout, u_int8_t *data, int datalen);
-void mode_edit(struct cam_device *device, int dbd, int pc, int page,
-              int subpage, int edit, int binary, int task_attr,
+void mode_sense(struct cam_device *device, int *cdb_len, int dbd, int pc,
+               int page, int subpage, int task_attr, int retry_count,
+               int timeout, uint8_t *data, int datalen);
+void mode_select(struct cam_device *device, int cdb_len, int save_pages,
+                int task_attr, int retry_count, int timeout, u_int8_t *data,
+                int datalen);
+void mode_edit(struct cam_device *device, int cdb_len, int dbd, int pc,
+              int page, int subpage, int edit, int binary, int task_attr,
               int retry_count, int timeout);
-void mode_list(struct cam_device *device, int dbd, int pc, int subpages,
-              int task_attr, int retry_count, int timeout);
+void mode_list(struct cam_device *device, int cdb_len, int dbd, int pc,
+              int subpages, int task_attr, int retry_count, int timeout);
 int scsidoinquiry(struct cam_device *device, int argc, char **argv,
                  char *combinedopt, int task_attr, int retry_count,
                  int timeout);

Modified: head/sbin/camcontrol/modeedit.c
==============================================================================
--- head/sbin/camcontrol/modeedit.c     Tue Jul 30 19:55:55 2019        
(r350456)
+++ head/sbin/camcontrol/modeedit.c     Tue Jul 30 20:58:56 2019        
(r350457)
@@ -60,15 +60,9 @@ __FBSDID("$FreeBSD$");
 #define        PAGENAME_START          '"'     /* Page name delimiter. */
 #define        PAGENAME_END            '"'     /* Page name delimiter. */
 #define        PAGEENTRY_END           ';'     /* Page entry terminator 
(optional). */
-#define        MAX_COMMAND_SIZE        255     /* Mode/Log sense data buffer 
size. */
+#define        MAX_DATA_SIZE           4096    /* Mode/Log sense data buffer 
size. */
 #define PAGE_CTRL_SHIFT                6       /* Bit offset to page control 
field. */
 
-
-/* Macros for working with mode pages. */
-#define        MODE_PAGE_HEADER(mh)                                            
\
-       (struct scsi_mode_page_header *)find_mode_page_6(mh)
-
-
 struct editentry {
        STAILQ_ENTRY(editentry) link;
        char    *name;
@@ -106,13 +100,12 @@ static int                 editentry_save(void *hook, 
char *name);
 static struct editentry        *editentry_lookup(char *name);
 static int              editentry_set(char *name, char *newvalue,
                                       int editonly);
-static void             editlist_populate(struct cam_device *device, int dbd,
-                                          int pc, int page, int subpage,
-                                          int task_attr, int retries,
-                                          int timeout);
-static void             editlist_save(struct cam_device *device, int dbd,
-                                      int pc, int page, int subpage,
-                                      int task_attr, int retries, int timeout);
+static void             editlist_populate(struct cam_device *device,
+                           int cdb_len, int dbd, int pc, int page, int subpage,
+                           int task_attr, int retries, int timeout);
+static void             editlist_save(struct cam_device *device, int cdb_len,
+                           int dbd, int pc, int page, int subpage,
+                           int task_attr, int retries, int timeout);
 static void             nameentry_create(int page, int subpage, char *name);
 static struct pagename *nameentry_lookup(int page, int subpage);
 static int              load_format(const char *pagedb_path, int lpage,
@@ -120,9 +113,9 @@ static int           load_format(const char *pagedb_path, 
int 
 static int              modepage_write(FILE *file, int editonly);
 static int              modepage_read(FILE *file);
 static void             modepage_edit(void);
-static void             modepage_dump(struct cam_device *device, int dbd,
-                           int pc, int page, int subpage, int task_attr,
-                           int retries, int timeout);
+static void             modepage_dump(struct cam_device *device, int cdb_len,
+                           int dbd, int pc, int page, int subpage,
+                           int task_attr, int retries, int timeout);
 static void             cleanup_editfile(void);
 
 
@@ -552,12 +545,11 @@ load_format(const char *pagedb_path, int lpage, int ls
 }
 
 static void
-editlist_populate(struct cam_device *device, int dbd, int pc, int page,
-    int subpage, int task_attr, int retries, int timeout)
+editlist_populate(struct cam_device *device, int cdb_len, int dbd, int pc,
+    int page, int subpage, int task_attr, int retries, int timeout)
 {
-       u_int8_t data[MAX_COMMAND_SIZE];/* Buffer to hold sense data. */
+       u_int8_t data[MAX_DATA_SIZE];/* Buffer to hold sense data. */
        u_int8_t *mode_pars;            /* Pointer to modepage params. */
-       struct scsi_mode_header_6 *mh;  /* Location of mode header. */
        struct scsi_mode_page_header *mph;
        struct scsi_mode_page_header_sp *mphsp;
        size_t len;
@@ -565,11 +557,18 @@ editlist_populate(struct cam_device *device, int dbd, 
        STAILQ_INIT(&editlist);
 
        /* Fetch changeable values; use to build initial editlist. */
-       mode_sense(device, dbd, 1, page, subpage, task_attr, retries, timeout,
-                  data, sizeof(data));
+       mode_sense(device, &cdb_len, dbd, 1, page, subpage, task_attr, retries,
+                  timeout, data, sizeof(data));
 
-       mh = (struct scsi_mode_header_6 *)data;
-       mph = MODE_PAGE_HEADER(mh);
+       if (cdb_len == 6) {
+               struct scsi_mode_header_6 *mh =
+                   (struct scsi_mode_header_6 *)data;
+               mph = find_mode_page_6(mh);
+       } else {
+               struct scsi_mode_header_10 *mh =
+                   (struct scsi_mode_header_10 *)data;
+               mph = find_mode_page_10(mh);
+       }
        if ((mph->page_code & SMPH_SPF) == 0) {
                mode_pars = (uint8_t *)(mph + 1);
                len = mph->page_length;
@@ -584,40 +583,80 @@ editlist_populate(struct cam_device *device, int dbd, 
        buff_decode_visit(mode_pars, len, format, editentry_create, 0);
 
        /* Fetch the current/saved values; use to set editentry values. */
-       mode_sense(device, dbd, pc, page, subpage, task_attr, retries, timeout,
-           data, sizeof(data));
+       mode_sense(device, &cdb_len, dbd, pc, page, subpage, task_attr,
+           retries, timeout, data, sizeof(data));
        buff_decode_visit(mode_pars, len, format, editentry_update, 0);
 }
 
 static void
-editlist_save(struct cam_device *device, int dbd, int pc, int page,
-    int subpage, int task_attr, int retries, int timeout)
+editlist_save(struct cam_device *device, int cdb_len, int dbd, int pc,
+    int page, int subpage, int task_attr, int retries, int timeout)
 {
-       u_int8_t data[MAX_COMMAND_SIZE];/* Buffer to hold sense data. */
+       u_int8_t data[MAX_DATA_SIZE];/* Buffer to hold sense data. */
        u_int8_t *mode_pars;            /* Pointer to modepage params. */
-       struct scsi_mode_header_6 *mh;  /* Location of mode header. */
        struct scsi_mode_page_header *mph;
        struct scsi_mode_page_header_sp *mphsp;
-       size_t len, hlen;
+       size_t len, hlen, mphlen;
 
        /* Make sure that something changed before continuing. */
        if (! editlist_changed)
                return;
 
        /* Preload the CDB buffer with the current mode page data. */
-       mode_sense(device, dbd, pc, page, subpage, task_attr, retries, timeout,
-           data, sizeof(data));
+       mode_sense(device, &cdb_len, dbd, pc, page, subpage, task_attr,
+           retries, timeout, data, sizeof(data));
 
        /* Initial headers & offsets. */
-       mh = (struct scsi_mode_header_6 *)data;
-       mph = MODE_PAGE_HEADER(mh);
+       /*
+        * Tape drives include write protect (WP), Buffered Mode and Speed
+        * settings in the device-specific parameter.  Clearing this
+        * parameter on a mode select can have the effect of turning off
+        * write protect or buffered mode, or changing the speed setting of
+        * the tape drive.
+        *
+        * Disks report DPO/FUA support via the device specific parameter
+        * for MODE SENSE, but the bit is reserved for MODE SELECT.  So we
+        * clear this for disks (and other non-tape devices) to avoid
+        * potential errors from the target device.
+        */
+       if (cdb_len == 6) {
+               struct scsi_mode_header_6 *mh =
+                   (struct scsi_mode_header_6 *)data;
+               hlen = sizeof(*mh);
+               /* Eliminate block descriptors. */
+               if (mh->blk_desc_len > 0) {
+                       bcopy(find_mode_page_6(mh), mh + 1,
+                           mh->data_length + 1 - hlen -
+                           mh->blk_desc_len);
+                       mh->blk_desc_len = 0;
+               }
+               mh->data_length = 0;    /* Reserved for MODE SELECT command. */
+               if (device->pd_type != T_SEQUENTIAL)
+                       mh->dev_spec = 0;       /* See comment above */
+               mph = find_mode_page_6(mh);
+       } else {
+               struct scsi_mode_header_10 *mh =
+                   (struct scsi_mode_header_10 *)data;
+               hlen = sizeof(*mh);
+               /* Eliminate block descriptors. */
+               if (scsi_2btoul(mh->blk_desc_len) > 0) {
+                       bcopy(find_mode_page_10(mh), mh + 1,
+                           scsi_2btoul(mh->data_length) + 1 - hlen -
+                           scsi_2btoul(mh->blk_desc_len));
+                       scsi_ulto2b(0, mh->blk_desc_len);
+               }
+               scsi_ulto2b(0, mh->data_length); /* Reserved for MODE SELECT. */
+               if (device->pd_type != T_SEQUENTIAL)
+                       mh->dev_spec = 0;       /* See comment above */
+               mph = find_mode_page_10(mh);
+       }
        if ((mph->page_code & SMPH_SPF) == 0) {
-               hlen = sizeof(*mph);
+               mphlen = sizeof(*mph);
                mode_pars = (uint8_t *)(mph + 1);
                len = mph->page_length;
        } else {
                mphsp = (struct scsi_mode_page_header_sp *)mph;
-               hlen = sizeof(*mphsp);
+               mphlen = sizeof(*mphsp);
                mode_pars = (uint8_t *)(mphsp + 1);
                len = scsi_2btoul(mphsp->page_length);
        }
@@ -626,27 +665,6 @@ editlist_save(struct cam_device *device, int dbd, int 
        /* Encode the value data to be passed back to the device. */
        buff_encode_visit(mode_pars, len, format, editentry_save, 0);
 
-       /* Eliminate block descriptors. */
-       bcopy(mph, mh + 1, hlen + len);
-
-       /* Recalculate headers & offsets. */
-       mh->data_length = 0;            /* Reserved for MODE SELECT command. */
-       mh->blk_desc_len = 0;           /* No block descriptors. */
-       /*
-        * Tape drives include write protect (WP), Buffered Mode and Speed
-        * settings in the device-specific parameter.  Clearing this
-        * parameter on a mode select can have the effect of turning off
-        * write protect or buffered mode, or changing the speed setting of
-        * the tape drive.
-        *
-        * Disks report DPO/FUA support via the device specific parameter
-        * for MODE SENSE, but the bit is reserved for MODE SELECT.  So we
-        * clear this for disks (and other non-tape devices) to avoid
-        * potential errors from the target device.
-        */
-       if (device->pd_type != T_SEQUENTIAL)
-               mh->dev_spec = 0;
-       mph = MODE_PAGE_HEADER(mh);
        mph->page_code &= ~SMPH_PS;     /* Reserved for MODE SELECT command. */
 
        /*
@@ -654,9 +672,8 @@ editlist_save(struct cam_device *device, int dbd, int 
         * page 3 (saved values) then request the changes be permanently
         * recorded.
         */
-       mode_select(device, (pc << PAGE_CTRL_SHIFT == SMS_PAGE_CTRL_SAVED),
-           task_attr, retries, timeout, (u_int8_t *)mh,
-           sizeof(*mh) + hlen + len);
+       mode_select(device, cdb_len, (pc << PAGE_CTRL_SHIFT == 
SMS_PAGE_CTRL_SAVED),
+           task_attr, retries, timeout, data, hlen + mphlen + len);
 }
 
 static int
@@ -825,21 +842,27 @@ modepage_edit(void)
 }
 
 static void
-modepage_dump(struct cam_device *device, int dbd, int pc, int page, int 
subpage,
-             int task_attr, int retries, int timeout)
+modepage_dump(struct cam_device *device, int cdb_len, int dbd, int pc,
+             int page, int subpage, int task_attr, int retries, int timeout)
 {
-       u_int8_t data[MAX_COMMAND_SIZE];/* Buffer to hold sense data. */
+       u_int8_t data[MAX_DATA_SIZE];/* Buffer to hold sense data. */
        u_int8_t *mode_pars;            /* Pointer to modepage params. */
-       struct scsi_mode_header_6 *mh;  /* Location of mode header. */
        struct scsi_mode_page_header *mph;
        struct scsi_mode_page_header_sp *mphsp;
        size_t indx, len;
 
-       mode_sense(device, dbd, pc, page, subpage, task_attr, retries, timeout,
-           data, sizeof(data));
+       mode_sense(device, &cdb_len, dbd, pc, page, subpage, task_attr,
+           retries, timeout, data, sizeof(data));
 
-       mh = (struct scsi_mode_header_6 *)data;
-       mph = MODE_PAGE_HEADER(mh);
+       if (cdb_len == 6) {
+               struct scsi_mode_header_6 *mh =
+                   (struct scsi_mode_header_6 *)data;
+               mph = find_mode_page_6(mh);
+       } else {
+               struct scsi_mode_header_10 *mh =
+                   (struct scsi_mode_header_10 *)data;
+               mph = find_mode_page_10(mh);
+       }
        if ((mph->page_code & SMPH_SPF) == 0) {
                mode_pars = (uint8_t *)(mph + 1);
                len = mph->page_length;
@@ -869,8 +892,9 @@ cleanup_editfile(void)
 }
 
 void
-mode_edit(struct cam_device *device, int dbd, int pc, int page, int subpage,
-         int edit, int binary, int task_attr, int retry_count, int timeout)
+mode_edit(struct cam_device *device, int cdb_len, int dbd, int pc, int page,
+         int subpage, int edit, int binary, int task_attr, int retry_count,
+         int timeout)
 {
        const char *pagedb_path;        /* Path to modepage database. */
 
@@ -901,8 +925,8 @@ mode_edit(struct cam_device *device, int dbd, int pc, 
                                exit(EX_OSFILE);
                }
 
-               editlist_populate(device, dbd, pc, page, subpage, task_attr,
-                   retry_count, timeout);
+               editlist_populate(device, cdb_len, dbd, pc, page, subpage,
+                   task_attr, retry_count, timeout);
        }
 
        if (edit) {
@@ -911,12 +935,12 @@ mode_edit(struct cam_device *device, int dbd, int pc, 
                        errx(EX_USAGE, "it only makes sense to edit page 0 "
                            "(current) or page 3 (saved values)");
                modepage_edit();
-               editlist_save(device, dbd, pc, page, subpage, task_attr,
-                   retry_count, timeout);
+               editlist_save(device, cdb_len, dbd, pc, page, subpage,
+                   task_attr, retry_count, timeout);
        } else if (binary || STAILQ_EMPTY(&editlist)) {
                /* Display without formatting information. */
-               modepage_dump(device, dbd, pc, page, subpage, task_attr, 
-                   retry_count, timeout);
+               modepage_dump(device, cdb_len, dbd, pc, page, subpage,
+                   task_attr, retry_count, timeout);
        } else {
                /* Display with format. */
                modepage_write(stdout, 0);
@@ -924,16 +948,15 @@ mode_edit(struct cam_device *device, int dbd, int pc, 
 }
 
 void
-mode_list(struct cam_device *device, int dbd, int pc, int subpages,
+mode_list(struct cam_device *device, int cdb_len, int dbd, int pc, int 
subpages,
          int task_attr, int retry_count, int timeout)
 {
-       u_int8_t data[MAX_COMMAND_SIZE];/* Buffer to hold sense data. */
-       struct scsi_mode_header_6 *mh;  /* Location of mode header. */
+       u_int8_t data[MAX_DATA_SIZE];/* Buffer to hold sense data. */
        struct scsi_mode_page_header *mph;
        struct scsi_mode_page_header_sp *mphsp;
        struct pagename *nameentry;
        const char *pagedb_path;
-       int len, page, subpage;
+       int len, off, page, subpage;
 
        if ((pagedb_path = getenv("SCSI_MODES")) == NULL)
                pagedb_path = DEFAULT_SCSI_MODE_DB;
@@ -944,26 +967,36 @@ mode_list(struct cam_device *device, int dbd, int pc, 
        }
 
        /* Build the list of all mode pages by querying the "all pages" page. */
-       mode_sense(device, dbd, pc, SMS_ALL_PAGES_PAGE,
+       mode_sense(device, &cdb_len, dbd, pc, SMS_ALL_PAGES_PAGE,
            subpages ? SMS_SUBPAGE_ALL : 0,
            task_attr, retry_count, timeout, data, sizeof(data));
 
-       mh = (struct scsi_mode_header_6 *)data;
-       len = sizeof(*mh) + mh->blk_desc_len;   /* Skip block descriptors. */
+       /* Skip block descriptors. */
+       if (cdb_len == 6) {
+               struct scsi_mode_header_6 *mh =
+                   (struct scsi_mode_header_6 *)data;
+               len = mh->data_length;
+               off = sizeof(*mh) + mh->blk_desc_len;
+       } else {
+               struct scsi_mode_header_10 *mh =
+                   (struct scsi_mode_header_10 *)data;
+               len = scsi_2btoul(mh->data_length);
+               off = sizeof(*mh) + scsi_2btoul(mh->blk_desc_len);
+       }
        /* Iterate through the pages in the reply. */
-       while (len < mh->data_length) {
+       while (off < len) {
                /* Locate the next mode page header. */
-               mph = (struct scsi_mode_page_header *)((intptr_t)mh + len);
+               mph = (struct scsi_mode_page_header *)(data + off);
 
                if ((mph->page_code & SMPH_SPF) == 0) {
                        page = mph->page_code & SMS_PAGE_CODE;
                        subpage = 0;
-                       len += sizeof(*mph) + mph->page_length;
+                       off += sizeof(*mph) + mph->page_length;
                } else {
                        mphsp = (struct scsi_mode_page_header_sp *)mph;
                        page = mphsp->page_code & SMS_PAGE_CODE;
                        subpage = mphsp->subpage;
-                       len += sizeof(*mphsp) + scsi_2btoul(mphsp->page_length);
+                       off += sizeof(*mphsp) + scsi_2btoul(mphsp->page_length);
                }
 
                nameentry = nameentry_lookup(page, subpage);
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to