svn commit: r351581 - stable/11/sbin/camcontrol
Alexander Motin
mav at FreeBSD.org
Wed Aug 28 20:22:15 UTC 2019
Author: mav
Date: Wed Aug 28 20:22:14 2019
New Revision: 351581
URL: https://svnweb.freebsd.org/changeset/base/351581
Log:
MFC r350457: Make `camcontrol modepage` to use 10 byte commands.
While old devices may not support 10 byte MODE SENSE/MODE SELECT commands,
new ones may not be able to report all mode pages with 6 byte commands.
This patch makes camcontrol by default start with 10 byte commands and
fall back to 6 byte on ILLEGAL REQUEST error, or 6 byte can be forced.
Modified:
stable/11/sbin/camcontrol/camcontrol.8
stable/11/sbin/camcontrol/camcontrol.c
stable/11/sbin/camcontrol/camcontrol.h
stable/11/sbin/camcontrol/modeedit.c
Directory Properties:
stable/11/ (props changed)
Modified: stable/11/sbin/camcontrol/camcontrol.8
==============================================================================
--- stable/11/sbin/camcontrol/camcontrol.8 Wed Aug 28 20:21:34 2019 (r351580)
+++ stable/11/sbin/camcontrol/camcontrol.8 Wed Aug 28 20:22:14 2019 (r351581)
@@ -27,7 +27,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd July 25, 2019
+.Dd July 30, 2019
.Dt CAMCONTROL 8
.Os
.Sh NAME
@@ -122,6 +122,7 @@
.Ic modepage
.Op device id
.Op generic args
+.Op Fl 6
.Aq Fl m Ar page[,subpage] | Fl l
.Op Fl P Ar pgctl
.Op Fl b | Fl e
@@ -723,6 +724,13 @@ The
.Ic modepage
command takes several arguments:
.Bl -tag -width 12n
+.It Fl 6
+Use 6 byte MODE commands instead of default 10 byte.
+Old devices may not support 10 byte MODE commands, while new devices may
+not be able to report all mode pages with 6 byte commands.
+If not specified,
+.Nm
+starts with 10 byte commands and falls back to 6 byte on error.
.It Fl d
Disable block descriptors for mode sense.
.It Fl b
Modified: stable/11/sbin/camcontrol/camcontrol.c
==============================================================================
--- stable/11/sbin/camcontrol/camcontrol.c Wed Aug 28 20:21:34 2019 (r351580)
+++ stable/11/sbin/camcontrol/camcontrol.c Wed Aug 28 20:22:14 2019 (r351581)
@@ -224,7 +224,7 @@ static struct camcontrol_opts option_table[] = {
{"devtype", CAM_CMD_DEVTYPE, CAM_ARG_NONE, ""},
#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, "6bdelm:P:"},
{"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},
@@ -4430,18 +4430,25 @@ reassignblocks(struct cam_device *device, u_int32_t *b
#ifndef MINIMALISTIC
void
-mode_sense(struct cam_device *device, 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 pc, int page,
+ int subpage, int task_attr, int retry_count, int timeout, u_int8_t *data,
+ int datalen)
{
union ccb *ccb;
- int retval;
+ int error_code, sense_key, asc, ascq;
ccb = cam_getccb(device);
-
if (ccb == NULL)
errx(1, "mode_sense: couldn't allocate CCB");
+retry:
+ /*
+ * MODE SENSE(6) can't handle more then 255 bytes. If there are more,
+ * device must return error, so we should not get trucated data.
+ */
+ if (*cdb_len == 6 && datalen > 255)
+ datalen = 255;
+
CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->csio);
scsi_mode_sense_subpage(&ccb->csio,
@@ -4454,36 +4461,47 @@ mode_sense(struct cam_device *device, int dbd, int pc,
/* subpage */ subpage,
/* param_buf */ data,
/* param_len */ datalen,
- /* minimum_cmd_size */ 0,
+ /* minimum_cmd_size */ *cdb_len,
/* sense_len */ SSD_FULL_SIZE,
/* timeout */ timeout ? timeout : 5000);
+ /* Record what CDB size the above function really set. */
+ *cdb_len = ccb->csio.cdb_len;
+
if (arglist & CAM_ARG_ERR_RECOVER)
ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
/* Disable freezing the device queue */
ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
- if (((retval = cam_send_ccb(device, ccb)) < 0)
- || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
+ if (cam_send_ccb(device, ccb) < 0)
+ err(1, "error sending mode sense command");
+
+ /* In case of ILLEGEL REQUEST try to fall back to 6-byte command. */
+ if (*cdb_len != 6 &&
+ ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INVALID ||
+ (scsi_extract_sense_ccb(ccb, &error_code, &sense_key, &asc, &ascq)
+ && sense_key == SSD_KEY_ILLEGAL_REQUEST))) {
+ *cdb_len = 6;
+ goto retry;
+ }
+
+ if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
if (arglist & CAM_ARG_VERBOSE) {
cam_error_print(device, ccb, CAM_ESF_ALL,
CAM_EPF_ALL, stderr);
}
cam_freeccb(ccb);
cam_close_device(device);
- if (retval < 0)
- err(1, "error sending mode sense command");
- else
- errx(1, "error sending mode sense command");
+ errx(1, "mode sense command returned error");
}
cam_freeccb(ccb);
}
void
-mode_select(struct cam_device *device, int save_pages, int task_attr,
- int retry_count, int timeout, u_int8_t *data, int datalen)
+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)
{
union ccb *ccb;
int retval;
@@ -4495,7 +4513,7 @@ mode_select(struct cam_device *device, int save_pages,
CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->csio);
- scsi_mode_select(&ccb->csio,
+ scsi_mode_select_len(&ccb->csio,
/* retries */ retry_count,
/* cbfcnp */ NULL,
/* tag_action */ task_attr,
@@ -4503,6 +4521,7 @@ mode_select(struct cam_device *device, int save_pages,
/* save_pages */ save_pages,
/* param_buf */ data,
/* param_len */ datalen,
+ /* minimum_cmd_size */ cdb_len,
/* sense_len */ SSD_FULL_SIZE,
/* timeout */ timeout ? timeout : 5000);
@@ -4537,10 +4556,13 @@ modepage(struct cam_device *device, int argc, char **a
{
char *str_subpage;
int c, page = -1, subpage = -1, pc = 0;
- int binary = 0, dbd = 0, edit = 0, list = 0;
+ int binary = 0, cdb_len = 10, dbd = 0, edit = 0, list = 0;
while ((c = getopt(argc, argv, combinedopt)) != -1) {
switch(c) {
+ case '6':
+ cdb_len = 6;
+ break;
case 'b':
binary = 1;
break;
@@ -4580,11 +4602,11 @@ modepage(struct cam_device *device, int argc, char **a
errx(1, "you must specify a mode page!");
if (list != 0) {
- mode_list(device, dbd, pc, list > 1, task_attr, retry_count,
- timeout);
+ mode_list(device, cdb_len, dbd, pc, list > 1, task_attr,
+ retry_count, timeout);
} else {
- mode_edit(device, dbd, pc, page, subpage, edit, binary,
- task_attr, retry_count, timeout);
+ mode_edit(device, cdb_len, dbd, pc, page, subpage, edit,
+ binary, task_attr, retry_count, timeout);
}
}
Modified: stable/11/sbin/camcontrol/camcontrol.h
==============================================================================
--- stable/11/sbin/camcontrol/camcontrol.h Wed Aug 28 20:21:34 2019 (r351580)
+++ stable/11/sbin/camcontrol/camcontrol.h Wed Aug 28 20:22:14 2019 (r351581)
@@ -88,16 +88,17 @@ int epc(struct cam_device *device, int argc, char **ar
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 dbd, 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 save_pages, int task_attr,
- int retry_count, int timeout, u_int8_t *data, int datalen);
-void mode_edit(struct cam_device *device, int dbd, int pc, int page,
- int subpage, int edit, int binary, int task_attr,
+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, 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_list(struct cam_device *device, int dbd, int pc, int subpages,
- 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,
char *combinedopt, int task_attr, int retry_count,
int timeout);
Modified: stable/11/sbin/camcontrol/modeedit.c
==============================================================================
--- stable/11/sbin/camcontrol/modeedit.c Wed Aug 28 20:21:34 2019 (r351580)
+++ stable/11/sbin/camcontrol/modeedit.c Wed Aug 28 20:22:14 2019 (r351581)
@@ -60,15 +60,9 @@ __FBSDID("$FreeBSD$");
#define PAGENAME_START '"' /* Page name delimiter. */
#define PAGENAME_END '"' /* Page name delimiter. */
#define PAGEENTRY_END ';' /* Page entry terminator (optional). */
-#define MAX_COMMAND_SIZE 255 /* Mode/Log sense data buffer size. */
+#define MAX_DATA_SIZE 4096 /* Mode/Log sense data buffer size. */
#define PAGE_CTRL_SHIFT 6 /* Bit offset to page control field. */
-
-/* Macros for working with mode pages. */
-#define MODE_PAGE_HEADER(mh) \
- (struct scsi_mode_page_header *)find_mode_page_6(mh)
-
-
struct editentry {
STAILQ_ENTRY(editentry) link;
char *name;
@@ -106,13 +100,12 @@ static int editentry_save(void *hook, char *name);
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 dbd,
- int pc, int page, int subpage,
- int task_attr, int retries,
- int timeout);
-static void editlist_save(struct cam_device *device, int dbd,
- int pc, int page, int subpage,
- int task_attr, int retries, int timeout);
+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_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 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,
@@ -120,9 +113,9 @@ static int load_format(const char *pagedb_path, int
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 dbd,
- int pc, int page, int subpage, int task_attr,
- int retries, int timeout);
+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 cleanup_editfile(void);
@@ -552,12 +545,11 @@ load_format(const char *pagedb_path, int lpage, int ls
}
static void
-editlist_populate(struct cam_device *device, int dbd, int pc, int page,
- int subpage, int task_attr, int retries, int timeout)
+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_COMMAND_SIZE];/* Buffer to hold sense data. */
+ u_int8_t data[MAX_DATA_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;
size_t len;
@@ -565,11 +557,18 @@ editlist_populate(struct cam_device *device, int dbd,
STAILQ_INIT(&editlist);
/* Fetch changeable values; use to build initial editlist. */
- mode_sense(device, dbd, 1, page, subpage, task_attr, retries, timeout,
- data, sizeof(data));
+ mode_sense(device, &cdb_len, dbd, 1, page, subpage, task_attr, retries,
+ timeout, data, sizeof(data));
- mh = (struct scsi_mode_header_6 *)data;
- mph = MODE_PAGE_HEADER(mh);
+ if (cdb_len == 6) {
+ struct scsi_mode_header_6 *mh =
+ (struct scsi_mode_header_6 *)data;
+ mph = find_mode_page_6(mh);
+ } else {
+ struct scsi_mode_header_10 *mh =
+ (struct scsi_mode_header_10 *)data;
+ mph = find_mode_page_10(mh);
+ }
if ((mph->page_code & SMPH_SPF) == 0) {
mode_pars = (uint8_t *)(mph + 1);
len = mph->page_length;
@@ -584,40 +583,80 @@ editlist_populate(struct cam_device *device, int dbd,
buff_decode_visit(mode_pars, len, format, editentry_create, 0);
/* Fetch the current/saved values; use to set editentry values. */
- mode_sense(device, dbd, pc, page, subpage, task_attr, retries, timeout,
- data, sizeof(data));
+ mode_sense(device, &cdb_len, dbd, pc, page, subpage, task_attr,
+ retries, timeout, data, sizeof(data));
buff_decode_visit(mode_pars, len, format, editentry_update, 0);
}
static void
-editlist_save(struct cam_device *device, int dbd, int pc, int page,
- int subpage, int task_attr, int retries, int timeout)
+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_COMMAND_SIZE];/* Buffer to hold sense data. */
+ u_int8_t data[MAX_DATA_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;
- size_t len, hlen;
+ size_t len, hlen, mphlen;
/* Make sure that something changed before continuing. */
if (! editlist_changed)
return;
/* Preload the CDB buffer with the current mode page data. */
- mode_sense(device, dbd, pc, page, subpage, task_attr, retries, timeout,
- data, sizeof(data));
+ mode_sense(device, &cdb_len, dbd, pc, page, subpage, task_attr,
+ retries, timeout, data, sizeof(data));
/* Initial headers & offsets. */
- mh = (struct scsi_mode_header_6 *)data;
- mph = MODE_PAGE_HEADER(mh);
+ /*
+ * Tape drives include write protect (WP), Buffered Mode and Speed
+ * settings in the device-specific parameter. Clearing this
+ * parameter on a mode select can have the effect of turning off
+ * write protect or buffered mode, or changing the speed setting of
+ * the tape drive.
+ *
+ * Disks report DPO/FUA support via the device specific parameter
+ * for MODE SENSE, but the bit is reserved for MODE SELECT. So we
+ * clear this for disks (and other non-tape devices) to avoid
+ * potential errors from the target device.
+ */
+ if (cdb_len == 6) {
+ struct scsi_mode_header_6 *mh =
+ (struct scsi_mode_header_6 *)data;
+ hlen = sizeof(*mh);
+ /* Eliminate block descriptors. */
+ if (mh->blk_desc_len > 0) {
+ bcopy(find_mode_page_6(mh), mh + 1,
+ mh->data_length + 1 - hlen -
+ mh->blk_desc_len);
+ mh->blk_desc_len = 0;
+ }
+ mh->data_length = 0; /* Reserved for MODE SELECT command. */
+ if (device->pd_type != T_SEQUENTIAL)
+ mh->dev_spec = 0; /* See comment above */
+ mph = find_mode_page_6(mh);
+ } else {
+ struct scsi_mode_header_10 *mh =
+ (struct scsi_mode_header_10 *)data;
+ hlen = sizeof(*mh);
+ /* Eliminate block descriptors. */
+ if (scsi_2btoul(mh->blk_desc_len) > 0) {
+ bcopy(find_mode_page_10(mh), mh + 1,
+ scsi_2btoul(mh->data_length) + 1 - hlen -
+ scsi_2btoul(mh->blk_desc_len));
+ scsi_ulto2b(0, 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 */
+ mph = find_mode_page_10(mh);
+ }
if ((mph->page_code & SMPH_SPF) == 0) {
- hlen = sizeof(*mph);
+ mphlen = sizeof(*mph);
mode_pars = (uint8_t *)(mph + 1);
len = mph->page_length;
} else {
mphsp = (struct scsi_mode_page_header_sp *)mph;
- hlen = sizeof(*mphsp);
+ mphlen = sizeof(*mphsp);
mode_pars = (uint8_t *)(mphsp + 1);
len = scsi_2btoul(mphsp->page_length);
}
@@ -626,27 +665,6 @@ editlist_save(struct cam_device *device, int dbd, int
/* Encode the value data to be passed back to the device. */
buff_encode_visit(mode_pars, len, format, editentry_save, 0);
- /* Eliminate block descriptors. */
- bcopy(mph, mh + 1, hlen + len);
-
- /* Recalculate headers & offsets. */
- mh->data_length = 0; /* Reserved for MODE SELECT command. */
- mh->blk_desc_len = 0; /* No block descriptors. */
- /*
- * Tape drives include write protect (WP), Buffered Mode and Speed
- * settings in the device-specific parameter. Clearing this
- * parameter on a mode select can have the effect of turning off
- * write protect or buffered mode, or changing the speed setting of
- * the tape drive.
- *
- * Disks report DPO/FUA support via the device specific parameter
- * for MODE SENSE, but the bit is reserved for MODE SELECT. So we
- * clear this for disks (and other non-tape devices) to avoid
- * potential errors from the target device.
- */
- if (device->pd_type != T_SEQUENTIAL)
- mh->dev_spec = 0;
- mph = MODE_PAGE_HEADER(mh);
mph->page_code &= ~SMPH_PS; /* Reserved for MODE SELECT command. */
/*
@@ -654,9 +672,8 @@ editlist_save(struct cam_device *device, int dbd, int
* page 3 (saved values) then request the changes be permanently
* recorded.
*/
- mode_select(device, (pc << PAGE_CTRL_SHIFT == SMS_PAGE_CTRL_SAVED),
- task_attr, retries, timeout, (u_int8_t *)mh,
- sizeof(*mh) + hlen + len);
+ mode_select(device, cdb_len, (pc << PAGE_CTRL_SHIFT == SMS_PAGE_CTRL_SAVED),
+ task_attr, retries, timeout, data, hlen + mphlen + len);
}
static int
@@ -825,21 +842,27 @@ modepage_edit(void)
}
static void
-modepage_dump(struct cam_device *device, int dbd, int pc, int page, int subpage,
- int task_attr, int retries, int timeout)
+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_COMMAND_SIZE];/* Buffer to hold sense data. */
+ u_int8_t data[MAX_DATA_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;
size_t indx, len;
- mode_sense(device, dbd, pc, page, subpage, task_attr, retries, timeout,
- data, sizeof(data));
+ mode_sense(device, &cdb_len, dbd, pc, page, subpage, task_attr,
+ retries, timeout, data, sizeof(data));
- mh = (struct scsi_mode_header_6 *)data;
- mph = MODE_PAGE_HEADER(mh);
+ if (cdb_len == 6) {
+ struct scsi_mode_header_6 *mh =
+ (struct scsi_mode_header_6 *)data;
+ mph = find_mode_page_6(mh);
+ } else {
+ struct scsi_mode_header_10 *mh =
+ (struct scsi_mode_header_10 *)data;
+ mph = find_mode_page_10(mh);
+ }
if ((mph->page_code & SMPH_SPF) == 0) {
mode_pars = (uint8_t *)(mph + 1);
len = mph->page_length;
@@ -869,8 +892,9 @@ cleanup_editfile(void)
}
void
-mode_edit(struct cam_device *device, 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 dbd, 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. */
@@ -901,8 +925,8 @@ mode_edit(struct cam_device *device, int dbd, int pc,
exit(EX_OSFILE);
}
- editlist_populate(device, dbd, pc, page, subpage, task_attr,
- retry_count, timeout);
+ editlist_populate(device, cdb_len, dbd, pc, page, subpage,
+ task_attr, retry_count, timeout);
}
if (edit) {
@@ -911,12 +935,12 @@ mode_edit(struct cam_device *device, int dbd, int pc,
errx(EX_USAGE, "it only makes sense to edit page 0 "
"(current) or page 3 (saved values)");
modepage_edit();
- editlist_save(device, dbd, pc, page, subpage, task_attr,
- retry_count, timeout);
+ 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, dbd, pc, page, subpage, task_attr,
- retry_count, timeout);
+ modepage_dump(device, cdb_len, dbd, pc, page, subpage,
+ task_attr, retry_count, timeout);
} else {
/* Display with format. */
modepage_write(stdout, 0);
@@ -924,16 +948,15 @@ mode_edit(struct cam_device *device, int dbd, int pc,
}
void
-mode_list(struct cam_device *device, int dbd, int pc, int subpages,
+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_COMMAND_SIZE];/* Buffer to hold sense data. */
- struct scsi_mode_header_6 *mh; /* Location of mode header. */
+ u_int8_t data[MAX_DATA_SIZE];/* Buffer to hold sense data. */
struct scsi_mode_page_header *mph;
struct scsi_mode_page_header_sp *mphsp;
struct pagename *nameentry;
const char *pagedb_path;
- int len, page, subpage;
+ int len, off, page, subpage;
if ((pagedb_path = getenv("SCSI_MODES")) == NULL)
pagedb_path = DEFAULT_SCSI_MODE_DB;
@@ -944,26 +967,36 @@ mode_list(struct cam_device *device, int dbd, int pc,
}
/* Build the list of all mode pages by querying the "all pages" page. */
- mode_sense(device, dbd, pc, SMS_ALL_PAGES_PAGE,
+ mode_sense(device, &cdb_len, dbd, pc, SMS_ALL_PAGES_PAGE,
subpages ? SMS_SUBPAGE_ALL : 0,
task_attr, retry_count, timeout, data, sizeof(data));
- mh = (struct scsi_mode_header_6 *)data;
- len = sizeof(*mh) + mh->blk_desc_len; /* Skip block descriptors. */
+ /* Skip block descriptors. */
+ if (cdb_len == 6) {
+ struct scsi_mode_header_6 *mh =
+ (struct scsi_mode_header_6 *)data;
+ len = mh->data_length;
+ off = sizeof(*mh) + mh->blk_desc_len;
+ } else {
+ struct scsi_mode_header_10 *mh =
+ (struct scsi_mode_header_10 *)data;
+ len = scsi_2btoul(mh->data_length);
+ off = sizeof(*mh) + scsi_2btoul(mh->blk_desc_len);
+ }
/* Iterate through the pages in the reply. */
- while (len < mh->data_length) {
+ while (off < len) {
/* Locate the next mode page header. */
- mph = (struct scsi_mode_page_header *)((intptr_t)mh + len);
+ mph = (struct scsi_mode_page_header *)(data + off);
if ((mph->page_code & SMPH_SPF) == 0) {
page = mph->page_code & SMS_PAGE_CODE;
subpage = 0;
- len += sizeof(*mph) + mph->page_length;
+ off += 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);
+ off += sizeof(*mphsp) + scsi_2btoul(mphsp->page_length);
}
nameentry = nameentry_lookup(page, subpage);
More information about the svn-src-all
mailing list