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

Bruce M Simpson bms at spc.org
Wed Oct 6 02:51:28 PDT 2004


I need some advice regarding the handling of 10-byte MODE SENSE/SELECT.

Apologies if this is more appropriate for freebsd-scsi@ to which I am
not currently subscribed.

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.

This is probably not the cleanest way but it avoids using a global flag
for such a thing, which might be cleaner.

Note however that the mode page layouts in src/share/misc/scsi_modes
only seem to be correct for the 6-byte MODE_SENSE and MODE_SELECT
which are not supported for such devices; for 10-byte forms the
mode page layout seems to be subtly different.

Could someone more knowledgeable about the inner workings of CAM and
SCSI in FreeBSD than I advise how we could go about teaching camcontrol(8)
to fetch and display mode pages in a human-readable manner?
(i.e. without necessarily implementing a new utility right away)

This is necessary in order to extract the geometry for a USB floppy
drive in order that track-by-track format may be implemented; the
FORMAT UNIT command for USB floppy drives requires such behaviour
as per the UFI Specification (usbmass-ufi10.pdf).

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 09:17:07 -0000
@@ -110,10 +110,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 +123,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,7 +528,7 @@ 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. */
@@ -538,7 +539,7 @@ editlist_populate(struct cam_device *dev
 
 	/* 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);
@@ -550,14 +551,14 @@ editlist_populate(struct cam_device *dev
 
 	/* Fetch the current/saved values; use to set editentry values. */
 	mode_sense(device, modepage, page_control, dbd, retries, timeout, data,
-		   sizeof(data));
+		   sizeof(data), force10bytes);
 	buff_decode_visit(mode_pars, mh->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. */
@@ -575,7 +576,7 @@ 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;
@@ -607,7 +608,8 @@ 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);
+	    sizeof(*mh) + mh->blk_desc_len + sizeof(*mph) + mph->page_length,
+	    force10bytes);
 }
 
 static int
@@ -777,7 +779,7 @@ 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. */
@@ -786,7 +788,7 @@ modepage_dump(struct cam_device *device,
 	int indx;			/* Index for scanning mode params. */
 
 	mode_sense(device, page, page_control, dbd, retries, timeout, data,
-		   sizeof(data));
+		   sizeof(data), force10bytes);
 
 	mh = (struct scsi_mode_header_6 *)data;
 	mph = MODE_PAGE_HEADER(mh);
@@ -812,7 +814,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 +845,7 @@ mode_edit(struct cam_device *device, int
 		}
 
 		editlist_populate(device, page, page_control, dbd, retry_count,
-			timeout);
+			timeout, force10bytes);
 	}
 
 	if (edit) {
@@ -852,11 +855,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 +868,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 +888,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/a13309f3/attachment.bin


More information about the freebsd-current mailing list