1 /*
2  * Copyright (c) 2006-2016 Douglas Gilbert.
3  * All rights reserved.
4  * Use of this source code is governed by a BSD-style
5  * license that can be found in the BSD_LICENSE file.
6  */
7 
8 #include <unistd.h>
9 #include <fcntl.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <stdbool.h>
13 #include <string.h>
14 #include <ctype.h>
15 #include <getopt.h>
16 #define __STDC_FORMAT_MACROS 1
17 #include <inttypes.h>
18 #include <errno.h>
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 #include "sg_lib.h"
26 #include "sg_cmds_basic.h"
27 #include "sg_pt.h"
28 #include "sg_unaligned.h"
29 #include "sg_pr2serr.h"
30 
31 /* This utility program was originally written for the Linux OS SCSI subsystem.
32 
33    This program fetches Vital Product Data (VPD) pages from the given
34    device and outputs it as directed. VPD pages are obtained via a
35    SCSI INQUIRY command. Most of the data in this program is obtained
36    from the SCSI SPC-4 document at http://www.t10.org .
37 
38 */
39 
40 static const char * version_str = "1.14 20160217";  /* spc5r08 + sbc4r10 */
41 
42 
43 /* These structures are duplicates of those of the same name in
44  * sg_vpd_vendor.c . Take care that both are the same. */
45 struct opts_t {
46     int do_all;
47     int do_enum;
48     int do_hex;
49     int num_vpd;
50     int do_ident;
51     int do_long;
52     int maxlen;
53     int do_quiet;
54     int do_raw;
55     int vend_prod_num;
56     int verbose;
57     const char * device_name;
58     const char * page_str;
59     const char * inhex_fn;
60     const char * vend_prod;
61 };
62 
63 struct svpd_values_name_t {
64     int value;       /* VPD page number */
65     int subvalue;    /* to differentiate if value+pdt are not unique */
66     int pdt;         /* peripheral device type id, -1 is the default */
67                      /* (all or not applicable) value */
68     const char * acron;
69     const char * name;
70 };
71 
72 
73 void svpd_enumerate_vendor(int vend_prod_num);
74 int svpd_count_vendor_vpds(int num_vpd, int vend_prod_num);
75 int svpd_decode_vendor(int sg_fd, struct opts_t * op, int off);
76 const struct svpd_values_name_t * svpd_find_vendor_by_acron(const char * ap);
77 int svpd_find_vp_num_by_acron(const char * vp_ap);
78 const struct svpd_values_name_t * svpd_find_vendor_by_num(int page_num,
79                                                           int vend_prod_num);
80 int vpd_fetch_page_from_dev(int sg_fd, unsigned char * rp, int page,
81                             int mxlen, int vb, int * rlenp);
82 
83 
84 /* standard VPD pages, in ascending page number order */
85 #define VPD_SUPPORTED_VPDS 0x0
86 #define VPD_UNIT_SERIAL_NUM 0x80
87 #define VPD_IMP_OP_DEF 0x81     /* obsolete in SPC-2 */
88 #define VPD_ASCII_OP_DEF 0x82   /* obsolete in SPC-2 */
89 #define VPD_DEVICE_ID 0x83
90 #define VPD_SOFTW_INF_ID 0x84
91 #define VPD_MAN_NET_ADDR 0x85
92 #define VPD_EXT_INQ 0x86
93 #define VPD_MODE_PG_POLICY 0x87
94 #define VPD_SCSI_PORTS 0x88
95 #define VPD_ATA_INFO 0x89
96 #define VPD_POWER_CONDITION 0x8a
97 #define VPD_DEVICE_CONSTITUENTS 0x8b
98 #define VPD_CFA_PROFILE_INFO 0x8c
99 #define VPD_POWER_CONSUMPTION  0x8d
100 #define VPD_3PARTY_COPY 0x8f    /* 3PC, XCOPY, SPC-4, SBC-3 */
101 #define VPD_PROTO_LU 0x90
102 #define VPD_PROTO_PORT 0x91
103 #define VPD_BLOCK_LIMITS 0xb0   /* SBC-3 */
104 #define VPD_SA_DEV_CAP 0xb0     /* SSC-3 */
105 #define VPD_OSD_INFO 0xb0       /* OSD */
106 #define VPD_BLOCK_DEV_CHARS 0xb1 /* SBC-3 */
107 #define VPD_MAN_ASS_SN 0xb1     /* SSC-3, ADC-2 */
108 #define VPD_SECURITY_TOKEN 0xb1 /* OSD */
109 #define VPD_TA_SUPPORTED 0xb2   /* SSC-3 */
110 #define VPD_LB_PROVISIONING 0xb2   /* SBC-3 */
111 #define VPD_REFERRALS 0xb3   /* SBC-3 */
112 #define VPD_AUTOMATION_DEV_SN 0xb3   /* SSC-3 */
113 #define VPD_SUP_BLOCK_LENS 0xb4 /* SBC-4 */
114 #define VPD_DTDE_ADDRESS 0xb4   /* SSC-4 */
115 #define VPD_BLOCK_DEV_C_EXTENS 0xb5 /* SBC-4 */
116 #define VPD_LB_PROTECTION 0xb5  /* SSC-5 */
117 #define VPD_ZBC_DEV_CHARS 0xb6  /* ZBC */
118 #define VPD_BLOCK_LIMITS_EXT 0xb7   /* SBC-4 */
119 #define VPD_NO_RATHER_STD_INQ -2      /* request for standard inquiry */
120 
121 /* Device identification VPD page associations */
122 #define VPD_ASSOC_LU 0
123 #define VPD_ASSOC_TPORT 1
124 #define VPD_ASSOC_TDEVICE 2
125 
126 /* values for selection one or more associations (2**vpd_assoc),
127    except _AS_IS */
128 #define VPD_DI_SEL_LU 1
129 #define VPD_DI_SEL_TPORT 2
130 #define VPD_DI_SEL_TARGET 4
131 #define VPD_DI_SEL_AS_IS 32
132 
133 #define DEF_ALLOC_LEN 252
134 #define MX_ALLOC_LEN (0xc000 + 0x80)
135 #define VPD_ATA_INFO_LEN  572
136 
137 #define SENSE_BUFF_LEN  64       /* Arbitrary, could be larger */
138 #define INQUIRY_CMD     0x12
139 #define INQUIRY_CMDLEN  6
140 #define DEF_PT_TIMEOUT  60       /* 60 seconds */
141 
142 
143 unsigned char rsp_buff[MX_ALLOC_LEN + 2];
144 
145 static int decode_dev_ids(const char * print_if_found, unsigned char * buff,
146                           int len, int m_assoc, int m_desig_type,
147                           int m_code_set, const struct opts_t * op);
148 static void decode_transport_id(const char * leadin, unsigned char * ucp,
149                                 int len);
150 
151 static struct option long_options[] = {
152         {"all", no_argument, 0, 'a'},
153         {"enumerate", no_argument, 0, 'e'},
154         {"help", no_argument, 0, 'h'},
155         {"hex", no_argument, 0, 'H'},
156         {"ident", no_argument, 0, 'i'},
157         {"inhex", required_argument, 0, 'I'},
158         {"long", no_argument, 0, 'l'},
159         {"maxlen", required_argument, 0, 'm'},
160         {"page", required_argument, 0, 'p'},
161         {"quiet", no_argument, 0, 'q'},
162         {"raw", no_argument, 0, 'r'},
163         {"vendor", required_argument, 0, 'M'},
164         {"verbose", no_argument, 0, 'v'},
165         {"version", no_argument, 0, 'V'},
166         {0, 0, 0, 0},
167 };
168 
169 
170 /* arranged in alphabetical order by acronym */
171 static struct svpd_values_name_t standard_vpd_pg[] = {
172     {VPD_ATA_INFO, 0, -1, "ai", "ATA information (SAT)"},
173     {VPD_ASCII_OP_DEF, 0, -1, "aod",
174      "ASCII implemented operating definition (obsolete)"},
175     {VPD_AUTOMATION_DEV_SN, 0, 1, "adsn", "Automation device serial "
176      "number (SSC)"},
177     {VPD_BLOCK_LIMITS, 0, 0, "bl", "Block limits (SBC)"},
178     {VPD_BLOCK_LIMITS_EXT, 0, 0, "ble", "Block limits extension (SBC)"},
179     {VPD_BLOCK_DEV_CHARS, 0, 0, "bdc", "Block device characteristics "
180      "(SBC)"},
181     {VPD_BLOCK_DEV_C_EXTENS, 0, 0, "bdce", "Block device characteristics "
182      "extension (SBC)"},
183     {VPD_CFA_PROFILE_INFO, 0, 0, "cfa", "CFA profile information"},
184     {VPD_DEVICE_CONSTITUENTS, 0, -1, "dc", "Device constituents"},
185     {VPD_DEVICE_ID, 0, -1, "di", "Device identification"},
186     {VPD_DEVICE_ID, VPD_DI_SEL_AS_IS, -1, "di_asis", "Like 'di' "
187      "but designators ordered as found"},
188     {VPD_DEVICE_ID, VPD_DI_SEL_LU, -1, "di_lu", "Device identification, "
189      "lu only"},
190     {VPD_DEVICE_ID, VPD_DI_SEL_TPORT, -1, "di_port", "Device "
191      "identification, target port only"},
192     {VPD_DEVICE_ID, VPD_DI_SEL_TARGET, -1, "di_target", "Device "
193      "identification, target device only"},
194     {VPD_DTDE_ADDRESS, 0, 1, "dtde",
195      "Data transfer device element address (SSC)"},
196     {VPD_EXT_INQ, 0, -1, "ei", "Extended inquiry data"},
197     {VPD_IMP_OP_DEF, 0, -1, "iod",
198      "Implemented operating definition (obsolete)"},
199     {VPD_LB_PROTECTION, 0, 0, "lbpro", "Logical block protection (SSC)"},
200     {VPD_LB_PROVISIONING, 0, 0, "lbpv", "Logical block provisioning (SBC)"},
201     {VPD_MAN_ASS_SN, 0, 1, "mas", "Manufacturer assigned serial number (SSC)"},
202     {VPD_MAN_ASS_SN, 0, 0x12, "masa",
203      "Manufacturer assigned serial number (ADC)"},
204     {VPD_MAN_NET_ADDR, 0, -1, "mna", "Management network addresses"},
205     {VPD_MODE_PG_POLICY, 0, -1, "mpp", "Mode page policy"},
206     {VPD_OSD_INFO, 0, 0x11, "oi", "OSD information"},
207     {VPD_POWER_CONDITION, 0, -1, "pc", "Power condition"},
208     {VPD_POWER_CONSUMPTION, 0, -1, "psm", "Power consumption"},
209     {VPD_PROTO_LU, 0, -1, "pslu", "Protocol-specific logical unit "
210      "information"},
211     {VPD_PROTO_PORT, 0, -1, "pspo", "Protocol-specific port information"},
212     {VPD_REFERRALS, 0, 0, "ref", "Referrals (SBC)"},
213     {VPD_SA_DEV_CAP, 0, 1, "sad",
214      "Sequential access device capabilities (SSC)"},
215     {VPD_SOFTW_INF_ID, 0, -1, "sii", "Software interface identification"},
216     {VPD_NO_RATHER_STD_INQ, 0, -1, "sinq", "Standard inquiry response"},
217     {VPD_UNIT_SERIAL_NUM, 0, -1, "sn", "Unit serial number"},
218     {VPD_SCSI_PORTS, 0, -1, "sp", "SCSI ports"},
219     {VPD_SECURITY_TOKEN, 0, 0x11, "st", "Security token (OSD)"},
220     {VPD_SUP_BLOCK_LENS, 0, 0, "sbl", "Supported block lengths and "
221      "protection types (SBC)"},
222     {VPD_SUPPORTED_VPDS, 0, -1, "sv", "Supported VPD pages"},
223     {VPD_TA_SUPPORTED, 0, 1, "tas", "TapeAlert supported flags (SSC)"},
224     {VPD_3PARTY_COPY, 0, -1, "tpc", "Third party copy"},
225     {VPD_ZBC_DEV_CHARS, 0, -1, "zbdc", "Zoned block device characteristics"},
226         /* Use pdt of -1 since this page both for pdt=0 and pdt=0x14 */
227     {0, 0, 0, NULL, NULL},
228 };
229 
230 
231 static void
usage()232 usage()
233 {
234     pr2serr("Usage: sg_vpd  [--all] [--enumerate] [--help] [--hex] "
235             "[--ident]\n"
236             "               [--inhex=FN] [--long] [--maxlen=LEN] "
237             "[--page=PG] [--quiet]\n"
238             "               [--raw] [--vendor=VP] [--verbose] [--version] "
239             "DEVICE\n");
240     pr2serr("  where:\n"
241             "    --all|-a        output all pages listed in the supported "
242             "pages VPD\n"
243             "                    page\n"
244             "    --enumerate|-e    enumerate known VPD pages names (ignore "
245             "DEVICE),\n"
246             "                      can be used with --page=num to search\n"
247             "    --help|-h       output this usage message then exit\n"
248             "    --hex|-H        output page in ASCII hexadecimal\n"
249             "    --ident|-i      output device identification VPD page, "
250             "twice for\n"
251             "                    short logical unit designator (equiv: "
252             "'-qp di_lu')\n"
253             "    --inhex=FN|-I FN    read ASCII hex from file FN instead of "
254             "DEVICE;\n"
255             "                        if used with --raw then read binary "
256             "from FN\n"
257             "    --long|-l       perform extra decoding\n"
258             "    --maxlen=LEN|-m LEN    max response length (allocation "
259             "length in cdb)\n"
260             "                           (def: 0 -> 252 bytes)\n"
261             "    --page=PG|-p PG    fetch VPD page where PG is an "
262             "acronym, or a decimal\n"
263             "                       number unless hex indicator "
264             "is given (e.g. '0x83')\n"
265             "    --quiet|-q      suppress some output when decoding\n"
266             "    --raw|-r        output page in binary; if --inhex=FN is "
267             "also\n"
268             "                    given, FN is in binary (else FN is in "
269             "hex)\n"
270             "    --vendor=VP | -M VP    vendor/product abbreviation [or "
271             "number]\n"
272             "    --verbose|-v    increase verbosity\n"
273             "    --version|-V    print version string and exit\n\n"
274             "Fetch Vital Product Data (VPD) page using SCSI INQUIRY or "
275             "decodes VPD\npage response held in file FN. To list available "
276             "pages use '-e'. Also\n'-p -1' yields the standard INQUIRY "
277             "response.\n");
278 }
279 
280 /* Read ASCII hex bytes or binary from fname (a file named '-' taken as
281  * stdin). If reading ASCII hex then there should be either one entry per
282  * line or a comma, space or tab separated list of bytes. If no_space is
283  * set then a string of ACSII hex digits is expected, 2 per byte. Everything
284  * from and including a '#' on a line is ignored. Returns 0 if ok, or 1 if
285  * error. */
286 static int
f2hex_arr(const char * fname,int as_binary,int no_space,unsigned char * mp_arr,int * mp_arr_len,int max_arr_len)287 f2hex_arr(const char * fname, int as_binary, int no_space,
288           unsigned char * mp_arr, int * mp_arr_len, int max_arr_len)
289 {
290     int fn_len, in_len, k, j, m, split_line, fd;
291     bool has_stdin;
292     unsigned int h;
293     const char * lcp;
294     FILE * fp;
295     char line[512];
296     char carry_over[4];
297     int off = 0;
298     struct stat a_stat;
299 
300     if ((NULL == fname) || (NULL == mp_arr) || (NULL == mp_arr_len))
301         return 1;
302     fn_len = strlen(fname);
303     if (0 == fn_len)
304         return 1;
305     has_stdin = ((1 == fn_len) && ('-' == fname[0]));   /* read from stdin */
306     if (as_binary) {
307         if (has_stdin)
308             fd = STDIN_FILENO;
309         else {
310             fd = open(fname, O_RDONLY);
311             if (fd < 0) {
312                 pr2serr("unable to open binary file %s: %s\n", fname,
313                          safe_strerror(errno));
314                 return 1;
315             }
316         }
317         k = read(fd, mp_arr, max_arr_len);
318         if (k <= 0) {
319             if (0 == k)
320                 pr2serr("read 0 bytes from binary file %s\n", fname);
321             else
322                 pr2serr("read from binary file %s: %s\n", fname,
323                         safe_strerror(errno));
324             if (! has_stdin)
325                 close(fd);
326             return 1;
327         }
328         if ((0 == fstat(fd, &a_stat)) && S_ISFIFO(a_stat.st_mode)) {
329             /* pipe; keep reading till error or 0 read */
330             while (k < max_arr_len) {
331                 m = read(fd, mp_arr + k, max_arr_len - k);
332                 if (0 == m)
333                    break;
334                 if (m < 0) {
335                     pr2serr("read from binary pipe %s: %s\n", fname,
336                             safe_strerror(errno));
337                     if (! has_stdin)
338                         close(fd);
339                     return 1;
340                 }
341                 k += m;
342             }
343         }
344         *mp_arr_len = k;
345         if (! has_stdin)
346             close(fd);
347         return 0;
348     } else {    /* So read the file as ASCII hex */
349         if (has_stdin)
350             fp = stdin;
351         else {
352             fp = fopen(fname, "r");
353             if (NULL == fp) {
354                 pr2serr("Unable to open %s for reading\n", fname);
355                 return 1;
356             }
357         }
358      }
359 
360     carry_over[0] = 0;
361     for (j = 0; j < 512; ++j) {
362         if (NULL == fgets(line, sizeof(line), fp))
363             break;
364         in_len = strlen(line);
365         if (in_len > 0) {
366             if ('\n' == line[in_len - 1]) {
367                 --in_len;
368                 line[in_len] = '\0';
369                 split_line = 0;
370             } else
371                 split_line = 1;
372         }
373         if (in_len < 1) {
374             carry_over[0] = 0;
375             continue;
376         }
377         if (carry_over[0]) {
378             if (isxdigit(line[0])) {
379                 carry_over[1] = line[0];
380                 carry_over[2] = '\0';
381                 if (1 == sscanf(carry_over, "%4x", &h))
382                     mp_arr[off - 1] = h;       /* back up and overwrite */
383                 else {
384                     pr2serr("%s: carry_over error ['%s'] around line %d\n",
385                             __func__, carry_over, j + 1);
386                     goto bad;
387                 }
388                 lcp = line + 1;
389                 --in_len;
390             } else
391                 lcp = line;
392             carry_over[0] = 0;
393         } else
394             lcp = line;
395 
396         m = strspn(lcp, " \t");
397         if (m == in_len)
398             continue;
399         lcp += m;
400         in_len -= m;
401         if ('#' == *lcp)
402             continue;
403         k = strspn(lcp, "0123456789aAbBcCdDeEfF ,\t");
404         if ((k < in_len) && ('#' != lcp[k]) && ('\r' != lcp[k])) {
405             pr2serr("%s: syntax error at line %d, pos %d\n", __func__,
406                     j + 1, m + k + 1);
407             goto bad;
408         }
409         if (no_space) {
410             for (k = 0; isxdigit(*lcp) && isxdigit(*(lcp + 1));
411                  ++k, lcp += 2) {
412                 if (1 != sscanf(lcp, "%2x", &h)) {
413                     pr2serr("%s: bad hex number in line %d, pos %d\n",
414                             __func__, j + 1, (int)(lcp - line + 1));
415                     goto bad;
416                 }
417                 if ((off + k) >= max_arr_len) {
418                     pr2serr("%s: array length exceeded\n", __func__);
419                     goto bad;
420                 }
421                 mp_arr[off + k] = h;
422             }
423             if (isxdigit(*lcp) && (! isxdigit(*(lcp + 1))))
424                 carry_over[0] = *lcp;
425             off += k;
426         } else {
427             for (k = 0; k < 1024; ++k) {
428                 if (1 == sscanf(lcp, "%10x", &h)) {
429                     if (h > 0xff) {
430                         pr2serr("%s: hex number larger than 0xff in line "
431                                 "%d, pos %d\n", __func__, j + 1,
432                                 (int)(lcp - line + 1));
433                         goto bad;
434                     }
435                     if (split_line && (1 == strlen(lcp))) {
436                         /* single trailing hex digit might be a split pair */
437                         carry_over[0] = *lcp;
438                     }
439                     if ((off + k) >= max_arr_len) {
440                         pr2serr("%s: array length exceeded\n", __func__);
441                         goto bad;
442                     }
443                     mp_arr[off + k] = h;
444                     lcp = strpbrk(lcp, " ,\t");
445                     if (NULL == lcp)
446                         break;
447                     lcp += strspn(lcp, " ,\t");
448                     if ('\0' == *lcp)
449                         break;
450                 } else {
451                     if (('#' == *lcp) || ('\r' == *lcp)) {
452                         --k;
453                         break;
454                     }
455                     pr2serr("%s: error in line %d, at pos %d\n", __func__,
456                             j + 1, (int)(lcp - line + 1));
457                     goto bad;
458                 }
459             }
460             off += (k + 1);
461         }
462     }
463     *mp_arr_len = off;
464     if (stdin != fp)
465         fclose(fp);
466     return 0;
467 bad:
468     if (stdin != fp)
469         fclose(fp);
470     return 1;
471 }
472 
473 /* Local version of sg_ll_inquiry() [found in libsgutils] that additionally
474  * passes back resid. Same return values as sg_ll_inquiry() (0 is good). */
475 static int
pt_inquiry(int sg_fd,int evpd,int pg_op,void * resp,int mx_resp_len,int * residp,int noisy,int verbose)476 pt_inquiry(int sg_fd, int evpd, int pg_op, void * resp, int mx_resp_len,
477            int * residp, int noisy, int verbose)
478 {
479     int res, ret, k, sense_cat, resid;
480     unsigned char inqCmdBlk[INQUIRY_CMDLEN] = {INQUIRY_CMD, 0, 0, 0, 0, 0};
481     unsigned char sense_b[SENSE_BUFF_LEN];
482     unsigned char * up;
483     struct sg_pt_base * ptvp;
484 
485     if (evpd)
486         inqCmdBlk[1] |= 1;
487     inqCmdBlk[2] = (unsigned char)pg_op;
488     /* 16 bit allocation length (was 8) is a recent SPC-3 addition */
489     sg_put_unaligned_be16((uint16_t)mx_resp_len, inqCmdBlk + 3);
490     if (verbose) {
491         pr2serr("    inquiry cdb: ");
492         for (k = 0; k < INQUIRY_CMDLEN; ++k)
493             pr2serr("%02x ", inqCmdBlk[k]);
494         pr2serr("\n");
495     }
496     if (resp && (mx_resp_len > 0)) {
497         up = (unsigned char *)resp;
498         up[0] = 0x7f;   /* defensive prefill */
499         if (mx_resp_len > 4)
500             up[4] = 0;
501     }
502     ptvp = construct_scsi_pt_obj();
503     if (NULL == ptvp) {
504         pr2serr("%s: out of memory\n", __func__);
505         return -1;
506     }
507     set_scsi_pt_cdb(ptvp, inqCmdBlk, sizeof(inqCmdBlk));
508     set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
509     set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
510     res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
511     ret = sg_cmds_process_resp(ptvp, "inquiry", res, mx_resp_len, sense_b,
512                                noisy, verbose, &sense_cat);
513     resid = get_scsi_pt_resid(ptvp);
514     if (residp)
515         *residp = resid;
516     destruct_scsi_pt_obj(ptvp);
517     if (-1 == ret)
518         ;
519     else if (-2 == ret) {
520         switch (sense_cat) {
521         case SG_LIB_CAT_RECOVERED:
522         case SG_LIB_CAT_NO_SENSE:
523             ret = 0;
524             break;
525         default:
526             ret = sense_cat;
527             break;
528         }
529     } else if (ret < 4) {
530         if (verbose)
531             pr2serr("%s: got too few bytes (%d)\n", __func__, ret);
532         ret = SG_LIB_CAT_MALFORMED;
533     } else
534         ret = 0;
535 
536     if (resid > 0) {
537         if (resid > mx_resp_len) {
538             pr2serr("INQUIRY resid (%d) should never exceed requested "
539                     "len=%d\n", resid, mx_resp_len);
540             return ret ? ret : SG_LIB_CAT_MALFORMED;
541         }
542         /* zero unfilled section of response buffer */
543         memset((unsigned char *)resp + (mx_resp_len - resid), 0, resid);
544     }
545     return ret;
546 }
547 
548 /* mxlen is command line --maxlen=LEN option (def: 0) or -1 for a VPD page
549  * with a short length (1 byte). Returns 0 for success. */
550 int     /* global: use by sg_vpd_vendor.c */
vpd_fetch_page_from_dev(int sg_fd,unsigned char * rp,int page,int mxlen,int vb,int * rlenp)551 vpd_fetch_page_from_dev(int sg_fd, unsigned char * rp, int page,
552                         int mxlen, int vb, int * rlenp)
553 {
554     int res, resid, rlen, len, n;
555 
556     if (sg_fd < 0) {
557         len = sg_get_unaligned_be16(rp + 2) + 4;
558         if (vb && (len > mxlen))
559             pr2serr("warning: VPD page's length (%d) > bytes in --inhex=FN "
560                     "file (%d)\n",  len , mxlen);
561         if (rlenp)
562             *rlenp = (len < mxlen) ? len : mxlen;
563         return 0;
564     }
565     if (mxlen > MX_ALLOC_LEN) {
566         pr2serr("--maxlen=LEN too long: %d > %d\n", mxlen, MX_ALLOC_LEN);
567         return SG_LIB_SYNTAX_ERROR;
568     }
569     n = (mxlen > 0) ? mxlen : DEF_ALLOC_LEN;
570     res = pt_inquiry(sg_fd, 1, page, rp, n, &resid, 1, vb);
571     if (res)
572         return res;
573     rlen = n - resid;
574     if (rlen < 4) {
575         pr2serr("VPD response too short (len=%d)\n", rlen);
576         return SG_LIB_CAT_MALFORMED;
577     }
578     if (page != rp[1]) {
579         pr2serr("invalid VPD response; probably a STANDARD INQUIRY "
580                 "response\n");
581         n = (rlen < 32) ? rlen : 32;
582         if (vb) {
583             pr2serr("First %d bytes of bad response\n", n);
584             dStrHexErr((const char *)rp, n, 0);
585         }
586         return SG_LIB_CAT_MALFORMED;
587     } else if ((0x80 == page) && (0x2 == rp[2]) && (0x2 == rp[3])) {
588         /* could be a Unit Serial number VPD page with a very long
589          * length of 4+514 bytes; more likely standard response for
590          * SCSI-2, RMB=1 and a response_data_format of 0x2. */
591         pr2serr("invalid Unit Serial Number VPD response; probably a "
592                 "STANDARD INQUIRY response\n");
593         return SG_LIB_CAT_MALFORMED;
594     }
595     if (mxlen < 0)
596         len = rp[3] + 4;
597     else
598         len = sg_get_unaligned_be16(rp + 2) + 4;
599     if (len <= rlen) {
600         if (rlenp)
601             *rlenp = len;
602         return 0;
603     } else if (mxlen) {
604         if (rlenp)
605             *rlenp = rlen;
606         return 0;
607     }
608     if (len > MX_ALLOC_LEN) {
609         pr2serr("response length too long: %d > %d\n", len, MX_ALLOC_LEN);
610         return SG_LIB_CAT_MALFORMED;
611     } else {
612         res = pt_inquiry(sg_fd, 1, page, rp, len, &resid, 1, vb);
613         if (res)
614             return res;
615         rlen = len - resid;
616         /* assume it is well behaved: hence page and len still same */
617         if (rlenp)
618             *rlenp = rlen;
619         return 0;
620     }
621 }
622 
623 static const struct svpd_values_name_t *
sdp_get_vpd_detail(int page_num,int subvalue,int pdt)624 sdp_get_vpd_detail(int page_num, int subvalue, int pdt)
625 {
626     const struct svpd_values_name_t * vnp;
627     int sv, ty;
628 
629     sv = (subvalue < 0) ? 1 : 0;
630     ty = (pdt < 0) ? 1 : 0;
631     for (vnp = standard_vpd_pg; vnp->acron; ++vnp) {
632         if ((page_num == vnp->value) &&
633             (sv || (subvalue == vnp->subvalue)) &&
634             (ty || (pdt == vnp->pdt)))
635             return vnp;
636     }
637     if (! ty)
638         return sdp_get_vpd_detail(page_num, subvalue, -1);
639     if (! sv)
640         return sdp_get_vpd_detail(page_num, -1, -1);
641     return NULL;
642 }
643 
644 static const struct svpd_values_name_t *
sdp_find_vpd_by_acron(const char * ap)645 sdp_find_vpd_by_acron(const char * ap)
646 {
647     const struct svpd_values_name_t * vnp;
648 
649     for (vnp = standard_vpd_pg; vnp->acron; ++vnp) {
650         if (0 == strcmp(vnp->acron, ap))
651             return vnp;
652     }
653     return NULL;
654 }
655 
656 static void
enumerate_vpds(int standard,int vendor)657 enumerate_vpds(int standard, int vendor)
658 {
659     const struct svpd_values_name_t * vnp;
660 
661     if (standard) {
662         for (vnp = standard_vpd_pg; vnp->acron; ++vnp) {
663             if (vnp->name) {
664                 if (vnp->value < 0)
665                     printf("  %-10s -1        %s\n", vnp->acron, vnp->name);
666                 else
667                     printf("  %-10s 0x%02x      %s\n", vnp->acron, vnp->value,
668                        vnp->name);
669             }
670         }
671     }
672     if (vendor)
673         svpd_enumerate_vendor(-2);
674 }
675 
676 static int
count_standard_vpds(int num_vpd)677 count_standard_vpds(int num_vpd)
678 {
679     const struct svpd_values_name_t * vnp;
680     int matches;
681 
682     for (vnp = standard_vpd_pg, matches = 0; vnp->acron; ++vnp) {
683         if ((num_vpd == vnp->value) && vnp->name) {
684             if (0 == matches)
685                 printf("Matching standard VPD pages:\n");
686             ++matches;
687             if (vnp->value < 0)
688                 printf("  %-10s -1        %s\n", vnp->acron, vnp->name);
689             else
690                 printf("  %-10s 0x%02x      %s\n", vnp->acron, vnp->value,
691                    vnp->name);
692         }
693     }
694     return matches;
695 }
696 
697 static void
dStrRaw(const char * str,int len)698 dStrRaw(const char * str, int len)
699 {
700     int k;
701 
702     for (k = 0 ; k < len; ++k)
703         printf("%c", str[k]);
704 }
705 
706 /* Assume index is less than 16 */
707 const char * sg_ansi_version_arr[] =
708 {
709     "no conformance claimed",
710     "SCSI-1",           /* obsolete, ANSI X3.131-1986 */
711     "SCSI-2",           /* obsolete, ANSI X3.131-1994 */
712     "SPC",              /* withdrawn */
713     "SPC-2",
714     "SPC-3",
715     "SPC-4",
716     "SPC-5",
717     "ecma=1, [8h]",
718     "ecma=1, [9h]",
719     "ecma=1, [Ah]",
720     "ecma=1, [Bh]",
721     "reserved [Ch]",
722     "reserved [Dh]",
723     "reserved [Eh]",
724     "reserved [Fh]",
725 };
726 
727 static void
decode_std_inq(unsigned char * b,int len,int verbose)728 decode_std_inq(unsigned char * b, int len, int verbose)
729 {
730     int pqual, n;
731 
732     if (len < 4)
733         return;
734     pqual = (b[0] & 0xe0) >> 5;
735     if (0 == pqual)
736         printf("standard INQUIRY:\n");
737     else if (1 == pqual)
738         printf("standard INQUIRY: [qualifier indicates no connected "
739                "LU]\n");
740     else if (3 == pqual)
741         printf("standard INQUIRY: [qualifier indicates not capable "
742                "of supporting LU]\n");
743     else
744         printf("standard INQUIRY: [reserved or vendor specific "
745                        "qualifier [%d]]\n", pqual);
746     printf("  PQual=%d  Device_type=%d  RMB=%d  LU_CONG=%d  version=0x%02x ",
747            pqual, b[0] & 0x1f, !!(b[1] & 0x80), !!(b[1] & 0x40),
748            (unsigned int)b[2]);
749     printf(" [%s]\n", sg_ansi_version_arr[b[2] & 0xf]);
750     printf("  [AERC=%d]  [TrmTsk=%d]  NormACA=%d  HiSUP=%d "
751            " Resp_data_format=%d\n",
752            !!(b[3] & 0x80), !!(b[3] & 0x40), !!(b[3] & 0x20),
753            !!(b[3] & 0x10), b[3] & 0x0f);
754     if (len < 5)
755         return;
756     n = b[4] + 5;
757     if (verbose)
758         pr2serr(">> requested %d bytes, %d bytes available\n", len, n);
759     printf("  SCCS=%d  ACC=%d  TPGS=%d  3PC=%d  Protect=%d ",
760            !!(b[5] & 0x80), !!(b[5] & 0x40), ((b[5] & 0x30) >> 4),
761            !!(b[5] & 0x08), !!(b[5] & 0x01));
762     printf(" [BQue=%d]\n  EncServ=%d  ", !!(b[6] & 0x80), !!(b[6] & 0x40));
763     if (b[6] & 0x10)
764         printf("MultiP=1 (VS=%d)  ", !!(b[6] & 0x20));
765     else
766         printf("MultiP=0  ");
767     printf("[MChngr=%d]  [ACKREQQ=%d]  Addr16=%d\n  [RelAdr=%d]  ",
768            !!(b[6] & 0x08), !!(b[6] & 0x04), !!(b[6] & 0x01),
769            !!(b[7] & 0x80));
770     printf("WBus16=%d  Sync=%d  [Linked=%d]  [TranDis=%d]  ",
771            !!(b[7] & 0x20), !!(b[7] & 0x10), !!(b[7] & 0x08),
772            !!(b[7] & 0x04));
773     printf("CmdQue=%d\n", !!(b[7] & 0x02));
774     if (len < 36)
775         return;
776     printf("  Vendor_identification: %.8s\n", b + 8);
777     printf("  Product_identification: %.16s\n", b + 16);
778     printf("  Product_revision_level: %.4s\n", b + 32);
779 }
780 
781 static void
decode_id_vpd(unsigned char * buff,int len,int subvalue,const struct opts_t * op)782 decode_id_vpd(unsigned char * buff, int len, int subvalue,
783               const struct opts_t * op)
784 {
785     int m_a, m_d, m_cs;
786 
787     if (len < 4) {
788         pr2serr("Device identification VPD page length too short=%d\n", len);
789         return;
790     }
791     m_a = -1;
792     m_d = -1;
793     m_cs = -1;
794     if (0 == subvalue) {
795         decode_dev_ids(sg_get_desig_assoc_str(VPD_ASSOC_LU), buff + 4,
796                        len - 4, VPD_ASSOC_LU, m_d, m_cs, op);
797         decode_dev_ids(sg_get_desig_assoc_str(VPD_ASSOC_TPORT), buff + 4,
798                        len - 4, VPD_ASSOC_TPORT, m_d, m_cs, op);
799         decode_dev_ids(sg_get_desig_assoc_str(VPD_ASSOC_TDEVICE), buff + 4,
800                        len - 4, VPD_ASSOC_TDEVICE, m_d, m_cs, op);
801     } else if (VPD_DI_SEL_AS_IS == subvalue)
802         decode_dev_ids(NULL, buff + 4, len - 4, m_a, m_d, m_cs, op);
803     else {
804         if (VPD_DI_SEL_LU & subvalue)
805             decode_dev_ids(sg_get_desig_assoc_str(VPD_ASSOC_LU), buff + 4,
806                            len - 4, VPD_ASSOC_LU, m_d, m_cs, op);
807         if (VPD_DI_SEL_TPORT & subvalue)
808             decode_dev_ids(sg_get_desig_assoc_str(VPD_ASSOC_TPORT), buff + 4,
809                            len - 4, VPD_ASSOC_TPORT, m_d, m_cs, op);
810         if (VPD_DI_SEL_TARGET & subvalue)
811             decode_dev_ids(sg_get_desig_assoc_str(VPD_ASSOC_TDEVICE),
812                            buff + 4, len - 4, VPD_ASSOC_TDEVICE, m_d, m_cs,
813                            op);
814     }
815 }
816 
817 static const char * network_service_type_arr[] =
818 {
819     "unspecified",
820     "storage configuration service",
821     "diagnostics",
822     "status",
823     "logging",
824     "code download",
825     "copy service",
826     "administrative configuration service",
827     "reserved[0x8]", "reserved[0x9]",
828     "reserved[0xa]", "reserved[0xb]", "reserved[0xc]", "reserved[0xd]",
829     "reserved[0xe]", "reserved[0xf]", "reserved[0x10]", "reserved[0x11]",
830     "reserved[0x12]", "reserved[0x13]", "reserved[0x14]", "reserved[0x15]",
831     "reserved[0x16]", "reserved[0x17]", "reserved[0x18]", "reserved[0x19]",
832     "reserved[0x1a]", "reserved[0x1b]", "reserved[0x1c]", "reserved[0x1d]",
833     "reserved[0x1e]", "reserved[0x1f]",
834 };
835 
836 /* VPD_MAN_NET_ADDR */
837 static void
decode_net_man_vpd(unsigned char * buff,int len,int do_hex)838 decode_net_man_vpd(unsigned char * buff, int len, int do_hex)
839 {
840     int k, bump, na_len;
841     unsigned char * ucp;
842 
843     if ((1 == do_hex) || (do_hex > 2)) {
844         dStrHex((const char *)buff, len, (1 == do_hex) ? 0 : -1);
845         return;
846     }
847     if (len < 4) {
848         pr2serr("Management network addresses VPD page length too short=%d\n",
849                 len);
850         return;
851     }
852     len -= 4;
853     ucp = buff + 4;
854     for (k = 0; k < len; k += bump, ucp += bump) {
855         printf("  %s, Service type: %s\n",
856                sg_get_desig_assoc_str((ucp[0] >> 5) & 0x3),
857                network_service_type_arr[ucp[0] & 0x1f]);
858         na_len = sg_get_unaligned_be16(ucp + 2);
859         bump = 4 + na_len;
860         if ((k + bump) > len) {
861             pr2serr("Management network addresses VPD page, short "
862                     "descriptor length=%d, left=%d\n", bump, (len - k));
863             return;
864         }
865         if (na_len > 0) {
866             if (do_hex > 1) {
867                 printf("    Network address:\n");
868                 dStrHex((const char *)(ucp + 4), na_len, 0);
869             } else
870                 printf("    %s\n", ucp + 4);
871         }
872     }
873 }
874 
875 static const char * mode_page_policy_arr[] =
876 {
877     "shared",
878     "per target port",
879     "per initiator port",
880     "per I_T nexus",
881 };
882 
883 /* VPD_MODE_PG_POLICY */
884 static void
decode_mode_policy_vpd(unsigned char * buff,int len,int do_hex)885 decode_mode_policy_vpd(unsigned char * buff, int len, int do_hex)
886 {
887     int k, bump;
888     unsigned char * ucp;
889 
890     if ((1 == do_hex) || (do_hex > 2)) {
891         dStrHex((const char *)buff, len, (1 == do_hex) ? 1 : -1);
892         return;
893     }
894     if (len < 4) {
895         pr2serr("Mode page policy VPD page length too short=%d\n", len);
896         return;
897     }
898     len -= 4;
899     ucp = buff + 4;
900     for (k = 0; k < len; k += bump, ucp += bump) {
901         bump = 4;
902         if ((k + bump) > len) {
903             pr2serr("Mode page policy VPD page, short "
904                     "descriptor length=%d, left=%d\n", bump, (len - k));
905             return;
906         }
907         if (do_hex > 1)
908             dStrHex((const char *)ucp, 4, 1);
909         else {
910             printf("  Policy page code: 0x%x", (ucp[0] & 0x3f));
911             if (ucp[1])
912                 printf(",  subpage code: 0x%x\n", ucp[1]);
913             else
914                 printf("\n");
915             printf("    MLUS=%d,  Policy: %s\n", !!(ucp[2] & 0x80),
916                    mode_page_policy_arr[ucp[2] & 0x3]);
917         }
918     }
919 }
920 
921 /* VPD_SCSI_PORTS */
922 static void
decode_scsi_ports_vpd(unsigned char * buff,int len,const struct opts_t * op)923 decode_scsi_ports_vpd(unsigned char * buff, int len, const struct opts_t * op)
924 {
925     int k, bump, rel_port, ip_tid_len, tpd_len;
926     unsigned char * ucp;
927 
928     if ((1 == op->do_hex) || (op->do_hex > 2)) {
929         dStrHex((const char *)buff, len, (1 == op->do_hex) ? 1 : -1);
930         return;
931     }
932     if (len < 4) {
933         pr2serr("SCSI Ports VPD page length too short=%d\n", len);
934         return;
935     }
936     len -= 4;
937     ucp = buff + 4;
938     for (k = 0; k < len; k += bump, ucp += bump) {
939         rel_port = sg_get_unaligned_be16(ucp + 2);
940         printf("  Relative port=%d\n", rel_port);
941         ip_tid_len = sg_get_unaligned_be16(ucp + 6);
942         bump = 8 + ip_tid_len;
943         if ((k + bump) > len) {
944             pr2serr("SCSI Ports VPD page, short descriptor "
945                     "length=%d, left=%d\n", bump, (len - k));
946             return;
947         }
948         if (ip_tid_len > 0) {
949             if (op->do_hex > 1) {
950                 printf("    Initiator port transport id:\n");
951                 dStrHex((const char *)(ucp + 8), ip_tid_len, 1);
952             } else
953                 decode_transport_id("    ", ucp + 8, ip_tid_len);
954         }
955         tpd_len = sg_get_unaligned_be16(ucp + bump + 2);
956         if ((k + bump + tpd_len + 4) > len) {
957             pr2serr("SCSI Ports VPD page, short descriptor(tgt) "
958                     "length=%d, left=%d\n", bump, (len - k));
959             return;
960         }
961         if (tpd_len > 0) {
962             if (op->do_hex > 1) {
963                 printf("    Target port descriptor(s):\n");
964                 dStrHex((const char *)(ucp + bump + 4), tpd_len, 1);
965             } else {
966                 if ((0 == op->do_quiet) || (ip_tid_len > 0))
967                     printf("    Target port descriptor(s):\n");
968                 decode_dev_ids("SCSI Ports", ucp + bump + 4, tpd_len,
969                                VPD_ASSOC_TPORT, -1, -1, op);
970             }
971         }
972         bump += tpd_len + 4;
973     }
974 }
975 
976 /* Prints outs an abridged set of device identification designators
977    selected by association, designator type and/or code set. */
978 static int
decode_dev_ids_quiet(unsigned char * buff,int len,int m_assoc,int m_desig_type,int m_code_set)979 decode_dev_ids_quiet(unsigned char * buff, int len, int m_assoc,
980                      int m_desig_type, int m_code_set)
981 {
982     int m, p_id, c_set, piv, desig_type, i_len, naa, off, u;
983     int assoc, is_sas, rtp;
984     const unsigned char * ucp;
985     const unsigned char * ip;
986     unsigned char sas_tport_addr[8];
987 
988     rtp = 0;
989     memset(sas_tport_addr, 0, sizeof(sas_tport_addr));
990     off = -1;
991     if (buff[2] != 0) {
992         if (m_assoc != VPD_ASSOC_LU)
993             return 0;
994         ip = buff;
995         p_id = 0;
996         c_set = 1;
997         assoc = VPD_ASSOC_LU;
998         piv = 0;
999         is_sas = 0;
1000         desig_type = 3;
1001         i_len = 16;
1002         off = 16;
1003         goto skip_1st_iter;
1004     }
1005     while ((u = sg_vpd_dev_id_iter(buff, len, &off, m_assoc, m_desig_type,
1006                                    m_code_set)) == 0) {
1007         ucp = buff + off;
1008         i_len = ucp[3];
1009         if ((off + i_len + 4) > len) {
1010             pr2serr("    VPD page error: designator length longer than\n"
1011                     "     remaining response length=%d\n", (len - off));
1012             return SG_LIB_CAT_MALFORMED;
1013         }
1014         ip = ucp + 4;
1015         p_id = ((ucp[0] >> 4) & 0xf);
1016         c_set = (ucp[0] & 0xf);
1017         piv = ((ucp[1] & 0x80) ? 1 : 0);
1018         is_sas = (piv && (6 == p_id)) ? 1 : 0;
1019         assoc = ((ucp[1] >> 4) & 0x3);
1020         desig_type = (ucp[1] & 0xf);
1021 skip_1st_iter:
1022         switch (desig_type) {
1023         case 0: /* vendor specific */
1024             break;
1025         case 1: /* T10 vendor identification */
1026             break;
1027         case 2: /* EUI-64 based */
1028             if ((8 != i_len) && (12 != i_len) && (16 != i_len))
1029                 pr2serr("      << expect 8, 12 and 16 byte "
1030                         "EUI, got %d>>\n", i_len);
1031             printf("  0x");
1032             for (m = 0; m < i_len; ++m)
1033                 printf("%02x", (unsigned int)ip[m]);
1034             printf("\n");
1035             break;
1036         case 3: /* NAA */
1037             naa = (ip[0] >> 4) & 0xff;
1038             if (1 != c_set) {
1039                 pr2serr("      << expected binary code_set (1), got %d for "
1040                         "NAA=%d>>\n", c_set, naa);
1041                 dStrHexErr((const char *)ip, i_len, 0);
1042                 break;
1043             }
1044             switch (naa) {
1045             case 2:             /* NAA IEEE extended */
1046                 if (8 != i_len) {
1047                     pr2serr("      << unexpected NAA 2 identifier "
1048                             "length: 0x%x>>\n", i_len);
1049                     dStrHexErr((const char *)ip, i_len, 0);
1050                     break;
1051                 }
1052                 printf("  0x");
1053                 for (m = 0; m < 8; ++m)
1054                     printf("%02x", (unsigned int)ip[m]);
1055                 printf("\n");
1056                 break;
1057             case 3:             /* Locally assigned */
1058             case 5:             /* IEEE Registered */
1059                 if (8 != i_len) {
1060                     pr2serr("      << unexpected NAA 3 or 5 "
1061                             "identifier length: 0x%x>>\n", i_len);
1062                     dStrHexErr((const char *)ip, i_len, 0);
1063                     break;
1064                 }
1065                 if ((0 == is_sas) || (1 != assoc)) {
1066                     printf("  0x");
1067                     for (m = 0; m < 8; ++m)
1068                         printf("%02x", (unsigned int)ip[m]);
1069                     printf("\n");
1070                 } else if (rtp) {
1071                     printf("  0x");
1072                     for (m = 0; m < 8; ++m)
1073                         printf("%02x", (unsigned int)ip[m]);
1074                     printf(",0x%x\n", rtp);
1075                     rtp = 0;
1076                 } else {
1077                     if (sas_tport_addr[0]) {
1078                         printf("  0x");
1079                         for (m = 0; m < 8; ++m)
1080                             printf("%02x", (unsigned int)sas_tport_addr[m]);
1081                         printf("\n");
1082                     }
1083                     memcpy(sas_tport_addr, ip, sizeof(sas_tport_addr));
1084                 }
1085                 break;
1086             case 6:             /* NAA IEEE registered extended */
1087                 if (16 != i_len) {
1088                     pr2serr("      << unexpected NAA 6 identifier length: "
1089                             "0x%x>>\n", i_len);
1090                     dStrHexErr((const char *)ip, i_len, 0);
1091                     break;
1092                 }
1093                 printf("  0x");
1094                 for (m = 0; m < 16; ++m)
1095                     printf("%02x", (unsigned int)ip[m]);
1096                 printf("\n");
1097                 break;
1098             default:
1099                 pr2serr("      << bad NAA nibble, expected 2, 3, 5 or 6, got "
1100                         "%d>>\n", naa);
1101                 dStrHexErr((const char *)ip, i_len, 0);
1102                 break;
1103             }
1104             break;
1105         case 4: /* Relative target port */
1106             if ((0 == is_sas) || (1 != c_set) || (1 != assoc) || (4 != i_len))
1107                 break;
1108             rtp = sg_get_unaligned_be16(ip + 2);
1109             if (sas_tport_addr[0]) {
1110                 printf("  0x");
1111                 for (m = 0; m < 8; ++m)
1112                     printf("%02x", (unsigned int)sas_tport_addr[m]);
1113                 printf(",0x%x\n", rtp);
1114                 memset(sas_tport_addr, 0, sizeof(sas_tport_addr));
1115                 rtp = 0;
1116             }
1117             break;
1118         case 5: /* (primary) Target port group */
1119             break;
1120         case 6: /* Logical unit group */
1121             break;
1122         case 7: /* MD5 logical unit identifier */
1123             break;
1124         case 8: /* SCSI name string */
1125             if (3 != c_set) {
1126                 pr2serr("      << expected UTF-8 code_set>>\n");
1127                 dStrHexErr((const char *)ip, i_len, 0);
1128                 break;
1129             }
1130             if (! (strncmp((const char *)ip, "eui.", 4) ||
1131                    strncmp((const char *)ip, "EUI.", 4) ||
1132                    strncmp((const char *)ip, "naa.", 4) ||
1133                    strncmp((const char *)ip, "NAA.", 4) ||
1134                    strncmp((const char *)ip, "iqn.", 4))) {
1135                 pr2serr("      << expected name string prefix>>\n");
1136                 dStrHexErr((const char *)ip, i_len, -1);
1137                 break;
1138             }
1139             /* does %s print out UTF-8 ok??
1140              * Seems to depend on the locale. Looks ok here with my
1141              * locale setting: en_AU.UTF-8
1142              */
1143             printf("  %s\n", (const char *)ip);
1144             break;
1145         case 9: /* Protocol specific port identifier */
1146             break;
1147         case 0xa: /* UUID identifier */
1148             if ((1 != c_set) || (18 != i_len) || (1 != ((ip[0] >> 4) & 0xf)))
1149                 break;
1150             for (m = 0; m < 16; ++m) {
1151                 if ((4 == m) || (6 == m) || (8 == m) || (10 == m))
1152                     printf("-");
1153                 printf("%02x", (unsigned int)ip[2 + m]);
1154             }
1155             printf("\n");
1156             break;
1157         default: /* reserved */
1158             break;
1159         }
1160     }
1161     if (sas_tport_addr[0]) {
1162         printf("  0x");
1163         for (m = 0; m < 8; ++m)
1164             printf("%02x", (unsigned int)sas_tport_addr[m]);
1165         printf("\n");
1166     }
1167     if (-2 == u) {
1168         pr2serr("VPD page error: short designator around offset %d\n", off);
1169         return SG_LIB_CAT_MALFORMED;
1170     }
1171     return 0;
1172 }
1173 
1174 static void
decode_designation_descriptor(const unsigned char * ip,int i_len,int p_id,int c_set,int piv,int assoc,int desig_type,int print_assoc,const struct opts_t * op)1175 decode_designation_descriptor(const unsigned char * ip, int i_len,
1176                               int p_id, int c_set, int piv, int assoc,
1177                               int desig_type, int print_assoc,
1178                               const struct opts_t * op)
1179 {
1180     int m, ci_off, c_id, d_id, naa;
1181     int vsi, k;
1182     uint64_t vsei;
1183     uint64_t id_ext;
1184     char b[64];
1185 
1186     if (print_assoc)
1187         printf("  %s:\n", sg_get_desig_assoc_str(assoc & 3));
1188     printf("    designator type: %s,  code set: %s\n",
1189            sg_get_desig_type_str(desig_type & 0xf),
1190            sg_get_desig_code_set_str(c_set & 0xf));
1191     if (piv && ((1 == assoc) || (2 == assoc)))
1192         printf("     transport: %s\n",
1193                sg_get_trans_proto_str(p_id, sizeof(b), b));
1194 /* printf("    associated with the %s\n", sg_get_desig_assoc_str(assoc)); */
1195     switch (desig_type) {
1196     case 0: /* vendor specific */
1197         k = 0;
1198         if ((2 == c_set) || (3 == c_set)) { /* ASCII or UTF-8 */
1199             for (k = 0; (k < i_len) && isprint(ip[k]); ++k)
1200                 ;
1201             if (k >= i_len)
1202                 k = 1;
1203         }
1204         if (k)
1205             printf("      vendor specific: %.*s\n", i_len, ip);
1206         else {
1207             pr2serr("      vendor specific:\n");
1208             dStrHexErr((const char *)ip, i_len, 0);
1209         }
1210         break;
1211     case 1: /* T10 vendor identification */
1212         printf("      vendor id: %.8s\n", ip);
1213         if (i_len > 8) {
1214             if ((2 == c_set) || (3 == c_set)) { /* ASCII or UTF-8 */
1215                 printf("      vendor specific: %.*s\n", i_len - 8, ip + 8);
1216             } else {
1217                 printf("      vendor specific: 0x");
1218                 for (m = 8; m < i_len; ++m)
1219                     printf("%02x", (unsigned int)ip[m]);
1220                 printf("\n");
1221             }
1222         }
1223         break;
1224     case 2: /* EUI-64 based */
1225         if (! op->do_long) {
1226             if ((8 != i_len) && (12 != i_len) && (16 != i_len)) {
1227                 pr2serr("      << expect 8, 12 and 16 byte EUI, got %d>>\n",
1228                         i_len);
1229                 dStrHexErr((const char *)ip, i_len, 0);
1230                 break;
1231             }
1232             printf("      0x");
1233             for (m = 0; m < i_len; ++m)
1234                 printf("%02x", (unsigned int)ip[m]);
1235             printf("\n");
1236             break;
1237         }
1238         printf("      EUI-64 based %d byte identifier\n", i_len);
1239         if (1 != c_set) {
1240             pr2serr("      << expected binary code_set (1)>>\n");
1241             dStrHexErr((const char *)ip, i_len, 0);
1242             break;
1243         }
1244         ci_off = 0;
1245         if (16 == i_len) {
1246             ci_off = 8;
1247             id_ext = sg_get_unaligned_be64(ip);
1248             printf("      Identifier extension: 0x%" PRIx64 "\n", id_ext);
1249         } else if ((8 != i_len) && (12 != i_len)) {
1250             pr2serr("      << can only decode 8, 12 and 16 byte ids>>\n");
1251             dStrHexErr((const char *)ip, i_len, 0);
1252             break;
1253         }
1254         c_id = sg_get_unaligned_be24(ip + ci_off);
1255         printf("      IEEE Company_id: 0x%x\n", c_id);
1256         vsei = ((uint64_t)sg_get_unaligned_be32(ip + ci_off + 3) << 8) +
1257                ip[ci_off + 3 + 4];      /* 5 byte integer */
1258         printf("      Vendor Specific Extension Identifier: 0x%" PRIx64
1259                "\n", vsei);
1260         if (12 == i_len) {
1261             d_id = sg_get_unaligned_be32(ip + 8);
1262             printf("      Directory ID: 0x%x\n", d_id);
1263         }
1264         break;
1265     case 3: /* NAA <n> */
1266         if (1 != c_set) {
1267             pr2serr("      << unexpected code set %d for NAA>>\n", c_set);
1268             dStrHexErr((const char *)ip, i_len, 0);
1269             break;
1270         }
1271         naa = (ip[0] >> 4) & 0xff;
1272         switch (naa) {
1273         case 2:         /* NAA 2: IEEE Extended */
1274             if (8 != i_len) {
1275                 pr2serr("      << unexpected NAA 2 identifier length: "
1276                         "0x%x>>\n", i_len);
1277                 dStrHexErr((const char *)ip, i_len, 0);
1278                 break;
1279             }
1280             d_id = sg_get_unaligned_be16(ip) & 0xfff;
1281             c_id = sg_get_unaligned_be24(ip + 2);
1282             vsi = sg_get_unaligned_be24(ip + 5);
1283             if (op->do_long) {
1284                 printf("      NAA 2, vendor specific identifier A: "
1285                        "0x%x\n", d_id);
1286                 printf("      IEEE Company_id: 0x%x\n", c_id);
1287                 printf("      vendor specific identifier B: 0x%x\n", vsi);
1288                 printf("      [0x");
1289                 for (m = 0; m < 8; ++m)
1290                     printf("%02x", (unsigned int)ip[m]);
1291                 printf("]\n");
1292             }
1293             printf("      0x");
1294             for (m = 0; m < 8; ++m)
1295                 printf("%02x", (unsigned int)ip[m]);
1296             printf("\n");
1297             break;
1298         case 3:         /* NAA 3: Locally assigned */
1299             if (8 != i_len) {
1300                 pr2serr("      << unexpected NAA 3 identifier length: "
1301                         "0x%x>>\n", i_len);
1302                 dStrHexErr((const char *)ip, i_len, 0);
1303                 break;
1304             }
1305             if (op->do_long)
1306                 printf("      NAA 3, Locally assigned value:\n");
1307             printf("      0x");
1308             for (m = 0; m < 8; ++m)
1309                 printf("%02x", (unsigned int)ip[m]);
1310             printf("\n");
1311             break;
1312         case 5:         /* NAA 5: IEEE Registered */
1313             if (8 != i_len) {
1314                 pr2serr("      << unexpected NAA 5 identifier length: "
1315                         "0x%x>>\n", i_len);
1316                 dStrHexErr((const char *)ip, i_len, 0);
1317                 break;
1318             }
1319             if (op->do_long) {
1320                 c_id = (((ip[0] & 0xf) << 20) | (ip[1] << 12) |
1321                         (ip[2] << 4) | ((ip[3] & 0xf0) >> 4));
1322                 vsei = ip[3] & 0xf;
1323                 for (m = 1; m < 5; ++m) {
1324                     vsei <<= 8;
1325                     vsei |= ip[3 + m];
1326                 }
1327                 printf("      NAA 5, IEEE Company_id: 0x%x\n", c_id);
1328                 printf("      Vendor Specific Identifier: 0x%" PRIx64
1329                        "\n", vsei);
1330                 printf("      [0x");
1331                 for (m = 0; m < 8; ++m)
1332                     printf("%02x", (unsigned int)ip[m]);
1333                 printf("]\n");
1334             } else {
1335                 printf("      0x");
1336                 for (m = 0; m < 8; ++m)
1337                     printf("%02x", (unsigned int)ip[m]);
1338                 printf("\n");
1339             }
1340             break;
1341         case 6:         /* NAA 6: IEEE Registered extended */
1342             if (16 != i_len) {
1343                 pr2serr("      << unexpected NAA 6 identifier length: "
1344                         "0x%x>>\n", i_len);
1345                 dStrHexErr((const char *)ip, i_len, 0);
1346                 break;
1347             }
1348             c_id = (((ip[0] & 0xf) << 20) | (ip[1] << 12) |
1349                     (ip[2] << 4) | ((ip[3] & 0xf0) >> 4));
1350             vsei = ip[3] & 0xf;
1351             for (m = 1; m < 5; ++m) {
1352                 vsei <<= 8;
1353                 vsei |= ip[3 + m];
1354             }
1355             if (op->do_long) {
1356                 printf("      NAA 6, IEEE Company_id: 0x%x\n", c_id);
1357                 printf("      Vendor Specific Identifier: 0x%" PRIx64
1358                        "\n", vsei);
1359                 vsei = sg_get_unaligned_be64(ip + 8);
1360                 printf("      Vendor Specific Identifier Extension: "
1361                        "0x%" PRIx64 "\n", vsei);
1362                 printf("      [0x");
1363                 for (m = 0; m < 16; ++m)
1364                     printf("%02x", (unsigned int)ip[m]);
1365                 printf("]\n");
1366             } else {
1367                 printf("      0x");
1368                 for (m = 0; m < 16; ++m)
1369                     printf("%02x", (unsigned int)ip[m]);
1370                 printf("\n");
1371             }
1372             break;
1373         default:
1374             pr2serr("      << unexpected NAA [0x%x]>>\n", naa);
1375             dStrHexErr((const char *)ip, i_len, 0);
1376             break;
1377         }
1378         break;
1379     case 4: /* Relative target port */
1380         if ((1 != c_set) || (1 != assoc) || (4 != i_len)) {
1381             pr2serr("      << expected binary code_set, target port "
1382                     "association, length 4>>\n");
1383             dStrHexErr((const char *)ip, i_len, 0);
1384             break;
1385         }
1386         d_id = sg_get_unaligned_be16(ip + 2);
1387         printf("      Relative target port: 0x%x\n", d_id);
1388         break;
1389     case 5: /* (primary) Target port group */
1390         if ((1 != c_set) || (1 != assoc) || (4 != i_len)) {
1391             pr2serr("      << expected binary code_set, target port "
1392                     "association, length 4>>\n");
1393             dStrHexErr((const char *)ip, i_len, 0);
1394             break;
1395         }
1396         d_id = sg_get_unaligned_be16(ip + 2);
1397         printf("      Target port group: 0x%x\n", d_id);
1398         break;
1399     case 6: /* Logical unit group */
1400         if ((1 != c_set) || (0 != assoc) || (4 != i_len)) {
1401             pr2serr("      << expected binary code_set, logical unit "
1402                     "association, length 4>>\n");
1403             dStrHexErr((const char *)ip, i_len, 0);
1404             break;
1405         }
1406         d_id = sg_get_unaligned_be16(ip + 2);
1407         printf("      Logical unit group: 0x%x\n", d_id);
1408         break;
1409     case 7: /* MD5 logical unit identifier */
1410         if ((1 != c_set) || (0 != assoc)) {
1411             pr2serr("      << expected binary code_set, logical unit "
1412                     "association>>\n");
1413             dStrHexErr((const char *)ip, i_len, 0);
1414             break;
1415         }
1416         printf("      MD5 logical unit identifier:\n");
1417         dStrHex((const char *)ip, i_len, 0);
1418         break;
1419     case 8: /* SCSI name string */
1420         if (3 != c_set) {
1421             pr2serr("      << expected UTF-8 code_set>>\n");
1422             dStrHexErr((const char *)ip, i_len, 0);
1423             break;
1424         }
1425         if (! (strncmp((const char *)ip, "eui.", 4) ||
1426                strncmp((const char *)ip, "EUI.", 4) ||
1427                strncmp((const char *)ip, "naa.", 4) ||
1428                strncmp((const char *)ip, "NAA.", 4) ||
1429                strncmp((const char *)ip, "iqn.", 4))) {
1430             pr2serr("      << expected name string prefix>>\n");
1431             dStrHexErr((const char *)ip, i_len, -1);
1432             break;
1433         }
1434         printf("      SCSI name string:\n");
1435         /* does %s print out UTF-8 ok??
1436          * Seems to depend on the locale. Looks ok here with my
1437          * locale setting: en_AU.UTF-8
1438          */
1439         printf("      %s\n", (const char *)ip);
1440         break;
1441     case 9: /* Protocol specific port identifier */
1442         /* added in spc4r36, PIV must be set, proto_id indicates */
1443         /* whether UAS (USB) or SOP (PCIe) or ... */
1444         if (! piv)
1445             printf("      >>>> Protocol specific port identifier "
1446                    "expects protocol\n"
1447                    "           identifier to be valid and it is not\n");
1448         if (TPROTO_UAS == p_id) {
1449             printf("      USB device address: 0x%x\n", 0x7f & ip[0]);
1450             printf("      USB interface number: 0x%x\n", ip[2]);
1451         } else if (TPROTO_SOP == p_id) {
1452             printf("      PCIe routing ID, bus number: 0x%x\n", ip[0]);
1453             printf("          function number: 0x%x\n", ip[1]);
1454             printf("          [or device number: 0x%x, function number: "
1455                    "0x%x]\n", (0x1f & (ip[1] >> 3)), 0x7 & ip[1]);
1456         } else
1457             pr2serr("      >>>> unexpected protocol indentifier: %s\n"
1458                     "           with Protocol specific port "
1459                     "identifier\n",
1460                     sg_get_trans_proto_str(p_id, sizeof(b), b));
1461         break;
1462     case 0xa: /* UUID identifier */
1463         if (1 != c_set) {
1464             pr2serr("      << expected binary code_set >>\n");
1465             dStrHexErr((const char *)ip, i_len, 0);
1466             break;
1467         }
1468         if ((1 != ((ip[0] >> 4) & 0xf)) || (18 != i_len)) {
1469             pr2serr("      << expected locally assigned UUID, 16 bytes long "
1470                     ">>\n");
1471             dStrHexErr((const char *)ip, i_len, 0);
1472             break;
1473         }
1474         printf("      Locally assigned UUID: ");
1475         for (m = 0; m < 16; ++m) {
1476             if ((4 == m) || (6 == m) || (8 == m) || (10 == m))
1477                 printf("-");    /* RFC 4122 format */
1478             printf("%02x", (unsigned int)ip[2 + m]);
1479         }
1480         printf("\n");
1481         if (op->do_long) {
1482             printf("      [0x");
1483             for (m = 0; m < 16; ++m)
1484                 printf("%02x", (unsigned int)ip[2 + m]);
1485             printf("]\n");
1486         }
1487         break;
1488     default: /* reserved */
1489         pr2serr("      reserved designator=0x%x\n", desig_type);
1490         dStrHexErr((const char *)ip, i_len, 0);
1491         break;
1492     }
1493 }
1494 
1495 /* Prints outs device identification designators selected by association,
1496    designator type and/or code set. */
1497 static int
decode_dev_ids(const char * print_if_found,unsigned char * buff,int len,int m_assoc,int m_desig_type,int m_code_set,const struct opts_t * op)1498 decode_dev_ids(const char * print_if_found, unsigned char * buff, int len,
1499                int m_assoc, int m_desig_type, int m_code_set,
1500                const struct opts_t * op)
1501 {
1502     int assoc, i_len, c_set, piv, p_id, desig_type;
1503     int printed, off, u;
1504     const unsigned char * ucp;
1505 
1506     if (op->do_quiet)
1507         return decode_dev_ids_quiet(buff, len, m_assoc, m_desig_type,
1508                                     m_code_set);
1509     if ( buff[2] != 0 ) {
1510         if (m_assoc == VPD_ASSOC_LU)
1511             decode_designation_descriptor(buff, 16, 0, 1, 0, m_assoc, 3, 0,
1512                                           op);
1513         return 0;
1514     }
1515     off = -1;
1516     printed = 0;
1517     while ((u = sg_vpd_dev_id_iter(buff, len, &off, m_assoc, m_desig_type,
1518                                    m_code_set)) == 0) {
1519         ucp = buff + off;
1520         i_len = ucp[3];
1521         if ((off + i_len + 4) > len) {
1522             pr2serr("    VPD page error: designator length longer than\n"
1523                     "     remaining response length=%d\n", (len - off));
1524             return SG_LIB_CAT_MALFORMED;
1525         }
1526         assoc = ((ucp[1] >> 4) & 0x3);
1527         if (print_if_found && (0 == printed)) {
1528             printed = 1;
1529             printf("  %s:\n", print_if_found);
1530         }
1531         if (NULL == print_if_found)
1532             printf("  %s:\n", sg_get_desig_assoc_str(assoc));
1533         p_id = ((ucp[0] >> 4) & 0xf);
1534         c_set = (ucp[0] & 0xf);
1535         piv = ((ucp[1] & 0x80) ? 1 : 0);
1536         desig_type = (ucp[1] & 0xf);
1537         decode_designation_descriptor(ucp + 4, i_len, p_id, c_set, piv, assoc,
1538                                       desig_type, 0, op);
1539     }
1540     if (-2 == u) {
1541         pr2serr("VPD page error: short designator around offset %d\n", off);
1542         return SG_LIB_CAT_MALFORMED;
1543     }
1544     return 0;
1545 }
1546 
1547 /* Transport IDs are initiator port identifiers, typically other than the
1548    initiator port issuing a SCSI command. */
1549 static void
decode_transport_id(const char * leadin,unsigned char * ucp,int len)1550 decode_transport_id(const char * leadin, unsigned char * ucp, int len)
1551 {
1552     int format_code, proto_id, num, k;
1553     uint64_t ull;
1554     int bump;
1555 
1556     for (k = 0, bump= 24; k < len; k += bump, ucp += bump) {
1557         if ((len < 24) || (0 != (len % 4)))
1558             printf("%sTransport Id short or not multiple of 4 "
1559                    "[length=%d]:\n", leadin, len);
1560         else
1561             printf("%sTransport Id of initiator:\n", leadin);
1562         format_code = ((ucp[0] >> 6) & 0x3);
1563         proto_id = (ucp[0] & 0xf);
1564         switch (proto_id) {
1565         case TPROTO_FCP: /* Fibre channel */
1566             printf("%s  FCP-2 World Wide Name:\n", leadin);
1567             if (0 != format_code)
1568                 printf("%s  [Unexpected format code: %d]\n", leadin,
1569                        format_code);
1570             dStrHex((const char *)&ucp[8], 8, -1);
1571             bump = 24;
1572             break;
1573         case TPROTO_SPI:        /* Scsi Parallel Interface */
1574             printf("%s  Parallel SCSI initiator SCSI address: 0x%x\n",
1575                    leadin, sg_get_unaligned_be16(ucp + 2));
1576             if (0 != format_code)
1577                 printf("%s  [Unexpected format code: %d]\n", leadin,
1578                        format_code);
1579             printf("%s  relative port number (of corresponding target): "
1580                    "0x%x\n", leadin, sg_get_unaligned_be16(ucp + 6));
1581             bump = 24;
1582             break;
1583         case TPROTO_SSA:
1584             printf("%s  SSA (transport id not defined):\n", leadin);
1585             printf("%s  format code: %d\n", leadin, format_code);
1586             dStrHex((const char *)ucp, ((len > 24) ? 24 : len), 0);
1587             bump = 24;
1588             break;
1589         case TPROTO_1394: /* IEEE 1394 */
1590             printf("%s  IEEE 1394 EUI-64 name:\n", leadin);
1591             if (0 != format_code)
1592                 printf("%s  [Unexpected format code: %d]\n", leadin,
1593                        format_code);
1594             dStrHex((const char *)&ucp[8], 8, -1);
1595             bump = 24;
1596             break;
1597         case TPROTO_SRP:
1598             printf("%s  RDMA initiator port identifier:\n", leadin);
1599             if (0 != format_code)
1600                 printf("%s  [Unexpected format code: %d]\n", leadin,
1601                        format_code);
1602             dStrHex((const char *)&ucp[8], 16, -1);
1603             bump = 24;
1604             break;
1605         case TPROTO_ISCSI:
1606             printf("%s  iSCSI ", leadin);
1607             num = sg_get_unaligned_be16(ucp + 2);
1608             if (0 == format_code)
1609                 printf("name: %.*s\n", num, &ucp[4]);
1610             else if (1 == format_code)
1611                 printf("world wide unique port id: %.*s\n", num, &ucp[4]);
1612             else {
1613                 pr2serr("  [Unexpected format code: %d]\n", format_code);
1614                 dStrHexErr((const char *)ucp, num + 4, 0);
1615             }
1616             bump = (((num + 4) < 24) ? 24 : num + 4);
1617             break;
1618         case TPROTO_SAS:
1619             ull = sg_get_unaligned_be64(ucp + 4);
1620             printf("%s  SAS address: 0x%" PRIx64 "\n", leadin, ull);
1621             if (0 != format_code)
1622                 printf("%s  [Unexpected format code: %d]\n", leadin,
1623                        format_code);
1624             bump = 24;
1625             break;
1626         case TPROTO_ADT:
1627             printf("%s  ADT:\n", leadin);
1628             printf("%s  format code: %d\n", leadin, format_code);
1629             dStrHex((const char *)ucp, ((len > 24) ? 24 : len), 0);
1630             bump = 24;
1631             break;
1632         case TPROTO_ATA: /* ATA/ATAPI */
1633             printf("%s  ATAPI:\n", leadin);
1634             printf("%s  format code: %d\n", leadin, format_code);
1635             dStrHex((const char *)ucp, ((len > 24) ? 24 : len), 0);
1636             bump = 24;
1637             break;
1638         case TPROTO_UAS:
1639             printf("%s  UAS:\n", leadin);
1640             printf("%s  format code: %d\n", leadin, format_code);
1641             dStrHex((const char *)ucp, ((len > 24) ? 24 : len), 0);
1642             bump = 24;
1643             break;
1644         case TPROTO_SOP:
1645             printf("%s  SOP ", leadin);
1646             num = sg_get_unaligned_be16(ucp + 2);
1647             if (0 == format_code)
1648                 printf("Routing ID: 0x%x\n", num);
1649             else {
1650                 pr2serr("  [Unexpected format code: %d]\n", format_code);
1651                 dStrHexErr((const char *)ucp, 24, 0);
1652             }
1653             bump = 24;
1654             break;
1655         case TPROTO_NONE:
1656             pr2serr("%s  No specified protocol\n", leadin);
1657             /* dStrHexErr((const char *)ucp, ((len > 24) ? 24 : len), 0); */
1658             bump = 24;
1659             break;
1660         default:
1661             pr2serr("%s  unknown protocol id=0x%x  format_code=%d\n", leadin,
1662                     proto_id, format_code);
1663             dStrHexErr((const char *)ucp, ((len > 24) ? 24 : len), 0);
1664             bump = 24;
1665             break;
1666         }
1667     }
1668 }
1669 
1670 /* VPD_EXT_INQ    Extended Inquiry VPD */
1671 static void
decode_x_inq_vpd(unsigned char * b,int len,int do_hex,int do_long,int protect)1672 decode_x_inq_vpd(unsigned char * b, int len, int do_hex, int do_long,
1673                  int protect)
1674 {
1675     int n;
1676 
1677     if (len < 7) {
1678         pr2serr("Extended INQUIRY data VPD page length too short=%d\n", len);
1679         return;
1680     }
1681     if (do_hex) {
1682         dStrHex((const char *)b, len, (1 == do_hex) ? 0 : -1);
1683         return;
1684     }
1685     if (do_long) {
1686         n = (b[4] >> 6) & 0x3;
1687         printf("  ACTIVATE_MICROCODE=%d", n);
1688         if (1 == n)
1689             printf(" [before final WRITE BUFFER]\n");
1690         else if (2 == n)
1691             printf(" [after power on or hard reset]\n");
1692         else
1693             printf("\n");
1694         n = (b[4] >> 3) & 0x7;
1695         printf("  SPT=%d", n);
1696         if (protect) {
1697             switch (n)
1698             {
1699             case 0:
1700                 printf(" [protection type 1 supported]\n");
1701                 break;
1702             case 1:
1703                 printf(" [protection types 1 and 2 supported]\n");
1704                 break;
1705             case 2:
1706                 printf(" [protection type 2 supported]\n");
1707                 break;
1708             case 3:
1709                 printf(" [protection types 1 and 3 supported]\n");
1710                 break;
1711             case 4:
1712                 printf(" [protection type 3 supported]\n");
1713                 break;
1714             case 5:
1715                 printf(" [protection types 2 and 3 supported]\n");
1716                 break;
1717             case 6:
1718                 printf(" [see Supported block lengths and protection types "
1719                        "VPD page]\n");
1720                 break;
1721             case 7:
1722                 printf(" [protection types 1, 2 and 3 supported]\n");
1723                 break;
1724             default:
1725                 printf("\n");
1726                 break;
1727             }
1728         } else
1729             printf("\n");
1730         printf("  GRD_CHK=%d\n", !!(b[4] & 0x4));
1731         printf("  APP_CHK=%d\n", !!(b[4] & 0x2));
1732         printf("  REF_CHK=%d\n", !!(b[4] & 0x1));
1733         printf("  UASK_SUP=%d\n", !!(b[5] & 0x20));
1734         printf("  GROUP_SUP=%d\n", !!(b[5] & 0x10));
1735         printf("  PRIOR_SUP=%d\n", !!(b[5] & 0x8));
1736         printf("  HEADSUP=%d\n", !!(b[5] & 0x4));
1737         printf("  ORDSUP=%d\n", !!(b[5] & 0x2));
1738         printf("  SIMPSUP=%d\n", !!(b[5] & 0x1));
1739         printf("  WU_SUP=%d\n", !!(b[6] & 0x8));
1740         printf("  CRD_SUP=%d\n", !!(b[6] & 0x4));
1741         printf("  NV_SUP=%d\n", !!(b[6] & 0x2));
1742         printf("  V_SUP=%d\n", !!(b[6] & 0x1));
1743         printf("  NO_PI_CHK=%d\n", !!(b[7] & 0x10));    /* spc5r02 */
1744         printf("  P_I_I_SUP=%d\n", !!(b[7] & 0x10));
1745         printf("  LUICLR=%d\n", !!(b[7] & 0x1));
1746         printf("  R_SUP=%d\n", !!(b[8] & 0x10));
1747         printf("  HSSRELEF=%d\n", !!(b[8] & 0x2));      /* spc5r02 */
1748         printf("  CBCS=%d\n", !!(b[8] & 0x1));  /* obsolete in spc5r01 */
1749         printf("  Multi I_T nexus microcode download=%d\n", b[9] & 0xf);
1750         printf("  Extended self-test completion minutes=%d\n",
1751                sg_get_unaligned_be16(b + 10));
1752         printf("  POA_SUP=%d\n", !!(b[12] & 0x80));     /* spc4r32 */
1753         printf("  HRA_SUP=%d\n", !!(b[12] & 0x40));     /* spc4r32 */
1754         printf("  VSA_SUP=%d\n", !!(b[12] & 0x20));     /* spc4r32 */
1755         printf("  Maximum supported sense data length=%d\n",
1756                b[13]); /* spc4r34 */
1757         return;
1758     }
1759     printf("  ACTIVATE_MICROCODE=%d SPT=%d GRD_CHK=%d APP_CHK=%d "
1760            "REF_CHK=%d\n", ((b[4] >> 6) & 0x3), ((b[4] >> 3) & 0x7),
1761            !!(b[4] & 0x4), !!(b[4] & 0x2), !!(b[4] & 0x1));
1762     printf("  UASK_SUP=%d GROUP_SUP=%d PRIOR_SUP=%d HEADSUP=%d ORDSUP=%d "
1763            "SIMPSUP=%d\n", !!(b[5] & 0x20), !!(b[5] & 0x10), !!(b[5] & 0x8),
1764            !!(b[5] & 0x4), !!(b[5] & 0x2), !!(b[5] & 0x1));
1765     /* CRD_SUP made obsolete in spc5r04 */
1766     printf("  WU_SUP=%d [CRD_SUP=%d] NV_SUP=%d V_SUP=%d\n",
1767            !!(b[6] & 0x8), !!(b[6] & 0x4), !!(b[6] & 0x2), !!(b[6] & 0x1));
1768     /* CBCS, capability-based command security, obsolete in spc5r01 */
1769     printf("  P_I_I_SUP=%d LUICLR=%d R_SUP=%d CBCS=%d\n",
1770            !!(b[7] & 0x10), !!(b[7] & 0x1), !!(b[8] & 0x10), !!(b[8] & 0x1));
1771     printf("  Multi I_T nexus microcode download=%d\n", b[9] & 0xf);
1772     printf("  Extended self-test completion minutes=%d\n",
1773            sg_get_unaligned_be16(b + 10));    /* spc4r27 */
1774     printf("  POA_SUP=%d HRA_SUP=%d VSA_SUP=%d\n",      /* spc4r32 */
1775            !!(b[12] & 0x80), !!(b[12] & 0x40), !!(b[12] & 0x20));
1776     printf("  Maximum supported sense data length=%d\n", b[13]); /* spc4r34 */
1777 }
1778 
1779 /* VPD_SOFTW_INF_ID */
1780 static void
decode_softw_inf_id(unsigned char * buff,int len,int do_hex)1781 decode_softw_inf_id(unsigned char * buff, int len, int do_hex)
1782 {
1783     if (do_hex) {
1784         dStrHex((const char *)buff, len, (1 == do_hex) ? 0 : -1);
1785         return;
1786     }
1787     len -= 4;
1788     buff += 4;
1789     for ( ; len > 5; len -= 6, buff += 6) {
1790         printf("    IEEE Company_id: 0x%06x, vendor specific extension "
1791                "id: 0x%06x\n", sg_get_unaligned_be24(buff),
1792                sg_get_unaligned_be24(buff + 3));
1793     }
1794 }
1795 
1796 /* VPD_ATA_INFO */
1797 static void
decode_ata_info_vpd(unsigned char * buff,int len,int do_long,int do_hex)1798 decode_ata_info_vpd(unsigned char * buff, int len, int do_long, int do_hex)
1799 {
1800     char b[80];
1801     int num, is_be;
1802     const char * cp;
1803     const char * ata_transp;
1804 
1805     if (len < 36) {
1806         pr2serr("ATA information VPD page length too short=%d\n", len);
1807         return;
1808     }
1809     if (do_hex && (2 != do_hex)) {
1810         dStrHex((const char *)buff, len, (1 == do_hex) ? 0 : -1);
1811         return;
1812     }
1813     memcpy(b, buff + 8, 8);
1814     b[8] = '\0';
1815     printf("  SAT Vendor identification: %s\n", b);
1816     memcpy(b, buff + 16, 16);
1817     b[16] = '\0';
1818     printf("  SAT Product identification: %s\n", b);
1819     memcpy(b, buff + 32, 4);
1820     b[4] = '\0';
1821     printf("  SAT Product revision level: %s\n", b);
1822     if (len < 56)
1823         return;
1824     ata_transp = (0x34 == buff[36]) ? "SATA" : "PATA";
1825     if (do_long) {
1826         printf("  Device signature [%s] (in hex):\n", ata_transp);
1827         dStrHex((const char *)buff + 36, 20, 0);
1828     } else
1829         printf("  Device signature indicates %s transport\n", ata_transp);
1830     if (len < 60)
1831         return;
1832     is_be = sg_is_big_endian();
1833     if ((0xec == buff[56]) || (0xa1 == buff[56])) {
1834         cp = (0xa1 == buff[56]) ? "PACKET " : "";
1835         printf("  ATA command IDENTIFY %sDEVICE response summary:\n", cp);
1836         num = sg_ata_get_chars((const unsigned short *)(buff + 60), 27, 20,
1837                                is_be, b);
1838         b[num] = '\0';
1839         printf("    model: %s\n", b);
1840         num = sg_ata_get_chars((const unsigned short *)(buff + 60), 10, 10,
1841                                is_be, b);
1842         b[num] = '\0';
1843         printf("    serial number: %s\n", b);
1844         num = sg_ata_get_chars((const unsigned short *)(buff + 60), 23, 4,
1845                                is_be, b);
1846         b[num] = '\0';
1847         printf("    firmware revision: %s\n", b);
1848         if (do_long)
1849             printf("  ATA command IDENTIFY %sDEVICE response in hex:\n", cp);
1850     } else if (do_long)
1851         printf("  ATA command 0x%x got following response:\n",
1852                (unsigned int)buff[56]);
1853     if (len < 572)
1854         return;
1855     if (2 == do_hex)
1856         dStrHex((const char *)(buff + 60), 512, 0);
1857     else if (do_long)
1858         dWordHex((const unsigned short *)(buff + 60), 256, 0, is_be);
1859 }
1860 
1861 
1862 /* VPD_POWER_CONDITION 0x8a */
1863 static void
decode_power_condition(unsigned char * buff,int len,int do_hex)1864 decode_power_condition(unsigned char * buff, int len, int do_hex)
1865 {
1866     if (len < 18) {
1867         pr2serr("Power condition VPD page length too short=%d\n", len);
1868         return;
1869     }
1870     if (do_hex) {
1871         dStrHex((const char *)buff, len, (1 == do_hex) ? 0 : -1);
1872         return;
1873     }
1874     printf("  Standby_y=%d Standby_z=%d Idle_c=%d Idle_b=%d Idle_a=%d\n",
1875            !!(buff[4] & 0x2), !!(buff[4] & 0x1),
1876            !!(buff[5] & 0x4), !!(buff[5] & 0x2), !!(buff[5] & 0x1));
1877     printf("  Stopped condition recovery time (ms) %d\n",
1878            sg_get_unaligned_be16(buff + 6));
1879     printf("  Standby_z condition recovery time (ms) %d\n",
1880            sg_get_unaligned_be16(buff + 8));
1881     printf("  Standby_y condition recovery time (ms) %d\n",
1882            sg_get_unaligned_be16(buff + 10));
1883     printf("  Idle_a condition recovery time (ms) %d\n",
1884            sg_get_unaligned_be16(buff + 12));
1885     printf("  Idle_b condition recovery time (ms) %d\n",
1886            sg_get_unaligned_be16(buff + 14));
1887     printf("  Idle_c condition recovery time (ms) %d\n",
1888            sg_get_unaligned_be16(buff + 16));
1889 }
1890 
1891 /* VPD_DEVICE_CONSTITUENTS 0x8b */
1892 static void
decode_dev_const_vpd(unsigned char * buff,int len,int do_hex)1893 decode_dev_const_vpd(unsigned char * buff, int len, int do_hex)
1894 {
1895     int k, j, bump, cd_len;
1896     unsigned char * ucp;
1897     const char * dcp = "Device constituents VPD page";
1898 
1899     if ((1 == do_hex) || (do_hex > 2)) {
1900         dStrHex((const char *)buff, len, (1 == do_hex) ? 0 : -1);
1901         return;
1902     }
1903     if (len < 4) {
1904         pr2serr("%s length too short=%d\n", dcp, len);
1905         return;
1906     }
1907     len -= 4;
1908     ucp = buff + 4;
1909     for (k = 0, j = 0; k < len; k += bump, ucp += bump, ++j) {
1910 
1911 
1912         printf("  Constituent descriptor %d:\n", j + 1);
1913         if ((k + 36) > len) {
1914             pr2serr("%s, short descriptor length=36, left=%d\n", dcp,
1915                     (len - k));
1916             return;
1917         }
1918         printf("    Constituent type: 0x%x\n",
1919                sg_get_unaligned_be16(ucp + 0));
1920         printf("    Constituent device type: 0x%x\n", ucp[2]);
1921         printf("    Vendor_identification: %.8s\n", ucp + 4);
1922         printf("    Product_identification: %.16s\n", ucp + 12);
1923         printf("    Product_revision_level: %.4s\n", ucp + 28);
1924         cd_len = sg_get_unaligned_be16(ucp + 34);
1925         bump = 36 + cd_len;
1926         if ((k + bump) > len) {
1927             pr2serr("%s, short descriptor length=%d, left=%d\n", dcp, bump,
1928                     (len - k));
1929             return;
1930         }
1931         if (cd_len > 0) {
1932             printf("   Constituent specific descriptor list (in hex):\n");
1933             dStrHex((const char *)(ucp + 36), cd_len, 1);
1934         }
1935     }
1936 }
1937 
1938 static const char * power_unit_arr[] =
1939 {
1940     "Gigawatts",
1941     "Megawatts",
1942     "Kilowatts",
1943     "Watts",
1944     "Milliwatts",
1945     "Microwatts",
1946     "Unit reserved",
1947     "Unit reserved",
1948 };
1949 
1950 /* VPD_POWER_CONSUMPTION */
1951 static void
decode_power_consumption_vpd(unsigned char * buff,int len,int do_hex)1952 decode_power_consumption_vpd(unsigned char * buff, int len, int do_hex)
1953 {
1954     int k, bump;
1955     unsigned char * ucp;
1956     unsigned int value;
1957     const char * pcp = "Power consumption VPD page";
1958 
1959     if ((1 == do_hex) || (do_hex > 2)) {
1960         dStrHex((const char *)buff, len, (1 == do_hex) ? 1 : -1);
1961         return;
1962     }
1963     if (len < 4) {
1964         pr2serr("%s length too short=%d\n", pcp,len);
1965         return;
1966     }
1967     len -= 4;
1968     ucp = buff + 4;
1969     for (k = 0; k < len; k += bump, ucp += bump) {
1970         bump = 4;
1971         if ((k + bump) > len) {
1972             pr2serr("%s, short descriptor length=%d, left=%d\n", pcp, bump,
1973                     (len - k));
1974             return;
1975         }
1976         if (do_hex > 1)
1977             dStrHex((const char *)ucp, 4, 1);
1978         else {
1979             value = sg_get_unaligned_be16(ucp + 2);
1980             printf("  Power consumption identifier: 0x%x", ucp[0]);
1981             if (value >= 1000 && (ucp[1] & 0x7) > 0)
1982                 printf("    Maximum power consumption: %d.%03d %s\n",
1983                        value / 1000, value % 1000,
1984                        power_unit_arr[(ucp[1] & 0x7) - 1]);
1985             else
1986                 printf("    Maximum power consumption: %u %s\n",
1987                        value, power_unit_arr[ucp[1] & 0x7]);
1988         }
1989     }
1990 }
1991 
1992 /* This is xcopy(LID4) related: "ROD" == Representation Of Data
1993  * Used by VPD_3PARTY_COPY */
1994 static void
decode_rod_descriptor(const unsigned char * buff,int len)1995 decode_rod_descriptor(const unsigned char * buff, int len)
1996 {
1997     const unsigned char * ucp = buff;
1998     int k, bump;
1999 
2000     for (k = 0; k < len; k += bump, ucp += bump) {
2001         bump = sg_get_unaligned_be16(ucp + 2) + 4;
2002         switch (ucp[0]) {
2003             case 0:
2004                 /* Block ROD device type specific descriptor */
2005                 printf("  Optimal block ROD length granularity: %d\n",
2006                        sg_get_unaligned_be16(ucp + 6));
2007                 printf("  Maximum Bytes in block ROD: %" PRIu64 "\n",
2008                        sg_get_unaligned_be64(ucp + 8));
2009                 printf("  Optimal Bytes in block ROD transfer: %" PRIu64 "\n",
2010                        sg_get_unaligned_be64(ucp + 16));
2011                 printf("  Optimal Bytes to token per segment: %" PRIu64 "\n",
2012                        sg_get_unaligned_be64(ucp + 24));
2013                 printf("  Optimal Bytes from token per segment:"
2014                        " %" PRIu64 "\n", sg_get_unaligned_be64(ucp + 32));
2015                 break;
2016             case 1:
2017                 /* Stream ROD device type specific descriptor */
2018                 printf("  Maximum Bytes in stream ROD: %" PRIu64 "\n",
2019                        sg_get_unaligned_be64(ucp + 8));
2020                 printf("  Optimal Bytes in stream ROD transfer:"
2021                        " %" PRIu64 "\n", sg_get_unaligned_be64(ucp + 16));
2022                 break;
2023             case 3:
2024                 /* Copy manager ROD device type specific descriptor */
2025                 printf("  Maximum Bytes in processor ROD: %" PRIu64 "\n",
2026                        sg_get_unaligned_be64(ucp + 8));
2027                 printf("  Optimal Bytes in processor ROD transfer:"
2028                        " %" PRIu64 "\n", sg_get_unaligned_be64(ucp + 16));
2029                 break;
2030             default:
2031                 printf("  Unhandled descriptor (format %d, device type %d)\n",
2032                        ucp[0] >> 5, ucp[0] & 0x1F);
2033                 break;
2034         }
2035     }
2036 }
2037 
2038 struct tpc_desc_type {
2039     unsigned char code;
2040     const char * name;
2041 };
2042 
2043 static struct tpc_desc_type tpc_desc_arr[] = {
2044     {0x0, "block -> stream"},
2045     {0x1, "stream -> block"},
2046     {0x2, "block -> block"},
2047     {0x3, "stream -> stream"},
2048     {0x4, "inline -> stream"},
2049     {0x5, "embedded -> stream"},
2050     {0x6, "stream -> discard"},
2051     {0x7, "verify CSCD"},
2052     {0x8, "block<o> -> stream"},
2053     {0x9, "stream -> block<o>"},
2054     {0xa, "block<o> -> block<o>"},
2055     {0xb, "block -> stream & application_client"},
2056     {0xc, "stream -> block & application_client"},
2057     {0xd, "block -> block & application_client"},
2058     {0xe, "stream -> stream&application_client"},
2059     {0xf, "stream -> discard&application_client"},
2060     {0x10, "filemark -> tape"},
2061     {0x11, "space -> tape"},            /* obsolete: spc5r02 */
2062     {0x12, "locate -> tape"},           /* obsolete: spc5r02 */
2063     {0x13, "<i>tape -> <i>tape"},
2064     {0x14, "register persistent reservation key"},
2065     {0x15, "third party persistent reservation source I_T nexus"},
2066     {0x16, "<i>block -> <i>block"},
2067     {0x17, "positioning -> tape"},      /* this and next added spc5r02 */
2068     {0x18, "<loi>tape -> <loi>tape"},   /* loi: logical object identifier */
2069     {0xbe, "ROD <- block range(n)"},
2070     {0xbf, "ROD <- block range(1)"},
2071     {0xe0, "CSCD: FC N_Port_Name"},
2072     {0xe1, "CSCD: FC N_Port_ID"},
2073     {0xe2, "CSCD: FC N_Port_ID with N_Port_Name, checking"},
2074     {0xe3, "CSCD: Parallel interface: I_T"},
2075     {0xe4, "CSCD: Identification Descriptor"},
2076     {0xe5, "CSCD: IPv4"},
2077     {0xe6, "CSCD: Alias"},
2078     {0xe7, "CSCD: RDMA"},
2079     {0xe8, "CSCD: IEEE 1394 EUI-64"},
2080     {0xe9, "CSCD: SAS SSP"},
2081     {0xea, "CSCD: IPv6"},
2082     {0xeb, "CSCD: IP copy service"},
2083     {0xfe, "CSCD: ROD"},
2084     {0xff, "CSCD: extension"},
2085     {0x0, NULL},
2086 };
2087 
2088 static const char *
get_tpc_desc_name(unsigned char code)2089 get_tpc_desc_name(unsigned char code)
2090 {
2091     const struct tpc_desc_type * dtp;
2092 
2093     for (dtp = tpc_desc_arr; dtp->name; ++dtp) {
2094         if (code == dtp->code)
2095             return dtp->name;
2096     }
2097     return "";
2098 }
2099 
2100 struct tpc_rod_type {
2101     uint32_t type;
2102     const char * name;
2103 };
2104 
2105 static struct tpc_rod_type tpc_rod_arr[] = {
2106     {0x0, "copy manager internal"},
2107     {0x10000, "access upon reference"},
2108     {0x800000, "point in time copy - default"},
2109     {0x800001, "point in time copy - change vulnerable"},
2110     {0x800002, "point in time copy - persistent"},
2111     {0x80ffff, "point in time copy - any"},
2112     {0xffff0001, "block device zero"},
2113     {0x0, NULL},
2114 };
2115 
2116 static const char *
get_tpc_rod_name(uint32_t rod_type)2117 get_tpc_rod_name(uint32_t rod_type)
2118 {
2119     const struct tpc_rod_type * rtp;
2120 
2121     for (rtp = tpc_rod_arr; rtp->name; ++rtp) {
2122         if (rod_type == rtp->type)
2123             return rtp->name;
2124     }
2125     return "";
2126 }
2127 
2128 struct cscd_desc_id_t {
2129     uint16_t id;
2130     const char * name;
2131 };
2132 
2133 static struct cscd_desc_id_t cscd_desc_id_arr[] = {
2134     /* only values higher than 0x7ff are listed */
2135     {0xc000, "copy src or dst null LU, pdt=0"},
2136     {0xc001, "copy src or dst null LU, pdt=1"},
2137     {0xf800, "copy src or dst in ROD token"},
2138     {0xffff, "copy src or dst is copy manager LU"},
2139     {0x0, NULL},
2140 };
2141 
2142 static const char *
get_cscd_desc_id_name(uint16_t cscd_desc_id)2143 get_cscd_desc_id_name(uint16_t cscd_desc_id)
2144 {
2145     const struct cscd_desc_id_t * cdip;
2146 
2147     for (cdip = cscd_desc_id_arr; cdip->name; ++cdip) {
2148         if (cscd_desc_id == cdip->id)
2149             return cdip->name;
2150     }
2151     return "";
2152 }
2153 
2154 /* VPD_3PARTY_COPY [3PC, third party copy] */
2155 static void
decode_3party_copy_vpd(unsigned char * buff,int len,int do_hex,int verbose)2156 decode_3party_copy_vpd(unsigned char * buff, int len, int do_hex, int verbose)
2157 {
2158     int j, k, m, bump, desc_type, desc_len, sa_len;
2159     unsigned int u;
2160     const unsigned char * ucp;
2161     const char * cp;
2162     uint64_t ull;
2163     char b[80];
2164 
2165     if (len < 4) {
2166         pr2serr("Third-party Copy VPD page length too short=%d\n", len);
2167         return;
2168     }
2169     len -= 4;
2170     ucp = buff + 4;
2171     for (k = 0; k < len; k += bump, ucp += bump) {
2172         desc_type = sg_get_unaligned_be16(ucp);
2173         desc_len = sg_get_unaligned_be16(ucp + 2);
2174         if (verbose)
2175             printf("Descriptor type=%d [0x%x] , len %d\n", desc_type,
2176                    desc_type, desc_len);
2177         bump = 4 + desc_len;
2178         if ((k + bump) > len) {
2179             pr2serr("Third-party Copy VPD page, short descriptor length=%d, "
2180                     "left=%d\n", bump, (len - k));
2181             return;
2182         }
2183         if (0 == desc_len)
2184             continue;
2185         if (2 == do_hex)
2186             dStrHex((const char *)ucp + 4, desc_len, 1);
2187         else if (do_hex > 2)
2188             dStrHex((const char *)ucp, bump, 1);
2189         else {
2190             switch (desc_type) {
2191             case 0x0000:    /* Required if POPULATE TOKEN (or friend) used */
2192                 printf(" Block Device ROD Token Limits:\n");
2193                 printf("  Maximum Range Descriptors: %d\n",
2194                        sg_get_unaligned_be16(ucp + 10));
2195                 u = sg_get_unaligned_be32(ucp + 12);
2196                 printf("  Maximum Inactivity Timeout: %u seconds\n", u);
2197                 u = sg_get_unaligned_be32(ucp + 16);
2198                 printf("  Default Inactivity Timeout: %u seconds\n", u);
2199                 ull = sg_get_unaligned_be64(ucp + 20);
2200                 printf("  Maximum Token Transfer Size: %" PRIu64 "\n", ull);
2201                 ull = sg_get_unaligned_be64(ucp + 28);
2202                 printf("  Optimal Transfer Count: %" PRIu64 "\n", ull);
2203                 break;
2204             case 0x0001:    /* Mandatory (SPC-4) */
2205                 printf(" Supported Commands:\n");
2206                 j = 0;
2207                 while (j < ucp[4]) {
2208                     sa_len = ucp[6 + j];
2209                     for (m = 0; m < sa_len; ++m) {
2210                         sg_get_opcode_sa_name(ucp[5 + j], ucp[7 + j + m],
2211                                               0, sizeof(b), b);
2212                         printf("  %s\n", b);
2213                     }
2214                     j += sa_len + 2;
2215                 }
2216                 break;
2217             case 0x0004:
2218                 printf(" Parameter Data:\n");
2219                 printf("  Maximum CSCD Descriptor Count: %d\n",
2220                        sg_get_unaligned_be16(ucp + 8));
2221                 printf("  Maximum Segment Descriptor Count: %d\n",
2222                        sg_get_unaligned_be16(ucp + 10));
2223                 u = sg_get_unaligned_be32(ucp + 12);
2224                 printf("  Maximum Descriptor List Length: %u\n", u);
2225                 u = sg_get_unaligned_be32(ucp + 16);
2226                 printf("  Maximum Inline Data Length: %u\n", u);
2227                 break;
2228             case 0x0008:
2229                 printf(" Supported Descriptors:\n");
2230                 for (j = 0; j < ucp[4]; j++) {
2231                     cp = get_tpc_desc_name(ucp[5 + j]);
2232                     if (strlen(cp) > 0)
2233                         printf("  %s [0x%x]\n", cp, ucp[5 + j]);
2234                     else
2235                         printf("  0x%x\n", ucp[5 + j]);
2236                 }
2237                 break;
2238             case 0x000C:
2239                 printf(" Supported CSCD IDs (above 0x7ff):\n");
2240                 for (j = 0; j < sg_get_unaligned_be16(ucp + 4); j += 2) {
2241                     u = sg_get_unaligned_be16(ucp + 6 + j);
2242                     cp = get_cscd_desc_id_name(u);
2243                     if (strlen(cp) > 0)
2244                         printf("  %s [0x%04x]\n", cp, u);
2245                     else
2246                         printf("  0x%04x\n", u);
2247                 }
2248                 break;
2249             case 0x0106:
2250                 printf(" ROD Token Features:\n");
2251                 printf("  Remote Tokens: %d\n", ucp[4] & 0x0f);
2252                 u = sg_get_unaligned_be32(ucp + 16);
2253                 printf("  Minimum Token Lifetime: %u seconds\n", u);
2254                 u = sg_get_unaligned_be32(ucp + 20);
2255                 printf("  Maximum Token Lifetime: %u seconds\n", u);
2256                 u = sg_get_unaligned_be32(ucp + 24);
2257                 printf("  Maximum Token inactivity timeout: %u\n", u);
2258                 decode_rod_descriptor(ucp + 48,
2259                                       sg_get_unaligned_be16(ucp + 46));
2260                 break;
2261             case 0x0108:
2262                 printf(" Supported ROD Token and ROD Types:\n");
2263                 for (j = 0; j < sg_get_unaligned_be16(ucp + 6); j+= 64) {
2264                     u = sg_get_unaligned_be32(ucp + 8 + j);
2265                     cp = get_tpc_rod_name(u);
2266                     if (strlen(cp) > 0)
2267                         printf("  ROD Type: %s [0x%x]\n", cp, u);
2268                     else
2269                         printf("  ROD Type: 0x%x\n", u);
2270                     printf("    Internal: %s\n",
2271                            (ucp[8 + j + 4] & 0x80) ? "yes" : "no");
2272                     printf("    Token In: %s\n",
2273                            (ucp[8 + j + 4] & 0x02) ? "yes" : "no");
2274                     printf("    Token Out: %s\n",
2275                            (ucp[8 + j + 4] & 0x01) ? "yes" : "no");
2276                     printf("    Preference: %d\n",
2277                            sg_get_unaligned_be16(ucp + 8 + j + 6));
2278                 }
2279                 break;
2280             case 0x8001:    /* Mandatory (SPC-4) */
2281                 printf(" General Copy Operations:\n");
2282                 u = sg_get_unaligned_be32(ucp + 4);
2283                 printf("  Total Concurrent Copies: %u\n", u);
2284                 u = sg_get_unaligned_be32(ucp + 8);
2285                 printf("  Maximum Identified Concurrent Copies: %u\n", u);
2286                 u = sg_get_unaligned_be32(ucp + 12);
2287                 printf("  Maximum Segment Length: %u\n", u);
2288                 ull = (1 << ucp[16]); /* field is power of 2 */
2289                 printf("  Data Segment Granularity: %" PRIu64 "\n", ull);
2290                 ull = (1 << ucp[17]);
2291                 printf("  Inline Data Granularity: %" PRIu64 "\n", ull);
2292                 break;
2293             case 0x9101:
2294                 printf(" Stream Copy Operations:\n");
2295                 u = sg_get_unaligned_be32(ucp + 4);
2296                 printf("  Maximum Stream Device Transfer Size: %u\n", u);
2297                 break;
2298             case 0xC001:
2299                 printf(" Held Data:\n");
2300                 u = sg_get_unaligned_be32(ucp + 4);
2301                 printf("  Held Data Limit: %u\n", u);
2302                 ull = (1 << ucp[8]);
2303                 printf("  Held Data Granularity: %" PRIu64 "\n", ull);
2304                 break;
2305             default:
2306                 pr2serr("Unexpected type=%d\n", desc_type);
2307                 dStrHexErr((const char *)ucp, bump, 1);
2308                 break;
2309             }
2310         }
2311     }
2312 }
2313 
2314 /* VPD_PROTO_LU */
2315 static void
decode_proto_lu_vpd(unsigned char * buff,int len,int do_hex)2316 decode_proto_lu_vpd(unsigned char * buff, int len, int do_hex)
2317 {
2318     int k, bump, rel_port, desc_len, proto;
2319     unsigned char * ucp;
2320 
2321     if (1 == do_hex) {
2322         dStrHex((const char *)buff, len, 0);
2323         return;
2324     }
2325     if (len < 4) {
2326         pr2serr("Protocol-specific logical unit information VPD page length "
2327                 "too short=%d\n", len);
2328         return;
2329     }
2330     len -= 4;
2331     ucp = buff + 4;
2332     for (k = 0; k < len; k += bump, ucp += bump) {
2333         rel_port = sg_get_unaligned_be16(ucp);
2334         printf("  Relative port=%d\n", rel_port);
2335         proto = ucp[2] & 0xf;
2336         desc_len = sg_get_unaligned_be16(ucp + 6);
2337         bump = 8 + desc_len;
2338         if ((k + bump) > len) {
2339             pr2serr("Protocol-specific logical unit information VPD page, "
2340                     "short descriptor length=%d, left=%d\n", bump, (len - k));
2341             return;
2342         }
2343         if (0 == desc_len)
2344             continue;
2345         if (2 == do_hex)
2346             dStrHex((const char *)ucp + 8, desc_len, 1);
2347         else if (do_hex > 2)
2348             dStrHex((const char *)ucp, bump, 1);
2349         else {
2350             switch (proto) {
2351             case TPROTO_SAS:
2352                 printf("    Protocol identifier: SAS\n");
2353                 printf("    TLR control supported: %d\n", !!(ucp[8] & 0x1));
2354                 break;
2355             default:
2356                 pr2serr("Unexpected proto=%d\n", proto);
2357                 dStrHexErr((const char *)ucp, bump, 1);
2358                 break;
2359             }
2360         }
2361     }
2362 }
2363 
2364 /* VPD_PROTO_PORT */
2365 static void
decode_proto_port_vpd(unsigned char * buff,int len,int do_hex)2366 decode_proto_port_vpd(unsigned char * buff, int len, int do_hex)
2367 {
2368     int k, j, bump, rel_port, desc_len, proto;
2369     unsigned char * ucp;
2370     unsigned char * pidp;
2371 
2372     if (1 == do_hex) {
2373         dStrHex((const char *)buff, len, 0);
2374         return;
2375     }
2376     if (len < 4) {
2377         pr2serr("Protocol-specific port information VPD page length too "
2378                 "short=%d\n", len);
2379         return;
2380     }
2381     len -= 4;
2382     ucp = buff + 4;
2383     for (k = 0; k < len; k += bump, ucp += bump) {
2384         rel_port = sg_get_unaligned_be16(ucp);
2385         printf("  Relative port=%d\n", rel_port);
2386         proto = ucp[2] & 0xf;
2387         desc_len = sg_get_unaligned_be16(ucp + 6);
2388         bump = 8 + desc_len;
2389         if ((k + bump) > len) {
2390             pr2serr("Protocol-specific port VPD page, short descriptor "
2391                     "length=%d, left=%d\n", bump, (len - k));
2392             return;
2393         }
2394         if (0 == desc_len)
2395             continue;
2396         if (2 == do_hex)
2397             dStrHex((const char *)ucp + 8, desc_len, 1);
2398         else if (do_hex > 2)
2399             dStrHex((const char *)ucp, bump, 1);
2400         else {
2401             switch (proto) {
2402             case TPROTO_SAS:    /* page added in spl3r02 */
2403                 printf("    power disable supported (pwr_d_s)=%d\n",
2404                        !!(ucp[3] & 0x1));       /* added spl3r03 */
2405                 pidp = ucp + 8;
2406                 for (j = 0; j < desc_len; j += 4, pidp += 4)
2407                     printf("      phy id=%d, SSP persistent capable=%d\n",
2408                            pidp[1], (0x1 & pidp[2]));
2409                 break;
2410             default:
2411                 pr2serr("Unexpected proto=%d\n", proto);
2412                 dStrHexErr((const char *)ucp, bump, 1);
2413                 break;
2414             }
2415         }
2416     }
2417 }
2418 
2419 /* VPD_BLOCK_LIMITS sbc */
2420 /* VPD_SA_DEV_CAP ssc */
2421 /* VPD_OSD_INFO osd */
2422 static void
decode_b0_vpd(unsigned char * buff,int len,int do_hex,int pdt)2423 decode_b0_vpd(unsigned char * buff, int len, int do_hex, int pdt)
2424 {
2425     unsigned int u;
2426     unsigned char b[4];
2427 
2428     if (do_hex) {
2429         dStrHex((const char *)buff, len, (1 == do_hex) ? 0 : -1);
2430         return;
2431     }
2432     switch (pdt) {
2433     case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
2434         if (len < 16) {
2435             pr2serr("Block limits VPD page length too short=%d\n", len);
2436             return;
2437         }
2438         printf("  Write same non-zero (WSNZ): %d\n", !!(buff[4] & 0x1));
2439         printf("  Maximum compare and write length: %u blocks\n",
2440                buff[5]);
2441         u = sg_get_unaligned_be16(buff + 6);
2442         printf("  Optimal transfer length granularity: %u blocks\n", u);
2443         u = sg_get_unaligned_be32(buff + 8);
2444         printf("  Maximum transfer length: %u blocks\n", u);
2445         u = sg_get_unaligned_be32(buff + 12);
2446         printf("  Optimal transfer length: %u blocks\n", u);
2447         if (len > 19) {     /* added in sbc3r09 */
2448             u = sg_get_unaligned_be32(buff + 16);
2449             printf("  Maximum prefetch length: %u blocks\n", u);
2450             /* was 'Maximum prefetch transfer length' prior to sbc3r33 */
2451         }
2452         if (len > 27) {     /* added in sbc3r18 */
2453             u = sg_get_unaligned_be32(buff + 20);
2454             printf("  Maximum unmap LBA count: %u\n", u);
2455             u = sg_get_unaligned_be32(buff + 24);
2456             printf("  Maximum unmap block descriptor count: %u\n", u);
2457         }
2458         if (len > 35) {     /* added in sbc3r19 */
2459             u = sg_get_unaligned_be32(buff + 28);
2460             printf("  Optimal unmap granularity: %u\n", u);
2461             printf("  Unmap granularity alignment valid: %u\n",
2462                    !!(buff[32] & 0x80));
2463             memcpy(b, buff + 32, 4);
2464             b[0] &= 0x7f;       /* mask off top bit */
2465             u = sg_get_unaligned_be32(b);
2466             printf("  Unmap granularity alignment: %u\n", u);
2467             /* added in sbc3r26 */
2468             printf("  Maximum write same length: 0x%" PRIx64 " blocks\n",
2469                    sg_get_unaligned_be64(buff + 36));
2470         }
2471         if (len > 44) {     /* added in sbc4r02 */
2472             u = sg_get_unaligned_be32(buff + 44);
2473             printf("  Maximum atomic transfer length: %u\n", u);
2474             u = sg_get_unaligned_be32(buff + 48);
2475             printf("  Atomic alignment: %u\n", u);
2476             u = sg_get_unaligned_be32(buff + 52);
2477             printf("  Atomic transfer length granularity: %u\n", u);
2478         }
2479         if (len > 56) {     /* added in sbc4r04 */
2480             u = sg_get_unaligned_be32(buff + 56);
2481             printf("  Maximum atomic transfer length with atomic boundary: "
2482                    "%u\n", u);
2483             u = sg_get_unaligned_be32(buff + 60);
2484             printf("  Maximum atomic boundary size: %u\n", u);
2485         }
2486         break;
2487     case PDT_TAPE: case PDT_MCHANGER:
2488         printf("  WORM=%d\n", !!(buff[4] & 0x1));
2489         break;
2490     case PDT_OSD:
2491     default:
2492         pr2serr("  Unable to decode pdt=0x%x, in hex:\n", pdt);
2493         dStrHexErr((const char *)buff, len, 0);
2494         break;
2495     }
2496 }
2497 
2498 static const char * product_type_arr[] =
2499 {
2500     "Not specified",
2501     "CFast",
2502     "CompactFlash",
2503     "MemoryStick",
2504     "MultiMediaCard",
2505     "Secure Digital Card (SD)",
2506     "XQD",
2507     "Universal Flash Storage Card (UFS)",
2508 };
2509 
2510 /* VPD_BLOCK_DEV_CHARS sbc */
2511 /* VPD_MAN_ASS_SN ssc */
2512 /* VPD_SECURITY_TOKEN osd */
2513 static void
decode_b1_vpd(unsigned char * buff,int len,int do_hex,int pdt)2514 decode_b1_vpd(unsigned char * buff, int len, int do_hex, int pdt)
2515 {
2516     unsigned int u, k;
2517 
2518     if (do_hex) {
2519         dStrHex((const char *)buff, len, (1 == do_hex) ? 0 : -1);
2520         return;
2521     }
2522     switch (pdt) {
2523     case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
2524         if (len < 64) {
2525             pr2serr("Block device characteristics VPD page length too "
2526                     "short=%d\n", len);
2527             return;
2528         }
2529         u = sg_get_unaligned_be16(buff + 4);
2530         if (0 == u)
2531             printf("  Medium rotation rate is not reported\n");
2532         else if (1 == u)
2533             printf("  Non-rotating medium (e.g. solid state)\n");
2534         else if ((u < 0x401) || (0xffff == u))
2535             printf("  Reserved [0x%x]\n", u);
2536         else
2537             printf("  Nominal rotation rate: %u rpm\n", u);
2538         u = buff[6];
2539         k = sizeof(product_type_arr) / sizeof(product_type_arr[0]);
2540         if (u < k)
2541             printf("  Product type: %s\n", product_type_arr[u]);
2542         else if (u < 0xf0)
2543             printf("  Product type: Reserved [0x%x]\n", u);
2544         else
2545             printf("  Product type: Vendor specific [0x%x]\n", u);
2546         printf("  WABEREQ=%d\n", (buff[7] >> 6) & 0x3);
2547         printf("  WACEREQ=%d\n", (buff[7] >> 4) & 0x3);
2548         u = buff[7] & 0xf;
2549         printf("  Nominal form factor");
2550         switch (u) {
2551         case 0:
2552             printf(" not reported\n");
2553             break;
2554         case 1:
2555             printf(": 5.25 inch\n");
2556             break;
2557         case 2:
2558             printf(": 3.5 inch\n");
2559             break;
2560         case 3:
2561             printf(": 2.5 inch\n");
2562             break;
2563         case 4:
2564             printf(": 1.8 inch\n");
2565             break;
2566         case 5:
2567             printf(": less then 1.8 inch\n");
2568             break;
2569         default:
2570             printf(": reserved\n");
2571             break;
2572         }
2573         printf("  ZONED=%d\n", (buff[8] >> 4) & 0x3);   /* sbc4r04 */
2574         printf("  BOCS=%d\n", !!(buff[8] & 0x4));       /* sbc4r07 */
2575         printf("  FUAB=%d\n", !!(buff[8] & 0x2));
2576         printf("  VBULS=%d\n", !!(buff[8] & 0x1));
2577         break;
2578     case PDT_TAPE: case PDT_MCHANGER: case PDT_ADC:
2579         printf("  Manufacturer-assigned serial number: %.*s\n",
2580                len - 4, buff + 4);
2581         break;
2582     default:
2583         pr2serr("  Unable to decode pdt=0x%x, in hex:\n", pdt);
2584         dStrHexErr((const char *)buff, len, 0);
2585         break;
2586     }
2587 }
2588 
2589 /* VPD_LB_PROVISIONING */
2590 static int
decode_block_lb_prov_vpd(unsigned char * b,int len,const struct opts_t * op)2591 decode_block_lb_prov_vpd(unsigned char * b, int len, const struct opts_t * op)
2592 {
2593     int dp;
2594 
2595     if (len < 4) {
2596         pr2serr("Logical block provisioning page too short=%d\n", len);
2597         return SG_LIB_CAT_MALFORMED;
2598     }
2599     printf("  Unmap command supported (LBPU): %d\n", !!(0x80 & b[5]));
2600     printf("  Write same (16) with unmap bit supported (LBWS): %d\n",
2601            !!(0x40 & b[5]));
2602     printf("  Write same (10) with unmap bit supported (LBWS10): %d\n",
2603            !!(0x20 & b[5]));
2604     printf("  Logical block provisioning read zeros (LBPRZ): %d\n",
2605            (0x7 & (b[5] >> 2)));
2606     printf("  Anchored LBAs supported (ANC_SUP): %d\n", !!(0x2 & b[5]));
2607     dp = !!(b[5] & 0x1);
2608     printf("  Threshold exponent: %d\n", b[4]);
2609     printf("  Descriptor present (DP): %d\n", dp);
2610     printf("  Minimum percentage: %d\n", 0x1f & (b[6] >> 3));
2611     printf("  Provisioning type: %d\n", b[6] & 0x7);
2612     printf("  Threshold percentage: %d\n", b[7]);
2613     if (dp) {
2614         const unsigned char * ucp;
2615         int i_len, p_id, c_set, piv, assoc, desig_type;
2616 
2617         ucp = b + 8;
2618         i_len = ucp[3];
2619         if (0 == i_len) {
2620             pr2serr("Logical block provisioning page provisioning group "
2621                     "descriptor too short=%d\n", i_len);
2622             return 0;
2623         }
2624         printf("  Provisioning group descriptor\n");
2625         p_id = ((ucp[0] >> 4) & 0xf);
2626         c_set = (ucp[0] & 0xf);
2627         piv = ((ucp[1] & 0x80) ? 1 : 0);
2628         assoc = ((ucp[1] >> 4) & 0x3);
2629         desig_type = (ucp[1] & 0xf);
2630         decode_designation_descriptor(ucp, i_len, p_id, c_set, piv, assoc,
2631                                       desig_type, 1, op);
2632     }
2633     return 0;
2634 }
2635 
2636 /* VPD_SUP_BLOCK_LENS  0xb4 */
2637 static void
decode_sup_block_lens_vpd(unsigned char * buff,int len)2638 decode_sup_block_lens_vpd(unsigned char * buff, int len)
2639 {
2640     int k;
2641     unsigned int u;
2642     unsigned char * ucp;
2643 
2644     if (len < 4) {
2645         pr2serr("Supported block lengths and protection types VPD page "
2646                 "length too short=%d\n", len);
2647         return;
2648     }
2649     len -= 4;
2650     ucp = buff + 4;
2651     for (k = 0; k < len; k += 8, ucp += 8) {
2652         u = sg_get_unaligned_be32(ucp);
2653         printf("  Logical block length: %u\n", u);
2654         printf("    P_I_I_SUP: %d\n", !!(ucp[4] & 0x40));
2655         printf("    NO_PI_CHK: %d\n", !!(ucp[4] & 0x8));  /* sbc4r05 */
2656         printf("    GRD_CHK: %d\n", !!(ucp[4] & 0x4));
2657         printf("    APP_CHK: %d\n", !!(ucp[4] & 0x2));
2658         printf("    REF_CHK: %d\n", !!(ucp[4] & 0x1));
2659         printf("    T3PS_SUP: %d\n", !!(ucp[5] & 0x8));
2660         printf("    T2PS_SUP: %d\n", !!(ucp[5] & 0x4));
2661         printf("    T1PS_SUP: %d\n", !!(ucp[5] & 0x2));
2662         printf("    T0PS_SUP: %d\n", !!(ucp[5] & 0x1));
2663     }
2664 }
2665 
2666 /* VPD_BLOCK_DEV_C_EXTENS  0xb5 */
2667 static void
decode_block_dev_char_ext_vpd(unsigned char * b,int len)2668 decode_block_dev_char_ext_vpd(unsigned char * b, int len)
2669 {
2670     if (len < 16) {
2671         pr2serr("Block device characteristics extension VPD page "
2672                 "length too short=%d\n", len);
2673         return;
2674     }
2675     printf("  Utilization type: ");
2676     switch (b[5]) {
2677     case 1:
2678         printf("Combined writes and reads");
2679         break;
2680     case 2:
2681         printf("Writes only");
2682         break;
2683     case 3:
2684         printf("Separate writes and reads");
2685         break;
2686     default:
2687         printf("Reserved");
2688         break;
2689     }
2690     printf(" [0x%x]\n", b[5]);
2691     printf("  Utilization units: ");
2692     switch (b[6]) {
2693     case 2:
2694         printf("megabytes");
2695         break;
2696     case 3:
2697         printf("gigabytes");
2698         break;
2699     case 4:
2700         printf("terabytes");
2701         break;
2702     case 5:
2703         printf("petabytes");
2704         break;
2705     case 6:
2706         printf("exabytes");
2707         break;
2708     default:
2709         printf("Reserved");
2710         break;
2711     }
2712     printf(" [0x%x]\n", b[6]);
2713     printf("  Utilization interval: ");
2714     switch (b[7]) {
2715     case 0xa:
2716         printf("per day");
2717         break;
2718     case 0xe:
2719         printf("per year");
2720         break;
2721     default:
2722         printf("Reserved");
2723         break;
2724     }
2725     printf(" [0x%x]\n", b[7]);
2726     printf("  Utilization B: %u\n", sg_get_unaligned_be32(b + 8));
2727     printf("  Utilization A: %u\n", sg_get_unaligned_be32(b + 12));
2728 }
2729 
2730 /* VPD_LB_PROTECTION    (SSC)  [added in ssc5r02a] */
2731 static void
decode_lb_protection_vpd(unsigned char * buff,int len,int do_hex)2732 decode_lb_protection_vpd(unsigned char * buff, int len, int do_hex)
2733 {
2734     int k, bump;
2735     unsigned char * ucp;
2736 
2737     if ((1 == do_hex) || (do_hex > 2)) {
2738         dStrHex((const char *)buff, len, (1 == do_hex) ? 0 : -1);
2739         return;
2740     }
2741     if (len < 8) {
2742         pr2serr("Logical block protection VPD page length too short=%d\n",
2743                 len);
2744         return;
2745     }
2746     len -= 8;
2747     ucp = buff + 8;
2748     for (k = 0; k < len; k += bump, ucp += bump) {
2749         bump = 1 + ucp[0];
2750         printf("  method: %d, info_len: %d, LBP_W_C=%d, LBP_R_C=%d, "
2751                "RBDP_C=%d\n", ucp[1], 0x3f & ucp[2], !!(0x80 & ucp[3]),
2752                !!(0x40 & ucp[3]), !!(0x20 & ucp[3]));
2753         if ((k + bump) > len) {
2754             pr2serr("Logical block protection VPD page, short "
2755                     "descriptor length=%d, left=%d\n", bump, (len - k));
2756             return;
2757         }
2758     }
2759 }
2760 
2761 /* VPD_TA_SUPPORTED */
2762 static int
decode_tapealert_supported_vpd(unsigned char * b,int len)2763 decode_tapealert_supported_vpd(unsigned char * b, int len)
2764 {
2765     if (len < 12) {
2766         pr2serr("TapeAlert supported flags length too short=%d\n", len);
2767         return SG_LIB_CAT_MALFORMED;
2768     }
2769     printf("  Flag01h: %d  02h: %d  03h: %d  04h: %d  05h: %d  06h: %d  "
2770            "07h: %d  08h: %d\n", !!(b[4] & 0x80), !!(b[4] & 0x40),
2771            !!(b[4] & 0x20), !!(b[4] & 0x10), !!(b[4] & 0x8), !!(b[4] & 0x4),
2772            !!(b[4] & 0x2), !!(b[4] & 0x1));
2773     printf("  Flag09h: %d  0ah: %d  0bh: %d  0ch: %d  0dh: %d  0eh: %d  "
2774            "0fh: %d  10h: %d\n", !!(b[5] & 0x80), !!(b[5] & 0x40),
2775            !!(b[5] & 0x20), !!(b[5] & 0x10), !!(b[5] & 0x8), !!(b[5] & 0x4),
2776            !!(b[5] & 0x2), !!(b[5] & 0x1));
2777     printf("  Flag11h: %d  12h: %d  13h: %d  14h: %d  15h: %d  16h: %d  "
2778            "17h: %d  18h: %d\n", !!(b[6] & 0x80), !!(b[6] & 0x40),
2779            !!(b[6] & 0x20), !!(b[6] & 0x10), !!(b[6] & 0x8), !!(b[6] & 0x4),
2780            !!(b[6] & 0x2), !!(b[6] & 0x1));
2781     printf("  Flag19h: %d  1ah: %d  1bh: %d  1ch: %d  1dh: %d  1eh: %d  "
2782            "1fh: %d  20h: %d\n", !!(b[7] & 0x80), !!(b[7] & 0x40),
2783            !!(b[7] & 0x20), !!(b[7] & 0x10), !!(b[7] & 0x8), !!(b[7] & 0x4),
2784            !!(b[7] & 0x2), !!(b[7] & 0x1));
2785     printf("  Flag21h: %d  22h: %d  23h: %d  24h: %d  25h: %d  26h: %d  "
2786            "27h: %d  28h: %d\n", !!(b[8] & 0x80), !!(b[8] & 0x40),
2787            !!(b[8] & 0x20), !!(b[8] & 0x10), !!(b[8] & 0x8), !!(b[8] & 0x4),
2788            !!(b[8] & 0x2), !!(b[8] & 0x1));
2789     printf("  Flag29h: %d  2ah: %d  2bh: %d  2ch: %d  2dh: %d  2eh: %d  "
2790            "2fh: %d  30h: %d\n", !!(b[9] & 0x80), !!(b[9] & 0x40),
2791            !!(b[9] & 0x20), !!(b[9] & 0x10), !!(b[9] & 0x8), !!(b[9] & 0x4),
2792            !!(b[9] & 0x2), !!(b[9] & 0x1));
2793     printf("  Flag31h: %d  32h: %d  33h: %d  34h: %d  35h: %d  36h: %d  "
2794            "37h: %d  38h: %d\n", !!(b[10] & 0x80), !!(b[10] & 0x40),
2795            !!(b[10] & 0x20), !!(b[10] & 0x10), !!(b[10] & 0x8),
2796            !!(b[10] & 0x4), !!(b[10] & 0x2), !!(b[10] & 0x1));
2797     printf("  Flag39h: %d  3ah: %d  3bh: %d  3ch: %d  3dh: %d  3eh: %d  "
2798            "3fh: %d  40h: %d\n", !!(b[11] & 0x80), !!(b[11] & 0x40),
2799            !!(b[11] & 0x20), !!(b[11] & 0x10), !!(b[11] & 0x8),
2800            !!(b[11] & 0x4), !!(b[11] & 0x2), !!(b[11] & 0x1));
2801     return 0;
2802 }
2803 
2804 /* VPD_LB_PROVISIONING sbc */
2805 /* VPD_TA_SUPPORTED ssc */
2806 static void
decode_b2_vpd(unsigned char * buff,int len,int pdt,const struct opts_t * op)2807 decode_b2_vpd(unsigned char * buff, int len, int pdt,
2808               const struct opts_t * op)
2809 {
2810     if (op->do_hex) {
2811         dStrHex((const char *)buff, len, (1 == op->do_hex) ? 0 : -1);
2812         return;
2813     }
2814     switch (pdt) {
2815     case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
2816         decode_block_lb_prov_vpd(buff, len, op);
2817         break;
2818     case PDT_TAPE: case PDT_MCHANGER:
2819         decode_tapealert_supported_vpd(buff, len);
2820         break;
2821     default:
2822         pr2serr("  Unable to decode pdt=0x%x, in hex:\n", pdt);
2823         dStrHexErr((const char *)buff, len, 0);
2824         break;
2825     }
2826 }
2827 
2828 /* VPD_REFERRALS sbc */
2829 /* VPD_AUTOMATION_DEV_SN ssc */
2830 static void
decode_b3_vpd(unsigned char * b,int len,int do_hex,int pdt)2831 decode_b3_vpd(unsigned char * b, int len, int do_hex, int pdt)
2832 {
2833     char obuff[DEF_ALLOC_LEN];
2834     unsigned int u;
2835 
2836     if (do_hex) {
2837         dStrHex((const char *)b, len, (1 == do_hex) ? 0 : -1);
2838         return;
2839     }
2840     switch (pdt) {
2841     case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
2842         if (len < 16) {
2843             pr2serr("Referrals VPD page length too short=%d\n", len);
2844             break;
2845         }
2846         u = sg_get_unaligned_be32(b + 8);
2847         printf("  User data segment size: %u\n", u);
2848         u = sg_get_unaligned_be32(b + 12);
2849         printf("  User data segment multiplier: %u\n", u);
2850         break;
2851     case PDT_TAPE: case PDT_MCHANGER:
2852         memset(obuff, 0, sizeof(obuff));
2853         len -= 4;
2854         if (len >= (int)sizeof(obuff))
2855             len = sizeof(obuff) - 1;
2856         memcpy(obuff, b + 4, len);
2857         printf("  Automation device serial number: %s\n", obuff);
2858         break;
2859     default:
2860         pr2serr("  Unable to decode pdt=0x%x, in hex:\n", pdt);
2861         dStrHexErr((const char *)b, len, 0);
2862         break;
2863     }
2864 }
2865 
2866 /* VPD_SUP_BLOCK_LENS sbc */
2867 /* VPD_DTDE_ADDRESS ssc */
2868 static void
decode_b4_vpd(unsigned char * b,int len,int do_hex,int pdt)2869 decode_b4_vpd(unsigned char * b, int len, int do_hex, int pdt)
2870 {
2871     int k;
2872 
2873     if (do_hex) {
2874         dStrHex((const char *)b, len, (1 == do_hex) ? 0 : -1);
2875         return;
2876     }
2877     switch (pdt) {
2878     case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
2879         decode_sup_block_lens_vpd(b, len);
2880         break;
2881     case PDT_TAPE: case PDT_MCHANGER:
2882         printf("  Data transfer device element address: 0x");
2883         for (k = 4; k < len; ++k)
2884             printf("%02x", (unsigned int)b[k]);
2885         printf("\n");
2886         break;
2887     default:
2888         pr2serr("  Unable to decode pdt=0x%x, in hex:\n", pdt);
2889         dStrHexErr((const char *)b, len, 0);
2890         break;
2891     }
2892 }
2893 
2894 /* VPD_BLOCK_DEV_C_EXTENS sbc */
2895 static void
decode_b5_vpd(unsigned char * b,int len,int do_hex,int pdt)2896 decode_b5_vpd(unsigned char * b, int len, int do_hex, int pdt)
2897 {
2898     if (do_hex) {
2899         dStrHex((const char *)b, len, (1 == do_hex) ? 0 : -1);
2900         return;
2901     }
2902     switch (pdt) {
2903     case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
2904         decode_block_dev_char_ext_vpd(b, len);
2905         break;
2906     case PDT_TAPE: case PDT_MCHANGER:
2907         decode_lb_protection_vpd(b, len, do_hex);
2908         break;
2909     default:
2910         pr2serr("  Unable to decode pdt=0x%x, in hex:\n", pdt);
2911         dStrHexErr((const char *)b, len, 0);
2912         break;
2913     }
2914 }
2915 
2916 /* VPD_ZBC_DEV_CHARS  sbc or zbc */
2917 static void
decode_zbdc_vpd(unsigned char * b,int len,int do_hex)2918 decode_zbdc_vpd(unsigned char * b, int len, int do_hex)
2919 {
2920     uint32_t u;
2921 
2922     if (do_hex) {
2923         dStrHex((const char *)b, len, (1 == do_hex) ? 0 : -1);
2924         return;
2925     }
2926     if (len < 64) {
2927         pr2serr("Zoned block device characteristics VPD page length too "
2928                 "short=%d\n", len);
2929         return;
2930     }
2931     printf("  URSWRZ type: %d\n", !!(b[4] & 0x1));
2932     u = sg_get_unaligned_be32(b + 8);
2933     printf("  Optimal number of open sequential write preferred zones: ");
2934     if (0xffffffff == u)
2935         printf("not reported\n");
2936     else
2937         printf("%" PRIu32 "\n", u);
2938     u = sg_get_unaligned_be32(b + 12);
2939     printf("  Optimal number of non-sequentially written sequential write "
2940            "preferred zones: ");
2941     if (0xffffffff == u)
2942         printf("not reported\n");
2943     else
2944         printf("%" PRIu32 "\n", u);
2945     u = sg_get_unaligned_be32(b + 16);
2946     printf("  Maximum number of open sequential write required zones: ");
2947     if (0xffffffff == u)
2948         printf("no limit\n");
2949     else
2950         printf("%" PRIu32 "\n", u);
2951 }
2952 
2953 /* VPD_BLOCK_LIMITS_EXT sbc */
2954 static void
decode_b7_vpd(unsigned char * buff,int len,int do_hex,int pdt)2955 decode_b7_vpd(unsigned char * buff, int len, int do_hex, int pdt)
2956 {
2957     unsigned int u;
2958 
2959     if (do_hex) {
2960         dStrHex((const char *)buff, len, (1 == do_hex) ? 0 : -1);
2961         return;
2962     }
2963     switch (pdt) {
2964     case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
2965         if (len < 12) {
2966             pr2serr("Block limits extension VPD page length too short=%d\n",
2967                     len);
2968             return;
2969         }
2970         u = sg_get_unaligned_be16(buff + 6);
2971         printf("  Maximum number of streams: %u\n", u);
2972         u = sg_get_unaligned_be16(buff + 8);
2973         printf("  Optimal stream write size: %u logical blocks\n", u);
2974         u = sg_get_unaligned_be32(buff + 10);
2975         printf("  Stream granularity size: %u\n", u);
2976         break;
2977     default:
2978         pr2serr("  Unable to decode pdt=0x%x, in hex:\n", pdt);
2979         dStrHexErr((const char *)buff, len, 0);
2980         break;
2981     }
2982 }
2983 
2984 /* Returns 0 if successful */
2985 static int
svpd_unable_to_decode(int sg_fd,struct opts_t * op,int subvalue,int off)2986 svpd_unable_to_decode(int sg_fd, struct opts_t * op, int subvalue, int off)
2987 {
2988     int len, res;
2989     int alloc_len = op->maxlen;
2990     unsigned char * rp;
2991 
2992     rp = rsp_buff + off;
2993     if ((! op->do_hex) && (! op->do_raw))
2994         printf("Only hex output supported\n");
2995     if ((!op->do_raw) && (op->do_hex < 2)) {
2996         if (subvalue)
2997             printf("VPD page code=0x%.2x, subvalue=0x%.2x:\n", op->num_vpd,
2998                    subvalue);
2999         else if (op->num_vpd >= 0)
3000             printf("VPD page code=0x%.2x:\n", op->num_vpd);
3001         else
3002             printf("VPD page code=%d:\n", op->num_vpd);
3003     }
3004     if (sg_fd >= 0) {
3005         if (0 == alloc_len)
3006             alloc_len = DEF_ALLOC_LEN;
3007     }
3008 
3009     res = vpd_fetch_page_from_dev(sg_fd, rp, op->num_vpd, alloc_len,
3010                                   op->verbose, &len);
3011     if (0 == res) {
3012         if (op->do_raw)
3013             dStrRaw((const char *)rp, len);
3014         else {
3015             if (op->do_hex > 1)
3016                 dStrHex((const char *)rp, len, -1);
3017             else if (VPD_ASCII_OP_DEF == op->num_vpd)
3018                 dStrHex((const char *)rp, len, 0);
3019             else
3020                 dStrHex((const char *)rp, len, (op->do_long ? 0 : 1));
3021         }
3022         return 0;
3023     } else {
3024         if (op->num_vpd >= 0)
3025             pr2serr("fetching VPD page code=0x%.2x: failed\n", op->num_vpd);
3026         else
3027             pr2serr("fetching VPD page code=%d: failed\n", op->num_vpd);
3028         return res;
3029     }
3030 }
3031 
3032 /* Returns 0 if successful, else see sg_ll_inquiry() */
3033 static int
svpd_decode_t10(int sg_fd,struct opts_t * op,int subvalue,int off)3034 svpd_decode_t10(int sg_fd, struct opts_t * op, int subvalue, int off)
3035 {
3036     int len, pdt, num, k, resid, alloc_len, pn, vb, allow_name, long_notquiet;
3037     int res = 0;
3038     char b[48];
3039     const struct svpd_values_name_t * vnp;
3040     char obuff[DEF_ALLOC_LEN];
3041     unsigned char * rp;
3042 
3043     pn = op->num_vpd;
3044     vb = op->verbose;
3045     long_notquiet = op->do_long && (! op->do_quiet);
3046     if (op->do_raw || (op->do_quiet && (! op->do_long) && (! op->do_all)) ||
3047         (op->do_hex >= 3))
3048         allow_name = 0;
3049     else
3050         allow_name = 1;
3051     rp = rsp_buff + off;
3052     switch(pn) {
3053     case VPD_NO_RATHER_STD_INQ:    /* -2 (want standard inquiry response) */
3054         if (sg_fd >= 0) {
3055             if (op->maxlen > 0)
3056                 alloc_len = op->maxlen;
3057             else if (op->do_long)
3058                 alloc_len = DEF_ALLOC_LEN;
3059             else
3060                 alloc_len = 36;
3061             res = pt_inquiry(sg_fd, 0, 0, rp, alloc_len, &resid, 1, vb);
3062         } else {
3063             alloc_len = op->maxlen;
3064             resid = 0;
3065             res = 0;
3066         }
3067         if (0 == res) {
3068             alloc_len -= resid;
3069             if (op->do_raw)
3070                 dStrRaw((const char *)rp, alloc_len);
3071             else if (op->do_hex) {
3072                 if (! op->do_quiet && (op->do_hex < 3))
3073                     printf("Standard Inquiry reponse:\n");
3074                 dStrHex((const char *)rp, alloc_len,
3075                         (1 == op->do_hex) ? 0 : -1);
3076             } else
3077                 decode_std_inq(rp, alloc_len, vb);
3078             return 0;
3079         }
3080         break;
3081     case VPD_SUPPORTED_VPDS:    /* 0x0 */
3082         if (allow_name)
3083             printf("Supported VPD pages VPD page:\n");
3084         res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len);
3085         if (0 == res) {
3086             if (op->do_raw)
3087                 dStrRaw((const char *)rp, len);
3088             else if (op->do_hex)
3089                 dStrHex((const char *)rp, len, (1 == op->do_hex) ? 0 : -1);
3090             else {
3091                 pdt = rp[0] & 0x1f;
3092                 if (vb || long_notquiet)
3093                     printf("   [PQual=%d  Peripheral device type: %s]\n",
3094                            (rp[0] & 0xe0) >> 5,
3095                            sg_get_pdt_str(pdt, sizeof(b), b));
3096                 num = rp[3];
3097                 if (num > (len - 4))
3098                     num = (len - 4);
3099                 for (k = 0; k < num; ++k) {
3100                     pn = rp[4 + k];
3101                     vnp = sdp_get_vpd_detail(pn, -1, pdt);
3102                     if (vnp) {
3103                         if (op->do_long)
3104                             printf("  0x%02x  %s [%s]\n", pn, vnp->name,
3105                                    vnp->acron);
3106                         else
3107                             printf("  %s [%s]\n", vnp->name, vnp->acron);
3108                     } else if (op->vend_prod_num >= 0) {
3109                         vnp = svpd_find_vendor_by_num(pn, op->vend_prod_num);
3110                         if (vnp) {
3111                             if (op->do_long)
3112                                 printf("  0x%02x  %s [%s]\n", pn, vnp->name,
3113                                        vnp->acron);
3114                             else
3115                                 printf("  %s [%s]\n", vnp->name, vnp->acron);
3116                         } else
3117                             printf("  0x%x\n", pn);
3118                     } else
3119                         printf("  0x%x\n", pn);
3120                 }
3121             }
3122             return 0;
3123         }
3124         break;
3125     case VPD_UNIT_SERIAL_NUM:   /* 0x80 */
3126         if (allow_name)
3127             printf("Unit serial number VPD page:\n");
3128         res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len);
3129         if (0 == res) {
3130             if (op->do_raw)
3131                 dStrRaw((const char *)rp, len);
3132             else if (op->do_hex)
3133                 dStrHex((const char *)rp, len, (1 == op->do_hex) ? 0 : -1);
3134             else {
3135                 pdt = rp[0] & 0x1f;
3136                 if (vb || long_notquiet)
3137                     printf("   [PQual=%d  Peripheral device type: %s]\n",
3138                            (rp[0] & 0xe0) >> 5,
3139                            sg_get_pdt_str(pdt, sizeof(b), b));
3140                 memset(obuff, 0, sizeof(obuff));
3141                 len -= 4;
3142                 if (len >= (int)sizeof(obuff))
3143                     len = sizeof(obuff) - 1;
3144                 memcpy(obuff, rp + 4, len);
3145                 printf("  Unit serial number: %s\n", obuff);
3146             }
3147             return 0;
3148         }
3149         break;
3150     case VPD_DEVICE_ID:         /* 0x83 */
3151         if (allow_name)
3152             printf("Device Identification VPD page:\n");
3153         res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len);
3154         if (0 == res) {
3155             if (op->do_raw)
3156                 dStrRaw((const char *)rp, len);
3157             else if (op->do_hex)
3158                 dStrHex((const char *)rp, len, (1 == op->do_hex) ? 0 : -1);
3159             else {
3160                 pdt = rp[0] & 0x1f;
3161                 if (vb || long_notquiet)
3162                     printf("   [PQual=%d  Peripheral device type: %s]\n",
3163                            (rp[0] & 0xe0) >> 5,
3164                            sg_get_pdt_str(pdt, sizeof(b), b));
3165                 decode_id_vpd(rp, len, subvalue, op);
3166             }
3167             return 0;
3168         }
3169         break;
3170     case VPD_SOFTW_INF_ID:      /* 0x84 */
3171         if (allow_name)
3172             printf("Software interface identification VPD page:\n");
3173         res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len);
3174         if (0 == res) {
3175             if (op->do_raw)
3176                 dStrRaw((const char *)rp, len);
3177             else {
3178                 pdt = rp[0] & 0x1f;
3179                 if (vb || long_notquiet)
3180                     printf("   [PQual=%d  Peripheral device type: %s]\n",
3181                            (rp[0] & 0xe0) >> 5,
3182                            sg_get_pdt_str(pdt, sizeof(b), b));
3183                 decode_softw_inf_id(rp, len, op->do_hex);
3184             }
3185             return 0;
3186         }
3187         break;
3188     case VPD_MAN_NET_ADDR:      /* 0x85 */
3189         if (allow_name)
3190             printf("Management network addresses VPD page:\n");
3191         res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len);
3192         if (0 == res) {
3193             if (op->do_raw)
3194                 dStrRaw((const char *)rp, len);
3195             else
3196                 decode_net_man_vpd(rp, len, op->do_hex);
3197             return 0;
3198         }
3199         break;
3200     case VPD_EXT_INQ:           /* 0x86 */
3201         if (allow_name)
3202             printf("extended INQUIRY data VPD page:\n");
3203         res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len);
3204         if (0 == res) {
3205             if (op->do_raw)
3206                 dStrRaw((const char *)rp, len);
3207             else {
3208                 int protect = 0;
3209                 struct sg_simple_inquiry_resp sir;
3210 
3211                 if ((sg_fd >= 0) && long_notquiet) {
3212                     res = sg_simple_inquiry(sg_fd, &sir, 0, vb);
3213                     if (res) {
3214                         if (op->verbose)
3215                             pr2serr("%s: sg_simple_inquiry() failed, "
3216                                     "res=%d\n", __func__, res);
3217                     } else
3218                         protect = sir.byte_5 & 0x1;  /* SPC-3 and later */
3219                 }
3220                 pdt = rp[0] & 0x1f;
3221                 if (vb || long_notquiet)
3222                     printf("   [PQual=%d  Peripheral device type: %s]\n",
3223                            (rp[0] & 0xe0) >> 5,
3224                            sg_get_pdt_str(pdt, sizeof(b), b));
3225                 decode_x_inq_vpd(rp, len, op->do_hex, long_notquiet, protect);
3226             }
3227             return 0;
3228         }
3229         break;
3230     case VPD_MODE_PG_POLICY:    /* 0x87 */
3231         if (allow_name)
3232             printf("Mode page policy VPD page:\n");
3233         res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len);
3234         if (0 == res) {
3235             if (op->do_raw)
3236                 dStrRaw((const char *)rp, len);
3237             else {
3238                 pdt = rp[0] & 0x1f;
3239                 if (vb || long_notquiet)
3240                     printf("   [PQual=%d  Peripheral device type: %s]\n",
3241                            (rp[0] & 0xe0) >> 5,
3242                            sg_get_pdt_str(pdt, sizeof(b), b));
3243                 decode_mode_policy_vpd(rp, len, op->do_hex);
3244             }
3245             return 0;
3246         }
3247         break;
3248     case VPD_SCSI_PORTS:        /* 0x88 */
3249         if (allow_name)
3250             printf("SCSI Ports VPD page:\n");
3251         res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len);
3252         if (0 == res) {
3253             if (op->do_raw)
3254                 dStrRaw((const char *)rp, len);
3255             else {
3256                 pdt = rp[0] & 0x1f;
3257                 if (vb || long_notquiet)
3258                     printf("   [PQual=%d  Peripheral device type: %s]\n",
3259                            (rp[0] & 0xe0) >> 5,
3260                            sg_get_pdt_str(pdt, sizeof(b), b));
3261                 decode_scsi_ports_vpd(rp, len, op);
3262             }
3263             return 0;
3264         }
3265         break;
3266     case VPD_ATA_INFO:          /* 0x89 */
3267         if (allow_name)
3268             printf("ATA information VPD page:\n");
3269         alloc_len = op->maxlen ? op->maxlen : VPD_ATA_INFO_LEN;
3270         res = vpd_fetch_page_from_dev(sg_fd, rp, pn, alloc_len, vb, &len);
3271         if (0 == res) {
3272             if ((2 == op->do_raw) || (3 == op->do_hex)) {  /* for hdparm */
3273                 if (len < (60 + 512))
3274                     pr2serr("ATA_INFO VPD page len (%d) less than expected "
3275                             "572\n", len);
3276                 else
3277                     dWordHex((const unsigned short *)(rp + 60), 256, -2,
3278                              sg_is_big_endian());
3279             }
3280             else if (op->do_raw)
3281                 dStrRaw((const char *)rp, len);
3282             else {
3283                 pdt = rp[0] & 0x1f;
3284                 if (vb || long_notquiet)
3285                     printf("   [PQual=%d  Peripheral device type: %s]\n",
3286                            (rp[0] & 0xe0) >> 5,
3287                            sg_get_pdt_str(pdt, sizeof(b), b));
3288                 decode_ata_info_vpd(rp, len, long_notquiet, op->do_hex);
3289             }
3290             return 0;
3291         }
3292         break;
3293     case VPD_POWER_CONDITION:          /* 0x8a */
3294         if (allow_name)
3295             printf("Power condition VPD page:\n");
3296         res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len);
3297         if (0 == res) {
3298             if (op->do_raw)
3299                 dStrRaw((const char *)rp, len);
3300             else {
3301                 pdt = rp[0] & 0x1f;
3302                 if (vb || long_notquiet)
3303                     printf("   [PQual=%d  Peripheral device type: %s]\n",
3304                            (rp[0] & 0xe0) >> 5,
3305                            sg_get_pdt_str(pdt, sizeof(b), b));
3306                 decode_power_condition(rp, len, op->do_hex);
3307             }
3308             return 0;
3309         }
3310         break;
3311     case VPD_DEVICE_CONSTITUENTS:      /* 0x8b */
3312         if (allow_name)
3313             printf("Device constituents VPD page:\n");
3314         res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len);
3315         if (0 == res) {
3316             if (op->do_raw)
3317                 dStrRaw((const char *)rp, len);
3318             else
3319                 decode_dev_const_vpd(rp, len, op->do_hex);
3320             return 0;
3321         }
3322         break;
3323     case VPD_POWER_CONSUMPTION:    /* 0x8d */
3324         if (allow_name)
3325             printf("Power consumption VPD page:\n");
3326         res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len);
3327         if (0 == res) {
3328             if (op->do_raw)
3329                 dStrRaw((const char *)rp, len);
3330             else {
3331                 pdt = rp[0] & 0x1f;
3332                 if (vb || long_notquiet)
3333                     printf("   [PQual=%d  Peripheral device type: %s]\n",
3334                            (rp[0] & 0xe0) >> 5,
3335                            sg_get_pdt_str(pdt, sizeof(b), b));
3336                 decode_power_consumption_vpd(rp, len, op->do_hex);
3337             }
3338             return 0;
3339         }
3340         break;
3341     case VPD_3PARTY_COPY:   /* 0x8f */
3342         if (allow_name)
3343             printf("Third party copy VPD page:\n");
3344         res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len);
3345         if (0 == res) {
3346             if (op->do_raw)
3347                 dStrRaw((const char *)rp, len);
3348             else if (1 == op->do_hex)
3349                 dStrHex((const char *)rp, len, 0);
3350             else {
3351                 pdt = rp[0] & 0x1f;
3352                 if (vb || long_notquiet)
3353                     printf("   [PQual=%d  Peripheral device type: %s]\n",
3354                            (rp[0] & 0xe0) >> 5,
3355                            sg_get_pdt_str(pdt, sizeof(b), b));
3356                 decode_3party_copy_vpd(rp, len, op->do_hex, vb);
3357             }
3358             return 0;
3359         }
3360         break;
3361     case VPD_PROTO_LU:          /* 0x90 */
3362         if (allow_name)
3363             printf("Protocol-specific logical unit information:\n");
3364         res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len);
3365         if (0 == res) {
3366             if (op->do_raw)
3367                 dStrRaw((const char *)rp, len);
3368             else {
3369                 pdt = rsp_buff[0] & 0x1f;
3370                 if (vb || long_notquiet)
3371                     printf("   [PQual=%d  Peripheral device type: %s]\n",
3372                            (rp[0] & 0xe0) >> 5,
3373                            sg_get_pdt_str(pdt, sizeof(b), b));
3374                 decode_proto_lu_vpd(rp, len, op->do_hex);
3375             }
3376             return 0;
3377         }
3378         break;
3379     case VPD_PROTO_PORT:        /* 0x91 */
3380         if (allow_name)
3381             printf("Protocol-specific port information:\n");
3382         res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len);
3383         if (0 == res) {
3384             if (op->do_raw)
3385                 dStrRaw((const char *)rp, len);
3386             else {
3387                 pdt = rp[0] & 0x1f;
3388                 if (vb || long_notquiet)
3389                     printf("   [PQual=%d  Peripheral device type: %s]\n",
3390                            (rp[0] & 0xe0) >> 5,
3391                            sg_get_pdt_str(pdt, sizeof(b), b));
3392                 decode_proto_port_vpd(rp, len, op->do_hex);
3393             }
3394             return 0;
3395         }
3396         break;
3397     case 0xb0:  /* depends on pdt */
3398         res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len);
3399         if (0 == res) {
3400             pdt = rp[0] & 0x1f;
3401             if (allow_name) {
3402                 switch (pdt) {
3403                 case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
3404                     printf("Block limits VPD page (SBC):\n");
3405                     break;
3406                 case PDT_TAPE: case PDT_MCHANGER:
3407                     printf("Sequential-access device capabilities VPD page "
3408                            "(SSC):\n");
3409                     break;
3410                 case PDT_OSD:
3411                     printf("OSD information VPD page (OSD):\n");
3412                     break;
3413                 default:
3414                     printf("VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
3415                     break;
3416                 }
3417             }
3418             if (op->do_raw)
3419                 dStrRaw((const char *)rp, len);
3420             else {
3421                 pdt = rp[0] & 0x1f;
3422                 if (vb || long_notquiet)
3423                     printf("   [PQual=%d  Peripheral device type: %s]\n",
3424                            (rp[0] & 0xe0) >> 5,
3425                            sg_get_pdt_str(pdt, sizeof(b), b));
3426                 decode_b0_vpd(rp, len, op->do_hex, pdt);
3427             }
3428             return 0;
3429         } else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3))
3430             printf("VPD page=0xb0\n");
3431         break;
3432     case 0xb1:  /* depends on pdt */
3433         res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len);
3434         if (0 == res) {
3435             pdt = rp[0] & 0x1f;
3436             if (allow_name) {
3437                 switch (pdt) {
3438                 case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
3439                     printf("Block device characteristics VPD page (SBC):\n");
3440                     break;
3441                 case PDT_TAPE: case PDT_MCHANGER:
3442                     printf("Manufactured-assigned serial number VPD page "
3443                            "(SSC):\n");
3444                     break;
3445                 case PDT_OSD:
3446                     printf("Security token VPD page (OSD):\n");
3447                     break;
3448                 case PDT_ADC:
3449                     printf("Manufactured-assigned serial number VPD page "
3450                            "(ADC):\n");
3451                     break;
3452                 default:
3453                     printf("VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
3454                     break;
3455                 }
3456             }
3457             if (op->do_raw)
3458                 dStrRaw((const char *)rp, len);
3459             else {
3460                 if (vb || long_notquiet)
3461                     printf("   [PQual=%d  Peripheral device type: %s]\n",
3462                            (rp[0] & 0xe0) >> 5,
3463                            sg_get_pdt_str(pdt, sizeof(b), b));
3464                 decode_b1_vpd(rp, len, op->do_hex, pdt);
3465             }
3466             return 0;
3467         } else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3))
3468             printf("VPD page=0xb1\n");
3469         break;
3470     case 0xb2:          /* VPD page depends on pdt */
3471         res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len);
3472         if (0 == res) {
3473             pdt = rp[0] & 0x1f;
3474             if (allow_name) {
3475                 switch (pdt) {
3476                 case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
3477                     printf("Logical block provisioning VPD page (SBC):\n");
3478                     break;
3479                 case PDT_TAPE: case PDT_MCHANGER:
3480                     printf("TapeAlert supported flags VPD page (SSC):\n");
3481                     break;
3482                 default:
3483                     printf("VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
3484                     break;
3485                 }
3486             }
3487             if (op->do_raw)
3488                 dStrRaw((const char *)rp, len);
3489             else {
3490                 if (vb || long_notquiet)
3491                     printf("   [PQual=%d  Peripheral device type: %s]\n",
3492                            (rp[0] & 0xe0) >> 5,
3493                            sg_get_pdt_str(pdt, sizeof(b), b));
3494                 decode_b2_vpd(rp, len, pdt, op);
3495             }
3496             return 0;
3497         } else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3))
3498             printf("VPD page=0xb2\n");
3499         break;
3500     case 0xb3:          /* VPD page depends on pdt */
3501         res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len);
3502         if (0 == res) {
3503             pdt = rp[0] & 0x1f;
3504             if (allow_name) {
3505                 switch (pdt) {
3506                 case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
3507                     printf("Referrals VPD page (SBC):\n");
3508                     break;
3509                 case PDT_TAPE: case PDT_MCHANGER:
3510                     printf("Automation device serial number VPD page "
3511                            "(SSC):\n");
3512                     break;
3513                 default:
3514                     printf("VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
3515                     break;
3516                 }
3517             }
3518             if (op->do_raw)
3519                 dStrRaw((const char *)rp, len);
3520             else {
3521                 if (vb || long_notquiet)
3522                     printf("   [PQual=%d  Peripheral device type: %s]\n",
3523                            (rp[0] & 0xe0) >> 5,
3524                            sg_get_pdt_str(pdt, sizeof(b), b));
3525                 decode_b3_vpd(rp, len, op->do_hex, pdt);
3526             }
3527             return 0;
3528         } else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3))
3529             printf("VPD page=0xb3\n");
3530         break;
3531     case 0xb4:          /* VPD page depends on pdt */
3532         res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len);
3533         if (0 == res) {
3534             pdt = rp[0] & 0x1f;
3535             if (allow_name) {
3536                 switch (pdt) {
3537                 case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
3538                     printf("Supported block lengths and protection types "
3539                            "VPD page (SBC):\n");
3540                     break;
3541                 case PDT_TAPE: case PDT_MCHANGER:
3542                     printf("Data transfer device element address (SSC):\n");
3543                     break;
3544                 default:
3545                     printf("VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
3546                     break;
3547                 }
3548             }
3549             if (op->do_raw)
3550                 dStrRaw((const char *)rp, len);
3551             else {
3552                 if (vb || long_notquiet)
3553                     printf("   [PQual=%d  Peripheral device type: %s]\n",
3554                            (rp[0] & 0xe0) >> 5,
3555                            sg_get_pdt_str(pdt, sizeof(b), b));
3556                 decode_b4_vpd(rp, len, op->do_hex, pdt);
3557             }
3558             return 0;
3559         } else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3))
3560             printf("VPD page=0xb4\n");
3561         break;
3562     case 0xb5:          /* VPD page depends on pdt */
3563         res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len);
3564         if (0 == res) {
3565             pdt = rp[0] & 0x1f;
3566             if (allow_name) {
3567                 switch (pdt) {
3568                 case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
3569                     printf("Block device characteristics extension VPD page "
3570                            "(SBC):\n");
3571                     break;
3572                 case PDT_TAPE: case PDT_MCHANGER:
3573                     printf("Logical block protection VPD page (SSC):\n");
3574                     break;
3575                 default:
3576                     printf("VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
3577                     break;
3578                 }
3579             }
3580             if (op->do_raw)
3581                 dStrRaw((const char *)rp, len);
3582             else {
3583                 if (vb || long_notquiet)
3584                     printf("   [PQual=%d  Peripheral device type: %s]\n",
3585                            (rp[0] & 0xe0) >> 5,
3586                            sg_get_pdt_str(pdt, sizeof(b), b));
3587                 decode_b5_vpd(rp, len, op->do_hex, pdt);
3588             }
3589             return 0;
3590         } else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3))
3591             printf("VPD page=0xb5\n");
3592         break;
3593     case VPD_ZBC_DEV_CHARS:       /* 0xb6 for both pdt=0 and pdt=0x14 */
3594         res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len);
3595         if (0 == res) {
3596             pdt = rp[0] & 0x1f;
3597             if (allow_name) {
3598                 switch (pdt) {
3599                 case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
3600                     printf("Zoned block device characteristics VPD page "
3601                            "(SBC, ZBC):\n");
3602                     break;
3603                 default:
3604                     printf("VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
3605                     break;
3606                 }
3607             }
3608             if (op->do_raw)
3609                 dStrRaw((const char *)rp, len);
3610             else {
3611                 if (vb || long_notquiet)
3612                     printf("   [PQual=%d  Peripheral device type: %s]\n",
3613                            (rp[0] & 0xe0) >> 5,
3614                            sg_get_pdt_str(pdt, sizeof(b), b));
3615                 decode_zbdc_vpd(rp, len, op->do_hex);
3616             }
3617             return 0;
3618         } else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3))
3619             printf("VPD page=0xb5\n");
3620         break;
3621     case 0xb7:
3622         res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len);
3623         if (0 == res) {
3624             pdt = rp[0] & 0x1f;
3625             if (allow_name) {
3626                 switch (pdt) {
3627                 case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
3628                     printf("Block limits extension VPD page (SBC):\n");
3629                     break;
3630                 default:
3631                     printf("VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
3632                     break;
3633                 }
3634             }
3635             if (op->do_raw)
3636                 dStrRaw((const char *)rp, len);
3637             else {
3638                 pdt = rp[0] & 0x1f;
3639                 if (vb || long_notquiet)
3640                     printf("   [PQual=%d  Peripheral device type: %s]\n",
3641                            (rp[0] & 0xe0) >> 5,
3642                            sg_get_pdt_str(pdt, sizeof(b), b));
3643                 decode_b7_vpd(rp, len, op->do_hex, pdt);
3644             }
3645             return 0;
3646         } else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3))
3647             printf("VPD page=0xb7\n");
3648         break;
3649     default:
3650         return SG_LIB_SYNTAX_ERROR;
3651     }
3652     return res;
3653 }
3654 
3655 static int
svpd_decode_all(int sg_fd,struct opts_t * op)3656 svpd_decode_all(int sg_fd, struct opts_t * op)
3657 {
3658     int k, res, rlen, n, pn;
3659     int max_pn = 255;
3660     int any_err = 0;
3661     unsigned char vpd0_buff[512];
3662     unsigned char * rp = vpd0_buff;
3663 
3664     if (op->num_vpd > 0)
3665         max_pn = op->num_vpd;
3666     if (sg_fd >= 0) {
3667         res = vpd_fetch_page_from_dev(sg_fd, rp, VPD_SUPPORTED_VPDS,
3668                                       op->maxlen, op->verbose, &rlen);
3669         if (res) {
3670             if (SG_LIB_CAT_ABORTED_COMMAND == res)
3671                 pr2serr("%s: VPD page 0, aborted command\n", __func__);
3672             else if (res) {
3673                 char b[80];
3674 
3675                 sg_get_category_sense_str(res, sizeof(b), b, op->verbose);
3676                 pr2serr("%s: fetching VPD page 0 failed: %s\n", __func__, b);
3677             }
3678             return res;
3679         }
3680         n = sg_get_unaligned_be16(rp + 2);
3681         if (n > (rlen - 4)) {
3682             if (op->verbose)
3683                 pr2serr("%s: rlen=%d > page0 size=%d\n", __func__, rlen,
3684                         n + 4);
3685             n = (rlen - 4);
3686         }
3687         for (k = 0; k < n; ++k) {
3688             pn = rp[4 + k];
3689             if (pn > max_pn)
3690                 continue;
3691             op->num_vpd = pn;
3692             if (op->do_long)
3693                 printf("[0x%x] ", pn);
3694 
3695             res = svpd_decode_t10(sg_fd, op, 0, 0);
3696             if (SG_LIB_SYNTAX_ERROR == res) {
3697                 res = svpd_decode_vendor(sg_fd, op, 0);
3698                 if (SG_LIB_SYNTAX_ERROR == res)
3699                     res = svpd_unable_to_decode(sg_fd, op, 0, 0);
3700             }
3701             if (SG_LIB_CAT_ABORTED_COMMAND == res)
3702                 pr2serr("fetching VPD page failed, aborted command\n");
3703             else if (res) {
3704                 char b[80];
3705 
3706                 sg_get_category_sense_str(res, sizeof(b), b, op->verbose);
3707                 pr2serr("fetching VPD page failed: %s\n", b);
3708             }
3709             if (res)
3710                 any_err = res;
3711         }
3712         res = any_err;
3713     } else {    /* input is coming from --inhex=FN */
3714         int bump, off;
3715         int in_len = op->maxlen;
3716         int prev_pn = -1;
3717 
3718         rp = rsp_buff;
3719         for (k = 0, off = 0; off < in_len; ++k, off += bump) {
3720             rp = rsp_buff + off;
3721             pn = rp[1];
3722             bump = sg_get_unaligned_be16(rp + 2) + 4;
3723             if ((off + bump) > in_len) {
3724                 pr2serr("%s: page 0x%x size (%d) exceeds buffer\n", __func__,
3725                         pn, bump);
3726                 bump = in_len - off;
3727             }
3728             if (pn <= prev_pn) {
3729                 pr2serr("%s: prev_pn=0x%x, this pn=0x%x, not ascending so "
3730                         "exit\n", __func__, prev_pn, pn);
3731                 break;
3732             }
3733             prev_pn = pn;
3734             op->num_vpd = pn;
3735             if (pn > max_pn) {
3736                 if (op->verbose > 2)
3737                     pr2serr("%s: skipping as this pn=0x%x exceeds "
3738                             "max_pn=0x%x\n", __func__, pn, max_pn);
3739                 continue;
3740             }
3741             if (op->do_long)
3742                 printf("[0x%x] ", pn);
3743 
3744             res = svpd_decode_t10(-1, op, 0, off);
3745             if (SG_LIB_SYNTAX_ERROR == res) {
3746                 res = svpd_decode_vendor(-1, op, off);
3747                 if (SG_LIB_SYNTAX_ERROR == res)
3748                     res = svpd_unable_to_decode(-1, op, 0, off);
3749             }
3750         }
3751     }
3752     return 0;
3753 }
3754 
3755 
3756 int
main(int argc,char * argv[])3757 main(int argc, char * argv[])
3758 {
3759     int sg_fd, c, res, matches;
3760     const struct svpd_values_name_t * vnp;
3761     const char * cp;
3762     int inhex_len = 0;
3763     int ret = 0;
3764     int subvalue = 0;
3765     int page_pdt = -1;
3766     struct opts_t opts;
3767     struct opts_t * op;
3768 
3769     op = &opts;
3770     memset(&opts, 0, sizeof(opts));
3771     op->vend_prod_num = -1;
3772     while (1) {
3773         int option_index = 0;
3774 
3775         c = getopt_long(argc, argv, "aehHiI:lm:M:p:qrvV", long_options,
3776                         &option_index);
3777         if (c == -1)
3778             break;
3779 
3780         switch (c) {
3781         case 'a':
3782             ++op->do_all;
3783             break;
3784         case 'e':
3785             ++op->do_enum;
3786             break;
3787         case 'h':
3788         case '?':
3789             usage();
3790             return 0;
3791         case 'H':
3792             ++op->do_hex;
3793             break;
3794         case 'i':
3795             ++op->do_ident;
3796             break;
3797         case 'I':
3798             if (op->inhex_fn) {
3799                 pr2serr("only one '--inhex=' option permitted\n");
3800                 usage();
3801                 return SG_LIB_SYNTAX_ERROR;
3802             } else
3803                 op->inhex_fn = optarg;
3804             break;
3805         case 'l':
3806             ++op->do_long;
3807             break;
3808         case 'm':
3809             op->maxlen = sg_get_num(optarg);
3810             if ((op->maxlen < 0) || (op->maxlen > MX_ALLOC_LEN)) {
3811                 pr2serr("argument to '--maxlen' should be %d or less\n",
3812                         MX_ALLOC_LEN);
3813                 return SG_LIB_SYNTAX_ERROR;
3814             }
3815             break;
3816         case 'M':
3817             if (op->vend_prod) {
3818                 pr2serr("only one '--vendor=' option permitted\n");
3819                 usage();
3820                 return SG_LIB_SYNTAX_ERROR;
3821             } else
3822                 op->vend_prod = optarg;
3823             break;
3824         case 'p':
3825             if (op->page_str) {
3826                 pr2serr("only one '--page=' option permitted\n");
3827                 usage();
3828                 return SG_LIB_SYNTAX_ERROR;
3829             } else
3830                 op->page_str = optarg;
3831             break;
3832         case 'q':
3833             ++op->do_quiet;
3834             break;
3835         case 'r':
3836             ++op->do_raw;
3837             break;
3838         case 'v':
3839             ++op->verbose;
3840             break;
3841         case 'V':
3842             pr2serr("version: %s\n", version_str);
3843             return 0;
3844         default:
3845             pr2serr("unrecognised option code 0x%x ??\n", c);
3846             usage();
3847             return SG_LIB_SYNTAX_ERROR;
3848         }
3849     }
3850     if (optind < argc) {
3851         if (NULL == op->device_name) {
3852             op->device_name = argv[optind];
3853             ++optind;
3854         }
3855         if (optind < argc) {
3856             for (; optind < argc; ++optind)
3857                 pr2serr("Unexpected extra argument: %s\n", argv[optind]);
3858             usage();
3859             return SG_LIB_SYNTAX_ERROR;
3860         }
3861     }
3862     if (op->do_enum) {
3863         if (op->device_name)
3864             pr2serr("Device name %s ignored when --enumerate given\n",
3865                     op->device_name);
3866         if (op->vend_prod) {
3867             if (isdigit(op->vend_prod[0])) {
3868                 op->vend_prod_num = sg_get_num_nomult(op->vend_prod);
3869                 if ((op->vend_prod_num < 0) || (op->vend_prod_num > 10)) {
3870                     pr2serr("Bad vendor/product number after '--vendor=' "
3871                             "option\n");
3872                     return SG_LIB_SYNTAX_ERROR;
3873                 }
3874             } else {
3875                 op->vend_prod_num = svpd_find_vp_num_by_acron(op->vend_prod);
3876                 if (op->vend_prod_num < 0) {
3877                     pr2serr("Bad vendor/product acronym after '--vendor=' "
3878                             "option\n");
3879                     return SG_LIB_SYNTAX_ERROR;
3880                 }
3881             }
3882             svpd_enumerate_vendor(op->vend_prod_num);
3883             return 0;
3884         }
3885         if (op->page_str) {
3886             if ((0 == strcmp("-1", op->page_str)) ||
3887                 (0 == strcmp("-2", op->page_str)))
3888                 op->num_vpd = VPD_NO_RATHER_STD_INQ;
3889             else if (isdigit(op->page_str[0])) {
3890                 op->num_vpd = sg_get_num_nomult(op->page_str);
3891                 if ((op->num_vpd < 0) || (op->num_vpd > 255)) {
3892                     pr2serr("Bad page code value after '-p' option\n");
3893                     return SG_LIB_SYNTAX_ERROR;
3894                 }
3895             } else {
3896                 pr2serr("with --enumerate only search using VPD page "
3897                         "numbers\n");
3898                 return SG_LIB_SYNTAX_ERROR;
3899             }
3900             matches = count_standard_vpds(op->num_vpd);
3901             if (0 == matches)
3902                 matches = svpd_count_vendor_vpds(op->num_vpd,
3903                                                  op->vend_prod_num);
3904             if (0 == matches)
3905                 printf("No matches found for VPD page number 0x%x\n",
3906                        op->num_vpd);
3907         } else {        /* enumerate standard then vendor VPD pages */
3908             printf("Standard VPD pages:\n");
3909             enumerate_vpds(1, 1);
3910         }
3911         return 0;
3912     }
3913     if (op->page_str) {
3914         if ((0 == strcmp("-1", op->page_str)) ||
3915             (0 == strcmp("-2", op->page_str)))
3916             op->num_vpd = VPD_NO_RATHER_STD_INQ;
3917         else if (isalpha(op->page_str[0])) {
3918             vnp = sdp_find_vpd_by_acron(op->page_str);
3919             if (NULL == vnp) {
3920                 vnp = svpd_find_vendor_by_acron(op->page_str);
3921                 if (NULL == vnp) {
3922                     pr2serr("abbreviation doesn't match a VPD page\n");
3923                     printf("Available standard VPD pages:\n");
3924                     enumerate_vpds(1, 1);
3925                     return SG_LIB_SYNTAX_ERROR;
3926                 }
3927             }
3928             op->num_vpd = vnp->value;
3929             subvalue = vnp->subvalue;
3930             op->vend_prod_num = subvalue;
3931             page_pdt = vnp->pdt;
3932         } else {
3933             cp = strchr(op->page_str, ',');
3934             if (cp && op->vend_prod) {
3935                 pr2serr("the --page=pg,vp and the --vendor=vp forms overlap, "
3936                         "choose one or the other\n");
3937                 return SG_LIB_SYNTAX_ERROR;
3938             }
3939             op->num_vpd = sg_get_num_nomult(op->page_str);
3940             if ((op->num_vpd < 0) || (op->num_vpd > 255)) {
3941                 pr2serr("Bad page code value after '-p' option\n");
3942                 printf("Available standard VPD pages:\n");
3943                 enumerate_vpds(1, 1);
3944                 return SG_LIB_SYNTAX_ERROR;
3945             }
3946             if (cp) {
3947                 if (isdigit(*(cp + 1)))
3948                     op->vend_prod_num = sg_get_num_nomult(cp + 1);
3949                 else
3950                     op->vend_prod_num = svpd_find_vp_num_by_acron(cp + 1);
3951                 if ((op->vend_prod_num < 0) || (op->vend_prod_num > 255)) {
3952                     pr2serr("Bad vendor/product acronym after comma in '-p' "
3953                             "option\n");
3954                     if (op->vend_prod_num < 0)
3955                         svpd_enumerate_vendor(-1);
3956                     return SG_LIB_SYNTAX_ERROR;
3957                 }
3958                 subvalue = op->vend_prod_num;
3959             } else if (op->vend_prod) {
3960                 if (isdigit(op->vend_prod[0]))
3961                     op->vend_prod_num = sg_get_num_nomult(op->vend_prod);
3962                 else
3963                     op->vend_prod_num =
3964                         svpd_find_vp_num_by_acron(op->vend_prod);
3965                 if ((op->vend_prod_num < 0) || (op->vend_prod_num > 255)) {
3966                     pr2serr("Bad vendor/product acronym after '--vendor=' "
3967                             "option\n");
3968                     svpd_enumerate_vendor(-1);
3969                     return SG_LIB_SYNTAX_ERROR;
3970                 }
3971                 subvalue = op->vend_prod_num;
3972             }
3973         }
3974     } else if (op->vend_prod) {
3975         if (isdigit(op->vend_prod[0]))
3976             op->vend_prod_num = sg_get_num_nomult(op->vend_prod);
3977         else
3978             op->vend_prod_num = svpd_find_vp_num_by_acron(op->vend_prod);
3979         if ((op->vend_prod_num < 0) || (op->vend_prod_num > 255)) {
3980             pr2serr("Bad vendor/product acronym after '--vendor=' "
3981                     "option\n");
3982             svpd_enumerate_vendor(-1);
3983             return SG_LIB_SYNTAX_ERROR;
3984         }
3985         subvalue = op->vend_prod_num;
3986     }
3987     if (op->inhex_fn) {
3988         if (op->device_name) {
3989             pr2serr("Cannot have both a DEVICE and --inhex= option\n");
3990             return SG_LIB_SYNTAX_ERROR;
3991         }
3992         if (f2hex_arr(op->inhex_fn, op->do_raw, 0, rsp_buff, &inhex_len,
3993                       sizeof(rsp_buff)))
3994             return SG_LIB_FILE_ERROR;
3995         if (op->verbose > 2)
3996             pr2serr("Read %d bytes of user supplied data\n", inhex_len);
3997         if (op->verbose > 3)
3998             dStrHexErr((const char *)rsp_buff, inhex_len, 0);
3999         op->do_raw = 0;         /* don't want raw on output with --inhex= */
4000         if ((NULL == op->page_str) && (0 == op->do_all)) {
4001             /* may be able to deduce VPD page */
4002             if ((0x2 == (0xf & rsp_buff[3])) && (rsp_buff[2] > 2)) {
4003                 if (op->verbose)
4004                     pr2serr("Guessing from --inhex= this is a standard "
4005                             "INQUIRY\n");
4006                 if (page_pdt < 0)
4007                     page_pdt = 0x1f & rsp_buff[0];
4008             } else if (rsp_buff[2] <= 2) {
4009                 if (op->verbose)
4010                     pr2serr("Guessing from --inhex this is VPD page 0x%x\n",
4011                             rsp_buff[1]);
4012                 op->num_vpd = rsp_buff[1];
4013                 if (page_pdt < 0)
4014                     page_pdt = 0x1f & rsp_buff[0];
4015             } else {
4016                 if (op->num_vpd > 0x80) {
4017                     op->num_vpd = rsp_buff[1];
4018                     if (page_pdt < 0)
4019                         page_pdt = 0x1f & rsp_buff[0];
4020                     if (op->verbose)
4021                         pr2serr("Guessing from --inhex this is VPD page "
4022                                 "0x%x\n", rsp_buff[1]);
4023                 } else {
4024                     op->num_vpd = VPD_NO_RATHER_STD_INQ;
4025                     if (op->verbose)
4026                         pr2serr("page number unclear from --inhex, hope "
4027                                 "it's a standard INQUIRY response\n");
4028                 }
4029             }
4030         }
4031     } else if (NULL == op->device_name) {
4032         pr2serr("No DEVICE argument given\n");
4033         usage();
4034         return SG_LIB_SYNTAX_ERROR;
4035     }
4036 
4037     if (op->do_raw && op->do_hex) {
4038         pr2serr("Can't do hex and raw at the same time\n");
4039         usage();
4040         return SG_LIB_SYNTAX_ERROR;
4041     }
4042     if (op->do_ident) {
4043         op->num_vpd = VPD_DEVICE_ID;
4044         if (op->do_ident > 1) {
4045             if (0 == op->do_long)
4046                 ++op->do_quiet;
4047             subvalue = VPD_DI_SEL_LU;
4048         }
4049     }
4050     if (op->do_raw) {
4051         if (sg_set_binary_mode(STDOUT_FILENO) < 0) {
4052             perror("sg_set_binary_mode");
4053             return SG_LIB_FILE_ERROR;
4054         }
4055     }
4056 
4057     if (op->inhex_fn) {
4058         if ((0 == op->maxlen) || (inhex_len < op->maxlen))
4059             op->maxlen = inhex_len;
4060         if (op->do_all)
4061             res = svpd_decode_all(-1, op);
4062         else {
4063             res = svpd_decode_t10(-1, op, subvalue, 0);
4064             if (SG_LIB_SYNTAX_ERROR == res) {
4065                 res = svpd_decode_vendor(-1, op, 0);
4066                 if (SG_LIB_SYNTAX_ERROR == res)
4067                     res = svpd_unable_to_decode(-1, op, subvalue, 0);
4068             }
4069         }
4070         return res;
4071     }
4072 
4073     if ((sg_fd = sg_cmds_open_device(op->device_name, 1 /* ro */,
4074                                      op->verbose)) < 0) {
4075         pr2serr("error opening file: %s: %s\n", op->device_name,
4076                 safe_strerror(-sg_fd));
4077         return SG_LIB_FILE_ERROR;
4078     }
4079 
4080     if (op->do_all)
4081         ret = svpd_decode_all(sg_fd, op);
4082     else {
4083         memset(rsp_buff, 0, sizeof(rsp_buff));
4084 
4085         res = svpd_decode_t10(sg_fd, op, subvalue, 0);
4086         if (SG_LIB_SYNTAX_ERROR == res) {
4087             res = svpd_decode_vendor(sg_fd, op, 0);
4088                 if (SG_LIB_SYNTAX_ERROR == res)
4089             res = svpd_unable_to_decode(sg_fd, op, subvalue, 0);
4090         }
4091         if (SG_LIB_CAT_ABORTED_COMMAND == res)
4092             pr2serr("fetching VPD page failed, aborted command\n");
4093         else if (res) {
4094             char b[80];
4095 
4096             sg_get_category_sense_str(res, sizeof(b), b, op->verbose);
4097             pr2serr("fetching VPD page failed: %s\n", b);
4098         }
4099         ret = res;
4100     }
4101     res = sg_cmds_close_device(sg_fd);
4102     if (res < 0) {
4103         pr2serr("close error: %s\n", safe_strerror(-res));
4104         if (0 == ret)
4105             return SG_LIB_FILE_ERROR;
4106     }
4107     return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
4108 }
4109