camcontrol(8) and MODE_[SENSE|SELECT]_10

Bruce M Simpson bms at spc.org
Wed Oct 6 03:49:13 PDT 2004


Hi all,

On Wed, Oct 06, 2004 at 02:51:21AM -0700, Bruce M Simpson wrote:
> Here is the patch I used to hack camcontrol to force the use of
> MODE_SENSE_10 and MODE_SELECT_10 for UFI (umass) devices, i.e.
> USB floppy drives.

El stupido. I didn't realize that the mode page headers were different
sizes. Considering I haven't hacked on SCSI proper in 3-5 years this is
no big surprise.

Here's a revised patch which correctly fetches and displays the Mode
Page 0x5 (Flexible Disk Page) from my USB floppy drive (a fairly
common-or-garden Y-E Data FlashBuster):

empiric# camcontrol modepage 2:0:0 -m 0x05 -s
Transfer rate:  500
Number of heads:  2
Sectors per track:  18
Data bytes per sector:  512
Number of cylinders:  80
Starting cylinder-write precompensation:  0
Starting cylinder-reduced write current:  0
Drive step rate:  0
Drive step pulse width:  0
Head settle delay:  0
Motor on delay:  5
Motor off delay:  30
TRDY:  0
SSN:  0
MO:  0
SPC:  0
Write Compensation:  0
Head load delay:  0
Head unload delay:  0
Pin 34:  0
Pin 2:  0
Pin 4:  0
Pin 1:  0
Medium rotation rate:  300

This geometry looks correct.  Please let me know your thoughts.

Regards,
BMS
-------------- next part --------------
Index: src/sbin/camcontrol/camcontrol.8
===================================================================
RCS file: /home/ncvs/src/sbin/camcontrol/camcontrol.8,v
retrieving revision 1.38
diff -u -p -r1.38 camcontrol.8
--- src/sbin/camcontrol/camcontrol.8	3 Jul 2004 00:13:43 -0000	1.38
+++ src/sbin/camcontrol/camcontrol.8	6 Oct 2004 09:17:37 -0000
@@ -95,6 +95,7 @@
 .Op Fl P Ar pgctl
 .Op Fl b | Fl e
 .Op Fl d
+.Op Fl s
 .Nm
 .Ic cmd
 .Op device id
@@ -376,6 +377,9 @@ and/or edit.
 This argument is mandatory unless
 .Fl l
 is specified.
+.It Fl s
+This forces the use of a 10-byte MODE SENSE or MODE SELECT command, which is
+necessary for certain kinds of devices.
 .It Fl P Ar pgctl
 This allows the user to specify the page control field.
 Possible values are:
