Subject: bin/29165: new scsictl(8) {get,set}errrecov commands
To: None <gnats-admin@netbsd.org, netbsd-bugs@netbsd.org>
From: Greg A. Woods <woods@weird.com>
List: netbsd-bugs
Date: 01/31/2005 01:28:00
>Number: 29165
>Category: bin
>Synopsis: new scsictl(8) {get,set}errrecov commands
>Confidential: no
>Severity: non-critical
>Priority: medium
>Responsible: bin-bug-people
>State: open
>Class: change-request
>Submitter-Id: net
>Arrival-Date: Mon Jan 31 01:28:00 +0000 2005
>Originator: Greg A. Woods
>Release: NetBSD-current 2005/01/29
>Organization:
Planix, Inc.; Toronto, Ontario; Canada
>Environment:
System: NetBSD
>Description:
scsictl(8) should have commands to view and change the automatic
read and write recovery bits in mode page 0x01 of block devices.
>How-To-Repeat:
Try to avoid having to use the ancient scsi(8) tool I ported
from FreeBSD oh so long ago just to check/enable ARRE & AWRE.
>Fix:
(note these changes are merged to -current from my netbsd-1-6 branch and
have only been tested fully on the latter)
(note also there seems to have been a missing byte in struct page_disk_format)
(note this code doesn't honour the SCSI spec. w.r.t. how the page length
is supposed to be handled and as a result some values could be missed or
clobbered on some devices)
(note too the hints about generic mode page handling :-)
Index: sys/dev/scsipi/scsi_disk.h
===================================================================
RCS file: /cvs/master/m-NetBSD/main/src/sys/dev/scsipi/scsi_disk.h,v
retrieving revision 1.28
diff -u -r1.28 scsi_disk.h
--- sys/dev/scsipi/scsi_disk.h 7 Jan 2005 02:08:34 -0000 1.28
+++ sys/dev/scsipi/scsi_disk.h 31 Jan 2005 00:31:21 -0000
@@ -236,6 +236,27 @@
union scsi_disk_pages {
#define DISK_PGCODE 0x3F /* only 6 bits valid */
+ struct page_err_recov {
+ u_int8_t pg_code; /* page code (should be 1) */
+ u_int8_t pg_length; /* page length (should be 0x09) */
+ u_int8_t flags;
+#define ERR_RECOV_DCR 0x01 /* disable correction */
+#define ERR_RECOV_DTE 0x02 /* disable transfer on error */
+#define ERR_RECOV_PER 0x04 /* post error */
+#define ERR_RECOV_EEC 0x08 /* enable early correction */
+#define ERR_RECOV_RC 0x10 /* read continuous */
+#define ERR_RECOV_TB 0x20 /* transfer block */
+#define ERR_RECOV_ARRE 0x40 /* automatic read recovery enable */
+#define ERR_RECOV_AWRE 0x80 /* automatic write recovery enable */
+ u_int8_t rd_retry_ct; /* read retry count */
+ u_int8_t corr_span; /* correction span */
+ u_int8_t hd_off_ct; /* head offset count */
+ u_int8_t dat_strb_off_ct; /* data strobe offset count */
+ u_int8_t reserved1;
+ u_int8_t wr_retry_ct; /* write retry count */
+ u_int8_t reserved2;
+ u_int8_t recov_tm_lim[2]; /* recovery time limit x10 ms */
+ } disk_format;
struct page_disk_format {
u_int8_t pg_code; /* page code (should be 3) */
u_int8_t pg_length; /* page length (should be 0x16) */
@@ -253,6 +274,7 @@
#define DISK_FMT_RMB 0x20
#define DISK_FMT_HSEC 0x40
#define DISK_FMT_SSEC 0x80
+ u_int8_t reserved1;
u_int8_t reserved2;
u_int8_t reserved3;
} disk_format;
Index: sbin/scsictl/scsictl.c
===================================================================
RCS file: /cvs/master/m-NetBSD/main/src/sbin/scsictl/scsictl.c,v
retrieving revision 1.25
diff -u -r1.25 scsictl.c
--- sbin/scsictl/scsictl.c 7 Jan 2005 02:08:34 -0000 1.25
+++ sbin/scsictl/scsictl.c 31 Jan 2005 00:44:17 -0000
@@ -99,6 +99,11 @@
void device_getcache __P((int, char *[]));
void device_setcache __P((int, char *[]));
void device_flushcache __P((int, char *[]));
+void device_geterrrecov __P((int, char *[]));
+void device_seterrrecov __P((int, char *[]));
+#if 0
+void device_modesense __P((int, char *[]));
+#endif
struct command device_commands[] = {
{ "defects", "[primary] [grown] [block|byte|physical]",
@@ -118,6 +123,12 @@
{ "getcache", "", device_getcache },
{ "setcache", "none|r|w|rw [save]", device_setcache },
{ "flushcache", "", device_flushcache },
+ { "geterrrecov","", device_geterrrecov },
+ { "seterrrecov","none|r|w|rw [save]", device_seterrrecov },
+#if 0
+ { "modesense", "pagenum [cur|chg|def|svd]", device_modesense },
+ { "modeedit", "pagenum", device_modeedit },
+#endif
{ NULL, NULL, NULL },
};
@@ -517,6 +528,7 @@
* Get the DISK FORMAT mode page. SCSI-2 recommends specifying the
* interleave read from this page in the FORMAT UNIT command.
*/
+ /* XXX 0x03 == Mode-page-03; 0x00 == current-values */
scsi_mode_sense(fd, 0x03, 0x00, &mode_page, sizeof(mode_page));
j = (mode_page.format_page.bytes_s[0] << 8) |
@@ -872,6 +884,10 @@
if (argc != 0)
usage();
+ /*
+ * Get the CACHING mode page.
+ */
+ /* XXX 0x08 == Mode-page-08; 0x00 == current-values */
scsi_mode_sense(fd, 0x08, 0x00, &data, sizeof(data));
if ((data.caching_params.flags & (CACHING_RCD|CACHING_WCE)) ==
@@ -926,6 +942,10 @@
usage();
}
+ /*
+ * Get the CACHING mode page.
+ */
+ /* XXX 0x08 == Mode-page-08; 0x00 == current-values */
scsi_mode_sense(fd, 0x08, 0x00, &data, sizeof(data));
data.caching_params.pg_code &= PGCODE_MASK;
@@ -972,6 +992,114 @@
}
/*
+ * device_geterrrecov:
+ *
+ * Get the automatic R/W Error Recovery parameters for a SCSI disk.
+ */
+void
+device_geterrrecov(argc, argv)
+ int argc;
+ char *argv[];
+{
+ struct {
+ struct scsipi_mode_header header;
+ struct scsi_blk_desc blk_desc;
+ struct page_err_recov err_recov_params;
+ } data;
+
+ /* No arguments. */
+ if (argc != 0)
+ usage();
+
+ /*
+ * Get the READ-WRITE ERROR RECOVERY mode page.
+ */
+ /* XXX 0x01 == Mode-page-01; 0x00 == current-values */
+ scsi_mode_sense(fd, 0x01, 0x00, &data, sizeof(data));
+
+ printf("%s: automatic write reallocation %senabled\n", dvname,
+ (data.err_recov_params.flags & ERR_RECOV_AWRE) ? "" : "not ");
+ printf("%s: automatic read reallocation %senabled\n", dvname,
+ (data.err_recov_params.flags & ERR_RECOV_ARRE) ? "" : "not ");
+ printf("%s: read retry count: %u\n", dvname,
+ (unsigned int) data.err_recov_params.rd_retry_ct);
+ printf("%s: correction span: %u\n", dvname,
+ (unsigned int) data.err_recov_params.corr_span);
+ printf("%s: head offset count: %u\n", dvname,
+ (unsigned int) data.err_recov_params.hd_off_ct);
+ printf("%s: data strobe offset count: %u\n", dvname,
+ (unsigned int) data.err_recov_params.dat_strb_off_ct);
+ printf("%s: write retry count: %u\n", dvname,
+ (unsigned int) data.err_recov_params.wr_retry_ct);
+ printf("%s: recovery time limit: %lu milliseconds\n", dvname,
+ (unsigned long) (_2btol(data.err_recov_params.recov_tm_lim) * 10));
+ printf("%s: error recovery parameters are %ssavable\n", dvname,
+ (data.err_recov_params.pg_code & PGCODE_PS) ? "" : "not ");
+}
+
+/*
+ * device_seterrrecov:
+ *
+ * Set the automatic R/W Error Recovery parameters for a SCSI disk.
+ */
+void
+device_seterrrecov(argc, argv)
+ int argc;
+ char *argv[];
+{
+ struct {
+ struct scsipi_mode_header header;
+ struct scsi_blk_desc blk_desc;
+ struct page_err_recov err_recov_params;
+ } data;
+ int dlen;
+ u_int8_t flags, byte2;
+
+ if (argc > 2 || argc == 0)
+ usage();
+
+ if (strcmp(argv[0], "none") == 0)
+ flags = 0;
+ else if (strcmp(argv[0], "r") == 0)
+ flags = ERR_RECOV_ARRE;
+ else if (strcmp(argv[0], "w") == 0)
+ flags = ERR_RECOV_AWRE;
+ else if (strcmp(argv[0], "rw") == 0)
+ flags = ERR_RECOV_ARRE|ERR_RECOV_AWRE;
+ else
+ usage();
+
+ if (argc == 2) {
+ /* XXX could allow specification of retry count(s) and time limit too? */
+ if (strcmp(argv[1], "save") == 0)
+ byte2 = SMS_SP;
+ else
+ usage();
+ }
+
+ /*
+ * Get the ERROR RECOVERY mode page.
+ */
+ /* XXX 0x08 == Mode-page-01; 0x00 == current-values */
+ scsi_mode_sense(fd, 0x01, 0x00, &data, sizeof(data));
+
+ data.err_recov_params.pg_code &= PGCODE_MASK;
+ data.err_recov_params.flags =
+ (data.err_recov_params.flags & ~(ERR_RECOV_AWRE|ERR_RECOV_ARRE)) | flags;
+
+ data.header.data_length = 0;
+
+ /* XXX what if sizeof(data) does not match dlen? */
+ dlen = sizeof(data.header) + sizeof(data.blk_desc) + 2 +
+ data.err_recov_params.pg_length;
+
+ /*
+ * save the (possibly modified) ERROR RECOVERY mode page.
+ */
+ scsi_mode_select(fd, byte2, &data, dlen);
+}
+
+/*
* device_prevent:
*
* Issue a prevent to a SCSI device.
Index: sbin/scsictl/scsictl.8
===================================================================
RCS file: /cvs/master/m-NetBSD/main/src/sbin/scsictl/scsictl.8,v
retrieving revision 1.22
diff -u -r1.22 scsictl.8
--- sbin/scsictl/scsictl.8 7 Jan 2005 02:13:13 -0000 1.22
+++ sbin/scsictl/scsictl.8 31 Jan 2005 00:45:05 -0000
@@ -203,6 +203,28 @@
.Nm flushcache
.Pp
Explicitly flushes the write cache.
+.Pp
+.Nm geterrrecov
+.Pp
+Returns basic error recovery parameters for the device.
+.Pp
+.Nm seterrrecov
+.Ar none|r|w|rw
+.Op Ar save
+.Pp
+Set automatic error recovery parameters for the device. Automatic error
+recovery may be disabled
+.Pq none ,
+just the automatic read recovery enabled
+.Pq r ,
+or just the automatic write recovery enabled
+.Pq w ,
+or both read and write automatic recovery can be enabled
+.Pq rw .
+If the drive's error recovery parameters are savable, specifying
+.Ar save
+after the error recovery enable state will cause the parameters to be
+saved in non-volatile storage.
.Sh BUS COMMANDS
The following commands are supported for SCSI busses:
.Pp