xref: /aosp_15_r20/external/sg3_utils/src/sg_vpd.c (revision 44704f698541f6367e81f991ef8bb54ccbf3fc18)
1*44704f69SBart Van Assche /*
2*44704f69SBart Van Assche  * Copyright (c) 2006-2022 Douglas Gilbert.
3*44704f69SBart Van Assche  * All rights reserved.
4*44704f69SBart Van Assche  * Use of this source code is governed by a BSD-style
5*44704f69SBart Van Assche  * license that can be found in the BSD_LICENSE file.
6*44704f69SBart Van Assche  *
7*44704f69SBart Van Assche  * SPDX-License-Identifier: BSD-2-Clause
8*44704f69SBart Van Assche  */
9*44704f69SBart Van Assche 
10*44704f69SBart Van Assche #include <unistd.h>
11*44704f69SBart Van Assche #include <fcntl.h>
12*44704f69SBart Van Assche #include <stdio.h>
13*44704f69SBart Van Assche #include <stdlib.h>
14*44704f69SBart Van Assche #include <stdarg.h>
15*44704f69SBart Van Assche #include <stdbool.h>
16*44704f69SBart Van Assche #include <string.h>
17*44704f69SBart Van Assche #include <ctype.h>
18*44704f69SBart Van Assche #include <getopt.h>
19*44704f69SBart Van Assche #define __STDC_FORMAT_MACROS 1
20*44704f69SBart Van Assche #include <inttypes.h>
21*44704f69SBart Van Assche #include <errno.h>
22*44704f69SBart Van Assche #include <sys/types.h>
23*44704f69SBart Van Assche #include <sys/stat.h>
24*44704f69SBart Van Assche 
25*44704f69SBart Van Assche #ifdef HAVE_CONFIG_H
26*44704f69SBart Van Assche #include "config.h"
27*44704f69SBart Van Assche #endif
28*44704f69SBart Van Assche 
29*44704f69SBart Van Assche #include "sg_lib.h"
30*44704f69SBart Van Assche #include "sg_cmds_basic.h"
31*44704f69SBart Van Assche #include "sg_unaligned.h"
32*44704f69SBart Van Assche #include "sg_pr2serr.h"
33*44704f69SBart Van Assche 
34*44704f69SBart Van Assche #include "sg_vpd_common.h"      /* shared with sg_inq */
35*44704f69SBart Van Assche 
36*44704f69SBart Van Assche /* This utility program was originally written for the Linux OS SCSI subsystem.
37*44704f69SBart Van Assche 
38*44704f69SBart Van Assche    This program fetches Vital Product Data (VPD) pages from the given
39*44704f69SBart Van Assche    device and outputs it as directed. VPD pages are obtained via a
40*44704f69SBart Van Assche    SCSI INQUIRY command. Most of the data in this program is obtained
41*44704f69SBart Van Assche    from the SCSI SPC-4 document at https://www.t10.org .
42*44704f69SBart Van Assche 
43*44704f69SBart Van Assche */
44*44704f69SBart Van Assche 
45*44704f69SBart Van Assche static const char * version_str = "1.83 20220915";  /* spc6r06 + sbc5r03 */
46*44704f69SBart Van Assche 
47*44704f69SBart Van Assche #define MY_NAME "sg_vpd"
48*44704f69SBart Van Assche 
49*44704f69SBart Van Assche /* Device identification VPD page associations */
50*44704f69SBart Van Assche #define VPD_ASSOC_LU 0
51*44704f69SBart Van Assche #define VPD_ASSOC_TPORT 1
52*44704f69SBart Van Assche #define VPD_ASSOC_TDEVICE 2
53*44704f69SBart Van Assche 
54*44704f69SBart Van Assche /* values for selection one or more associations (2**vpd_assoc),
55*44704f69SBart Van Assche    except _AS_IS */
56*44704f69SBart Van Assche #define VPD_DI_SEL_LU 1
57*44704f69SBart Van Assche #define VPD_DI_SEL_TPORT 2
58*44704f69SBart Van Assche #define VPD_DI_SEL_TARGET 4
59*44704f69SBart Van Assche #define VPD_DI_SEL_AS_IS 32
60*44704f69SBart Van Assche 
61*44704f69SBart Van Assche #define DEF_ALLOC_LEN 252
62*44704f69SBart Van Assche #define MIN_MAXLEN 16
63*44704f69SBart Van Assche #define MX_ALLOC_LEN (0xc000 + 0x80)
64*44704f69SBart Van Assche #define VPD_ATA_INFO_LEN  572
65*44704f69SBart Van Assche 
66*44704f69SBart Van Assche #define SENSE_BUFF_LEN  64       /* Arbitrary, could be larger */
67*44704f69SBart Van Assche #define INQUIRY_CMD     0x12
68*44704f69SBart Van Assche #define INQUIRY_CMDLEN  6
69*44704f69SBart Van Assche #define DEF_PT_TIMEOUT  60       /* 60 seconds */
70*44704f69SBart Van Assche 
71*44704f69SBart Van Assche 
72*44704f69SBart Van Assche uint8_t * rsp_buff;
73*44704f69SBart Van Assche 
74*44704f69SBart Van Assche static int svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
75*44704f69SBart Van Assche                            int subvalue, int off, const char * prefix);
76*44704f69SBart Van Assche static int svpd_unable_to_decode(int sg_fd, struct opts_t * op, int subvalue,
77*44704f69SBart Van Assche                                  int off);
78*44704f69SBart Van Assche 
79*44704f69SBart Van Assche static int filter_dev_ids(const char * print_if_found, int num_leading,
80*44704f69SBart Van Assche                           uint8_t * buff, int len, int m_assoc,
81*44704f69SBart Van Assche                           struct opts_t * op, sgj_opaque_p jop);
82*44704f69SBart Van Assche 
83*44704f69SBart Van Assche static const int rsp_buff_sz = MX_ALLOC_LEN + 2;
84*44704f69SBart Van Assche 
85*44704f69SBart Van Assche static uint8_t * free_rsp_buff;
86*44704f69SBart Van Assche 
87*44704f69SBart Van Assche static struct option long_options[] = {
88*44704f69SBart Van Assche         {"all", no_argument, 0, 'a'},
89*44704f69SBart Van Assche         {"enumerate", no_argument, 0, 'e'},
90*44704f69SBart Van Assche         {"examine", no_argument, 0, 'E'},
91*44704f69SBart Van Assche         {"force", no_argument, 0, 'f'},
92*44704f69SBart Van Assche         {"help", no_argument, 0, 'h'},
93*44704f69SBart Van Assche         {"hex", no_argument, 0, 'H'},
94*44704f69SBart Van Assche         {"ident", no_argument, 0, 'i'},
95*44704f69SBart Van Assche         {"inhex", required_argument, 0, 'I'},
96*44704f69SBart Van Assche         {"json", optional_argument, 0, 'j'},
97*44704f69SBart Van Assche         {"long", no_argument, 0, 'l'},
98*44704f69SBart Van Assche         {"maxlen", required_argument, 0, 'm'},
99*44704f69SBart Van Assche         {"page", required_argument, 0, 'p'},
100*44704f69SBart Van Assche         {"quiet", no_argument, 0, 'q'},
101*44704f69SBart Van Assche         {"raw", no_argument, 0, 'r'},
102*44704f69SBart Van Assche         {"sinq_inraw", required_argument, 0, 'Q'},
103*44704f69SBart Van Assche         {"sinq-inraw", required_argument, 0, 'Q'},
104*44704f69SBart Van Assche         {"vendor", required_argument, 0, 'M'},
105*44704f69SBart Van Assche         {"verbose", no_argument, 0, 'v'},
106*44704f69SBart Van Assche         {"version", no_argument, 0, 'V'},
107*44704f69SBart Van Assche         {0, 0, 0, 0},
108*44704f69SBart Van Assche };
109*44704f69SBart Van Assche 
110*44704f69SBart Van Assche 
111*44704f69SBart Van Assche /* arranged in alphabetical order by acronym */
112*44704f69SBart Van Assche static struct svpd_values_name_t standard_vpd_pg[] = {
113*44704f69SBart Van Assche     {VPD_AUTOMATION_DEV_SN, 0, 1, "adsn", "Automation device serial "
114*44704f69SBart Van Assche      "number (SSC)"},
115*44704f69SBart Van Assche     {VPD_ATA_INFO, 0, -1, "ai", "ATA information (SAT)"},
116*44704f69SBart Van Assche     {VPD_ASCII_OP_DEF, 0, -1, "aod",
117*44704f69SBart Van Assche      "ASCII implemented operating definition (obsolete)"},
118*44704f69SBart Van Assche     {VPD_BLOCK_DEV_CHARS, 0, 0, "bdc", "Block device characteristics "
119*44704f69SBart Van Assche      "(SBC)"},
120*44704f69SBart Van Assche     {VPD_BLOCK_DEV_C_EXTENS, 0, 0, "bdce", "Block device characteristics "
121*44704f69SBart Van Assche      "extension (SBC)"},
122*44704f69SBart Van Assche     {VPD_BLOCK_LIMITS, 0, 0, "bl", "Block limits (SBC)"},
123*44704f69SBart Van Assche     {VPD_BLOCK_LIMITS_EXT, 0, 0, "ble", "Block limits extension (SBC)"},
124*44704f69SBart Van Assche     {VPD_CFA_PROFILE_INFO, 0, 0, "cfa", "CFA profile information"},
125*44704f69SBart Van Assche     {VPD_CON_POS_RANGE, 0, 0, "cpr", "Concurrent positioning ranges"},
126*44704f69SBart Van Assche     {VPD_DEVICE_CONSTITUENTS, 0, -1, "dc", "Device constituents"},
127*44704f69SBart Van Assche     {VPD_DEVICE_ID, 0, -1, "di", "Device identification"},
128*44704f69SBart Van Assche     {VPD_DEVICE_ID, VPD_DI_SEL_AS_IS, -1, "di_asis", "Like 'di' "
129*44704f69SBart Van Assche      "but designators ordered as found"},
130*44704f69SBart Van Assche     {VPD_DEVICE_ID, VPD_DI_SEL_LU, -1, "di_lu", "Device identification, "
131*44704f69SBart Van Assche      "lu only"},
132*44704f69SBart Van Assche     {VPD_DEVICE_ID, VPD_DI_SEL_TPORT, -1, "di_port", "Device "
133*44704f69SBart Van Assche      "identification, target port only"},
134*44704f69SBart Van Assche     {VPD_DEVICE_ID, VPD_DI_SEL_TARGET, -1, "di_target", "Device "
135*44704f69SBart Van Assche      "identification, target device only"},
136*44704f69SBart Van Assche     {VPD_DTDE_ADDRESS, 0, 1, "dtde",
137*44704f69SBart Van Assche      "Data transfer device element address (SSC)"},
138*44704f69SBart Van Assche     {VPD_EXT_INQ, 0, -1, "ei", "Extended inquiry data"},
139*44704f69SBart Van Assche     {VPD_FORMAT_PRESETS, 0, 0, "fp", "Format presets"},
140*44704f69SBart Van Assche     {VPD_IMP_OP_DEF, 0, -1, "iod",
141*44704f69SBart Van Assche      "Implemented operating definition (obsolete)"},
142*44704f69SBart Van Assche     {VPD_LB_PROTECTION, 0, 0, "lbpro", "Logical block protection (SSC)"},
143*44704f69SBart Van Assche     {VPD_LB_PROVISIONING, 0, 0, "lbpv", "Logical block provisioning (SBC)"},
144*44704f69SBart Van Assche     {VPD_MAN_ASS_SN, 0, 1, "mas", "Manufacturer assigned serial number (SSC)"},
145*44704f69SBart Van Assche     {VPD_MAN_ASS_SN, 0, 0x12, "masa",
146*44704f69SBart Van Assche      "Manufacturer assigned serial number (ADC)"},
147*44704f69SBart Van Assche     {VPD_MAN_NET_ADDR, 0, -1, "mna", "Management network addresses"},
148*44704f69SBart Van Assche     {VPD_MODE_PG_POLICY, 0, -1, "mpp", "Mode page policy"},
149*44704f69SBart Van Assche     {VPD_OSD_INFO, 0, 0x11, "oi", "OSD information"},
150*44704f69SBart Van Assche     {VPD_POWER_CONDITION, 0, -1, "pc", "Power condition"},/* "po" in sg_inq */
151*44704f69SBart Van Assche     {VPD_POWER_CONSUMPTION, 0, -1, "psm", "Power consumption"},
152*44704f69SBart Van Assche     {VPD_PROTO_LU, 0, -1, "pslu", "Protocol-specific logical unit "
153*44704f69SBart Van Assche      "information"},
154*44704f69SBart Van Assche     {VPD_PROTO_PORT, 0, -1, "pspo", "Protocol-specific port information"},
155*44704f69SBart Van Assche     {VPD_REFERRALS, 0, 0, "ref", "Referrals (SBC)"},
156*44704f69SBart Van Assche     {VPD_SA_DEV_CAP, 0, 1, "sad",
157*44704f69SBart Van Assche      "Sequential access device capabilities (SSC)"},
158*44704f69SBart Van Assche     {VPD_SUP_BLOCK_LENS, 0, 0, "sbl", "Supported block lengths and "
159*44704f69SBart Van Assche      "protection types (SBC)"},
160*44704f69SBart Van Assche     {VPD_SCSI_FEATURE_SETS, 0, -1, "sfs", "SCSI feature sets"},
161*44704f69SBart Van Assche     {VPD_SOFTW_INF_ID, 0, -1, "sii", "Software interface identification"},
162*44704f69SBart Van Assche     {VPD_NOPE_WANT_STD_INQ, 0, -1, "sinq", "Standard inquiry data format"},
163*44704f69SBart Van Assche     {VPD_UNIT_SERIAL_NUM, 0, -1, "sn", "Unit serial number"},
164*44704f69SBart Van Assche     {VPD_SCSI_PORTS, 0, -1, "sp", "SCSI ports"},
165*44704f69SBart Van Assche     {VPD_SECURITY_TOKEN, 0, 0x11, "st", "Security token (OSD)"},
166*44704f69SBart Van Assche     {VPD_SUPPORTED_VPDS, 0, -1, "sv", "Supported VPD pages"},
167*44704f69SBart Van Assche     {VPD_TA_SUPPORTED, 0, 1, "tas", "TapeAlert supported flags (SSC)"},
168*44704f69SBart Van Assche     {VPD_3PARTY_COPY, 0, -1, "tpc", "Third party copy"},
169*44704f69SBart Van Assche     {VPD_ZBC_DEV_CHARS, 0, -1, "zbdch", "Zoned block device characteristics"},
170*44704f69SBart Van Assche         /* Use pdt of -1 since this page both for pdt=0 and pdt=0x14 */
171*44704f69SBart Van Assche     {0, 0, 0, NULL, NULL},
172*44704f69SBart Van Assche };
173*44704f69SBart Van Assche 
174*44704f69SBart Van Assche 
175*44704f69SBart Van Assche static void
usage()176*44704f69SBart Van Assche usage()
177*44704f69SBart Van Assche {
178*44704f69SBart Van Assche     pr2serr("Usage: sg_vpd  [--all] [--enumerate] [--examine] [--force] "
179*44704f69SBart Van Assche             "[--help] [--hex]\n"
180*44704f69SBart Van Assche             "               [--ident] [--inhex=FN] [--long] [--maxlen=LEN] "
181*44704f69SBart Van Assche             "[--page=PG]\n"
182*44704f69SBart Van Assche             "               [--quiet] [--raw] [--sinq_inraw=RFN] "
183*44704f69SBart Van Assche             "[--vendor=VP] [--verbose]\n"
184*44704f69SBart Van Assche             "               [--version] DEVICE\n");
185*44704f69SBart Van Assche     pr2serr("  where:\n"
186*44704f69SBart Van Assche             "    --all|-a        output all pages listed in the supported "
187*44704f69SBart Van Assche             "pages VPD\n"
188*44704f69SBart Van Assche             "                    page\n"
189*44704f69SBart Van Assche             "    --enumerate|-e    enumerate known VPD pages names (ignore "
190*44704f69SBart Van Assche             "DEVICE),\n"
191*44704f69SBart Van Assche             "                      can be used with --page=num to search\n"
192*44704f69SBart Van Assche             "    --examine|-E    starting at 0x80 scan pages code to 0xff\n"
193*44704f69SBart Van Assche             "    --force|-f      skip VPD page 0 (supported VPD pages) "
194*44704f69SBart Van Assche             "checking\n"
195*44704f69SBart Van Assche             "    --help|-h       output this usage message then exit\n"
196*44704f69SBart Van Assche             "    --hex|-H        output page in ASCII hexadecimal\n"
197*44704f69SBart Van Assche             "    --ident|-i      output device identification VPD page, "
198*44704f69SBart Van Assche             "twice for\n"
199*44704f69SBart Van Assche             "                    short logical unit designator (equiv: "
200*44704f69SBart Van Assche             "'-qp di_lu')\n"
201*44704f69SBart Van Assche             "    --inhex=FN|-I FN    read ASCII hex from file FN instead of "
202*44704f69SBart Van Assche             "DEVICE;\n"
203*44704f69SBart Van Assche             "                        if used with --raw then read binary "
204*44704f69SBart Van Assche             "from FN\n"
205*44704f69SBart Van Assche             "    --json[=JO]|-j[JO]    output in JSON instead of human "
206*44704f69SBart Van Assche             "readable text.\n"
207*44704f69SBart Van Assche             "                          Use --json=? for JSON help\n"
208*44704f69SBart Van Assche             "    --long|-l       perform extra decoding\n"
209*44704f69SBart Van Assche             "    --maxlen=LEN|-m LEN    max response length (allocation "
210*44704f69SBart Van Assche             "length in cdb)\n"
211*44704f69SBart Van Assche             "                           (def: 0 -> 252 bytes)\n"
212*44704f69SBart Van Assche             "    --page=PG|-p PG    fetch VPD page where PG is an "
213*44704f69SBart Van Assche             "acronym, or a decimal\n"
214*44704f69SBart Van Assche             "                       number unless hex indicator "
215*44704f69SBart Van Assche             "is given (e.g. '0x83');\n"
216*44704f69SBart Van Assche             "                       can also take PG,VP as an "
217*44704f69SBart Van Assche             "operand\n"
218*44704f69SBart Van Assche             "    --quiet|-q      suppress some output when decoding\n"
219*44704f69SBart Van Assche             "    --raw|-r        output page in binary; if --inhex=FN is "
220*44704f69SBart Van Assche             "also\n"
221*44704f69SBart Van Assche             "                    given, FN is in binary (else FN is in "
222*44704f69SBart Van Assche             "hex)\n"
223*44704f69SBart Van Assche             "    --sinq_inraw=RFN|-Q RFN    read raw (binary) standard "
224*44704f69SBart Van Assche             "INQUIRY\n"
225*44704f69SBart Van Assche             "                               response from the RFN filename\n"
226*44704f69SBart Van Assche             "    --vendor=VP|-M VP    vendor/product abbreviation [or "
227*44704f69SBart Van Assche             "number]\n"
228*44704f69SBart Van Assche             "    --verbose|-v    increase verbosity\n"
229*44704f69SBart Van Assche             "    --version|-V    print version string and exit\n\n"
230*44704f69SBart Van Assche             "Fetch Vital Product Data (VPD) page using SCSI INQUIRY or "
231*44704f69SBart Van Assche             "decodes VPD\npage response held in file FN. To list available "
232*44704f69SBart Van Assche             "pages use '-e'. Also\n'-p -1' or '-p sinq' yields the standard "
233*44704f69SBart Van Assche             "INQUIRY response.\n");
234*44704f69SBart Van Assche }
235*44704f69SBart Van Assche 
236*44704f69SBart Van Assche static const struct svpd_values_name_t *
sdp_get_vpd_detail(int page_num,int subvalue,int pdt)237*44704f69SBart Van Assche sdp_get_vpd_detail(int page_num, int subvalue, int pdt)
238*44704f69SBart Van Assche {
239*44704f69SBart Van Assche     const struct svpd_values_name_t * vnp;
240*44704f69SBart Van Assche     int sv, ty;
241*44704f69SBart Van Assche 
242*44704f69SBart Van Assche     sv = (subvalue < 0) ? 1 : 0;
243*44704f69SBart Van Assche     ty = (pdt < 0) ? 1 : 0;
244*44704f69SBart Van Assche     for (vnp = standard_vpd_pg; vnp->acron; ++vnp) {
245*44704f69SBart Van Assche         if ((page_num == vnp->value) &&
246*44704f69SBart Van Assche             (sv || (subvalue == vnp->subvalue)) &&
247*44704f69SBart Van Assche             (ty || (pdt == vnp->pdt)))
248*44704f69SBart Van Assche             return vnp;
249*44704f69SBart Van Assche     }
250*44704f69SBart Van Assche     if (! ty)
251*44704f69SBart Van Assche         return sdp_get_vpd_detail(page_num, subvalue, -1);
252*44704f69SBart Van Assche     if (! sv)
253*44704f69SBart Van Assche         return sdp_get_vpd_detail(page_num, -1, -1);
254*44704f69SBart Van Assche     return NULL;
255*44704f69SBart Van Assche }
256*44704f69SBart Van Assche 
257*44704f69SBart Van Assche static const struct svpd_values_name_t *
sdp_find_vpd_by_acron(const char * ap)258*44704f69SBart Van Assche sdp_find_vpd_by_acron(const char * ap)
259*44704f69SBart Van Assche {
260*44704f69SBart Van Assche     const struct svpd_values_name_t * vnp;
261*44704f69SBart Van Assche 
262*44704f69SBart Van Assche     for (vnp = standard_vpd_pg; vnp->acron; ++vnp) {
263*44704f69SBart Van Assche         if (0 == strcmp(vnp->acron, ap))
264*44704f69SBart Van Assche             return vnp;
265*44704f69SBart Van Assche     }
266*44704f69SBart Van Assche     return NULL;
267*44704f69SBart Van Assche }
268*44704f69SBart Van Assche 
269*44704f69SBart Van Assche static void
enumerate_vpds(int standard,int vendor)270*44704f69SBart Van Assche enumerate_vpds(int standard, int vendor)
271*44704f69SBart Van Assche {
272*44704f69SBart Van Assche     const struct svpd_values_name_t * vnp;
273*44704f69SBart Van Assche 
274*44704f69SBart Van Assche     if (standard) {
275*44704f69SBart Van Assche         for (vnp = standard_vpd_pg; vnp->acron; ++vnp) {
276*44704f69SBart Van Assche             if (vnp->name) {
277*44704f69SBart Van Assche                 if (vnp->value < 0)
278*44704f69SBart Van Assche                     printf("  %-10s -1        %s\n", vnp->acron, vnp->name);
279*44704f69SBart Van Assche                 else
280*44704f69SBart Van Assche                     printf("  %-10s 0x%02x      %s\n", vnp->acron, vnp->value,
281*44704f69SBart Van Assche                        vnp->name);
282*44704f69SBart Van Assche             }
283*44704f69SBart Van Assche         }
284*44704f69SBart Van Assche     }
285*44704f69SBart Van Assche     if (vendor)
286*44704f69SBart Van Assche         svpd_enumerate_vendor(-2);
287*44704f69SBart Van Assche }
288*44704f69SBart Van Assche 
289*44704f69SBart Van Assche static int
count_standard_vpds(int vpd_pn)290*44704f69SBart Van Assche count_standard_vpds(int vpd_pn)
291*44704f69SBart Van Assche {
292*44704f69SBart Van Assche     const struct svpd_values_name_t * vnp;
293*44704f69SBart Van Assche     int matches = 0;
294*44704f69SBart Van Assche 
295*44704f69SBart Van Assche     for (vnp = standard_vpd_pg; vnp->acron; ++vnp) {
296*44704f69SBart Van Assche         if ((vpd_pn == vnp->value) && vnp->name) {
297*44704f69SBart Van Assche             if (0 == matches)
298*44704f69SBart Van Assche                 printf("Matching standard VPD pages:\n");
299*44704f69SBart Van Assche             ++matches;
300*44704f69SBart Van Assche             if (vnp->value < 0)
301*44704f69SBart Van Assche                 printf("  %-10s -1        %s\n", vnp->acron, vnp->name);
302*44704f69SBart Van Assche             else
303*44704f69SBart Van Assche                 printf("  %-10s 0x%02x      %s\n", vnp->acron, vnp->value,
304*44704f69SBart Van Assche                    vnp->name);
305*44704f69SBart Van Assche         }
306*44704f69SBart Van Assche     }
307*44704f69SBart Van Assche     return matches;
308*44704f69SBart Van Assche }
309*44704f69SBart Van Assche 
310*44704f69SBart Van Assche static void
dStrRaw(const uint8_t * str,int len)311*44704f69SBart Van Assche dStrRaw(const uint8_t * str, int len)
312*44704f69SBart Van Assche {
313*44704f69SBart Van Assche     int k;
314*44704f69SBart Van Assche 
315*44704f69SBart Van Assche     for (k = 0; k < len; ++k)
316*44704f69SBart Van Assche         printf("%c", str[k]);
317*44704f69SBart Van Assche }
318*44704f69SBart Van Assche 
319*44704f69SBart Van Assche /* Assume index is less than 16 */
320*44704f69SBart Van Assche static const char * sg_ansi_version_arr[16] =
321*44704f69SBart Van Assche {
322*44704f69SBart Van Assche     "no conformance claimed",
323*44704f69SBart Van Assche     "SCSI-1",           /* obsolete, ANSI X3.131-1986 */
324*44704f69SBart Van Assche     "SCSI-2",           /* obsolete, ANSI X3.131-1994 */
325*44704f69SBart Van Assche     "SPC",              /* withdrawn, ANSI INCITS 301-1997 */
326*44704f69SBart Van Assche     "SPC-2",            /* ANSI INCITS 351-2001, ISO/IEC 14776-452 */
327*44704f69SBart Van Assche     "SPC-3",            /* ANSI INCITS 408-2005, ISO/IEC 14776-453 */
328*44704f69SBart Van Assche     "SPC-4",            /* ANSI INCITS 513-2015 */
329*44704f69SBart Van Assche     "SPC-5",            /* ANSI INCITS 502-2020 */
330*44704f69SBart Van Assche     "ecma=1, [8h]",
331*44704f69SBart Van Assche     "ecma=1, [9h]",
332*44704f69SBart Van Assche     "ecma=1, [Ah]",
333*44704f69SBart Van Assche     "ecma=1, [Bh]",
334*44704f69SBart Van Assche     "reserved [Ch]",
335*44704f69SBart Van Assche     "reserved [Dh]",
336*44704f69SBart Van Assche     "reserved [Eh]",
337*44704f69SBart Van Assche     "reserved [Fh]",
338*44704f69SBart Van Assche };
339*44704f69SBart Van Assche 
340*44704f69SBart Van Assche static void
std_inq_decode(uint8_t * b,int len,struct opts_t * op,sgj_opaque_p jop)341*44704f69SBart Van Assche std_inq_decode(uint8_t * b, int len, struct opts_t * op, sgj_opaque_p jop)
342*44704f69SBart Van Assche {
343*44704f69SBart Van Assche     uint8_t ver;
344*44704f69SBart Van Assche     int pqual, pdt, hp, j, n;
345*44704f69SBart Van Assche     sgj_state * jsp = &op->json_st;
346*44704f69SBart Van Assche     const char * cp;
347*44704f69SBart Van Assche     char c[256];
348*44704f69SBart Van Assche     static const int clen = sizeof(c);
349*44704f69SBart Van Assche     static const char * np = "Standard INQUIRY data format:";
350*44704f69SBart Van Assche 
351*44704f69SBart Van Assche     if (len < 4) {
352*44704f69SBart Van Assche         pr2serr("%s: len [%d] too short\n", __func__, len);
353*44704f69SBart Van Assche         return;
354*44704f69SBart Van Assche     }
355*44704f69SBart Van Assche     pqual = (b[0] & 0xe0) >> 5;
356*44704f69SBart Van Assche     pdt = b[0] & PDT_MASK;
357*44704f69SBart Van Assche     hp = (b[1] >> 4) & 0x3;
358*44704f69SBart Van Assche     ver = b[2];
359*44704f69SBart Van Assche     sgj_pr_hr(jsp, "%s", np);
360*44704f69SBart Van Assche     if (0 == pqual)
361*44704f69SBart Van Assche         sgj_pr_hr(jsp, "\n");
362*44704f69SBart Van Assche     else {
363*44704f69SBart Van Assche         cp = pqual_str(pqual);
364*44704f69SBart Van Assche 
365*44704f69SBart Van Assche         if (pqual < 3)
366*44704f69SBart Van Assche             sgj_pr_hr(jsp, " [PQ indicates %s]\n", cp);
367*44704f69SBart Van Assche         else
368*44704f69SBart Van Assche             sgj_pr_hr(jsp, " [PQ indicates %s [0x%x] ]\n", cp, pqual);
369*44704f69SBart Van Assche     }
370*44704f69SBart Van Assche     sgj_pr_hr(jsp, "  PQual=%d  PDT=%d  RMB=%d  LU_CONG=%d  hot_pluggable="
371*44704f69SBart Van Assche               "%d  version=0x%02x  [%s]\n", pqual, pdt, !!(b[1] & 0x80),
372*44704f69SBart Van Assche               !!(b[1] & 0x40), hp, ver, sg_ansi_version_arr[ver & 0xf]);
373*44704f69SBart Van Assche     sgj_pr_hr(jsp, "  [AERC=%d]  [TrmTsk=%d]  NormACA=%d  HiSUP=%d "
374*44704f69SBart Van Assche            " Resp_data_format=%d\n",
375*44704f69SBart Van Assche            !!(b[3] & 0x80), !!(b[3] & 0x40), !!(b[3] & 0x20),
376*44704f69SBart Van Assche            !!(b[3] & 0x10), b[3] & 0x0f);
377*44704f69SBart Van Assche     if (len < 5)
378*44704f69SBart Van Assche         goto skip1;
379*44704f69SBart Van Assche     j = b[4] + 5;
380*44704f69SBart Van Assche     if (op->verbose > 2)
381*44704f69SBart Van Assche         pr2serr(">> requested %d bytes, %d bytes available\n", len, j);
382*44704f69SBart Van Assche     sgj_pr_hr(jsp, "  SCCS=%d  ACC=%d  TPGS=%d  3PC=%d  Protect=%d  "
383*44704f69SBart Van Assche               "[BQue=%d]\n", !!(b[5] & 0x80), !!(b[5] & 0x40),
384*44704f69SBart Van Assche               ((b[5] & 0x30) >> 4), !!(b[5] & 0x08), !!(b[5] & 0x01),
385*44704f69SBart Van Assche               !!(b[6] & 0x80));
386*44704f69SBart Van Assche     n = 0;
387*44704f69SBart Van Assche     n += sg_scnpr(c + n, clen - n, "EncServ=%d  ", !!(b[6] & 0x40));
388*44704f69SBart Van Assche     if (b[6] & 0x10)
389*44704f69SBart Van Assche         n += sg_scnpr(c + n, clen - n, "MultiP=1 (VS=%d)  ", !!(b[6] & 0x20));
390*44704f69SBart Van Assche     else
391*44704f69SBart Van Assche         n += sg_scnpr(c + n, clen - n, "MultiP=0  ");
392*44704f69SBart Van Assche     n += sg_scnpr(c + n, clen - n, "[MChngr=%d]  [ACKREQQ=%d]  Addr16=%d",
393*44704f69SBart Van Assche                   !!(b[6] & 0x08), !!(b[6] & 0x04), !!(b[6] & 0x01));
394*44704f69SBart Van Assche     sgj_pr_hr(jsp, "  %s\n", c);
395*44704f69SBart Van Assche     sgj_pr_hr(jsp, "  [RelAdr=%d]  WBus16=%d  Sync=%d  [Linked=%d]  "
396*44704f69SBart Van Assche               "[TranDis=%d]  CmdQue=%d\n", !!(b[7] & 0x80), !!(b[7] & 0x20),
397*44704f69SBart Van Assche               !!(b[7] & 0x10), !!(b[7] & 0x08), !!(b[7] & 0x04),
398*44704f69SBart Van Assche               !!(b[7] & 0x02));
399*44704f69SBart Van Assche     if (len < 36)
400*44704f69SBart Van Assche         goto skip1;
401*44704f69SBart Van Assche     sgj_pr_hr(jsp, "  %s: %.8s\n", t10_vendor_id_hr, b + 8);
402*44704f69SBart Van Assche     sgj_pr_hr(jsp, "  %s: %.16s\n", product_id_hr, b + 16);
403*44704f69SBart Van Assche     sgj_pr_hr(jsp, "  %s: %.4s\n", product_rev_lev_hr, b + 32);
404*44704f69SBart Van Assche skip1:
405*44704f69SBart Van Assche     if (! jsp->pr_as_json || (len < 8))
406*44704f69SBart Van Assche         return;
407*44704f69SBart Van Assche     std_inq_decode_js(b, len, op, jop);
408*44704f69SBart Van Assche }
409*44704f69SBart Van Assche 
410*44704f69SBart Van Assche /* VPD_DEVICE_ID 0x83 ["di, di_asis, di_lu, di_port, di_target"] */
411*44704f69SBart Van Assche static void
device_id_vpd_variants(uint8_t * buff,int len,int subvalue,struct opts_t * op,sgj_opaque_p jap)412*44704f69SBart Van Assche device_id_vpd_variants(uint8_t * buff, int len, int subvalue,
413*44704f69SBart Van Assche                        struct opts_t * op, sgj_opaque_p jap)
414*44704f69SBart Van Assche {
415*44704f69SBart Van Assche     int m_a, blen;
416*44704f69SBart Van Assche     uint8_t * b;
417*44704f69SBart Van Assche 
418*44704f69SBart Van Assche     if (len < 4) {
419*44704f69SBart Van Assche         pr2serr("Device identification VPD page length too short=%d\n", len);
420*44704f69SBart Van Assche         return;
421*44704f69SBart Van Assche     }
422*44704f69SBart Van Assche     blen = len - 4;
423*44704f69SBart Van Assche     b = buff + 4;
424*44704f69SBart Van Assche     m_a = -1;
425*44704f69SBart Van Assche     if (0 == subvalue) {
426*44704f69SBart Van Assche         filter_dev_ids(sg_get_desig_assoc_str(VPD_ASSOC_LU), 0, b, blen,
427*44704f69SBart Van Assche                        VPD_ASSOC_LU, op, jap);
428*44704f69SBart Van Assche         filter_dev_ids(sg_get_desig_assoc_str(VPD_ASSOC_TPORT), 0, b, blen,
429*44704f69SBart Van Assche                        VPD_ASSOC_TPORT, op, jap);
430*44704f69SBart Van Assche         filter_dev_ids(sg_get_desig_assoc_str(VPD_ASSOC_TDEVICE), 0, b, blen,
431*44704f69SBart Van Assche                        VPD_ASSOC_TDEVICE, op, jap);
432*44704f69SBart Van Assche     } else if (VPD_DI_SEL_AS_IS == subvalue)
433*44704f69SBart Van Assche         filter_dev_ids(NULL, 0, b, blen, m_a, op, jap);
434*44704f69SBart Van Assche     else {
435*44704f69SBart Van Assche         if (VPD_DI_SEL_LU & subvalue)
436*44704f69SBart Van Assche             filter_dev_ids(sg_get_desig_assoc_str(VPD_ASSOC_LU), 0, b, blen,
437*44704f69SBart Van Assche                            VPD_ASSOC_LU, op, jap);
438*44704f69SBart Van Assche         if (VPD_DI_SEL_TPORT & subvalue)
439*44704f69SBart Van Assche             filter_dev_ids(sg_get_desig_assoc_str(VPD_ASSOC_TPORT), 0, b,
440*44704f69SBart Van Assche                            blen, VPD_ASSOC_TPORT, op, jap);
441*44704f69SBart Van Assche         if (VPD_DI_SEL_TARGET & subvalue)
442*44704f69SBart Van Assche             filter_dev_ids(sg_get_desig_assoc_str(VPD_ASSOC_TDEVICE), 0,
443*44704f69SBart Van Assche                            b, blen, VPD_ASSOC_TDEVICE, op, jap);
444*44704f69SBart Van Assche     }
445*44704f69SBart Van Assche }
446*44704f69SBart Van Assche 
447*44704f69SBart Van Assche static void             /* VPD_SUPPORTED_VPDS  ["sv"] */
decode_supported_vpd_4vpd(uint8_t * buff,int len,struct opts_t * op,sgj_opaque_p jap)448*44704f69SBart Van Assche decode_supported_vpd_4vpd(uint8_t * buff, int len, struct opts_t * op,
449*44704f69SBart Van Assche                           sgj_opaque_p jap)
450*44704f69SBart Van Assche {
451*44704f69SBart Van Assche     uint8_t pn;
452*44704f69SBart Van Assche     int k, rlen, pdt;
453*44704f69SBart Van Assche     sgj_state * jsp = &op->json_st;
454*44704f69SBart Van Assche     sgj_opaque_p jo2p;
455*44704f69SBart Van Assche     const struct svpd_values_name_t * vnp;
456*44704f69SBart Van Assche     uint8_t * bp;
457*44704f69SBart Van Assche     char b[144];
458*44704f69SBart Van Assche     static const int blen = sizeof(b);
459*44704f69SBart Van Assche     static const char * svps = "Supported VPD pages";
460*44704f69SBart Van Assche 
461*44704f69SBart Van Assche     if ((1 == op->do_hex) || (op->do_hex > 2)) {
462*44704f69SBart Van Assche         hex2stdout(buff, len, no_ascii_4hex(op));
463*44704f69SBart Van Assche         return;
464*44704f69SBart Van Assche     }
465*44704f69SBart Van Assche     pdt = PDT_MASK & buff[0];
466*44704f69SBart Van Assche     rlen = buff[3] + 4;
467*44704f69SBart Van Assche     if (rlen > len)
468*44704f69SBart Van Assche         pr2serr("%s VPD page truncated, indicates %d, got %d\n", svps, rlen,
469*44704f69SBart Van Assche                 len);
470*44704f69SBart Van Assche     else
471*44704f69SBart Van Assche         len = rlen;
472*44704f69SBart Van Assche     if (len < 4) {
473*44704f69SBart Van Assche         pr2serr("%s VPD page length too short=%d\n", svps, len);
474*44704f69SBart Van Assche         return;
475*44704f69SBart Van Assche     }
476*44704f69SBart Van Assche     len -= 4;
477*44704f69SBart Van Assche     bp = buff + 4;
478*44704f69SBart Van Assche 
479*44704f69SBart Van Assche     for (k = 0; k < len; ++k) {
480*44704f69SBart Van Assche         pn = bp[k];
481*44704f69SBart Van Assche         snprintf(b, blen, "0x%02x", pn);
482*44704f69SBart Van Assche         vnp = sdp_get_vpd_detail(pn, -1, pdt);
483*44704f69SBart Van Assche         if (vnp) {
484*44704f69SBart Van Assche             if (op->do_long)
485*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  %s  %s [%s]\n", b, vnp->name, vnp->acron);
486*44704f69SBart Van Assche             else
487*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  %s [%s]\n", vnp->name, vnp->acron);
488*44704f69SBart Van Assche         } else if (op->vend_prod_num >= 0) {
489*44704f69SBart Van Assche             vnp = svpd_find_vendor_by_num(pn, op->vend_prod_num);
490*44704f69SBart Van Assche             if (vnp) {
491*44704f69SBart Van Assche                 if (op->do_long)
492*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "  %s  %s [%s]\n", b, vnp->name,
493*44704f69SBart Van Assche                               vnp->acron);
494*44704f69SBart Van Assche                 else
495*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "  %s [%s]\n", vnp->name, vnp->acron);
496*44704f69SBart Van Assche             } else
497*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  %s\n", b);
498*44704f69SBart Van Assche         } else
499*44704f69SBart Van Assche             sgj_pr_hr(jsp, "  %s\n", b);
500*44704f69SBart Van Assche         if (jsp->pr_as_json) {
501*44704f69SBart Van Assche             jo2p = sgj_new_unattached_object_r(jsp);
502*44704f69SBart Van Assche             sgj_js_nv_i(jsp, jo2p, "i", pn);
503*44704f69SBart Van Assche             sgj_js_nv_s(jsp, jo2p, "hex", b + 2);
504*44704f69SBart Van Assche             if (vnp) {
505*44704f69SBart Van Assche                 sgj_js_nv_s(jsp, jo2p, "name", vnp->name);
506*44704f69SBart Van Assche                 sgj_js_nv_s(jsp, jo2p, "acronym", vnp->acron);
507*44704f69SBart Van Assche             } else {
508*44704f69SBart Van Assche                 sgj_js_nv_s(jsp, jo2p, "name", "unknown");
509*44704f69SBart Van Assche                 sgj_js_nv_s(jsp, jo2p, "acronym", "unknown");
510*44704f69SBart Van Assche             }
511*44704f69SBart Van Assche             sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p);
512*44704f69SBart Van Assche         }
513*44704f69SBart Van Assche     }
514*44704f69SBart Van Assche }
515*44704f69SBart Van Assche 
516*44704f69SBart Van Assche /* VPD_SCSI_PORTS     0x88  ["sp"] */
517*44704f69SBart Van Assche static void
decode_scsi_ports_vpd_4vpd(uint8_t * buff,int len,struct opts_t * op,sgj_opaque_p jap)518*44704f69SBart Van Assche decode_scsi_ports_vpd_4vpd(uint8_t * buff, int len, struct opts_t * op,
519*44704f69SBart Van Assche                            sgj_opaque_p jap)
520*44704f69SBart Van Assche {
521*44704f69SBart Van Assche     int k, bump, rel_port, ip_tid_len, tpd_len;
522*44704f69SBart Van Assche     sgj_state * jsp = &op->json_st;
523*44704f69SBart Van Assche     sgj_opaque_p jo2p = NULL;
524*44704f69SBart Van Assche     sgj_opaque_p ja2p = NULL;
525*44704f69SBart Van Assche     uint8_t * bp;
526*44704f69SBart Van Assche 
527*44704f69SBart Van Assche     if ((1 == op->do_hex) || (op->do_hex > 2)) {
528*44704f69SBart Van Assche         hex2stdout(buff, len, no_ascii_4hex(op));
529*44704f69SBart Van Assche         return;
530*44704f69SBart Van Assche     }
531*44704f69SBart Van Assche     if (len < 4) {
532*44704f69SBart Van Assche         pr2serr("SCSI Ports VPD page length too short=%d\n", len);
533*44704f69SBart Van Assche         return;
534*44704f69SBart Van Assche     }
535*44704f69SBart Van Assche     len -= 4;
536*44704f69SBart Van Assche     bp = buff + 4;
537*44704f69SBart Van Assche     for (k = 0; k < len; k += bump, bp += bump) {
538*44704f69SBart Van Assche         rel_port = sg_get_unaligned_be16(bp + 2);
539*44704f69SBart Van Assche         sgj_pr_hr(jsp, "  Relative port=%d\n", rel_port);
540*44704f69SBart Van Assche         jo2p = sgj_new_unattached_object_r(jsp);
541*44704f69SBart Van Assche         sgj_js_nv_i(jsp, jo2p, "relative_port", rel_port);
542*44704f69SBart Van Assche         ip_tid_len = sg_get_unaligned_be16(bp + 6);
543*44704f69SBart Van Assche         bump = 8 + ip_tid_len;
544*44704f69SBart Van Assche         if ((k + bump) > len) {
545*44704f69SBart Van Assche             pr2serr("SCSI Ports VPD page, short descriptor "
546*44704f69SBart Van Assche                     "length=%d, left=%d\n", bump, (len - k));
547*44704f69SBart Van Assche             return;
548*44704f69SBart Van Assche         }
549*44704f69SBart Van Assche         if (ip_tid_len > 0) {
550*44704f69SBart Van Assche             if (op->do_hex > 1) {
551*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "    Initiator port transport id:\n");
552*44704f69SBart Van Assche                 hex2stdout((bp + 8), ip_tid_len, 1);
553*44704f69SBart Van Assche             } else {
554*44704f69SBart Van Assche                 char b[1024];
555*44704f69SBart Van Assche 
556*44704f69SBart Van Assche                 sg_decode_transportid_str("    ", bp + 8, ip_tid_len,
557*44704f69SBart Van Assche                                           true, sizeof(b), b);
558*44704f69SBart Van Assche                 if (jsp->pr_as_json)
559*44704f69SBart Van Assche                     sgj_js_nv_s(jsp, jo2p, "initiator_port_transport_id", b);
560*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "%s",
561*44704f69SBart Van Assche                           sg_decode_transportid_str("    ", bp + 8,
562*44704f69SBart Van Assche                                             ip_tid_len, true, sizeof(b), b));
563*44704f69SBart Van Assche             }
564*44704f69SBart Van Assche         }
565*44704f69SBart Van Assche         tpd_len = sg_get_unaligned_be16(bp + bump + 2);
566*44704f69SBart Van Assche         if ((k + bump + tpd_len + 4) > len) {
567*44704f69SBart Van Assche             pr2serr("SCSI Ports VPD page, short descriptor(tgt) "
568*44704f69SBart Van Assche                     "length=%d, left=%d\n", bump, (len - k));
569*44704f69SBart Van Assche             return;
570*44704f69SBart Van Assche         }
571*44704f69SBart Van Assche         if (tpd_len > 0) {
572*44704f69SBart Van Assche             if (op->do_hex > 1) {
573*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "    Target port descriptor(s):\n");
574*44704f69SBart Van Assche                 hex2stdout(bp + bump + 4, tpd_len, 1);
575*44704f69SBart Van Assche             } else {
576*44704f69SBart Van Assche                 if ((0 == op->do_quiet) || (ip_tid_len > 0))
577*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "    Target port descriptor(s):\n");
578*44704f69SBart Van Assche                 if (jsp->pr_as_json) {
579*44704f69SBart Van Assche                     sgj_opaque_p jo3p = sgj_named_subobject_r(jsp, jo2p,
580*44704f69SBart Van Assche                                                               "target_port");
581*44704f69SBart Van Assche 
582*44704f69SBart Van Assche                     ja2p = sgj_named_subarray_r(jsp, jo3p,
583*44704f69SBart Van Assche                                         "designation_descriptor_list");
584*44704f69SBart Van Assche                 }
585*44704f69SBart Van Assche                 filter_dev_ids("", 2 /* leading spaces */, bp + bump + 4,
586*44704f69SBart Van Assche                                tpd_len, VPD_ASSOC_TPORT, op, ja2p);
587*44704f69SBart Van Assche             }
588*44704f69SBart Van Assche         }
589*44704f69SBart Van Assche         bump += tpd_len + 4;
590*44704f69SBart Van Assche         sgj_js_nv_o(jsp, jap, NULL, jo2p);
591*44704f69SBart Van Assche     }
592*44704f69SBart Van Assche }
593*44704f69SBart Van Assche 
594*44704f69SBart Van Assche /* Prints outs an abridged set of device identification designators
595*44704f69SBart Van Assche    selected by association, designator type and/or code set. Not used
596*44704f69SBart Van Assche    for JSON output. */
597*44704f69SBart Van Assche static int
filter_dev_ids_quiet(uint8_t * buff,int len,int m_assoc)598*44704f69SBart Van Assche filter_dev_ids_quiet(uint8_t * buff, int len, int m_assoc)
599*44704f69SBart Van Assche {
600*44704f69SBart Van Assche     int k, m, p_id, c_set, piv, desig_type, i_len, naa, off, u;
601*44704f69SBart Van Assche     int assoc, is_sas, rtp;
602*44704f69SBart Van Assche     const uint8_t * bp;
603*44704f69SBart Van Assche     const uint8_t * ip;
604*44704f69SBart Van Assche     uint8_t sas_tport_addr[8];
605*44704f69SBart Van Assche 
606*44704f69SBart Van Assche     rtp = 0;
607*44704f69SBart Van Assche     memset(sas_tport_addr, 0, sizeof(sas_tport_addr));
608*44704f69SBart Van Assche     for (k = 0, off = -1; true; ++k) {
609*44704f69SBart Van Assche         if ((0 == k) && (0 != buff[2])) {
610*44704f69SBart Van Assche             /* first already in buff */
611*44704f69SBart Van Assche             if (m_assoc != VPD_ASSOC_LU)
612*44704f69SBart Van Assche                 return 0;
613*44704f69SBart Van Assche             ip = buff;
614*44704f69SBart Van Assche             c_set = 1;
615*44704f69SBart Van Assche             assoc = VPD_ASSOC_LU;
616*44704f69SBart Van Assche             is_sas = 0;
617*44704f69SBart Van Assche             desig_type = 3;
618*44704f69SBart Van Assche             i_len = 16;
619*44704f69SBart Van Assche         } else {
620*44704f69SBart Van Assche             u = sg_vpd_dev_id_iter(buff, len, &off, m_assoc, -1, -1);
621*44704f69SBart Van Assche             if (0 != u)
622*44704f69SBart Van Assche                 break;
623*44704f69SBart Van Assche             bp = buff + off;
624*44704f69SBart Van Assche             i_len = bp[3];
625*44704f69SBart Van Assche             if ((off + i_len + 4) > len) {
626*44704f69SBart Van Assche                 pr2serr("    VPD page error: designator length longer than\n"
627*44704f69SBart Van Assche                         "     remaining response length=%d\n", (len - off));
628*44704f69SBart Van Assche                 return SG_LIB_CAT_MALFORMED;
629*44704f69SBart Van Assche             }
630*44704f69SBart Van Assche             ip = bp + 4;
631*44704f69SBart Van Assche             p_id = ((bp[0] >> 4) & 0xf);
632*44704f69SBart Van Assche             c_set = (bp[0] & 0xf);
633*44704f69SBart Van Assche             piv = ((bp[1] & 0x80) ? 1 : 0);
634*44704f69SBart Van Assche             is_sas = (piv && (6 == p_id)) ? 1 : 0;
635*44704f69SBart Van Assche             assoc = ((bp[1] >> 4) & 0x3);
636*44704f69SBart Van Assche             desig_type = (bp[1] & 0xf);
637*44704f69SBart Van Assche         }
638*44704f69SBart Van Assche         switch (desig_type) {
639*44704f69SBart Van Assche         case 0: /* vendor specific */
640*44704f69SBart Van Assche             break;
641*44704f69SBart Van Assche         case 1: /* T10 vendor identification */
642*44704f69SBart Van Assche             break;
643*44704f69SBart Van Assche         case 2: /* EUI-64 based */
644*44704f69SBart Van Assche             if ((8 != i_len) && (12 != i_len) && (16 != i_len))
645*44704f69SBart Van Assche                 pr2serr("      << expect 8, 12 and 16 byte "
646*44704f69SBart Van Assche                         "EUI, got %d>>\n", i_len);
647*44704f69SBart Van Assche             printf("  0x");
648*44704f69SBart Van Assche             for (m = 0; m < i_len; ++m)
649*44704f69SBart Van Assche                 printf("%02x", (unsigned int)ip[m]);
650*44704f69SBart Van Assche             printf("\n");
651*44704f69SBart Van Assche             break;
652*44704f69SBart Van Assche         case 3: /* NAA */
653*44704f69SBart Van Assche             naa = (ip[0] >> 4) & 0xff;
654*44704f69SBart Van Assche             if (1 != c_set) {
655*44704f69SBart Van Assche                 pr2serr("      << expected binary code_set (1), got %d for "
656*44704f69SBart Van Assche                         "NAA=%d>>\n", c_set, naa);
657*44704f69SBart Van Assche                 hex2stderr(ip, i_len, 0);
658*44704f69SBart Van Assche                 break;
659*44704f69SBart Van Assche             }
660*44704f69SBart Van Assche             switch (naa) {
661*44704f69SBart Van Assche             case 2:             /* NAA IEEE extended */
662*44704f69SBart Van Assche                 if (8 != i_len) {
663*44704f69SBart Van Assche                     pr2serr("      << unexpected NAA 2 identifier "
664*44704f69SBart Van Assche                             "length: 0x%x>>\n", i_len);
665*44704f69SBart Van Assche                     hex2stderr(ip, i_len, 0);
666*44704f69SBart Van Assche                     break;
667*44704f69SBart Van Assche                 }
668*44704f69SBart Van Assche                 printf("  0x");
669*44704f69SBart Van Assche                 for (m = 0; m < 8; ++m)
670*44704f69SBart Van Assche                     printf("%02x", (unsigned int)ip[m]);
671*44704f69SBart Van Assche                 printf("\n");
672*44704f69SBart Van Assche                 break;
673*44704f69SBart Van Assche             case 3:             /* Locally assigned */
674*44704f69SBart Van Assche             case 5:             /* IEEE Registered */
675*44704f69SBart Van Assche                 if (8 != i_len) {
676*44704f69SBart Van Assche                     pr2serr("      << unexpected NAA 3 or 5 "
677*44704f69SBart Van Assche                             "identifier length: 0x%x>>\n", i_len);
678*44704f69SBart Van Assche                     hex2stderr(ip, i_len, 0);
679*44704f69SBart Van Assche                     break;
680*44704f69SBart Van Assche                 }
681*44704f69SBart Van Assche                 if ((0 == is_sas) || (1 != assoc)) {
682*44704f69SBart Van Assche                     printf("  0x");
683*44704f69SBart Van Assche                     for (m = 0; m < 8; ++m)
684*44704f69SBart Van Assche                         printf("%02x", (unsigned int)ip[m]);
685*44704f69SBart Van Assche                     printf("\n");
686*44704f69SBart Van Assche                 } else if (rtp) {
687*44704f69SBart Van Assche                     printf("  0x");
688*44704f69SBart Van Assche                     for (m = 0; m < 8; ++m)
689*44704f69SBart Van Assche                         printf("%02x", (unsigned int)ip[m]);
690*44704f69SBart Van Assche                     printf(",0x%x\n", rtp);
691*44704f69SBart Van Assche                     rtp = 0;
692*44704f69SBart Van Assche                 } else {
693*44704f69SBart Van Assche                     if (sas_tport_addr[0]) {
694*44704f69SBart Van Assche                         printf("  0x");
695*44704f69SBart Van Assche                         for (m = 0; m < 8; ++m)
696*44704f69SBart Van Assche                             printf("%02x", (unsigned int)sas_tport_addr[m]);
697*44704f69SBart Van Assche                         printf("\n");
698*44704f69SBart Van Assche                     }
699*44704f69SBart Van Assche                     memcpy(sas_tport_addr, ip, sizeof(sas_tport_addr));
700*44704f69SBart Van Assche                 }
701*44704f69SBart Van Assche                 break;
702*44704f69SBart Van Assche             case 6:             /* NAA IEEE registered extended */
703*44704f69SBart Van Assche                 if (16 != i_len) {
704*44704f69SBart Van Assche                     pr2serr("      << unexpected NAA 6 identifier length: "
705*44704f69SBart Van Assche                             "0x%x>>\n", i_len);
706*44704f69SBart Van Assche                     hex2stderr(ip, i_len, 0);
707*44704f69SBart Van Assche                     break;
708*44704f69SBart Van Assche                 }
709*44704f69SBart Van Assche                 printf("  0x");
710*44704f69SBart Van Assche                 for (m = 0; m < 16; ++m)
711*44704f69SBart Van Assche                     printf("%02x", (unsigned int)ip[m]);
712*44704f69SBart Van Assche                 printf("\n");
713*44704f69SBart Van Assche                 break;
714*44704f69SBart Van Assche             default:
715*44704f69SBart Van Assche                 pr2serr("      << bad NAA nibble, expected 2, 3, 5 or 6, got "
716*44704f69SBart Van Assche                         "%d>>\n", naa);
717*44704f69SBart Van Assche                 hex2stderr(ip, i_len, 0);
718*44704f69SBart Van Assche                 break;
719*44704f69SBart Van Assche             }
720*44704f69SBart Van Assche             break;
721*44704f69SBart Van Assche         case 4: /* Relative target port */
722*44704f69SBart Van Assche             if ((0 == is_sas) || (1 != c_set) || (1 != assoc) || (4 != i_len))
723*44704f69SBart Van Assche                 break;
724*44704f69SBart Van Assche             rtp = sg_get_unaligned_be16(ip + 2);
725*44704f69SBart Van Assche             if (sas_tport_addr[0]) {
726*44704f69SBart Van Assche                 printf("  0x");
727*44704f69SBart Van Assche                 for (m = 0; m < 8; ++m)
728*44704f69SBart Van Assche                     printf("%02x", (unsigned int)sas_tport_addr[m]);
729*44704f69SBart Van Assche                 printf(",0x%x\n", rtp);
730*44704f69SBart Van Assche                 memset(sas_tport_addr, 0, sizeof(sas_tport_addr));
731*44704f69SBart Van Assche                 rtp = 0;
732*44704f69SBart Van Assche             }
733*44704f69SBart Van Assche             break;
734*44704f69SBart Van Assche         case 5: /* (primary) Target port group */
735*44704f69SBart Van Assche             break;
736*44704f69SBart Van Assche         case 6: /* Logical unit group */
737*44704f69SBart Van Assche             break;
738*44704f69SBart Van Assche         case 7: /* MD5 logical unit identifier */
739*44704f69SBart Van Assche             break;
740*44704f69SBart Van Assche         case 8: /* SCSI name string */
741*44704f69SBart Van Assche             if (c_set < 2) {    /* quietly accept ASCII for UTF-8 */
742*44704f69SBart Van Assche                 pr2serr("      << expected UTF-8 code_set>>\n");
743*44704f69SBart Van Assche                 hex2stderr(ip, i_len, 0);
744*44704f69SBart Van Assche                 break;
745*44704f69SBart Van Assche             }
746*44704f69SBart Van Assche             if (! (strncmp((const char *)ip, "eui.", 4) ||
747*44704f69SBart Van Assche                    strncmp((const char *)ip, "EUI.", 4) ||
748*44704f69SBart Van Assche                    strncmp((const char *)ip, "naa.", 4) ||
749*44704f69SBart Van Assche                    strncmp((const char *)ip, "NAA.", 4) ||
750*44704f69SBart Van Assche                    strncmp((const char *)ip, "iqn.", 4))) {
751*44704f69SBart Van Assche                 pr2serr("      << expected name string prefix>>\n");
752*44704f69SBart Van Assche                 hex2stderr(ip, i_len, -1);
753*44704f69SBart Van Assche                 break;
754*44704f69SBart Van Assche             }
755*44704f69SBart Van Assche             /* does %s print out UTF-8 ok??
756*44704f69SBart Van Assche              * Seems to depend on the locale. Looks ok here with my
757*44704f69SBart Van Assche              * locale setting: en_AU.UTF-8
758*44704f69SBart Van Assche              */
759*44704f69SBart Van Assche             printf("  %.*s\n", i_len, (const char *)ip);
760*44704f69SBart Van Assche             break;
761*44704f69SBart Van Assche         case 9: /* Protocol specific port identifier */
762*44704f69SBart Van Assche             break;
763*44704f69SBart Van Assche         case 0xa: /* UUID identifier [spc5r08] RFC 4122 */
764*44704f69SBart Van Assche             if ((1 != c_set) || (18 != i_len) || (1 != ((ip[0] >> 4) & 0xf)))
765*44704f69SBart Van Assche                 break;
766*44704f69SBart Van Assche             for (m = 0; m < 16; ++m) {
767*44704f69SBart Van Assche                 if ((4 == m) || (6 == m) || (8 == m) || (10 == m))
768*44704f69SBart Van Assche                     printf("-");
769*44704f69SBart Van Assche                 printf("%02x", (unsigned int)ip[2 + m]);
770*44704f69SBart Van Assche             }
771*44704f69SBart Van Assche             printf("\n");
772*44704f69SBart Van Assche             break;
773*44704f69SBart Van Assche         default: /* reserved */
774*44704f69SBart Van Assche             break;
775*44704f69SBart Van Assche         }
776*44704f69SBart Van Assche     }
777*44704f69SBart Van Assche     if (sas_tport_addr[0]) {
778*44704f69SBart Van Assche         printf("  0x");
779*44704f69SBart Van Assche         for (m = 0; m < 8; ++m)
780*44704f69SBart Van Assche             printf("%02x", (unsigned int)sas_tport_addr[m]);
781*44704f69SBart Van Assche         printf("\n");
782*44704f69SBart Van Assche     }
783*44704f69SBart Van Assche     if (-2 == u) {
784*44704f69SBart Van Assche         pr2serr("VPD page error: short designator around offset %d\n", off);
785*44704f69SBart Van Assche         return SG_LIB_CAT_MALFORMED;
786*44704f69SBart Van Assche     }
787*44704f69SBart Van Assche     return 0;
788*44704f69SBart Van Assche }
789*44704f69SBart Van Assche 
790*44704f69SBart Van Assche /* Prints outs designation descriptors (dd_s) selected by association,
791*44704f69SBart Van Assche    designator type and/or code set. VPD_DEVICE_ID and VPD_SCSI_PORTS */
792*44704f69SBart Van Assche static int
filter_dev_ids(const char * print_if_found,int num_leading,uint8_t * buff,int len,int m_assoc,struct opts_t * op,sgj_opaque_p jap)793*44704f69SBart Van Assche filter_dev_ids(const char * print_if_found, int num_leading, uint8_t * buff,
794*44704f69SBart Van Assche                int len, int m_assoc, struct opts_t * op, sgj_opaque_p jap)
795*44704f69SBart Van Assche {
796*44704f69SBart Van Assche     bool printed, sgj_out_hr;
797*44704f69SBart Van Assche     int assoc, off, u, i_len;
798*44704f69SBart Van Assche     const uint8_t * bp;
799*44704f69SBart Van Assche     sgj_state * jsp = &op->json_st;
800*44704f69SBart Van Assche     char b[1024];
801*44704f69SBart Van Assche     char sp[82];
802*44704f69SBart Van Assche     static const int blen = sizeof(b);
803*44704f69SBart Van Assche 
804*44704f69SBart Van Assche     if (op->do_quiet && (! jsp->pr_as_json))
805*44704f69SBart Van Assche         return filter_dev_ids_quiet(buff, len, m_assoc);
806*44704f69SBart Van Assche     sgj_out_hr = false;
807*44704f69SBart Van Assche     if (jsp->pr_as_json) {
808*44704f69SBart Van Assche         int ret = filter_json_dev_ids(buff, len, m_assoc, op, jap);
809*44704f69SBart Van Assche 
810*44704f69SBart Van Assche         if (ret || (! jsp->pr_out_hr))
811*44704f69SBart Van Assche             return ret;
812*44704f69SBart Van Assche         sgj_out_hr = true;
813*44704f69SBart Van Assche     }
814*44704f69SBart Van Assche     if (num_leading > (int)(sizeof(sp) - 2))
815*44704f69SBart Van Assche         num_leading = sizeof(sp) - 2;
816*44704f69SBart Van Assche     if (num_leading > 0)
817*44704f69SBart Van Assche         snprintf(sp, sizeof(sp), "%*c", num_leading, ' ');
818*44704f69SBart Van Assche     else
819*44704f69SBart Van Assche         sp[0] = '\0';
820*44704f69SBart Van Assche     if (buff[2] != 0) { /* all valid dd_s should have 0 in this byte */
821*44704f69SBart Van Assche         if (op->verbose)
822*44704f69SBart Van Assche             pr2serr("%s: designation descriptors byte 2 should be 0\n"
823*44704f69SBart Van Assche                     "perhaps this is a standard inquiry response, ignore\n",
824*44704f69SBart Van Assche                     __func__);
825*44704f69SBart Van Assche         return 0;
826*44704f69SBart Van Assche     }
827*44704f69SBart Van Assche     off = -1;
828*44704f69SBart Van Assche     printed = false;
829*44704f69SBart Van Assche     while ((u = sg_vpd_dev_id_iter(buff, len, &off, m_assoc, -1, -1)) == 0) {
830*44704f69SBart Van Assche         bp = buff + off;
831*44704f69SBart Van Assche         i_len = bp[3];
832*44704f69SBart Van Assche         if ((off + i_len + 4) > len) {
833*44704f69SBart Van Assche             pr2serr("    VPD page error: designator length longer than\n"
834*44704f69SBart Van Assche                     "     remaining response length=%d\n", (len - off));
835*44704f69SBart Van Assche             return SG_LIB_CAT_MALFORMED;
836*44704f69SBart Van Assche         }
837*44704f69SBart Van Assche         assoc = ((bp[1] >> 4) & 0x3);
838*44704f69SBart Van Assche         if (print_if_found && (! printed)) {
839*44704f69SBart Van Assche             printed = true;
840*44704f69SBart Van Assche             if (strlen(print_if_found) > 0) {
841*44704f69SBart Van Assche                 snprintf(b, blen, "  %s:", print_if_found);
842*44704f69SBart Van Assche                 if (sgj_out_hr)
843*44704f69SBart Van Assche                     sgj_js_str_out(jsp, b, strlen(b));
844*44704f69SBart Van Assche                 else
845*44704f69SBart Van Assche                     printf("%s\n", b);
846*44704f69SBart Van Assche             }
847*44704f69SBart Van Assche         }
848*44704f69SBart Van Assche         if (NULL == print_if_found) {
849*44704f69SBart Van Assche             snprintf(b, blen, "  %s%s:", sp, sg_get_desig_assoc_str(assoc));
850*44704f69SBart Van Assche             if (sgj_out_hr)
851*44704f69SBart Van Assche                 sgj_js_str_out(jsp, b, strlen(b));
852*44704f69SBart Van Assche             else
853*44704f69SBart Van Assche                 printf("%s\n", b);
854*44704f69SBart Van Assche         }
855*44704f69SBart Van Assche         sg_get_designation_descriptor_str(sp, bp, i_len + 4, false,
856*44704f69SBart Van Assche                                           op->do_long, blen, b);
857*44704f69SBart Van Assche         if (sgj_out_hr)
858*44704f69SBart Van Assche             sgj_js_str_out(jsp, b, strlen(b));
859*44704f69SBart Van Assche         else
860*44704f69SBart Van Assche             printf("%s", b);
861*44704f69SBart Van Assche     }
862*44704f69SBart Van Assche     if (-2 == u) {
863*44704f69SBart Van Assche         pr2serr("VPD page error: short designator around offset %d\n", off);
864*44704f69SBart Van Assche         return SG_LIB_CAT_MALFORMED;
865*44704f69SBart Van Assche     }
866*44704f69SBart Van Assche     return 0;
867*44704f69SBart Van Assche }
868*44704f69SBart Van Assche 
869*44704f69SBart Van Assche /* VPD_BLOCK_LIMITS sbc */
870*44704f69SBart Van Assche /* VPD_SA_DEV_CAP ssc */
871*44704f69SBart Van Assche /* VPD_OSD_INFO osd */
872*44704f69SBart Van Assche static void
decode_b0_vpd(uint8_t * buff,int len,struct opts_t * op,sgj_opaque_p jop)873*44704f69SBart Van Assche decode_b0_vpd(uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop)
874*44704f69SBart Van Assche {
875*44704f69SBart Van Assche     int pdt = PDT_MASK & buff[0];
876*44704f69SBart Van Assche     sgj_state * jsp = &op->json_st;
877*44704f69SBart Van Assche 
878*44704f69SBart Van Assche     if (op->do_hex) {
879*44704f69SBart Van Assche         hex2stdout(buff, len, no_ascii_4hex(op));
880*44704f69SBart Van Assche         return;
881*44704f69SBart Van Assche     }
882*44704f69SBart Van Assche     switch (pdt) {
883*44704f69SBart Van Assche     case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
884*44704f69SBart Van Assche          /* now done by decode_block_limits_vpd() in sg_vpd_common.c */
885*44704f69SBart Van Assche         break;
886*44704f69SBart Van Assche     case PDT_TAPE: case PDT_MCHANGER:
887*44704f69SBart Van Assche         sgj_haj_vi_nex(jsp, jop, 2, "TSMC", SGJ_SEP_EQUAL_NO_SPACE,
888*44704f69SBart Van Assche                        !!(buff[4] & 0x2), false, "Tape Stream Mirror "
889*44704f69SBart Van Assche                        "Capable");
890*44704f69SBart Van Assche         sgj_haj_vi_nex(jsp, jop, 2, "WORM", SGJ_SEP_EQUAL_NO_SPACE,
891*44704f69SBart Van Assche                        !!(buff[4] & 0x1), false, "Write Once Read Multiple "
892*44704f69SBart Van Assche                        "supported");
893*44704f69SBart Van Assche         break;
894*44704f69SBart Van Assche     case PDT_OSD:
895*44704f69SBart Van Assche     default:
896*44704f69SBart Van Assche         pr2serr("  Unable to decode pdt=0x%x, in hex:\n", pdt);
897*44704f69SBart Van Assche         hex2stderr(buff, len, 0);
898*44704f69SBart Van Assche         break;
899*44704f69SBart Van Assche     }
900*44704f69SBart Van Assche }
901*44704f69SBart Van Assche 
902*44704f69SBart Van Assche /* VPD_BLOCK_DEV_CHARS sbc  0xb1 ["bdc"] */
903*44704f69SBart Van Assche /* VPD_MAN_ASS_SN ssc */
904*44704f69SBart Van Assche /* VPD_SECURITY_TOKEN osd */
905*44704f69SBart Van Assche /* VPD_ES_DEV_CHARS ses-4 */
906*44704f69SBart Van Assche static void
decode_b1_vpd(uint8_t * buff,int len,struct opts_t * op,sgj_opaque_p jop)907*44704f69SBart Van Assche decode_b1_vpd(uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop)
908*44704f69SBart Van Assche {
909*44704f69SBart Van Assche     int pdt;
910*44704f69SBart Van Assche     sgj_state * jsp = &op->json_st;
911*44704f69SBart Van Assche 
912*44704f69SBart Van Assche     pdt = buff[0] & PDT_MASK;
913*44704f69SBart Van Assche     if (op->do_hex) {
914*44704f69SBart Van Assche         hex2stdout(buff, len, no_ascii_4hex(op));
915*44704f69SBart Van Assche         return;
916*44704f69SBart Van Assche     }
917*44704f69SBart Van Assche     switch (pdt) {
918*44704f69SBart Van Assche     case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
919*44704f69SBart Van Assche         /* now done by decode_block_dev_ch_vpd() in sg_vpd_common.c */
920*44704f69SBart Van Assche     case PDT_TAPE: case PDT_MCHANGER: case PDT_ADC:
921*44704f69SBart Van Assche         sgj_pr_hr(jsp, "  Manufacturer-assigned serial number: %.*s\n",
922*44704f69SBart Van Assche                   len - 4, buff + 4);
923*44704f69SBart Van Assche         sgj_js_nv_s_len(jsp, jop, "manufacturer_assigned_serial_number",
924*44704f69SBart Van Assche                         (const char *)buff + 4, len - 4);
925*44704f69SBart Van Assche         break;
926*44704f69SBart Van Assche     default:
927*44704f69SBart Van Assche         pr2serr("  Unable to decode pdt=0x%x, in hex:\n", pdt);
928*44704f69SBart Van Assche         hex2stderr(buff, len, 0);
929*44704f69SBart Van Assche         break;
930*44704f69SBart Van Assche     }
931*44704f69SBart Van Assche }
932*44704f69SBart Van Assche 
933*44704f69SBart Van Assche /* VPD_LB_PROVISIONING sbc */
934*44704f69SBart Van Assche /* VPD_TA_SUPPORTED ssc */
935*44704f69SBart Van Assche static void
decode_b2_vpd(uint8_t * buff,int len,int pdt,struct opts_t * op)936*44704f69SBart Van Assche decode_b2_vpd(uint8_t * buff, int len, int pdt, struct opts_t * op)
937*44704f69SBart Van Assche {
938*44704f69SBart Van Assche     if (op->do_hex) {
939*44704f69SBart Van Assche         hex2stdout(buff, len, no_ascii_4hex(op));
940*44704f69SBart Van Assche         return;
941*44704f69SBart Van Assche     }
942*44704f69SBart Van Assche     switch (pdt) {
943*44704f69SBart Van Assche     case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
944*44704f69SBart Van Assche         /* decode_block_lb_prov_vpd() is now in sg_vpd_common.c */
945*44704f69SBart Van Assche         break;
946*44704f69SBart Van Assche     case PDT_TAPE: case PDT_MCHANGER:
947*44704f69SBart Van Assche         /* decode_tapealert_supported_vpd() is now in sg_vpd_common.c */
948*44704f69SBart Van Assche         break;
949*44704f69SBart Van Assche     default:
950*44704f69SBart Van Assche         pr2serr("  Unable to decode pdt=0x%x, in hex:\n", pdt);
951*44704f69SBart Van Assche         hex2stderr(buff, len, 0);
952*44704f69SBart Van Assche         break;
953*44704f69SBart Van Assche     }
954*44704f69SBart Van Assche }
955*44704f69SBart Van Assche 
956*44704f69SBart Van Assche /* VPD_REFERRALS sbc          0xb3 ["ref"] */
957*44704f69SBart Van Assche /* VPD_AUTOMATION_DEV_SN ssc  0xb3 ["adsn"] */
958*44704f69SBart Van Assche static void
decode_b3_vpd(uint8_t * buff,int len,struct opts_t * op,sgj_opaque_p jop)959*44704f69SBart Van Assche decode_b3_vpd(uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop)
960*44704f69SBart Van Assche {
961*44704f69SBart Van Assche     int pdt;
962*44704f69SBart Van Assche     sgj_state * jsp = &op->json_st;
963*44704f69SBart Van Assche 
964*44704f69SBart Van Assche     if (op->do_hex) {
965*44704f69SBart Van Assche         hex2stdout(buff, len, no_ascii_4hex(op));
966*44704f69SBart Van Assche         return;
967*44704f69SBart Van Assche     }
968*44704f69SBart Van Assche     pdt = buff[0] & PDT_MASK;
969*44704f69SBart Van Assche     switch (pdt) {
970*44704f69SBart Van Assche     case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
971*44704f69SBart Van Assche         /* now done in decode_referrals_vpd() in sg_vpd_common.c */
972*44704f69SBart Van Assche         break;
973*44704f69SBart Van Assche     case PDT_TAPE: case PDT_MCHANGER:
974*44704f69SBart Van Assche         sgj_pr_hr(jsp, "  Automation device serial number: %.*s\n",
975*44704f69SBart Van Assche                   len - 4, buff + 4);
976*44704f69SBart Van Assche         sgj_js_nv_s_len(jsp, jop, "automation_device_serial_number",
977*44704f69SBart Van Assche                         (const char *)buff + 4, len - 4);
978*44704f69SBart Van Assche         break;
979*44704f69SBart Van Assche     default:
980*44704f69SBart Van Assche         pr2serr("  Unable to decode pdt=0x%x, in hex:\n", pdt);
981*44704f69SBart Van Assche         hex2stderr(buff, len, 0);
982*44704f69SBart Van Assche         break;
983*44704f69SBart Van Assche     }
984*44704f69SBart Van Assche }
985*44704f69SBart Van Assche 
986*44704f69SBart Van Assche /* VPD_SUP_BLOCK_LENS   sbc ["sbl"] */
987*44704f69SBart Van Assche /* VPD_DTDE_ADDRESS ssc */
988*44704f69SBart Van Assche static void
decode_b4_vpd(uint8_t * buff,int len,struct opts_t * op,sgj_opaque_p jop)989*44704f69SBart Van Assche decode_b4_vpd(uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop)
990*44704f69SBart Van Assche {
991*44704f69SBart Van Assche     int pdt = buff[0] & PDT_MASK;
992*44704f69SBart Van Assche     sgj_state * jsp = &op->json_st;
993*44704f69SBart Van Assche 
994*44704f69SBart Van Assche     if (op->do_hex) {
995*44704f69SBart Van Assche         hex2stdout(buff, len, no_ascii_4hex(op));
996*44704f69SBart Van Assche         return;
997*44704f69SBart Van Assche     }
998*44704f69SBart Van Assche     switch (pdt) {
999*44704f69SBart Van Assche     case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
1000*44704f69SBart Van Assche         /* now done by decode_sup_block_lens_vpd() in sg_vpd_common.c */
1001*44704f69SBart Van Assche         break;
1002*44704f69SBart Van Assche     case PDT_TAPE: case PDT_MCHANGER:
1003*44704f69SBart Van Assche         sgj_pr_hr(jsp, "  Device transfer data element:\n");
1004*44704f69SBart Van Assche         if (! jsp->pr_as_json)
1005*44704f69SBart Van Assche             hex2stdout(buff + 4, len - 4, 1);
1006*44704f69SBart Van Assche         sgj_js_nv_hex_bytes(jsp, jop, "device_transfer_data_element",
1007*44704f69SBart Van Assche                             buff + 4, len - 4);
1008*44704f69SBart Van Assche         break;
1009*44704f69SBart Van Assche     default:
1010*44704f69SBart Van Assche         pr2serr("  Unable to decode pdt=0x%x, in hex:\n", pdt);
1011*44704f69SBart Van Assche         hex2stderr(buff, len, 0);
1012*44704f69SBart Van Assche         break;
1013*44704f69SBart Van Assche     }
1014*44704f69SBart Van Assche }
1015*44704f69SBart Van Assche 
1016*44704f69SBart Van Assche /* VPD_BLOCK_DEV_C_EXTENS sbc */
1017*44704f69SBart Van Assche /* VPD_LB_PROTECTION  0xb5 ["lbpro"] ssc */
1018*44704f69SBart Van Assche static void
decode_b5_vpd(uint8_t * b,int len,int do_hex,int pdt)1019*44704f69SBart Van Assche decode_b5_vpd(uint8_t * b, int len, int do_hex, int pdt)
1020*44704f69SBart Van Assche {
1021*44704f69SBart Van Assche     if (do_hex) {
1022*44704f69SBart Van Assche         hex2stdout(b, len, (1 == do_hex) ? 0 : -1);
1023*44704f69SBart Van Assche         return;
1024*44704f69SBart Van Assche     }
1025*44704f69SBart Van Assche     switch (pdt) {
1026*44704f69SBart Van Assche     case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
1027*44704f69SBart Van Assche         /* now done by decode_block_dev_char_ext_vpd() in sg_vpd_common.c */
1028*44704f69SBart Van Assche         break;
1029*44704f69SBart Van Assche     case PDT_TAPE: case PDT_MCHANGER:
1030*44704f69SBart Van Assche         /* now done by decode_lb_protection_vpd() in sg_vpd_common.c */
1031*44704f69SBart Van Assche         break;
1032*44704f69SBart Van Assche     default:
1033*44704f69SBart Van Assche         pr2serr("  Unable to decode pdt=0x%x, in hex:\n", pdt);
1034*44704f69SBart Van Assche         hex2stderr(b, len, 0);
1035*44704f69SBart Van Assche         break;
1036*44704f69SBart Van Assche     }
1037*44704f69SBart Van Assche }
1038*44704f69SBart Van Assche 
1039*44704f69SBart Van Assche /* Returns 0 if successful */
1040*44704f69SBart Van Assche static int
svpd_unable_to_decode(int sg_fd,struct opts_t * op,int subvalue,int off)1041*44704f69SBart Van Assche svpd_unable_to_decode(int sg_fd, struct opts_t * op, int subvalue, int off)
1042*44704f69SBart Van Assche {
1043*44704f69SBart Van Assche     bool as_json, json_o_hr, hex0;
1044*44704f69SBart Van Assche     int res, len, n;
1045*44704f69SBart Van Assche     sgj_state * jsp = &op->json_st;
1046*44704f69SBart Van Assche     uint8_t * rp;
1047*44704f69SBart Van Assche 
1048*44704f69SBart Van Assche     as_json = jsp->pr_as_json;
1049*44704f69SBart Van Assche     json_o_hr = as_json && jsp->pr_out_hr;
1050*44704f69SBart Van Assche     hex0 = (0 == op->do_hex);
1051*44704f69SBart Van Assche     rp = rsp_buff + off;
1052*44704f69SBart Van Assche     if (hex0 && (! op->do_raw) && (! op->examine_given))
1053*44704f69SBart Van Assche         sgj_pr_hr(jsp, "Only hex output supported\n");
1054*44704f69SBart Van Assche     if ((!op->do_raw) && (op->do_hex < 2) && (! op->examine_given)) {
1055*44704f69SBart Van Assche         if (subvalue) {
1056*44704f69SBart Van Assche             if (hex0)
1057*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "VPD page code=0x%.2x, subvalue=0x%.2x:\n",
1058*44704f69SBart Van Assche                           op->vpd_pn, subvalue);
1059*44704f69SBart Van Assche             else
1060*44704f69SBart Van Assche                 printf("VPD page code=0x%.2x, subvalue=0x%.2x:\n", op->vpd_pn,
1061*44704f69SBart Van Assche                        subvalue);
1062*44704f69SBart Van Assche         } else if (op->vpd_pn >= 0) {
1063*44704f69SBart Van Assche             if (hex0)
1064*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "VPD page code=0x%.2x:\n", op->vpd_pn);
1065*44704f69SBart Van Assche             else
1066*44704f69SBart Van Assche                 printf("VPD page code=0x%.2x:\n", op->vpd_pn);
1067*44704f69SBart Van Assche         } else {
1068*44704f69SBart Van Assche             if (hex0)
1069*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "VPD page code=%d:\n", op->vpd_pn);
1070*44704f69SBart Van Assche             else
1071*44704f69SBart Van Assche                 printf("VPD page code=%d:\n", op->vpd_pn);
1072*44704f69SBart Van Assche         }
1073*44704f69SBart Van Assche     }
1074*44704f69SBart Van Assche 
1075*44704f69SBart Van Assche     res = vpd_fetch_page(sg_fd, rp, op->vpd_pn, op->maxlen, op->do_quiet,
1076*44704f69SBart Van Assche                          op->verbose, &len);
1077*44704f69SBart Van Assche     if (0 == res) {
1078*44704f69SBart Van Assche         if (op->do_raw)
1079*44704f69SBart Van Assche             dStrRaw(rp, len);
1080*44704f69SBart Van Assche         else {
1081*44704f69SBart Van Assche            if (json_o_hr && hex0 && (len > 0) && (len < UINT16_MAX)) {
1082*44704f69SBart Van Assche                 char * p;
1083*44704f69SBart Van Assche 
1084*44704f69SBart Van Assche                 n = len * 4;
1085*44704f69SBart Van Assche                 p = malloc(n);
1086*44704f69SBart Van Assche                 if (p) {
1087*44704f69SBart Van Assche                     n = hex2str(rp, len, NULL, 1, n - 1, p);
1088*44704f69SBart Van Assche                     sgj_js_str_out(jsp, p, n);
1089*44704f69SBart Van Assche                 }
1090*44704f69SBart Van Assche             } else
1091*44704f69SBart Van Assche                 hex2stdout(rp, len, no_ascii_4hex(op));
1092*44704f69SBart Van Assche         }
1093*44704f69SBart Van Assche     } else if ((! op->do_quiet) && (! op->examine_given)) {
1094*44704f69SBart Van Assche         if (op->vpd_pn >= 0)
1095*44704f69SBart Van Assche             pr2serr("fetching VPD page code=0x%.2x: failed\n", op->vpd_pn);
1096*44704f69SBart Van Assche         else
1097*44704f69SBart Van Assche             pr2serr("fetching VPD page code=%d: failed\n", op->vpd_pn);
1098*44704f69SBart Van Assche     }
1099*44704f69SBart Van Assche     return res;
1100*44704f69SBart Van Assche }
1101*44704f69SBart Van Assche 
1102*44704f69SBart Van Assche static int
recurse_vpd_decode(struct opts_t * op,sgj_opaque_p jop,int off)1103*44704f69SBart Van Assche recurse_vpd_decode(struct opts_t * op, sgj_opaque_p jop, int off)
1104*44704f69SBart Van Assche {
1105*44704f69SBart Van Assche     int res = svpd_decode_t10(-1, op, jop, 0, off, NULL);
1106*44704f69SBart Van Assche 
1107*44704f69SBart Van Assche     if (SG_LIB_CAT_OTHER == res) {
1108*44704f69SBart Van Assche         res = svpd_decode_vendor(-1, op, jop, off);
1109*44704f69SBart Van Assche         if (SG_LIB_CAT_OTHER == res)
1110*44704f69SBart Van Assche             svpd_unable_to_decode(-1, op, 0, off);
1111*44704f69SBart Van Assche     }
1112*44704f69SBart Van Assche     return res;
1113*44704f69SBart Van Assche }
1114*44704f69SBart Van Assche 
1115*44704f69SBart Van Assche /* Returns 0 if successful. If don't know how to decode, returns
1116*44704f69SBart Van Assche  * SG_LIB_CAT_OTHER else see sg_ll_inquiry(). */
1117*44704f69SBart Van Assche static int
svpd_decode_t10(int sg_fd,struct opts_t * op,sgj_opaque_p jop,int subvalue,int off,const char * prefix)1118*44704f69SBart Van Assche svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
1119*44704f69SBart Van Assche                 int subvalue, int off, const char * prefix)
1120*44704f69SBart Van Assche {
1121*44704f69SBart Van Assche     bool allow_name, allow_if_found, long_notquiet, qt;
1122*44704f69SBart Van Assche     bool vpd_supported = false;
1123*44704f69SBart Van Assche     bool inhex_active = (-1 == sg_fd);
1124*44704f69SBart Van Assche     bool exam_not_given = ! op->examine_given;
1125*44704f69SBart Van Assche     int len, pdt, pqual, num, k, resid, alloc_len, pn, vb;
1126*44704f69SBart Van Assche     int res = 0;
1127*44704f69SBart Van Assche     sgj_state * jsp = &op->json_st;
1128*44704f69SBart Van Assche     uint8_t * rp;
1129*44704f69SBart Van Assche     sgj_opaque_p jap = NULL;
1130*44704f69SBart Van Assche     sgj_opaque_p jo2p = NULL;
1131*44704f69SBart Van Assche     const char * np;
1132*44704f69SBart Van Assche     const char * ep;
1133*44704f69SBart Van Assche     const char * pre = (prefix ? prefix : "");
1134*44704f69SBart Van Assche     const char * pdt_str;
1135*44704f69SBart Van Assche     bool as_json = jsp->pr_as_json;
1136*44704f69SBart Van Assche     bool not_json = ! as_json;
1137*44704f69SBart Van Assche     char obuff[DEF_ALLOC_LEN];
1138*44704f69SBart Van Assche     char d[48];
1139*44704f69SBart Van Assche 
1140*44704f69SBart Van Assche     vb = op->verbose;
1141*44704f69SBart Van Assche     qt = op->do_quiet;
1142*44704f69SBart Van Assche     long_notquiet = op->do_long && (! op->do_quiet);
1143*44704f69SBart Van Assche     if (op->do_raw || (op->do_quiet && (! op->do_long) && (! op->do_all)) ||
1144*44704f69SBart Van Assche         (op->do_hex >= 3) || op->examine_given)
1145*44704f69SBart Van Assche         allow_name = false;
1146*44704f69SBart Van Assche     else
1147*44704f69SBart Van Assche         allow_name = true;
1148*44704f69SBart Van Assche     allow_if_found = op->examine_given && (! op->do_quiet);
1149*44704f69SBart Van Assche     rp = rsp_buff + off;
1150*44704f69SBart Van Assche     pn = op->vpd_pn;
1151*44704f69SBart Van Assche     if ((off > 0) && (VPD_NOPE_WANT_STD_INQ != op->vpd_pn))
1152*44704f69SBart Van Assche         pn = rp[1];
1153*44704f69SBart Van Assche     else
1154*44704f69SBart Van Assche         pn = op->vpd_pn;
1155*44704f69SBart Van Assche     if (!inhex_active && !op->do_force && exam_not_given &&
1156*44704f69SBart Van Assche         pn != VPD_NOPE_WANT_STD_INQ &&
1157*44704f69SBart Van Assche         pn != VPD_SUPPORTED_VPDS) {
1158*44704f69SBart Van Assche         res = vpd_fetch_page(sg_fd, rp, VPD_SUPPORTED_VPDS, op->maxlen, qt,
1159*44704f69SBart Van Assche                              vb, &len);
1160*44704f69SBart Van Assche         if (res)
1161*44704f69SBart Van Assche             return res;
1162*44704f69SBart Van Assche 
1163*44704f69SBart Van Assche         num = rp[3];
1164*44704f69SBart Van Assche         if (num > (len - 4))
1165*44704f69SBart Van Assche             num = (len - 4);
1166*44704f69SBart Van Assche         if (vb > 1) {
1167*44704f69SBart Van Assche             pr2serr("Supported VPD pages, hex list: ");
1168*44704f69SBart Van Assche             hex2stderr(rp + 4, num, -1);
1169*44704f69SBart Van Assche         }
1170*44704f69SBart Van Assche         for (k = 0; k < num; ++k) {
1171*44704f69SBart Van Assche             if (pn == rp[4 + k]) {
1172*44704f69SBart Van Assche                 vpd_supported = true;
1173*44704f69SBart Van Assche                 break;
1174*44704f69SBart Van Assche             }
1175*44704f69SBart Van Assche         }
1176*44704f69SBart Van Assche         if (! vpd_supported) { /* get creative, was SG_LIB_CAT_ILLEGAL_REQ */
1177*44704f69SBart Van Assche             if (vb)
1178*44704f69SBart Van Assche                 pr2serr("Given VPD page not in supported list, use --force "
1179*44704f69SBart Van Assche                         "to override this check\n");
1180*44704f69SBart Van Assche             return sg_convert_errno(EDOM);
1181*44704f69SBart Van Assche         }
1182*44704f69SBart Van Assche     }
1183*44704f69SBart Van Assche     pdt = rp[0] & PDT_MASK;
1184*44704f69SBart Van Assche     pdt_str = sg_get_pdt_str(pdt, sizeof(d), d);
1185*44704f69SBart Van Assche     pqual = (rp[0] & 0xe0) >> 5;
1186*44704f69SBart Van Assche 
1187*44704f69SBart Van Assche     switch(pn) {
1188*44704f69SBart Van Assche     case VPD_NOPE_WANT_STD_INQ:    /* -2 (want standard inquiry response) */
1189*44704f69SBart Van Assche         if (!inhex_active) {
1190*44704f69SBart Van Assche             if (op->maxlen > 0)
1191*44704f69SBart Van Assche                 alloc_len = op->maxlen;
1192*44704f69SBart Van Assche             else if (op->do_long)
1193*44704f69SBart Van Assche                 alloc_len = DEF_ALLOC_LEN;
1194*44704f69SBart Van Assche             else
1195*44704f69SBart Van Assche                 alloc_len = 36;
1196*44704f69SBart Van Assche             res = sg_ll_inquiry_v2(sg_fd, false, 0, rp, alloc_len,
1197*44704f69SBart Van Assche                                    DEF_PT_TIMEOUT, &resid, ! op->do_quiet, vb);
1198*44704f69SBart Van Assche         } else {
1199*44704f69SBart Van Assche             alloc_len = op->maxlen;
1200*44704f69SBart Van Assche             resid = 0;
1201*44704f69SBart Van Assche             res = 0;
1202*44704f69SBart Van Assche         }
1203*44704f69SBart Van Assche         if (0 == res) {
1204*44704f69SBart Van Assche             alloc_len -= resid;
1205*44704f69SBart Van Assche             if (op->do_raw)
1206*44704f69SBart Van Assche                 dStrRaw(rp, alloc_len);
1207*44704f69SBart Van Assche             else if (op->do_hex) {
1208*44704f69SBart Van Assche                 if (! op->do_quiet && (op->do_hex < 3))
1209*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "Standard Inquiry data format:\n");
1210*44704f69SBart Van Assche                 hex2stdout(rp, alloc_len, (1 == op->do_hex) ? 0 : -1);
1211*44704f69SBart Van Assche             } else
1212*44704f69SBart Van Assche                 std_inq_decode(rp, alloc_len, op, jop);
1213*44704f69SBart Van Assche             return 0;
1214*44704f69SBart Van Assche         }
1215*44704f69SBart Van Assche         break;
1216*44704f69SBart Van Assche     case VPD_SUPPORTED_VPDS:    /* 0x0 ["sv"] */
1217*44704f69SBart Van Assche         np = "Supported VPD pages VPD page";
1218*44704f69SBart Van Assche         if (allow_name)
1219*44704f69SBart Van Assche             sgj_pr_hr(jsp, "%s%s:\n", pre, np);
1220*44704f69SBart Van Assche         res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
1221*44704f69SBart Van Assche         if (0 == res) {
1222*44704f69SBart Van Assche             if (! allow_name && allow_if_found)
1223*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "%s%s:\n", pre, np);
1224*44704f69SBart Van Assche             if (op->do_raw)
1225*44704f69SBart Van Assche                 dStrRaw(rp, len);
1226*44704f69SBart Van Assche             else if (op->do_hex)
1227*44704f69SBart Van Assche                 hex2stdout(rp, len, no_ascii_4hex(op));
1228*44704f69SBart Van Assche             else {
1229*44704f69SBart Van Assche                 if (vb || long_notquiet)
1230*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "   [PQual=%d  Peripheral device type: "
1231*44704f69SBart Van Assche                               "%s]\n", pqual, pdt_str);
1232*44704f69SBart Van Assche                 num = rp[3];
1233*44704f69SBart Van Assche                 if (num > (len - 4))
1234*44704f69SBart Van Assche                     num = (len - 4);
1235*44704f69SBart Van Assche                 if (as_json) {
1236*44704f69SBart Van Assche                     jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
1237*44704f69SBart Van Assche                     jap = sgj_named_subarray_r(jsp, jo2p,
1238*44704f69SBart Van Assche                                                "supported_vpd_page_list");
1239*44704f69SBart Van Assche                 }
1240*44704f69SBart Van Assche                 decode_supported_vpd_4vpd(rp, len, op, jap);
1241*44704f69SBart Van Assche             }
1242*44704f69SBart Van Assche             return 0;
1243*44704f69SBart Van Assche         }
1244*44704f69SBart Van Assche         break;
1245*44704f69SBart Van Assche     case VPD_UNIT_SERIAL_NUM:   /* 0x80 ["sn"] */
1246*44704f69SBart Van Assche         np = "Unit serial number VPD page";
1247*44704f69SBart Van Assche         if (allow_name && not_json)
1248*44704f69SBart Van Assche             sgj_pr_hr(jsp, "%s%s:\n", pre, np);
1249*44704f69SBart Van Assche         res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
1250*44704f69SBart Van Assche         if (0 == res) {
1251*44704f69SBart Van Assche             if (! allow_name && allow_if_found)
1252*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "%s%s:\n", pre, np);
1253*44704f69SBart Van Assche             if (op->do_raw)
1254*44704f69SBart Van Assche                 dStrRaw(rp, len);
1255*44704f69SBart Van Assche             else if (op->do_hex)
1256*44704f69SBart Van Assche                 hex2stdout(rp, len, no_ascii_4hex(op));
1257*44704f69SBart Van Assche             else {
1258*44704f69SBart Van Assche                 if (vb || long_notquiet)
1259*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "   [PQual=%d  Peripheral device type: "
1260*44704f69SBart Van Assche                               "%s]\n", pqual, pdt_str);
1261*44704f69SBart Van Assche                 memset(obuff, 0, sizeof(obuff));
1262*44704f69SBart Van Assche                 len -= 4;
1263*44704f69SBart Van Assche                 if (len >= (int)sizeof(obuff))
1264*44704f69SBart Van Assche                     len = sizeof(obuff) - 1;
1265*44704f69SBart Van Assche                 memcpy(obuff, rp + 4, len);
1266*44704f69SBart Van Assche                 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
1267*44704f69SBart Van Assche                 sgj_haj_vs(jsp, jo2p, 2, np, SGJ_SEP_COLON_1_SPACE, obuff);
1268*44704f69SBart Van Assche             }
1269*44704f69SBart Van Assche             return 0;
1270*44704f69SBart Van Assche         }
1271*44704f69SBart Van Assche         break;
1272*44704f69SBart Van Assche     case VPD_DEVICE_ID: /* 0x83 ["di, di_asis, di_lu, di_port, di_target"] */
1273*44704f69SBart Van Assche         np = "Device Identification VPD page";
1274*44704f69SBart Van Assche         if (allow_name)
1275*44704f69SBart Van Assche             sgj_pr_hr(jsp, "%s%s:\n", pre, np);
1276*44704f69SBart Van Assche         res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
1277*44704f69SBart Van Assche         if (0 == res) {
1278*44704f69SBart Van Assche             if (! allow_name && allow_if_found)
1279*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "%s%s:\n", pre, np);
1280*44704f69SBart Van Assche             if (op->do_raw)
1281*44704f69SBart Van Assche                 dStrRaw(rp, len);
1282*44704f69SBart Van Assche             else if (op->do_hex)
1283*44704f69SBart Van Assche                 hex2stdout(rp, len, no_ascii_4hex(op));
1284*44704f69SBart Van Assche             else {
1285*44704f69SBart Van Assche                 if (vb || long_notquiet)
1286*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "   [PQual=%d  Peripheral device type: "
1287*44704f69SBart Van Assche                               "%s]\n", pqual, pdt_str);
1288*44704f69SBart Van Assche                 if (as_json) {
1289*44704f69SBart Van Assche                     jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
1290*44704f69SBart Van Assche                     jap = sgj_named_subarray_r(jsp, jo2p,
1291*44704f69SBart Van Assche                                                "designation_descriptor_list");
1292*44704f69SBart Van Assche                 }
1293*44704f69SBart Van Assche                 device_id_vpd_variants(rp, len, subvalue, op, jap);
1294*44704f69SBart Van Assche             }
1295*44704f69SBart Van Assche             return 0;
1296*44704f69SBart Van Assche         }
1297*44704f69SBart Van Assche         break;
1298*44704f69SBart Van Assche     case VPD_SOFTW_INF_ID:      /* 0x84 ["sii"] */
1299*44704f69SBart Van Assche         np = "Software interface identification VPD page";
1300*44704f69SBart Van Assche         if (allow_name)
1301*44704f69SBart Van Assche             sgj_pr_hr(jsp, "%s%s:\n", pre, np);
1302*44704f69SBart Van Assche         res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
1303*44704f69SBart Van Assche         if (0 == res) {
1304*44704f69SBart Van Assche             if (! allow_name && allow_if_found)
1305*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "%s%s:\n", pre, np);
1306*44704f69SBart Van Assche             if (op->do_raw)
1307*44704f69SBart Van Assche                 dStrRaw(rp, len);
1308*44704f69SBart Van Assche             else {
1309*44704f69SBart Van Assche                 if (vb || long_notquiet)
1310*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "   [PQual=%d  Peripheral device type: "
1311*44704f69SBart Van Assche                               "%s]\n", pqual, pdt_str);
1312*44704f69SBart Van Assche                 if (as_json) {
1313*44704f69SBart Van Assche                     jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
1314*44704f69SBart Van Assche                     jap = sgj_named_subarray_r(jsp, jo2p,
1315*44704f69SBart Van Assche                                       "software_interface_identifier_list");
1316*44704f69SBart Van Assche                 }
1317*44704f69SBart Van Assche                 decode_softw_inf_id(rp, len, op, jap);
1318*44704f69SBart Van Assche             }
1319*44704f69SBart Van Assche             return 0;
1320*44704f69SBart Van Assche         }
1321*44704f69SBart Van Assche         break;
1322*44704f69SBart Van Assche     case VPD_MAN_NET_ADDR:      /* 0x85 ["mna"] */
1323*44704f69SBart Van Assche         np= "Management network addresses VPD page";
1324*44704f69SBart Van Assche         if (allow_name)
1325*44704f69SBart Van Assche             sgj_pr_hr(jsp, "%s%s:\n", pre, np);
1326*44704f69SBart Van Assche         res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
1327*44704f69SBart Van Assche         if (0 == res) {
1328*44704f69SBart Van Assche             if (! allow_name && allow_if_found)
1329*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "%s%s:\n", pre, np);
1330*44704f69SBart Van Assche             if (op->do_raw)
1331*44704f69SBart Van Assche                 dStrRaw(rp, len);
1332*44704f69SBart Van Assche             else {
1333*44704f69SBart Van Assche                 if (as_json) {
1334*44704f69SBart Van Assche                     jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
1335*44704f69SBart Van Assche                     jap = sgj_named_subarray_r(jsp, jo2p,
1336*44704f69SBart Van Assche                                       "network_services_descriptor_list");
1337*44704f69SBart Van Assche                 }
1338*44704f69SBart Van Assche                 decode_net_man_vpd(rp, len, op, jap);
1339*44704f69SBart Van Assche             }
1340*44704f69SBart Van Assche             return 0;
1341*44704f69SBart Van Assche         }
1342*44704f69SBart Van Assche         break;
1343*44704f69SBart Van Assche     case VPD_EXT_INQ:           /* 0x86 ["ei"] */
1344*44704f69SBart Van Assche         np = "extended INQUIRY data VPD page";
1345*44704f69SBart Van Assche         if (allow_name)
1346*44704f69SBart Van Assche             sgj_pr_hr(jsp, "%s%s:\n", pre, np);
1347*44704f69SBart Van Assche         res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
1348*44704f69SBart Van Assche         if (0 == res) {
1349*44704f69SBart Van Assche             if (! allow_name && allow_if_found)
1350*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "%s%s:\n", pre, np);
1351*44704f69SBart Van Assche             if (op->do_raw)
1352*44704f69SBart Van Assche                 dStrRaw(rp, len);
1353*44704f69SBart Van Assche             else {
1354*44704f69SBart Van Assche                 bool protect = false;
1355*44704f69SBart Van Assche 
1356*44704f69SBart Van Assche                 op->protect_not_sure = false;
1357*44704f69SBart Van Assche                 if (op->std_inq_a_valid)
1358*44704f69SBart Van Assche                      protect = !! (0x1 & op->std_inq_a[5]);
1359*44704f69SBart Van Assche                 else if ((sg_fd >= 0) && (! op->do_force)) {
1360*44704f69SBart Van Assche                     struct sg_simple_inquiry_resp sir;
1361*44704f69SBart Van Assche 
1362*44704f69SBart Van Assche                     res = sg_simple_inquiry(sg_fd, &sir, false, vb);
1363*44704f69SBart Van Assche                     if (res) {
1364*44704f69SBart Van Assche                         if (op->verbose)
1365*44704f69SBart Van Assche                             pr2serr("%s: sg_simple_inquiry() failed, "
1366*44704f69SBart Van Assche                                     "res=%d\n", __func__, res);
1367*44704f69SBart Van Assche                         op->protect_not_sure = true;
1368*44704f69SBart Van Assche                     } else
1369*44704f69SBart Van Assche                         protect = !!(sir.byte_5 & 0x1); /* SPC-3 and later */
1370*44704f69SBart Van Assche                 } else
1371*44704f69SBart Van Assche                     op->protect_not_sure = true;
1372*44704f69SBart Van Assche                 if (vb || long_notquiet)
1373*44704f69SBart Van Assche                     sgj_pr_hr(jsp,"   [PQual=%d  Peripheral device type: "
1374*44704f69SBart Van Assche                               "%s]\n", pqual, pdt_str);
1375*44704f69SBart Van Assche                 if (as_json)
1376*44704f69SBart Van Assche                     jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
1377*44704f69SBart Van Assche                 decode_x_inq_vpd(rp, len, protect, op, jo2p);
1378*44704f69SBart Van Assche             }
1379*44704f69SBart Van Assche             return 0;
1380*44704f69SBart Van Assche         }
1381*44704f69SBart Van Assche         break;
1382*44704f69SBart Van Assche     case VPD_MODE_PG_POLICY:    /* 0x87 */
1383*44704f69SBart Van Assche         np = "Mode page policy VPD page";
1384*44704f69SBart Van Assche         if (allow_name)
1385*44704f69SBart Van Assche             sgj_pr_hr(jsp, "%s%s:\n", pre, np);
1386*44704f69SBart Van Assche         res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
1387*44704f69SBart Van Assche         if (0 == res) {
1388*44704f69SBart Van Assche             if (! allow_name && allow_if_found)
1389*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "%s%s:\n", (prefix ? prefix : ""), np);
1390*44704f69SBart Van Assche             if (op->do_raw)
1391*44704f69SBart Van Assche                 dStrRaw(rp, len);
1392*44704f69SBart Van Assche             else {
1393*44704f69SBart Van Assche                 if (vb || long_notquiet)
1394*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "   [PQual=%d  Peripheral device type: "
1395*44704f69SBart Van Assche                               "%s]\n", pqual, pdt_str);
1396*44704f69SBart Van Assche                 if (as_json) {
1397*44704f69SBart Van Assche                     jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
1398*44704f69SBart Van Assche                     jap = sgj_named_subarray_r(jsp, jo2p,
1399*44704f69SBart Van Assche                                       "mode_page_policy_descriptor_list");
1400*44704f69SBart Van Assche                 }
1401*44704f69SBart Van Assche                 decode_mode_policy_vpd(rp, len, op, jap);
1402*44704f69SBart Van Assche             }
1403*44704f69SBart Van Assche             return 0;
1404*44704f69SBart Van Assche         }
1405*44704f69SBart Van Assche         break;
1406*44704f69SBart Van Assche     case VPD_SCSI_PORTS:        /* 0x88  ["sp"] */
1407*44704f69SBart Van Assche         np = "SCSI Ports VPD page";
1408*44704f69SBart Van Assche         if (allow_name)
1409*44704f69SBart Van Assche             sgj_pr_hr(jsp, "%s%s:\n", pre, np);
1410*44704f69SBart Van Assche         res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
1411*44704f69SBart Van Assche         if (0 == res) {
1412*44704f69SBart Van Assche             if (! allow_name && allow_if_found)
1413*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "%s%s:\n", pre, np);
1414*44704f69SBart Van Assche             if (op->do_raw)
1415*44704f69SBart Van Assche                 dStrRaw(rp, len);
1416*44704f69SBart Van Assche             else {
1417*44704f69SBart Van Assche                 if (vb || long_notquiet)
1418*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "   [PQual=%d  Peripheral device type: "
1419*44704f69SBart Van Assche                               "%s]\n", pqual, pdt_str);
1420*44704f69SBart Van Assche                 if (as_json) {
1421*44704f69SBart Van Assche                     jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
1422*44704f69SBart Van Assche                     jap = sgj_named_subarray_r(jsp, jo2p,
1423*44704f69SBart Van Assche                                                "scsi_ports_descriptor_list");
1424*44704f69SBart Van Assche                 }
1425*44704f69SBart Van Assche                 decode_scsi_ports_vpd_4vpd(rp, len, op, jap);
1426*44704f69SBart Van Assche             }
1427*44704f69SBart Van Assche             return 0;
1428*44704f69SBart Van Assche         }
1429*44704f69SBart Van Assche         break;
1430*44704f69SBart Van Assche     case VPD_ATA_INFO:          /* 0x89 ['ai"] */
1431*44704f69SBart Van Assche         np = "ATA information VPD page";
1432*44704f69SBart Van Assche         if (allow_name)
1433*44704f69SBart Van Assche             sgj_pr_hr(jsp, "%s%s:\n", pre, np);
1434*44704f69SBart Van Assche         alloc_len = op->maxlen ? op->maxlen : VPD_ATA_INFO_LEN;
1435*44704f69SBart Van Assche         res = vpd_fetch_page(sg_fd, rp, pn, alloc_len, qt, vb, &len);
1436*44704f69SBart Van Assche         if (0 == res) {
1437*44704f69SBart Van Assche             if (! allow_name && allow_if_found)
1438*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "%s%s:\n", (prefix ? prefix : ""), np);
1439*44704f69SBart Van Assche             if ((2 == op->do_raw) || (3 == op->do_hex)) {  /* for hdparm */
1440*44704f69SBart Van Assche                 if (len < (60 + 512))
1441*44704f69SBart Van Assche                     pr2serr("ATA_INFO VPD page len (%d) less than expected "
1442*44704f69SBart Van Assche                             "572\n", len);
1443*44704f69SBart Van Assche                 else
1444*44704f69SBart Van Assche                     dWordHex((const unsigned short *)(rp + 60), 256, -2,
1445*44704f69SBart Van Assche                              sg_is_big_endian());
1446*44704f69SBart Van Assche             }
1447*44704f69SBart Van Assche             else if (op->do_raw)
1448*44704f69SBart Van Assche                 dStrRaw(rp, len);
1449*44704f69SBart Van Assche             else {
1450*44704f69SBart Van Assche                 if (vb || long_notquiet)
1451*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "   [PQual=%d  Peripheral device type: "
1452*44704f69SBart Van Assche                               "%s]\n", pqual, pdt_str);
1453*44704f69SBart Van Assche                 if (as_json)
1454*44704f69SBart Van Assche                     jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
1455*44704f69SBart Van Assche                 decode_ata_info_vpd(rp, len, op, jo2p);
1456*44704f69SBart Van Assche             }
1457*44704f69SBart Van Assche             return 0;
1458*44704f69SBart Van Assche         }
1459*44704f69SBart Van Assche         break;
1460*44704f69SBart Van Assche     case VPD_POWER_CONDITION:          /* 0x8a ["pc"] */
1461*44704f69SBart Van Assche         np = "Power condition VPD page:";
1462*44704f69SBart Van Assche         if (allow_name)
1463*44704f69SBart Van Assche             sgj_pr_hr(jsp, "%s%s\n", pre, np);
1464*44704f69SBart Van Assche         res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
1465*44704f69SBart Van Assche         if (0 == res) {
1466*44704f69SBart Van Assche             if (! allow_name && allow_if_found)
1467*44704f69SBart Van Assche                 sgj_pr_hr(jsp,  "%s%s\n", pre, np);
1468*44704f69SBart Van Assche             if (op->do_raw)
1469*44704f69SBart Van Assche                 dStrRaw(rp, len);
1470*44704f69SBart Van Assche             else {
1471*44704f69SBart Van Assche                 if (vb || long_notquiet)
1472*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "   [PQual=%d  Peripheral device type: "
1473*44704f69SBart Van Assche                               "%s]\n", pqual, pdt_str);
1474*44704f69SBart Van Assche                 if (as_json)
1475*44704f69SBart Van Assche                     jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
1476*44704f69SBart Van Assche                 decode_power_condition(rp, len, op, jo2p);
1477*44704f69SBart Van Assche             }
1478*44704f69SBart Van Assche             return 0;
1479*44704f69SBart Van Assche         }
1480*44704f69SBart Van Assche         break;
1481*44704f69SBart Van Assche     case VPD_DEVICE_CONSTITUENTS:      /* 0x8b  ["dc"] */
1482*44704f69SBart Van Assche         np = "Device constituents VPD page";
1483*44704f69SBart Van Assche         if (allow_name)
1484*44704f69SBart Van Assche             sgj_pr_hr(jsp, "%s%s:\n", pre, np);
1485*44704f69SBart Van Assche         res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
1486*44704f69SBart Van Assche         if (0 == res) {
1487*44704f69SBart Van Assche             if (! allow_name && allow_if_found)
1488*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "%s%s:\n", pre, np);
1489*44704f69SBart Van Assche             if (op->do_raw)
1490*44704f69SBart Van Assche                 dStrRaw(rp, len);
1491*44704f69SBart Van Assche             else {
1492*44704f69SBart Van Assche                 if (vb || long_notquiet)
1493*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "   [PQual=%d  Peripheral device type: "
1494*44704f69SBart Van Assche                               "%s]\n", pqual, pdt_str);
1495*44704f69SBart Van Assche                 if (as_json) {
1496*44704f69SBart Van Assche                     jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
1497*44704f69SBart Van Assche                     jap = sgj_named_subarray_r(jsp, jo2p,
1498*44704f69SBart Van Assche                                                "constituent_descriptor_list");
1499*44704f69SBart Van Assche                 }
1500*44704f69SBart Van Assche                 decode_dev_constit_vpd(rp, len, op, jap, recurse_vpd_decode);
1501*44704f69SBart Van Assche             }
1502*44704f69SBart Van Assche             return 0;
1503*44704f69SBart Van Assche         }
1504*44704f69SBart Van Assche         break;
1505*44704f69SBart Van Assche     case VPD_CFA_PROFILE_INFO:    /* 0x8c ["cfa"] */
1506*44704f69SBart Van Assche         np = "CFA profile information VPD page";
1507*44704f69SBart Van Assche         if (allow_name)
1508*44704f69SBart Van Assche             sgj_pr_hr(jsp, "%s%s:\n", pre, np);
1509*44704f69SBart Van Assche         res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
1510*44704f69SBart Van Assche         if (0 == res) {
1511*44704f69SBart Van Assche             if (! allow_name && allow_if_found)
1512*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "%s%s\n", pre, np);
1513*44704f69SBart Van Assche             if (op->do_raw)
1514*44704f69SBart Van Assche                 dStrRaw(rp, len);
1515*44704f69SBart Van Assche             else {
1516*44704f69SBart Van Assche                 if (vb || long_notquiet)
1517*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "   [PQual=%d  Peripheral device type: "
1518*44704f69SBart Van Assche                               "%s]\n", pqual, pdt_str);
1519*44704f69SBart Van Assche                 if (as_json) {
1520*44704f69SBart Van Assche                     jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
1521*44704f69SBart Van Assche                     jap = sgj_named_subarray_r(jsp, jo2p,
1522*44704f69SBart Van Assche                                       "cfa_profile_descriptor_list");
1523*44704f69SBart Van Assche                 }
1524*44704f69SBart Van Assche                 decode_cga_profile_vpd(rp, len, op, jap);
1525*44704f69SBart Van Assche             }
1526*44704f69SBart Van Assche             return 0;
1527*44704f69SBart Van Assche         }
1528*44704f69SBart Van Assche         break;
1529*44704f69SBart Van Assche     case VPD_POWER_CONSUMPTION:    /* 0x8d ["psm"] */
1530*44704f69SBart Van Assche         np = "Power consumption VPD page";
1531*44704f69SBart Van Assche         if (allow_name)
1532*44704f69SBart Van Assche             sgj_pr_hr(jsp, "%s%s:\n", pre, np);
1533*44704f69SBart Van Assche         res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
1534*44704f69SBart Van Assche         if (0 == res) {
1535*44704f69SBart Van Assche             if (! allow_name && allow_if_found)
1536*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "%s%s\n", pre, np);
1537*44704f69SBart Van Assche             if (op->do_raw)
1538*44704f69SBart Van Assche                 dStrRaw(rp, len);
1539*44704f69SBart Van Assche             else {
1540*44704f69SBart Van Assche                 if (vb || long_notquiet)
1541*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "   [PQual=%d  Peripheral device type: "
1542*44704f69SBart Van Assche                               "%s]\n", pqual, pdt_str);
1543*44704f69SBart Van Assche                 if (as_json) {
1544*44704f69SBart Van Assche                     jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
1545*44704f69SBart Van Assche                     jap = sgj_named_subarray_r(jsp, jo2p,
1546*44704f69SBart Van Assche                                       "power_consumption_descriptor_list");
1547*44704f69SBart Van Assche                 }
1548*44704f69SBart Van Assche                 decode_power_consumption(rp, len, op, jap);
1549*44704f69SBart Van Assche             }
1550*44704f69SBart Van Assche             return 0;
1551*44704f69SBart Van Assche         }
1552*44704f69SBart Van Assche         break;
1553*44704f69SBart Van Assche     case VPD_3PARTY_COPY:   /* 0x8f */
1554*44704f69SBart Van Assche         np = "Third party copy VPD page";       /* ["tpc"] */
1555*44704f69SBart Van Assche         if (allow_name)
1556*44704f69SBart Van Assche             sgj_pr_hr(jsp, "%s%s:\n", pre, np);
1557*44704f69SBart Van Assche         res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
1558*44704f69SBart Van Assche         if (0 == res) {
1559*44704f69SBart Van Assche             if (! allow_name && allow_if_found)
1560*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "%s%s\n", pre, np);
1561*44704f69SBart Van Assche             if (op->do_raw)
1562*44704f69SBart Van Assche                 dStrRaw(rp, len);
1563*44704f69SBart Van Assche             else {
1564*44704f69SBart Van Assche                 if (vb || long_notquiet)
1565*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "   [PQual=%d  Peripheral device type: "
1566*44704f69SBart Van Assche                               "%s]\n", pqual, pdt_str);
1567*44704f69SBart Van Assche                 if (as_json) {
1568*44704f69SBart Van Assche                     jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
1569*44704f69SBart Van Assche                     jap = sgj_named_subarray_r(jsp, jo2p,
1570*44704f69SBart Van Assche                                       "third_party_copy_descriptors");
1571*44704f69SBart Van Assche                 }
1572*44704f69SBart Van Assche                 decode_3party_copy_vpd(rp, len, op, jap);
1573*44704f69SBart Van Assche             }
1574*44704f69SBart Van Assche             return 0;
1575*44704f69SBart Van Assche         }
1576*44704f69SBart Van Assche         break;
1577*44704f69SBart Van Assche     case VPD_PROTO_LU:          /* 0x90 ["pslu"] */
1578*44704f69SBart Van Assche         np = "Protocol-specific logical unit information VPD page";
1579*44704f69SBart Van Assche         if (allow_name)
1580*44704f69SBart Van Assche             sgj_pr_hr(jsp, "%s%s:\n", pre, np);
1581*44704f69SBart Van Assche         res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
1582*44704f69SBart Van Assche         if (0 == res) {
1583*44704f69SBart Van Assche             if (! allow_name && allow_if_found)
1584*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "%s%s:\n", pre, np);
1585*44704f69SBart Van Assche             if (op->do_raw)
1586*44704f69SBart Van Assche                 dStrRaw(rp, len);
1587*44704f69SBart Van Assche             else {
1588*44704f69SBart Van Assche                 if (vb || long_notquiet)
1589*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "   [PQual=%d  Peripheral device type: "
1590*44704f69SBart Van Assche                               "%s]\n", pqual, pdt_str);
1591*44704f69SBart Van Assche                 if (as_json) {
1592*44704f69SBart Van Assche                     jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
1593*44704f69SBart Van Assche                     jap = sgj_named_subarray_r(jsp, jo2p,
1594*44704f69SBart Van Assche                               "logical_unit_information_descriptor_list");
1595*44704f69SBart Van Assche                 }
1596*44704f69SBart Van Assche                 decode_proto_lu_vpd(rp, len, op, jap);
1597*44704f69SBart Van Assche             }
1598*44704f69SBart Van Assche             return 0;
1599*44704f69SBart Van Assche         }
1600*44704f69SBart Van Assche         break;
1601*44704f69SBart Van Assche     case VPD_PROTO_PORT:        /* 0x91  ["pspo"] */
1602*44704f69SBart Van Assche         np = "Protocol-specific port VPD page";
1603*44704f69SBart Van Assche         if (allow_name)
1604*44704f69SBart Van Assche             sgj_pr_hr(jsp, "%s%s\n", pre, np);
1605*44704f69SBart Van Assche         res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
1606*44704f69SBart Van Assche         if (0 == res) {
1607*44704f69SBart Van Assche             if (! allow_name && allow_if_found)
1608*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "%s%s:\n", pre, np);
1609*44704f69SBart Van Assche             if (op->do_raw)
1610*44704f69SBart Van Assche                 dStrRaw(rp, len);
1611*44704f69SBart Van Assche             else {
1612*44704f69SBart Van Assche                 if (vb || long_notquiet)
1613*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "   [PQual=%d  Peripheral device type: "
1614*44704f69SBart Van Assche                               "%s]\n", pqual, pdt_str);
1615*44704f69SBart Van Assche                 if (as_json) {
1616*44704f69SBart Van Assche                     jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
1617*44704f69SBart Van Assche                     jap = sgj_named_subarray_r(jsp, jo2p,
1618*44704f69SBart Van Assche                               "port_information_descriptor_list");
1619*44704f69SBart Van Assche                 }
1620*44704f69SBart Van Assche                 decode_proto_port_vpd(rp, len, op, jap);
1621*44704f69SBart Van Assche             }
1622*44704f69SBart Van Assche             return 0;
1623*44704f69SBart Van Assche         }
1624*44704f69SBart Van Assche         break;
1625*44704f69SBart Van Assche     case VPD_SCSI_FEATURE_SETS:         /* 0x92  ["sfs"] */
1626*44704f69SBart Van Assche         np = "SCSI Feature sets VPD page";
1627*44704f69SBart Van Assche         if (allow_name)
1628*44704f69SBart Van Assche             sgj_pr_hr(jsp, "%s%s:\n", pre, np);
1629*44704f69SBart Van Assche         res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
1630*44704f69SBart Van Assche         if (0 == res) {
1631*44704f69SBart Van Assche             if (! allow_name && allow_if_found)
1632*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "%s%s\n", pre, np);
1633*44704f69SBart Van Assche             if (op->do_raw)
1634*44704f69SBart Van Assche                 dStrRaw(rp, len);
1635*44704f69SBart Van Assche             else {
1636*44704f69SBart Van Assche                 if (vb || long_notquiet)
1637*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "   [PQual=%d  Peripheral device type: "
1638*44704f69SBart Van Assche                               "%s]\n", pqual, pdt_str);
1639*44704f69SBart Van Assche                 if (as_json) {
1640*44704f69SBart Van Assche                     jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
1641*44704f69SBart Van Assche                     jap = sgj_named_subarray_r(jsp, jo2p,
1642*44704f69SBart Van Assche                                       "feature_set_code_list");
1643*44704f69SBart Van Assche                 }
1644*44704f69SBart Van Assche                 decode_feature_sets_vpd(rp, len, op, jap);
1645*44704f69SBart Van Assche             }
1646*44704f69SBart Van Assche             return 0;
1647*44704f69SBart Van Assche         }
1648*44704f69SBart Van Assche         break;
1649*44704f69SBart Van Assche     case 0xb0:  /* depends on pdt */
1650*44704f69SBart Van Assche         res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
1651*44704f69SBart Van Assche         if (0 == res) {
1652*44704f69SBart Van Assche             bool bl = false;
1653*44704f69SBart Van Assche             bool sad = false;
1654*44704f69SBart Van Assche             bool oi = false;
1655*44704f69SBart Van Assche 
1656*44704f69SBart Van Assche             switch (pdt) {
1657*44704f69SBart Van Assche             case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
1658*44704f69SBart Van Assche                 np = "Block limits VPD page";
1659*44704f69SBart Van Assche                 ep = "(SBC)";
1660*44704f69SBart Van Assche                 bl = true;
1661*44704f69SBart Van Assche                 break;
1662*44704f69SBart Van Assche             case PDT_TAPE: case PDT_MCHANGER:
1663*44704f69SBart Van Assche                 np = "Sequential-access device capabilities VPD page";
1664*44704f69SBart Van Assche                 ep = "(SSC)";
1665*44704f69SBart Van Assche                 sad = true;
1666*44704f69SBart Van Assche                 break;
1667*44704f69SBart Van Assche             case PDT_OSD:
1668*44704f69SBart Van Assche                 np = "OSD information VPD page";
1669*44704f69SBart Van Assche                 ep = "(OSD)";
1670*44704f69SBart Van Assche                 oi = true;
1671*44704f69SBart Van Assche                 break;
1672*44704f69SBart Van Assche             default:
1673*44704f69SBart Van Assche                 np = NULL;
1674*44704f69SBart Van Assche                 break;
1675*44704f69SBart Van Assche             }
1676*44704f69SBart Van Assche             if (NULL == np)
1677*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
1678*44704f69SBart Van Assche             else if (allow_name || allow_if_found)
1679*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "%s%s %s\n", pre, np, ep ? ep : "");
1680*44704f69SBart Van Assche             if (op->do_raw)
1681*44704f69SBart Van Assche                 dStrRaw(rp, len);
1682*44704f69SBart Van Assche             else {
1683*44704f69SBart Van Assche                 if (vb || long_notquiet)
1684*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "   [PQual=%d  Peripheral device type: "
1685*44704f69SBart Van Assche                               "%s]\n", pqual, pdt_str);
1686*44704f69SBart Van Assche                 if (as_json)
1687*44704f69SBart Van Assche                     jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
1688*44704f69SBart Van Assche                 if (bl)
1689*44704f69SBart Van Assche                     decode_block_limits_vpd(rp, len, op, jo2p);
1690*44704f69SBart Van Assche                 else if (sad) {
1691*44704f69SBart Van Assche                     decode_b0_vpd(rp, len, op, jop);
1692*44704f69SBart Van Assche                 } else if (oi) {
1693*44704f69SBart Van Assche                     decode_b0_vpd(rp, len, op, jop);
1694*44704f69SBart Van Assche                 } else {
1695*44704f69SBart Van Assche 
1696*44704f69SBart Van Assche                 }
1697*44704f69SBart Van Assche             }
1698*44704f69SBart Van Assche             return 0;
1699*44704f69SBart Van Assche         } else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3) &&
1700*44704f69SBart Van Assche                    exam_not_given)
1701*44704f69SBart Van Assche             sgj_pr_hr(jsp, "%sVPD page=0xb0\n", pre);
1702*44704f69SBart Van Assche         break;
1703*44704f69SBart Van Assche     case 0xb1:  /* depends on pdt */
1704*44704f69SBart Van Assche         res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
1705*44704f69SBart Van Assche         if (0 == res) {
1706*44704f69SBart Van Assche             bool bdc = false;
1707*44704f69SBart Van Assche             static const char * masn =
1708*44704f69SBart Van Assche                         "Manufactured-assigned serial number VPD page";
1709*44704f69SBart Van Assche 
1710*44704f69SBart Van Assche             switch (pdt) {
1711*44704f69SBart Van Assche             case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
1712*44704f69SBart Van Assche                 np = "Block device characteristics VPD page";
1713*44704f69SBart Van Assche                 ep = "(SBC)";
1714*44704f69SBart Van Assche                 bdc = true;
1715*44704f69SBart Van Assche                 break;
1716*44704f69SBart Van Assche             case PDT_TAPE: case PDT_MCHANGER:
1717*44704f69SBart Van Assche                 np = masn;
1718*44704f69SBart Van Assche                 ep = "(SSC)";
1719*44704f69SBart Van Assche                 break;
1720*44704f69SBart Van Assche             case PDT_OSD:
1721*44704f69SBart Van Assche                 np = "Security token VPD page";
1722*44704f69SBart Van Assche                 ep = "(OSD)";
1723*44704f69SBart Van Assche                 break;
1724*44704f69SBart Van Assche             case PDT_ADC:
1725*44704f69SBart Van Assche                 np = masn;
1726*44704f69SBart Van Assche                 ep = "(ADC)";
1727*44704f69SBart Van Assche                 break;
1728*44704f69SBart Van Assche             default:
1729*44704f69SBart Van Assche                 np = NULL;
1730*44704f69SBart Van Assche                 break;
1731*44704f69SBart Van Assche             }
1732*44704f69SBart Van Assche             if (NULL == np)
1733*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
1734*44704f69SBart Van Assche             else if (allow_name || allow_if_found)
1735*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "%s%s %s\n", pre, np, ep ? ep : "");
1736*44704f69SBart Van Assche             if (op->do_raw)
1737*44704f69SBart Van Assche                 dStrRaw(rp, len);
1738*44704f69SBart Van Assche             else {
1739*44704f69SBart Van Assche                 if (vb || long_notquiet)
1740*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "   [PQual=%d  Peripheral device type: "
1741*44704f69SBart Van Assche                               "%s]\n", pqual, pdt_str);
1742*44704f69SBart Van Assche                 if (as_json)
1743*44704f69SBart Van Assche                     jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
1744*44704f69SBart Van Assche                 if (bdc)
1745*44704f69SBart Van Assche                     decode_block_dev_ch_vpd(rp, len, op, jo2p);
1746*44704f69SBart Van Assche                 else
1747*44704f69SBart Van Assche                     decode_b1_vpd(rp, len, op, jo2p);
1748*44704f69SBart Van Assche             }
1749*44704f69SBart Van Assche             return 0;
1750*44704f69SBart Van Assche         } else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3) &&
1751*44704f69SBart Van Assche                    exam_not_given)
1752*44704f69SBart Van Assche             sgj_pr_hr(jsp, "%sVPD page=0xb1\n", pre);
1753*44704f69SBart Van Assche         break;
1754*44704f69SBart Van Assche     case 0xb2:          /* VPD page depends on pdt */
1755*44704f69SBart Van Assche         res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
1756*44704f69SBart Van Assche         if (0 == res) {
1757*44704f69SBart Van Assche             bool lbpv = false;
1758*44704f69SBart Van Assche             bool tas = false;
1759*44704f69SBart Van Assche 
1760*44704f69SBart Van Assche             switch (pdt) {
1761*44704f69SBart Van Assche             case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
1762*44704f69SBart Van Assche                 np = "Logical block provisioning VPD page";
1763*44704f69SBart Van Assche                 ep = "(SBC)";
1764*44704f69SBart Van Assche                 lbpv = true;
1765*44704f69SBart Van Assche                 break;
1766*44704f69SBart Van Assche             case PDT_TAPE: case PDT_MCHANGER:
1767*44704f69SBart Van Assche                 np = "TapeAlert supported flags VPD page";
1768*44704f69SBart Van Assche                 ep = "(SSC)";
1769*44704f69SBart Van Assche                 tas = true;
1770*44704f69SBart Van Assche                 break;
1771*44704f69SBart Van Assche             default:
1772*44704f69SBart Van Assche                 np = NULL;
1773*44704f69SBart Van Assche                 break;
1774*44704f69SBart Van Assche             }
1775*44704f69SBart Van Assche             if (NULL == np)
1776*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
1777*44704f69SBart Van Assche             else if (allow_name || allow_if_found)
1778*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "%s%s %s\n", pre, np, ep ? ep : "");
1779*44704f69SBart Van Assche             if (op->do_raw)
1780*44704f69SBart Van Assche                 dStrRaw(rp, len);
1781*44704f69SBart Van Assche             else {
1782*44704f69SBart Van Assche                 if (vb || long_notquiet)
1783*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "   [PQual=%d  Peripheral device type: "
1784*44704f69SBart Van Assche                               "%s]\n", pqual, pdt_str);
1785*44704f69SBart Van Assche                 if (as_json)
1786*44704f69SBart Van Assche                     jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
1787*44704f69SBart Van Assche                 if (lbpv)
1788*44704f69SBart Van Assche                     decode_block_lb_prov_vpd(rp, len, op, jo2p);
1789*44704f69SBart Van Assche                 else if (tas)
1790*44704f69SBart Van Assche                     decode_tapealert_supported_vpd(rp, len, op, jo2p);
1791*44704f69SBart Van Assche                 else
1792*44704f69SBart Van Assche                     decode_b2_vpd(rp, len, pdt, op);
1793*44704f69SBart Van Assche             }
1794*44704f69SBart Van Assche             return 0;
1795*44704f69SBart Van Assche         } else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3) &&
1796*44704f69SBart Van Assche                    exam_not_given)
1797*44704f69SBart Van Assche             sgj_pr_hr(jsp, "%sVPD page=0xb2\n", pre);
1798*44704f69SBart Van Assche         break;
1799*44704f69SBart Van Assche     case 0xb3:          /* VPD page depends on pdt */
1800*44704f69SBart Van Assche         res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
1801*44704f69SBart Van Assche         if (0 == res) {
1802*44704f69SBart Van Assche             bool ref = false;
1803*44704f69SBart Van Assche 
1804*44704f69SBart Van Assche             pdt = rp[0] & PDT_MASK;
1805*44704f69SBart Van Assche             switch (pdt) {
1806*44704f69SBart Van Assche             case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
1807*44704f69SBart Van Assche                 np = "Referrals VPD page";
1808*44704f69SBart Van Assche                 ep = "(SBC)";
1809*44704f69SBart Van Assche                 ref = true;
1810*44704f69SBart Van Assche                 break;
1811*44704f69SBart Van Assche             case PDT_TAPE: case PDT_MCHANGER:
1812*44704f69SBart Van Assche                 np = "Automation device serial number VPD page";
1813*44704f69SBart Van Assche                 ep = "(SSC)";
1814*44704f69SBart Van Assche                 break;
1815*44704f69SBart Van Assche             default:
1816*44704f69SBart Van Assche                 np = NULL;
1817*44704f69SBart Van Assche                 break;
1818*44704f69SBart Van Assche             }
1819*44704f69SBart Van Assche             if (NULL == np)
1820*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
1821*44704f69SBart Van Assche             else if (allow_name || allow_if_found)
1822*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "%s%s %s\n", pre, np, ep ? ep : "");
1823*44704f69SBart Van Assche             if (op->do_raw)
1824*44704f69SBart Van Assche                 dStrRaw(rp, len);
1825*44704f69SBart Van Assche             else {
1826*44704f69SBart Van Assche                 if (vb || long_notquiet)
1827*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "   [PQual=%d  Peripheral device type: "
1828*44704f69SBart Van Assche                               "%s]\n", pqual, pdt_str);
1829*44704f69SBart Van Assche                 if (as_json)
1830*44704f69SBart Van Assche                     jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
1831*44704f69SBart Van Assche                 if (ref)
1832*44704f69SBart Van Assche                     decode_referrals_vpd(rp, len, op, jo2p);
1833*44704f69SBart Van Assche                 else
1834*44704f69SBart Van Assche                     decode_b3_vpd(rp, len, op, jo2p);
1835*44704f69SBart Van Assche             }
1836*44704f69SBart Van Assche             return 0;
1837*44704f69SBart Van Assche         } else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3) &&
1838*44704f69SBart Van Assche                    exam_not_given)
1839*44704f69SBart Van Assche             sgj_pr_hr(jsp, "%sVPD page=0xb3\n", pre);
1840*44704f69SBart Van Assche         break;
1841*44704f69SBart Van Assche     case 0xb4:          /* VPD page depends on pdt */
1842*44704f69SBart Van Assche         res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
1843*44704f69SBart Van Assche         if (0 == res) {
1844*44704f69SBart Van Assche             bool sbl = false;
1845*44704f69SBart Van Assche 
1846*44704f69SBart Van Assche             pdt = rp[0] & PDT_MASK;
1847*44704f69SBart Van Assche             switch (pdt) {
1848*44704f69SBart Van Assche             case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
1849*44704f69SBart Van Assche                 np = "Supported block lengths and protection types VPD page";
1850*44704f69SBart Van Assche                 ep = "(SBC)";
1851*44704f69SBart Van Assche                 sbl = true;
1852*44704f69SBart Van Assche                 break;
1853*44704f69SBart Van Assche             case PDT_TAPE: case PDT_MCHANGER:
1854*44704f69SBart Van Assche                 np = "Data transfer device element address";
1855*44704f69SBart Van Assche                 ep = "(SSC)";
1856*44704f69SBart Van Assche                 break;
1857*44704f69SBart Van Assche             default:
1858*44704f69SBart Van Assche                 np = NULL;
1859*44704f69SBart Van Assche                 break;
1860*44704f69SBart Van Assche             }
1861*44704f69SBart Van Assche             if (NULL == np)
1862*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
1863*44704f69SBart Van Assche             else if (allow_name || allow_if_found)
1864*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "%s%s %s\n", pre, np, ep ? ep : "");
1865*44704f69SBart Van Assche             if (op->do_raw)
1866*44704f69SBart Van Assche                 dStrRaw(rp, len);
1867*44704f69SBart Van Assche             else {
1868*44704f69SBart Van Assche                 if (vb || long_notquiet)
1869*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "   [PQual=%d  Peripheral device type: "
1870*44704f69SBart Van Assche                               "%s]\n", pqual, pdt_str);
1871*44704f69SBart Van Assche                 if (as_json)
1872*44704f69SBart Van Assche                     jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
1873*44704f69SBart Van Assche                 if (sbl) {
1874*44704f69SBart Van Assche                     if (as_json)
1875*44704f69SBart Van Assche                         jap = sgj_named_subarray_r(jsp, jo2p, "logical_block_"
1876*44704f69SBart Van Assche                                 "length_and_protection_types_descriptor_list");
1877*44704f69SBart Van Assche                     decode_sup_block_lens_vpd(rp, len, op, jap);
1878*44704f69SBart Van Assche                 } else
1879*44704f69SBart Van Assche                     decode_b4_vpd(rp, len, op, jo2p);
1880*44704f69SBart Van Assche             }
1881*44704f69SBart Van Assche             return 0;
1882*44704f69SBart Van Assche         } else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3) &&
1883*44704f69SBart Van Assche                    exam_not_given)
1884*44704f69SBart Van Assche             sgj_pr_hr(jsp, "%sVPD page=0xb4\n", pre);
1885*44704f69SBart Van Assche         break;
1886*44704f69SBart Van Assche     case 0xb5:          /* VPD page depends on pdt */
1887*44704f69SBart Van Assche         res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
1888*44704f69SBart Van Assche         if (0 == res) {
1889*44704f69SBart Van Assche             bool bdce = false;
1890*44704f69SBart Van Assche             bool lbp = false;
1891*44704f69SBart Van Assche 
1892*44704f69SBart Van Assche             pdt = rp[0] & PDT_MASK;
1893*44704f69SBart Van Assche             switch (pdt) {
1894*44704f69SBart Van Assche             case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
1895*44704f69SBart Van Assche                 np = "Block device characteristics extension VPD page";
1896*44704f69SBart Van Assche                 ep = "(SBC)";
1897*44704f69SBart Van Assche                 bdce = true;
1898*44704f69SBart Van Assche                 break;
1899*44704f69SBart Van Assche             case PDT_TAPE: case PDT_MCHANGER:
1900*44704f69SBart Van Assche                 np = "Logical block protection VPD page";
1901*44704f69SBart Van Assche                 ep = "(SSC)";
1902*44704f69SBart Van Assche                 lbp = true;
1903*44704f69SBart Van Assche                 break;
1904*44704f69SBart Van Assche             default:
1905*44704f69SBart Van Assche                 np = NULL;
1906*44704f69SBart Van Assche                 break;
1907*44704f69SBart Van Assche             }
1908*44704f69SBart Van Assche             if (NULL == np)
1909*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
1910*44704f69SBart Van Assche             else if (allow_name || allow_if_found)
1911*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "%s%s %s\n", pre, np, ep ? ep : "");
1912*44704f69SBart Van Assche             if (op->do_raw)
1913*44704f69SBart Van Assche                 dStrRaw(rp, len);
1914*44704f69SBart Van Assche             else {
1915*44704f69SBart Van Assche                 if (vb || long_notquiet)
1916*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "   [PQual=%d  Peripheral device type: "
1917*44704f69SBart Van Assche                               "%s]\n", pqual, pdt_str);
1918*44704f69SBart Van Assche                 if (as_json)
1919*44704f69SBart Van Assche                     jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
1920*44704f69SBart Van Assche                 if (bdce)
1921*44704f69SBart Van Assche                     decode_block_dev_char_ext_vpd(rp, len, op, jo2p);
1922*44704f69SBart Van Assche                 else if (lbp) {
1923*44704f69SBart Van Assche                     if (as_json)
1924*44704f69SBart Van Assche                         jap = sgj_named_subarray_r(jsp, jo2p,
1925*44704f69SBart Van Assche                          "logical_block_protection_method_descriptor_list");
1926*44704f69SBart Van Assche                      decode_lb_protection_vpd(rp, len, op, jap);
1927*44704f69SBart Van Assche                 } else
1928*44704f69SBart Van Assche                     decode_b5_vpd(rp, len, op->do_hex, pdt);
1929*44704f69SBart Van Assche             }
1930*44704f69SBart Van Assche             return 0;
1931*44704f69SBart Van Assche         } else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3) &&
1932*44704f69SBart Van Assche                    exam_not_given)
1933*44704f69SBart Van Assche             sgj_pr_hr(jsp, "%sVPD page=0xb5\n", pre);
1934*44704f69SBart Van Assche         break;
1935*44704f69SBart Van Assche     case VPD_ZBC_DEV_CHARS:       /* 0xb6 for both pdt=0 and pdt=0x14 */
1936*44704f69SBart Van Assche         res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
1937*44704f69SBart Van Assche         if (0 == res) {
1938*44704f69SBart Van Assche             bool zbdch = false;
1939*44704f69SBart Van Assche 
1940*44704f69SBart Van Assche             pdt = rp[0] & PDT_MASK;
1941*44704f69SBart Van Assche             switch (pdt) {
1942*44704f69SBart Van Assche             case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
1943*44704f69SBart Van Assche                 np = "Zoned block device characteristics VPD page";
1944*44704f69SBart Van Assche                 ep = "(SBC, ZBC)";
1945*44704f69SBart Van Assche                 zbdch = true;
1946*44704f69SBart Van Assche                 break;
1947*44704f69SBart Van Assche             default:
1948*44704f69SBart Van Assche                 np = NULL;
1949*44704f69SBart Van Assche                 break;
1950*44704f69SBart Van Assche             }
1951*44704f69SBart Van Assche             if (NULL == np)
1952*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
1953*44704f69SBart Van Assche             else if (allow_name || allow_if_found)
1954*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "%s%s %s\n", pre, np, ep ? ep : "");
1955*44704f69SBart Van Assche             if (op->do_raw)
1956*44704f69SBart Van Assche                 dStrRaw(rp, len);
1957*44704f69SBart Van Assche             else {
1958*44704f69SBart Van Assche                 if (vb || long_notquiet)
1959*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "   [PQual=%d  Peripheral device type: "
1960*44704f69SBart Van Assche                               "%s]\n", pqual, pdt_str);
1961*44704f69SBart Van Assche                 if (as_json)
1962*44704f69SBart Van Assche                     jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
1963*44704f69SBart Van Assche                 if (zbdch)
1964*44704f69SBart Van Assche                     decode_zbdch_vpd(rp, len, op, jo2p);
1965*44704f69SBart Van Assche                 else
1966*44704f69SBart Van Assche                     return SG_LIB_CAT_OTHER;
1967*44704f69SBart Van Assche             }
1968*44704f69SBart Van Assche             return 0;
1969*44704f69SBart Van Assche         } else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3) &&
1970*44704f69SBart Van Assche                    exam_not_given)
1971*44704f69SBart Van Assche             sgj_pr_hr(jsp, "%sVPD page=0xb6\n", pre);
1972*44704f69SBart Van Assche         break;
1973*44704f69SBart Van Assche     case 0xb7:
1974*44704f69SBart Van Assche         res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
1975*44704f69SBart Van Assche         if (0 == res) {
1976*44704f69SBart Van Assche             bool ble = false;
1977*44704f69SBart Van Assche 
1978*44704f69SBart Van Assche             pdt = rp[0] & PDT_MASK;
1979*44704f69SBart Van Assche             switch (pdt) {
1980*44704f69SBart Van Assche             case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
1981*44704f69SBart Van Assche                 np = "Block limits extension VPD page";
1982*44704f69SBart Van Assche                 ep = "(SBC)";
1983*44704f69SBart Van Assche                 ble = true;
1984*44704f69SBart Van Assche                 break;
1985*44704f69SBart Van Assche             default:
1986*44704f69SBart Van Assche                 np = NULL;
1987*44704f69SBart Van Assche                 break;
1988*44704f69SBart Van Assche             }
1989*44704f69SBart Van Assche             if (NULL == np)
1990*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
1991*44704f69SBart Van Assche             else if (allow_name || allow_if_found)
1992*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "%s%s %s:\n", pre, np, ep ? ep : "");
1993*44704f69SBart Van Assche             if (op->do_raw)
1994*44704f69SBart Van Assche                 dStrRaw(rp, len);
1995*44704f69SBart Van Assche             else {
1996*44704f69SBart Van Assche                 if (vb || long_notquiet)
1997*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "   [PQual=%d  Peripheral device type: "
1998*44704f69SBart Van Assche                               "%s]\n", pqual, pdt_str);
1999*44704f69SBart Van Assche                 if (as_json)
2000*44704f69SBart Van Assche                     jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
2001*44704f69SBart Van Assche                 if (ble)
2002*44704f69SBart Van Assche                     decode_block_limits_ext_vpd(rp, len, op, jo2p);
2003*44704f69SBart Van Assche                 else
2004*44704f69SBart Van Assche                     return SG_LIB_CAT_OTHER;
2005*44704f69SBart Van Assche             }
2006*44704f69SBart Van Assche             return 0;
2007*44704f69SBart Van Assche         } else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3) &&
2008*44704f69SBart Van Assche                    exam_not_given)
2009*44704f69SBart Van Assche             sgj_pr_hr(jsp, "%sVPD page=0xb7\n", pre);
2010*44704f69SBart Van Assche         break;
2011*44704f69SBart Van Assche     case 0xb8:          /* VPD_FORMAT_PRESETS */
2012*44704f69SBart Van Assche         res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
2013*44704f69SBart Van Assche         if (0 == res) {
2014*44704f69SBart Van Assche             bool fp = false;
2015*44704f69SBart Van Assche 
2016*44704f69SBart Van Assche             pdt = rp[0] & PDT_MASK;
2017*44704f69SBart Van Assche             switch (pdt) {
2018*44704f69SBart Van Assche             case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
2019*44704f69SBart Van Assche                 np = "Format presets VPD page";
2020*44704f69SBart Van Assche                 ep = "(SBC)";
2021*44704f69SBart Van Assche                 fp = true;
2022*44704f69SBart Van Assche                 break;
2023*44704f69SBart Van Assche             default:
2024*44704f69SBart Van Assche                 np = NULL;
2025*44704f69SBart Van Assche                 break;
2026*44704f69SBart Van Assche             }
2027*44704f69SBart Van Assche             if (NULL == np)
2028*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
2029*44704f69SBart Van Assche             else if (allow_name || allow_if_found)
2030*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "%s%s %s:\n", pre, np, ep ? ep : "");
2031*44704f69SBart Van Assche             if (op->do_raw)
2032*44704f69SBart Van Assche                 dStrRaw(rp, len);
2033*44704f69SBart Van Assche             else {
2034*44704f69SBart Van Assche                 if (vb || long_notquiet)
2035*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "   [PQual=%d  Peripheral device type: "
2036*44704f69SBart Van Assche                               "%s]\n", pqual, pdt_str);
2037*44704f69SBart Van Assche                 if (as_json) {
2038*44704f69SBart Van Assche                     jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
2039*44704f69SBart Van Assche                     jap = sgj_named_subarray_r(jsp, jo2p, "format_preset_"
2040*44704f69SBart Van Assche                                                "descriptor_list");
2041*44704f69SBart Van Assche                 }
2042*44704f69SBart Van Assche                 if (fp)
2043*44704f69SBart Van Assche                     decode_format_presets_vpd(rp, len, op, jap);
2044*44704f69SBart Van Assche                 else
2045*44704f69SBart Van Assche                     return SG_LIB_CAT_OTHER;
2046*44704f69SBart Van Assche             }
2047*44704f69SBart Van Assche             return 0;
2048*44704f69SBart Van Assche         } else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3) &&
2049*44704f69SBart Van Assche                    exam_not_given)
2050*44704f69SBart Van Assche             sgj_pr_hr(jsp, "%sVPD page=0xb8\n", pre);
2051*44704f69SBart Van Assche         break;
2052*44704f69SBart Van Assche     case 0xb9:          /* VPD_CON_POS_RANGE */
2053*44704f69SBart Van Assche         res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
2054*44704f69SBart Van Assche         if (0 == res) {
2055*44704f69SBart Van Assche             bool cpr = false;           /* ["cpr"] */
2056*44704f69SBart Van Assche 
2057*44704f69SBart Van Assche             pdt = rp[0] & PDT_MASK;
2058*44704f69SBart Van Assche             switch (pdt) {
2059*44704f69SBart Van Assche             case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
2060*44704f69SBart Van Assche                 np = "Concurrent positioning ranges VPD page";
2061*44704f69SBart Van Assche                 ep = "(SBC)";
2062*44704f69SBart Van Assche                 cpr = true;
2063*44704f69SBart Van Assche                 break;
2064*44704f69SBart Van Assche             default:
2065*44704f69SBart Van Assche                 np = NULL;
2066*44704f69SBart Van Assche                 break;
2067*44704f69SBart Van Assche             }
2068*44704f69SBart Van Assche             if (NULL == np)
2069*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
2070*44704f69SBart Van Assche             else if (allow_name || allow_if_found)
2071*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "%s%s %s:\n", pre, np, ep ? ep : "");
2072*44704f69SBart Van Assche             if (op->do_raw)
2073*44704f69SBart Van Assche                 dStrRaw(rp, len);
2074*44704f69SBart Van Assche             else {
2075*44704f69SBart Van Assche                 if (vb || long_notquiet)
2076*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "   [PQual=%d  Peripheral device type: "
2077*44704f69SBart Van Assche                               "%s]\n", pqual, pdt_str);
2078*44704f69SBart Van Assche                 if (as_json) {
2079*44704f69SBart Van Assche                     jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
2080*44704f69SBart Van Assche                     jap = sgj_named_subarray_r(jsp, jo2p, "lba_range_"
2081*44704f69SBart Van Assche                                                "descriptor_list");
2082*44704f69SBart Van Assche                 }
2083*44704f69SBart Van Assche                 if (cpr)
2084*44704f69SBart Van Assche                     decode_con_pos_range_vpd(rp, len, op, jap);
2085*44704f69SBart Van Assche                 else
2086*44704f69SBart Van Assche                     return SG_LIB_CAT_OTHER;
2087*44704f69SBart Van Assche             }
2088*44704f69SBart Van Assche             return 0;
2089*44704f69SBart Van Assche         } else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3) &&
2090*44704f69SBart Van Assche                    exam_not_given)
2091*44704f69SBart Van Assche             sgj_pr_hr(jsp, "%sVPD page=0xb8\n", pre);
2092*44704f69SBart Van Assche         break;
2093*44704f69SBart Van Assche     default:
2094*44704f69SBart Van Assche         return SG_LIB_CAT_OTHER;
2095*44704f69SBart Van Assche     }
2096*44704f69SBart Van Assche     return res;
2097*44704f69SBart Van Assche }
2098*44704f69SBart Van Assche 
2099*44704f69SBart Van Assche static int
svpd_decode_all(int sg_fd,struct opts_t * op,sgj_opaque_p jop)2100*44704f69SBart Van Assche svpd_decode_all(int sg_fd, struct opts_t * op, sgj_opaque_p jop)
2101*44704f69SBart Van Assche {
2102*44704f69SBart Van Assche     int k, res, rlen, n, pn;
2103*44704f69SBart Van Assche     int max_pn = 255;
2104*44704f69SBart Van Assche     int any_err = 0;
2105*44704f69SBart Van Assche     sgj_state * jsp = &op->json_st;
2106*44704f69SBart Van Assche     uint8_t vpd0_buff[512];
2107*44704f69SBart Van Assche     uint8_t * rp = vpd0_buff;
2108*44704f69SBart Van Assche 
2109*44704f69SBart Van Assche     if (op->vpd_pn > 0)
2110*44704f69SBart Van Assche         max_pn = op->vpd_pn;
2111*44704f69SBart Van Assche     if (sg_fd >= 0) {   /* have valid open file descriptor (handle) */
2112*44704f69SBart Van Assche         res = vpd_fetch_page(sg_fd, rp, VPD_SUPPORTED_VPDS, op->maxlen,
2113*44704f69SBart Van Assche                              op->do_quiet, op->verbose, &rlen);
2114*44704f69SBart Van Assche         if (res) {
2115*44704f69SBart Van Assche             if (! op->do_quiet) {
2116*44704f69SBart Van Assche                 if (SG_LIB_CAT_ABORTED_COMMAND == res)
2117*44704f69SBart Van Assche                     pr2serr("%s: VPD page 0, aborted command\n", __func__);
2118*44704f69SBart Van Assche                 else if (res) {
2119*44704f69SBart Van Assche                     char b[80];
2120*44704f69SBart Van Assche 
2121*44704f69SBart Van Assche                     sg_get_category_sense_str(res, sizeof(b), b, op->verbose);
2122*44704f69SBart Van Assche                     pr2serr("%s: fetching VPD page 0 failed: %s\n", __func__,
2123*44704f69SBart Van Assche                             b);
2124*44704f69SBart Van Assche                 }
2125*44704f69SBart Van Assche             }
2126*44704f69SBart Van Assche             return res;
2127*44704f69SBart Van Assche         }
2128*44704f69SBart Van Assche         n = sg_get_unaligned_be16(rp + 2);
2129*44704f69SBart Van Assche         if (n > (rlen - 4)) {
2130*44704f69SBart Van Assche             if (op->verbose)
2131*44704f69SBart Van Assche                 pr2serr("%s: rlen=%d > page0 size=%d\n", __func__, rlen,
2132*44704f69SBart Van Assche                         n + 4);
2133*44704f69SBart Van Assche             n = (rlen - 4);
2134*44704f69SBart Van Assche         }
2135*44704f69SBart Van Assche         for (k = 0; k < n; ++k) {
2136*44704f69SBart Van Assche             pn = rp[4 + k];
2137*44704f69SBart Van Assche             if (pn > max_pn)
2138*44704f69SBart Van Assche                 continue;
2139*44704f69SBart Van Assche             op->vpd_pn = pn;
2140*44704f69SBart Van Assche             if (k > 0)
2141*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "\n");
2142*44704f69SBart Van Assche             if (op->do_long) {
2143*44704f69SBart Van Assche                 if (jsp->pr_as_json)
2144*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "[0x%x]:\n", pn);
2145*44704f69SBart Van Assche                 else
2146*44704f69SBart Van Assche                     printf("[0x%x] ", pn);
2147*44704f69SBart Van Assche             }
2148*44704f69SBart Van Assche 
2149*44704f69SBart Van Assche             res = svpd_decode_t10(sg_fd, op, jop, 0, 0, NULL);
2150*44704f69SBart Van Assche             if (SG_LIB_CAT_OTHER == res) {
2151*44704f69SBart Van Assche                 res = svpd_decode_vendor(sg_fd, op, jop, 0);
2152*44704f69SBart Van Assche                 if (SG_LIB_CAT_OTHER == res)
2153*44704f69SBart Van Assche                     res = svpd_unable_to_decode(sg_fd, op, 0, 0);
2154*44704f69SBart Van Assche             }
2155*44704f69SBart Van Assche             if (! op->do_quiet) {
2156*44704f69SBart Van Assche                 if (SG_LIB_CAT_ABORTED_COMMAND == res)
2157*44704f69SBart Van Assche                     pr2serr("fetching VPD page failed, aborted command\n");
2158*44704f69SBart Van Assche                 else if (res) {
2159*44704f69SBart Van Assche                     char b[80];
2160*44704f69SBart Van Assche 
2161*44704f69SBart Van Assche                     sg_get_category_sense_str(res, sizeof(b), b, op->verbose);
2162*44704f69SBart Van Assche                     pr2serr("fetching VPD page failed: %s\n", b);
2163*44704f69SBart Van Assche                 }
2164*44704f69SBart Van Assche             }
2165*44704f69SBart Van Assche             if (res)
2166*44704f69SBart Van Assche                 any_err = res;
2167*44704f69SBart Van Assche         }
2168*44704f69SBart Van Assche         res = any_err;
2169*44704f69SBart Van Assche     } else {    /* input is coming from --inhex=FN */
2170*44704f69SBart Van Assche         int bump, off;
2171*44704f69SBart Van Assche         int in_len = op->maxlen;
2172*44704f69SBart Van Assche         int prev_pn = -1;
2173*44704f69SBart Van Assche 
2174*44704f69SBart Van Assche         res = 0;
2175*44704f69SBart Van Assche         if (op->page_given && (VPD_NOPE_WANT_STD_INQ == op->vpd_pn))
2176*44704f69SBart Van Assche             return svpd_decode_t10(-1, op, jop, 0, 0, NULL);
2177*44704f69SBart Van Assche 
2178*44704f69SBart Van Assche         for (k = 0, off = 0; off < in_len; ++k, off += bump) {
2179*44704f69SBart Van Assche             rp = rsp_buff + off;
2180*44704f69SBart Van Assche             pn = rp[1];
2181*44704f69SBart Van Assche             bump = sg_get_unaligned_be16(rp + 2) + 4;
2182*44704f69SBart Van Assche             if ((off + bump) > in_len) {
2183*44704f69SBart Van Assche                 pr2serr("%s: page 0x%x size (%d) exceeds buffer\n", __func__,
2184*44704f69SBart Van Assche                         pn, bump);
2185*44704f69SBart Van Assche                 bump = in_len - off;
2186*44704f69SBart Van Assche             }
2187*44704f69SBart Van Assche             if (op->page_given && (pn != op->vpd_pn))
2188*44704f69SBart Van Assche                 continue;
2189*44704f69SBart Van Assche             if (pn <= prev_pn) {
2190*44704f69SBart Van Assche                 pr2serr("%s: prev_pn=0x%x, this pn=0x%x, not ascending so "
2191*44704f69SBart Van Assche                         "exit\n", __func__, prev_pn, pn);
2192*44704f69SBart Van Assche                 break;
2193*44704f69SBart Van Assche             }
2194*44704f69SBart Van Assche             prev_pn = pn;
2195*44704f69SBart Van Assche             op->vpd_pn = pn;
2196*44704f69SBart Van Assche             if (pn > max_pn) {
2197*44704f69SBart Van Assche                 if (op->verbose > 2)
2198*44704f69SBart Van Assche                     pr2serr("%s: skipping as this pn=0x%x exceeds "
2199*44704f69SBart Van Assche                             "max_pn=0x%x\n", __func__, pn, max_pn);
2200*44704f69SBart Van Assche                 continue;
2201*44704f69SBart Van Assche             }
2202*44704f69SBart Van Assche             if (op->do_long) {
2203*44704f69SBart Van Assche                 if (jsp->pr_as_json)
2204*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "[0x%x]:\n", pn);
2205*44704f69SBart Van Assche                 else
2206*44704f69SBart Van Assche                     printf("[0x%x] ", pn);
2207*44704f69SBart Van Assche             }
2208*44704f69SBart Van Assche 
2209*44704f69SBart Van Assche             res = svpd_decode_t10(-1, op, jop, 0, off, NULL);
2210*44704f69SBart Van Assche             if (SG_LIB_CAT_OTHER == res) {
2211*44704f69SBart Van Assche                 res = svpd_decode_vendor(-1, op, jop, off);
2212*44704f69SBart Van Assche                 if (SG_LIB_CAT_OTHER == res)
2213*44704f69SBart Van Assche                     res = svpd_unable_to_decode(-1, op, 0, off);
2214*44704f69SBart Van Assche             }
2215*44704f69SBart Van Assche         }
2216*44704f69SBart Van Assche     }
2217*44704f69SBart Van Assche     return res;
2218*44704f69SBart Van Assche }
2219*44704f69SBart Van Assche 
2220*44704f69SBart Van Assche static int
svpd_examine_all(int sg_fd,struct opts_t * op,sgj_opaque_p jop)2221*44704f69SBart Van Assche svpd_examine_all(int sg_fd, struct opts_t * op, sgj_opaque_p jop)
2222*44704f69SBart Van Assche {
2223*44704f69SBart Van Assche     bool first = true;
2224*44704f69SBart Van Assche     bool got_one = false;
2225*44704f69SBart Van Assche     int k, res, start;
2226*44704f69SBart Van Assche     int max_pn;
2227*44704f69SBart Van Assche     int any_err = 0;
2228*44704f69SBart Van Assche     sgj_state * jsp = &op->json_st;
2229*44704f69SBart Van Assche     char b[80];
2230*44704f69SBart Van Assche 
2231*44704f69SBart Van Assche     max_pn = (op->page_given ? op->vpd_pn : 0xff);
2232*44704f69SBart Van Assche     switch (op->examine) {
2233*44704f69SBart Van Assche     case 1:
2234*44704f69SBart Van Assche         start = 0x80;
2235*44704f69SBart Van Assche         break;
2236*44704f69SBart Van Assche     case 2:
2237*44704f69SBart Van Assche         start = 0x0;
2238*44704f69SBart Van Assche         break;
2239*44704f69SBart Van Assche     default:
2240*44704f69SBart Van Assche         start = 0xc0;
2241*44704f69SBart Van Assche         break;
2242*44704f69SBart Van Assche     }
2243*44704f69SBart Van Assche     if (start > max_pn) {       /* swap them around */
2244*44704f69SBart Van Assche         k = start;
2245*44704f69SBart Van Assche         start = max_pn;
2246*44704f69SBart Van Assche         max_pn = k;
2247*44704f69SBart Van Assche     }
2248*44704f69SBart Van Assche     for (k = start; k <= max_pn; ++k) {
2249*44704f69SBart Van Assche         op->vpd_pn = k;
2250*44704f69SBart Van Assche         if (first)
2251*44704f69SBart Van Assche             first = false;
2252*44704f69SBart Van Assche         else if (got_one) {
2253*44704f69SBart Van Assche             sgj_pr_hr(jsp, "\n");
2254*44704f69SBart Van Assche             got_one = false;
2255*44704f69SBart Van Assche         }
2256*44704f69SBart Van Assche         if (op->do_long)
2257*44704f69SBart Van Assche             snprintf(b, sizeof(b), "[0x%x] ", k);
2258*44704f69SBart Van Assche         else
2259*44704f69SBart Van Assche             b[0] = '\0';
2260*44704f69SBart Van Assche         res = svpd_decode_t10(sg_fd, op, jop, 0, 0, b);
2261*44704f69SBart Van Assche         if (SG_LIB_CAT_OTHER == res) {
2262*44704f69SBart Van Assche             res = svpd_decode_vendor(sg_fd, op, jop, 0);
2263*44704f69SBart Van Assche             if (SG_LIB_CAT_OTHER == res)
2264*44704f69SBart Van Assche                 res = svpd_unable_to_decode(sg_fd, op, 0, 0);
2265*44704f69SBart Van Assche         }
2266*44704f69SBart Van Assche         if (! op->do_quiet) {
2267*44704f69SBart Van Assche             if (SG_LIB_CAT_ABORTED_COMMAND == res)
2268*44704f69SBart Van Assche                 pr2serr("fetching VPD page failed, aborted command\n");
2269*44704f69SBart Van Assche             else if (res && (SG_LIB_CAT_ILLEGAL_REQ != res)) {
2270*44704f69SBart Van Assche                 /* SG_LIB_CAT_ILLEGAL_REQ expected as well examine all */
2271*44704f69SBart Van Assche                 sg_get_category_sense_str(res, sizeof(b), b, op->verbose);
2272*44704f69SBart Van Assche                 pr2serr("fetching VPD page failed: %s\n", b);
2273*44704f69SBart Van Assche             }
2274*44704f69SBart Van Assche         }
2275*44704f69SBart Van Assche         if (res && (SG_LIB_CAT_ILLEGAL_REQ != res))
2276*44704f69SBart Van Assche             any_err = res;
2277*44704f69SBart Van Assche         if (0 == res)
2278*44704f69SBart Van Assche             got_one = true;
2279*44704f69SBart Van Assche     }
2280*44704f69SBart Van Assche     return any_err;
2281*44704f69SBart Van Assche }
2282*44704f69SBart Van Assche 
2283*44704f69SBart Van Assche 
2284*44704f69SBart Van Assche int
main(int argc,char * argv[])2285*44704f69SBart Van Assche main(int argc, char * argv[])
2286*44704f69SBart Van Assche {
2287*44704f69SBart Van Assche     bool as_json;
2288*44704f69SBart Van Assche     int c, res, matches;
2289*44704f69SBart Van Assche     int sg_fd = -1;
2290*44704f69SBart Van Assche     int inhex_len = 0;
2291*44704f69SBart Van Assche     int inraw_len = 0;
2292*44704f69SBart Van Assche     int ret = 0;
2293*44704f69SBart Van Assche     int subvalue = 0;
2294*44704f69SBart Van Assche     const char * cp;
2295*44704f69SBart Van Assche     sgj_state * jsp;
2296*44704f69SBart Van Assche     sgj_opaque_p jop = NULL;
2297*44704f69SBart Van Assche     const struct svpd_values_name_t * vnp;
2298*44704f69SBart Van Assche     struct opts_t opts SG_C_CPP_ZERO_INIT;
2299*44704f69SBart Van Assche     struct opts_t * op = &opts;
2300*44704f69SBart Van Assche 
2301*44704f69SBart Van Assche     op->invoker = SG_VPD_INV_SG_VPD;
2302*44704f69SBart Van Assche     dup_sanity_chk((int)sizeof(opts), (int)sizeof(*vnp));
2303*44704f69SBart Van Assche     op->vend_prod_num = -1;
2304*44704f69SBart Van Assche     while (1) {
2305*44704f69SBart Van Assche         int option_index = 0;
2306*44704f69SBart Van Assche 
2307*44704f69SBart Van Assche         c = getopt_long(argc, argv, "aeEfhHiI:j::lm:M:p:qQ:rvV", long_options,
2308*44704f69SBart Van Assche                         &option_index);
2309*44704f69SBart Van Assche         if (c == -1)
2310*44704f69SBart Van Assche             break;
2311*44704f69SBart Van Assche 
2312*44704f69SBart Van Assche         switch (c) {
2313*44704f69SBart Van Assche         case 'a':
2314*44704f69SBart Van Assche             op->do_all = true;
2315*44704f69SBart Van Assche             break;
2316*44704f69SBart Van Assche         case 'e':
2317*44704f69SBart Van Assche             op->do_enum = true;
2318*44704f69SBart Van Assche             break;
2319*44704f69SBart Van Assche         case 'E':
2320*44704f69SBart Van Assche             ++op->examine;
2321*44704f69SBart Van Assche             op->examine_given = true;
2322*44704f69SBart Van Assche             break;
2323*44704f69SBart Van Assche         case 'f':
2324*44704f69SBart Van Assche             op->do_force = true;
2325*44704f69SBart Van Assche             break;
2326*44704f69SBart Van Assche         case 'h':
2327*44704f69SBart Van Assche         case '?':
2328*44704f69SBart Van Assche             usage();
2329*44704f69SBart Van Assche             return 0;
2330*44704f69SBart Van Assche         case 'H':
2331*44704f69SBart Van Assche             ++op->do_hex;
2332*44704f69SBart Van Assche             break;
2333*44704f69SBart Van Assche         case 'i':
2334*44704f69SBart Van Assche             ++op->do_ident;
2335*44704f69SBart Van Assche             break;
2336*44704f69SBart Van Assche         case 'I':
2337*44704f69SBart Van Assche             if (op->inhex_fn) {
2338*44704f69SBart Van Assche                 pr2serr("only one '--inhex=' option permitted\n");
2339*44704f69SBart Van Assche                 usage();
2340*44704f69SBart Van Assche                 return SG_LIB_SYNTAX_ERROR;
2341*44704f69SBart Van Assche             } else
2342*44704f69SBart Van Assche                 op->inhex_fn = optarg;
2343*44704f69SBart Van Assche             break;
2344*44704f69SBart Van Assche         case 'j':
2345*44704f69SBart Van Assche             if (! sgj_init_state(&op->json_st, optarg)) {
2346*44704f69SBart Van Assche                 int bad_char = op->json_st.first_bad_char;
2347*44704f69SBart Van Assche                 char e[1500];
2348*44704f69SBart Van Assche 
2349*44704f69SBart Van Assche                 if (bad_char) {
2350*44704f69SBart Van Assche                     pr2serr("bad argument to --json= option, unrecognized "
2351*44704f69SBart Van Assche                             "character '%c'\n\n", bad_char);
2352*44704f69SBart Van Assche                 }
2353*44704f69SBart Van Assche                 sg_json_usage(0, e, sizeof(e));
2354*44704f69SBart Van Assche                 pr2serr("%s", e);
2355*44704f69SBart Van Assche                 return SG_LIB_SYNTAX_ERROR;
2356*44704f69SBart Van Assche             }
2357*44704f69SBart Van Assche             break;
2358*44704f69SBart Van Assche         case 'l':
2359*44704f69SBart Van Assche             op->do_long = true;
2360*44704f69SBart Van Assche             break;
2361*44704f69SBart Van Assche         case 'm':
2362*44704f69SBart Van Assche             op->maxlen = sg_get_num(optarg);
2363*44704f69SBart Van Assche             if ((op->maxlen < 0) || (op->maxlen > MX_ALLOC_LEN)) {
2364*44704f69SBart Van Assche                 pr2serr("argument to '--maxlen' should be %d or less\n",
2365*44704f69SBart Van Assche                         MX_ALLOC_LEN);
2366*44704f69SBart Van Assche                 return SG_LIB_SYNTAX_ERROR;
2367*44704f69SBart Van Assche             }
2368*44704f69SBart Van Assche             if ((op->maxlen > 0) && (op->maxlen < MIN_MAXLEN)) {
2369*44704f69SBart Van Assche                 pr2serr("Warning: overriding '--maxlen' < %d, using "
2370*44704f69SBart Van Assche                         "default\n", MIN_MAXLEN);
2371*44704f69SBart Van Assche                 op->maxlen = 0;
2372*44704f69SBart Van Assche             }
2373*44704f69SBart Van Assche             break;
2374*44704f69SBart Van Assche         case 'M':
2375*44704f69SBart Van Assche             if (op->vend_prod) {
2376*44704f69SBart Van Assche                 pr2serr("only one '--vendor=' option permitted\n");
2377*44704f69SBart Van Assche                 usage();
2378*44704f69SBart Van Assche                 return SG_LIB_SYNTAX_ERROR;
2379*44704f69SBart Van Assche             } else
2380*44704f69SBart Van Assche                 op->vend_prod = optarg;
2381*44704f69SBart Van Assche             break;
2382*44704f69SBart Van Assche         case 'p':
2383*44704f69SBart Van Assche             if (op->page_str) {
2384*44704f69SBart Van Assche                 pr2serr("only one '--page=' option permitted\n");
2385*44704f69SBart Van Assche                 usage();
2386*44704f69SBart Van Assche                 return SG_LIB_SYNTAX_ERROR;
2387*44704f69SBart Van Assche             } else
2388*44704f69SBart Van Assche                 op->page_str = optarg;
2389*44704f69SBart Van Assche             op->page_given = true;
2390*44704f69SBart Van Assche             break;
2391*44704f69SBart Van Assche         case 'q':
2392*44704f69SBart Van Assche             op->do_quiet = true;
2393*44704f69SBart Van Assche             break;
2394*44704f69SBart Van Assche         case 'Q':
2395*44704f69SBart Van Assche             op->sinq_inraw_fn = optarg;
2396*44704f69SBart Van Assche             break;
2397*44704f69SBart Van Assche         case 'r':
2398*44704f69SBart Van Assche             ++op->do_raw;
2399*44704f69SBart Van Assche             break;
2400*44704f69SBart Van Assche         case 'v':
2401*44704f69SBart Van Assche             op->verbose_given = true;
2402*44704f69SBart Van Assche             ++op->verbose;
2403*44704f69SBart Van Assche             break;
2404*44704f69SBart Van Assche         case 'V':
2405*44704f69SBart Van Assche             op->version_given = true;
2406*44704f69SBart Van Assche             break;
2407*44704f69SBart Van Assche         default:
2408*44704f69SBart Van Assche             pr2serr("unrecognised option code 0x%x ??\n", c);
2409*44704f69SBart Van Assche             usage();
2410*44704f69SBart Van Assche             return SG_LIB_SYNTAX_ERROR;
2411*44704f69SBart Van Assche         }
2412*44704f69SBart Van Assche     }
2413*44704f69SBart Van Assche     if (optind < argc) {
2414*44704f69SBart Van Assche         if (NULL == op->device_name) {
2415*44704f69SBart Van Assche             op->device_name = argv[optind];
2416*44704f69SBart Van Assche             ++optind;
2417*44704f69SBart Van Assche         }
2418*44704f69SBart Van Assche         if (optind < argc) {
2419*44704f69SBart Van Assche             for (; optind < argc; ++optind)
2420*44704f69SBart Van Assche                 pr2serr("Unexpected extra argument: %s\n", argv[optind]);
2421*44704f69SBart Van Assche             usage();
2422*44704f69SBart Van Assche             return SG_LIB_SYNTAX_ERROR;
2423*44704f69SBart Van Assche         }
2424*44704f69SBart Van Assche     }
2425*44704f69SBart Van Assche 
2426*44704f69SBart Van Assche #ifdef DEBUG
2427*44704f69SBart Van Assche     pr2serr("In DEBUG mode, ");
2428*44704f69SBart Van Assche     if (op->verbose_given && op->version_given) {
2429*44704f69SBart Van Assche         pr2serr("but override: '-vV' given, zero verbose and continue\n");
2430*44704f69SBart Van Assche         op->verbose_given = false;
2431*44704f69SBart Van Assche         op->version_given = false;
2432*44704f69SBart Van Assche         op->verbose = 0;
2433*44704f69SBart Van Assche     } else if (! op->verbose_given) {
2434*44704f69SBart Van Assche         pr2serr("set '-vv'\n");
2435*44704f69SBart Van Assche         op->verbose = 2;
2436*44704f69SBart Van Assche     } else
2437*44704f69SBart Van Assche         pr2serr("keep verbose=%d\n", op->verbose);
2438*44704f69SBart Van Assche #else
2439*44704f69SBart Van Assche     if (op->verbose_given && op->version_given)
2440*44704f69SBart Van Assche         pr2serr("Not in DEBUG mode, so '-vV' has no special action\n");
2441*44704f69SBart Van Assche #endif
2442*44704f69SBart Van Assche     if (op->version_given) {
2443*44704f69SBart Van Assche         pr2serr("version: %s\n", version_str);
2444*44704f69SBart Van Assche         return 0;
2445*44704f69SBart Van Assche     }
2446*44704f69SBart Van Assche 
2447*44704f69SBart Van Assche     jsp = &op->json_st;
2448*44704f69SBart Van Assche     if (op->do_enum) {
2449*44704f69SBart Van Assche         if (op->device_name)
2450*44704f69SBart Van Assche             pr2serr("Device name %s ignored when --enumerate given\n",
2451*44704f69SBart Van Assche                     op->device_name);
2452*44704f69SBart Van Assche         if (op->vend_prod) {
2453*44704f69SBart Van Assche             if (isdigit((uint8_t)op->vend_prod[0])) {
2454*44704f69SBart Van Assche                 op->vend_prod_num = sg_get_num_nomult(op->vend_prod);
2455*44704f69SBart Van Assche                 if ((op->vend_prod_num < 0) || (op->vend_prod_num > 10)) {
2456*44704f69SBart Van Assche                     pr2serr("Bad vendor/product number after '--vendor=' "
2457*44704f69SBart Van Assche                             "option\n");
2458*44704f69SBart Van Assche                     return SG_LIB_SYNTAX_ERROR;
2459*44704f69SBart Van Assche                 }
2460*44704f69SBart Van Assche             } else {
2461*44704f69SBart Van Assche                 op->vend_prod_num = svpd_find_vp_num_by_acron(op->vend_prod);
2462*44704f69SBart Van Assche                 if (op->vend_prod_num < 0) {
2463*44704f69SBart Van Assche                     pr2serr("Bad vendor/product acronym after '--vendor=' "
2464*44704f69SBart Van Assche                             "option\n");
2465*44704f69SBart Van Assche                     return SG_LIB_SYNTAX_ERROR;
2466*44704f69SBart Van Assche                 }
2467*44704f69SBart Van Assche             }
2468*44704f69SBart Van Assche             svpd_enumerate_vendor(op->vend_prod_num);
2469*44704f69SBart Van Assche             return 0;
2470*44704f69SBart Van Assche         }
2471*44704f69SBart Van Assche         if (op->page_str) {
2472*44704f69SBart Van Assche             if ((0 == strcmp("-1", op->page_str)) ||
2473*44704f69SBart Van Assche                 (0 == strcmp("-2", op->page_str)))
2474*44704f69SBart Van Assche                 op->vpd_pn = VPD_NOPE_WANT_STD_INQ;
2475*44704f69SBart Van Assche             else if (isdigit((uint8_t)op->page_str[0])) {
2476*44704f69SBart Van Assche                 op->vpd_pn = sg_get_num_nomult(op->page_str);
2477*44704f69SBart Van Assche                 if ((op->vpd_pn < 0) || (op->vpd_pn > 255)) {
2478*44704f69SBart Van Assche                     pr2serr("Bad page code value after '-p' option\n");
2479*44704f69SBart Van Assche                     return SG_LIB_SYNTAX_ERROR;
2480*44704f69SBart Van Assche                 }
2481*44704f69SBart Van Assche             } else {
2482*44704f69SBart Van Assche                 pr2serr("with --enumerate only search using VPD page "
2483*44704f69SBart Van Assche                         "numbers\n");
2484*44704f69SBart Van Assche                 return SG_LIB_SYNTAX_ERROR;
2485*44704f69SBart Van Assche             }
2486*44704f69SBart Van Assche             matches = count_standard_vpds(op->vpd_pn);
2487*44704f69SBart Van Assche             if (0 == matches)
2488*44704f69SBart Van Assche                 matches = svpd_count_vendor_vpds(op->vpd_pn,
2489*44704f69SBart Van Assche                                                  op->vend_prod_num);
2490*44704f69SBart Van Assche             if (0 == matches)
2491*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "No matches found for VPD page number 0x%x\n",
2492*44704f69SBart Van Assche                           op->vpd_pn);
2493*44704f69SBart Van Assche         } else {        /* enumerate standard then vendor VPD pages */
2494*44704f69SBart Van Assche             sgj_pr_hr(jsp, "Standard VPD pages:\n");
2495*44704f69SBart Van Assche             enumerate_vpds(1, 1);
2496*44704f69SBart Van Assche         }
2497*44704f69SBart Van Assche         return 0;
2498*44704f69SBart Van Assche     }
2499*44704f69SBart Van Assche 
2500*44704f69SBart Van Assche     as_json = jsp->pr_as_json;
2501*44704f69SBart Van Assche     if (as_json)
2502*44704f69SBart Van Assche         jop = sgj_start_r(MY_NAME, version_str, argc, argv, jsp);
2503*44704f69SBart Van Assche 
2504*44704f69SBart Van Assche     if (op->page_str) {
2505*44704f69SBart Van Assche         if ('-' == op->page_str[0])
2506*44704f69SBart Van Assche             op->vpd_pn = VPD_NOPE_WANT_STD_INQ;
2507*44704f69SBart Van Assche         else if (isalpha((uint8_t)op->page_str[0])) {
2508*44704f69SBart Van Assche             vnp = sdp_find_vpd_by_acron(op->page_str);
2509*44704f69SBart Van Assche             if (NULL == vnp) {
2510*44704f69SBart Van Assche                 vnp = svpd_find_vendor_by_acron(op->page_str);
2511*44704f69SBart Van Assche                 if (NULL == vnp) {
2512*44704f69SBart Van Assche                     if (0 == strcmp("stdinq", op->page_str)) {
2513*44704f69SBart Van Assche                         vnp = sdp_find_vpd_by_acron("sinq");
2514*44704f69SBart Van Assche                     } else {
2515*44704f69SBart Van Assche                         pr2serr("abbreviation doesn't match a VPD page\n");
2516*44704f69SBart Van Assche                         sgj_pr_hr(jsp, "Available standard VPD pages:\n");
2517*44704f69SBart Van Assche                         enumerate_vpds(1, 1);
2518*44704f69SBart Van Assche                         ret = SG_LIB_SYNTAX_ERROR;
2519*44704f69SBart Van Assche                         goto fini;
2520*44704f69SBart Van Assche                     }
2521*44704f69SBart Van Assche                 }
2522*44704f69SBart Van Assche             }
2523*44704f69SBart Van Assche             op->vpd_pn = vnp->value;
2524*44704f69SBart Van Assche             subvalue = vnp->subvalue;
2525*44704f69SBart Van Assche             op->vend_prod_num = subvalue;
2526*44704f69SBart Van Assche         } else {
2527*44704f69SBart Van Assche             cp = strchr(op->page_str, ',');
2528*44704f69SBart Van Assche             if (cp && op->vend_prod) {
2529*44704f69SBart Van Assche                 pr2serr("the --page=pg,vp and the --vendor=vp forms overlap, "
2530*44704f69SBart Van Assche                         "choose one or the other\n");
2531*44704f69SBart Van Assche                 ret = SG_LIB_SYNTAX_ERROR;
2532*44704f69SBart Van Assche                 goto fini;
2533*44704f69SBart Van Assche             }
2534*44704f69SBart Van Assche             op->vpd_pn = sg_get_num_nomult(op->page_str);
2535*44704f69SBart Van Assche             if ((op->vpd_pn < 0) || (op->vpd_pn > 255)) {
2536*44704f69SBart Van Assche                 pr2serr("Bad page code value after '-p' option\n");
2537*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "Available standard VPD pages:\n");
2538*44704f69SBart Van Assche                 enumerate_vpds(1, 1);
2539*44704f69SBart Van Assche                 ret = SG_LIB_SYNTAX_ERROR;
2540*44704f69SBart Van Assche                 goto fini;
2541*44704f69SBart Van Assche             }
2542*44704f69SBart Van Assche             if (cp) {
2543*44704f69SBart Van Assche                 if (isdigit((uint8_t)*(cp + 1)))
2544*44704f69SBart Van Assche                     op->vend_prod_num = sg_get_num_nomult(cp + 1);
2545*44704f69SBart Van Assche                 else
2546*44704f69SBart Van Assche                     op->vend_prod_num = svpd_find_vp_num_by_acron(cp + 1);
2547*44704f69SBart Van Assche                 if ((op->vend_prod_num < 0) || (op->vend_prod_num > 255)) {
2548*44704f69SBart Van Assche                     pr2serr("Bad vendor/product acronym after comma in '-p' "
2549*44704f69SBart Van Assche                             "option\n");
2550*44704f69SBart Van Assche                     if (op->vend_prod_num < 0)
2551*44704f69SBart Van Assche                         svpd_enumerate_vendor(-1);
2552*44704f69SBart Van Assche                     ret = SG_LIB_SYNTAX_ERROR;
2553*44704f69SBart Van Assche                     goto fini;
2554*44704f69SBart Van Assche                 }
2555*44704f69SBart Van Assche                 subvalue = op->vend_prod_num;
2556*44704f69SBart Van Assche             } else if (op->vend_prod) {
2557*44704f69SBart Van Assche                 if (isdigit((uint8_t)op->vend_prod[0]))
2558*44704f69SBart Van Assche                     op->vend_prod_num = sg_get_num_nomult(op->vend_prod);
2559*44704f69SBart Van Assche                 else
2560*44704f69SBart Van Assche                     op->vend_prod_num =
2561*44704f69SBart Van Assche                         svpd_find_vp_num_by_acron(op->vend_prod);
2562*44704f69SBart Van Assche                 if ((op->vend_prod_num < 0) || (op->vend_prod_num > 255)) {
2563*44704f69SBart Van Assche                     pr2serr("Bad vendor/product acronym after '--vendor=' "
2564*44704f69SBart Van Assche                             "option\n");
2565*44704f69SBart Van Assche                     svpd_enumerate_vendor(-1);
2566*44704f69SBart Van Assche                     ret = SG_LIB_SYNTAX_ERROR;
2567*44704f69SBart Van Assche                     goto fini;
2568*44704f69SBart Van Assche                 }
2569*44704f69SBart Van Assche                 subvalue = op->vend_prod_num;
2570*44704f69SBart Van Assche             }
2571*44704f69SBart Van Assche         }
2572*44704f69SBart Van Assche         if (op->verbose > 3)
2573*44704f69SBart Van Assche                pr2serr("'--page=' matched pn=%d [0x%x], subvalue=%d\n",
2574*44704f69SBart Van Assche                        op->vpd_pn, op->vpd_pn, subvalue);
2575*44704f69SBart Van Assche     } else if (op->vend_prod) {
2576*44704f69SBart Van Assche         if (isdigit((uint8_t)op->vend_prod[0]))
2577*44704f69SBart Van Assche             op->vend_prod_num = sg_get_num_nomult(op->vend_prod);
2578*44704f69SBart Van Assche         else
2579*44704f69SBart Van Assche             op->vend_prod_num = svpd_find_vp_num_by_acron(op->vend_prod);
2580*44704f69SBart Van Assche         if ((op->vend_prod_num < 0) || (op->vend_prod_num > 255)) {
2581*44704f69SBart Van Assche             pr2serr("Bad vendor/product acronym after '--vendor=' "
2582*44704f69SBart Van Assche                     "option\n");
2583*44704f69SBart Van Assche             svpd_enumerate_vendor(-1);
2584*44704f69SBart Van Assche             ret = SG_LIB_SYNTAX_ERROR;
2585*44704f69SBart Van Assche             goto fini;
2586*44704f69SBart Van Assche         }
2587*44704f69SBart Van Assche         subvalue = op->vend_prod_num;
2588*44704f69SBart Van Assche     }
2589*44704f69SBart Van Assche 
2590*44704f69SBart Van Assche     rsp_buff = sg_memalign(rsp_buff_sz, 0 /* page align */, &free_rsp_buff,
2591*44704f69SBart Van Assche                            false);
2592*44704f69SBart Van Assche     if (NULL == rsp_buff) {
2593*44704f69SBart Van Assche         pr2serr("Unable to allocate %d bytes on heap\n", rsp_buff_sz);
2594*44704f69SBart Van Assche         ret = sg_convert_errno(ENOMEM);
2595*44704f69SBart Van Assche         goto fini;
2596*44704f69SBart Van Assche     }
2597*44704f69SBart Van Assche     if (op->sinq_inraw_fn) {
2598*44704f69SBart Van Assche         if ((ret = sg_f2hex_arr(op->sinq_inraw_fn, true, false, rsp_buff,
2599*44704f69SBart Van Assche                                 &inraw_len, rsp_buff_sz))) {
2600*44704f69SBart Van Assche             goto err_out;
2601*44704f69SBart Van Assche         }
2602*44704f69SBart Van Assche         if (inraw_len < 36) {
2603*44704f69SBart Van Assche             pr2serr("Unable to read 36 or more bytes from %s\n",
2604*44704f69SBart Van Assche                     op->sinq_inraw_fn);
2605*44704f69SBart Van Assche             ret = SG_LIB_FILE_ERROR;
2606*44704f69SBart Van Assche             goto err_out;
2607*44704f69SBart Van Assche         }
2608*44704f69SBart Van Assche         memcpy(op->std_inq_a,  rsp_buff, 36);
2609*44704f69SBart Van Assche         op->std_inq_a_valid = true;
2610*44704f69SBart Van Assche     }
2611*44704f69SBart Van Assche     if (op->inhex_fn) {
2612*44704f69SBart Van Assche         if (op->device_name) {
2613*44704f69SBart Van Assche             pr2serr("Cannot have both a DEVICE and --inhex= option\n");
2614*44704f69SBart Van Assche             ret = SG_LIB_SYNTAX_ERROR;
2615*44704f69SBart Van Assche             goto err_out;
2616*44704f69SBart Van Assche         }
2617*44704f69SBart Van Assche         if ((ret = sg_f2hex_arr(op->inhex_fn, !!op->do_raw, false, rsp_buff,
2618*44704f69SBart Van Assche                                 &inhex_len, rsp_buff_sz))) {
2619*44704f69SBart Van Assche             goto err_out;
2620*44704f69SBart Van Assche         }
2621*44704f69SBart Van Assche         if (op->verbose > 2)
2622*44704f69SBart Van Assche             pr2serr("Read %d [0x%x] bytes of user supplied data\n", inhex_len,
2623*44704f69SBart Van Assche                     inhex_len);
2624*44704f69SBart Van Assche         if (op->verbose > 3)
2625*44704f69SBart Van Assche             hex2stderr(rsp_buff, inhex_len, 0);
2626*44704f69SBart Van Assche         op->do_raw = 0;         /* don't want raw on output with --inhex= */
2627*44704f69SBart Van Assche         if ((NULL == op->page_str) && (! op->do_all)) {
2628*44704f69SBart Van Assche             /* may be able to deduce VPD page */
2629*44704f69SBart Van Assche             if ((0x2 == (0xf & rsp_buff[3])) && (rsp_buff[2] > 2)) {
2630*44704f69SBart Van Assche                 if (op->verbose)
2631*44704f69SBart Van Assche                     pr2serr("Guessing from --inhex= this is a standard "
2632*44704f69SBart Van Assche                             "INQUIRY\n");
2633*44704f69SBart Van Assche             } else if (rsp_buff[2] <= 2) {
2634*44704f69SBart Van Assche                 if (op->verbose)
2635*44704f69SBart Van Assche                     pr2serr("Guessing from --inhex this is VPD page 0x%x\n",
2636*44704f69SBart Van Assche                             rsp_buff[1]);
2637*44704f69SBart Van Assche                 op->vpd_pn = rsp_buff[1];
2638*44704f69SBart Van Assche             } else {
2639*44704f69SBart Van Assche                 if (op->vpd_pn > 0x80) {
2640*44704f69SBart Van Assche                     op->vpd_pn = rsp_buff[1];
2641*44704f69SBart Van Assche                     if (op->verbose)
2642*44704f69SBart Van Assche                         pr2serr("Guessing from --inhex this is VPD page "
2643*44704f69SBart Van Assche                                 "0x%x\n", rsp_buff[1]);
2644*44704f69SBart Van Assche                 } else {
2645*44704f69SBart Van Assche                     op->vpd_pn = VPD_NOPE_WANT_STD_INQ;
2646*44704f69SBart Van Assche                     if (op->verbose)
2647*44704f69SBart Van Assche                         pr2serr("page number unclear from --inhex, hope "
2648*44704f69SBart Van Assche                                 "it's a standard INQUIRY response\n");
2649*44704f69SBart Van Assche                 }
2650*44704f69SBart Van Assche             }
2651*44704f69SBart Van Assche         }
2652*44704f69SBart Van Assche     } else if ((NULL == op->device_name) && (! op->std_inq_a_valid)) {
2653*44704f69SBart Van Assche         pr2serr("No DEVICE argument given\n\n");
2654*44704f69SBart Van Assche         usage();
2655*44704f69SBart Van Assche         ret = SG_LIB_SYNTAX_ERROR;
2656*44704f69SBart Van Assche         goto err_out;
2657*44704f69SBart Van Assche     }
2658*44704f69SBart Van Assche 
2659*44704f69SBart Van Assche     if (op->do_raw && op->do_hex) {
2660*44704f69SBart Van Assche         pr2serr("Can't do hex and raw at the same time\n");
2661*44704f69SBart Van Assche         usage();
2662*44704f69SBart Van Assche         ret = SG_LIB_SYNTAX_ERROR;
2663*44704f69SBart Van Assche         goto err_out;
2664*44704f69SBart Van Assche     }
2665*44704f69SBart Van Assche     if (op->do_ident) {
2666*44704f69SBart Van Assche         op->vpd_pn = VPD_DEVICE_ID;
2667*44704f69SBart Van Assche         if (op->do_ident > 1) {
2668*44704f69SBart Van Assche             if (! op->do_long)
2669*44704f69SBart Van Assche                 op->do_quiet = true;
2670*44704f69SBart Van Assche             subvalue = VPD_DI_SEL_LU;
2671*44704f69SBart Van Assche         }
2672*44704f69SBart Van Assche     }
2673*44704f69SBart Van Assche     if (op->do_raw) {
2674*44704f69SBart Van Assche         if (sg_set_binary_mode(STDOUT_FILENO) < 0) {
2675*44704f69SBart Van Assche             perror("sg_set_binary_mode");
2676*44704f69SBart Van Assche             ret = SG_LIB_FILE_ERROR;
2677*44704f69SBart Van Assche             goto err_out;
2678*44704f69SBart Van Assche         }
2679*44704f69SBart Van Assche     }
2680*44704f69SBart Van Assche 
2681*44704f69SBart Van Assche     if (op->inhex_fn) {
2682*44704f69SBart Van Assche         if ((0 == op->maxlen) || (inhex_len < op->maxlen))
2683*44704f69SBart Van Assche             op->maxlen = inhex_len;
2684*44704f69SBart Van Assche         if (op->do_all || op->page_given)
2685*44704f69SBart Van Assche             res = svpd_decode_all(-1, op, jop);
2686*44704f69SBart Van Assche         else {
2687*44704f69SBart Van Assche             res = svpd_decode_t10(-1, op, jop, subvalue, 0, NULL);
2688*44704f69SBart Van Assche             if (SG_LIB_CAT_OTHER == res) {
2689*44704f69SBart Van Assche                 res = svpd_decode_vendor(-1, op, jop, 0);
2690*44704f69SBart Van Assche                 if (SG_LIB_CAT_OTHER == res)
2691*44704f69SBart Van Assche                     res = svpd_unable_to_decode(-1, op, subvalue, 0);
2692*44704f69SBart Van Assche             }
2693*44704f69SBart Van Assche         }
2694*44704f69SBart Van Assche         ret = res;
2695*44704f69SBart Van Assche         goto err_out;
2696*44704f69SBart Van Assche     } else if (op->std_inq_a_valid && (NULL == op->device_name)) {
2697*44704f69SBart Van Assche         /* nothing else to do ... */
2698*44704f69SBart Van Assche         /* --sinq_inraw=RFN contents still in rsp_buff */
2699*44704f69SBart Van Assche         if (op->do_raw)
2700*44704f69SBart Van Assche             dStrRaw(rsp_buff, inraw_len);
2701*44704f69SBart Van Assche         else if (op->do_hex) {
2702*44704f69SBart Van Assche             if (! op->do_quiet && (op->do_hex < 3))
2703*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "Standard Inquiry data format:\n");
2704*44704f69SBart Van Assche             hex2stdout(rsp_buff, inraw_len, (1 == op->do_hex) ? 0 : -1);
2705*44704f69SBart Van Assche         } else
2706*44704f69SBart Van Assche             std_inq_decode(rsp_buff, inraw_len, op, jop);
2707*44704f69SBart Van Assche         ret = 0;
2708*44704f69SBart Van Assche         goto fini;
2709*44704f69SBart Van Assche     }
2710*44704f69SBart Van Assche 
2711*44704f69SBart Van Assche     if ((sg_fd = sg_cmds_open_device(op->device_name, true /* ro */,
2712*44704f69SBart Van Assche                                      op->verbose)) < 0) {
2713*44704f69SBart Van Assche         if (op->verbose > 0)
2714*44704f69SBart Van Assche             pr2serr("error opening file: %s: %s\n", op->device_name,
2715*44704f69SBart Van Assche                     safe_strerror(-sg_fd));
2716*44704f69SBart Van Assche         ret = sg_convert_errno(-sg_fd);
2717*44704f69SBart Van Assche         if (ret < 0)
2718*44704f69SBart Van Assche             ret = SG_LIB_FILE_ERROR;
2719*44704f69SBart Van Assche         goto err_out;
2720*44704f69SBart Van Assche     }
2721*44704f69SBart Van Assche 
2722*44704f69SBart Van Assche     if (op->examine_given) {
2723*44704f69SBart Van Assche         ret = svpd_examine_all(sg_fd, op, jop);
2724*44704f69SBart Van Assche     } else if (op->do_all)
2725*44704f69SBart Van Assche         ret = svpd_decode_all(sg_fd, op, jop);
2726*44704f69SBart Van Assche     else {
2727*44704f69SBart Van Assche         memset(rsp_buff, 0, rsp_buff_sz);
2728*44704f69SBart Van Assche 
2729*44704f69SBart Van Assche         res = svpd_decode_t10(sg_fd, op, jop, subvalue, 0, NULL);
2730*44704f69SBart Van Assche         if (SG_LIB_CAT_OTHER == res) {
2731*44704f69SBart Van Assche             res = svpd_decode_vendor(sg_fd, op, jop, 0);
2732*44704f69SBart Van Assche             if (SG_LIB_CAT_OTHER == res)
2733*44704f69SBart Van Assche                 res = svpd_unable_to_decode(sg_fd, op, subvalue, 0);
2734*44704f69SBart Van Assche         }
2735*44704f69SBart Van Assche         if (! op->do_quiet) {
2736*44704f69SBart Van Assche             if (SG_LIB_CAT_ABORTED_COMMAND == res)
2737*44704f69SBart Van Assche                 pr2serr("fetching VPD page failed, aborted command\n");
2738*44704f69SBart Van Assche             else if (res) {
2739*44704f69SBart Van Assche                 char b[80];
2740*44704f69SBart Van Assche 
2741*44704f69SBart Van Assche                 sg_get_category_sense_str(res, sizeof(b), b, op->verbose);
2742*44704f69SBart Van Assche                 pr2serr("fetching VPD page failed: %s\n", b);
2743*44704f69SBart Van Assche             }
2744*44704f69SBart Van Assche         }
2745*44704f69SBart Van Assche         ret = res;
2746*44704f69SBart Van Assche     }
2747*44704f69SBart Van Assche err_out:
2748*44704f69SBart Van Assche     if (free_rsp_buff)
2749*44704f69SBart Van Assche         free(free_rsp_buff);
2750*44704f69SBart Van Assche     if ((0 == op->verbose) && (! op->do_quiet)) {
2751*44704f69SBart Van Assche         if (! sg_if_can2stderr("sg_vpd failed: ", ret))
2752*44704f69SBart Van Assche             pr2serr("Some error occurred, try again with '-v' or '-vv' for "
2753*44704f69SBart Van Assche                     "more information\n");
2754*44704f69SBart Van Assche     }
2755*44704f69SBart Van Assche fini:
2756*44704f69SBart Van Assche     res = (sg_fd >= 0) ? sg_cmds_close_device(sg_fd) : 0;
2757*44704f69SBart Van Assche 
2758*44704f69SBart Van Assche     if (res < 0) {
2759*44704f69SBart Van Assche         pr2serr("close error: %s\n", safe_strerror(-res));
2760*44704f69SBart Van Assche         if (0 == ret)
2761*44704f69SBart Van Assche             ret = sg_convert_errno(-res);
2762*44704f69SBart Van Assche     }
2763*44704f69SBart Van Assche     ret = (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
2764*44704f69SBart Van Assche     if (as_json) {
2765*44704f69SBart Van Assche         if (0 == op->do_hex)
2766*44704f69SBart Van Assche             sgj_js2file(jsp, NULL, ret, stdout);
2767*44704f69SBart Van Assche         sgj_finish(jsp);
2768*44704f69SBart Van Assche     }
2769*44704f69SBart Van Assche     return ret;
2770*44704f69SBart Van Assche }
2771