Index: src/sbin/camcontrol/camcontrol.c
===================================================================
RCS file: /home/ncvs/src/sbin/camcontrol/camcontrol.c,v
retrieving revision 1.52
diff -u -p -r1.52 camcontrol.c
--- src/sbin/camcontrol/camcontrol.c	3 Mar 2004 01:51:24 -0000	1.52
+++ src/sbin/camcontrol/camcontrol.c	6 Oct 2004 09:13:52 -0000
@@ -139,7 +139,7 @@ struct camcontrol_opts option_table[] = 
 	{"devlist", CAM_CMD_DEVTREE, CAM_ARG_NONE, NULL},
 #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, "bdelm:sP:"},
 	{"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},
@@ -1586,7 +1586,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)
+	   int dbd, int retry_count, int timeout, u_int8_t *data, int datalen,
+	   int force10bytes)
 {
 	union ccb *ccb;
 	int retval;
@@ -1599,7 +1600,7 @@ mode_sense(struct cam_device *device, in
 	bzero(&(&ccb->ccb_h)[1],
 	      sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
 
-	scsi_mode_sense(&ccb->csio,
+	scsi_mode_sense_len(&ccb->csio,
 			/* retries */ retry_count,
 			/* cbfcnp */ NULL,
 			/* tag_action */ MSG_SIMPLE_Q_TAG,
@@ -1608,6 +1609,7 @@ mode_sense(struct cam_device *device, in
 			/* page */ mode_page,
 			/* param_buf */ data,
 			/* param_len */ datalen,
+			/* minimum_cmd_size */ force10bytes ? 10 : 0,
 			/* sense_len */ SSD_FULL_SIZE,
 			/* timeout */ timeout ? timeout : 5000);
 
@@ -1636,7 +1638,7 @@ mode_sense(struct cam_device *device, in
 
 void
 mode_select(struct cam_device *device, int save_pages, int retry_count,
-	   int timeout, u_int8_t *data, int datalen)
+	   int timeout, u_int8_t *data, int datalen, int force10bytes)
 {
 	union ccb *ccb;
 	int retval;
@@ -1649,7 +1651,7 @@ mode_select(struct cam_device *device, i
 	bzero(&(&ccb->ccb_h)[1],
 	      sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
 
-	scsi_mode_select(&ccb->csio,
+	scsi_mode_select_len(&ccb->csio,
 			 /* retries */ retry_count,
 			 /* cbfcnp */ NULL,
 			 /* tag_action */ MSG_SIMPLE_Q_TAG,
@@ -1657,6 +1659,7 @@ mode_select(struct cam_device *device, i
 			 /* save_pages */ save_pages,
 			 /* param_buf */ data,
 			 /* param_len */ datalen,
+			 /* minimum_cmd_size */ force10bytes ? 10 : 0,
 			 /* sense_len */ SSD_FULL_SIZE,
 			 /* timeout */ timeout ? timeout : 5000);
 
@@ -1690,7 +1693,7 @@ modepage(struct cam_device *device, int 
 	 int retry_count, int timeout)
 {
 	int c, mode_page = -1, page_control = 0;
-	int binary = 0, list = 0;
+	int binary = 0, list = 0, force10bytes = 0;
 
 	while ((c = getopt(argc, argv, combinedopt)) != -1) {
 		switch(c) {
@@ -1711,6 +1714,9 @@ modepage(struct cam_device *device, int 
 			if (mode_page < 0)
 				errx(1, "invalid mode page %d", mode_page);
 			break;
+		case 's':
+			force10bytes = 1;
+			break;
 		case 'P':
 			page_control = strtol(optarg, NULL, 0);
 			if ((page_control < 0) || (page_control > 3))
@@ -1728,11 +1734,11 @@ modepage(struct cam_device *device, int 
 
 	if (list) {
 		mode_list(device, page_control, arglist & CAM_ARG_DBD,
-		    retry_count, timeout);
+		    retry_count, timeout, force10bytes);
 	} else {
 		mode_edit(device, mode_page, page_control,
 		    arglist & CAM_ARG_DBD, arglist & CAM_ARG_MODE_EDIT, binary,
-		    retry_count, timeout);
+		    retry_count, timeout, force10bytes);
 	}
 }
 
@@ -3166,7 +3172,7 @@ usage(int verbose)
 #ifndef MINIMALISTIC
 "        camcontrol defects    [dev_id][generic args] <-f format> [-P][-G]\n"
 "        camcontrol modepage   [dev_id][generic args] <-m page | -l>\n"
-"                              [-P pagectl][-e | -b][-d]\n"
+"                              [-P pagectl][-e | -b][-d][-s]\n"
 "        camcontrol cmd        [dev_id][generic args] <-c cmd [args]>\n"
 "                              [-i len fmt|-o len fmt [args]]\n"
 "        camcontrol debug      [-I][-P][-T][-S][-X][-c]\n"
Index: src/sbin/camcontrol/camcontrol.h
===================================================================
RCS file: /home/ncvs/src/sbin/camcontrol/camcontrol.h,v
retrieving revision 1.4
diff -u -p -r1.4 camcontrol.h
--- src/sbin/camcontrol/camcontrol.h	8 Aug 2000 06:24:15 -0000	1.4
+++ src/sbin/camcontrol/camcontrol.h	6 Oct 2004 09:14:03 -0000
@@ -42,13 +42,14 @@ struct get_hook
 
 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);
+		int datalen, int force10bytes);
 void mode_select(struct cam_device *device, int save_pages, int retry_count,
-		 int timeout, u_int8_t *data, int datalen);
+		 int timeout, u_int8_t *data, int datalen, int force10bytes);
 void mode_edit(struct cam_device *device, int page, int page_control, int dbd,
-	       int edit, int binary, int retry_count, int timeout);
+	       int edit, int binary, int retry_count, int timeout,
+	       int force10bytes);
 void mode_list(struct cam_device *device, int page_control, int dbd,
-	       int retry_count, int timeout);
+	       int retry_count, int timeout, int force10bytes);
 char *cget(void *hook, char *name);
 int iget(void *hook, char *name);
 void arg_put(void *hook, int letter, void *arg, int count, char *name);
Index: src/sbin/camcontrol/modeedit.c
===================================================================
RCS file: /home/ncvs/src/sbin/camcontrol/modeedit.c,v
retrieving revision 1.17
diff -u -p -r1.17 modeedit.c
--- src/sbin/camcontrol/modeedit.c	22 Jan 2004 07:23:35 -0000	1.17
+++ src/sbin/camcontrol/modeedit.c	6 Oct 2004 10:44:30 -0000
@@ -65,9 +65,12 @@ int verbose = 0;
 
 
 /* Macros for working with mode pages. */
-#define	MODE_PAGE_HEADER(mh)						\
+#define	MODE_PAGE_HEADER_6(mh)						\
 	(struct scsi_mode_page_header *)find_mode_page_6(mh)
 
+#define	MODE_PAGE_HEADER_10(mh)						\
+	(struct scsi_mode_page_header *)find_mode_page_10(mh)
+
 #define	MODE_PAGE_DATA(mph)						\
 	(u_int8_t *)(mph) + sizeof(struct scsi_mode_page_header)
 
@@ -110,10 +113,11 @@ static int		 editentry_set(char *name, c
 				       int editonly);
 static void		 editlist_populate(struct cam_device *device,
 					   int modepage, int page_control,
-					   int dbd, int retries, int timeout);
+					   int dbd, int retries, int timeout,
+					   int force10bytes);
 static void		 editlist_save(struct cam_device *device, int modepage,
 				       int page_control, int dbd, int retries,
-				       int timeout);
+				       int timeout, int force10bytes);
 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);
@@ -122,7 +126,7 @@ 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);
+				       int timeout, int force10bytes);
 static void		 cleanup_editfile(void);
 
 
@@ -527,42 +531,53 @@ 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)
+		  int dbd, int retries, int timeout, int force10bytes)
 {
 	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. */
+	u_int32_t data_length;
+	struct scsi_mode_header_6 *mh6;
+	struct scsi_mode_header_10 *mh10;
 	struct scsi_mode_page_header *mph;
 
 	STAILQ_INIT(&editlist);
 
 	/* Fetch changeable values; use to build initial editlist. */
 	mode_sense(device, modepage, 1, dbd, retries, timeout, data,
-		   sizeof(data));
+		   sizeof(data), force10bytes);
 
