From owner-svn-src-head@freebsd.org Wed Aug 7 14:45:12 2019 Return-Path: Delivered-To: svn-src-head@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 6754AACAF0; Wed, 7 Aug 2019 14:45:12 +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 463Z6c2psVz3JTd; Wed, 7 Aug 2019 14:45:12 +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 436F4E2DC; Wed, 7 Aug 2019 14:45:12 +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 x77EjCpx010370; Wed, 7 Aug 2019 14:45:12 GMT (envelope-from mav@FreeBSD.org) Received: (from mav@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id x77EjB95010365; Wed, 7 Aug 2019 14:45:11 GMT (envelope-from mav@FreeBSD.org) Message-Id: <201908071445.x77EjB95010365@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: mav set sender to mav@FreeBSD.org using -f From: Alexander Motin Date: Wed, 7 Aug 2019 14:45:11 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r350676 - in head: sbin/camcontrol sys/cam/scsi X-SVN-Group: head X-SVN-Commit-Author: mav X-SVN-Commit-Paths: in head: sbin/camcontrol sys/cam/scsi X-SVN-Commit-Revision: 350676 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 07 Aug 2019 14:45:12 -0000 Author: mav Date: Wed Aug 7 14:45:10 2019 New Revision: 350676 URL: https://svnweb.freebsd.org/changeset/base/350676 Log: 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. Modified: head/sbin/camcontrol/camcontrol.8 head/sbin/camcontrol/camcontrol.c head/sbin/camcontrol/camcontrol.h head/sbin/camcontrol/modeedit.c head/sys/cam/scsi/scsi_all.c head/sys/cam/scsi/scsi_all.h Modified: head/sbin/camcontrol/camcontrol.8 ============================================================================== --- head/sbin/camcontrol/camcontrol.8 Wed Aug 7 13:35:13 2019 (r350675) +++ head/sbin/camcontrol/camcontrol.8 Wed Aug 7 14:45:10 2019 (r350676) @@ -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 Modified: head/sbin/camcontrol/camcontrol.c ============================================================================== --- head/sbin/camcontrol/camcontrol.c Wed Aug 7 13:35:13 2019 (r350675) +++ head/sbin/camcontrol/camcontrol.c Wed Aug 7 14:45:10 2019 (r350676) @@ -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 *b #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 **a 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 **a 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 **a } } - 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); } } Modified: head/sbin/camcontrol/camcontrol.h ============================================================================== --- head/sbin/camcontrol/camcontrol.h Wed Aug 7 13:35:13 2019 (r350675) +++ head/sbin/camcontrol/camcontrol.h Wed Aug 7 14:45:10 2019 (r350676) @@ -88,15 +88,15 @@ 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 *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, Modified: head/sbin/camcontrol/modeedit.c ============================================================================== --- head/sbin/camcontrol/modeedit.c Wed Aug 7 13:35:13 2019 (r350675) +++ head/sbin/camcontrol/modeedit.c Wed Aug 7 14:45:10 2019 (r350676) @@ -33,6 +33,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include @@ -96,6 +97,8 @@ static void editentry_create(void *hook, int letter, 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 } } +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_l 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_l 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, 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, 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,7 +1042,38 @@ modepage_dump(struct cam_device *device, int cdb_len, } 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 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 } /* 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)); Modified: head/sys/cam/scsi/scsi_all.c ============================================================================== --- head/sys/cam/scsi/scsi_all.c Wed Aug 7 13:35:13 2019 (r350675) +++ head/sys/cam/scsi/scsi_all.c Wed Aug 7 14:45:10 2019 (r350676) @@ -2056,7 +2056,7 @@ static struct asc_table_entry asc_table[] = { { SST(0x30, 0x13, SS_RDEF, /* XXX TBD */ "Cleaning volume expired") }, /* DT WRO BK */ - { SST(0x31, 0x00, SS_RDEF, + { SST(0x31, 0x00, SS_FATAL | ENXIO, "Medium format corrupted") }, /* D L RO B */ { SST(0x31, 0x01, SS_RDEF, Modified: head/sys/cam/scsi/scsi_all.h ============================================================================== --- head/sys/cam/scsi/scsi_all.h Wed Aug 7 13:35:13 2019 (r350675) +++ head/sys/cam/scsi/scsi_all.h Wed Aug 7 14:45:10 2019 (r350676) @@ -3622,7 +3622,9 @@ struct scsi_mode_header_10 u_int8_t data_length[2];/* Sense data length */ u_int8_t medium_type; u_int8_t dev_spec; - u_int8_t unused[2]; + u_int8_t flags; +#define SMH_LONGLBA 0x01 + u_int8_t unused; u_int8_t blk_desc_len[2]; };