svn commit: r351581 - stable/11/sbin/camcontrol

Alexander Motin mav at FreeBSD.org
Wed Aug 28 20:22:15 UTC 2019


Author: mav
Date: Wed Aug 28 20:22:14 2019
New Revision: 351581
URL: https://svnweb.freebsd.org/changeset/base/351581

Log:
  MFC r350457: 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.

Modified:
  stable/11/sbin/camcontrol/camcontrol.8
  stable/11/sbin/camcontrol/camcontrol.c
  stable/11/sbin/camcontrol/camcontrol.h
  stable/11/sbin/camcontrol/modeedit.c
Directory Properties:
  stable/11/   (props changed)

Modified: stable/11/sbin/camcontrol/camcontrol.8
==============================================================================
--- stable/11/sbin/camcontrol/camcontrol.8	Wed Aug 28 20:21:34 2019	(r351580)
+++ stable/11/sbin/camcontrol/camcontrol.8	Wed Aug 28 20:22:14 2019	(r351581)
@@ -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: stable/11/sbin/camcontrol/camcontrol.c
==============================================================================
--- stable/11/sbin/camcontrol/camcontrol.c	Wed Aug 28 20:21:34 2019	(r351580)
+++ stable/11/sbin/camcontrol/camcontrol.c	Wed Aug 28 20:22:14 2019	(r351581)
@@ -224,7 +224,7 @@ static struct camcontrol_opts option_table[] = {
 	{"devtype", CAM_CMD_DEVTYPE, CAM_ARG_NONE, ""},
 #ifndef MINIMALISTIC
 	{"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},
@@ -4430,18 +4430,25 @@ reassignblocks(struct cam_device *device, u_int32_t *b
 
 #ifndef MINIMALISTIC
 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,
@@ -4454,36 +4461,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;
@@ -4495,7 +4513,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,
@@ -4503,6 +4521,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);
 
@@ -4537,10 +4556,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;
@@ -4580,11 +4602,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: stable/11/sbin/camcontrol/camcontrol.h
==============================================================================
--- stable/11/sbin/camcontrol/camcontrol.h	Wed Aug 28 20:21:34 2019	(r351580)
+++ stable/11/sbin/camcontrol/camcontrol.h	Wed Aug 28 20:22:14 2019	(r351581)
@@ -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: stable/11/sbin/camcontrol/modeedit.c
==============================================================================
--- stable/11/sbin/camcontrol/modeedit.c	Wed Aug 28 20:21:34 2019	(r351580)
+++ stable/11/sbin/camcontrol/modeedit.c	Wed Aug 28 20:22:14 2019	(r351581)
@@ -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);


More information about the svn-src-all mailing list