-	mh = (struct scsi_mode_header_6 *)data;
-	mph = MODE_PAGE_HEADER(mh);
-	mode_pars = MODE_PAGE_DATA(mph);
+	if (force10bytes) {
+		mh10 = (struct scsi_mode_header_10 *)data;
+		mph = MODE_PAGE_HEADER_10(mh10);
+		mode_pars = MODE_PAGE_DATA(mph);
+		data_length = scsi_2btoul(mh10->data_length);
+	} else {
+		mh6 = (struct scsi_mode_header_6 *)data;
+		mph = MODE_PAGE_HEADER_6(mh6);
+		mode_pars = MODE_PAGE_DATA(mph);
+		data_length = mh6->data_length;
+	}
 
 	/* Decode the value data, creating edit_entries for each value. */
-	buff_decode_visit(mode_pars, mh->data_length, format,
+	buff_decode_visit(mode_pars, data_length, 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);
+		   sizeof(data), force10bytes);
+	buff_decode_visit(mode_pars, data_length, format, editentry_update, 0);
 }
 
 static void
 editlist_save(struct cam_device *device, int modepage, int page_control,
-	      int dbd, int retries, int timeout)
+	      int dbd, int retries, int timeout, int force10bytes)
 {
 	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_header_6 *mh6;
+	struct scsi_mode_header_10 *mh10;
 	struct scsi_mode_page_header *mph;
+	u_int32_t data_length, mh_size, mh_blk_desc_len;
 
 	/* Make sure that something changed before continuing. */
 	if (! editlist_changed)
@@ -575,29 +590,50 @@ editlist_save(struct cam_device *device,
 	 *     now, we need mode_sense to find out the page length.
 	 */
 	mode_sense(device, modepage, page_control, dbd, retries, timeout, data,
-		   sizeof(data));
+		   sizeof(data), force10bytes);
 
 	/* Initial headers & offsets. */
-	mh = (struct scsi_mode_header_6 *)data;
-	mph = MODE_PAGE_HEADER(mh);
+	mh6 = (struct scsi_mode_header_6 *)data;
+	mh10 = (struct scsi_mode_header_10 *)data;
+	if (force10bytes) {
+		mh_size = sizeof(*mh10);
+		mph = MODE_PAGE_HEADER_10(mh10);
+		data_length = scsi_2btoul(mh10->data_length);
+	} else {
+		mh_size = sizeof(*mh6);
+		mph = MODE_PAGE_HEADER_6(mh6);
+		data_length = mh6->data_length;
+	}
+
 	mode_pars = MODE_PAGE_DATA(mph);
 
 	/* Encode the value data to be passed back to the device. */
-	buff_encode_visit(mode_pars, mh->data_length, format,
+	buff_encode_visit(mode_pars, data_length, format,
 	    editentry_save, 0);
 
 	/* Eliminate block descriptors. */
-	bcopy(mph, ((u_int8_t *)mh) + sizeof(*mh),
+	bcopy(mph, ((u_int8_t *)data) + mh_size,
 	    sizeof(*mph) + mph->page_length);
 
 	/* Recalculate headers & offsets. */
-	mh->blk_desc_len = 0;		/* No block descriptors. */
-	mh->dev_spec = 0;		/* Clear device-specific parameters. */
-	mph = MODE_PAGE_HEADER(mh);
+	/* Clear device-specific parameters. */
+	if (force10bytes) {
+		scsi_ulto2b(0, mh10->blk_desc_len);
+		mh10->dev_spec = 0;
+		scsi_ulto2b(0, mh10->data_length);
+		mph = MODE_PAGE_HEADER_10(mh10);
+		mh_blk_desc_len = scsi_2btoul(&mh6->blk_desc_len);
+	} else {
+		mh6->blk_desc_len = 0;
+		mh6->dev_spec = 0;
+		mh6->data_length = 0;
+		mph = MODE_PAGE_HEADER_6(mh6);
+		mh_blk_desc_len = mh6->blk_desc_len;
+	}
 	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. */
+	/* Isolate just the page code. */
+	mph->page_code &= SMS_PAGE_CODE;
 
 	/*
 	 * Write the changes back to the device. If the user editted control
@@ -606,8 +642,9 @@ editlist_save(struct cam_device *device,
 	 */
 	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);
+	    retries, timeout, (u_int8_t *)data,
+	    mh_size + mh_blk_desc_len + sizeof(*mph) + mph->page_length,
+	    force10bytes);
 }
 
 static int
