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. MFC after: 2 weeks Sponsored by: iXsystems, Inc.
This commit is contained in:
parent
c71b8899d3
commit
166d34c6ff
@ -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
|
||||
|
@ -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, "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},
|
||||
@ -4586,18 +4586,25 @@ reassignblocks(struct cam_device *device, u_int32_t *blocks, int num_blocks)
|
||||
#endif
|
||||
|
||||
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,
|
||||
@ -4610,36 +4617,47 @@ mode_sense(struct cam_device *device, int dbd, int pc, int page, int subpage,
|
||||
/* 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;
|
||||
@ -4651,7 +4669,7 @@ mode_select(struct cam_device *device, int save_pages, int task_attr,
|
||||
|
||||
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,
|
||||
@ -4659,6 +4677,7 @@ mode_select(struct cam_device *device, int save_pages, int task_attr,
|
||||
/* save_pages */ save_pages,
|
||||
/* param_buf */ data,
|
||||
/* param_len */ datalen,
|
||||
/* minimum_cmd_size */ cdb_len,
|
||||
/* sense_len */ SSD_FULL_SIZE,
|
||||
/* timeout */ timeout ? timeout : 5000);
|
||||
|
||||
@ -4693,10 +4712,13 @@ modepage(struct cam_device *device, int argc, char **argv, char *combinedopt,
|
||||
{
|
||||
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;
|
||||
@ -4736,11 +4758,11 @@ modepage(struct cam_device *device, int argc, char **argv, char *combinedopt,
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -88,16 +88,17 @@ 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 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);
|
||||
|
@ -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 lpage,
|
||||
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 lsubpage)
|
||||
}
|
||||
|
||||
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, int pc, int page,
|
||||
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,54 +583,30 @@ editlist_populate(struct cam_device *device, int dbd, int pc, int page,
|
||||
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);
|
||||
if ((mph->page_code & SMPH_SPF) == 0) {
|
||||
hlen = sizeof(*mph);
|
||||
mode_pars = (uint8_t *)(mph + 1);
|
||||
len = mph->page_length;
|
||||
} else {
|
||||
mphsp = (struct scsi_mode_page_header_sp *)mph;
|
||||
hlen = sizeof(*mphsp);
|
||||
mode_pars = (uint8_t *)(mphsp + 1);
|
||||
len = scsi_2btoul(mphsp->page_length);
|
||||
}
|
||||
len = MIN(len, sizeof(data) - (mode_pars - data));
|
||||
|
||||
/* 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
|
||||
@ -644,9 +619,52 @@ editlist_save(struct cam_device *device, int dbd, int pc, int page,
|
||||
* 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);
|
||||
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) {
|
||||
mphlen = sizeof(*mph);
|
||||
mode_pars = (uint8_t *)(mph + 1);
|
||||
len = mph->page_length;
|
||||
} else {
|
||||
mphsp = (struct scsi_mode_page_header_sp *)mph;
|
||||
mphlen = sizeof(*mphsp);
|
||||
mode_pars = (uint8_t *)(mphsp + 1);
|
||||
len = scsi_2btoul(mphsp->page_length);
|
||||
}
|
||||
len = MIN(len, sizeof(data) - (mode_pars - data));
|
||||
|
||||
/* Encode the value data to be passed back to the device. */
|
||||
buff_encode_visit(mode_pars, len, format, editentry_save, 0);
|
||||
|
||||
mph->page_code &= ~SMPH_PS; /* Reserved for MODE SELECT command. */
|
||||
|
||||
/*
|
||||
@ -654,9 +672,8 @@ editlist_save(struct cam_device *device, int dbd, int pc, int page,
|
||||
* 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, int page, int subpage,
|
||||
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, int page, int subpage,
|
||||
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, int page, int subpage,
|
||||
}
|
||||
|
||||
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, int subpages,
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
Loading…
Reference in New Issue
Block a user