From owner-svn-src-stable-12@freebsd.org Tue Aug 27 03:54:30 2019 Return-Path: Delivered-To: svn-src-stable-12@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id 93096C816E; Tue, 27 Aug 2019 03:54:30 +0000 (UTC) (envelope-from mav@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 46HZkZ48WGz4JY7; Tue, 27 Aug 2019 03:54:30 +0000 (UTC) (envelope-from mav@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 70A7018E3F; Tue, 27 Aug 2019 03:54:30 +0000 (UTC) (envelope-from mav@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id x7R3sUR6094585; Tue, 27 Aug 2019 03:54:30 GMT (envelope-from mav@FreeBSD.org) Received: (from mav@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id x7R3sTR7094581; Tue, 27 Aug 2019 03:54:29 GMT (envelope-from mav@FreeBSD.org) Message-Id: <201908270354.x7R3sTR7094581@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: mav set sender to mav@FreeBSD.org using -f From: Alexander Motin Date: Tue, 27 Aug 2019 03:54:29 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-12@freebsd.org Subject: svn commit: r351529 - stable/12/sbin/camcontrol X-SVN-Group: stable-12 X-SVN-Commit-Author: mav X-SVN-Commit-Paths: stable/12/sbin/camcontrol X-SVN-Commit-Revision: 351529 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-stable-12@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: SVN commit messages for only the 12-stable src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 27 Aug 2019 03:54:30 -0000 Author: mav Date: Tue Aug 27 03:54:29 2019 New Revision: 351529 URL: https://svnweb.freebsd.org/changeset/base/351529 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/12/sbin/camcontrol/camcontrol.8 stable/12/sbin/camcontrol/camcontrol.c stable/12/sbin/camcontrol/camcontrol.h stable/12/sbin/camcontrol/modeedit.c Directory Properties: stable/12/ (props changed) Modified: stable/12/sbin/camcontrol/camcontrol.8 ============================================================================== --- stable/12/sbin/camcontrol/camcontrol.8 Tue Aug 27 03:53:22 2019 (r351528) +++ stable/12/sbin/camcontrol/camcontrol.8 Tue Aug 27 03:54:29 2019 (r351529) @@ -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/12/sbin/camcontrol/camcontrol.c ============================================================================== --- stable/12/sbin/camcontrol/camcontrol.c Tue Aug 27 03:53:22 2019 (r351528) +++ stable/12/sbin/camcontrol/camcontrol.c Tue Aug 27 03:54:29 2019 (r351529) @@ -230,7 +230,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}, @@ -4611,18 +4611,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, @@ -4635,36 +4642,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; @@ -4676,7 +4694,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, @@ -4684,6 +4702,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); @@ -4718,10 +4737,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; @@ -4761,11 +4783,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/12/sbin/camcontrol/camcontrol.h ============================================================================== --- stable/12/sbin/camcontrol/camcontrol.h Tue Aug 27 03:53:22 2019 (r351528) +++ stable/12/sbin/camcontrol/camcontrol.h Tue Aug 27 03:54:29 2019 (r351529) @@ -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/12/sbin/camcontrol/modeedit.c ============================================================================== --- stable/12/sbin/camcontrol/modeedit.c Tue Aug 27 03:53:22 2019 (r351528) +++ stable/12/sbin/camcontrol/modeedit.c Tue Aug 27 03:54:29 2019 (r351529) @@ -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);