@@ -777,19 +814,26 @@ modepage_edit(void)
 
 static void
 modepage_dump(struct cam_device *device, int page, int page_control, int dbd,
-	      int retries, int timeout)
+	      int retries, int timeout, int force10bytes)
 {
 	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_header_6 *mh6;
+	struct scsi_mode_header_10 *mh10;
 	struct scsi_mode_page_header *mph;
 	int indx;			/* Index for scanning mode params. */
 
 	mode_sense(device, page, page_control, dbd, retries, timeout, data,
-		   sizeof(data));
+		   sizeof(data), force10bytes);
+
+	mh6 = (struct scsi_mode_header_6 *)data;
+	mh10 = (struct scsi_mode_header_10 *)data;
+
+	if (force10bytes)
+		mph = MODE_PAGE_HEADER_10(mh10);
+	else
+		mph = MODE_PAGE_HEADER_6(mh6);
 
-	mh = (struct scsi_mode_header_6 *)data;
-	mph = MODE_PAGE_HEADER(mh);
 	mode_pars = MODE_PAGE_DATA(mph);
 
 	/* Print the raw mode page data with newlines each 8 bytes. */
@@ -812,7 +856,8 @@ cleanup_editfile(void)
 
 void
 mode_edit(struct cam_device *device, int page, int page_control, int dbd,
-	  int edit, int binary, int retry_count, int timeout)
+	  int edit, int binary, int retry_count, int timeout,
+	  int force10bytes)
 {
 	const char *pagedb_path;	/* Path to modepage database. */
 
@@ -842,7 +887,7 @@ mode_edit(struct cam_device *device, int
 		}
 
 		editlist_populate(device, page, page_control, dbd, retry_count,
-			timeout);
+			timeout, force10bytes);
 	}
 
 	if (edit) {
@@ -852,11 +897,11 @@ mode_edit(struct cam_device *device, int
 			    "(current) or page 3 (saved values)");
 		modepage_edit();
 		editlist_save(device, page, page_control, dbd, retry_count,
-			timeout);
+			timeout, force10bytes);
 	} else if (binary || STAILQ_EMPTY(&editlist)) {
 		/* Display without formatting information. */
 		modepage_dump(device, page, page_control, dbd, retry_count,
-		    timeout);
+		    timeout, force10bytes);
 	} else {
 		/* Display with format. */
 		modepage_write(stdout, 0);
@@ -865,7 +910,7 @@ mode_edit(struct cam_device *device, int
 
 void
 mode_list(struct cam_device *device, int page_control, int dbd,
-	  int retry_count, int timeout)
+	  int retry_count, int timeout, int force10bytes)
 {
 	u_int8_t data[MAX_COMMAND_SIZE];/* Buffer to hold sense data. */
 	u_int8_t *mode_pars;		/* Pointer to modepage params. */
@@ -885,7 +930,7 @@ mode_list(struct cam_device *device, int
 
 	/* 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));
+	    timeout, data, sizeof(data), force10bytes);
 
 	mh = (struct scsi_mode_header_6 *)data;
 	len = mh->blk_desc_len;		/* Skip block descriptors. */
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 167 bytes
Desc: not available
Url : http://lists.freebsd.org/pipermail/freebsd-current/attachments/20041006/ef49579f/attachment-0001.bin


More information about the freebsd-current mailing list