Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 7 Jan 2017 09:56:12 +0000 (UTC)
From:      Alexander Motin <mav@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r311636 - in head: sbin/camcontrol share/misc sys/cam/scsi
Message-ID:  <201701070956.v079uCg4012574@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mav
Date: Sat Jan  7 09:56:12 2017
New Revision: 311636
URL: https://svnweb.freebsd.org/changeset/base/311636

Log:
  Make 'camcontrol modepage' support subpages.
  
  MFC after:	2 weeks

Modified:
  head/sbin/camcontrol/camcontrol.8
  head/sbin/camcontrol/camcontrol.c
  head/sbin/camcontrol/camcontrol.h
  head/sbin/camcontrol/modeedit.c
  head/share/misc/scsi_modes
  head/sys/cam/scsi/scsi_all.c
  head/sys/cam/scsi/scsi_all.h
  head/sys/cam/scsi/scsi_ch.c

Modified: head/sbin/camcontrol/camcontrol.8
==============================================================================
--- head/sbin/camcontrol/camcontrol.8	Sat Jan  7 09:45:00 2017	(r311635)
+++ head/sbin/camcontrol/camcontrol.8	Sat Jan  7 09:56:12 2017	(r311636)
@@ -27,7 +27,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd November 30, 2016
+.Dd January 6, 2017
 .Dt CAMCONTROL 8
 .Os
 .Sh NAME
@@ -121,7 +121,7 @@
 .Ic modepage
 .Op device id
 .Op generic args
-.Aq Fl m Ar page | Fl l
+.Aq Fl m Ar page[,subpage] | Fl l
 .Op Fl P Ar pgctl
 .Op Fl b | Fl e
 .Op Fl d
@@ -702,9 +702,10 @@ The editor will be invoked if
 detects that standard input is terminal.
 .It Fl l
 Lists all available mode pages.
-.It Fl m Ar mode_page
-This specifies the number of the mode page the user would like to view
-and/or edit.
+If specified more then once, also lists subpages.
+.It Fl m Ar page[,subpage]
+This specifies the number of the mode page and optionally subpage the user
+would like to view and/or edit.
 This argument is mandatory unless
 .Fl l
 is specified.

