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