aboutsummaryrefslogtreecommitdiff
path: root/sbin
diff options
context:
space:
mode:
authorAlexander Motin <mav@FreeBSD.org>2019-08-07 14:45:10 +0000
committerAlexander Motin <mav@FreeBSD.org>2019-08-07 14:45:10 +0000
commit09128776167afe057fa4281c3d49f53b0ee52572 (patch)
tree4fb887f961a186fe25c2dcc4906b3d1a29553320 /sbin
parent3194b270146ad7bf128f3d2cb4866954801a81fe (diff)
downloadsrc-09128776167afe057fa4281c3d49f53b0ee52572.tar.gz
src-09128776167afe057fa4281c3d49f53b0ee52572.zip
Make `camcontrol modepage` support block descriptors.
It allows to read and write block descriptors alike to mode page parameters. It allows to change block size or short-stroke HDDs or overprovision SSDs. Depenting on -P parameter the change can be either persistent or till reset. In case of block size change device may need reformat after the setting. In case of SSD overprovisioning format or sanitize may be needed to really free the flash. During implementation appeared that csio_encode_visit() can not handle integers of more then 4 bytes, that makes 8-byte LBA handling awkward. I had to split it into two 4-byte halves now. MFC after: 1 week Relnotes: yes Sponsored by: iXsystems, Inc.
Notes
Notes: svn path=/head/; revision=350676
Diffstat (limited to 'sbin')
-rw-r--r--sbin/camcontrol/camcontrol.89
-rw-r--r--sbin/camcontrol/camcontrol.c35
-rw-r--r--sbin/camcontrol/camcontrol.h10
-rw-r--r--sbin/camcontrol/modeedit.c262
4 files changed, 273 insertions, 43 deletions
diff --git a/sbin/camcontrol/camcontrol.8 b/sbin/camcontrol/camcontrol.8
index b27dd7521d39..334f30390a3a 100644
--- a/sbin/camcontrol/camcontrol.8
+++ b/sbin/camcontrol/camcontrol.8
@@ -27,7 +27,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd July 30, 2019
+.Dd August 6, 2019
.Dt CAMCONTROL 8
.Os
.Sh NAME
@@ -125,6 +125,8 @@
.Op Fl 6
.Aq Fl m Ar page[,subpage] | Fl l
.Op Fl P Ar pgctl
+.Op Fl D
+.Op Fl L
.Op Fl b | Fl e
.Op Fl d
.Nm
@@ -733,6 +735,11 @@ If not specified,
starts with 10 byte commands and falls back to 6 byte on error.
.It Fl d
Disable block descriptors for mode sense.
+.It Fl D
+Display/edit block descriptors instead of mode page.
+.It Fl L
+Use long LBA block descriptors.
+Allows number of LBAs bigger then 2^^32.
.It Fl b
Displays mode page data in binary format.
.It Fl e
diff --git a/sbin/camcontrol/camcontrol.c b/sbin/camcontrol/camcontrol.c
index 27fa75efbceb..4d8c3fdc0332 100644
--- a/sbin/camcontrol/camcontrol.c
+++ b/sbin/camcontrol/camcontrol.c
@@ -221,7 +221,7 @@ static struct camcontrol_opts option_table[] = {
{"devlist", CAM_CMD_DEVTREE, CAM_ARG_NONE, "-b"},
{"devtype", CAM_CMD_DEVTYPE, CAM_ARG_NONE, ""},
{"periphlist", CAM_CMD_DEVLIST, CAM_ARG_NONE, NULL},
- {"modepage", CAM_CMD_MODE_PAGE, CAM_ARG_NONE, "6bdelm:P:"},
+ {"modepage", CAM_CMD_MODE_PAGE, CAM_ARG_NONE, "6bdelm:DLP:"},
{"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},
@@ -4586,9 +4586,9 @@ reassignblocks(struct cam_device *device, u_int32_t *blocks, int num_blocks)
#endif
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, u_int8_t *data,
- int datalen)
+mode_sense(struct cam_device *device, int *cdb_len, int dbd, int llbaa, int pc,
+ int page, int subpage, int task_attr, int retry_count, int timeout,
+ u_int8_t *data, int datalen)
{
union ccb *ccb;
int error_code, sense_key, asc, ascq;
@@ -4620,6 +4620,11 @@ retry:
/* minimum_cmd_size */ *cdb_len,
/* sense_len */ SSD_FULL_SIZE,
/* timeout */ timeout ? timeout : 5000);
+ if (llbaa && ccb->csio.cdb_len == 10) {
+ struct scsi_mode_sense_10 *cdb =
+ (struct scsi_mode_sense_10 *)ccb->csio.cdb_io.cdb_bytes;
+ cdb->byte2 |= SMS10_LLBAA;
+ }
/* Record what CDB size the above function really set. */
*cdb_len = ccb->csio.cdb_len;
@@ -4711,8 +4716,8 @@ modepage(struct cam_device *device, int argc, char **argv, char *combinedopt,
int task_attr, int retry_count, int timeout)
{
char *str_subpage;
- int c, page = -1, subpage = -1, pc = 0;
- int binary = 0, cdb_len = 10, dbd = 0, edit = 0, list = 0;
+ int c, page = -1, subpage = -1, pc = 0, llbaa = 0;
+ int binary = 0, cdb_len = 10, dbd = 0, desc = 0, edit = 0, list = 0;
while ((c = getopt(argc, argv, combinedopt)) != -1) {
switch(c) {
@@ -4744,6 +4749,12 @@ modepage(struct cam_device *device, int argc, char **argv, char *combinedopt,
if (subpage < 0)
errx(1, "invalid mode subpage %d", subpage);
break;
+ case 'D':
+ desc = 1;
+ break;
+ case 'L':
+ llbaa = 1;
+ break;
case 'P':
pc = strtol(optarg, NULL, 0);
if ((pc < 0) || (pc > 3))
@@ -4754,15 +4765,21 @@ modepage(struct cam_device *device, int argc, char **argv, char *combinedopt,
}
}
- if (page == -1 && list == 0)
+ if (page == -1 && desc == 0 && list == 0)
errx(1, "you must specify a mode page!");
+ if (dbd && desc)
+ errx(1, "-d and -D are incompatible!");
+
+ if (llbaa && cdb_len != 10)
+ errx(1, "LLBAA bit is not present in MODE SENSE(6)!");
+
if (list != 0) {
mode_list(device, cdb_len, dbd, pc, list > 1, task_attr,
retry_count, timeout);
} else {
- mode_edit(device, cdb_len, dbd, pc, page, subpage, edit,
- binary, task_attr, retry_count, timeout);
+ mode_edit(device, cdb_len, desc, dbd, llbaa, pc, page, subpage,
+ edit, binary, task_attr, retry_count, timeout);
}
}
diff --git a/sbin/camcontrol/camcontrol.h b/sbin/camcontrol/camcontrol.h
index d876c6e83a20..85f2e8658fe8 100644
--- a/sbin/camcontrol/camcontrol.h
+++ b/sbin/camcontrol/camcontrol.h
@@ -88,15 +88,15 @@ int epc(struct cam_device *device, int argc, char **argv, char *combinedopt,
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 *cdb_len, int dbd, int pc,
- int page, int subpage, int task_attr, int retry_count,
+void mode_sense(struct cam_device *device, int *cdb_len, int dbd, int llbaa,
+ 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_edit(struct cam_device *device, int cdb_len, int desc, int dbd,
+ int llbaa, 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 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,
diff --git a/sbin/camcontrol/modeedit.c b/sbin/camcontrol/modeedit.c
index b13da6f14a6a..f6648abb2c35 100644
--- a/sbin/camcontrol/modeedit.c
+++ b/sbin/camcontrol/modeedit.c
@@ -33,6 +33,7 @@ __FBSDID("$FreeBSD$");
#include <sys/queue.h>
#include <sys/types.h>
+#include <sys/sbuf.h>
#include <assert.h>
#include <ctype.h>
@@ -96,6 +97,8 @@ static void editentry_create(void *hook, int letter, void *arg,
int count, char *name);
static void editentry_update(void *hook, int letter, void *arg,
int count, char *name);
+static void editentry_create_desc(void *hook, int letter, void *arg,
+ int count, char *name);
static int editentry_save(void *hook, char *name);
static struct editentry *editentry_lookup(char *name);
static int editentry_set(char *name, char *newvalue,
@@ -103,9 +106,16 @@ static int editentry_set(char *name, char *newvalue,
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_populate_desc(struct cam_device *device,
+ int cdb_len, int llbaa, 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 editlist_save_desc(struct cam_device *device, int cdb_len,
+ int llbaa, 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,
@@ -116,6 +126,10 @@ static void modepage_edit(void);
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 modepage_dump_desc(struct cam_device *device,
+ int cdb_len, int llbaa, int pc, int page,
+ int subpage, int task_attr, int retries,
+ int timeout);
static void cleanup_editfile(void);
@@ -182,6 +196,43 @@ editentry_update(void *hook __unused, int letter, void *arg, int count,
}
}
+static void
+editentry_create_desc(void *hook __unused, int letter, void *arg, int count,
+ char *name)
+{
+ struct editentry *newentry; /* Buffer to hold new entry. */
+
+ /* Allocate memory for the new entry and a copy of the entry name. */
+ if ((newentry = malloc(sizeof(struct editentry))) == NULL ||
+ (newentry->name = strdup(name)) == NULL)
+ err(EX_OSERR, NULL);
+
+ /* Trim any trailing whitespace for the entry name. */
+ RTRIM(newentry->name);
+
+ newentry->editable = 1;
+ newentry->type = letter;
+ newentry->size = count;
+ newentry->value.svalue = NULL;
+
+ STAILQ_INSERT_TAIL(&editlist, newentry, link);
+
+ switch (letter) {
+ case 'i': /* Byte-sized integral type. */
+ case 'b': /* Bit-sized integral types. */
+ case 't':
+ newentry->value.ivalue = (intptr_t)arg;
+ break;
+
+ case 'c': /* Character array. */
+ case 'z': /* Null-padded string. */
+ editentry_set(name, (char *)arg, 0);
+ break;
+ default:
+ ; /* NOTREACHED */
+ }
+}
+
static int
editentry_save(void *hook __unused, char *name)
{
@@ -238,7 +289,7 @@ editentry_set(char *name, char *newvalue, int editonly)
struct editentry *dest; /* Modepage entry to update. */
char *cval; /* Pointer to new string value. */
char *convertend; /* End-of-conversion pointer. */
- int ival; /* New integral value. */
+ long long ival, newival; /* New integral value. */
int resolution; /* Resolution in bits for integer conversion. */
/*
@@ -248,7 +299,7 @@ editentry_set(char *name, char *newvalue, int editonly)
* currently workaround it (even for int64's), so we have to kludge it.
*/
#define RESOLUTION_MAX(size) ((resolution * (size) == 32)? \
- INT_MAX: (1 << (resolution * (size))) - 1)
+ UINT_MAX: (1 << (resolution * (size))) - 1)
assert(newvalue != NULL);
if (*newvalue == '\0')
@@ -265,13 +316,13 @@ editentry_set(char *name, char *newvalue, int editonly)
case 't':
/* Convert the value string to an integer. */
resolution = (dest->type == 'i')? 8: 1;
- ival = (int)strtol(newvalue, &convertend, 0);
+ ival = strtoll(newvalue, &convertend, 0);
if (*convertend != '\0')
returnerr(EINVAL);
if (ival > RESOLUTION_MAX(dest->size) || ival < 0) {
- int newival = (ival < 0)? 0: RESOLUTION_MAX(dest->size);
- warnx("value %d is out of range for entry %s; clipping "
- "to %d", ival, name, newival);
+ newival = (ival < 0) ? 0 : RESOLUTION_MAX(dest->size);
+ warnx("value %lld is out of range for entry %s; "
+ "clipping to %lld", ival, name, newival);
ival = newival;
}
if (dest->value.ivalue != ival)
@@ -548,7 +599,7 @@ 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)
{
- u_int8_t data[MAX_DATA_SIZE];/* Buffer to hold sense data. */
+ u_int8_t data[MAX_DATA_SIZE]; /* Buffer to hold mode parameters. */
u_int8_t *mode_pars; /* Pointer to modepage params. */
struct scsi_mode_page_header *mph;
struct scsi_mode_page_header_sp *mphsp;
@@ -557,8 +608,8 @@ editlist_populate(struct cam_device *device, int cdb_len, int dbd, int pc,
STAILQ_INIT(&editlist);
/* Fetch changeable values; use to build initial editlist. */
- mode_sense(device, &cdb_len, dbd, 1, page, subpage, task_attr, retries,
- timeout, data, sizeof(data));
+ mode_sense(device, &cdb_len, dbd, 0, 1, page, subpage, task_attr,
+ retries, timeout, data, sizeof(data));
if (cdb_len == 6) {
struct scsi_mode_header_6 *mh =
@@ -583,16 +634,77 @@ editlist_populate(struct cam_device *device, int cdb_len, int dbd, int pc,
buff_decode_visit(mode_pars, len, format, editentry_create, 0);
/* Fetch the current/saved values; use to set editentry values. */
- mode_sense(device, &cdb_len, dbd, pc, page, subpage, task_attr,
+ mode_sense(device, &cdb_len, dbd, 0, pc, page, subpage, task_attr,
retries, timeout, data, sizeof(data));
buff_decode_visit(mode_pars, len, format, editentry_update, 0);
}
static void
+editlist_populate_desc(struct cam_device *device, int cdb_len, int llbaa, int pc,
+ int page, int subpage, int task_attr, int retries, int timeout)
+{
+ uint8_t data[MAX_DATA_SIZE]; /* Buffer to hold mode parameters. */
+ uint8_t *desc; /* Pointer to block descriptor. */
+ char num[8];
+ struct sbuf sb;
+ size_t len;
+ u_int longlba, dlen, i;
+
+ STAILQ_INIT(&editlist);
+
+ /* Fetch the current/saved values. */
+ mode_sense(device, &cdb_len, 0, llbaa, pc, page, subpage, task_attr,
+ retries, timeout, data, sizeof(data));
+
+ if (cdb_len == 6) {
+ struct scsi_mode_header_6 *mh =
+ (struct scsi_mode_header_6 *)data;
+ desc = (uint8_t *)(mh + 1);
+ len = mh->blk_desc_len;
+ longlba = 0;
+ } else {
+ struct scsi_mode_header_10 *mh =
+ (struct scsi_mode_header_10 *)data;
+ desc = (uint8_t *)(mh + 1);
+ len = scsi_2btoul(mh->blk_desc_len);
+ longlba = (mh->flags & SMH_LONGLBA) != 0;
+ }
+ dlen = longlba ? 16 : 8;
+ len = MIN(len, sizeof(data) - (desc - data));
+
+ sbuf_new(&sb, format, sizeof(format), SBUF_FIXEDLEN);
+ num[0] = 0;
+ for (i = 0; i * dlen < len; i++) {
+ if (i > 0)
+ snprintf(num, sizeof(num), " %d", i + 1);
+ if (longlba) {
+ sbuf_printf(&sb, "{Number of Logical Blocks%s High} i4\n", num);
+ sbuf_printf(&sb, "{Number of Logical Blocks%s} i4\n", num);
+ sbuf_cat(&sb, "{Reserved} *i4\n");
+ sbuf_printf(&sb, "{Logical Block Length%s} i4\n", num);
+ } else if (device->pd_type == T_DIRECT) {
+ sbuf_printf(&sb, "{Number of Logical Blocks%s} i4\n", num);
+ sbuf_cat(&sb, "{Reserved} *i1\n");
+ sbuf_printf(&sb, "{Logical Block Length%s} i3\n", num);
+ } else {
+ sbuf_printf(&sb, "{Density Code%s} i1\n", num);
+ sbuf_printf(&sb, "{Number of Logical Blocks%s} i3\n", num);
+ sbuf_cat(&sb, "{Reserved} *i1\n");
+ sbuf_printf(&sb, "{Logical Block Length%s} i3\n", num);
+ }
+ }
+ sbuf_finish(&sb);
+ sbuf_delete(&sb);
+
+ /* Decode the value data, creating edit_entries for each value. */
+ buff_decode_visit(desc, len, format, editentry_create_desc, 0);
+}
+
+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)
{
- u_int8_t data[MAX_DATA_SIZE];/* Buffer to hold sense data. */
+ u_int8_t data[MAX_DATA_SIZE]; /* Buffer to hold mode parameters. */
u_int8_t *mode_pars; /* Pointer to modepage params. */
struct scsi_mode_page_header *mph;
struct scsi_mode_page_header_sp *mphsp;
@@ -603,7 +715,7 @@ editlist_save(struct cam_device *device, int cdb_len, int dbd, int pc,
return;
/* Preload the CDB buffer with the current mode page data. */
- mode_sense(device, &cdb_len, dbd, pc, page, subpage, task_attr,
+ mode_sense(device, &cdb_len, dbd, 0, pc, page, subpage, task_attr,
retries, timeout, data, sizeof(data));
/* Initial headers & offsets. */
@@ -676,6 +788,56 @@ editlist_save(struct cam_device *device, int cdb_len, int dbd, int pc,
task_attr, retries, timeout, data, hlen + mphlen + len);
}
+static void
+editlist_save_desc(struct cam_device *device, int cdb_len, int llbaa, int pc,
+ int page, int subpage, int task_attr, int retries, int timeout)
+{
+ uint8_t data[MAX_DATA_SIZE]; /* Buffer to hold mode parameters. */
+ uint8_t *desc; /* Pointer to block descriptor. */
+ size_t len, hlen;
+
+ /* Make sure that something changed before continuing. */
+ if (! editlist_changed)
+ return;
+
+ /* Preload the CDB buffer with the current mode page data. */
+ mode_sense(device, &cdb_len, 0, llbaa, pc, page, subpage, task_attr,
+ retries, timeout, data, sizeof(data));
+
+ /* Initial headers & offsets. */
+ if (cdb_len == 6) {
+ struct scsi_mode_header_6 *mh =
+ (struct scsi_mode_header_6 *)data;
+ hlen = sizeof(*mh);
+ desc = (uint8_t *)(mh + 1);
+ len = mh->blk_desc_len;
+ mh->data_length = 0; /* Reserved for MODE SELECT command. */
+ if (device->pd_type != T_SEQUENTIAL)
+ mh->dev_spec = 0; /* See comment above */
+ } else {
+ struct scsi_mode_header_10 *mh =
+ (struct scsi_mode_header_10 *)data;
+ hlen = sizeof(*mh);
+ desc = (uint8_t *)(mh + 1);
+ len = scsi_2btoul(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 */
+ }
+ len = MIN(len, sizeof(data) - (desc - data));
+
+ /* Encode the value data to be passed back to the device. */
+ buff_encode_visit(desc, len, format, editentry_save, 0);
+
+ /*
+ * 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, cdb_len, (pc << PAGE_CTRL_SHIFT == SMS_PAGE_CTRL_SAVED),
+ task_attr, retries, timeout, data, hlen + len);
+}
+
static int
modepage_write(FILE *file, int editonly)
{
@@ -689,7 +851,7 @@ modepage_write(FILE *file, int editonly)
fprintf(file, "%s: %s\n", scan->name,
scan->value.svalue);
} else {
- fprintf(file, "%s: %d\n", scan->name,
+ fprintf(file, "%s: %u\n", scan->name,
scan->value.ivalue);
}
}
@@ -845,13 +1007,13 @@ 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)
{
- u_int8_t data[MAX_DATA_SIZE];/* Buffer to hold sense data. */
+ u_int8_t data[MAX_DATA_SIZE]; /* Buffer to hold mode parameters. */
u_int8_t *mode_pars; /* Pointer to modepage params. */
struct scsi_mode_page_header *mph;
struct scsi_mode_page_header_sp *mphsp;
size_t indx, len;
- mode_sense(device, &cdb_len, dbd, pc, page, subpage, task_attr,
+ mode_sense(device, &cdb_len, dbd, 0, pc, page, subpage, task_attr,
retries, timeout, data, sizeof(data));
if (cdb_len == 6) {
@@ -880,6 +1042,37 @@ modepage_dump(struct cam_device *device, int cdb_len, int dbd, int pc,
}
putchar('\n');
}
+static void
+modepage_dump_desc(struct cam_device *device, int cdb_len, int llbaa, int pc,
+ int page, int subpage, int task_attr, int retries, int timeout)
+{
+ uint8_t data[MAX_DATA_SIZE]; /* Buffer to hold mode parameters. */
+ uint8_t *desc; /* Pointer to block descriptor. */
+ size_t indx, len;
+
+ mode_sense(device, &cdb_len, 0, llbaa, pc, page, subpage, task_attr,
+ retries, timeout, data, sizeof(data));
+
+ if (cdb_len == 6) {
+ struct scsi_mode_header_6 *mh =
+ (struct scsi_mode_header_6 *)data;
+ desc = (uint8_t *)(mh + 1);
+ len = mh->blk_desc_len;
+ } else {
+ struct scsi_mode_header_10 *mh =
+ (struct scsi_mode_header_10 *)data;
+ desc = (uint8_t *)(mh + 1);
+ len = scsi_2btoul(mh->blk_desc_len);
+ }
+ len = MIN(len, sizeof(data) - (desc - data));
+
+ /* Print the raw mode page data with newlines each 8 bytes. */
+ for (indx = 0; indx < len; indx++) {
+ printf("%02x%c", desc[indx],
+ (((indx + 1) % 8) == 0) ? '\n' : ' ');
+ }
+ putchar('\n');
+}
static void
cleanup_editfile(void)
@@ -892,16 +1085,19 @@ cleanup_editfile(void)
}
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)
+mode_edit(struct cam_device *device, int cdb_len, int desc, int dbd, int llbaa,
+ 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. */
- if (edit && binary)
- errx(EX_USAGE, "cannot edit in binary mode.");
-
- if (! binary) {
+ if (binary) {
+ if (edit)
+ errx(EX_USAGE, "cannot edit in binary mode.");
+ } else if (desc) {
+ editlist_populate_desc(device, cdb_len, llbaa, pc, page,
+ subpage, task_attr, retry_count, timeout);
+ } else {
if ((pagedb_path = getenv("SCSI_MODES")) == NULL)
pagedb_path = DEFAULT_SCSI_MODE_DB;
@@ -935,12 +1131,22 @@ mode_edit(struct cam_device *device, int cdb_len, int dbd, int pc, int page,
errx(EX_USAGE, "it only makes sense to edit page 0 "
"(current) or page 3 (saved values)");
modepage_edit();
- editlist_save(device, cdb_len, dbd, pc, page, subpage,
- task_attr, retry_count, timeout);
+ if (desc) {
+ editlist_save_desc(device, cdb_len, llbaa, pc, page,
+ subpage, task_attr, retry_count, timeout);
+ } else {
+ 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, cdb_len, dbd, pc, page, subpage,
- task_attr, retry_count, timeout);
+ if (desc) {
+ modepage_dump_desc(device, cdb_len, llbaa, pc, page,
+ subpage, task_attr, retry_count, timeout);
+ } else {
+ modepage_dump(device, cdb_len, dbd, pc, page, subpage,
+ task_attr, retry_count, timeout);
+ }
} else {
/* Display with format. */
modepage_write(stdout, 0);
@@ -951,7 +1157,7 @@ void
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_DATA_SIZE];/* Buffer to hold sense data. */
+ u_int8_t data[MAX_DATA_SIZE]; /* Buffer to hold mode parameters. */
struct scsi_mode_page_header *mph;
struct scsi_mode_page_header_sp *mphsp;
struct pagename *nameentry;
@@ -967,7 +1173,7 @@ mode_list(struct cam_device *device, int cdb_len, int dbd, int pc, int subpages,
}
/* Build the list of all mode pages by querying the "all pages" page. */
- mode_sense(device, &cdb_len, dbd, pc, SMS_ALL_PAGES_PAGE,
+ mode_sense(device, &cdb_len, dbd, 0, pc, SMS_ALL_PAGES_PAGE,
subpages ? SMS_SUBPAGE_ALL : 0,
task_attr, retry_count, timeout, data, sizeof(data));