aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--inhex/vpd_cpr.hex14
-rw-r--r--inhex/vpd_fp.hex27
-rw-r--r--lib/sg_pt_linux_nvme.c2
-rw-r--r--src/sg_inq.c24
-rw-r--r--src/sg_vpd.c150
6 files changed, 213 insertions, 9 deletions
diff --git a/ChangeLog b/ChangeLog
index 81d71ba2..9ee0f357 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,11 +2,14 @@ Each utility has its own version number, date of last change and
some description at the top of its ".c" file. All utilities in the main
directory have their own "man" pages. There is also a sg3_utils man page.
-Changelog for sg3_utils-1.46 [20201109] [svn: r866]
+Changelog for sg3_utils-1.46 [20201114] [svn: r867]
- sg_rep_pip: report new provisioning initialization pattern cmd
- sg_turs: estimated time-to-ready [20-061r2]
- add --delay=MS option
- sg_requests: substantial cleanup
+ - sg_vpd: add Format presets and Concurrent positioning ranges
+ - add hot-pluggable field in standard Inquiry [20-0114r2]
+ - sg_inq: add hot-pluggable field in standard Inquiry
- sg_dd: --verify : separate category for miscompare errors
- --verify : oflag=coe continue on miscompares, counts them
- add oflag=nocreat and conv=nocreat : OFILE must exist
diff --git a/inhex/vpd_cpr.hex b/inhex/vpd_cpr.hex
new file mode 100644
index 00000000..ec8aaa0a
--- /dev/null
+++ b/inhex/vpd_cpr.hex
@@ -0,0 +1,14 @@
+# Dummy data for Concurrent positioning ranges VPD page
+00 b9 00 7c 00 00 00 00
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+# after 64 byte header there is the first LBA range descriptor (32 bytes)
+01 02 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 10 00 00 00
+ 00 00 00 00 00 00 00 00
+# second LBA range descriptor (32 bytes)
+02 02 00 00 00 00 00 00
+00 00 00 00 10 00 00 00
+00 00 00 00 10 00 00 00
+ 00 00 00 00 00 00 00 00
diff --git a/inhex/vpd_fp.hex b/inhex/vpd_fp.hex
new file mode 100644
index 00000000..5bf71ff5
--- /dev/null
+++ b/inhex/vpd_fp.hex
@@ -0,0 +1,27 @@
+# Dummy data for Format presets VPD page
+00 b8 00 80
+
+# after 4 byte header here is the first Format preset descriptor (64 bytes)
+00 00 01 00
+01 0 0 00
+01 00 00 00
+0 0 0 0
+00 00 00 00 00 ff ff ff # last LBA
+0 0 0 0 0 0 0 0 0 0 0 0 0 0
+00 00 # FMPTINFO, Protection field usage and protection interval exp
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0
+
+# second Format preset descriptor (64 bytes)
+00 00 01 01
+02 0 0 00
+01 00 00 00
+0 0 0 0
+00 00 00 00 01 ff ff ff # last LBA
+0 0 0 0 0 0 0 0 0 0 0 0 0 0
+00 00 # FMPTINFO, Protection field usage and protection interval exp
+# host-aware zones schema type specific information
+5 ff
+0 0 0 0 0 0 0 0 0 0
+20 00 00 00
+0 0 0 0
diff --git a/lib/sg_pt_linux_nvme.c b/lib/sg_pt_linux_nvme.c
index b8d88696..d8868004 100644
--- a/lib/sg_pt_linux_nvme.c
+++ b/lib/sg_pt_linux_nvme.c
@@ -646,7 +646,7 @@ sntl_inq(struct sg_pt_linux_scsi * ptp, const uint8_t * cdbp, int time_secs,
} else { /* Standard INQUIRY response */
/* pdt=0 --> disk; pdt=0xd --> SES; pdt=3 --> processor (safte) */
inq_dout[0] = (0x1f & ptp->dev_stat.pdt); /* (PQ=0)<<5 */
- /* inq_dout[1] = (RMD=0)<<7 | (LU_CONG=0)<<6; rest reserved */
+ /* inq_dout[1] = (RMD=0)<<7 | (LU_CONG=0)<<6 | (HOT_PLUG=0)<<4; */
inq_dout[2] = 6; /* version: SPC-4 */
inq_dout[3] = 2; /* NORMACA=0, HISUP=0, response data format: 2 */
inq_dout[4] = 31; /* so response length is (or could be) 36 bytes */
diff --git a/src/sg_inq.c b/src/sg_inq.c
index 8e10409f..546d2a65 100644
--- a/src/sg_inq.c
+++ b/src/sg_inq.c
@@ -51,7 +51,7 @@
#include "sg_pt_nvme.h"
#endif
-static const char * version_str = "2.07 20200422"; /* SPC-6 rev 01 */
+static const char * version_str = "2.08 20201114"; /* spc6r02 + 20-0114r2 */
/* INQUIRY notes:
* It is recommended that the initial allocation length given to a
@@ -109,6 +109,7 @@ static const char * version_str = "2.07 20200422"; /* SPC-6 rev 01 */
#define VPD_ZBC_DEV_CHARS 0xb6 /* zbc-r01b */
#define VPD_BLOCK_LIMITS_EXT 0xb7 /* sbc4r08 */
#define VPD_FORMAT_PRESETS 0xb8 /* sbc4r18 */
+#define VPD_CON_POS_RANGE 0xb9 /* 20-089r2 */
#ifndef SG_NVME_VPD_NICR
#define SG_NVME_VPD_NICR 0xde
@@ -179,6 +180,8 @@ static struct svpd_values_name_t vpd_pg[] = {
"extension (SBC)"},
{VPD_BLOCK_LIMITS, 0, 0, 0, "bl", "Block limits (SBC)"},
{VPD_BLOCK_LIMITS_EXT, 0, 0, 0, "ble", "Block limits extension (SBC)"},
+ {VPD_CON_POS_RANGE, 0, 0, 0, "cpr", "Concurrent positioning ranges "
+ "(SBC)"},
{VPD_DEVICE_ID, 0, -1, 0, "di", "Device identification"},
#if 0 /* following found in sg_vpd */
{VPD_DEVICE_ID, VPD_DI_SEL_AS_IS, -1, 0, "di_asis", "Like 'di' "
@@ -2808,9 +2811,9 @@ std_inq_decode(const struct opts_t * op, int act_len)
if (strlen(cp) > 0)
printf("SCSI_TYPE=%s\n", cp);
} else {
- printf(" PQual=%d Device_type=%d RMB=%d LU_CONG=%d "
+ printf(" PQual=%d PDT=%d RMB=%d LU_CONG=%d hot_pluggable=%d "
"version=0x%02x ", pqual, peri_type, !!(rp[1] & 0x80),
- !!(rp[1] & 0x40), (unsigned int)rp[2]);
+ !!(rp[1] & 0x40), (rp[1] >> 4) & 0x3, (unsigned int)rp[2]);
printf(" [%s]\n", get_ansi_version_str(ansi_version, buff,
sizeof(buff)));
printf(" [AERC=%d] [TrmTsk=%d] NormACA=%d HiSUP=%d "
@@ -3348,6 +3351,7 @@ vpd_mainly_hex(int sg_fd, const struct opts_t * op, int inhex_len)
static int
vpd_decode(int sg_fd, const struct opts_t * op, int inhex_len)
{
+ bool bad = false;
int len, pdt, pn, vb, mxlen;
int res = 0;
uint8_t * rp;
@@ -3611,6 +3615,16 @@ vpd_decode(int sg_fd, const struct opts_t * op, int inhex_len)
} else if (! op->do_raw)
pr2serr("VPD INQUIRY: page=0xb3\n");
break;
+ case 0xb4:
+ case 0xb5:
+ case 0xb6:
+ case 0xb7:
+ case 0xb8:
+ case 0xb9:
+ bad = true;
+ pr2serr("Please try the sg_vpd utility which decodes more VPD "
+ "pages\n\n");
+ break;
case VPD_UPR_EMC: /* 0xc0 */
if (!op->do_raw && (op->do_hex < 2))
printf("VPD INQUIRY: Unit Path Report Page (EMC)\n");
@@ -3656,6 +3670,10 @@ vpd_decode(int sg_fd, const struct opts_t * op, int inhex_len)
decode_scsi_ports_vpd(rp, len, op->do_hex, op->verbose);
break;
default:
+ bad = true;
+ break;
+ }
+ if (bad) {
if ((pn > 0) && (pn < 0x80)) {
if (!op->do_raw && (op->do_hex < 2))
printf("VPD INQUIRY: ASCII information page, FRU code=0x%x\n",
diff --git a/src/sg_vpd.c b/src/sg_vpd.c
index f088330c..69919dec 100644
--- a/src/sg_vpd.c
+++ b/src/sg_vpd.c
@@ -40,7 +40,7 @@
*/
-static const char * version_str = "1.60 20200501"; /* spc6r01 + sbc4r20a */
+static const char * version_str = "1.61 20201114"; /* spc6r02 + sbc4r22 */
/* standard VPD pages, in ascending page number order */
#define VPD_SUPPORTED_VPDS 0x0
@@ -79,6 +79,7 @@ static const char * version_str = "1.60 20200501"; /* spc6r01 + sbc4r20a */
#define VPD_ZBC_DEV_CHARS 0xb6 /* zbc-r01b */
#define VPD_BLOCK_LIMITS_EXT 0xb7 /* sbc4r08 */
#define VPD_FORMAT_PRESETS 0xb8 /* sbc4r18 */
+#define VPD_CON_POS_RANGE 0xb9 /* 20-089r2 */
#define VPD_NOPE_WANT_STD_INQ -2 /* request for standard inquiry */
/* Device identification VPD page associations */
@@ -198,6 +199,7 @@ static struct svpd_values_name_t standard_vpd_pg[] = {
{VPD_BLOCK_DEV_C_EXTENS, 0, 0, "bdce", "Block device characteristics "
"extension (SBC)"},
{VPD_CFA_PROFILE_INFO, 0, 0, "cfa", "CFA profile information"},
+ {VPD_CON_POS_RANGE, 0, 0, "cpr", "Concurrent positioning ranges"},
{VPD_DEVICE_CONSTITUENTS, 0, -1, "dc", "Device constituents"},
{VPD_DEVICE_ID, 0, -1, "di", "Device identification"},
{VPD_DEVICE_ID, VPD_DI_SEL_AS_IS, -1, "di_asis", "Like 'di' "
@@ -500,9 +502,9 @@ std_inq_decode(uint8_t * b, int len, int verbose)
printf(" [PQ indicates LU not accessible via this port]\n");
else
printf(" [reserved or vendor specific qualifier [%d]]\n", pqual);
- printf(" PQual=%d Device_type=%d RMB=%d LU_CONG=%d version=0x%02x ",
- pqual, b[0] & 0x1f, !!(b[1] & 0x80), !!(b[1] & 0x40),
- (unsigned int)b[2]);
+ printf(" PQual=%d PDT=%d RMB=%d LU_CONG=%d hot_pluggable=%d "
+ "version=0x%02x ", pqual, b[0] & 0x1f, !!(b[1] & 0x80),
+ !!(b[1] & 0x40), (b[1] >> 4) & 0x3, (unsigned int)b[2]);
printf(" [%s]\n", sg_ansi_version_arr[b[2] & 0xf]);
printf(" [AERC=%d] [TrmTsk=%d] NormACA=%d HiSUP=%d "
" Resp_data_format=%d\n",
@@ -2646,6 +2648,84 @@ decode_b7_vpd(uint8_t * buff, int len, int do_hex, int pdt)
}
}
+/* VPD_FORMAT_PRESETS 0xb8 (added sbc4r18) */
+static void
+decode_format_presets_vpd(uint8_t * buff, int len, bool do_hex)
+{
+ int k;
+ unsigned int sch_type;
+ uint8_t * bp;
+
+ if (do_hex) {
+ hex2stdout(buff, len, (1 == do_hex) ? 0 : -1);
+ return;
+ }
+ if (len < 4) {
+ pr2serr("Format presets VPD page length too short=%d\n", len);
+ return;
+ }
+ len -= 4;
+ bp = buff + 4;
+ for (k = 0; k < len; k += 64, bp += 64) {
+ printf(" Preset identifier: 0x%x\n", sg_get_unaligned_be32(bp));
+ sch_type = bp[4];
+ printf(" schema type: %u\n", sch_type);
+ printf(" logical blocks per physical block exponent type: %u\n",
+ 0xf & bp[7]);
+ printf(" logical block length: %u\n",
+ sg_get_unaligned_be32(bp + 8));
+ printf(" designed last LBA: 0x%" PRIx64 "\n",
+ sg_get_unaligned_be64(bp + 16));
+ printf(" FMPT_INFO: %u\n", (bp[38] >> 6) & 0x3);
+ printf(" protection field usage: %u\n", bp[38] & 0x7);
+ printf(" protection interval exponent: %u\n", bp[39] & 0xf);
+ if (2 == sch_type)
+ printf(" Defines zones for host aware device:\n");
+ else if (3 == sch_type)
+ printf(" Defines zones for host managed device:\n");
+ if ((2 == sch_type) || (3 == sch_type)) {
+ unsigned int u = bp[40 + 0];
+
+ printf(" low LBA conventional zones percentage: "
+ "%u.%u %%\n", u / 10, u % 10);
+ u = bp[40 + 1];
+ printf(" high LBA conventional zones percentage: "
+ "%u.%u %%\n", u / 10, u % 10);
+ printf(" logical blocks per zone: %u\n",
+ sg_get_unaligned_be32(bp + 40 + 12));
+ }
+ }
+}
+
+/* VPD_CON_POS_RANGE 0xb9 (added 20-089r2) */
+static void
+decode_con_pos_range_vpd(uint8_t * buff, int len, bool do_hex)
+{
+ int k;
+ uint64_t u;
+ uint8_t * bp;
+
+ if (do_hex) {
+ hex2stdout(buff, len, (1 == do_hex) ? 0 : -1);
+ return;
+ }
+ if (len < 64) {
+ pr2serr("Concurrent position ranges VPD page length too short=%d\n",
+ len);
+ return;
+ }
+ len -= 64;
+ bp = buff + 64;
+ for (k = 0; k < len; k += 32, bp += 32) {
+ printf(" LBA range number: %u\n", bp[0]);
+ printf(" number of storage elements: %u\n", bp[1]);
+ printf(" starting LBA: 0x%" PRIx64 "\n",
+ sg_get_unaligned_be64(bp + 8));
+ u = sg_get_unaligned_be64(bp + 16);
+ printf(" number of LBAs: 0x%" PRIx64 " [%" PRIu64 "]\n", u, u);
+ }
+}
+
/* Returns 0 if successful */
static int
svpd_unable_to_decode(int sg_fd, struct opts_t * op, int subvalue, int off)
@@ -3431,6 +3511,68 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, int subvalue, int off,
(0 == op->examine))
printf("%sVPD page=0xb7\n", pre);
break;
+ case 0xb8: /* VPD_FORMAT_PRESETS */
+ res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
+ if (0 == res) {
+ pdt = rp[0] & 0x1f;
+ switch (pdt) {
+ case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
+ np = "Format presets VPD page (SBC):";
+ break;
+ default:
+ np = NULL;
+ break;
+ }
+ if (NULL == np)
+ printf("VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
+ else if (allow_name || allow_if_found)
+ printf("%s%s\n", pre, np);
+ if (op->do_raw)
+ dStrRaw(rp, len);
+ else {
+ pdt = rp[0] & 0x1f;
+ if (vb || long_notquiet)
+ printf(" [PQual=%d Peripheral device type: %s]\n",
+ (rp[0] & 0xe0) >> 5,
+ sg_get_pdt_str(pdt, sizeof(b), b));
+ decode_format_presets_vpd(rp, len, op->do_hex);
+ }
+ return 0;
+ } else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3) &&
+ (0 == op->examine))
+ printf("%sVPD page=0xb7\n", pre);
+ break;
+ case 0xb9: /* VPD_CON_POS_RANGE */
+ res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
+ if (0 == res) {
+ pdt = rp[0] & 0x1f;
+ switch (pdt) {
+ case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
+ np = "Concurrent positioning ranges VPD page (SBC):";
+ break;
+ default:
+ np = NULL;
+ break;
+ }
+ if (NULL == np)
+ printf("VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
+ else if (allow_name || allow_if_found)
+ printf("%s%s\n", pre, np);
+ if (op->do_raw)
+ dStrRaw(rp, len);
+ else {
+ pdt = rp[0] & 0x1f;
+ if (vb || long_notquiet)
+ printf(" [PQual=%d Peripheral device type: %s]\n",
+ (rp[0] & 0xe0) >> 5,
+ sg_get_pdt_str(pdt, sizeof(b), b));
+ decode_con_pos_range_vpd(rp, len, op->do_hex);
+ }
+ return 0;
+ } else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3) &&
+ (0 == op->examine))
+ printf("%sVPD page=0xb7\n", pre);
+ break;
default:
return SG_LIB_CAT_OTHER;
}