Modified: head/sbin/camcontrol/camcontrol.c
==============================================================================
--- head/sbin/camcontrol/camcontrol.c	Sat Jan  7 09:45:00 2017	(r311635)
+++ head/sbin/camcontrol/camcontrol.c	Sat Jan  7 09:56:12 2017	(r311636)
@@ -125,12 +125,9 @@ typedef enum {
 	CAM_ARG_GET_STDINQ	= 0x00002000,
 	CAM_ARG_GET_XFERRATE	= 0x00004000,
 	CAM_ARG_INQ_MASK	= 0x00007000,
-	CAM_ARG_MODE_EDIT	= 0x00008000,
-	CAM_ARG_PAGE_CNTL	= 0x00010000,
 	CAM_ARG_TIMEOUT		= 0x00020000,
 	CAM_ARG_CMD_IN		= 0x00040000,
 	CAM_ARG_CMD_OUT		= 0x00080000,
-	CAM_ARG_DBD		= 0x00100000,
 	CAM_ARG_ERR_RECOVER	= 0x00200000,
 	CAM_ARG_RETRIES		= 0x00400000,
 	CAM_ARG_START_UNIT	= 0x00800000,
@@ -3987,8 +3984,8 @@ reassignblocks(struct cam_device *device
 
 #ifndef MINIMALISTIC
 void
-mode_sense(struct cam_device *device, int mode_page, int page_control,
-	   int dbd, int retry_count, int timeout, u_int8_t *data, int datalen)
+mode_sense(struct cam_device *device, int dbd, int pc, int page, int subpage,
+	   int retry_count, int timeout, u_int8_t *data, int datalen)
 {
 	union ccb *ccb;
 	int retval;
@@ -4000,15 +3997,17 @@ mode_sense(struct cam_device *device, in
 
 	CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->csio);
 
-	scsi_mode_sense(&ccb->csio,
+	scsi_mode_sense_subpage(&ccb->csio,
 			/* retries */ retry_count,
 			/* cbfcnp */ NULL,
 			/* tag_action */ MSG_SIMPLE_Q_TAG,
 			/* dbd */ dbd,
-			/* page_code */ page_control << 6,
-			/* page */ mode_page,
+			/* pc */ pc << 6,
+			/* page */ page,
+			/* subpage */ subpage,
 			/* param_buf */ data,
 			/* param_len */ datalen,
+			/* minimum_cmd_size */ 0,
 			/* sense_len */ SSD_FULL_SIZE,
 			/* timeout */ timeout ? timeout : 5000);
 
@@ -4089,8 +4088,9 @@ void
 modepage(struct cam_device *device, int argc, char **argv, char *combinedopt,
 	 int retry_count, int timeout)
 {
-	int c, mode_page = -1, page_control = 0;
-	int binary = 0, list = 0;
+	char *str_subpage;
+	int c, page = -1, subpage = -1, pc = 0;
+	int binary = 0, dbd = 0, edit = 0, list = 0;
 
 	while ((c = getopt(argc, argv, combinedopt)) != -1) {
 		switch(c) {
@@ -4098,40 +4098,44 @@ modepage(struct cam_device *device, int 
 			binary = 1;
 			break;
 		case 'd':
-			arglist |= CAM_ARG_DBD;
+			dbd = 1;
 			break;
 		case 'e':
-			arglist |= CAM_ARG_MODE_EDIT;
+			edit = 1;
 			break;
 		case 'l':
-			list = 1;
+			list++;
 			break;
 		case 'm':
-			mode_page = strtol(optarg, NULL, 0);
-			if (mode_page < 0)
-				errx(1, "invalid mode page %d", mode_page);
+			str_subpage = optarg;
+			strsep(&str_subpage, ",");
+			page = strtol(optarg, NULL, 0);
+			if (str_subpage)
+			    subpage = strtol(str_subpage, NULL, 0);
+			else
+			    subpage = 0;
+			if (page < 0)
+				errx(1, "invalid mode page %d", page);
+			if (subpage < 0)
+				errx(1, "invalid mode subpage %d", subpage);
 			break;
 		case 'P':
-			page_control = strtol(optarg, NULL, 0);
-			if ((page_control < 0) || (page_control > 3))
-				errx(1, "invalid page control field %d",
-				     page_control);
-			arglist |= CAM_ARG_PAGE_CNTL;
+			pc = strtol(optarg, NULL, 0);
+			if ((pc < 0) || (pc > 3))
+				errx(1, "invalid page control field %d", pc);
 			break;
 		default:
 			break;
 		}
 	}
 
-	if (mode_page == -1 && list == 0)
+	if (page == -1 && list == 0)
 		errx(1, "you must specify a mode page!");
 
-	if (list) {
-		mode_list(device, page_control, arglist & CAM_ARG_DBD,
-		    retry_count, timeout);
+	if (list != 0) {
+		mode_list(device, dbd, pc, list > 1, retry_count, timeout);
 	} else {
-		mode_edit(device, mode_page, page_control,
-		    arglist & CAM_ARG_DBD, arglist & CAM_ARG_MODE_EDIT, binary,
+		mode_edit(device, dbd, pc, page, subpage, edit, binary,
 		    retry_count, timeout);
 	}
 }

Modified: head/sbin/camcontrol/camcontrol.h
==============================================================================
--- head/sbin/camcontrol/camcontrol.h	Sat Jan  7 09:45:00 2017	(r311635)
+++ head/sbin/camcontrol/camcontrol.h	Sat Jan  7 09:56:12 2017	(r311636)
@@ -84,14 +84,14 @@ int epc(struct cam_device *device, int a
 int timestamp(struct cam_device *device, int argc, char **argv,
 	      char *combinedopt, int retry_count, int timeout,
 	      int verbosemode);
-void mode_sense(struct cam_device *device, int mode_page, int page_control,
-		int dbd, int retry_count, int timeout, u_int8_t *data,
+void mode_sense(struct cam_device *device, int dbd, int pc, int page,
+		int subpage, int retry_count, int timeout, uint8_t *data,
 		int datalen);
 void mode_select(struct cam_device *device, int save_pages, int retry_count,
 		 int timeout, u_int8_t *data, int datalen);
-void mode_edit(struct cam_device *device, int page, int page_control, int dbd,
+void mode_edit(struct cam_device *device, int dbd, int pc, int page, int subpage,
 	       int edit, int binary, int retry_count, int timeout);
-void mode_list(struct cam_device *device, int page_control, int dbd,
+void mode_list(struct cam_device *device, int dbd, int pc, int subpages,
 	       int retry_count, int timeout);
 int scsidoinquiry(struct cam_device *device, int argc, char **argv,
 		  char *combinedopt, int retry_count, int timeout);

Modified: head/sbin/camcontrol/modeedit.c
==============================================================================
--- head/sbin/camcontrol/modeedit.c	Sat Jan  7 09:45:00 2017	(r311635)
+++ head/sbin/camcontrol/modeedit.c	Sat Jan  7 09:56:12 2017	(r311636)
@@ -66,9 +66,6 @@ __FBSDID("$FreeBSD$");
 #define	MODE_PAGE_HEADER(mh)						\
 	(struct scsi_mode_page_header *)find_mode_page_6(mh)
 
-#define	MODE_PAGE_DATA(mph)						\
-	(u_int8_t *)(mph) + sizeof(struct scsi_mode_page_header)
-
 
 struct editentry {
 	STAILQ_ENTRY(editentry) link;
@@ -86,7 +83,8 @@ static int editlist_changed = 0;	/* Whet
 
 struct pagename {
 	SLIST_ENTRY(pagename) link;
-	int pagenum;
+	int page;
+	int subpage;
 	char *name;
 };
 static SLIST_HEAD(, pagename) namelist;	/* Page number to name mappings. */
@@ -106,21 +104,22 @@ static int		 editentry_save(void *hook, 
 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 modepage, int page_control,
-					   int dbd, int retries, int timeout);
-static void		 editlist_save(struct cam_device *device, int modepage,
-				       int page_control, int dbd, int retries,
-				       int timeout);
-static void		 nameentry_create(int pagenum, char *name);
-static struct pagename	*nameentry_lookup(int pagenum);
-static int		 load_format(const char *pagedb_path, int page);
+static void		 editlist_populate(struct cam_device *device, int dbd,
+					   int pc, int page, int subpage,
+					   int retries, int timeout);
+static void		 editlist_save(struct cam_device *device, int dbd,
+				       int pc, int page, int subpage,
+				       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,
+			    int lsubpage);
 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 page,
-				       int page_control, int dbd, int retries,
-				       int timeout);
+static void		 modepage_dump(struct cam_device *device, int dbd,
+			    int pc, int page, int subpage, int retries,
+			    int timeout);
 static void		 cleanup_editfile(void);
 
 
@@ -325,10 +324,10 @@ editentry_set(char *name, char *newvalue
 }
 
 static void
-nameentry_create(int pagenum, char *name) {
+nameentry_create(int page, int subpage, char *name) {
 	struct pagename *newentry;
 
-	if (pagenum < 0 || name == NULL || name[0] == '\0')
+	if (page < 0 || subpage < 0 || name == NULL || name[0] == '\0')
 		return;
 
 	/* Allocate memory for the new entry and a copy of the entry name. */
@@ -339,16 +338,17 @@ nameentry_create(int pagenum, char *name
 	/* Trim any trailing whitespace for the page name. */
 	RTRIM(newentry->name);
 
-	newentry->pagenum = pagenum;
+	newentry->page = page;
+	newentry->subpage = subpage;
 	SLIST_INSERT_HEAD(&namelist, newentry, link);
 }
 
 static struct pagename *
-nameentry_lookup(int pagenum) {
+nameentry_lookup(int page, int subpage) {
 	struct pagename *scan;
 
 	SLIST_FOREACH(scan, &namelist, link) {
-		if (pagenum == scan->pagenum)
+		if (page == scan->page && subpage == scan->subpage)
 			return (scan);
 	}
 
@@ -357,12 +357,14 @@ nameentry_lookup(int pagenum) {
 }
 
 static int
-load_format(const char *pagedb_path, int page)
+load_format(const char *pagedb_path, int lpage, int lsubpage)
 {
 	FILE *pagedb;
-	char str_pagenum[MAX_PAGENUM_LEN];
+	char str_page[MAX_PAGENUM_LEN];
+	char *str_subpage;
 	char str_pagename[MAX_PAGENAME_LEN];
-	int pagenum;
+	int page;
+	int subpage;
 	int depth;			/* Quoting depth. */
 	int found;
 	int lineno;
@@ -371,9 +373,10 @@ load_format(const char *pagedb_path, int
 	char c;
 
 #define	SETSTATE_LOCATE do {						\
-	str_pagenum[0] = '\0';						\
+	str_page[0] = '\0';						\
 	str_pagename[0] = '\0';						\
-	pagenum = -1;							\
+	page = -1;							\
+	subpage = -1;							\
 	state = LOCATE;							\
 } while (0)
 
@@ -450,32 +453,46 @@ load_format(const char *pagedb_path, int
 				 * modes without providing a mode definition).
 				 */
 				/* Record the name of this page. */
-				pagenum = strtol(str_pagenum, NULL, 0);
-				nameentry_create(pagenum, str_pagename);
+				str_subpage = str_page;
+				strsep(&str_subpage, ",");
+				page = strtol(str_page, NULL, 0);
+				if (str_subpage)
+				    subpage = strtol(str_subpage, NULL, 0);
+				else
+				    subpage = 0;
+				nameentry_create(page, subpage, str_pagename);
 				SETSTATE_LOCATE;
 			} else if (depth == 0 && c == PAGENAME_START) {
 				SETSTATE_PAGENAME;
 			} else if (c == PAGEDEF_START) {
-				pagenum = strtol(str_pagenum, NULL, 0);
+				str_subpage = str_page;
+				strsep(&str_subpage, ",");
+				page = strtol(str_page, NULL, 0);
+				if (str_subpage)
+				    subpage = strtol(str_subpage, NULL, 0);
+				else
+				    subpage = 0;
 				if (depth == 1) {
 					/* Record the name of this page. */
-					nameentry_create(pagenum, str_pagename);
+					nameentry_create(page, subpage,
+					    str_pagename);
 					/*
 					 * Only record the format if this is
 					 * the page we are interested in.
 					 */
-					if (page == pagenum && !found)
+					if (lpage == page &&
+					    lsubpage == subpage && !found)
 						SETSTATE_PAGEDEF;
 				}
 			} else if (c == PAGEDEF_END) {
 				/* Reset the processor state. */
 				SETSTATE_LOCATE;
-			} else if (depth == 0 && ! BUFFERFULL(str_pagenum)) {
-				strncat(str_pagenum, &c, 1);
+			} else if (depth == 0 && ! BUFFERFULL(str_page)) {
+				strncat(str_page, &c, 1);
 			} else if (depth == 0) {
 				errx(EX_OSFILE, "%s:%d: %s %zd %s", pagedb_path,
 				    lineno, "page identifier exceeds",
-				    sizeof(str_pagenum) - 1, "characters");
+				    sizeof(str_page) - 1, "characters");
 			}
 			break;
 
@@ -491,7 +508,7 @@ load_format(const char *pagedb_path, int
 			} else {
 				errx(EX_OSFILE, "%s:%d: %s %zd %s", pagedb_path,
 				    lineno, "page name exceeds",
-				    sizeof(str_pagenum) - 1, "characters");
+				    sizeof(str_page) - 1, "characters");
 			}
 			break;
 
@@ -532,88 +549,95 @@ load_format(const char *pagedb_path, int
 }
 
 static void
-editlist_populate(struct cam_device *device, int modepage, int page_control,
-		  int dbd, int retries, int timeout)
+editlist_populate(struct cam_device *device, int dbd, int pc, int page,
+    int subpage, int retries, int timeout)
 {
 	u_int8_t data[MAX_COMMAND_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;
+	int len;
 
 	STAILQ_INIT(&editlist);
 
 	/* Fetch changeable values; use to build initial editlist. */
-	mode_sense(device, modepage, 1, dbd, retries, timeout, data,
+	mode_sense(device, dbd, 1, page, subpage, retries, timeout, data,
 		   sizeof(data));
 
 	mh = (struct scsi_mode_header_6 *)data;
 	mph = MODE_PAGE_HEADER(mh);
-	mode_pars = MODE_PAGE_DATA(mph);
+	if ((mph->page_code & SMPH_SPF) == 0) {
+		mode_pars = (uint8_t *)(mph + 1);
+		len = mph->page_length;
+	} else {
+		mphsp = (struct scsi_mode_page_header_sp *)mph;
+		mode_pars = (uint8_t *)(mphsp + 1);
+		len = scsi_2btoul(mphsp->page_length);
+	}
 
 	/* Decode the value data, creating edit_entries for each value. */
-	buff_decode_visit(mode_pars, mh->data_length, format,
-	    editentry_create, 0);
+	buff_decode_visit(mode_pars, len, format, editentry_create, 0);
 
 	/* Fetch the current/saved values; use to set editentry values. */
-	mode_sense(device, modepage, page_control, dbd, retries, timeout, data,
-		   sizeof(data));
-	buff_decode_visit(mode_pars, mh->data_length, format,
-	    editentry_update, 0);
+	mode_sense(device, dbd, pc, page, subpage, retries, timeout,
+	    data, sizeof(data));
+	buff_decode_visit(mode_pars, len, format, editentry_update, 0);
 }
 
 static void
-editlist_save(struct cam_device *device, int modepage, int page_control,
-	      int dbd, int retries, int timeout)
+editlist_save(struct cam_device *device, int dbd, int pc, int page,
+    int subpage, int retries, int timeout)
 {
 	u_int8_t data[MAX_COMMAND_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;
+	int len, hlen;
 
 	/* Make sure that something changed before continuing. */
 	if (! editlist_changed)
 		return;
 
-	/*
-	 * Preload the CDB buffer with the current mode page data.
-	 * XXX If buff_encode_visit would return the number of bytes encoded
-	 *     we *should* use that to build a header from scratch. As it is
-	 *     now, we need mode_sense to find out the page length.
-	 */
-	mode_sense(device, modepage, page_control, dbd, retries, timeout, data,
-		   sizeof(data));
+	/* Preload the CDB buffer with the current mode page data. */
+	mode_sense(device, dbd, pc, page, subpage, retries, timeout,
+	    data, sizeof(data));
 
 	/* Initial headers & offsets. */
 	mh = (struct scsi_mode_header_6 *)data;
 	mph = MODE_PAGE_HEADER(mh);
-	mode_pars = MODE_PAGE_DATA(mph);
+	if ((mph->page_code & SMPH_SPF) == 0) {
+		hlen = sizeof(*mph);
+		mode_pars = (uint8_t *)(mph + 1);
+		len = mph->page_length;
+	} else {
+		mphsp = (struct scsi_mode_page_header_sp *)mph;
+		hlen = sizeof(*mphsp);
+		mode_pars = (uint8_t *)(mphsp + 1);
+		len = scsi_2btoul(mphsp->page_length);
+	}
 
 	/* Encode the value data to be passed back to the device. */
-	buff_encode_visit(mode_pars, mh->data_length, format,
-	    editentry_save, 0);
+	buff_encode_visit(mode_pars, len, format, editentry_save, 0);
 
 	/* Eliminate block descriptors. */
-	bcopy(mph, ((u_int8_t *)mh) + sizeof(*mh),
-	    sizeof(*mph) + mph->page_length);
+	bcopy(mph, mh + 1, hlen + len);
 
 	/* Recalculate headers & offsets. */
-	mh->blk_desc_len = 0;		/* No block descriptors. */
+	mh->data_length = 0;		/* Reserved for MODE SELECT command. */
 	mh->dev_spec = 0;		/* Clear device-specific parameters. */
+	mh->blk_desc_len = 0;		/* No block descriptors. */
 	mph = MODE_PAGE_HEADER(mh);
-	mode_pars = MODE_PAGE_DATA(mph);
-
-	mph->page_code &= SMS_PAGE_CODE;/* Isolate just the page code. */
-	mh->data_length = 0;		/* Reserved for MODE SELECT command. */
+	mph->page_code &= ~SMPH_PS;	/* Reserved for MODE SELECT command. */
 
 	/*
 	 * Write the changes back to the device. If the user editted control
 	 * page 3 (saved values) then request the changes be permanently
 	 * recorded.
 	 */
-	mode_select(device,
-	    (page_control << PAGE_CTRL_SHIFT == SMS_PAGE_CTRL_SAVED),
-	    retries, timeout, (u_int8_t *)mh,
-	    sizeof(*mh) + mh->blk_desc_len + sizeof(*mph) + mph->page_length);
+	mode_select(device, (pc << PAGE_CTRL_SHIFT == SMS_PAGE_CTRL_SAVED),
+	    retries, timeout, (u_int8_t *)mh, sizeof(*mh) + hlen + len);
 }
 
 static int
@@ -782,24 +806,32 @@ modepage_edit(void)
 }
 
 static void
-modepage_dump(struct cam_device *device, int page, int page_control, int dbd,
+modepage_dump(struct cam_device *device, int dbd, int pc, int page, int subpage,
 	      int retries, int timeout)
 {
 	u_int8_t data[MAX_COMMAND_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;
-	int indx;			/* Index for scanning mode params. */
+	struct scsi_mode_page_header_sp *mphsp;
+	int indx, len;
 
-	mode_sense(device, page, page_control, dbd, retries, timeout, data,
-		   sizeof(data));
+	mode_sense(device, dbd, pc, page, subpage, retries, timeout,
+	    data, sizeof(data));
 
 	mh = (struct scsi_mode_header_6 *)data;
 	mph = MODE_PAGE_HEADER(mh);
-	mode_pars = MODE_PAGE_DATA(mph);
+	if ((mph->page_code & SMPH_SPF) == 0) {
+		mode_pars = (uint8_t *)(mph + 1);
+		len = mph->page_length;
+	} else {
+		mphsp = (struct scsi_mode_page_header_sp *)mph;
+		mode_pars = (uint8_t *)(mphsp + 1);
+		len = scsi_2btoul(mphsp->page_length);
+	}
 
 	/* Print the raw mode page data with newlines each 8 bytes. */
-	for (indx = 0; indx < mph->page_length; indx++) {
+	for (indx = 0; indx < len; indx++) {
 		printf("%02x%c",mode_pars[indx],
 		    (((indx + 1) % 8) == 0) ? '\n' : ' ');
 	}
@@ -817,7 +849,7 @@ cleanup_editfile(void)
 }
 
 void
-mode_edit(struct cam_device *device, int page, int page_control, int dbd,
+mode_edit(struct cam_device *device, int dbd, int pc, int page, int subpage,
 	  int edit, int binary, int retry_count, int timeout)
 {
 	const char *pagedb_path;	/* Path to modepage database. */
@@ -829,15 +861,17 @@ mode_edit(struct cam_device *device, int
 		if ((pagedb_path = getenv("SCSI_MODES")) == NULL)
 			pagedb_path = DEFAULT_SCSI_MODE_DB;
 
-		if (load_format(pagedb_path, page) != 0 && (edit || verbose)) {
+		if (load_format(pagedb_path, page, subpage) != 0 &&
+		    (edit || verbose)) {
 			if (errno == ENOENT) {
 				/* Modepage database file not found. */
 				warn("cannot open modepage database \"%s\"",
 				    pagedb_path);
 			} else if (errno == ESRCH) {
 				/* Modepage entry not found in database. */
-				warnx("modepage %d not found in database"
-				    "\"%s\"", page, pagedb_path);
+				warnx("modepage 0x%02x,0x%02x not found in "
+				    "database \"%s\"", page, subpage,
+				    pagedb_path);
 			}
 			/* We can recover in display mode, otherwise we exit. */
 			if (!edit) {
@@ -847,22 +881,20 @@ mode_edit(struct cam_device *device, int
 				exit(EX_OSFILE);
 		}
 
-		editlist_populate(device, page, page_control, dbd, retry_count,
+		editlist_populate(device, dbd, pc, page, subpage, retry_count,
 			timeout);
 	}
 
 	if (edit) {
-		if (page_control << PAGE_CTRL_SHIFT != SMS_PAGE_CTRL_CURRENT &&
-		    page_control << PAGE_CTRL_SHIFT != SMS_PAGE_CTRL_SAVED)
+		if (pc << PAGE_CTRL_SHIFT != SMS_PAGE_CTRL_CURRENT &&
+		    pc << PAGE_CTRL_SHIFT != SMS_PAGE_CTRL_SAVED)
 			errx(EX_USAGE, "it only makes sense to edit page 0 "
 			    "(current) or page 3 (saved values)");
 		modepage_edit();
-		editlist_save(device, page, page_control, dbd, retry_count,
-			timeout);
+		editlist_save(device, dbd, pc, page, subpage, retry_count, timeout);
 	} else if (binary || STAILQ_EMPTY(&editlist)) {
 		/* Display without formatting information. */
-		modepage_dump(device, page, page_control, dbd, retry_count,
-		    timeout);
+		modepage_dump(device, dbd, pc, page, subpage, retry_count, timeout);
 	} else {
 		/* Display with format. */
 		modepage_write(stdout, 0);
@@ -870,44 +902,55 @@ mode_edit(struct cam_device *device, int
 }
 
 void
-mode_list(struct cam_device *device, int page_control, int dbd,
+mode_list(struct cam_device *device, int dbd, int pc, int subpages,
 	  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. */
 	struct scsi_mode_page_header *mph;
+	struct scsi_mode_page_header_sp *mphsp;
 	struct pagename *nameentry;
 	const char *pagedb_path;
-	int len;
+	int len, page, subpage;
 
 	if ((pagedb_path = getenv("SCSI_MODES")) == NULL)
 		pagedb_path = DEFAULT_SCSI_MODE_DB;
 
-	if (load_format(pagedb_path, 0) != 0 && verbose && errno == ENOENT) {
+	if (load_format(pagedb_path, 0, 0) != 0 && verbose && errno == ENOENT) {
 		/* Modepage database file not found. */
 		warn("cannot open modepage database \"%s\"", pagedb_path);
 	}
 
 	/* Build the list of all mode pages by querying the "all pages" page. */
-	mode_sense(device, SMS_ALL_PAGES_PAGE, page_control, dbd, retry_count,
-	    timeout, data, sizeof(data));
+	mode_sense(device, dbd, pc, SMS_ALL_PAGES_PAGE,
+	    subpages ? SMS_SUBPAGE_ALL : 0,
+	    retry_count, timeout, data, sizeof(data));
 
 	mh = (struct scsi_mode_header_6 *)data;
 	len = sizeof(*mh) + mh->blk_desc_len;	/* Skip block descriptors. */
 	/* Iterate through the pages in the reply. */
 	while (len < mh->data_length) {
 		/* Locate the next mode page header. */
-		mph = (struct scsi_mode_page_header *)
-		    ((intptr_t)mh + len);
+		mph = (struct scsi_mode_page_header *)((intptr_t)mh + len);
 
-		mph->page_code &= SMS_PAGE_CODE;
-		nameentry = nameentry_lookup(mph->page_code);
+		if ((mph->page_code & SMPH_SPF) == 0) {
+			page = mph->page_code & SMS_PAGE_CODE;
+			subpage = 0;
+			len += 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);
+		}
 
-		if (nameentry == NULL || nameentry->name == NULL)
-			printf("0x%02x\n", mph->page_code);
-		else
-			printf("0x%02x\t%s\n", mph->page_code,
-			    nameentry->name); 
-		len += mph->page_length + sizeof(*mph);
+		nameentry = nameentry_lookup(page, subpage);
+		if (subpage == 0) {
+			printf("0x%02x\t%s\n", page,
+			    nameentry ? nameentry->name : "");
+		} else {
+			printf("0x%02x,0x%02x\t%s\n", page, subpage,
+			    nameentry ? nameentry->name : "");
+		}
 	}
 }

Modified: head/share/misc/scsi_modes
==============================================================================
--- head/share/misc/scsi_modes	Sat Jan  7 09:45:00 2017	(r311635)
+++ head/share/misc/scsi_modes	Sat Jan  7 09:56:12 2017	(r311636)
@@ -49,7 +49,11 @@
 
 # ALL DEVICE TYPES
 
-0x0a "Control Mode Page" {
+0x0a,0x03 "Command Duration Limit A";
+
+0x0a,0x04 "Command Duration Limit B";
+
+0x0a "Control" {
 	{TST} t3
 	{TMF_ONLY} t1
 	{DPICZ} t1
@@ -78,7 +82,18 @@
 	{Extended Self-Test Completion Time} i2
 }
 
-0x02 "Disconnect-Reconnect Page" {
+0x0a,0x01 "Control Extension" {
+	{Reserved} *t4
+	{DLC} t1
+	{TCMOS} t1
+	{SCSIP} t1
+	{IALUAE} t1
+	{Reserved} *t4
+	{Initial Command Priority} t4
+	{Maximum Sense Data Length} i1
+}
+
+0x02 "Disconnect-Reconnect" {
 	{Buffer Full Ratio} i1
 	{Buffer Empty Ratio} i1
 	{Bus Inactivity Limit} i2
@@ -92,26 +107,11 @@
 	{Reserved} *i1
 }
 
-0x15 "Extended Page";
+0x15 "Extended";
 
-0x16 "Extended Device-Type Specific Page";
+0x16 "Extended Device-Type Specific";
 
-0x1c "Informational Exceptions Control Page" {
-	{PERF} t1
-	{Reserved} *t1
-	{EBF} t1
-	{EWasc} t1
-	{DExcpt} t1
-	{TEST} t1
-	{EBACKERR} t1
-	{LogErr} t1
-	{Reserved} *t4
-	{MRIE} t4
-	{Interval Timer} i4
-	{Report Count} i4
-}
-
-0x09 "Peripheral Device Page" {
+0x09 "Peripheral Device" {
 	{Interface Identifier} i2
 	{Reserved} *i1
 	{Reserved} *i1
@@ -119,21 +119,69 @@
 	{Reserved} *i1
 }
 
-0x1a "Power Condition Page" {
-	{Reserved} *i1
+0x1a "Power Condition" {
+	{PM_BG_PRECEDENCE} t1
+	{Reserved} *t6
+	{STANDBY_Y} t1
+	{Reserved} *t4
+	{IDLE_C} t1
+	{IDLE_B} t1
+	{IDLE_A} t1
+	{STANDBY_Z} t1
+	{IDLE_A Condition Timer} i4
+	{STANDBY_Z Condition Timer} i4
+	{IDLE_B Condition Timer} i4
+	{IDLE_C Condition Timer} i4
+	{STANDBY_Y Condition Timer} i4
+	{Reserved} *i4
+	{Reserved} *i4
+	{Reserved} *i4
+	{Reserved} *i3
+	{CCF Idle} t2
+	{CCF Standby} t2
+	{CCF Stopped} t2
+	{Reserved} *t2
+}
+
+0x1a,0x01 "Power Consumption" {
+	{Reserved} *i2
 	{Reserved} *t6
-	{Idle} t1
-	{Standby} t1
-	{Idle Condition Timer} i4
-	{Standby Condition Timer} i4
+	{Active Level} t2
+	{Power Consumption Identifier} i1
+	{Reserved} *i4
+	{Reserved} *i4
 }
 
-0x18 "Protocol-Specific LUN Page";
+0x18 "Protocol-Specific Logical Unit";
 
-0x19 "Protocol-Specific Port Page";
+0x19 "Protocol-Specific Port";
 
 # DIRECT ACCESS DEVICES
-0x08 "Caching Page" {
+
+0x0a,0x02 "Application Tag";
+
+0x1a,0xf1 "ATA Power Condition";
+
+0x1c,0x01 "Background Control" {
+	{Reserved} *t5
+	{S_L_FULL} *t1
+	{LOWIR} *t1
+	{EN_BMS} *t1
+	{Reserved} *t7
+	{EN_PS} *t1
+	{Background Medium Scan Interval Time} i2
+	{Background Pre-Scan Time Limit} i2
+	{Minimum Idle Time Before Background Scan} i2
+	{Maximum Time To Suspend Background Scan} i2
+	{Reserved} *i2
+}
+
+0x0a,0x06 "Background Operation Control" {
+	{BO_MODE} t2
+	{Reserved} *t6
+}
+
+0x08 "Caching" {
 	{IC} t1
 	{ABPF} t1
 	{CAP} t1
@@ -159,7 +207,7 @@
 	{Reserved} *t4
 }
 
-0x05 "Flexible Disk Page" {
+0x05 "Flexible Disk" {
 	{Transfer rate} i2
 	{Number of heads} i1
 	{Sectors per track} i1
@@ -190,7 +238,7 @@
 	{Reserved} *i1
 }
 
-0x03 "Format Device Page" {
+0x03 "Format Device" {
 	{Tracks per Zone} i2
 	{Alternate Sectors per Zone} i2
 	{Alternate Tracks per Zone} i2
@@ -207,7 +255,34 @@
 	{Reserved} *t4
 }
 
-0x0b "Medium Types Supported Page" {
+0x0a,0x05 "I/O Advice Hints Grouping";
+
+0x1c "Informational Exceptions Control" {
+	{PERF} t1
+	{Reserved} *t1
+	{EBF} t1
+	{EWasc} t1
+	{DExcpt} t1
+	{TEST} t1
+	{EBACKERR} t1
+	{LogErr} t1
+	{Reserved} *t4
+	{MRIE} t4
+	{Interval Timer} i4
+	{Report Count} i4
+}
+
+0x1c,0x02 "Logical Block Provisioning" {
+	{Reserved} *t7
+	{SITUA} t1
+	{Reserved} *i1
+	{Reserved} *i1
+	{Reserved} *i1
+	{Reserved} *i4
+	{Reserved} *i4
+}
+
+0x0b "Medium Types Supported" {
 	{Reserved} *i1
 	{Reserved} *i1
 	{Medium type one supported} i1
@@ -216,10 +291,11 @@
 	{Medium type four supported} i1
 }
 
-# Notch page (0x0c)
-0x0c "Notch and Partition Page";
+0x0c "Notch and Partition";
+
+0x0a,0xf1 "PATA Control";
 
-0x01 "Read-Write Error Recovery Page" {
+0x01 "Read-Write Error Recovery" {
 	{AWRE (Auto Write Reallocation Enbld)} t1
 	{ARRE (Auto Read Reallocation Enbld)} t1
 	{TB (Transfer Block)} t1
@@ -240,7 +316,7 @@
 	{Recovery Time Limit} i2
 }
 
-0x04 "Rigid Disk Drive Geometry Page" {
+0x04 "Rigid Disk Drive Geometry" {
 	{Number of Cylinders} i3
 	{Number of Heads} i1
 	{Starting Cylinder-Write Precompensation} i3
@@ -256,7 +332,7 @@
 	{Reserved} *i1
 }
 
-0x07 "Verify Error Recovery Page" {
+0x07 "Verify Error Recovery" {
 	{Reserved} *t4
 	{EER} t1
 	{PER} t1
@@ -272,7 +348,7 @@
 	{Verify Recovery Time Limit} i2
 }
 
-0x0E "CD-ROM Audio Control Parameters Page" {
+0x0E "CD-ROM Audio Control Parameters" {
 	{Reserved} *t5
 	{Immed} t1
 	{SOTC} t1
@@ -297,7 +373,7 @@
 }
 
 # SEQUENTIAL ACCESS DEVICES
-0x10 "Device Configuration Page" {
+0x10 "Device Configuration" {
 	{Reserved} *t1
 	{Change Active Partition} t1
 	{Change Active Format} t1
@@ -326,7 +402,7 @@
 	{SCSI-3 Permanent Write Protect} t1
 }
 
-0x0f "Data Compression Page" {
+0x0f "Data Compression" {
 	{Data Compression Enabled} t1
 	{Date Compression Capable} t1
 	{Reserved} *t6
@@ -339,7 +415,7 @@
 }
 
 # Removable devices
-0x1b "Removable Block Access Capacities Page" {
+0x1b "Removable Block Access Capacities" {
 	{System Floppy Type Device} t1
 	{Supports Reporting Format Progress} t1
 	{Reserved} *t6
@@ -351,7 +427,7 @@
 }
 
 # CD-ROM (and CD-R[W]) devices
-0x2a "CD capabilities and mechanical status page" {
+0x2a "CD capabilities and mechanical status" {
 	{Reserved} *t4
 	{Method 2} t1
 	{CD-RW Read} t1

Modified: head/sys/cam/scsi/scsi_all.c
==============================================================================
--- head/sys/cam/scsi/scsi_all.c	Sat Jan  7 09:45:00 2017	(r311635)
+++ head/sys/cam/scsi/scsi_all.c	Sat Jan  7 09:56:12 2017	(r311636)
@@ -7622,24 +7622,34 @@ scsi_inquiry(struct ccb_scsiio *csio, u_
 }
 
 void
-scsi_mode_sense(struct ccb_scsiio *csio, u_int32_t retries,
-		void (*cbfcnp)(struct cam_periph *, union ccb *),
-		u_int8_t tag_action, int dbd, u_int8_t page_code,
-		u_int8_t page, u_int8_t *param_buf, u_int32_t param_len,
-		u_int8_t sense_len, u_int32_t timeout)
+scsi_mode_sense(struct ccb_scsiio *csio, uint32_t retries,
+    void (*cbfcnp)(struct cam_periph *, union ccb *), uint8_t tag_action,
+    int dbd, uint8_t pc, uint8_t page, uint8_t *param_buf, uint32_t param_len,
+    uint8_t sense_len, uint32_t timeout)
 {
 
-	scsi_mode_sense_len(csio, retries, cbfcnp, tag_action, dbd,
-			    page_code, page, param_buf, param_len, 0,
-			    sense_len, timeout);
+	scsi_mode_sense_subpage(csio, retries, cbfcnp, tag_action, dbd,
+	    pc, page, 0, param_buf, param_len, 0, sense_len, timeout);
 }
 
 void
-scsi_mode_sense_len(struct ccb_scsiio *csio, u_int32_t retries,
-		    void (*cbfcnp)(struct cam_periph *, union ccb *),
-		    u_int8_t tag_action, int dbd, u_int8_t page_code,
-		    u_int8_t page, u_int8_t *param_buf, u_int32_t param_len,
-		    int minimum_cmd_size, u_int8_t sense_len, u_int32_t timeout)
+scsi_mode_sense_len(struct ccb_scsiio *csio, uint32_t retries,
+    void (*cbfcnp)(struct cam_periph *, union ccb *), uint8_t tag_action,
+    int dbd, uint8_t pc, uint8_t page, uint8_t *param_buf, uint32_t param_len,
+    int minimum_cmd_size, uint8_t sense_len, uint32_t timeout)
+{
+
+	scsi_mode_sense_subpage(csio, retries, cbfcnp, tag_action, dbd,
+	    pc, page, 0, param_buf, param_len, minimum_cmd_size,
+	    sense_len, timeout);
+}
+
+void
+scsi_mode_sense_subpage(struct ccb_scsiio *csio, uint32_t retries,
+    void (*cbfcnp)(struct cam_periph *, union ccb *), uint8_t tag_action,
+    int dbd, uint8_t pc, uint8_t page, uint8_t subpage, uint8_t *param_buf,
+    uint32_t param_len, int minimum_cmd_size, uint8_t sense_len,
+    uint32_t timeout)
 {
 	u_int8_t cdb_len;
 
@@ -7658,7 +7668,8 @@ scsi_mode_sense_len(struct ccb_scsiio *c
 		scsi_cmd->opcode = MODE_SENSE_6;
 		if (dbd != 0)
 			scsi_cmd->byte2 |= SMS_DBD;
-		scsi_cmd->page = page_code | page;
+		scsi_cmd->page = pc | page;
+		scsi_cmd->subpage = subpage;
 		scsi_cmd->length = param_len;
 		cdb_len = sizeof(*scsi_cmd);
 	} else {
@@ -7672,7 +7683,8 @@ scsi_mode_sense_len(struct ccb_scsiio *c
 		scsi_cmd->opcode = MODE_SENSE_10;
 		if (dbd != 0)
 			scsi_cmd->byte2 |= SMS_DBD;

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



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