xref: /aosp_15_r20/external/sg3_utils/src/sg_inq.c (revision 44704f698541f6367e81f991ef8bb54ccbf3fc18)
1 /* A utility program originally written for the Linux OS SCSI subsystem.
2  * Copyright (C) 2000-2022 D. Gilbert
3  * This program is free software; you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License as published by
5  * the Free Software Foundation; either version 2, or (at your option)
6  * any later version.
7  *
8  * SPDX-License-Identifier: GPL-2.0-or-later
9  *
10  * This program outputs information provided by a SCSI INQUIRY command.
11  * It is mainly based on the SCSI SPC-6 document at https://www.t10.org .
12  *
13  * Acknowledgment:
14  *    - Martin Schwenke <martin at meltin dot net> added the raw switch and
15  *      other improvements [20020814]
16  *    - Lars Marowsky-Bree <lmb at suse dot de> contributed Unit Path Report
17  *      VPD page decoding for EMC CLARiiON devices [20041016]
18  */
19 
20 #include <unistd.h>
21 #include <fcntl.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <stdbool.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <ctype.h>
28 #include <getopt.h>
29 #define __STDC_FORMAT_MACROS 1
30 #include <inttypes.h>
31 #include <errno.h>
32 
33 #ifdef SG_LIB_LINUX
34 #include <sys/ioctl.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <linux/hdreg.h>
38 #endif
39 
40 #ifdef HAVE_CONFIG_H
41 #include "config.h"
42 #endif
43 
44 #include "sg_lib.h"
45 #include "sg_lib_data.h"
46 #include "sg_cmds_basic.h"
47 #include "sg_pt.h"
48 #include "sg_unaligned.h"
49 #include "sg_pr2serr.h"
50 #if (HAVE_NVME && (! IGNORE_NVME))
51 #include "sg_pt_nvme.h"
52 #endif
53 
54 #include "sg_vpd_common.h"  /* for shared VPD page processing with sg_vpd */
55 
56 static const char * version_str = "2.31 20220915";  /* spc6r06, sbc5r03 */
57 
58 #define MY_NAME "sg_inq"
59 
60 /* INQUIRY notes:
61  * It is recommended that the initial allocation length given to a
62  * standard INQUIRY is 36 (bytes), especially if this is the first
63  * SCSI command sent to a logical unit. This is compliant with SCSI-2
64  * and another major operating system. There are devices out there
65  * that use one of the SCSI commands sets and lock up if they receive
66  * an allocation length other than 36. This technique is sometimes
67  * referred to as a "36 byte INQUIRY".
68  *
69  * A "standard" INQUIRY is one that has the EVPD and the CmdDt bits
70  * clear.
71  *
72  * When doing device discovery on a SCSI transport (e.g. bus scanning)
73  * the first SCSI command sent to a device should be a standard (36
74  * byte) INQUIRY.
75  *
76  * The allocation length field in the INQUIRY command was changed
77  * from 1 to 2 bytes in SPC-3, revision 9, 17 September 2002.
78  * Be careful using allocation lengths greater than 252 bytes, especially
79  * if the lower byte is 0x0 (e.g. a 512 byte allocation length may
80  * not be a good arbitrary choice (as 512 == 0x200) ).
81  *
82  * From SPC-3 revision 16 the CmdDt bit in an INQUIRY is obsolete. There
83  * is now a REPORT SUPPORTED OPERATION CODES command that yields similar
84  * information [MAINTENANCE IN, service action = 0xc]; see sg_opcodes.
85  */
86 
87 // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< TESTING
88 // #undef SG_SCSI_STRINGS
89 // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< TESTING
90 
91 #define VPD_NOPE_WANT_STD_INQ -2        /* request for standard inquiry */
92 
93 /* Vendor specific VPD pages (typically >= 0xc0) */
94 #define VPD_UPR_EMC 0xc0
95 #define VPD_RDAC_VERS 0xc2
96 #define VPD_RDAC_VAC 0xc9
97 
98 /* values for selection one or more associations (2**vpd_assoc),
99    except _AS_IS */
100 #define VPD_DI_SEL_LU 1
101 #define VPD_DI_SEL_TPORT 2
102 #define VPD_DI_SEL_TARGET 4
103 #define VPD_DI_SEL_AS_IS 32
104 
105 #define DEF_ALLOC_LEN 252       /* highest 1 byte value that is modulo 4 */
106 #define SAFE_STD_INQ_RESP_LEN 36
107 #define MX_ALLOC_LEN (0xc000 + 0x80)
108 #define VPD_ATA_INFO_LEN  572
109 
110 #define SENSE_BUFF_LEN  64       /* Arbitrary, could be larger */
111 #define INQUIRY_CMD     0x12
112 #define INQUIRY_CMDLEN  6
113 #define DEF_PT_TIMEOUT  60       /* 60 seconds */
114 
115 
116 uint8_t * rsp_buff;
117 
118 static uint8_t * free_rsp_buff;
119 static const int rsp_buff_sz = MX_ALLOC_LEN + 1;
120 
121 static char xtra_buff[MX_ALLOC_LEN + 1];
122 static char usn_buff[MX_ALLOC_LEN + 1];
123 
124 static const char * find_version_descriptor_str(int value);
125 static void decode_dev_ids(const char * leadin, uint8_t * buff, int len,
126                            struct opts_t * op, sgj_opaque_p jop);
127 static int vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
128                       int off);
129 
130 // Test define that will only work for Linux
131 // #define HDIO_GET_IDENTITY 1
132 
133 #if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS) && \
134     defined(HDIO_GET_IDENTITY)
135 #include <sys/ioctl.h>
136 
137 static int try_ata_identify(int ata_fd, int do_hex, int do_raw,
138                             int verbose);
139 static void prepare_ata_identify(const struct opts_t * op, int inhex_len);
140 #endif
141 
142 
143 /* Note that this table is sorted by acronym */
144 static struct svpd_values_name_t t10_vpd_pg[] = {
145     {VPD_AUTOMATION_DEV_SN, 0, 1, "adsn", "Automation device serial "
146      "number (SSC)"},
147     {VPD_ATA_INFO, 0, -1, "ai", "ATA information (SAT)"},
148     {VPD_BLOCK_DEV_CHARS, 0, 0, "bdc",
149      "Block device characteristics (SBC)"},
150     {VPD_BLOCK_DEV_C_EXTENS, 0, 0, "bdce", "Block device characteristics "
151      "extension (SBC)"},
152     {VPD_BLOCK_LIMITS, 0, 0, "bl", "Block limits (SBC)"},
153     {VPD_BLOCK_LIMITS_EXT, 0, 0, "ble", "Block limits extension (SBC)"},
154     {VPD_CFA_PROFILE_INFO, 0, 0, "cfa", "CFA profile information"},
155     {VPD_CON_POS_RANGE, 0, 0, "cpr", "Concurrent positioning ranges "
156      "(SBC)"},
157     {VPD_DEVICE_CONSTITUENTS, 0, -1, "dc", "Device constituents"},
158     {VPD_DEVICE_ID, 0, -1, "di", "Device identification"},
159 #if 0           /* following found in sg_vpd */
160     {VPD_DEVICE_ID, VPD_DI_SEL_AS_IS, -1, "di_asis", "Like 'di' "
161      "but designators ordered as found"},
162     {VPD_DEVICE_ID, VPD_DI_SEL_LU, -1, "di_lu", "Device identification, "
163      "lu only"},
164     {VPD_DEVICE_ID, VPD_DI_SEL_TPORT, -1, "di_port", "Device "
165      "identification, target port only"},
166     {VPD_DEVICE_ID, VPD_DI_SEL_TARGET, -1, "di_target", "Device "
167      "identification, target device only"},
168 #endif
169     {VPD_EXT_INQ, 0, -1, "ei", "Extended inquiry data"},
170     {VPD_FORMAT_PRESETS, 0, 0, "fp", "Format presets"},
171     {VPD_LB_PROTECTION, 0, 0, "lbpro", "Logical block protection (SSC)"},
172     {VPD_LB_PROVISIONING, 0, 0, "lbpv", "Logical block provisioning "
173      "(SBC)"},
174     {VPD_MAN_ASS_SN, 0, 1, "mas", "Manufacturer assigned serial number (SSC)"},
175     {VPD_MAN_ASS_SN, 0, 0x12, "masa",
176      "Manufacturer assigned serial number (ADC)"},
177     {VPD_MAN_NET_ADDR, 0, -1, "mna", "Management network addresses"},
178     {VPD_MODE_PG_POLICY, 0, -1, "mpp", "Mode page policy"},
179     {VPD_POWER_CONDITION, 0, -1, "po", "Power condition"},/* "pc" in sg_vpd */
180     {VPD_POWER_CONSUMPTION, 0, -1, "psm", "Power consumption"},
181     {VPD_PROTO_LU, 0, -1, "pslu", "Protocol-specific logical unit "
182      "information"},
183     {VPD_PROTO_PORT, 0, -1, "pspo", "Protocol-specific port information"},
184     {VPD_REFERRALS, 0, 0, "ref", "Referrals (SBC)"},
185     {VPD_SA_DEV_CAP, 0, 1, "sad",
186      "Sequential access device capabilities (SSC)"},
187     {VPD_SUP_BLOCK_LENS, 0, 0, "sbl", "Supported block lengths and "
188      "protection types (SBC)"},
189     {VPD_SCSI_FEATURE_SETS, 0, -1, "sfs", "SCSI Feature sets"},
190     {VPD_SOFTW_INF_ID, 0, -1, "sii", "Software interface identification"},
191     {VPD_NOPE_WANT_STD_INQ, 0, -1, "sinq", "Standard inquiry data format"},
192     {VPD_UNIT_SERIAL_NUM, 0, -1, "sn", "Unit serial number"},
193     {VPD_SCSI_PORTS, 0, -1, "sp", "SCSI ports"},
194     {VPD_SUPPORTED_VPDS, 0, -1, "sv", "Supported VPD pages"},
195     {VPD_TA_SUPPORTED, 0, 1, "tas", "TapeAlert supported flags (SSC)"},
196     {VPD_3PARTY_COPY, 0, -1, "tpc", "Third party copy"},
197     {VPD_ZBC_DEV_CHARS, 0, 0, "zbdch", "Zoned block device "
198      "characteristics"},
199     {0, 0, 0, NULL, NULL},
200 };
201 
202 /* Some alternate acronyms for T10 VPD pages (compatibility with sg_vpd) */
203 static struct svpd_values_name_t alt_t10_vpd_pg[] = {
204     {VPD_NOPE_WANT_STD_INQ, 0, -1, "stdinq", "Standard inquiry data format"},
205     {VPD_POWER_CONDITION, 0, -1, "pc", "Power condition"},
206     {0, 0, 0, NULL, NULL},
207 };
208 
209 static struct svpd_values_name_t vs_vpd_pg[] = {
210     /* Following are vendor specific */
211     {SG_NVME_VPD_NICR, 0, -1, "nicr",
212      "NVMe Identify Controller Response (sg3_utils)"},
213     {VPD_RDAC_VAC, 0, -1, "rdac_vac", "RDAC volume access control (RDAC)"},
214     {VPD_RDAC_VERS, 0, -1, "rdac_vers", "RDAC software version (RDAC)"},
215     {VPD_UPR_EMC, 0, -1, "upr", "Unit path report (EMC)"},
216     {0, 0, 0, NULL, NULL},
217 };
218 
219 static struct option long_options[] = {
220 #if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS) && \
221     defined(HDIO_GET_IDENTITY)
222         {"ata", no_argument, 0, 'a'},
223 #endif
224         {"block", required_argument, 0, 'B'},
225         {"cmddt", no_argument, 0, 'c'},
226         {"descriptors", no_argument, 0, 'd'},
227         {"export", no_argument, 0, 'u'},
228         {"extended", no_argument, 0, 'x'},
229         {"force", no_argument, 0, 'f'},
230         {"help", no_argument, 0, 'h'},
231         {"hex", no_argument, 0, 'H'},
232         {"id", no_argument, 0, 'i'},
233         {"inhex", required_argument, 0, 'I'},
234         {"len", required_argument, 0, 'l'},
235         {"long", no_argument, 0, 'L'},
236         {"maxlen", required_argument, 0, 'm'},
237 #ifdef SG_SCSI_STRINGS
238         {"new", no_argument, 0, 'N'},
239         {"old", no_argument, 0, 'O'},
240 #endif
241         {"only", no_argument, 0, 'o'},
242         {"page", required_argument, 0, 'p'},
243         {"raw", no_argument, 0, 'r'},
244         {"sinq_inraw", required_argument, 0, 'Q'},
245         {"sinq-inraw", required_argument, 0, 'Q'},
246         {"vendor", no_argument, 0, 's'},
247         {"verbose", no_argument, 0, 'v'},
248         {"version", no_argument, 0, 'V'},
249         {"vpd", no_argument, 0, 'e'},
250         {0, 0, 0, 0},
251 };
252 
253 
254 static void
usage()255 usage()
256 {
257 #if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS) && \
258     defined(HDIO_GET_IDENTITY)
259 
260     pr2serr("Usage: sg_inq [--ata] [--block=0|1] [--cmddt] [--descriptors] "
261             "[--export]\n"
262             "              [--extended] [--help] [--hex] [--id] "
263             "[--inhex=FN]\n"
264             "              [--json[=JO]] [--len=LEN] [--long] "
265             "[--maxlen=LEN]\n"
266             "              [--only] [--page=PG] [--raw] [--sinq_inraw=RFN] "
267             "[--vendor]\n"
268             "              [--verbose] [--version] [--vpd] DEVICE\n"
269             "  where:\n"
270             "    --ata|-a        treat DEVICE as (directly attached) ATA "
271             "device\n");
272 #else
273     pr2serr("Usage: sg_inq [--block=0|1] [--cmddt] [--descriptors] "
274             "[--export]\n"
275             "              [--extended] [--help] [--hex] [--id] "
276             "[--inhex=FN]\n"
277             "              [--json[=JO]] [--len=LEN] [--long] "
278             "[--maxlen=LEN]\n"
279             "              [--only] [--page=PG] [--raw] [--sinq_inraw=RFN] "
280             "[--verbose]\n"
281             "              [--version] [--vpd] DEVICE\n"
282             "  where:\n");
283 #endif
284     pr2serr("    --block=0|1     0-> open(non-blocking); 1-> "
285             "open(blocking)\n"
286             "      -B 0|1        (def: depends on OS; Linux pt: 0)\n"
287             "    --cmddt|-c      command support data mode (set opcode "
288             "with '--page=PG')\n"
289             "                    use twice for list of supported "
290             "commands; obsolete\n"
291             "    --descriptors|-d    fetch and decode version descriptors\n"
292             "    --export|-u     SCSI_IDENT_<assoc>_<type>=<ident> output "
293             "format.\n"
294             "                    Defaults to device id page (0x83) if --page "
295             "not given,\n"
296             "                    only supported for VPD pages 0x80 and 0x83\n"
297             "    --extended|-E|-x    decode extended INQUIRY data VPD page "
298             "(0x86)\n"
299             "    --force|-f      skip VPD page 0 check; directly fetch "
300             "requested page\n"
301             "    --help|-h       print usage message then exit\n"
302             "    --hex|-H        output response in hex\n"
303             "    --id|-i         decode device identification VPD page "
304             "(0x83)\n"
305             "    --inhex=FN|-I FN    read ASCII hex from file FN instead of "
306             "DEVICE;\n"
307             "                        if used with --raw then read binary "
308             "from FN\n"
309             "    --json[=JO]|-j[JO]    output in JSON instead of human "
310             "readable text.\n"
311             "                          Use --json=? for JSON help\n"
312             "    --len=LEN|-l LEN    requested response length (def: 0 "
313             "-> fetch 36\n"
314             "                        bytes first, then fetch again as "
315             "indicated)\n"
316             "    --long|-L       supply extra information on NVMe devices\n"
317             "    --maxlen=LEN|-m LEN    same as '--len='\n"
318             "    --old|-O        use old interface (use as first option)\n"
319             "    --only|-o       for std inquiry do not fetch serial number "
320             "vpd page;\n"
321             "                    for NVMe device only do Identify "
322             "controller\n"
323             "    --page=PG|-p PG     Vital Product Data (VPD) page number "
324             "or\n"
325             "                        abbreviation (opcode number if "
326             "'--cmddt' given)\n"
327             "    --raw|-r        output response in binary (to stdout)\n"
328             "    --sinq_inraw=RFN|-Q RFN    read raw (binary) standard "
329             "INQUIRY\n"
330             "                               response from the RFN filename\n"
331             "    --vendor|-s     show vendor specific fields in std "
332             "inquiry\n"
333             "    --verbose|-v    increase verbosity\n"
334             "    --version|-V    print version string then exit\n"
335             "    --vpd|-e        vital product data (set page with "
336             "'--page=PG')\n\n"
337             "Sends a SCSI INQUIRY command to the DEVICE and decodes the "
338             "response.\nAlternatively it decodes the INQUIRY response held "
339             "in file FN. If no\noptions given then it sends a 'standard' "
340             "INQUIRY command to DEVICE. Can\nlist VPD pages with '--vpd' or "
341             "'--page=PG' option.\n");
342 }
343 
344 #ifdef SG_SCSI_STRINGS
345 static void
usage_old()346 usage_old()
347 {
348 #ifdef SG_LIB_LINUX
349     pr2serr("Usage:  sg_inq [-a] [-A] [-b] [-B=0|1] [-c] [-cl] [-d] [-e] "
350             "[-h]\n"
351             "               [-H] [-i] [-I=FN] [-j[=JO]] [-l=LEN] [-L] [-m] "
352             "[-M]\n"
353             "               [-o] [-p=VPD_PG] [-P] [-r] [-s] [-u] [-U] [-v] "
354             "[-V]\n"
355             "               [-x] [-36] [-?] DEVICE\n"
356             "  where:\n"
357             "    -a    decode ATA information VPD page (0x89)\n"
358             "    -A    treat <device> as (directly attached) ATA device\n");
359 #else
360     pr2serr("Usage:  sg_inq [-a] [-b] [-B 0|1] [-c] [-cl] [-d] [-e] [-h] "
361             "[-H]\n"
362             "               [-i] [-l=LEN] [-L] [-m] [-M] [-o] "
363             "[-p=VPD_PG]\n"
364             "               [-P] [-r] [-s] [-u] [-v] [-V] [-x] [-36] "
365             "[-?]\n"
366             "               DEVICE\n"
367             "  where:\n"
368             "    -a    decode ATA information VPD page (0x89)\n");
369 
370 #endif  /* SG_LIB_LINUX */
371     pr2serr("    -b    decode Block limits VPD page (0xb0) (SBC)\n"
372             "    -B=0|1    0-> open(non-blocking); 1->open(blocking)\n"
373             "    -c    set CmdDt mode (use -o for opcode) [obsolete]\n"
374             "    -cl   list supported commands using CmdDt mode [obsolete]\n"
375             "    -d    decode: version descriptors or VPD page\n"
376             "    -e    set VPD mode (use -p for page code)\n"
377             "    -h    output in hex (ASCII to the right)\n"
378             "    -H    output in hex (ASCII to the right) [same as '-h']\n"
379             "    -i    decode device identification VPD page (0x83)\n"
380             "    -I=FN    use ASCII hex in file FN instead of DEVICE\n"
381             "    -j[=JO]    output in JSON instead of human readable "
382             "text.\n"
383             "    -l=LEN    requested response length (def: 0 "
384             "-> fetch 36\n"
385             "                    bytes first, then fetch again as "
386             "indicated)\n"
387             "    -L    supply extra information on NVMe devices\n"
388             "    -m    decode management network addresses VPD page "
389             "(0x85)\n"
390             "    -M    decode mode page policy VPD page (0x87)\n"
391             "    -N|--new   use new interface\n"
392             "    -o    for std inquiry only do that, not serial number vpd "
393             "page\n"
394             "    -p=VPD_PG    vpd page code in hex (def: 0)\n"
395             "    -P    decode Unit Path Report VPD page (0xc0) (EMC)\n"
396             "    -r    output response in binary ('-rr': output for hdparm)\n"
397             "    -s    decode SCSI Ports VPD page (0x88)\n"
398             "    -u    SCSI_IDENT_<assoc>_<type>=<ident> output format\n"
399             "    -v    verbose (output cdb and, if non-zero, resid)\n"
400             "    -V    output version string\n"
401             "    -x    decode extended INQUIRY data VPD page (0x86)\n"
402             "    -36   perform standard INQUIRY with a 36 byte response\n"
403             "    -?    output this usage message\n\n"
404             "If no options given then sends a standard SCSI INQUIRY "
405             "command and\ndecodes the response.\n");
406 }
407 
408 static void
usage_for(const struct opts_t * op)409 usage_for(const struct opts_t * op)
410 {
411     if (op->opt_new)
412         usage();
413     else
414         usage_old();
415 }
416 
417 #else  /* SG_SCSI_STRINGS */
418 
419 static void
usage_for(const struct opts_t * op)420 usage_for(const struct opts_t * op)
421 {
422     if (op) { }         /* suppress warning */
423     usage();
424 }
425 
426 #endif /* SG_SCSI_STRINGS */
427 
428 /* Processes command line options according to new option format. Returns
429  * 0 is ok, else SG_LIB_SYNTAX_ERROR is returned. */
430 static int
new_parse_cmd_line(struct opts_t * op,int argc,char * argv[])431 new_parse_cmd_line(struct opts_t * op, int argc, char * argv[])
432 {
433     int c, n;
434 
435     while (1) {
436         int option_index = 0;
437 
438 #ifdef SG_LIB_LINUX
439 #ifdef SG_SCSI_STRINGS
440         c = getopt_long(argc, argv, "aB:cdeEfhHiI:j::l:Lm:M:NoOp:Q:rsuvVx",
441                         long_options, &option_index);
442 #else
443         c = getopt_long(argc, argv, "B:cdeEfhHiI:j::l:Lm:M:op:Q:rsuvVx",
444                         long_options, &option_index);
445 #endif /* SG_SCSI_STRINGS */
446 #else  /* SG_LIB_LINUX */
447 #ifdef SG_SCSI_STRINGS
448         c = getopt_long(argc, argv, "B:cdeEfhHiI:j::l:Lm:M:NoOp:Q:rsuvVx",
449                         long_options, &option_index);
450 #else
451         c = getopt_long(argc, argv, "B:cdeEfhHiI:j::l:Lm:M:op:Q:rsuvVx",
452                         long_options, &option_index);
453 #endif /* SG_SCSI_STRINGS */
454 #endif /* SG_LIB_LINUX */
455         if (c == -1)
456             break;
457 
458         switch (c) {
459 #if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS) && \
460     defined(HDIO_GET_IDENTITY)
461         case 'a':
462             op->do_ata = true;
463             break;
464 #endif
465         case 'B':
466             if ('-' == optarg[0])
467                 n = -1;
468             else {
469                 n = sg_get_num(optarg);
470                 if ((n < 0) || (n > 1)) {
471                     pr2serr("bad argument to '--block=' want 0 or 1\n");
472                     usage_for(op);
473                     return SG_LIB_SYNTAX_ERROR;
474                 }
475             }
476             op->do_block = n;
477             break;
478         case 'c':
479             ++op->do_cmddt;
480             break;
481         case 'd':
482             op->do_descriptors = true;
483             break;
484         case 'e':
485             op->do_vpd = true;
486             break;
487         case 'E':       /* --extended */
488         case 'x':
489             op->do_decode = true;
490             op->do_vpd = true;
491             op->vpd_pn = VPD_EXT_INQ;
492             op->page_given = true;
493             break;
494         case 'f':
495             op->do_force = true;
496             break;
497         case 'h':
498             ++op->do_help;
499             break;
500         case 'j':
501             if (! sgj_init_state(&op->json_st, optarg)) {
502                 int bad_char = op->json_st.first_bad_char;
503                 char e[1500];
504 
505                 if (bad_char) {
506                     pr2serr("bad argument to --json= option, unrecognized "
507                             "character '%c'\n\n", bad_char);
508                 }
509                 sg_json_usage(0, e, sizeof(e));
510                 pr2serr("%s", e);
511                 return SG_LIB_SYNTAX_ERROR;
512             }
513             break;
514         case 'o':
515             op->do_only = true;
516             break;
517         case '?':
518             if (! op->do_help)
519                 ++op->do_help;
520             break;
521         case 'H':
522             ++op->do_hex;
523             break;
524         case 'i':
525             op->do_decode = true;
526             op->do_vpd = true;
527             op->vpd_pn = VPD_DEVICE_ID;
528             op->page_given = true;
529             break;
530         case 'I':
531             op->inhex_fn = optarg;
532             break;
533         case 'l':
534         case 'm':
535             n = sg_get_num(optarg);
536             if ((n < 0) || (n > 65532)) {
537                 pr2serr("bad argument to '--len='\n");
538                 usage_for(op);
539                 return SG_LIB_SYNTAX_ERROR;
540             }
541             if ((n > 0) && (n < 4)) {
542                 pr2serr("Changing that '--maxlen=' value to 4\n");
543                 n = 4;
544             }
545             op->maxlen = n;
546             break;
547         case 'M':
548             if (op->vend_prod) {
549                 pr2serr("only one '--vendor=' option permitted\n");
550                 usage();
551                 return SG_LIB_SYNTAX_ERROR;
552             } else
553                 op->vend_prod = optarg;
554             break;
555         case 'L':
556             ++op->do_long;
557             break;
558 #ifdef SG_SCSI_STRINGS
559         case 'N':
560             break;      /* ignore */
561         case 'O':
562             op->opt_new = false;
563             return 0;
564 #endif
565         case 'p':
566             op->page_str = optarg;
567             op->page_given = true;
568             break;
569         case 'Q':
570             op->sinq_inraw_fn = optarg;
571             break;
572         case 'r':
573             ++op->do_raw;
574             break;
575         case 's':
576             ++op->do_vendor;
577             break;
578         case 'u':
579             op->do_export = true;
580             break;
581         case 'v':
582             op->verbose_given = true;
583             ++op->verbose;
584             break;
585         case 'V':
586             op->version_given = true;
587             break;
588         default:
589             pr2serr("unrecognised option code %c [0x%x]\n", c, c);
590             if (op->do_help)
591                 break;
592             usage_for(op);
593             return SG_LIB_SYNTAX_ERROR;
594         }
595     }
596     if (optind < argc) {
597         if (NULL == op->device_name) {
598             op->device_name = argv[optind];
599             ++optind;
600         }
601         if (optind < argc) {
602             for (; optind < argc; ++optind)
603                 pr2serr("Unexpected extra argument: %s\n", argv[optind]);
604             usage_for(op);
605             return SG_LIB_SYNTAX_ERROR;
606         }
607     }
608     return 0;
609 }
610 
611 #ifdef SG_SCSI_STRINGS
612 /* Processes command line options according to old option format. Returns
613  * 0 is ok, else SG_LIB_SYNTAX_ERROR is returned. */
614 static int
old_parse_cmd_line(struct opts_t * op,int argc,char * argv[])615 old_parse_cmd_line(struct opts_t * op, int argc, char * argv[])
616 {
617     bool jmp_out;
618     int k, plen, num, n;
619     const char * cp;
620 
621     for (k = 1; k < argc; ++k) {
622         cp = argv[k];
623         plen = strlen(cp);
624         if (plen <= 0)
625             continue;
626         if ('-' == *cp) {
627             for (--plen, ++cp, jmp_out = false; plen > 0; --plen, ++cp) {
628                 switch (*cp) {
629                 case '3':
630                     if ('6' == *(cp + 1)) {
631                         op->maxlen = 36;
632                         --plen;
633                         ++cp;
634                     } else
635                         jmp_out = true;
636                     break;
637                 case 'a':
638                     op->vpd_pn = VPD_ATA_INFO;
639                     op->do_vpd = true;
640                     op->page_given = true;
641                     ++op->num_pages;
642                     break;
643 #ifdef SG_LIB_LINUX
644                 case 'A':
645                     op->do_ata = true;
646                     break;
647 #endif
648                 case 'b':
649                     op->vpd_pn = VPD_BLOCK_LIMITS;
650                     op->do_vpd = true;
651                     op->page_given = true;
652                     ++op->num_pages;
653                     break;
654                 case 'c':
655                     ++op->do_cmddt;
656                     if ('l' == *(cp + 1)) {
657                         ++op->do_cmddt;
658                         --plen;
659                         ++cp;
660                     }
661                     break;
662                 case 'd':
663                     op->do_descriptors = true;
664                     op->do_decode = true;
665                     break;
666                 case 'e':
667                     op->do_vpd = true;
668                     break;
669                 case 'f':
670                     op->do_force = true;
671                     break;
672                 case 'h':
673                 case 'H':
674                     ++op->do_hex;
675                     break;
676                 case 'i':
677                     op->vpd_pn = VPD_DEVICE_ID;
678                     op->do_vpd = true;
679                     op->page_given = true;
680                     ++op->num_pages;
681                     break;
682                 case 'L':
683                     ++op->do_long;
684                     break;
685                 case 'm':
686                     op->vpd_pn = VPD_MAN_NET_ADDR;
687                     op->do_vpd = true;
688                     ++op->num_pages;
689                     op->page_given = true;
690                     break;
691                 case 'M':
692                     op->vpd_pn = VPD_MODE_PG_POLICY;
693                     op->do_vpd = true;
694                     op->page_given = true;
695                     ++op->num_pages;
696                     break;
697                 case 'N':
698                     op->opt_new = true;
699                     return 0;
700                 case 'o':
701                     op->do_only = true;
702                     break;
703                 case 'O':
704                     break;
705                 case 'P':
706                     op->vpd_pn = VPD_UPR_EMC;
707                     op->do_vpd = true;
708                     op->page_given = true;
709                     ++op->num_pages;
710                     break;
711                 case 'r':
712                     ++op->do_raw;
713                     break;
714                 case 's':
715                     op->vpd_pn = VPD_SCSI_PORTS;
716                     op->do_vpd = true;
717                     op->page_given = true;
718                     ++op->num_pages;
719                     break;
720                 case 'u':
721                     op->do_export = true;
722                     break;
723                 case 'v':
724                     op->verbose_given = true;
725                     ++op->verbose;
726                     break;
727                 case 'V':
728                     op->version_given = true;
729                     break;
730                 case 'x':
731                     op->vpd_pn = VPD_EXT_INQ;
732                     op->do_vpd = true;
733                     op->page_given = true;
734                     ++op->num_pages;
735                     break;
736                 case '?':
737                     if (! op->do_help)
738                         ++op->do_help;
739                     break;
740                 default:
741                     jmp_out = true;
742                     break;
743                 }
744                 if (jmp_out)
745                     break;
746             }
747             if (plen <= 0)
748                 continue;
749             else if (0 == strncmp("B=", cp, 2)) {
750                 num = sscanf(cp + 2, "%d", &n);
751                 if ((1 != num) || (n < 0) || (n > 1)) {
752                     pr2serr("'B=' option expects 0 or 1\n");
753                     usage_for(op);
754                     return SG_LIB_SYNTAX_ERROR;
755                 }
756                 op->do_block = n;
757             } else if (0 == strncmp("I=", cp, 2))
758                 op->inhex_fn = cp + 2;
759             else if ('j' == *cp) { /* handle either '-j' or '-j=<JO>' */
760                 const char * c2p = (('=' == *(cp + 1)) ? cp + 2 : NULL);
761 
762                 if (! sgj_init_state(&op->json_st, c2p)) {
763                     int bad_char = op->json_st.first_bad_char;
764                     char e[1500];
765 
766                     if (bad_char) {
767                         pr2serr("bad argument to --json= option, unrecognized "
768                                 "character '%c'\n\n", bad_char);
769                     }
770                     sg_json_usage(0, e, sizeof(e));
771                     pr2serr("%s", e);
772                     return SG_LIB_SYNTAX_ERROR;
773                 }
774             } else if (0 == strncmp("l=", cp, 2)) {
775                 num = sscanf(cp + 2, "%d", &n);
776                 if ((1 != num) || (n < 1)) {
777                     pr2serr("Inappropriate value after 'l=' option\n");
778                     usage_for(op);
779                     return SG_LIB_SYNTAX_ERROR;
780                 } else if (n > MX_ALLOC_LEN) {
781                     pr2serr("value after 'l=' option too large\n");
782                     return SG_LIB_SYNTAX_ERROR;
783                 }
784                 if ((n > 0) && (n < 4)) {
785                     pr2serr("Changing that '-l=' value to 4\n");
786                     n = 4;
787                 }
788                 op->maxlen = n;
789             } else if (0 == strncmp("p=", cp, 2)) {
790                 op->page_str = cp + 2;
791                 op->page_given = true;
792             } else if (0 == strncmp("-old", cp, 4))
793                 ;
794             else if (jmp_out) {
795                 pr2serr("Unrecognized option: %s\n", cp);
796                 usage_for(op);
797                 return SG_LIB_SYNTAX_ERROR;
798             }
799         } else if (0 == op->device_name)
800             op->device_name = cp;
801         else {
802             pr2serr("too many arguments, got: %s, not expecting: %s\n",
803                     op->device_name, cp);
804             usage_for(op);
805             return SG_LIB_SYNTAX_ERROR;
806         }
807     }
808     return 0;
809 }
810 
811 /* Process command line options. First check using new option format unless
812  * the SG3_UTILS_OLD_OPTS environment variable is defined which causes the
813  * old option format to be checked first. Both new and old format can be
814  * countermanded by a '-O' and '-N' options respectively. As soon as either
815  * of these options is detected (when processing the other format), processing
816  * stops and is restarted using the other format. Clear? */
817 static int
parse_cmd_line(struct opts_t * op,int argc,char * argv[])818 parse_cmd_line(struct opts_t * op, int argc, char * argv[])
819 {
820     int res;
821     char * cp;
822 
823     cp = getenv("SG3_UTILS_OLD_OPTS");
824     if (cp) {
825         op->opt_new = false;
826         res = old_parse_cmd_line(op, argc, argv);
827         if ((0 == res) && op->opt_new)
828             res = new_parse_cmd_line(op, argc, argv);
829     } else {
830         op->opt_new = true;
831         res = new_parse_cmd_line(op, argc, argv);
832         if ((0 == res) && (! op->opt_new))
833             res = old_parse_cmd_line(op, argc, argv);
834     }
835     return res;
836 }
837 
838 #else  /* SG_SCSI_STRINGS */
839 
840 static int
parse_cmd_line(struct opts_t * op,int argc,char * argv[])841 parse_cmd_line(struct opts_t * op, int argc, char * argv[])
842 {
843     return new_parse_cmd_line(op, argc, argv);
844 }
845 
846 #endif  /* SG_SCSI_STRINGS */
847 
848 
849 static const struct svpd_values_name_t *
sdp_find_vpd_by_acron(const char * ap)850 sdp_find_vpd_by_acron(const char * ap)
851 {
852     const struct svpd_values_name_t * vnp;
853 
854     for (vnp = t10_vpd_pg; vnp->acron; ++vnp) {
855         if (0 == strcmp(vnp->acron, ap))
856             return vnp;
857     }
858     for (vnp = alt_t10_vpd_pg; vnp->acron; ++vnp) {
859         if (0 == strcmp(vnp->acron, ap))
860             return vnp;
861     }
862     for (vnp = vs_vpd_pg; vnp->acron; ++vnp) {
863         if (0 == strcmp(vnp->acron, ap))
864             return vnp;
865     }
866     return NULL;
867 }
868 
869 static void
enumerate_vpds()870 enumerate_vpds()
871 {
872     const struct svpd_values_name_t * vnp;
873 
874     printf("T10 defined VPD pages:\n");
875     for (vnp = t10_vpd_pg; vnp->acron; ++vnp) {
876         if (vnp->name) {
877             if (vnp->value < 0)
878                 printf("  %-10s   -1      %s\n", vnp->acron, vnp->name);
879             else
880                 printf("  %-10s 0x%02x      %s\n", vnp->acron, vnp->value,
881                        vnp->name);
882         }
883     }
884     printf("Vendor specific VPD pages:\n");
885     for (vnp = vs_vpd_pg; vnp->acron; ++vnp) {
886         if (vnp->name) {
887             if (vnp->value < 0)
888                 printf("  %-10s   -1      %s\n", vnp->acron, vnp->name);
889             else
890                 printf("  %-10s 0x%02x      %s\n", vnp->acron, vnp->value,
891                        vnp->name);
892         }
893     }
894 }
895 
896 static void
dStrRaw(const char * str,int len)897 dStrRaw(const char * str, int len)
898 {
899     int k;
900 
901     for (k = 0; k < len; ++k)
902         printf("%c", str[k]);
903 }
904 
905 /* Strip initial and trailing whitespaces; convert one or repeated
906  * whitespaces to a single "_"; convert non-printable characters to "."
907  * and if there are no valid (i.e. printable) characters return 0.
908  * Process 'str' in place (i.e. it's input and output) and return the
909  * length of the output, excluding the trailing '\0'. To cover any
910  * potential unicode string an intermediate zero is skipped; two
911  * consecutive zeroes indicate a string termination.
912  */
913 static int
encode_whitespaces(uint8_t * str,int inlen)914 encode_whitespaces(uint8_t *str, int inlen)
915 {
916     int k, res;
917     int j;
918     bool valid = false;
919     int outlen = inlen, zeroes = 0;
920 
921     /* Skip initial whitespaces */
922     for (j = 0; (j < inlen) && isblank(str[j]); ++j)
923         ;
924     if (j < inlen) {
925         /* Skip possible unicode prefix characters */
926         for ( ; (j < inlen) && (str[j] < 0x20); ++j)
927             ;
928     }
929     k = j;
930     /* Strip trailing whitespaces */
931     while ((outlen > k) &&
932            (isblank(str[outlen - 1]) || ('\0' == str[outlen - 1]))) {
933         str[outlen - 1] = '\0';
934         outlen--;
935     }
936     for (res = 0; k < outlen; ++k) {
937         if (isblank(str[k])) {
938             if ((res > 0) && ('_' != str[res - 1])) {
939                 str[res++] = '_';
940                 valid = true;
941             }
942             zeroes = 0;
943         } else if (! isprint(str[k])) {
944             if (str[k] == 0x00) {
945                 /* Stop on more than one consecutive zero */
946                 if (zeroes)
947                     break;
948                 zeroes++;
949                 continue;
950             }
951             str[res++] = '.';
952             zeroes = 0;
953         } else {
954             str[res++] = str[k];
955             valid = true;
956             zeroes = 0;
957         }
958     }
959     if (! valid)
960         res = 0;
961     if (res < inlen)
962         str[res] = '\0';
963     return res;
964 }
965 
966 static int
encode_unicode(uint8_t * str,int inlen)967 encode_unicode(uint8_t *str, int inlen)
968 {
969     int k = 0, res;
970     int zeroes = 0;
971 
972     for (res = 0; k < inlen; ++k) {
973         if (str[k] == 0x00) {
974             if (zeroes) {
975                 str[res++] = '\0';
976                 break;
977             }
978             zeroes++;
979         } else {
980             zeroes = 0;
981             if (isprint(str[k]))
982                 str[res++] = str[k];
983             else
984                 str[res++] = ' ';
985         }
986     }
987 
988     return res;
989 }
990 
991 static int
encode_string(char * out,const uint8_t * in,int inlen)992 encode_string(char *out, const uint8_t *in, int inlen)
993 {
994     int i, j = 0;
995 
996     for (i = 0; (i < inlen); ++i) {
997         if (isblank(in[i]) || !isprint(in[i])) {
998             sprintf(&out[j], "\\x%02x", in[i]);
999             j += 4;
1000         } else {
1001             out[j] = in[i];
1002             j++;
1003         }
1004     }
1005     out[j] = '\0';
1006     return j;
1007 }
1008 
1009 static const struct svpd_values_name_t *
get_vpd_page_info(int vpd_page_num,int dev_pdt)1010 get_vpd_page_info(int vpd_page_num, int dev_pdt)
1011 {
1012     int decay_pdt;
1013     const struct svpd_values_name_t * vnp;
1014     const struct svpd_values_name_t * prev_vnp;
1015 
1016     if (vpd_page_num < 0xb0) {  /* take T10 first match */
1017         for (vnp = t10_vpd_pg; vnp->acron; ++vnp) {
1018             if (vnp->value == vpd_page_num)
1019                 return vnp;
1020         }
1021         return NULL;
1022     } else if (vpd_page_num < 0xc0) {
1023         for (vnp = t10_vpd_pg; vnp->acron; ++vnp) {
1024             if (vnp->value == vpd_page_num)
1025                 break;
1026         }
1027         if (NULL == vnp->acron)
1028             return NULL;
1029         if (vnp->pdt == dev_pdt)        /* exact match */
1030             return vnp;
1031         prev_vnp = vnp;
1032 
1033         for (++vnp; vnp->acron; ++vnp) {
1034             if (vnp->value == vpd_page_num)
1035                 break;
1036         }
1037         decay_pdt = sg_lib_pdt_decay(dev_pdt);
1038         if (NULL == vnp->acron) {
1039             if (decay_pdt == prev_vnp->pdt)
1040                 return prev_vnp;
1041             return NULL;
1042         }
1043         if ((vnp->pdt == dev_pdt) || (vnp->pdt == decay_pdt))
1044             return vnp;
1045         if (decay_pdt == prev_vnp->pdt)
1046             return prev_vnp;
1047 
1048         for (++vnp; vnp->acron; ++vnp) {
1049             if (vnp->value == vpd_page_num)
1050                 break;
1051         }
1052         if (NULL == vnp->acron)
1053             return NULL;
1054         if ((vnp->pdt == dev_pdt) || (vnp->pdt == decay_pdt))
1055             return vnp;
1056         return NULL;            /* give up */
1057     } else {    /* vendor specific: vpd >= 0xc0 */
1058         for (vnp = vs_vpd_pg; vnp->acron; ++vnp) {
1059             if (vnp->pdt == dev_pdt)
1060                 return vnp;
1061         }
1062         return NULL;
1063     }
1064 }
1065 
1066 static int
svpd_inhex_decode_all(struct opts_t * op,sgj_opaque_p jop)1067 svpd_inhex_decode_all(struct opts_t * op, sgj_opaque_p jop)
1068 {
1069     int k, res, pn;
1070     int max_pn = 255;
1071     int bump, off;
1072     int in_len = op->maxlen;
1073     int prev_pn = -1;
1074     sgj_state * jsp = &op->json_st;
1075     uint8_t vpd0_buff[512];
1076     uint8_t * rp = vpd0_buff;
1077 
1078     if (op->vpd_pn > 0)
1079         max_pn = op->vpd_pn;
1080 
1081     res = 0;
1082     if (op->page_given && (VPD_NOPE_WANT_STD_INQ == op->vpd_pn))
1083         return vpd_decode(-1, op, jop, 0);
1084 
1085     for (k = 0, off = 0; off < in_len; ++k, off += bump) {
1086         rp = rsp_buff + off;
1087         pn = rp[1];
1088         bump = sg_get_unaligned_be16(rp + 2) + 4;
1089         if ((off + bump) > in_len) {
1090             pr2serr("%s: page 0x%x size (%d) exceeds buffer\n", __func__,
1091                     pn, bump);
1092             bump = in_len - off;
1093         }
1094         if (op->page_given && (pn != op->vpd_pn))
1095             continue;
1096         if (pn <= prev_pn) {
1097             pr2serr("%s: prev_pn=0x%x, this pn=0x%x, not ascending so "
1098                     "exit\n", __func__, prev_pn, pn);
1099             break;
1100         }
1101         prev_pn = pn;
1102         op->vpd_pn = pn;
1103         if (pn > max_pn) {
1104             if (op->verbose > 2)
1105                 pr2serr("%s: skipping as this pn=0x%x exceeds "
1106                         "max_pn=0x%x\n", __func__, pn, max_pn);
1107             continue;
1108         }
1109         if (op->do_long) {
1110             if (jsp->pr_as_json)
1111                sgj_pr_hr(jsp, "[0x%x]:\n", pn);
1112             else
1113                sgj_pr_hr(jsp, "[0x%x] ", pn);
1114         }
1115 
1116         res = vpd_decode(-1, op, jop, off);
1117         if (SG_LIB_CAT_OTHER == res) {
1118             if (op->verbose)
1119                 pr2serr("Can't decode VPD page=0x%x\n", pn);
1120         }
1121     }
1122     return res;
1123 }
1124 
1125 static void
decode_supported_vpd_4inq(uint8_t * buff,int len,struct opts_t * op,sgj_opaque_p jap)1126 decode_supported_vpd_4inq(uint8_t * buff, int len, struct opts_t * op,
1127                           sgj_opaque_p jap)
1128 {
1129     int vpd, k, rlen, pdt;
1130     sgj_state * jsp = &op->json_st;
1131     sgj_opaque_p jo2p;
1132     const struct svpd_values_name_t * vnp;
1133     char b[64];
1134 
1135     if (op->do_hex) {
1136         hex2stdout(buff, len, no_ascii_4hex(op));
1137         return;
1138     }
1139     if (len < 4) {
1140         pr2serr("Supported VPD pages VPD page length too short=%d\n", len);
1141         return;
1142     }
1143     pdt = PDT_MASK & buff[0];
1144     rlen = buff[3] + 4;
1145     if (rlen > len)
1146         pr2serr("Supported VPD pages VPD page truncated, indicates %d, got "
1147                 "%d\n", rlen, len);
1148     else
1149         len = rlen;
1150     sgj_pr_hr(jsp, "   Supported VPD pages:\n");
1151     for (k = 0; k < len - 4; ++k) {
1152         vpd = buff[4 + k];
1153         snprintf(b, sizeof(b), "0x%x", vpd);
1154         vnp = get_vpd_page_info(vpd, pdt);
1155         if (jsp->pr_as_json && jap) {
1156             jo2p = sgj_new_unattached_object_r(jsp);
1157             sgj_js_nv_i(jsp, jo2p, "i", vpd);
1158             sgj_js_nv_s(jsp, jo2p, "hex", b + 2);
1159             sgj_js_nv_s(jsp, jo2p, "name", vnp ? vnp->name : "unknown");
1160             sgj_js_nv_s(jsp, jo2p, "acronym", vnp ? vnp->acron : "unknown");
1161             sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p);
1162         }
1163         if (vnp)
1164             sgj_pr_hr(jsp, "     %s\t%s\n", b, vnp->name);
1165         else
1166             sgj_pr_hr(jsp, "     %s\n", b);
1167     }
1168 }
1169 
1170 static bool
vpd_page_is_supported(uint8_t * vpd_pg0,int v0_len,int pg_num,int vb)1171 vpd_page_is_supported(uint8_t * vpd_pg0, int v0_len, int pg_num, int vb)
1172 {
1173     int k, rlen;
1174 
1175     if (v0_len < 4)
1176         return false;
1177 
1178     rlen = vpd_pg0[3] + 4;
1179     if (rlen > v0_len)
1180         pr2serr("Supported VPD pages VPD page truncated, indicates %d, got "
1181                 "%d\n", rlen, v0_len);
1182     else
1183         v0_len = rlen;
1184     if (vb > 1) {
1185         pr2serr("Supported VPD pages, hex list: ");
1186         hex2stderr(vpd_pg0 + 4, v0_len - 4, -1);
1187     }
1188     for (k = 4; k < v0_len; ++k) {
1189         if(vpd_pg0[k] == pg_num)
1190             return true;
1191     }
1192     return false;
1193 }
1194 
1195 /* ASCII Information VPD pages (page numbers: 0x1 to 0x7f) */
1196 static void
decode_ascii_inf(uint8_t * buff,int len,struct opts_t * op)1197 decode_ascii_inf(uint8_t * buff, int len, struct opts_t * op)
1198 {
1199     int al, k, bump;
1200     uint8_t * bp;
1201     uint8_t * p;
1202     sgj_state * jsp = &op->json_st;
1203 
1204     if (op->do_hex) {
1205         hex2stdout(buff, len, no_ascii_4hex(op));
1206         return;
1207     }
1208     if (len < 4) {
1209         pr2serr("ASCII information VPD page length too short=%d\n", len);
1210         return;
1211     }
1212     if (4 == len)
1213         return;
1214     al = buff[4];
1215     if ((al + 5) > len)
1216         al = len - 5;
1217     for (k = 0, bp = buff + 5; k < al; k += bump, bp += bump) {
1218         p = (uint8_t *)memchr(bp, 0, al - k);
1219         if (! p) {
1220             sgj_pr_hr(jsp, "  %.*s\n", al - k, (const char *)bp);
1221             break;
1222         }
1223         sgj_pr_hr(jsp, "  %s\n", (const char *)bp);
1224         bump = (p - bp) + 1;
1225     }
1226     bp = buff + 5 + al;
1227     if (bp < (buff + len)) {
1228         sgj_pr_hr(jsp, "Vendor specific information in hex:\n");
1229         hex2stdout(bp, len - (al + 5), 0);
1230     }
1231 }
1232 
1233 static void
decode_id_vpd(uint8_t * buff,int len,struct opts_t * op,sgj_opaque_p jap)1234 decode_id_vpd(uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap)
1235 {
1236     if (len < 4) {
1237         pr2serr("Device identification VPD page length too "
1238                 "short=%d\n", len);
1239         return;
1240     }
1241     decode_dev_ids("Device identification", buff + 4, len - 4, op, jap);
1242 }
1243 
1244 /* VPD_SCSI_PORTS   0x88  ["sp"] */
1245 static void
decode_scsi_ports_vpd_4inq(uint8_t * buff,int len,struct opts_t * op,sgj_opaque_p jap)1246 decode_scsi_ports_vpd_4inq(uint8_t * buff, int len, struct opts_t * op,
1247                            sgj_opaque_p jap)
1248 {
1249     int k, bump, rel_port, ip_tid_len, tpd_len;
1250     uint8_t * bp;
1251     sgj_state * jsp = &op->json_st;
1252     sgj_opaque_p jo2p;
1253 
1254     if (len < 4) {
1255         pr2serr("SCSI Ports VPD page length too short=%d\n", len);
1256         return;
1257     }
1258     if (op->do_hex > 2) {
1259         hex2stdout(buff, len, -1);
1260         return;
1261     }
1262     len -= 4;
1263     bp = buff + 4;
1264     for (k = 0; k < len; k += bump, bp += bump) {
1265         jo2p = sgj_new_unattached_object_r(jsp);
1266         rel_port = sg_get_unaligned_be16(bp + 2);
1267         sgj_pr_hr(jsp, "Relative port=%d\n", rel_port);
1268         sgj_js_nv_i(jsp, jo2p, "relative_port", rel_port);
1269         ip_tid_len = sg_get_unaligned_be16(bp + 6);
1270         bump = 8 + ip_tid_len;
1271         if ((k + bump) > len) {
1272             pr2serr("SCSI Ports VPD page, short descriptor "
1273                     "length=%d, left=%d\n", bump, (len - k));
1274             sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p);
1275             return;
1276         }
1277         if (ip_tid_len > 0) {
1278             if (op->do_hex) {
1279                 printf(" Initiator port transport id:\n");
1280                 hex2stdout((bp + 8), ip_tid_len, no_ascii_4hex(op));
1281             } else {
1282                 char b[1024];
1283 
1284                 sg_decode_transportid_str("    ", bp + 8, ip_tid_len,
1285                                           true, sizeof(b), b);
1286                 if (jsp->pr_as_json)
1287                     sgj_js_nv_s(jsp, jo2p, "initiator_port_transport_id", b);
1288                 sgj_pr_hr(jsp, "%s",
1289                           sg_decode_transportid_str("    ", bp + 8,
1290                                             ip_tid_len, true, sizeof(b), b));
1291             }
1292         }
1293         tpd_len = sg_get_unaligned_be16(bp + bump + 2);
1294         if ((k + bump + tpd_len + 4) > len) {
1295             pr2serr("SCSI Ports VPD page, short descriptor(tgt) "
1296                     "length=%d, left=%d\n", bump, (len - k));
1297             sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p);
1298             return;
1299         }
1300         if (tpd_len > 0) {
1301             sgj_pr_hr(jsp, " Target port descriptor(s):\n");
1302             if (op->do_hex)
1303                 hex2stdout(bp + bump + 4, tpd_len, no_ascii_4hex(op));
1304             else {
1305                 sgj_opaque_p ja2p = sgj_named_subarray_r(jsp, jo2p,
1306                                         "target_port_descriptor_list");
1307 
1308                 decode_dev_ids("SCSI Ports", bp + bump + 4, tpd_len,
1309                                op, ja2p);
1310             }
1311         }
1312         bump += tpd_len + 4;
1313         sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p);
1314     }
1315 }
1316 
1317 /* These are target port, device server (i.e. target) and LU identifiers */
1318 static void
decode_dev_ids(const char * leadin,uint8_t * buff,int len,struct opts_t * op,sgj_opaque_p jap)1319 decode_dev_ids(const char * leadin, uint8_t * buff, int len,
1320                struct opts_t * op, sgj_opaque_p jap)
1321 {
1322     int u, j, m, id_len, p_id, c_set, piv, assoc, desig_type, i_len;
1323     int off, ci_off, c_id, d_id, naa, vsi, k, n;
1324     uint64_t vsei, id_ext, ccc_id;
1325     const uint8_t * bp;
1326     const uint8_t * ip;
1327     const char * cp;
1328     sgj_state * jsp = &op->json_st;
1329     char b[256];
1330     char d[64];
1331     static const int blen = sizeof(b);
1332     static const int dlen = sizeof(d);
1333 
1334     if (jsp->pr_as_json) {
1335         int ret = filter_json_dev_ids(buff, len, -1, op, jap);
1336 
1337         if (ret || (! jsp->pr_out_hr))
1338             return;
1339     }
1340     if (buff[2] > 2) {  /* SPC-3,4,5 buff[2] is upper byte of length */
1341         /*
1342          * Reference the 3rd byte of the first Identification descriptor
1343          * of a page 83 reply to determine whether the reply is compliant
1344          * with SCSI-2 or SPC-2/3 specifications.  A zero value in the
1345          * 3rd byte indicates an SPC-2/3 conforming reply ( the field is
1346          * reserved ).  This byte will be non-zero for a SCSI-2
1347          * conforming page 83 reply from these EMC Symmetrix models since
1348          * the 7th byte of the reply corresponds to the 4th and 5th
1349          * nibbles of the 6-byte OUI for EMC, that is, 0x006048.
1350          */
1351         i_len = len;
1352         ip = bp = buff;
1353         c_set = 1;
1354         assoc = 0;
1355         piv = 0;
1356         p_id = 0xf;
1357         desig_type = 3;
1358         j = 1;
1359         off = 16;
1360         sgj_pr_hr(jsp, "  Pre-SPC descriptor, descriptor length: %d\n",
1361                   i_len);
1362         goto decode;
1363     }
1364 
1365     for (j = 1, off = -1;
1366          (u = sg_vpd_dev_id_iter(buff, len, &off, -1, -1, -1)) == 0;
1367          ++j) {
1368         bp = buff + off;
1369         i_len = bp[3];
1370         id_len = i_len + 4;
1371         sgj_pr_hr(jsp, "  Designation descriptor number %d, "
1372                   "descriptor length: %d\n", j, id_len);
1373         if ((off + id_len) > len) {
1374             pr2serr("%s VPD page error: designator length longer "
1375                     "than\n     remaining response length=%d\n", leadin,
1376                     (len - off));
1377             return;
1378         }
1379         ip = bp + 4;
1380         p_id = ((bp[0] >> 4) & 0xf);   /* protocol identifier */
1381         c_set = (bp[0] & 0xf);         /* code set */
1382         piv = ((bp[1] & 0x80) ? 1 : 0); /* protocol identifier valid */
1383         assoc = ((bp[1] >> 4) & 0x3);
1384         desig_type = (bp[1] & 0xf);
1385   decode:
1386         if (piv && ((1 == assoc) || (2 == assoc)))
1387             sgj_pr_hr(jsp, "    transport: %s\n",
1388                       sg_get_trans_proto_str(p_id, dlen, d));
1389         n = 0;
1390         cp = sg_get_desig_type_str(desig_type);
1391         n += sg_scnpr(b + n, blen - n, "    designator_type: %s,  ",
1392                       cp ? cp : "-");
1393         cp = sg_get_desig_code_set_str(c_set);
1394         sgj_pr_hr(jsp, "%scode_set: %s\n", b, cp ? cp : "-");
1395         cp = sg_get_desig_assoc_str(assoc);
1396         sgj_pr_hr(jsp, "    associated with the %s\n", cp ? cp : "-");
1397         if (op->do_hex) {
1398             sgj_pr_hr(jsp, "    designator header(hex): %.2x %.2x %.2x %.2x\n",
1399                    bp[0], bp[1], bp[2], bp[3]);
1400             sgj_pr_hr(jsp, "    designator:\n");
1401             hex2stdout(ip, i_len, 0);
1402             continue;
1403         }
1404         switch (desig_type) {
1405         case 0: /* vendor specific */
1406             k = 0;
1407             if ((2 == c_set) || (3 == c_set)) { /* ASCII or UTF-8 */
1408                 for (k = 0; (k < i_len) && isprint(ip[k]); ++k)
1409                     ;
1410                 if (k >= i_len)
1411                     k = 1;
1412             }
1413             if (k)
1414                 sgj_pr_hr(jsp, "      vendor specific: %.*s\n", i_len, ip);
1415             else {
1416                 sgj_pr_hr(jsp, "      vendor specific:\n");
1417                 hex2stdout(ip, i_len, -1);
1418             }
1419             break;
1420         case 1: /* T10 vendor identification */
1421             sgj_pr_hr(jsp, "      vendor id: %.8s\n", ip);
1422             if (i_len > 8) {
1423                 if ((2 == c_set) || (3 == c_set)) { /* ASCII or UTF-8 */
1424                     sgj_pr_hr(jsp, "      vendor specific: %.*s\n", i_len - 8,
1425                               ip + 8);
1426                 } else {
1427                     n = 0;
1428                     n += sg_scnpr(b + n, blen - n,
1429                                   "      vendor specific: 0x");
1430                     for (m = 8; m < i_len; ++m)
1431                         n += sg_scnpr(b + n, blen - n, "%02x", ip[m]);
1432                     sgj_pr_hr(jsp, "%s\n", b);
1433                 }
1434             }
1435             break;
1436         case 2: /* EUI-64 based */
1437             sgj_pr_hr(jsp, "      EUI-64 based %d byte identifier\n", i_len);
1438             if (1 != c_set) {
1439                 pr2serr("      << expected binary code_set (1)>>\n");
1440                 hex2stderr(ip, i_len, -1);
1441                 break;
1442             }
1443             ci_off = 0;
1444             n = 0;
1445             b[0] = '\0';
1446             if (16 == i_len) {
1447                 ci_off = 8;
1448                 id_ext = sg_get_unaligned_be64(ip);
1449                 n += sg_scnpr(b + n, blen - n,
1450                               "      Identifier extension: 0x%" PRIx64 "\n",
1451                               id_ext);
1452             } else if ((8 != i_len) && (12 != i_len)) {
1453                 pr2serr("      << can only decode 8, 12 and 16 "
1454                         "byte ids>>\n");
1455                 hex2stderr(ip, i_len, -1);
1456                 break;
1457             }
1458             ccc_id = sg_get_unaligned_be64(ip + ci_off);
1459             sgj_pr_hr(jsp, "%s      IEEE identifier: 0x%" PRIx64 "\n", b,
1460                       ccc_id);
1461             if (12 == i_len) {
1462                 d_id = sg_get_unaligned_be32(ip + 8);
1463                 sgj_pr_hr(jsp, "      Directory ID: 0x%x\n", d_id);
1464             }
1465             n = 0;
1466             n += sg_scnpr(b + n, blen - n, "      [0x");
1467             for (m = 0; m < i_len; ++m)
1468                 n += sg_scnpr(b + n, blen - n, "%02x", ip[m]);
1469             sgj_pr_hr(jsp, "%s]\n", b);
1470             break;
1471         case 3: /* NAA <n> */
1472             naa = (ip[0] >> 4) & 0xff;
1473             if (1 != c_set) {
1474                 pr2serr("      << expected binary code_set (1), got %d for "
1475                         "NAA=%d>>\n", c_set, naa);
1476                 hex2stderr(ip, i_len, -1);
1477                 break;
1478             }
1479             switch (naa) {
1480             case 2:     /* NAA 2: IEEE Extended */
1481                 if (8 != i_len) {
1482                     pr2serr("      << unexpected NAA 2 identifier "
1483                             "length: 0x%x>>\n", i_len);
1484                     hex2stderr(ip, i_len, -1);
1485                     break;
1486                 }
1487                 d_id = (((ip[0] & 0xf) << 8) | ip[1]);
1488                 c_id = sg_get_unaligned_be24(ip + 2);
1489                 vsi = sg_get_unaligned_be24(ip + 5);
1490                 sgj_pr_hr(jsp, "      NAA 2, vendor specific identifier A: "
1491                           "0x%x\n", d_id);
1492                 sgj_pr_hr(jsp, "      AOI: 0x%x\n", c_id);
1493                 sgj_pr_hr(jsp, "      vendor specific identifier B: 0x%x\n",
1494                           vsi);
1495                 n = 0;
1496                 n += sg_scnpr(b + n, blen - n, "      [0x");
1497                 for (m = 0; m < 8; ++m)
1498                     n += sg_scnpr(b + n, blen - n, "%02x", ip[m]);
1499                 sgj_pr_hr(jsp, "%s]\n", b);
1500                 break;
1501             case 3:     /* NAA 3: Locally assigned */
1502                 if (8 != i_len) {
1503                     pr2serr("      << unexpected NAA 3 identifier "
1504                             "length: 0x%x>>\n", i_len);
1505                     hex2stderr(ip, i_len, -1);
1506                     break;
1507                 }
1508                 sgj_pr_hr(jsp, "      NAA 3, Locally assigned:\n");
1509                 n = 0;
1510                 n += sg_scnpr(b + n, blen - n, "      [0x");
1511                 for (m = 0; m < 8; ++m)
1512                     n += sg_scnpr(b + n, blen - n, "%02x", ip[m]);
1513                 sgj_pr_hr(jsp, "%s]\n", b);
1514                 break;
1515             case 5:     /* NAA 5: IEEE Registered */
1516                 if (8 != i_len) {
1517                     pr2serr("      << unexpected NAA 5 identifier "
1518                             "length: 0x%x>>\n", i_len);
1519                     hex2stderr(ip, i_len, -1);
1520                     break;
1521                 }
1522                 c_id = (((ip[0] & 0xf) << 20) | (ip[1] << 12) |
1523                         (ip[2] << 4) | ((ip[3] & 0xf0) >> 4));
1524                 vsei = ip[3] & 0xf;
1525                 for (m = 1; m < 5; ++m) {
1526                     vsei <<= 8;
1527                     vsei |= ip[3 + m];
1528                 }
1529                 sgj_pr_hr(jsp, "      NAA 5, AOI: 0x%x\n", c_id);
1530                 n = 0;
1531                 n += sg_scnpr(b + n, blen - n, "      Vendor Specific "
1532                               "Identifier: 0x%" PRIx64 "\n", vsei);
1533                 n += sg_scnpr(b + n, blen - n, "      [0x");
1534                 for (m = 0; m < 8; ++m)
1535                     n += sg_scnpr(b + n, blen - n, "%02x", ip[m]);
1536                 sgj_pr_hr(jsp, "%s]\n", b);
1537                 break;
1538             case 6:     /* NAA 6: IEEE Registered extended */
1539                 if (16 != i_len) {
1540                     pr2serr("      << unexpected NAA 6 identifier "
1541                             "length: 0x%x>>\n", i_len);
1542                     hex2stderr(ip, i_len, 0);
1543                     break;
1544                 }
1545                 c_id = (((ip[0] & 0xf) << 20) | (ip[1] << 12) |
1546                         (ip[2] << 4) | ((ip[3] & 0xf0) >> 4));
1547                 vsei = ip[3] & 0xf;
1548                 for (m = 1; m < 5; ++m) {
1549                     vsei <<= 8;
1550                     vsei |= ip[3 + m];
1551                 }
1552                 sgj_pr_hr(jsp, "      NAA 6, AOI: 0x%x\n", c_id);
1553                 sgj_pr_hr(jsp, "      Vendor Specific Identifier: 0x%"
1554                           PRIx64 "\n", vsei);
1555                 vsei = sg_get_unaligned_be64(ip + 8);
1556                 sgj_pr_hr(jsp, "      Vendor Specific Identifier Extension: "
1557                           "0x%" PRIx64 "\n", vsei);
1558                 n = 0;
1559                 n += sg_scnpr(b + n, blen - n, "      [0x");
1560                 for (m = 0; m < 16; ++m)
1561                     n += sg_scnpr(b + n, blen - n, "%02x", ip[m]);
1562                 sgj_pr_hr(jsp, "%s]\n", b);
1563                 break;
1564             default:
1565                 pr2serr("      << bad NAA nibble , expect 2, 3, 5 or 6, "
1566                         "got %d>>\n", naa);
1567                 hex2stderr(ip, i_len, -1);
1568                 break;
1569             }
1570             break;
1571         case 4: /* Relative target port */
1572             if ((1 != c_set) || (1 != assoc) || (4 != i_len)) {
1573                 pr2serr("      << expected binary code_set, target "
1574                         "port association, length 4>>\n");
1575                 hex2stderr(ip, i_len, -1);
1576                 break;
1577             }
1578             d_id = sg_get_unaligned_be16(ip + 2);
1579             sgj_pr_hr(jsp, "      Relative target port: 0x%x\n", d_id);
1580             break;
1581         case 5: /* (primary) Target port group */
1582             if ((1 != c_set) || (1 != assoc) || (4 != i_len)) {
1583                 pr2serr("      << expected binary code_set, target "
1584                         "port association, length 4>>\n");
1585                 hex2stderr(ip, i_len, -1);
1586                 break;
1587             }
1588             d_id = sg_get_unaligned_be16(ip + 2);
1589             sgj_pr_hr(jsp, "      Target port group: 0x%x\n", d_id);
1590             break;
1591         case 6: /* Logical unit group */
1592             if ((1 != c_set) || (0 != assoc) || (4 != i_len)) {
1593                 pr2serr("      << expected binary code_set, logical "
1594                         "unit association, length 4>>\n");
1595                 hex2stderr(ip, i_len, -1);
1596                 break;
1597             }
1598             d_id = sg_get_unaligned_be16(ip + 2);
1599             sgj_pr_hr(jsp, "      Logical unit group: 0x%x\n", d_id);
1600             break;
1601         case 7: /* MD5 logical unit identifier */
1602             if ((1 != c_set) || (0 != assoc)) {
1603                 pr2serr("      << expected binary code_set, logical "
1604                         "unit association>>\n");
1605                 hex2stderr(ip, i_len, -1);
1606                 break;
1607             }
1608             sgj_pr_hr(jsp, "      MD5 logical unit identifier:\n");
1609             if (jsp->pr_out_hr)
1610                 sgj_js_str_out(jsp, (const char *)ip, i_len);
1611             else
1612                 hex2stdout(ip, i_len, -1);
1613             break;
1614         case 8: /* SCSI name string */
1615             if (3 != c_set) {
1616                 if (2 == c_set) {
1617                     if (op->verbose)
1618                         pr2serr("      << expected UTF-8, use ASCII>>\n");
1619                 } else {
1620                     pr2serr("      << expected UTF-8 code_set>>\n");
1621                     hex2stderr(ip, i_len, -1);
1622                     break;
1623                 }
1624             }
1625             sgj_pr_hr(jsp, "      SCSI name string:\n");
1626             /* does %s print out UTF-8 ok??
1627              * Seems to depend on the locale. Looks ok here with my
1628              * locale setting: en_AU.UTF-8
1629              */
1630             sgj_pr_hr(jsp, "      %.*s\n", i_len, (const char *)ip);
1631             break;
1632         case 9: /* Protocol specific port identifier */
1633             /* added in spc4r36, PIV must be set, proto_id indicates */
1634             /* whether UAS (USB) or SOP (PCIe) or ... */
1635             if (! piv)
1636                 pr2serr("      >>>> Protocol specific port identifier "
1637                         "expects protocol\n"
1638                         "           identifier to be valid and it is not\n");
1639             if (TPROTO_UAS == p_id) {
1640                 sgj_pr_hr(jsp, "      USB device address: 0x%x\n",
1641                           0x7f & ip[0]);
1642                 sgj_pr_hr(jsp, "      USB interface number: 0x%x\n", ip[2]);
1643             } else if (TPROTO_SOP == p_id) {
1644                 sgj_pr_hr(jsp, "      PCIe routing ID, bus number: 0x%x\n",
1645                           ip[0]);
1646                 sgj_pr_hr(jsp, "          function number: 0x%x\n", ip[1]);
1647                 sgj_pr_hr(jsp, "          [or device number: 0x%x, function "
1648                           "number: 0x%x]\n", (0x1f & (ip[1] >> 3)),
1649                           0x7 & ip[1]);
1650             } else
1651                 sgj_pr_hr(jsp, "      >>>> unexpected protocol identifier: "
1652                           "%s\n           with Protocol specific port "
1653                           "identifier\n", sg_get_trans_proto_str(p_id, dlen,
1654                                                                  d));
1655             break;
1656         case 0xa: /* UUID identifier [spc5r08] RFC 4122 */
1657             if (1 != c_set) {
1658                 pr2serr("      << expected binary code_set >>\n");
1659                 hex2stderr(ip, i_len, 0);
1660                 break;
1661             }
1662             if ((1 != ((ip[0] >> 4) & 0xf)) || (18 != i_len)) {
1663                 pr2serr("      << expected locally assigned UUID, 16 bytes "
1664                         "long >>\n");
1665                 hex2stderr(ip, i_len, 0);
1666                 break;
1667             }
1668             n = 0;
1669             n += sg_scnpr(b + n, blen - n, "      Locally assigned UUID: ");
1670             for (m = 0; m < 16; ++m) {
1671                 if ((4 == m) || (6 == m) || (8 == m) || (10 == m))
1672                     n += sg_scnpr(b + n, blen - n, "-");
1673                 n += sg_scnpr(b + n, blen - n, "%02x", ip[2 + m]);
1674             }
1675             sgj_pr_hr(jsp, "%s\n", b);
1676             break;
1677         default: /* reserved */
1678             pr2serr("      reserved designator=0x%x\n", desig_type);
1679             hex2stderr(ip, i_len, -1);
1680             break;
1681         }
1682     }
1683     if (-2 == u)
1684         pr2serr("%s VPD page error: around offset=%d\n", leadin, off);
1685 }
1686 
1687 /* The --export and --json options are assumed to be mutually exclusive.
1688  * Here the former takes precedence. */
1689 static void
export_dev_ids(uint8_t * buff,int len,int verbose)1690 export_dev_ids(uint8_t * buff, int len, int verbose)
1691 {
1692     int u, j, m, id_len, c_set, assoc, desig_type, i_len;
1693     int off, d_id, naa, k, p_id;
1694     uint8_t * bp;
1695     uint8_t * ip;
1696     const char * assoc_str;
1697     const char * suffix;
1698 
1699     if (buff[2] != 0) {
1700         /*
1701          * Cf decode_dev_ids() for details
1702          */
1703         i_len = len;
1704         ip = buff;
1705         c_set = 1;
1706         assoc = 0;
1707         p_id = 0xf;
1708         desig_type = 3;
1709         j = 1;
1710         off = 16;
1711         goto decode;
1712     }
1713 
1714     for (j = 1, off = -1;
1715          (u = sg_vpd_dev_id_iter(buff, len, &off, -1, -1, -1)) == 0;
1716          ++j) {
1717         bp = buff + off;
1718         i_len = bp[3];
1719         id_len = i_len + 4;
1720         if ((off + id_len) > len) {
1721             if (verbose)
1722                 pr2serr("Device Identification VPD page error: designator "
1723                         "length longer than\n     remaining response "
1724                         "length=%d\n", (len - off));
1725             return;
1726         }
1727         ip = bp + 4;
1728         p_id = ((bp[0] >> 4) & 0xf);   /* protocol identifier */
1729         c_set = (bp[0] & 0xf);
1730         assoc = ((bp[1] >> 4) & 0x3);
1731         desig_type = (bp[1] & 0xf);
1732   decode:
1733         switch (assoc) {
1734             case 0:
1735                 assoc_str = "LUN";
1736                 break;
1737             case 1:
1738                 assoc_str = "PORT";
1739                 break;
1740             case 2:
1741                 assoc_str = "TARGET";
1742                 break;
1743             default:
1744                 if (verbose)
1745                     pr2serr("    Invalid association %d\n", assoc);
1746                 return;
1747         }
1748         switch (desig_type) {
1749         case 0: /* vendor specific */
1750             if (i_len == 0 || i_len > 128)
1751                 break;
1752             if ((2 == c_set) || (3 == c_set)) { /* ASCII or UTF-8 */
1753                 k = encode_whitespaces(ip, i_len);
1754                 /* udev-conforming character encoding */
1755                 if (k > 0) {
1756                     printf("SCSI_IDENT_%s_VENDOR=", assoc_str);
1757                     for (m = 0; m < k; ++m) {
1758                         if ((ip[m] >= '0' && ip[m] <= '9') ||
1759                             (ip[m] >= 'A' && ip[m] <= 'Z') ||
1760                             (ip[m] >= 'a' && ip[m] <= 'z') ||
1761                             strchr("#+-.:=@_", ip[m]) != NULL)
1762                             printf("%c", ip[m]);
1763                         else
1764                             printf("\\x%02x", ip[m]);
1765                     }
1766                     printf("\n");
1767                 }
1768             } else {
1769                 printf("SCSI_IDENT_%s_VENDOR=", assoc_str);
1770                 for (m = 0; m < i_len; ++m)
1771                     printf("%02x", (unsigned int)ip[m]);
1772                 printf("\n");
1773             }
1774             break;
1775         case 1: /* T10 vendor identification */
1776             printf("SCSI_IDENT_%s_T10=", assoc_str);
1777             if ((2 == c_set) || (3 == c_set)) {
1778                 k = encode_whitespaces(ip, i_len);
1779                 /* udev-conforming character encoding */
1780                 for (m = 0; m < k; ++m) {
1781                     if ((ip[m] >= '0' && ip[m] <= '9') ||
1782                         (ip[m] >= 'A' && ip[m] <= 'Z') ||
1783                         (ip[m] >= 'a' && ip[m] <= 'z') ||
1784                         strchr("#+-.:=@_", ip[m]) != NULL)
1785                         printf("%c", ip[m]);
1786                     else
1787                         printf("\\x%02x", ip[m]);
1788                 }
1789                 printf("\n");
1790                 if (!memcmp(ip, "ATA_", 4)) {
1791                     printf("SCSI_IDENT_%s_ATA=%.*s\n", assoc_str,
1792                            k - 4, ip + 4);
1793                 }
1794             } else {
1795                 for (m = 0; m < i_len; ++m)
1796                     printf("%02x", (unsigned int)ip[m]);
1797                 printf("\n");
1798             }
1799             break;
1800         case 2: /* EUI-64 based */
1801             if (1 != c_set) {
1802                 if (verbose) {
1803                     pr2serr("      << expected binary code_set (1)>>\n");
1804                     hex2stderr(ip, i_len, 0);
1805                 }
1806                 break;
1807             }
1808             printf("SCSI_IDENT_%s_EUI64=", assoc_str);
1809             for (m = 0; m < i_len; ++m)
1810                 printf("%02x", (unsigned int)ip[m]);
1811             printf("\n");
1812             break;
1813         case 3: /* NAA */
1814             if (1 != c_set) {
1815                 if (verbose) {
1816                     pr2serr("      << expected binary code_set (1)>>\n");
1817                     hex2stderr(ip, i_len, 0);
1818                 }
1819                 break;
1820             }
1821             /*
1822              * Unfortunately, there are some (broken) implementations
1823              * which return _several_ NAA descriptors.
1824              * So add a suffix to differentiate between them.
1825              */
1826             naa = (ip[0] >> 4) & 0xff;
1827             switch (naa) {
1828                 case 6:
1829                     suffix="REGEXT";
1830                     break;
1831                 case 5:
1832                     suffix="REG";
1833                     break;
1834                 case 2:
1835                     suffix="EXT";
1836                     break;
1837                 case 3:
1838                 default:
1839                     suffix="LOCAL";
1840                     break;
1841             }
1842             printf("SCSI_IDENT_%s_NAA_%s=", assoc_str, suffix);
1843             for (m = 0; m < i_len; ++m)
1844                 printf("%02x", (unsigned int)ip[m]);
1845             printf("\n");
1846             break;
1847         case 4: /* Relative target port */
1848             if ((1 != c_set) || (1 != assoc) || (4 != i_len)) {
1849                 if (verbose) {
1850                     pr2serr("      << expected binary code_set, target "
1851                             "port association, length 4>>\n");
1852                     hex2stderr(ip, i_len, 0);
1853                 }
1854                 break;
1855             }
1856             d_id = sg_get_unaligned_be16(ip + 2);
1857             printf("SCSI_IDENT_%s_RELATIVE=%d\n", assoc_str, d_id);
1858             break;
1859         case 5: /* (primary) Target port group */
1860             if ((1 != c_set) || (1 != assoc) || (4 != i_len)) {
1861                 if (verbose) {
1862                     pr2serr("      << expected binary code_set, target "
1863                             "port association, length 4>>\n");
1864                     hex2stderr(ip, i_len, 0);
1865                 }
1866                 break;
1867             }
1868             d_id = sg_get_unaligned_be16(ip + 2);
1869             printf("SCSI_IDENT_%s_TARGET_PORT_GROUP=0x%x\n", assoc_str, d_id);
1870             break;
1871         case 6: /* Logical unit group */
1872             if ((1 != c_set) || (0 != assoc) || (4 != i_len)) {
1873                 if (verbose) {
1874                     pr2serr("      << expected binary code_set, logical "
1875                             "unit association, length 4>>\n");
1876                     hex2stderr(ip, i_len, 0);
1877                 }
1878                 break;
1879             }
1880             d_id = sg_get_unaligned_be16(ip + 2);
1881             printf("SCSI_IDENT_%s_LOGICAL_UNIT_GROUP=0x%x\n", assoc_str, d_id);
1882             break;
1883         case 7: /* MD5 logical unit identifier */
1884             if ((1 != c_set) || (0 != assoc)) {
1885                 if (verbose) {
1886                     pr2serr("      << expected binary code_set, logical "
1887                             "unit association>>\n");
1888                     hex2stderr(ip, i_len, 0);
1889                 }
1890                 break;
1891             }
1892             printf("SCSI_IDENT_%s_MD5=", assoc_str);
1893             hex2stdout(ip, i_len, -1);
1894             break;
1895         case 8: /* SCSI name string */
1896             if (3 != c_set) {
1897                 if (verbose) {
1898                     pr2serr("      << expected UTF-8 code_set>>\n");
1899                     hex2stderr(ip, i_len, -1);
1900                 }
1901                 break;
1902             }
1903             if (! (strncmp((const char *)ip, "eui.", 4) ||
1904                    strncmp((const char *)ip, "EUI.", 4) ||
1905                    strncmp((const char *)ip, "naa.", 4) ||
1906                    strncmp((const char *)ip, "NAA.", 4) ||
1907                    strncmp((const char *)ip, "iqn.", 4))) {
1908                 if (verbose) {
1909                     pr2serr("      << expected name string prefix>>\n");
1910                     hex2stderr(ip, i_len, -1);
1911                 }
1912                 break;
1913             }
1914 
1915             printf("SCSI_IDENT_%s_NAME=%.*s\n", assoc_str, i_len,
1916                    (const char *)ip);
1917             break;
1918         case 9: /*  Protocol specific port identifier */
1919             if (TPROTO_UAS == p_id) {
1920                 if ((4 != i_len) || (1 != assoc)) {
1921                     if (verbose) {
1922                         pr2serr("      << UAS (USB) expected target "
1923                                 "port association>>\n");
1924                         hex2stderr(ip, i_len, 0);
1925                     }
1926                     break;
1927                 }
1928                 printf("SCSI_IDENT_%s_UAS_DEVICE_ADDRESS=0x%x\n", assoc_str,
1929                        ip[0] & 0x7f);
1930                 printf("SCSI_IDENT_%s_UAS_INTERFACE_NUMBER=0x%x\n", assoc_str,
1931                        ip[2]);
1932             } else if (TPROTO_SOP == p_id) {
1933                 if ((4 != i_len) && (8 != i_len)) {   /* spc4r36h confused */
1934                     if (verbose) {
1935                         pr2serr("      << SOP (PCIe) descriptor "
1936                                 "length=%d >>\n", i_len);
1937                         hex2stderr(ip, i_len, 0);
1938                     }
1939                     break;
1940                 }
1941                 printf("SCSI_IDENT_%s_SOP_ROUTING_ID=0x%x\n", assoc_str,
1942                        sg_get_unaligned_be16(ip + 0));
1943             } else {
1944                 pr2serr("      << Protocol specific port identifier "
1945                         "protocol_id=0x%x>>\n", p_id);
1946             }
1947             break;
1948         case 0xa: /* UUID based */
1949             if (1 != c_set) {
1950                 if (verbose) {
1951                     pr2serr("      << expected binary code_set (1)>>\n");
1952                     hex2stderr(ip, i_len, 0);
1953                 }
1954                 break;
1955             }
1956             if (i_len < 18) {
1957                 if (verbose) {
1958                     pr2serr("      << short UUID field expected 18 or more, "
1959                             "got %d >>\n", i_len);
1960                     hex2stderr(ip, i_len, 0);
1961                 }
1962                 break;
1963             }
1964             printf("SCSI_IDENT_%s_UUID=", assoc_str);
1965             for (m = 2; m < i_len; ++m) {
1966                 if ((6 == m) || (8 == m) || (10 == m) || (12 == m))
1967                     printf("-%02x", (unsigned int)ip[m]);
1968                 else
1969                     printf("%02x", (unsigned int)ip[m]);
1970             }
1971             printf("\n");
1972             break;
1973         default: /* reserved */
1974             if (verbose) {
1975                 pr2serr("      reserved designator=0x%x\n", desig_type);
1976                 hex2stderr(ip, i_len, -1);
1977             }
1978             break;
1979         }
1980     }
1981     if (-2 == u && verbose)
1982         pr2serr("Device identification VPD page error: "
1983                 "around offset=%d\n", off);
1984 }
1985 
1986 /* VPD_BLOCK_LIMITS  0xb0 ["bl"]  (SBC) */
1987 /* VPD_SA_DEV_CAP  0xb0 ["sad"]  (SSC) */
1988 /* Sequential access device characteristics,  ssc+smc */
1989 /* OSD information, osd */
1990 static void
decode_b0_vpd(uint8_t * buff,int len,struct opts_t * op,sgj_opaque_p jop)1991 decode_b0_vpd(uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop)
1992 {
1993     int pdt = PDT_MASK & buff[0];
1994     sgj_state * jsp = &op->json_st;
1995 
1996     if (op->do_hex) {
1997         hex2stdout(buff, len, no_ascii_4hex(op));
1998         return;
1999     }
2000     switch (pdt) {
2001     case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
2002         /* done by decode_block_limits_vpd() */
2003         break;
2004     case PDT_TAPE: case PDT_MCHANGER:
2005         sgj_haj_vi_nex(jsp, jop, 2, "TSMC", SGJ_SEP_EQUAL_NO_SPACE,
2006                        !!(buff[4] & 0x2), false, "Tape Stream Mirror "
2007                        "Capable");
2008         sgj_haj_vi_nex(jsp, jop, 2, "WORM", SGJ_SEP_EQUAL_NO_SPACE,
2009                        !!(buff[4] & 0x1), false, "Write Once Read Multiple "
2010                        "supported");
2011 
2012         break;
2013     case PDT_OSD:
2014     default:
2015         pr2serr("  Unable to decode pdt=0x%x, in hex:\n", pdt);
2016         hex2stderr(buff, len, 0);
2017         break;
2018     }
2019 }
2020 
2021 /* VPD_BLOCK_DEV_CHARS sbc  0xb1 ["bdc"] */
2022 /* VPD_MAN_ASS_SN ssc */
2023 static void
decode_b1_vpd(uint8_t * buff,int len,struct opts_t * op,sgj_opaque_p jop)2024 decode_b1_vpd(uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop)
2025 {
2026     int pdt;
2027     sgj_state * jsp = &op->json_st;
2028 
2029     if (op->do_hex) {
2030         hex2stdout(buff, len, no_ascii_4hex(op));
2031         return;
2032     }
2033     pdt = PDT_MASK & buff[0];
2034     switch (pdt) {
2035     case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
2036         /* now done by decode_block_dev_ch_vpd() in sg_vpd_common.c */
2037         break;
2038     case PDT_TAPE: case PDT_MCHANGER: case PDT_ADC:
2039         sgj_pr_hr(jsp, "  Manufacturer-assigned serial number: %.*s\n",
2040                   len - 4, buff + 4);
2041         sgj_js_nv_s_len(jsp, jop, "manufacturer_assigned_serial_number",
2042                         (const char *)buff + 4, len - 4);
2043         break;
2044     default:
2045         pr2serr("  Unable to decode pdt=0x%x, in hex:\n", pdt);
2046         hex2stderr(buff, len, 0);
2047         break;
2048     }
2049 }
2050 
2051 /* VPD_REFERRALS sbc          0xb3 ["ref"] */
2052 /* VPD_AUTOMATION_DEV_SN ssc  0xb3 ["adsn"] */
2053 static void
decode_b3_vpd(uint8_t * buff,int len,struct opts_t * op,sgj_opaque_p jop)2054 decode_b3_vpd(uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop)
2055 {
2056     int pdt;
2057     sgj_state * jsp = &op->json_st;
2058 
2059     if (op->do_hex) {
2060         hex2stdout(buff, len, no_ascii_4hex(op));
2061         return;
2062     }
2063     pdt = buff[0] & PDT_MASK;
2064     switch (pdt) {
2065     case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
2066         /* now done in decode_referrals_vpd() in sg_vpd_common.c */
2067         break;
2068     case PDT_TAPE: case PDT_MCHANGER:
2069         sgj_pr_hr(jsp, "  Automation device serial number: %.*s\n",
2070                   len - 4, buff + 4);
2071         sgj_js_nv_s_len(jsp, jop, "automation_device_serial_number",
2072                         (const char *)buff + 4, len - 4);
2073         break;
2074     default:
2075         pr2serr("  Unable to decode pdt=0x%x, in hex:\n", pdt);
2076         hex2stderr(buff, len, 0);
2077         break;
2078     }
2079 }
2080 
2081 #if 0
2082 static void
2083 decode_rdac_vpd_c9_rtpg_data(uint8_t aas, uint8_t vendor)
2084 {
2085     printf("  Asymmetric Access State:");
2086     switch(aas & 0x0F) {
2087         case 0x0:
2088             printf(" Active/Optimized");
2089             break;
2090         case 0x1:
2091             printf(" Active/Non-Optimized");
2092             break;
2093         case 0x2:
2094             printf(" Standby");
2095             break;
2096         case 0x3:
2097             printf(" Unavailable");
2098             break;
2099         case 0xE:
2100             printf(" Offline");
2101             break;
2102         case 0xF:
2103             printf(" Transitioning");
2104             break;
2105         default:
2106             printf(" (unknown)");
2107             break;
2108     }
2109     printf("\n");
2110 
2111     printf("  Vendor Specific Field:");
2112     switch(vendor) {
2113         case 0x01:
2114             printf(" Operating normally");
2115             break;
2116         case 0x02:
2117             printf(" Non-responsive to queries");
2118             break;
2119         case 0x03:
2120             printf(" Controller being held in reset");
2121             break;
2122         case 0x04:
2123             printf(" Performing controller firmware download (1st "
2124                    "controller)");
2125             break;
2126         case 0x05:
2127             printf(" Performing controller firmware download (2nd "
2128                    "controller)");
2129             break;
2130         case 0x06:
2131             printf(" Quiesced as a result of an administrative request");
2132             break;
2133         case 0x07:
2134             printf(" Service mode as a result of an administrative request");
2135             break;
2136         case 0xFF:
2137             printf(" Details are not available");
2138             break;
2139         default:
2140             printf(" (unknown)");
2141             break;
2142     }
2143     printf("\n");
2144 }
2145 
2146 static void
2147 decode_rdac_vpd_c9(uint8_t * buff, int len, struct opts_t * op)
2148 {
2149     if (len < 3) {
2150         pr2serr("Volume Access Control VPD page length too short=%d\n", len);
2151         return;
2152     }
2153     if (op->do_hex) {
2154         hex2stdout(buff, len, no_ascii_4hex(op));
2155         return;
2156     }
2157     if (buff[4] != 'v' && buff[5] != 'a' && buff[6] != 'c') {
2158         pr2serr("Invalid page identifier %c%c%c%c, decoding "
2159                 "not possible.\n" , buff[4], buff[5], buff[6], buff[7]);
2160         return;
2161     }
2162     if (buff[7] != '1') {
2163         pr2serr("Invalid page version '%c' (should be 1)\n", buff[7]);
2164     }
2165     if ( (buff[8] & 0xE0) == 0xE0 ) {
2166         printf("  IOShipping (ALUA): Enabled\n");
2167     } else {
2168         printf("  AVT:");
2169         if (buff[8] & 0x80) {
2170             printf(" Enabled");
2171             if (buff[8] & 0x40)
2172                 printf(" (Allow reads on sector 0)");
2173             printf("\n");
2174         } else {
2175             printf(" Disabled\n");
2176         }
2177     }
2178     printf("  Volume Access via: ");
2179     if (buff[8] & 0x01)
2180         printf("primary controller\n");
2181     else
2182         printf("alternate controller\n");
2183 
2184     if (buff[8] & 0x08) {
2185         printf("  Path priority: %d ", buff[15] & 0xf);
2186         switch(buff[15] & 0xf) {
2187             case 0x1:
2188                 printf("(preferred path)\n");
2189                 break;
2190             case 0x2:
2191                 printf("(secondary path)\n");
2192                 break;
2193             default:
2194                 printf("(unknown)\n");
2195                 break;
2196         }
2197 
2198         printf("  Preferred Path Auto Changeable:");
2199         switch(buff[14] & 0x3C) {
2200             case 0x14:
2201                 printf(" No (User Disabled and Host Type Restricted)\n");
2202                 break;
2203             case 0x18:
2204                 printf(" No (User Disabled)\n");
2205                 break;
2206             case 0x24:
2207                 printf(" No (Host Type Restricted)\n");
2208                 break;
2209             case 0x28:
2210                 printf(" Yes\n");
2211                 break;
2212             default:
2213                 printf(" (Unknown)\n");
2214                 break;
2215         }
2216 
2217         printf("  Implicit Failback:");
2218         switch(buff[14] & 0x03) {
2219             case 0x1:
2220                 printf(" Disabled\n");
2221                 break;
2222             case 0x2:
2223                 printf(" Enabled\n");
2224                 break;
2225             default:
2226                 printf(" (Unknown)\n");
2227                 break;
2228         }
2229     } else {
2230         printf("  Path priority: %d ", buff[9] & 0xf);
2231         switch(buff[9] & 0xf) {
2232             case 0x1:
2233                 printf("(preferred path)\n");
2234                 break;
2235             case 0x2:
2236                 printf("(secondary path)\n");
2237                 break;
2238             default:
2239                 printf("(unknown)\n");
2240                 break;
2241         }
2242     }
2243 
2244     if (buff[8] & 0x80) {
2245         printf(" Target Port Group Data (This controller):\n");
2246         decode_rdac_vpd_c9_rtpg_data(buff[10], buff[11]);
2247 
2248         printf(" Target Port Group Data (Alternate controller):\n");
2249         decode_rdac_vpd_c9_rtpg_data(buff[12], buff[13]);
2250     }
2251 
2252     return;
2253 }
2254 #endif
2255 
2256 extern const char * sg_ansi_version_arr[];
2257 
2258 static const char *
get_ansi_version_str(int version,char * b,int blen)2259 get_ansi_version_str(int version, char * b, int blen)
2260 {
2261     version &= 0xf;
2262     b[blen - 1] = '\0';
2263     strncpy(b, sg_ansi_version_arr[version], blen - 1);
2264     return b;
2265 }
2266 
2267 static void
std_inq_decode(struct opts_t * op,sgj_opaque_p jop,int off)2268 std_inq_decode(struct opts_t * op, sgj_opaque_p jop, int off)
2269 {
2270     int len, pqual, pdt, ansi_version, k, j;
2271     sgj_state * jsp = &op->json_st;
2272     bool as_json = jsp->pr_as_json;
2273     const char * cp;
2274     const uint8_t * rp;
2275     int vdesc_arr[8];
2276     char b[128];
2277     static const int blen = sizeof(b);
2278 
2279     rp = rsp_buff + off;
2280     memset(vdesc_arr, 0, sizeof(vdesc_arr));
2281     if (op->do_raw) {
2282         dStrRaw((const char *)rp, op->maxlen);
2283         return;
2284     } else if (op->do_hex) {
2285         /* with -H, print with address, -HH without */
2286         hex2stdout(rp, op->maxlen, no_ascii_4hex(op));
2287         return;
2288     }
2289     pqual = (rp[0] & 0xe0) >> 5;
2290     if (! op->do_raw && ! op->do_export) {
2291         strcpy(b, "standard INQUIRY:");
2292         if (0 == pqual)
2293             sgj_pr_hr(jsp, "%s\n", b);
2294         else if (1 == pqual)
2295             sgj_pr_hr(jsp, "%s [PQ indicates LU temporarily unavailable]\n",
2296                       b);
2297         else if (3 == pqual)
2298             sgj_pr_hr(jsp, "%s [PQ indicates LU not accessible via this "
2299                       "port]\n", b);
2300         else
2301             sgj_pr_hr(jsp, "%s [reserved or vendor specific qualifier "
2302                       "[%d]]\n", b, pqual);
2303     }
2304     len = rp[4] + 5;
2305     /* N.B. rp[2] full byte is 'version' in SPC-2,3,4 but in SPC
2306      * [spc-r11a (1997)] bits 6,7: ISO/IEC version; bits 3-5: ECMA
2307      * version; bits 0-2: SCSI version */
2308     ansi_version = rp[2] & 0x7;       /* Only take SCSI version */
2309     pdt = rp[0] & PDT_MASK;
2310     if (op->do_export) {
2311         printf("SCSI_TPGS=%d\n", (rp[5] & 0x30) >> 4);
2312         cp = sg_get_pdt_str(pdt, blen, b);
2313         if (strlen(cp) > 0)
2314             printf("SCSI_TYPE=%s\n", cp);
2315     } else {
2316         sgj_pr_hr(jsp, "  PQual=%d  PDT=%d  RMB=%d  LU_CONG=%d  "
2317                   "hot_pluggable=%d  version=0x%02x ", pqual, pdt,
2318                   !!(rp[1] & 0x80), !!(rp[1] & 0x40), (rp[1] >> 4) & 0x3,
2319                   (unsigned int)rp[2]);
2320         sgj_pr_hr(jsp, " [%s]\n", get_ansi_version_str(ansi_version, b,
2321                                                        blen));
2322         sgj_pr_hr(jsp, "  [AERC=%d]  [TrmTsk=%d]  NormACA=%d  HiSUP=%d "
2323                   " Resp_data_format=%d\n  SCCS=%d  ", !!(rp[3] & 0x80),
2324                   !!(rp[3] & 0x40), !!(rp[3] & 0x20), !!(rp[3] & 0x10),
2325                   rp[3] & 0x0f, !!(rp[5] & 0x80));
2326         sgj_pr_hr(jsp, "ACC=%d  TPGS=%d  3PC=%d  Protect=%d ",
2327                   !!(rp[5] & 0x40), ((rp[5] & 0x30) >> 4), !!(rp[5] & 0x08),
2328                   !!(rp[5] & 0x01));
2329         sgj_pr_hr(jsp, " [BQue=%d]\n  EncServ=%d  ", !!(rp[6] & 0x80),
2330                   !!(rp[6] & 0x40));
2331         if (rp[6] & 0x10)
2332             sgj_pr_hr(jsp, "MultiP=1 (VS=%d)  ", !!(rp[6] & 0x20));
2333         else
2334             sgj_pr_hr(jsp, "MultiP=0  ");
2335         sgj_pr_hr(jsp, "[MChngr=%d]  [ACKREQQ=%d]  Addr16=%d\n  "
2336                   "[RelAdr=%d]  ", !!(rp[6] & 0x08), !!(rp[6] & 0x04),
2337                   !!(rp[6] & 0x01), !!(rp[7] & 0x80));
2338         sgj_pr_hr(jsp, "WBus16=%d  Sync=%d  [Linked=%d]  [TranDis=%d]  ",
2339                   !!(rp[7] & 0x20), !!(rp[7] & 0x10), !!(rp[7] & 0x08),
2340                   !!(rp[7] & 0x04));
2341         sgj_pr_hr(jsp, "CmdQue=%d\n", !!(rp[7] & 0x02));
2342         if (op->maxlen > 56)
2343             sgj_pr_hr(jsp, "  [SPI: Clocking=0x%x  QAS=%d  IUS=%d]\n",
2344                       (rp[56] & 0x0c) >> 2, !!(rp[56] & 0x2),
2345                       !!(rp[56] & 0x1));
2346         if (op->maxlen >= len)
2347             sgj_pr_hr(jsp, "    length=%d (0x%x)", len, len);
2348         else
2349             sgj_pr_hr(jsp, "    length=%d (0x%x), but only fetched %d bytes",
2350                       len, len, op->maxlen);
2351         if ((ansi_version >= 2) && (len < SAFE_STD_INQ_RESP_LEN))
2352             sgj_pr_hr(jsp, "\n  [for SCSI>=2, len>=36 is expected]");
2353         cp = sg_get_pdt_str(pdt, blen, b);
2354         if (strlen(cp) > 0)
2355             sgj_pr_hr(jsp, "   Peripheral device type: %s\n", cp);
2356     }
2357     if (op->maxlen <= 8) {
2358         if (! op->do_export)
2359             sgj_pr_hr(jsp, " Inquiry response length=%d, no vendor, product "
2360                       "or revision data\n", op->maxlen);
2361     } else {
2362         int i;
2363 
2364         memcpy(xtra_buff, &rp[8], 8);
2365         xtra_buff[8] = '\0';
2366         /* Fixup any tab characters */
2367         for (i = 0; i < 8; ++i)
2368             if (xtra_buff[i] == 0x09)
2369                 xtra_buff[i] = ' ';
2370         if (op->do_export) {
2371             len = encode_whitespaces((uint8_t *)xtra_buff, 8);
2372             if (len > 0) {
2373                 printf("SCSI_VENDOR=%s\n", xtra_buff);
2374                 encode_string(xtra_buff, &rp[8], 8);
2375                 printf("SCSI_VENDOR_ENC=%s\n", xtra_buff);
2376             }
2377         } else
2378             sgj_pr_hr(jsp, " Vendor identification: %s\n", xtra_buff);
2379         if (op->maxlen <= 16) {
2380             if (! op->do_export)
2381                 sgj_pr_hr(jsp, " Product identification: <none>\n");
2382         } else {
2383             memcpy(xtra_buff, &rp[16], 16);
2384             xtra_buff[16] = '\0';
2385             if (op->do_export) {
2386                 len = encode_whitespaces((uint8_t *)xtra_buff, 16);
2387                 if (len > 0) {
2388                     printf("SCSI_MODEL=%s\n", xtra_buff);
2389                     encode_string(xtra_buff, &rp[16], 16);
2390                     printf("SCSI_MODEL_ENC=%s\n", xtra_buff);
2391                 }
2392             } else
2393                 sgj_pr_hr(jsp, " Product identification: %s\n", xtra_buff);
2394         }
2395         if (op->maxlen <= 32) {
2396             if (! op->do_export)
2397                 sgj_pr_hr(jsp, " Product revision level: <none>\n");
2398         } else {
2399             memcpy(xtra_buff, &rp[32], 4);
2400             xtra_buff[4] = '\0';
2401             if (op->do_export) {
2402                 len = encode_whitespaces((uint8_t *)xtra_buff, 4);
2403                 if (len > 0)
2404                     printf("SCSI_REVISION=%s\n", xtra_buff);
2405             } else
2406                 sgj_pr_hr(jsp, " Product revision level: %s\n", xtra_buff);
2407         }
2408         if (op->do_vendor && (op->maxlen > 36) && ('\0' != rp[36]) &&
2409             (' ' != rp[36])) {
2410             memcpy(xtra_buff, &rp[36], op->maxlen < 56 ? op->maxlen - 36 :
2411                    20);
2412             if (op->do_export) {
2413                 len = encode_whitespaces((uint8_t *)xtra_buff, 20);
2414                 if (len > 0)
2415                     printf("VENDOR_SPECIFIC=%s\n", xtra_buff);
2416             } else
2417                 sgj_pr_hr(jsp, " Vendor specific: %s\n", xtra_buff);
2418         }
2419         if (op->do_descriptors) {
2420             for (j = 0, k = 58; ((j < 8) && ((k + 1) < op->maxlen));
2421                  k +=2, ++j)
2422                 vdesc_arr[j] = sg_get_unaligned_be16(rp + k);
2423         }
2424         if ((op->do_vendor > 1) && (op->maxlen > 96)) {
2425             memcpy(xtra_buff, &rp[96], op->maxlen - 96);
2426             if (op->do_export) {
2427                 len = encode_whitespaces((uint8_t *)xtra_buff,
2428                                          op->maxlen - 96);
2429                 if (len > 0)
2430                     printf("VENDOR_SPECIFIC=%s\n", xtra_buff);
2431             } else
2432                 sgj_pr_hr(jsp, " Vendor specific: %s\n", xtra_buff);
2433         }
2434         if (op->do_vendor && (op->maxlen > 243) &&
2435             (0 == strncmp("OPEN-V", (const char *)&rp[16], 6))) {
2436            memcpy(xtra_buff, &rp[212], 32);
2437            if (op->do_export) {
2438                 len = encode_whitespaces((uint8_t *)xtra_buff, 32);
2439                 if (len > 0)
2440                     printf("VENDOR_SPECIFIC_OPEN-V_LDEV_NAME=%s\n", xtra_buff);
2441             } else
2442                 sgj_pr_hr(jsp, " Vendor specific OPEN-V LDEV Name: %s\n",
2443                           xtra_buff);
2444         }
2445     }
2446     if (! op->do_export) {
2447         sgj_opaque_p jo2p = NULL;
2448 
2449         if (as_json)
2450             jo2p = std_inq_decode_js(rp, op->maxlen, op, jop);
2451         if ((0 == op->maxlen) && usn_buff[0])
2452             sgj_pr_hr(jsp, " Unit serial number: %s\n", usn_buff);
2453         if (op->do_descriptors) {
2454             sgj_opaque_p jap = sgj_named_subarray_r(jsp, jo2p,
2455                                                 "version_descriptor_list");
2456             if (0 == vdesc_arr[0]) {
2457                 sgj_pr_hr(jsp, "\n");
2458                 sgj_pr_hr(jsp, "  No version descriptors available\n");
2459             } else {
2460                 sgj_pr_hr(jsp, "\n");
2461                 sgj_pr_hr(jsp, "  Version descriptors:\n");
2462                 for (k = 0; k < 8; ++k) {
2463                     sgj_opaque_p jo3p = sgj_new_unattached_object_r(jsp);
2464                     int vdv = vdesc_arr[k];
2465 
2466                     if (0 == vdv)
2467                         break;
2468                     cp = find_version_descriptor_str(vdv);
2469                     if (cp)
2470                         sgj_pr_hr(jsp, "    %s\n", cp);
2471                     else
2472                         sgj_pr_hr(jsp, "    [unrecognised version descriptor "
2473                                   "code: 0x%x]\n", vdv);
2474                     sgj_js_nv_ihexstr(jsp, jo3p, "version_descriptor", vdv,
2475                                       NULL, cp ? cp : "unknown");
2476                     sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
2477                 }
2478             }
2479         }
2480     }
2481 }
2482 
2483 /* Returns 0 if Unit Serial Number VPD page contents found, else see
2484  * sg_ll_inquiry_v2() return values */
2485 static int
fetch_unit_serial_num(int sg_fd,char * obuff,int obuff_len,int verbose)2486 fetch_unit_serial_num(int sg_fd, char * obuff, int obuff_len, int verbose)
2487 {
2488     int len, k, res, c;
2489     uint8_t * b;
2490     uint8_t * free_b;
2491 
2492     b = sg_memalign(DEF_ALLOC_LEN, 0, &free_b, false);
2493     if (NULL == b) {
2494         pr2serr("%s: unable to allocate on heap\n", __func__);
2495         return sg_convert_errno(ENOMEM);
2496     }
2497     res = vpd_fetch_page(sg_fd, b, VPD_SUPPORTED_VPDS,
2498                          -1 /* 1 byte alloc_len */, false, verbose, &len);
2499     if (res) {
2500         if (verbose > 2)
2501             pr2serr("%s: no supported VPDs page\n", __func__);
2502         res = SG_LIB_CAT_MALFORMED;
2503         goto fini;
2504     }
2505     if (! vpd_page_is_supported(b, len, VPD_UNIT_SERIAL_NUM, verbose)) {
2506         res = sg_convert_errno(EDOM); /* was SG_LIB_CAT_ILLEGAL_REQ */
2507         goto fini;
2508     }
2509 
2510     memset(b, 0xff, 4); /* guard against empty response */
2511     res = vpd_fetch_page(sg_fd, b, VPD_UNIT_SERIAL_NUM, -1, false, verbose,
2512                          &len);
2513     if ((0 == res) && (len > 3)) {
2514         len -= 4;
2515         len = (len < (obuff_len - 1)) ? len : (obuff_len - 1);
2516         if (len > 0) {
2517             /* replace non-printable characters (except NULL) with space */
2518             for (k = 0; k < len; ++k) {
2519                 c = b[4 + k];
2520                 if (c)
2521                     obuff[k] = isprint(c) ? c : ' ';
2522                 else
2523                     break;
2524             }
2525             obuff[k] = '\0';
2526             res = 0;
2527             goto fini;
2528         } else {
2529             if (verbose > 2)
2530                 pr2serr("%s: bad sn VPD page\n", __func__);
2531             res = SG_LIB_CAT_MALFORMED;
2532         }
2533     } else {
2534         if (verbose > 2)
2535             pr2serr("%s: no supported VPDs page\n", __func__);
2536         res = SG_LIB_CAT_MALFORMED;
2537     }
2538 fini:
2539     if (free_b)
2540         free(free_b);
2541     return res;
2542 }
2543 
2544 
2545 /* Process a standard INQUIRY data format (response).
2546  * Returns 0 if successful */
2547 static int
std_inq_process(int sg_fd,struct opts_t * op,sgj_opaque_p jop,int off)2548 std_inq_process(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off)
2549 {
2550     int res, len, rlen, act_len;
2551     int vb, resid;
2552     char buff[48];
2553 
2554     if (sg_fd < 0) {    /* assume --inhex=FD usage */
2555         std_inq_decode(op, jop, off);
2556         return 0;
2557     }
2558     rlen = (op->maxlen > 0) ? op->maxlen : SAFE_STD_INQ_RESP_LEN;
2559     vb = op->verbose;
2560     res = sg_ll_inquiry_v2(sg_fd, false, 0, rsp_buff, rlen, DEF_PT_TIMEOUT,
2561                            &resid, false, vb);
2562     if (0 == res) {
2563         if ((vb > 4) && ((rlen - resid) > 0)) {
2564             pr2serr("Safe (36 byte) Inquiry response:\n");
2565             hex2stderr(rsp_buff, rlen - resid, 0);
2566         }
2567         len = rsp_buff[4] + 5;
2568         if ((len > SAFE_STD_INQ_RESP_LEN) && (len < 256) &&
2569             (0 == op->maxlen)) {
2570             rlen = len;
2571             memset(rsp_buff, 0, rlen);
2572             if (sg_ll_inquiry_v2(sg_fd, false, 0, rsp_buff, rlen,
2573                                  DEF_PT_TIMEOUT, &resid, true, vb)) {
2574                 pr2serr("second INQUIRY (%d byte) failed\n", len);
2575                 return SG_LIB_CAT_OTHER;
2576             }
2577             if (len != (rsp_buff[4] + 5)) {
2578                 pr2serr("strange, consecutive INQUIRYs yield different "
2579                         "'additional lengths'\n");
2580                 len = rsp_buff[4] + 5;
2581             }
2582         }
2583         if (op->maxlen > 0)
2584             act_len = rlen;
2585         else
2586             act_len = (rlen < len) ? rlen : len;
2587         /* don't use more than HBA's resid says was transferred from LU */
2588         if (act_len > (rlen - resid))
2589             act_len = rlen - resid;
2590         if (act_len < SAFE_STD_INQ_RESP_LEN)
2591             rsp_buff[act_len] = '\0';
2592         if ((! op->do_only) && (! op->do_export) && (0 == op->maxlen)) {
2593             if (fetch_unit_serial_num(sg_fd, usn_buff, sizeof(usn_buff), vb))
2594                 usn_buff[0] = '\0';
2595         }
2596         op->maxlen = act_len;
2597         std_inq_decode(op, jop, 0);
2598         return 0;
2599     } else if (res < 0) { /* could be an ATA device */
2600 #if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS) && \
2601     defined(HDIO_GET_IDENTITY)
2602         /* Try an ATA Identify Device command */
2603         res = try_ata_identify(sg_fd, op->do_hex, op->do_raw, vb);
2604         if (0 != res) {
2605             pr2serr("SCSI INQUIRY, NVMe Identify and fetching ATA "
2606                     "information failed on %s\n", op->device_name);
2607             return (res < 0) ? SG_LIB_CAT_OTHER : res;
2608         }
2609 #else
2610         pr2serr("SCSI INQUIRY failed on %s, res=%d\n",
2611                 op->device_name, res);
2612         return res;
2613 #endif
2614     } else {
2615         char b[80];
2616 
2617         if (vb > 0) {
2618             pr2serr("    inquiry: failed requesting %d byte response: ", rlen);
2619             if (resid && (vb > 1))
2620                 snprintf(buff, sizeof(buff), " [resid=%d]", resid);
2621             else
2622                 buff[0] = '\0';
2623             sg_get_category_sense_str(res, sizeof(b), b, vb);
2624             pr2serr("%s%s\n", b, buff);
2625         }
2626         return res;
2627     }
2628     return 0;
2629 }
2630 
2631 #ifdef SG_SCSI_STRINGS
2632 /* Returns 0 if successful */
2633 static int
cmddt_process(int sg_fd,const struct opts_t * op)2634 cmddt_process(int sg_fd, const struct opts_t * op)
2635 {
2636     int k, j, num, len, pdt, reserved_cmddt, support_num, res;
2637     char op_name[128];
2638 
2639     memset(rsp_buff, 0, rsp_buff_sz);
2640     if (op->do_cmddt > 1) {
2641         printf("Supported command list:\n");
2642         for (k = 0; k < 256; ++k) {
2643             res = sg_ll_inquiry(sg_fd, true /* cmddt */, false, k, rsp_buff,
2644                                 DEF_ALLOC_LEN, true, op->verbose);
2645             if (0 == res) {
2646                 pdt = rsp_buff[0] & PDT_MASK;
2647                 support_num = rsp_buff[1] & 7;
2648                 reserved_cmddt = rsp_buff[4];
2649                 if ((3 == support_num) || (5 == support_num)) {
2650                     num = rsp_buff[5];
2651                     for (j = 0; j < num; ++j)
2652                         printf(" %.2x", (int)rsp_buff[6 + j]);
2653                     if (5 == support_num)
2654                         printf("  [vendor specific manner (5)]");
2655                     sg_get_opcode_name((uint8_t)k, pdt,
2656                                        sizeof(op_name) - 1, op_name);
2657                     op_name[sizeof(op_name) - 1] = '\0';
2658                     printf("  %s\n", op_name);
2659                 } else if ((4 == support_num) || (6 == support_num))
2660                     printf("  opcode=0x%.2x vendor specific (%d)\n",
2661                            k, support_num);
2662                 else if ((0 == support_num) && (reserved_cmddt > 0)) {
2663                     printf("  opcode=0x%.2x ignored cmddt bit, "
2664                            "given standard INQUIRY response, stop\n", k);
2665                     break;
2666                 }
2667             } else if (SG_LIB_CAT_ILLEGAL_REQ == res)
2668                 break;
2669             else {
2670                 pr2serr("CmdDt INQUIRY on opcode=0x%.2x: failed\n", k);
2671                 break;
2672             }
2673         }
2674     }
2675     else {
2676         res = sg_ll_inquiry(sg_fd, true /* cmddt */, false, op->vpd_pn,
2677                             rsp_buff, DEF_ALLOC_LEN, true, op->verbose);
2678         if (0 == res) {
2679             pdt = rsp_buff[0] & PDT_MASK;
2680             if (! op->do_raw) {
2681                 printf("CmdDt INQUIRY, opcode=0x%.2x:  [", op->vpd_pn);
2682                 sg_get_opcode_name((uint8_t)op->vpd_pn, pdt,
2683                                    sizeof(op_name) - 1, op_name);
2684                 op_name[sizeof(op_name) - 1] = '\0';
2685                 printf("%s]\n", op_name);
2686             }
2687             len = rsp_buff[5] + 6;
2688             reserved_cmddt = rsp_buff[4];
2689             if (op->do_hex)
2690                 hex2stdout(rsp_buff, len, no_ascii_4hex(op));
2691             else if (op->do_raw)
2692                 dStrRaw((const char *)rsp_buff, len);
2693             else {
2694                 bool prnt_cmd = false;
2695                 const char * desc_p;
2696 
2697                 support_num = rsp_buff[1] & 7;
2698                 num = rsp_buff[5];
2699                 switch (support_num) {
2700                 case 0:
2701                     if (0 == reserved_cmddt)
2702                         desc_p = "no data available";
2703                     else
2704                         desc_p = "ignored cmddt bit, standard INQUIRY "
2705                                  "response";
2706                     break;
2707                 case 1: desc_p = "not supported"; break;
2708                 case 2: desc_p = "reserved (2)"; break;
2709                 case 3: desc_p = "supported as per standard";
2710                         prnt_cmd = true;
2711                         break;
2712                 case 4: desc_p = "vendor specific (4)"; break;
2713                 case 5: desc_p = "supported in vendor specific way";
2714                         prnt_cmd = true;
2715                         break;
2716                 case 6: desc_p = "vendor specific (6)"; break;
2717                 case 7: desc_p = "reserved (7)"; break;
2718                 }
2719                 if (prnt_cmd) {
2720                     printf("  Support field: %s [", desc_p);
2721                     for (j = 0; j < num; ++j)
2722                         printf(" %.2x", (int)rsp_buff[6 + j]);
2723                     printf(" ]\n");
2724                 } else
2725                     printf("  Support field: %s\n", desc_p);
2726             }
2727         } else if (SG_LIB_CAT_ILLEGAL_REQ != res) {
2728             if (! op->do_raw) {
2729                 printf("CmdDt INQUIRY, opcode=0x%.2x:  [", op->vpd_pn);
2730                 sg_get_opcode_name((uint8_t)op->vpd_pn, 0,
2731                                    sizeof(op_name) - 1, op_name);
2732                 op_name[sizeof(op_name) - 1] = '\0';
2733                 printf("%s]\n", op_name);
2734             }
2735             pr2serr("CmdDt INQUIRY on opcode=0x%.2x: failed\n", op->vpd_pn);
2736         }
2737     }
2738     return res;
2739 }
2740 
2741 #else /* SG_SCSI_STRINGS */
2742 
2743 /* Returns 0. */
2744 static int
cmddt_process(int sg_fd,const struct opts_t * op)2745 cmddt_process(int sg_fd, const struct opts_t * op)
2746 {
2747     if (sg_fd) { }      /* suppress warning */
2748     if (op) { }         /* suppress warning */
2749     pr2serr("'--cmddt' not implemented, use sg_opcodes\n");
2750     return 0;
2751 }
2752 
2753 #endif /* SG_SCSI_STRINGS */
2754 
2755 
2756 /* Returns 0 if successful */
2757 static int
vpd_mainly_hex(int sg_fd,struct opts_t * op,sgj_opaque_p jap,int off)2758 vpd_mainly_hex(int sg_fd, struct opts_t * op, sgj_opaque_p jap, int off)
2759 {
2760     bool as_json;
2761     bool json_o_hr;
2762     int res, len, n;
2763     char b[128];
2764     sgj_state * jsp = &op->json_st;
2765     const char * cp;
2766     uint8_t * rp;
2767 
2768     as_json = jsp->pr_as_json;
2769     json_o_hr = as_json && jsp->pr_out_hr;
2770     rp = rsp_buff + off;
2771     if ((! op->do_raw) && (op->do_hex < 3)) {
2772         if (op->do_hex)
2773             printf("VPD INQUIRY, page code=0x%.2x:\n", op->vpd_pn);
2774         else
2775             sgj_pr_hr(jsp, "VPD INQUIRY, page code=0x%.2x:\n", op->vpd_pn);
2776     }
2777     if (sg_fd < 0) {
2778         len = sg_get_unaligned_be16(rp + 2) + 4;
2779         res = 0;
2780     } else {
2781         memset(rp, 0, DEF_ALLOC_LEN);
2782         res = vpd_fetch_page(sg_fd, rp, op->vpd_pn, op->maxlen,
2783                              op->do_quiet, op->verbose, &len);
2784     }
2785     if (0 == res) {
2786         if (op->do_raw)
2787             dStrRaw((const char *)rp, len);
2788         else {
2789             int pdt = pdt = rp[0] & PDT_MASK;
2790 
2791             if (0 == op->vpd_pn)
2792                 decode_supported_vpd_4inq(rp, len, op, jap);
2793             else {
2794                 if (op->verbose) {
2795                     cp = sg_get_pdt_str(pdt, sizeof(b), b);
2796                     if (op->do_hex)
2797                         printf("   [PQual=%d  Peripheral device type: %s]\n",
2798                                (rp[0] & 0xe0) >> 5, cp);
2799                     else
2800                         sgj_pr_hr(jsp, "   [PQual=%d  Peripheral device "
2801                                   "type: %s]\n", (rp[0] & 0xe0) >> 5, cp);
2802                 }
2803                 if (json_o_hr && (0 == op->do_hex) && (len > 0) &&
2804                     (len < UINT16_MAX)) {
2805                     char * p;
2806 
2807                     n = len * 4;
2808                     p = malloc(n);
2809                     if (p) {
2810                         n = hex2str(rp, len, NULL, 1, n - 1, p);
2811                         sgj_js_str_out(jsp, p, n);
2812                     }
2813                 } else
2814                     hex2stdout(rp, len, no_ascii_4hex(op));
2815             }
2816         }
2817     } else {
2818         if (SG_LIB_CAT_ILLEGAL_REQ == res)
2819             pr2serr("    inquiry: field in cdb illegal (page not "
2820                     "supported)\n");
2821         else {
2822             sg_get_category_sense_str(res, sizeof(b), b, op->verbose);
2823             pr2serr("    inquiry: %s\n", b);
2824         }
2825     }
2826     return res;
2827 }
2828 
2829 static int
recurse_vpd_decode(struct opts_t * op,sgj_opaque_p jop,int off)2830 recurse_vpd_decode(struct opts_t * op, sgj_opaque_p jop, int off)
2831 {
2832     return vpd_decode(-1, op, jop, off);
2833 }
2834 
2835 /* Returns 0 if successful */
2836 static int
vpd_decode(int sg_fd,struct opts_t * op,sgj_opaque_p jop,int off)2837 vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off)
2838 {
2839     bool bad = false;
2840     bool qt = op->do_quiet;
2841     int len, pdt, pn, vb /*, pqual */;
2842     int res = 0;
2843     sgj_state * jsp = &op->json_st;
2844     bool as_json = jsp->pr_as_json;
2845     sgj_opaque_p jo2p = NULL;
2846     sgj_opaque_p jap = NULL;
2847     const char * np;
2848     const char * ep = "";
2849     uint8_t * rp;
2850 
2851     rp = rsp_buff + off;
2852     vb = op->verbose;
2853     if ((off > 0) && (VPD_NOPE_WANT_STD_INQ != op->vpd_pn))
2854         pn = rp[1];
2855     else
2856         pn = op->vpd_pn;
2857     if (sg_fd != -1 && !op->do_force && pn != VPD_SUPPORTED_VPDS) {
2858         res = vpd_fetch_page(sg_fd, rp, VPD_SUPPORTED_VPDS, op->maxlen,
2859                              qt, vb, &len);
2860         if (res)
2861             goto out;
2862         if (! vpd_page_is_supported(rp, len, pn, vb)) {
2863             if (vb)
2864                 pr2serr("Given VPD page not in supported list, use --force "
2865                         "to override this check\n");
2866             res = sg_convert_errno(EDOM); /* was SG_LIB_CAT_ILLEGAL_REQ */
2867             goto out;
2868         }
2869     }
2870     switch (pn) {
2871     case VPD_SUPPORTED_VPDS:            /* 0x0  ["sv"] */
2872         np = "Supported VPD pages VPD page";
2873         if (!op->do_raw && (op->do_hex < 3))
2874             sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
2875         res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
2876         if (res)
2877             break;
2878         if (op->do_raw)
2879             dStrRaw((const char *)rp, len);
2880         else if (op->do_hex)
2881             hex2stdout(rp, len, no_ascii_4hex(op));
2882         else {
2883             if (as_json) {
2884                 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
2885                 jap = sgj_named_subarray_r(jsp, jo2p,
2886                                   "supported_vpd_page_list");
2887             }
2888             decode_supported_vpd_4inq(rp, len, op, jap);
2889         }
2890         break;
2891     case VPD_UNIT_SERIAL_NUM:           /* 0x80  ["sn"] */
2892         np = "Unit serial number VPD page";
2893         if (! op->do_raw && ! op->do_export && (op->do_hex < 3))
2894             sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
2895         res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
2896         if (res)
2897             break;
2898         if (op->do_raw)
2899             dStrRaw((const char *)rp, len);
2900         else if (op->do_hex)
2901             hex2stdout(rp, len, no_ascii_4hex(op));
2902         else {
2903             char obuff[DEF_ALLOC_LEN];
2904             int k, m;
2905 
2906             memset(obuff, 0, sizeof(obuff));
2907             len -= 4;
2908             if (len >= (int)sizeof(obuff))
2909                 len = sizeof(obuff) - 1;
2910             memcpy(obuff, rp + 4, len);
2911             if (op->do_export) {
2912                 k = encode_whitespaces((uint8_t *)obuff, len);
2913                 if (k > 0) {
2914                     printf("SCSI_IDENT_SERIAL=");
2915                     /* udev-conforming character encoding */
2916                     for (m = 0; m < k; ++m) {
2917                         if ((obuff[m] >= '0' && obuff[m] <= '9') ||
2918                             (obuff[m] >= 'A' && obuff[m] <= 'Z') ||
2919                             (obuff[m] >= 'a' && obuff[m] <= 'z') ||
2920                             strchr("#+-.:=@_", obuff[m]) != NULL)
2921                             printf("%c", obuff[m]);
2922                         else
2923                             printf("\\x%02x", obuff[m]);
2924                     }
2925                     printf("\n");
2926                 }
2927             } else {
2928                 if (as_json)
2929                     jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
2930                 k = encode_unicode((uint8_t *)obuff, len);
2931                 if (k > 0) {
2932                     sgj_pr_hr(jsp, "  Unit serial number: %s\n", obuff);
2933                     sgj_js_nv_s(jsp, jo2p, "unit_serial_number", obuff);
2934                 }
2935             }
2936         }
2937         break;
2938     case VPD_DEVICE_ID:         /* 0x83  ["di"] */
2939         np = "Device Identification VPD page";
2940         if (! op->do_raw && ! op->do_export && (op->do_hex < 3))
2941             sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
2942         res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
2943         if (res)
2944             break;
2945         if (op->do_raw)
2946             dStrRaw((const char *)rp, len);
2947         else if (op->do_hex > 2)
2948             hex2stdout(rp, len, -1);
2949         else if (op->do_export && (! as_json))
2950             export_dev_ids(rp + 4, len - 4, op->verbose);
2951         else {
2952             if (as_json) {
2953                 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
2954                 jap = sgj_named_subarray_r(jsp, jo2p,
2955                                   "designation_descriptor_list");
2956             }
2957             decode_id_vpd(rp, len, op, jap);
2958         }
2959         break;
2960     case VPD_SOFTW_INF_ID:      /* 0x84  ["sii"] */
2961         np = "Software interface identification VPD page";
2962         if (! op->do_raw && (op->do_hex < 3))
2963             sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
2964         res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
2965         if (res)
2966             break;
2967         if (op->do_raw)
2968             dStrRaw((const char *)rp, len);
2969         else {
2970             if (as_json) {
2971                 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
2972                 jap = sgj_named_subarray_r(jsp, jo2p,
2973                                   "software_interface_identifier_list");
2974             }
2975             decode_softw_inf_id(rp, len, op, jap);
2976         }
2977         break;
2978     case VPD_MAN_NET_ADDR:    /* 0x85 ["mna"] */
2979         np = "Management network addresses page";
2980         if (!op->do_raw && (op->do_hex < 3))
2981             sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
2982         res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
2983         if (res)
2984             break;
2985         if (op->do_raw)
2986             dStrRaw((const char *)rp, len);
2987         else {
2988             // pdt = rp[0] & PDT_MASK;
2989             // pdt_str = sg_get_pdt_str(pdt, sizeof(d), d);
2990             // pqual = (rp[0] & 0xe0) >> 5;
2991             if (as_json) {
2992                 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
2993                 jap = sgj_named_subarray_r(jsp, jo2p,
2994                                   "network_services_descriptor_list");
2995             }
2996             decode_net_man_vpd(rp, len, op, jap);
2997         }
2998         break;
2999     case VPD_EXT_INQ:           /* 0x86  ["ei"] */
3000         np = "Extended INQUIRY data";
3001         if (!op->do_raw && (op->do_hex < 3))
3002             sgj_pr_hr(jsp, "VPD INQUIRY: %s page\n", np);
3003         res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
3004         if (res)
3005             break;
3006         if (op->do_raw)
3007             dStrRaw((const char *)rp, len);
3008         else {
3009             bool protect = false;
3010 
3011             op->protect_not_sure = false;
3012             if ((sg_fd >= 0) && (! op->do_force)) {
3013                 struct sg_simple_inquiry_resp sir;
3014 
3015                 res = sg_simple_inquiry(sg_fd, &sir, false, vb);
3016                 if (res) {
3017                     if (op->verbose)
3018                         pr2serr("%s: sg_simple_inquiry() failed, res=%d\n",
3019                                 __func__, res);
3020                     op->protect_not_sure = true;
3021                 } else
3022                     protect = !!(sir.byte_5 & 0x1); /* SPC-3 and later */
3023             } else
3024                 op->protect_not_sure = true;
3025             if (as_json)
3026                 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
3027             decode_x_inq_vpd(rp, len, protect, op, jo2p);
3028         }
3029         break;
3030     case VPD_MODE_PG_POLICY:            /*  0x87  ["mpp"] */
3031         np = "Mode page policy";
3032         if (!op->do_raw && (op->do_hex < 3))
3033             sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
3034         res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
3035         if (res)
3036             break;
3037         if (op->do_raw)
3038             dStrRaw((const char *)rp, len);
3039         else {
3040             if (as_json) {
3041                 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
3042                 jap = sgj_named_subarray_r(jsp, jo2p,
3043                                   "mode_page_policy_descriptor_list");
3044             }
3045             decode_mode_policy_vpd(rp, len, op, jap);
3046         }
3047         break;
3048     case VPD_SCSI_PORTS:        /* 0x88  ["sp"] */
3049         np = "SCSI Ports VPD page";
3050         if (!op->do_raw && (op->do_hex < 3))
3051             sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
3052         res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
3053         if (res)
3054             break;
3055         if (op->do_raw)
3056             dStrRaw((const char *)rp, len);
3057         else {
3058             if (as_json) {
3059                 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
3060                 jap = sgj_named_subarray_r(jsp, jo2p,
3061                                   "scsi_ports_descriptor_list");
3062             }
3063             decode_scsi_ports_vpd_4inq(rp, len, op, jap);
3064         }
3065         break;
3066     case VPD_ATA_INFO:          /* 0x89  ["ai"] */
3067         np = "ATA information VPD page";
3068         if (!op->do_raw && (op->do_hex < 3))
3069             sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
3070         res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
3071         if (res)
3072             break;
3073         /* format output for 'hdparm --Istdin' with '-rr' or '-HHH' */
3074         if ((2 == op->do_raw) || (3 == op->do_hex))
3075             dWordHex((const unsigned short *)(rp + 60), 256, -2,
3076                      sg_is_big_endian());
3077         else if (op->do_raw)
3078             dStrRaw((const char *)rp, len);
3079         else {
3080             if (as_json)
3081                 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
3082             else
3083                 op->do_long = true;
3084             decode_ata_info_vpd(rp, len, op, jo2p);
3085         }
3086         break;
3087     case VPD_POWER_CONDITION:   /* 0x8a   ["pc"] */
3088         np = "Power condition VPD page";
3089         if (!op->do_raw && (op->do_hex < 3))
3090             sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
3091         res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
3092         if (res)
3093             break;
3094         if (op->do_raw)
3095             dStrRaw((const char *)rp, len);
3096         else {
3097             if (as_json)
3098                 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
3099             decode_power_condition(rp, len, op, jo2p);
3100         }
3101         break;
3102     case VPD_DEVICE_CONSTITUENTS:       /* 0x8b  ["dc"] */
3103         np = "Device constituents page VPD page";
3104         if (!op->do_raw && (op->do_hex < 3))
3105             sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
3106         res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
3107         if (res)
3108             break;
3109         if (op->do_raw)
3110             dStrRaw((const char *)rp, len);
3111         else {
3112             if (as_json) {
3113                 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
3114                 jap = sgj_named_subarray_r(jsp, jo2p,
3115                                   "constituent_descriptor_list");
3116             }
3117             decode_dev_constit_vpd(rp, len, op, jap, recurse_vpd_decode);
3118         }
3119         break;
3120     case VPD_CFA_PROFILE_INFO:    /* 0x8c ["cfa"] */
3121         np = "CFA profile information VPD page";
3122         if (!op->do_raw && (op->do_hex < 3))
3123             sgj_pr_hr(jsp, "%s:\n", np);
3124         res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
3125         if (0 == res) {
3126             if (op->do_raw)
3127                 dStrRaw((const char *)rp, len);
3128             else {
3129                 if (as_json) {
3130                     jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
3131                     jap = sgj_named_subarray_r(jsp, jo2p,
3132                                       "cfa_profile_descriptor_list");
3133                 }
3134                 decode_cga_profile_vpd(rp, len, op, jap);
3135             }
3136         }
3137         break;
3138     case VPD_POWER_CONSUMPTION:   /* 0x8d   ["psm"] */
3139         np = "Power consumption VPD page";
3140         if (!op->do_raw && (op->do_hex < 3))
3141             sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
3142         res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
3143         if (res)
3144             break;
3145         if (op->do_raw)
3146             dStrRaw((const char *)rp, len);
3147         else {
3148             if (as_json) {
3149                 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
3150                 jap = sgj_named_subarray_r(jsp, jo2p,
3151                                   "power_consumption_descriptor_list");
3152             }
3153             decode_power_consumption(rp, len, op, jap);
3154         }
3155         break;
3156     case VPD_3PARTY_COPY:       /* 0x8f  ["tpc"] */
3157         np = "Third party copy VPD page";
3158         if (!op->do_raw && (op->do_hex < 3))
3159             sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
3160         res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
3161         if (res)
3162             break;
3163         if (op->do_raw)
3164             dStrRaw((const char *)rp, len);
3165         else {
3166             if (as_json) {
3167                 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
3168                 jap = sgj_named_subarray_r(jsp, jo2p,
3169                                   "third_party_copy_descriptor_list");
3170             }
3171             decode_3party_copy_vpd(rp, len, op, jap);
3172         }
3173         break;
3174     case VPD_PROTO_LU:          /* 0x90  ["pslu"] */
3175         np = "Protocol specific logical unit information VPD page";
3176         if (!op->do_raw && (op->do_hex < 3))
3177             sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
3178         res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
3179         if (res)
3180             break;
3181         if (op->do_raw)
3182             dStrRaw((const char *)rp, len);
3183         else {
3184             if (as_json) {
3185                 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
3186                 jap = sgj_named_subarray_r(jsp, jo2p,
3187                                   "logical_unit_information_descriptor_list");
3188             }
3189             decode_proto_lu_vpd(rp, len, op, jap);
3190         }
3191         break;
3192     case VPD_PROTO_PORT:        /* 0x91  ["pspo"] */
3193         np = "Protocol specific port information VPD page";
3194         if (!op->do_raw && (op->do_hex < 3))
3195             sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
3196         res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
3197         if (res)
3198             break;
3199         if (op->do_raw)
3200             dStrRaw((const char *)rp, len);
3201         else {
3202             if (as_json) {
3203                 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
3204                 jap = sgj_named_subarray_r(jsp, jo2p,
3205                                   "port_information_descriptor_list");
3206             }
3207             decode_proto_port_vpd(rp, len, op, jap);
3208         }
3209         break;
3210     case VPD_SCSI_FEATURE_SETS:         /* 0x92  ["sfs"] */
3211         np = "SCSI Feature sets VPD page";
3212         if (!op->do_raw && (op->do_hex < 3))
3213             sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
3214         res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
3215         if (res)
3216             break;
3217         if (op->do_raw)
3218             dStrRaw((const char *)rp, len);
3219         else {
3220             if (as_json) {
3221                 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
3222                 jap = sgj_named_subarray_r(jsp, jo2p,
3223                                   "feature_set_code_list");
3224             }
3225             decode_feature_sets_vpd(rp, len, op, jap);
3226         }
3227         break;
3228     case 0xb0:  /* VPD pages in B0h to BFh range depend on pdt */
3229         np = NULL;
3230         res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
3231         if (0 == res) {
3232             bool bl = false;
3233             bool sad = false;
3234             bool oi = false;
3235 
3236             ep = "";
3237             if (op->do_raw) {
3238                 dStrRaw((const char *)rp, len);
3239                 break;
3240             }
3241             pdt = rp[0] & PDT_MASK;
3242             switch (pdt) {
3243             case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
3244                 np = "Block limits VPD page";
3245                 ep = "(SBC)";
3246                 bl = true;
3247                 break;
3248             case PDT_TAPE: case PDT_MCHANGER:
3249                 np = "Sequential-access device capabilities VPD page";
3250                 ep = "(SSC)";
3251                 sad = true;
3252                 break;
3253             case PDT_OSD:
3254                 np = "OSD information VPD page";
3255                 ep = "(OSD)";
3256                 oi = true;
3257                 break;
3258             default:
3259                 np = NULL;
3260                 break;
3261             }
3262             if (op->do_hex < 3) {
3263                 if (NULL == np)
3264                     sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
3265                 else
3266                     sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep);
3267             }
3268             if (as_json)
3269                 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
3270             if (bl)
3271                 decode_block_limits_vpd(rp, len, op, jo2p);
3272             else if (sad || oi)
3273                 decode_b0_vpd(rp, len, op, jop);
3274         } else if (! op->do_raw)
3275             pr2serr("VPD INQUIRY: page=0xb0\n");
3276         break;
3277     case 0xb1:  /* VPD pages in B0h to BFh range depend on pdt */
3278         res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
3279         if (0 == res) {
3280             bool bdc = false;
3281             static const char * masn =
3282                         "Manufactured-assigned serial number VPD page";
3283 
3284             if (op->do_raw) {
3285                 dStrRaw((const char *)rp, len);
3286                 break;
3287             }
3288             pdt = rp[0] & PDT_MASK;
3289             switch (pdt) {
3290             case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
3291                 np = "Block device characteristics VPD page";
3292                 ep = "(SBC)";
3293                 bdc = true;
3294                 break;
3295             case PDT_TAPE: case PDT_MCHANGER:
3296                 np = masn;
3297                 ep = "(SSC)";
3298                 break;
3299             case PDT_OSD:
3300                 np = "Security token VPD page";
3301                 ep = "(OSD)";
3302                 break;
3303             case PDT_ADC:
3304                 np = masn;
3305                 ep = "(ADC)";
3306                 break;
3307             default:
3308                 np = NULL;
3309                 printf("VPD INQUIRY: page=0x%x, pdt=0x%x\n", 0xb1, pdt);
3310                 break;
3311             }
3312             if (op->do_hex < 3) {
3313                 if (NULL == np)
3314                     sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
3315                 else
3316                     sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep);
3317             }
3318             if (as_json)
3319                 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
3320             if (bdc)
3321                 decode_block_dev_ch_vpd(rp, len, op, jo2p);
3322             else
3323                 decode_b1_vpd(rp, len, op, jo2p);
3324         } else if (! op->do_raw)
3325             pr2serr("VPD INQUIRY: page=0xb1\n");
3326         break;
3327     case 0xb2:  /* VPD pages in B0h to BFh range depend on pdt */
3328         res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
3329         if (0 == res) {
3330             bool lbpv = false;
3331             bool tas = false;
3332 
3333             if (op->do_raw) {
3334                 dStrRaw((const char *)rp, len);
3335                 break;
3336             }
3337             pdt = rp[0] & PDT_MASK;
3338             switch (pdt) {
3339             case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
3340                 np = "Logical block provisioning VPD page";
3341                 ep = "(SBC)";
3342                 lbpv = true;
3343                 break;
3344             case PDT_TAPE: case PDT_MCHANGER:
3345                 np = "TapeAlert supported flags VPD page";
3346                 ep = "(SSC)";
3347                 tas = true;
3348                 break;
3349             default:
3350                 np = NULL;
3351                 break;
3352             }
3353             if (op->do_hex < 3) {
3354                 if (NULL == np)
3355                     sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
3356                 else
3357                     sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep);
3358             }
3359             if (as_json)
3360                 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
3361             if (lbpv)
3362                 return decode_block_lb_prov_vpd(rp, len, op, jo2p);
3363             else if (tas)
3364                 decode_tapealert_supported_vpd(rp, len, op, jo2p);
3365             else
3366                 return vpd_mainly_hex(sg_fd, op, NULL, off);
3367         } else if (! op->do_raw)
3368             pr2serr("VPD INQUIRY: page=0xb2\n");
3369         break;
3370     case 0xb3:
3371         res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
3372         if (0 == res) {
3373             bool ref = false;
3374 
3375             if (op->do_raw) {
3376                 dStrRaw((const char *)rp, len);
3377                 break;
3378             }
3379             pdt = rp[0] & PDT_MASK;
3380             switch (pdt) {
3381             case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
3382                 np = "Referrals VPD page";
3383                 ep = "(SBC)";
3384                 ref = true;
3385                 break;
3386             default:
3387                 np = NULL;
3388                 break;
3389             }
3390             if (op->do_hex < 3) {
3391                 if (NULL == np)
3392                     sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
3393                 else
3394                     sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep);
3395             }
3396             if (as_json)
3397                 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
3398             if (ref)
3399                 decode_referrals_vpd(rp, len, op, jo2p);
3400             else
3401                 decode_b3_vpd(rp, len, op, jo2p);
3402             return 0;
3403         } else if (! op->do_raw)
3404             pr2serr("VPD INQUIRY: page=0xb3\n");
3405         break;
3406     case 0xb4:
3407         res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
3408         if (0 == res) {
3409             bool sbl = false;
3410             bool dtde = false;
3411 
3412             if (op->do_raw) {
3413                 dStrRaw((const char *)rp, len);
3414                 break;
3415             }
3416             pdt = rp[0] & PDT_MASK;
3417             switch (pdt) {
3418             case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
3419                 np = "Supported block lengths and protection types VPD page";
3420                 ep = "(SBC)";
3421                 sbl = true;
3422                 break;
3423             case PDT_TAPE: case PDT_MCHANGER:
3424                 np = "Device transfer data element VPD page";
3425                 ep = "(SSC)";
3426                 dtde = true;
3427                 break;
3428             default:
3429                 np = NULL;
3430                 break;
3431             }
3432             if (op->do_hex < 3) {
3433                 if (NULL == np)
3434                     sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
3435                 else
3436                     sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep);
3437             }
3438             if (as_json)
3439                 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
3440             if (sbl) {
3441                 if (as_json)
3442                     jap = sgj_named_subarray_r(jsp, jo2p, "logical_block_"
3443                             "length_and_protection_types_descriptor_list");
3444                 decode_sup_block_lens_vpd(rp, len, op, jap);
3445             } else if (dtde) {
3446                 if (! jsp->pr_as_json)
3447                     hex2stdout(rp + 4, len - 4, 1);
3448                 sgj_js_nv_hex_bytes(jsp, jop, "device_transfer_data_element",
3449                                     rp + 4, len - 4);
3450             } else
3451                 return vpd_mainly_hex(sg_fd, op, NULL, off);
3452             return 0;
3453         } else if (! op->do_raw)
3454             pr2serr("VPD INQUIRY: page=0xb4\n");
3455         break;
3456     case 0xb5:
3457         res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
3458         if (0 == res) {
3459             bool bdce = false;
3460             bool lbp = false;
3461 
3462             if (op->do_raw) {
3463                 dStrRaw((const char *)rp, len);
3464                 break;
3465             }
3466             pdt = rp[0] & PDT_MASK;
3467             switch (pdt) {
3468             case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
3469                 np = "Block device characteristics VPD page";
3470                 ep = "(SBC)";
3471                 bdce = true;
3472                 break;
3473             case PDT_TAPE: case PDT_MCHANGER:
3474                 np = "Logical block protection VPD page";
3475                 ep = "(SSC)";
3476                 lbp = true;
3477                 break;
3478             default:
3479                 np = NULL;
3480                 break;
3481             }
3482             if (op->do_hex < 3) {
3483                 if (NULL == np)
3484                     sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
3485                 else
3486                     sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep);
3487             }
3488             if (as_json)
3489                 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
3490             if (bdce)
3491                 decode_block_dev_char_ext_vpd(rp, len, op, jo2p);
3492             else if (lbp) {     /* VPD_LB_PROTECTION  0xb5 ["lbpro"] (SSC) */
3493                 if (as_json)
3494                     jap = sgj_named_subarray_r(jsp, jo2p,
3495                      "logical_block_protection_method_descriptor_list");
3496                 decode_lb_protection_vpd(rp, len, op, jap);
3497             } else
3498                 return vpd_mainly_hex(sg_fd, op, NULL, off);
3499             return 0;
3500         } else if (! op->do_raw)
3501             pr2serr("VPD INQUIRY: page=0xb5\n");
3502         break;
3503     case 0xb6:
3504         res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
3505         if (0 == res) {
3506             bool zbdch = false;
3507 
3508             if (op->do_raw) {
3509                 dStrRaw((const char *)rp, len);
3510                 break;
3511             }
3512             pdt = rp[0] & PDT_MASK;
3513             switch (pdt) {
3514             case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
3515                 np = "Zoned block device characteristics VPD page";
3516                 ep = "(SBC, ZBC)";
3517                 zbdch = true;
3518                 break;
3519             default:
3520                 np = NULL;
3521                 break;
3522             }
3523             if (op->do_hex < 3) {
3524                 if (NULL == np)
3525                     sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
3526                 else
3527                     sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep);
3528             }
3529             if (as_json)
3530                 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
3531             if (zbdch)
3532                 decode_zbdch_vpd(rp, len, op, jo2p);
3533             else
3534                 return vpd_mainly_hex(sg_fd, op, NULL, off);
3535             return 0;
3536         } else if (! op->do_raw)
3537             pr2serr("VPD INQUIRY: page=0xb6\n");
3538         break;
3539     case 0xb7:
3540         res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
3541         if (0 == res) {
3542             bool ble = false;
3543 
3544             if (op->do_raw) {
3545                 dStrRaw((const char *)rp, len);
3546                 break;
3547             }
3548             pdt = rp[0] & PDT_MASK;
3549             switch (pdt) {
3550             case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
3551                 np = "Block limits extension VPD page";
3552                 ep = "(SBC)";
3553                 ble = true;
3554                 break;
3555             default:
3556                 np = NULL;
3557                 break;
3558             }
3559             if (op->do_hex < 3) {
3560                 if (NULL == np)
3561                     sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
3562                 else
3563                     sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep);
3564             }
3565             if (as_json)
3566                 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
3567             if (ble)
3568                 decode_block_limits_ext_vpd(rp, len, op, jo2p);
3569             else
3570                 return vpd_mainly_hex(sg_fd, op, NULL, off);
3571             return 0;
3572         } else if (! op->do_raw)
3573             pr2serr("VPD INQUIRY: page=0xb7\n");
3574         break;
3575     case 0xb8:
3576         res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
3577         if (0 == res) {
3578             bool fp = false;
3579 
3580             if (op->do_raw) {
3581                 dStrRaw((const char *)rp, len);
3582                 break;
3583             }
3584             pdt = rp[0] & PDT_MASK;
3585             switch (pdt) {
3586             case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
3587                 np = "Format presets VPD page";
3588                 ep = "(SBC)";
3589                 fp = true;
3590                 break;
3591             default:
3592                 np = NULL;
3593                 break;
3594             }
3595             if (op->do_hex < 3) {
3596                 if (NULL == np)
3597                     sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
3598                 else
3599                     sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep);
3600             }
3601             if (as_json) {
3602                 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
3603                 jap = sgj_named_subarray_r(jsp, jo2p, "format_preset_"
3604                             "descriptor_list");
3605             }
3606             if (fp)
3607                 decode_format_presets_vpd(rp, len, op, jap);
3608             else
3609                 return vpd_mainly_hex(sg_fd, op, NULL, off);
3610             return 0;
3611         } else if (! op->do_raw)
3612             pr2serr("VPD INQUIRY: page=0xb8\n");
3613         break;
3614     case 0xb9:
3615         res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
3616         if (0 == res) {
3617             bool cpr = false;
3618 
3619             if (op->do_raw) {
3620                 dStrRaw((const char *)rp, len);
3621                 break;
3622             }
3623             pdt = rp[0] & PDT_MASK;
3624             switch (pdt) {
3625             case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
3626                 np = "Concurrent positioning LBAs VPD page";
3627                 ep = "(SBC)";
3628                 cpr = true;
3629                 break;
3630             default:
3631                 np = NULL;
3632                 break;
3633             }
3634             if (op->do_hex < 3) {
3635                 if (NULL == np)
3636                     sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
3637                 else
3638                     sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep);
3639             }
3640             if (as_json) {
3641                 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
3642                 jap = sgj_named_subarray_r(jsp, jo2p, "lba_range_"
3643                                            "descriptor_list");
3644             }
3645             if (cpr)
3646                 decode_con_pos_range_vpd(rp, len, op, jap);
3647             else
3648                 return vpd_mainly_hex(sg_fd, op, NULL, off);
3649             return 0;
3650         } else if (! op->do_raw)
3651             pr2serr("VPD INQUIRY: page=0xb8\n");
3652         break;
3653     /* Vendor specific VPD pages (>= 0xc0) */
3654     case VPD_UPR_EMC:   /* 0xc0 */
3655         np = "Unit path report VPD page";
3656         ep = "(EMC)";
3657         if (!op->do_raw && (op->do_hex < 3))
3658             sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep);
3659         res = vpd_fetch_page(sg_fd, rp, pn, -1, qt, vb, &len);
3660         if (res)
3661             break;
3662         if (op->do_raw)
3663             dStrRaw((const char *)rp, len);
3664         else {
3665             if (as_json)
3666                 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
3667             decode_upr_vpd_c0_emc(rp, len, op, jo2p);
3668         }
3669         break;
3670     case VPD_RDAC_VERS:         /* 0xc2 */
3671         np = "Software Version VPD page";
3672         ep = "(RDAC)";
3673         if (!op->do_raw && (op->do_hex < 3))
3674             sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep);
3675         res = vpd_fetch_page(sg_fd, rp, pn, -1, qt, vb, &len);
3676         if (res)
3677             break;
3678         if (op->do_raw)
3679             dStrRaw((const char *)rp, len);
3680         else {
3681             if (as_json)
3682                 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
3683             decode_rdac_vpd_c2(rp, len, op, jo2p);
3684         }
3685         break;
3686     case VPD_RDAC_VAC:          /* 0xc9 */
3687         np = "Volume access control VPD page";
3688         ep = "(RDAC)";
3689         if (!op->do_raw && (op->do_hex < 3))
3690             sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep);
3691         res = vpd_fetch_page(sg_fd, rp, pn, -1, qt, vb, &len);
3692         if (res)
3693             break;
3694         if (op->do_raw)
3695             dStrRaw((const char *)rp, len);
3696         else {
3697             if (as_json)
3698                 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
3699             decode_rdac_vpd_c9(rp, len, op, jo2p);
3700         }
3701         break;
3702     case SG_NVME_VPD_NICR:          /* 0xde */
3703         np = "NVMe Identify Controller Response VPD page";
3704         /* NVMe: Identify Controller data structure (CNS 01h) */
3705         ep = "(sg3_utils)";
3706         res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
3707         if (res) {
3708             sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep);
3709             break;
3710         }
3711         if (op->do_raw) {
3712             dStrRaw((const char *)rp, len);
3713             break;
3714         }
3715         pdt = rp[0] & PDT_MASK;
3716         if (op->do_hex < 3) {
3717             if (NULL == np)
3718                 sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
3719             else
3720                 sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep);
3721         }
3722         if (len < 16) {
3723             pr2serr("%s expected to be > 15 bytes long (got: %d)\n", ep, len);
3724             break;
3725         } else {
3726             int n = len - 16;
3727 
3728             if (n > 4096) {
3729                 pr2serr("NVMe Identify response expected to be <= 4096 "
3730                         "bytes (got: %d)\n", n);
3731                 break;
3732             }
3733             if (op->do_hex)
3734                 hex2stdout(rp, len, no_ascii_4hex(op));
3735             else if (as_json) {
3736                 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
3737                 sgj_js_nv_hex_bytes(jsp, jo2p, "response_bytes", rp + 16, n);
3738             } else
3739                 hex2stdout(rp + 16, n, 1);
3740         }
3741         break;
3742     default:
3743         bad = true;
3744         break;
3745     }
3746     if (bad) {
3747         if ((pn > 0) && (pn < 0x80)) {
3748             if (!op->do_raw && (op->do_hex < 3))
3749                 printf("VPD INQUIRY: ASCII information page, FRU code=0x%x\n",
3750                        pn);
3751             res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
3752             if (0 == res) {
3753                 if (op->do_raw)
3754                     dStrRaw((const char *)rp, len);
3755                 else
3756                     decode_ascii_inf(rp, len, op);
3757             }
3758         } else {
3759             if (op->do_hex < 3)
3760                 pr2serr(" Only hex output supported.\n");
3761             return vpd_mainly_hex(sg_fd, op, NULL, off);
3762         }
3763     }
3764 out:
3765     if (res) {
3766         char b[80];
3767 
3768         if (SG_LIB_CAT_ILLEGAL_REQ == res)
3769             pr2serr("    inquiry: field in cdb illegal (page not "
3770                     "supported)\n");
3771         else {
3772             sg_get_category_sense_str(res, sizeof(b), b, vb);
3773             pr2serr("    inquiry: %s\n", b);
3774         }
3775     }
3776     return res;
3777 }
3778 
3779 #if (HAVE_NVME && (! IGNORE_NVME))
3780 
3781 static void
nvme_hex_raw(const uint8_t * b,int b_len,const struct opts_t * op)3782 nvme_hex_raw(const uint8_t * b, int b_len, const struct opts_t * op)
3783 {
3784     if (op->do_raw)
3785         dStrRaw((const char *)b, b_len);
3786     else if (op->do_hex) {
3787         if (op->do_hex < 3) {
3788             printf("data_in buffer:\n");
3789             hex2stdout(b, b_len, (2 == op->do_hex));
3790         } else
3791             hex2stdout(b, b_len, -1);
3792     }
3793 }
3794 
3795 static const char * rperf[] = {"Best", "Better", "Good", "Degraded"};
3796 
3797 static void
show_nvme_id_ns(const uint8_t * dinp,int do_long)3798 show_nvme_id_ns(const uint8_t * dinp, int do_long)
3799 {
3800     bool got_eui_128 = false;
3801     uint32_t u, k, off, num_lbaf, flbas, flba_info, md_size, lb_size;
3802     uint64_t ns_sz, eui_64;
3803 
3804     num_lbaf = dinp[25] + 1;  /* spec says this is "0's based value" */
3805     flbas = dinp[26] & 0xf;   /* index of active LBA format (for this ns) */
3806     ns_sz = sg_get_unaligned_le64(dinp + 0);
3807     eui_64 = sg_get_unaligned_be64(dinp + 120);  /* N.B. big endian */
3808     if (! sg_all_zeros(dinp + 104, 16))
3809         got_eui_128 = true;
3810     printf("    Namespace size/capacity: %" PRIu64 "/%" PRIu64
3811            " blocks\n", ns_sz, sg_get_unaligned_le64(dinp + 8));
3812     printf("    Namespace utilization: %" PRIu64 " blocks\n",
3813            sg_get_unaligned_le64(dinp + 16));
3814     if (got_eui_128) {          /* N.B. big endian */
3815         printf("    NGUID: 0x%02x", dinp[104]);
3816         for (k = 1; k < 16; ++k)
3817             printf("%02x", dinp[104 + k]);
3818         printf("\n");
3819     } else if (do_long)
3820         printf("    NGUID: 0x0\n");
3821     if (eui_64)
3822         printf("    EUI-64: 0x%" PRIx64 "\n", eui_64); /* N.B. big endian */
3823     printf("    Number of LBA formats: %u\n", num_lbaf);
3824     printf("    Index LBA size: %u\n", flbas);
3825     for (k = 0, off = 128; k < num_lbaf; ++k, off += 4) {
3826         printf("    LBA format %u support:", k);
3827         if (k == flbas)
3828             printf(" <-- active\n");
3829         else
3830             printf("\n");
3831         flba_info = sg_get_unaligned_le32(dinp + off);
3832         md_size = flba_info & 0xffff;
3833         lb_size = flba_info >> 16 & 0xff;
3834         if (lb_size > 31) {
3835             pr2serr("%s: logical block size exponent of %u implies a LB "
3836                     "size larger than 4 billion bytes, ignore\n", __func__,
3837                     lb_size);
3838             continue;
3839         }
3840         lb_size = 1U << lb_size;
3841         ns_sz *= lb_size;
3842         ns_sz /= 500*1000*1000;
3843         if (ns_sz & 0x1)
3844             ns_sz = (ns_sz / 2) + 1;
3845         else
3846             ns_sz = ns_sz / 2;
3847         u = (flba_info >> 24) & 0x3;
3848         printf("      Logical block size: %u bytes\n", lb_size);
3849         printf("      Approximate namespace size: %" PRIu64 " GB\n", ns_sz);
3850         printf("      Metadata size: %u bytes\n", md_size);
3851         printf("      Relative performance: %s [0x%x]\n", rperf[u], u);
3852     }
3853 }
3854 
3855 /* Send Identify(CNS=0, nsid) and decode the Identify namespace response */
3856 static int
nvme_id_namespace(struct sg_pt_base * ptvp,uint32_t nsid,struct sg_nvme_passthru_cmd * id_cmdp,uint8_t * id_dinp,int id_din_len,const struct opts_t * op)3857 nvme_id_namespace(struct sg_pt_base * ptvp, uint32_t nsid,
3858                   struct sg_nvme_passthru_cmd * id_cmdp, uint8_t * id_dinp,
3859                   int id_din_len, const struct opts_t * op)
3860 {
3861     int ret = 0;
3862     int vb = op->verbose;
3863     uint8_t resp[16];
3864 
3865     clear_scsi_pt_obj(ptvp);
3866     id_cmdp->nsid = nsid;
3867     id_cmdp->cdw10 = 0x0;       /* CNS=0x0 Identify NS (CNTID=0) */
3868     id_cmdp->cdw11 = 0x0;       /* NVMSETID=0 (only valid when CNS=0x4) */
3869     id_cmdp->cdw14 = 0x0;       /* UUID index (assume not supported) */
3870     set_scsi_pt_data_in(ptvp, id_dinp, id_din_len);
3871     set_scsi_pt_sense(ptvp, resp, sizeof(resp));
3872     set_scsi_pt_cdb(ptvp, (const uint8_t *)id_cmdp, sizeof(*id_cmdp));
3873     ret = do_scsi_pt(ptvp, -1, 0 /* timeout (def: 1 min) */, vb);
3874     if (vb > 2)
3875         pr2serr("%s: do_scsi_pt() result is %d\n", __func__, ret);
3876     if (ret) {
3877         if (SCSI_PT_DO_BAD_PARAMS == ret)
3878             ret = SG_LIB_SYNTAX_ERROR;
3879         else if (SCSI_PT_DO_TIMEOUT == ret)
3880             ret = SG_LIB_CAT_TIMEOUT;
3881         else if (ret < 0)
3882             ret = sg_convert_errno(-ret);
3883         return ret;
3884     }
3885     if (op->do_hex || op->do_raw) {
3886         nvme_hex_raw(id_dinp, id_din_len, op);
3887         return 0;
3888     }
3889     show_nvme_id_ns(id_dinp, op->do_long);
3890     return 0;
3891 }
3892 
3893 static void
show_nvme_id_ctrl(const uint8_t * dinp,const char * dev_name,int do_long)3894 show_nvme_id_ctrl(const uint8_t *dinp, const char *dev_name, int do_long)
3895 {
3896     bool got_fguid;
3897     uint8_t ver_min, ver_ter, mtds;
3898     uint16_t ver_maj, oacs, oncs;
3899     uint32_t k, ver, max_nsid, npss, j, n, m;
3900     uint64_t sz1, sz2;
3901     const uint8_t * up;
3902 
3903     max_nsid = sg_get_unaligned_le32(dinp + 516); /* NN */
3904     printf("Identify controller for %s:\n", dev_name);
3905     printf("  Model number: %.40s\n", (const char *)(dinp + 24));
3906     printf("  Serial number: %.20s\n", (const char *)(dinp + 4));
3907     printf("  Firmware revision: %.8s\n", (const char *)(dinp + 64));
3908     ver = sg_get_unaligned_le32(dinp + 80);
3909     ver_maj = (ver >> 16);
3910     ver_min = (ver >> 8) & 0xff;
3911     ver_ter = (ver & 0xff);
3912     printf("  Version: %u.%u", ver_maj, ver_min);
3913     if ((ver_maj > 1) || ((1 == ver_maj) && (ver_min > 2)) ||
3914         ((1 == ver_maj) && (2 == ver_min) && (ver_ter > 0)))
3915         printf(".%u\n", ver_ter);
3916     else
3917         printf("\n");
3918     oacs = sg_get_unaligned_le16(dinp + 256);
3919     if (0x1ff & oacs) {
3920         printf("  Optional admin command support:\n");
3921         if (0x200 & oacs)
3922             printf("    Get LBA status\n");     /* NVMe 1.4 */
3923         if (0x100 & oacs)
3924             printf("    Doorbell buffer config\n");
3925         if (0x80 & oacs)
3926             printf("    Virtualization management\n");
3927         if (0x40 & oacs)
3928             printf("    NVMe-MI send and NVMe-MI receive\n");
3929         if (0x20 & oacs)
3930             printf("    Directive send and directive receive\n");
3931         if (0x10 & oacs)
3932             printf("    Device self-test\n");
3933         if (0x8 & oacs)
3934             printf("    Namespace management and attachment\n");
3935         if (0x4 & oacs)
3936             printf("    Firmware download and commit\n");
3937         if (0x2 & oacs)
3938             printf("    Format NVM\n");
3939         if (0x1 & oacs)
3940             printf("    Security send and receive\n");
3941     } else
3942         printf("  No optional admin command support\n");
3943     oncs = sg_get_unaligned_le16(dinp + 256);
3944     if (0x7f & oncs) {
3945         printf("  Optional NVM command support:\n");
3946         if (0x80 & oncs)
3947             printf("    Verify\n");     /* NVMe 1.4 */
3948         if (0x40 & oncs)
3949             printf("    Timestamp feature\n");
3950         if (0x20 & oncs)
3951             printf("    Reservations\n");
3952         if (0x10 & oncs)
3953             printf("    Save and Select fields non-zero\n");
3954         if (0x8 & oncs)
3955             printf("    Write zeroes\n");
3956         if (0x4 & oncs)
3957             printf("    Dataset management\n");
3958         if (0x2 & oncs)
3959             printf("    Write uncorrectable\n");
3960         if (0x1 & oncs)
3961             printf("    Compare\n");
3962     } else
3963         printf("  No optional NVM command support\n");
3964     printf("  PCI vendor ID VID/SSVID: 0x%x/0x%x\n",
3965            sg_get_unaligned_le16(dinp + 0),
3966            sg_get_unaligned_le16(dinp + 2));
3967     printf("  IEEE OUI Identifier: 0x%x\n",  /* this has been renamed AOI */
3968            sg_get_unaligned_le24(dinp + 73));
3969     got_fguid = ! sg_all_zeros(dinp + 112, 16);
3970     if (got_fguid) {
3971         printf("  FGUID: 0x%02x", dinp[112]);
3972         for (k = 1; k < 16; ++k)
3973             printf("%02x", dinp[112 + k]);
3974         printf("\n");
3975     } else if (do_long)
3976         printf("  FGUID: 0x0\n");
3977     printf("  Controller ID: 0x%x\n", sg_get_unaligned_le16(dinp + 78));
3978     if (do_long) {      /* Bytes 240 to 255 are reserved for NVME-MI */
3979         printf("  NVMe Management Interface [MI] settings:\n");
3980         printf("    Enclosure: %d [NVMEE]\n", !! (0x2 & dinp[253]));
3981         printf("    NVMe Storage device: %d [NVMESD]\n",
3982                !! (0x1 & dinp[253]));
3983         printf("    Management endpoint capabilities, over a PCIe port: %d "
3984                "[PCIEME]\n",
3985                !! (0x2 & dinp[255]));
3986         printf("    Management endpoint capabilities, over a SMBus/I2C port: "
3987                "%d [SMBUSME]\n", !! (0x1 & dinp[255]));
3988     }
3989     printf("  Number of namespaces: %u\n", max_nsid);
3990     sz1 = sg_get_unaligned_le64(dinp + 280);  /* lower 64 bits */
3991     sz2 = sg_get_unaligned_le64(dinp + 288);  /* upper 64 bits */
3992     if (sz2)
3993         printf("  Total NVM capacity: huge ...\n");
3994     else if (sz1)
3995         printf("  Total NVM capacity: %" PRIu64 " bytes\n", sz1);
3996     mtds = dinp[77];
3997     printf("  Maximum data transfer size: ");
3998     if (mtds)
3999         printf("%u pages\n", 1U << mtds);
4000     else
4001         printf("<unlimited>\n");
4002 
4003     if (do_long) {
4004         const char * const non_op = "does not process I/O";
4005         const char * const operat = "processes I/O";
4006         const char * cp;
4007 
4008         printf("  Total NVM capacity: 0 bytes\n");
4009         npss = dinp[263] + 1;
4010         up = dinp + 2048;
4011         for (k = 0; k < npss; ++k, up += 32) {
4012             n = sg_get_unaligned_le16(up + 0);
4013             n *= (0x1 & up[3]) ? 1 : 100;    /* unit: 100 microWatts */
4014             j = n / 10;                      /* unit: 1 milliWatts */
4015             m = j % 1000;
4016             j /= 1000;
4017             cp = (0x2 & up[3]) ? non_op : operat;
4018             printf("  Power state %u: Max power: ", k);
4019             if (0 == j) {
4020                 m = n % 10;
4021                 n /= 10;
4022                 printf("%u.%u milliWatts, %s\n", n, m, cp);
4023             } else
4024                 printf("%u.%03u Watts, %s\n", j, m, cp);
4025             n = sg_get_unaligned_le32(up + 4);
4026             if (0 == n)
4027                 printf("    [ENLAT], ");
4028             else
4029                 printf("    ENLAT=%u, ", n);
4030             n = sg_get_unaligned_le32(up + 8);
4031             if (0 == n)
4032                 printf("[EXLAT], ");
4033             else
4034                 printf("EXLAT=%u, ", n);
4035             n = 0x1f & up[12];
4036             printf("RRT=%u, ", n);
4037             n = 0x1f & up[13];
4038             printf("RRL=%u, ", n);
4039             n = 0x1f & up[14];
4040             printf("RWT=%u, ", n);
4041             n = 0x1f & up[15];
4042             printf("RWL=%u\n", n);
4043         }
4044     }
4045 }
4046 
4047 /* Send a NVMe Identify(CNS=1) and decode Controller info. If the
4048  * device name includes a namespace indication (e.g. /dev/nvme0ns1) then
4049  * an Identify namespace command is sent to that namespace (e.g. 1). If the
4050  * device name does not contain a namespace indication (e.g. /dev/nvme0)
4051  * and --only is not given then nvme_id_namespace() is sent for each
4052  * namespace in the controller. Namespaces number sequentially starting at
4053  * 1 . The CNS (Controller or Namespace Structure) field is CDW10 7:0, was
4054  * only bit 0 in NVMe 1.0 and bits 1:0 in NVMe 1.1, thereafter 8 bits. */
4055 static int
do_nvme_identify_ctrl(int pt_fd,const struct opts_t * op)4056 do_nvme_identify_ctrl(int pt_fd, const struct opts_t * op)
4057 {
4058     int ret = 0;
4059     int vb = op->verbose;
4060     uint32_t k, nsid, max_nsid;
4061     struct sg_pt_base * ptvp;
4062     struct sg_nvme_passthru_cmd identify_cmd;
4063     struct sg_nvme_passthru_cmd * id_cmdp = &identify_cmd;
4064     uint8_t * id_dinp = NULL;
4065     uint8_t * free_id_dinp = NULL;
4066     const uint32_t pg_sz = sg_get_page_size();
4067     uint8_t resp[16];
4068 
4069     if (op->do_raw) {
4070         if (sg_set_binary_mode(STDOUT_FILENO) < 0) {
4071             perror("sg_set_binary_mode");
4072             return SG_LIB_FILE_ERROR;
4073         }
4074     }
4075     ptvp = construct_scsi_pt_obj_with_fd(pt_fd, vb);
4076     if (NULL == ptvp) {
4077         pr2serr("%s: memory problem\n", __func__);
4078         return sg_convert_errno(ENOMEM);
4079     }
4080     memset(id_cmdp, 0, sizeof(*id_cmdp));
4081     id_cmdp->opcode = 0x6;
4082     nsid = get_pt_nvme_nsid(ptvp);
4083     id_cmdp->cdw10 = 0x1;       /* CNS=0x1 --> Identify controller */
4084     /* id_cmdp->nsid is a "don't care" when CNS=1, so leave as 0 */
4085     id_dinp = sg_memalign(pg_sz, pg_sz, &free_id_dinp, false);
4086     if (NULL == id_dinp) {
4087         pr2serr("%s: sg_memalign problem\n", __func__);
4088         return sg_convert_errno(ENOMEM);
4089     }
4090     set_scsi_pt_data_in(ptvp, id_dinp, pg_sz);
4091     set_scsi_pt_cdb(ptvp, (const uint8_t *)id_cmdp, sizeof(*id_cmdp));
4092     set_scsi_pt_sense(ptvp, resp, sizeof(resp));
4093     ret = do_scsi_pt(ptvp, -1, 0 /* timeout (def: 1 min) */, vb);
4094     if (vb > 2)
4095         pr2serr("%s: do_scsi_pt result is %d\n", __func__, ret);
4096     if (ret) {
4097         if (SCSI_PT_DO_BAD_PARAMS == ret)
4098             ret = SG_LIB_SYNTAX_ERROR;
4099         else if (SCSI_PT_DO_TIMEOUT == ret)
4100             ret = SG_LIB_CAT_TIMEOUT;
4101         else if (ret < 0)
4102             ret = sg_convert_errno(-ret);
4103         goto err_out;
4104     }
4105     max_nsid = sg_get_unaligned_le32(id_dinp + 516); /* NN */
4106     if (op->do_raw || op->do_hex) {
4107         if (op->do_only || (SG_NVME_CTL_NSID == nsid ) ||
4108             (SG_NVME_BROADCAST_NSID == nsid)) {
4109             nvme_hex_raw(id_dinp, pg_sz, op);
4110             goto fini;
4111         }
4112         goto skip1;
4113     }
4114     show_nvme_id_ctrl(id_dinp, op->device_name, op->do_long);
4115 skip1:
4116     if (op->do_only)
4117         goto fini;
4118     if (nsid > 0) {
4119         if (! (op->do_raw || (op->do_hex > 2))) {
4120             printf("  Namespace %u (deduced from device name):\n", nsid);
4121             if (nsid > max_nsid)
4122                 pr2serr("NSID from device (%u) should not exceed number of "
4123                         "namespaces (%u)\n", nsid, max_nsid);
4124         }
4125         ret = nvme_id_namespace(ptvp, nsid, id_cmdp, id_dinp, pg_sz, op);
4126         if (ret)
4127             goto err_out;
4128 
4129     } else {        /* nsid=0 so char device; loop over all namespaces */
4130         for (k = 1; k <= max_nsid; ++k) {
4131             if ((! op->do_raw) || (op->do_hex < 3))
4132                 printf("  Namespace %u (of %u):\n", k, max_nsid);
4133             ret = nvme_id_namespace(ptvp, k, id_cmdp, id_dinp, pg_sz, op);
4134             if (ret)
4135                 goto err_out;
4136             if (op->do_raw || op->do_hex)
4137                 goto fini;
4138         }
4139     }
4140 fini:
4141     ret = 0;
4142 err_out:
4143     destruct_scsi_pt_obj(ptvp);
4144     free(free_id_dinp);
4145     return ret;
4146 }
4147 #endif          /* (HAVE_NVME && (! IGNORE_NVME)) */
4148 
4149 
4150 int
main(int argc,char * argv[])4151 main(int argc, char * argv[])
4152 {
4153     bool as_json;
4154     int res, n, err;
4155     int sg_fd = -1;
4156     int ret = 0;
4157     int subvalue = 0;
4158     int inhex_len = 0;
4159     int inraw_len = 0;
4160     const char * cp;
4161     const struct svpd_values_name_t * vnp;
4162     sgj_state * jsp;
4163     sgj_opaque_p jop = NULL;
4164     struct opts_t opts SG_C_CPP_ZERO_INIT;
4165     struct opts_t * op;
4166 
4167     op = &opts;
4168     op->invoker = SG_VPD_INV_SG_INQ;
4169     op->vpd_pn = -1;
4170     op->vend_prod_num = -1;
4171     op->page_pdt = -1;
4172     op->do_block = -1;         /* use default for OS */
4173     res = parse_cmd_line(op, argc, argv);
4174     if (res)
4175         return SG_LIB_SYNTAX_ERROR;
4176     if (op->do_help) {
4177         usage_for(op);
4178         if (op->do_help > 1) {
4179             pr2serr("\n>>> Available VPD page abbreviations:\n");
4180             enumerate_vpds();
4181         }
4182         return 0;
4183     }
4184 
4185 #ifdef DEBUG
4186     pr2serr("In DEBUG mode, ");
4187     if (op->verbose_given && op->version_given) {
4188         pr2serr("but override: '-vV' given, zero verbose and continue\n");
4189         op->verbose_given = false;
4190         op->version_given = false;
4191         op->verbose = 0;
4192     } else if (! op->verbose_given) {
4193         pr2serr("set '-vv'\n");
4194         op->verbose = 2;
4195     } else
4196         pr2serr("keep verbose=%d\n", op->verbose);
4197 #else
4198     if (op->verbose_given && op->version_given)
4199         pr2serr("Not in DEBUG mode, so '-vV' has no special action\n");
4200 #endif
4201     if (op->version_given) {
4202         pr2serr("Version string: %s\n", version_str);
4203         return 0;
4204     }
4205     jsp = &op->json_st;
4206     as_json = jsp->pr_as_json;
4207     if (op->page_str) {
4208         if (op->vpd_pn >= 0) {
4209             pr2serr("Given '-p' option and another option that "
4210                     "implies a page\n");
4211             return SG_LIB_CONTRADICT;
4212         }
4213         if ('-' == op->page_str[0])
4214             op->vpd_pn = VPD_NOPE_WANT_STD_INQ;
4215         else if (isalpha((uint8_t)op->page_str[0])) {
4216             vnp = sdp_find_vpd_by_acron(op->page_str);
4217             if (NULL == vnp) {
4218 #ifdef SG_SCSI_STRINGS
4219                 if (op->opt_new)
4220                     pr2serr("abbreviation %s given to '--page=' "
4221                             "not recognized\n", op->page_str);
4222                 else
4223                     pr2serr("abbreviation %s given to '-p=' "
4224                             "not recognized\n", op->page_str);
4225 #else
4226                 pr2serr("abbreviation %s given to '--page=' "
4227                         "not recognized\n", op->page_str);
4228 #endif
4229                 pr2serr(">>> Available abbreviations:\n");
4230                 enumerate_vpds();
4231                 return SG_LIB_SYNTAX_ERROR;
4232             }
4233             // if ((1 != op->do_hex) && (0 == op->do_raw))
4234             if (0 == op->do_raw)
4235                 op->do_decode = true;
4236             op->vpd_pn = vnp->value;
4237             subvalue = vnp->subvalue;
4238             op->page_pdt = vnp->pdt;
4239         } else {
4240             cp = strchr(op->page_str, ',');
4241             if (cp && op->vend_prod) {
4242                 pr2serr("the --page=pg,vp and the --vendor=vp forms overlap, "
4243                         "choose one or the other\n");
4244                 ret = SG_LIB_SYNTAX_ERROR;
4245                 goto err_out;
4246             }
4247             op->vpd_pn = sg_get_num_nomult(op->page_str);
4248             if ((op->vpd_pn < 0) || (op->vpd_pn > 255)) {
4249                 pr2serr("Bad page code value after '-p' option\n");
4250                 printf("Available standard VPD pages:\n");
4251                 enumerate_vpds(/* 1, 1 */);
4252                 ret = SG_LIB_SYNTAX_ERROR;
4253                 goto err_out;
4254             }
4255             if (cp) {
4256                 if (isdigit((uint8_t)*(cp + 1)))
4257                     op->vend_prod_num = sg_get_num_nomult(cp + 1);
4258                 else
4259                     op->vend_prod_num = svpd_find_vp_num_by_acron(cp + 1);
4260                 if ((op->vend_prod_num < 0) || (op->vend_prod_num > 255)) {
4261                     pr2serr("Bad vendor/product acronym after comma in '-p' "
4262                             "option\n");
4263                     if (op->vend_prod_num < 0)
4264                         svpd_enumerate_vendor(-1);
4265                     ret = SG_LIB_SYNTAX_ERROR;
4266                     goto err_out;
4267                 }
4268                 subvalue = op->vend_prod_num;
4269             } else if (op->vend_prod) {
4270                 if (isdigit((uint8_t)op->vend_prod[0]))
4271                     op->vend_prod_num = sg_get_num_nomult(op->vend_prod);
4272                 else
4273                     op->vend_prod_num =
4274                         svpd_find_vp_num_by_acron(op->vend_prod);
4275                 if ((op->vend_prod_num < 0) || (op->vend_prod_num > 255)) {
4276                     pr2serr("Bad vendor/product acronym after '--vendor=' "
4277                             "option\n");
4278                     svpd_enumerate_vendor(-1);
4279                     ret = SG_LIB_SYNTAX_ERROR;
4280                     goto err_out;
4281                 }
4282                 subvalue = op->vend_prod_num;
4283             }
4284         }
4285         if (op->verbose > 3)
4286            pr2serr("'--page=' matched pn=%d [0x%x], subvalue=%d\n",
4287                    op->vpd_pn, op->vpd_pn, subvalue);
4288 #if 0
4289         else {
4290 #ifdef SG_SCSI_STRINGS
4291             if (op->opt_new) {
4292                 n = sg_get_num(op->page_str);
4293                 if ((n < 0) || (n > 255)) {
4294                     pr2serr("Bad argument to '--page=', "
4295                             "expecting 0 to 255 inclusive\n");
4296                     usage_for(op);
4297                     return SG_LIB_SYNTAX_ERROR;
4298                 }
4299                 if ((1 != op->do_hex) && (0 == op->do_raw))
4300                     op->do_decode = true;
4301             } else {
4302                 int num;
4303                 unsigned int u;
4304 
4305                 num = sscanf(op->page_str, "%x", &u);
4306                 if ((1 != num) || (u > 255)) {
4307                     pr2serr("Inappropriate value after '-o=' "
4308                             "or '-p=' option\n");
4309                     usage_for(op);
4310                     return SG_LIB_SYNTAX_ERROR;
4311                 }
4312                 n = u;
4313             }
4314 #else
4315             n = sg_get_num(op->page_str);
4316             if ((n < 0) || (n > 255)) {
4317                 pr2serr("Bad argument to '--page=', "
4318                         "expecting 0 to 255 inclusive\n");
4319                 usage_for(op);
4320                 return SG_LIB_SYNTAX_ERROR;
4321             }
4322             if ((1 != op->do_hex) && (0 == op->do_raw))
4323                 op->do_decode = true;
4324 #endif /* SG_SCSI_STRINGS */
4325             op->vpd_pn = n;
4326         }
4327 #endif
4328     } else if (op->vend_prod) {
4329         if (isdigit((uint8_t)op->vend_prod[0]))
4330             op->vend_prod_num = sg_get_num_nomult(op->vend_prod);
4331         else
4332             op->vend_prod_num = svpd_find_vp_num_by_acron(op->vend_prod);
4333         if ((op->vend_prod_num < 0) || (op->vend_prod_num > 255)) {
4334             pr2serr("Bad vendor/product acronym after '--vendor=' "
4335                     "option\n");
4336             svpd_enumerate_vendor(-1);
4337             ret = SG_LIB_SYNTAX_ERROR;
4338             goto err_out;
4339         }
4340         subvalue = op->vend_prod_num;
4341     }
4342     if (as_json)
4343         jop = sgj_start_r(MY_NAME, version_str, argc, argv, jsp);
4344 
4345     rsp_buff = sg_memalign(rsp_buff_sz, 0 /* page align */, &free_rsp_buff,
4346                            false);
4347     if (NULL == rsp_buff) {
4348         pr2serr("Unable to allocate %d bytes on heap\n", rsp_buff_sz);
4349         return sg_convert_errno(ENOMEM);
4350     }
4351     if (op->sinq_inraw_fn) {
4352         if (op->do_cmddt) {
4353             pr2serr("Don't support --cmddt with --sinq-inraw= option\n");
4354             ret = SG_LIB_CONTRADICT;
4355             goto err_out;
4356         }
4357         if ((ret = sg_f2hex_arr(op->sinq_inraw_fn, true, false, rsp_buff,
4358                                 &inraw_len, rsp_buff_sz))) {
4359             goto err_out;
4360         }
4361         if (inraw_len < 36) {
4362             pr2serr("Unable to read 36 or more bytes from %s\n",
4363                     op->sinq_inraw_fn);
4364             ret = SG_LIB_FILE_ERROR;
4365             goto err_out;
4366         }
4367         memcpy(op->std_inq_a,  rsp_buff, 36);
4368         op->std_inq_a_valid = true;
4369     }
4370     if (op->inhex_fn) {
4371         if (op->device_name) {
4372             pr2serr("Cannot have both a DEVICE and --inhex= option\n");
4373             ret = SG_LIB_CONTRADICT;
4374             goto err_out;
4375         }
4376         if (op->do_cmddt) {
4377             pr2serr("Don't support --cmddt with --inhex= option\n");
4378             ret = SG_LIB_CONTRADICT;
4379             goto err_out;
4380         }
4381         err = sg_f2hex_arr(op->inhex_fn, !!op->do_raw, false, rsp_buff,
4382                            &inhex_len, rsp_buff_sz);
4383         if (err) {
4384             if (err < 0)
4385                 err = sg_convert_errno(-err);
4386             ret = err;
4387             goto err_out;
4388         }
4389         op->do_raw = 0;         /* don't want raw on output with --inhex= */
4390         if (-1 == op->vpd_pn) {       /* may be able to deduce VPD page */
4391             if (op->page_pdt < 0)
4392                 op->page_pdt = PDT_MASK & rsp_buff[0];
4393             if ((0x2 == (0xf & rsp_buff[3])) && (rsp_buff[2] > 2)) {
4394                 if (op->verbose)
4395                     pr2serr("Guessing from --inhex= this is a standard "
4396                             "INQUIRY\n");
4397             } else if (rsp_buff[2] <= 2) {
4398                 /*
4399                  * Removable devices have the RMB bit set, which would
4400                  * present itself as vpd page 0x80 output if we're not
4401                  * careful
4402                  *
4403                  * Serial number must be right-aligned ASCII data in
4404                  * bytes 5-7; standard INQUIRY will have flags here.
4405                  */
4406                 if (rsp_buff[1] == 0x80 &&
4407                     (rsp_buff[5] < 0x20 || rsp_buff[5] > 0x80 ||
4408                      rsp_buff[6] < 0x20 || rsp_buff[6] > 0x80 ||
4409                      rsp_buff[7] < 0x20 || rsp_buff[7] > 0x80)) {
4410                     if (op->verbose)
4411                         pr2serr("Guessing from --inhex= this is a "
4412                                 "standard INQUIRY\n");
4413                 } else {
4414                     if (op->verbose)
4415                         pr2serr("Guessing from --inhex= this is VPD "
4416                                 "page 0x%x\n", rsp_buff[1]);
4417                     op->vpd_pn = rsp_buff[1];
4418                     op->do_vpd = true;
4419                     if ((1 != op->do_hex) && (0 == op->do_raw))
4420                         op->do_decode = true;
4421                 }
4422             } else {
4423                 if (op->verbose)
4424                     pr2serr("page number unclear from --inhex, hope it's a "
4425                             "standard INQUIRY\n");
4426             }
4427         } else
4428             op->do_vpd = true;
4429         if (op->do_vpd) {   /* Allow for multiple VPD pages from 'sg_vpd -a' */
4430             op->maxlen = inhex_len;
4431             ret = svpd_inhex_decode_all(op, jop);
4432             goto fini2;
4433         }
4434     } else if (0 == op->device_name) {
4435         pr2serr("No DEVICE argument given\n\n");
4436         usage_for(op);
4437         ret = SG_LIB_SYNTAX_ERROR;
4438         goto err_out;
4439     }
4440     if (VPD_NOPE_WANT_STD_INQ == op->vpd_pn)
4441         op->vpd_pn = -1;  /* now past guessing, set to normal indication */
4442 
4443     if (op->do_export) {
4444         if (op->vpd_pn != -1) {
4445             if (op->vpd_pn != VPD_DEVICE_ID &&
4446                 op->vpd_pn != VPD_UNIT_SERIAL_NUM) {
4447                 pr2serr("Option '--export' only supported for VPD pages 0x80 "
4448                         "and 0x83\n");
4449                 usage_for(op);
4450                 ret = SG_LIB_CONTRADICT;
4451                 goto err_out;
4452             }
4453             op->do_decode = true;
4454             op->do_vpd = true;
4455         }
4456     }
4457 
4458     if ((0 == op->do_cmddt) && (op->vpd_pn >= 0) && op->page_given)
4459         op->do_vpd = true;
4460 
4461     if (op->do_raw && op->do_hex) {
4462         pr2serr("Can't do hex and raw at the same time\n");
4463         usage_for(op);
4464         ret = SG_LIB_CONTRADICT;
4465         goto err_out;
4466     }
4467     if (op->do_vpd && op->do_cmddt) {
4468 #ifdef SG_SCSI_STRINGS
4469         if (op->opt_new)
4470             pr2serr("Can't use '--cmddt' with VPD pages\n");
4471         else
4472             pr2serr("Can't have both '-e' and '-c' (or '-cl')\n");
4473 #else
4474         pr2serr("Can't use '--cmddt' with VPD pages\n");
4475 #endif
4476         usage_for(op);
4477         ret = SG_LIB_CONTRADICT;
4478         goto err_out;
4479     }
4480     if (((op->do_vpd || op->do_cmddt)) && (op->vpd_pn < 0))
4481         op->vpd_pn = 0;
4482     if (op->num_pages > 1) {
4483         pr2serr("Can only fetch one page (VPD or Cmd) at a time\n");
4484         usage_for(op);
4485         ret = SG_LIB_SYNTAX_ERROR;
4486         goto err_out;
4487     }
4488     if (op->do_descriptors) {
4489         if ((op->maxlen > 0) && (op->maxlen < 60)) {
4490             pr2serr("version descriptors need INQUIRY response "
4491                     "length >= 60 bytes\n");
4492             ret = SG_LIB_SYNTAX_ERROR;
4493             goto err_out;
4494         }
4495         if (op->do_vpd || op->do_cmddt) {
4496             pr2serr("version descriptors require standard INQUIRY\n");
4497             ret = SG_LIB_SYNTAX_ERROR;
4498             goto err_out;
4499         }
4500     }
4501     if (op->num_pages && op->do_ata) {
4502         pr2serr("Can't use '-A' with an explicit decode VPD page option\n");
4503         ret = SG_LIB_CONTRADICT;
4504         goto err_out;
4505     }
4506 
4507     if (op->do_raw) {
4508         if (sg_set_binary_mode(STDOUT_FILENO) < 0) {
4509             perror("sg_set_binary_mode");
4510             ret = SG_LIB_FILE_ERROR;
4511             goto err_out;
4512         }
4513     }
4514     if (op->inhex_fn) {
4515         if (op->do_vpd) {
4516             if (op->do_decode)
4517                 ret = vpd_decode(-1, op, jop, 0);
4518             else
4519                 ret = vpd_mainly_hex(-1, op, NULL, 0);
4520             goto err_out;
4521         }
4522 #if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS) && \
4523     defined(HDIO_GET_IDENTITY)
4524         else if (op->do_ata) {
4525             prepare_ata_identify(op, inhex_len);
4526             ret = 0;
4527             goto err_out;
4528         }
4529 #endif
4530         else {
4531             op->maxlen = inhex_len;
4532             ret = std_inq_process(-1, op, jop, 0);
4533             goto err_out;
4534         }
4535     }
4536 
4537 #if defined(O_NONBLOCK) && defined(O_RDONLY)
4538     if (op->do_block >= 0) {
4539         n = O_RDONLY | (op->do_block ? 0 : O_NONBLOCK);
4540         if ((sg_fd = sg_cmds_open_flags(op->device_name, n,
4541                                         op->verbose)) < 0) {
4542             pr2serr("sg_inq: error opening file: %s: %s\n",
4543                     op->device_name, safe_strerror(-sg_fd));
4544             ret = sg_convert_errno(-sg_fd);
4545             if (ret < 0)
4546                 ret = SG_LIB_FILE_ERROR;
4547             goto err_out;
4548         }
4549 
4550     } else {
4551         if ((sg_fd = sg_cmds_open_device(op->device_name, true /* ro */,
4552                                          op->verbose)) < 0) {
4553             pr2serr("sg_inq: error opening file: %s: %s\n",
4554                     op->device_name, safe_strerror(-sg_fd));
4555             ret = sg_convert_errno(-sg_fd);
4556             if (ret < 0)
4557                 ret = SG_LIB_FILE_ERROR;
4558             goto err_out;
4559         }
4560     }
4561 #else
4562     if ((sg_fd = sg_cmds_open_device(op->device_name, true /* ro */,
4563                                      op->verbose)) < 0) {
4564         pr2serr("sg_inq: error opening file: %s: %s\n",
4565                 op->device_name, safe_strerror(-sg_fd));
4566         ret = sg_convert_errno(-sg_fd);
4567         if (ret < 0)
4568             ret = SG_LIB_FILE_ERROR;
4569         goto err_out;
4570     }
4571 #endif
4572     memset(rsp_buff, 0, rsp_buff_sz);
4573 
4574 #if (HAVE_NVME && (! IGNORE_NVME))
4575     n = check_pt_file_handle(sg_fd, op->device_name, op->verbose);
4576     if (op->verbose > 1)
4577         pr2serr("check_pt_file_handle()-->%d, page_given: %s\n", n,
4578                 (op->page_given ? "yes" : "no"));
4579     if (n > 2) {   /* NVMe char or NVMe block */
4580         op->possible_nvme = true;
4581         if (! op->page_given) {
4582             ret = do_nvme_identify_ctrl(sg_fd, op);
4583             goto fini2;
4584         }
4585     }
4586 #endif
4587 
4588 #if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS) && \
4589     defined(HDIO_GET_IDENTITY)
4590     if (op->do_ata) {
4591         res = try_ata_identify(sg_fd, op->do_hex, op->do_raw,
4592                                op->verbose);
4593         if (0 != res) {
4594             pr2serr("fetching ATA information failed on %s\n",
4595                     op->device_name);
4596             ret = SG_LIB_CAT_OTHER;
4597         } else
4598             ret = 0;
4599         goto fini3;
4600     }
4601 #endif
4602 
4603     if ((! op->do_cmddt) && (! op->do_vpd)) {
4604         /* So it's a standard INQUIRY, try ATA IDENTIFY if that fails */
4605         ret = std_inq_process(sg_fd, op, jop, 0);
4606         if (ret)
4607             goto err_out;
4608     } else if (op->do_cmddt) {
4609         if (op->vpd_pn < 0)
4610             op->vpd_pn = 0;
4611         ret = cmddt_process(sg_fd, op);
4612         if (ret)
4613             goto err_out;
4614     } else if (op->do_vpd) {
4615         if (op->do_decode) {
4616             ret = vpd_decode(sg_fd, op, jop, 0);
4617             if (ret)
4618                 goto err_out;
4619         } else {
4620             ret = vpd_mainly_hex(sg_fd, op, NULL, 0);
4621             if (ret)
4622                 goto err_out;
4623         }
4624     }
4625 
4626 #if (HAVE_NVME && (! IGNORE_NVME))
4627 fini2:
4628 #endif
4629 #if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS) && \
4630     defined(HDIO_GET_IDENTITY)
4631 fini3:
4632 #endif
4633 
4634 err_out:
4635     if (free_rsp_buff)
4636         free(free_rsp_buff);
4637     if ((0 == op->verbose) && (! op->do_export)) {
4638         if (! sg_if_can2stderr("sg_inq failed: ", ret))
4639             pr2serr("Some error occurred, try again with '-v' or '-vv' for "
4640                     "more information\n");
4641     }
4642     res = (sg_fd >= 0) ? sg_cmds_close_device(sg_fd) : 0;
4643     if (res < 0) {
4644         pr2serr("close error: %s\n", safe_strerror(-res));
4645         if (0 == ret)
4646             ret = sg_convert_errno(-res);
4647     }
4648     ret = (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
4649     if (as_json) {
4650         if (0 == op->do_hex)
4651             sgj_js2file(jsp, NULL, ret, stdout);
4652         sgj_finish(jsp);
4653     }
4654     return ret;
4655 }
4656 
4657 
4658 #if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS) && \
4659     defined(HDIO_GET_IDENTITY)
4660 /* Following code permits ATA IDENTIFY commands to be performed on
4661    ATA non "Packet Interface" devices (e.g. ATA disks).
4662    GPL-ed code borrowed from smartmontools (smartmontools.sf.net).
4663    Copyright (C) 2002-4 Bruce Allen
4664                 <[email protected]>
4665  */
4666 #ifndef ATA_IDENTIFY_DEVICE
4667 #define ATA_IDENTIFY_DEVICE 0xec
4668 #define ATA_IDENTIFY_PACKET_DEVICE 0xa1
4669 #endif
4670 #ifndef HDIO_DRIVE_CMD
4671 #define HDIO_DRIVE_CMD    0x031f
4672 #endif
4673 
4674 /* Needed parts of the ATA DRIVE IDENTIFY Structure. Those labeled
4675  * word* are NOT used.
4676  */
4677 struct ata_identify_device {
4678   unsigned short words000_009[10];
4679   uint8_t  serial_no[20];
4680   unsigned short words020_022[3];
4681   uint8_t  fw_rev[8];
4682   uint8_t  model[40];
4683   unsigned short words047_079[33];
4684   unsigned short major_rev_num;
4685   unsigned short minor_rev_num;
4686   unsigned short command_set_1;
4687   unsigned short command_set_2;
4688   unsigned short command_set_extension;
4689   unsigned short cfs_enable_1;
4690   unsigned short word086;
4691   unsigned short csf_default;
4692   unsigned short words088_255[168];
4693 };
4694 
4695 #define ATA_IDENTIFY_BUFF_SZ  sizeof(struct ata_identify_device)
4696 #define HDIO_DRIVE_CMD_OFFSET 4
4697 
4698 static int
ata_command_interface(int device,char * data,bool * atapi_flag,int verbose)4699 ata_command_interface(int device, char *data, bool * atapi_flag, int verbose)
4700 {
4701     int err;
4702     uint8_t buff[ATA_IDENTIFY_BUFF_SZ + HDIO_DRIVE_CMD_OFFSET];
4703     unsigned short get_ident[256];
4704 
4705     if (atapi_flag)
4706         *atapi_flag = false;
4707     memset(buff, 0, sizeof(buff));
4708     if (ioctl(device, HDIO_GET_IDENTITY, &get_ident) < 0) {
4709         err = errno;
4710         if (ENOTTY == err) {
4711             if (verbose > 1)
4712                 pr2serr("HDIO_GET_IDENTITY failed with ENOTTY, "
4713                         "try HDIO_DRIVE_CMD ioctl ...\n");
4714             buff[0] = ATA_IDENTIFY_DEVICE;
4715             buff[3] = 1;
4716             if (ioctl(device, HDIO_DRIVE_CMD, buff) < 0) {
4717                 if (verbose)
4718                     pr2serr("HDIO_DRIVE_CMD(ATA_IDENTIFY_DEVICE) "
4719                             "ioctl failed:\n\t%s [%d]\n",
4720                             safe_strerror(err), err);
4721                 return sg_convert_errno(err);
4722             }
4723             memcpy(data, buff + HDIO_DRIVE_CMD_OFFSET, ATA_IDENTIFY_BUFF_SZ);
4724             return 0;
4725         } else {
4726             if (verbose)
4727                 pr2serr("HDIO_GET_IDENTITY ioctl failed:\n"
4728                         "\t%s [%d]\n", safe_strerror(err), err);
4729             return sg_convert_errno(err);
4730         }
4731     } else if (verbose > 1)
4732         pr2serr("HDIO_GET_IDENTITY succeeded\n");
4733     if (0x2 == ((get_ident[0] >> 14) &0x3)) {   /* ATAPI device */
4734         if (verbose > 1)
4735             pr2serr("assume ATAPI device from HDIO_GET_IDENTITY response\n");
4736         memset(buff, 0, sizeof(buff));
4737         buff[0] = ATA_IDENTIFY_PACKET_DEVICE;
4738         buff[3] = 1;
4739         if (ioctl(device, HDIO_DRIVE_CMD, buff) < 0) {
4740             err = errno;
4741             if (verbose)
4742                 pr2serr("HDIO_DRIVE_CMD(ATA_IDENTIFY_PACKET_DEVICE) ioctl "
4743                         "failed:\n\t%s [%d]\n", safe_strerror(err), err);
4744             buff[0] = ATA_IDENTIFY_DEVICE;
4745             buff[3] = 1;
4746             if (ioctl(device, HDIO_DRIVE_CMD, buff) < 0) {
4747                 err = errno;
4748                 if (verbose)
4749                     pr2serr("HDIO_DRIVE_CMD(ATA_IDENTIFY_DEVICE) ioctl "
4750                             "failed:\n\t%s [%d]\n", safe_strerror(err), err);
4751                 return sg_convert_errno(err);
4752             }
4753         } else if (atapi_flag) {
4754             *atapi_flag = true;
4755             if (verbose > 1)
4756                 pr2serr("HDIO_DRIVE_CMD(ATA_IDENTIFY_DEVICE) succeeded\n");
4757         }
4758     } else {    /* assume non-packet device */
4759         buff[0] = ATA_IDENTIFY_DEVICE;
4760         buff[3] = 1;
4761         if (ioctl(device, HDIO_DRIVE_CMD, buff) < 0) {
4762             err = errno;
4763             if (verbose)
4764                 pr2serr("HDIO_DRIVE_CMD(ATA_IDENTIFY_DEVICE) ioctl failed:"
4765                         "\n\t%s [%d]\n", safe_strerror(err), err);
4766             return sg_convert_errno(err);
4767         } else if (verbose > 1)
4768             pr2serr("HDIO_DRIVE_CMD(ATA_IDENTIFY_DEVICE) succeeded\n");
4769     }
4770     /* if the command returns data, copy it back */
4771     memcpy(data, buff + HDIO_DRIVE_CMD_OFFSET, ATA_IDENTIFY_BUFF_SZ);
4772     return 0;
4773 }
4774 
4775 static void
show_ata_identify(const struct ata_identify_device * aidp,bool atapi,int vb)4776 show_ata_identify(const struct ata_identify_device * aidp, bool atapi,
4777                   int vb)
4778 {
4779     int res;
4780     char model[64];
4781     char serial[64];
4782     char firm[64];
4783 
4784     printf("%s device: model, serial number and firmware revision:\n",
4785            (atapi ? "ATAPI" : "ATA"));
4786     res = sg_ata_get_chars((const unsigned short *)aidp->model,
4787                            0, 20, sg_is_big_endian(), model);
4788     model[res] = '\0';
4789     res = sg_ata_get_chars((const unsigned short *)aidp->serial_no,
4790                            0, 10, sg_is_big_endian(), serial);
4791     serial[res] = '\0';
4792     res = sg_ata_get_chars((const unsigned short *)aidp->fw_rev,
4793                            0, 4, sg_is_big_endian(), firm);
4794     firm[res] = '\0';
4795     printf("  %s %s %s\n", model, serial, firm);
4796     if (vb) {
4797         if (atapi)
4798             printf("ATA IDENTIFY PACKET DEVICE response "
4799                    "(256 words):\n");
4800         else
4801             printf("ATA IDENTIFY DEVICE response (256 words):\n");
4802         dWordHex((const unsigned short *)aidp, 256, 0,
4803                  sg_is_big_endian());
4804     }
4805 }
4806 
4807 static void
prepare_ata_identify(const struct opts_t * op,int inhex_len)4808 prepare_ata_identify(const struct opts_t * op, int inhex_len)
4809 {
4810     int n = inhex_len;
4811     struct ata_identify_device ata_ident;
4812 
4813     if (n < 16) {
4814         pr2serr("%s: got only %d bytes, give up\n", __func__, n);
4815         return;
4816     } else if (n < 512)
4817         pr2serr("%s: expect 512 bytes or more, got %d, continue\n", __func__,
4818                 n);
4819     else if (n > 512)
4820         n = 512;
4821     memset(&ata_ident, 0, sizeof(ata_ident));
4822     memcpy(&ata_ident, rsp_buff, n);
4823     show_ata_identify(&ata_ident, false, op->verbose);
4824 }
4825 
4826 /* Returns 0 if successful, else errno of error */
4827 static int
try_ata_identify(int ata_fd,int do_hex,int do_raw,int verbose)4828 try_ata_identify(int ata_fd, int do_hex, int do_raw, int verbose)
4829 {
4830     bool atapi;
4831     int res;
4832     struct ata_identify_device ata_ident;
4833 
4834     memset(&ata_ident, 0, sizeof(ata_ident));
4835     res = ata_command_interface(ata_fd, (char *)&ata_ident, &atapi, verbose);
4836     if (res)
4837         return res;
4838     if ((2 == do_raw) || (3 == do_hex))
4839         dWordHex((const unsigned short *)&ata_ident, 256, -2,
4840                  sg_is_big_endian());
4841     else if (do_raw)
4842         dStrRaw((const char *)&ata_ident, 512);
4843     else {
4844         if (do_hex) {
4845             if (atapi)
4846                 printf("ATA IDENTIFY PACKET DEVICE response ");
4847             else
4848                 printf("ATA IDENTIFY DEVICE response ");
4849             if (do_hex > 1) {
4850                 printf("(512 bytes):\n");
4851                 hex2stdout((const uint8_t *)&ata_ident, 512, 0);
4852             } else {
4853                 printf("(256 words):\n");
4854                 dWordHex((const unsigned short *)&ata_ident, 256, 0,
4855                          sg_is_big_endian());
4856             }
4857         } else
4858             show_ata_identify(&ata_ident, atapi, verbose);
4859     }
4860     return 0;
4861 }
4862 #endif
4863 
4864 /* structure defined in sg_lib_data.h */
4865 extern struct sg_lib_simple_value_name_t sg_version_descriptor_arr[];
4866 
4867 
4868 static const char *
find_version_descriptor_str(int value)4869 find_version_descriptor_str(int value)
4870 {
4871     int k;
4872     const struct sg_lib_simple_value_name_t * vdp;
4873 
4874     for (k = 0; ((vdp = sg_version_descriptor_arr + k) && vdp->name); ++k) {
4875         if (value == vdp->value)
4876             return vdp->name;
4877         if (value < vdp->value)
4878             break;
4879     }
4880     return NULL;
4881 }
4882