xref: /aosp_15_r20/external/sg3_utils/src/sg_logs.c (revision 44704f698541f6367e81f991ef8bb54ccbf3fc18)
1*44704f69SBart Van Assche /* A utility program originally written for the Linux OS SCSI subsystem.
2*44704f69SBart Van Assche  *  Copyright (C) 2000-2022 D. Gilbert
3*44704f69SBart Van Assche  *  This program is free software; you can redistribute it and/or modify
4*44704f69SBart Van Assche  *  it under the terms of the GNU General Public License as published by
5*44704f69SBart Van Assche  *  the Free Software Foundation; either version 2, or (at your option)
6*44704f69SBart Van Assche  *  any later version.
7*44704f69SBart Van Assche  *
8*44704f69SBart Van Assche  * SPDX-License-Identifier: GPL-2.0-or-later
9*44704f69SBart Van Assche  *
10*44704f69SBart Van Assche  * This program outputs information provided by a SCSI LOG SENSE command
11*44704f69SBart Van Assche  * and in some cases issues a LOG SELECT command.
12*44704f69SBart Van Assche  *
13*44704f69SBart Van Assche  */
14*44704f69SBart Van Assche 
15*44704f69SBart Van Assche #include <unistd.h>
16*44704f69SBart Van Assche #include <fcntl.h>
17*44704f69SBart Van Assche #include <stdio.h>
18*44704f69SBart Van Assche #include <stdlib.h>
19*44704f69SBart Van Assche #include <stdarg.h>
20*44704f69SBart Van Assche #include <stdbool.h>
21*44704f69SBart Van Assche #include <string.h>
22*44704f69SBart Van Assche #include <ctype.h>
23*44704f69SBart Van Assche #include <getopt.h>
24*44704f69SBart Van Assche #define __STDC_FORMAT_MACROS 1
25*44704f69SBart Van Assche #include <inttypes.h>
26*44704f69SBart Van Assche #include <errno.h>
27*44704f69SBart Van Assche 
28*44704f69SBart Van Assche #ifdef HAVE_CONFIG_H
29*44704f69SBart Van Assche #include "config.h"
30*44704f69SBart Van Assche #endif
31*44704f69SBart Van Assche #include "sg_lib.h"
32*44704f69SBart Van Assche #include "sg_lib_names.h"
33*44704f69SBart Van Assche #include "sg_cmds_basic.h"
34*44704f69SBart Van Assche #ifdef SG_LIB_WIN32
35*44704f69SBart Van Assche #include "sg_pt.h"      /* needed for scsi_pt_win32_direct() */
36*44704f69SBart Van Assche #endif
37*44704f69SBart Van Assche #include "sg_unaligned.h"
38*44704f69SBart Van Assche #include "sg_pr2serr.h"
39*44704f69SBart Van Assche 
40*44704f69SBart Van Assche static const char * version_str = "2.08 20221112";    /* spc6r06 + sbc5r03 */
41*44704f69SBart Van Assche 
42*44704f69SBart Van Assche #define MY_NAME "sg_logs"
43*44704f69SBart Van Assche 
44*44704f69SBart Van Assche #define MX_ALLOC_LEN (0xfffc)
45*44704f69SBart Van Assche #define MX_INLEN_ALLOC_LEN (0x800000)
46*44704f69SBart Van Assche #define DEF_INLEN_ALLOC_LEN (0x40000)
47*44704f69SBart Van Assche #define SHORT_RESP_LEN 128
48*44704f69SBart Van Assche 
49*44704f69SBart Van Assche #define SUPP_PAGES_LPAGE 0x0
50*44704f69SBart Van Assche #define BUFF_OVER_UNDER_LPAGE 0x1
51*44704f69SBart Van Assche #define WRITE_ERR_LPAGE 0x2
52*44704f69SBart Van Assche #define READ_ERR_LPAGE 0x3
53*44704f69SBart Van Assche #define READ_REV_ERR_LPAGE 0x4
54*44704f69SBart Van Assche #define VERIFY_ERR_LPAGE 0x5
55*44704f69SBart Van Assche #define NON_MEDIUM_LPAGE 0x6
56*44704f69SBart Van Assche #define LAST_N_ERR_LPAGE 0x7
57*44704f69SBart Van Assche #define FORMAT_STATUS_LPAGE 0x8
58*44704f69SBart Van Assche #define LAST_N_DEFERRED_LPAGE 0xb
59*44704f69SBart Van Assche #define LB_PROV_LPAGE 0xc
60*44704f69SBart Van Assche #define TEMPERATURE_LPAGE 0xd
61*44704f69SBart Van Assche #define START_STOP_LPAGE 0xe
62*44704f69SBart Van Assche #define APP_CLIENT_LPAGE 0xf
63*44704f69SBart Van Assche #define SELF_TEST_LPAGE 0x10
64*44704f69SBart Van Assche #define SOLID_STATE_MEDIA_LPAGE 0x11
65*44704f69SBart Van Assche #define REQ_RECOVERY_LPAGE 0x13
66*44704f69SBart Van Assche #define DEVICE_STATS_LPAGE 0x14
67*44704f69SBart Van Assche #define BACKGROUND_SCAN_LPAGE 0x15
68*44704f69SBart Van Assche #define SAT_ATA_RESULTS_LPAGE 0x16
69*44704f69SBart Van Assche #define PROTO_SPECIFIC_LPAGE 0x18
70*44704f69SBart Van Assche #define STATS_LPAGE 0x19
71*44704f69SBart Van Assche #define PCT_LPAGE 0x1a
72*44704f69SBart Van Assche #define TAPE_ALERT_LPAGE 0x2e
73*44704f69SBart Van Assche #define IE_LPAGE 0x2f
74*44704f69SBart Van Assche #define NOT_SPG_SUBPG 0x0                       /* any page: no subpages */
75*44704f69SBart Van Assche #define SUPP_SPGS_SUBPG 0xff                    /* all subpages of ... */
76*44704f69SBart Van Assche #define PENDING_DEFECTS_SUBPG 0x1               /* page 0x15 */
77*44704f69SBart Van Assche #define BACKGROUND_OP_SUBPG 0x2                 /* page 0x15 */
78*44704f69SBart Van Assche #define CACHE_STATS_SUBPG 0x20                  /* page 0x19 */
79*44704f69SBart Van Assche #define CMD_DUR_LIMITS_SUBPG 0x21               /* page 0x19 */
80*44704f69SBart Van Assche #define ENV_REPORTING_SUBPG 0x1                 /* page 0xd */
81*44704f69SBart Van Assche #define UTILIZATION_SUBPG 0x1                   /* page 0xe */
82*44704f69SBart Van Assche #define ENV_LIMITS_SUBPG 0x2                    /* page 0xd */
83*44704f69SBart Van Assche #define LPS_MISALIGNMENT_SUBPG 0x3              /* page 0x15 */
84*44704f69SBart Van Assche #define ZONED_BLOCK_DEV_STATS_SUBPG 0x1         /* page 0x14 */
85*44704f69SBart Van Assche #define LAST_N_INQUIRY_DATA_CH_SUBPG 0x1        /* page 0xb */
86*44704f69SBart Van Assche #define LAST_N_MODE_PG_DATA_CH_SUBPG 0x2        /* page 0xb */
87*44704f69SBart Van Assche 
88*44704f69SBart Van Assche /* Vendor product numbers/identifiers */
89*44704f69SBart Van Assche #define VP_NONE   (-1)
90*44704f69SBart Van Assche #define VP_SEAG   0
91*44704f69SBart Van Assche #define VP_HITA   1
92*44704f69SBart Van Assche #define VP_TOSH   2
93*44704f69SBart Van Assche #define VP_LTO5   3
94*44704f69SBart Van Assche #define VP_LTO6   4
95*44704f69SBart Van Assche #define VP_ALL    99
96*44704f69SBart Van Assche 
97*44704f69SBart Van Assche #define MVP_OFFSET 8
98*44704f69SBart Van Assche 
99*44704f69SBart Van Assche /* Vendor product masks
100*44704f69SBart Van Assche  * MVP_STD OR-ed with MVP_<vendor> is a T10 defined lpage with vendor
101*44704f69SBart Van Assche  * specific parameter codes (e.g. Information Exceptions lpage [0x2f]) */
102*44704f69SBart Van Assche #define MVP_STD    (1 << (MVP_OFFSET - 1))
103*44704f69SBart Van Assche #define MVP_SEAG   (1 << (VP_SEAG + MVP_OFFSET))
104*44704f69SBart Van Assche #define MVP_HITA   (1 << (VP_HITA + MVP_OFFSET))
105*44704f69SBart Van Assche #define MVP_TOSH   (1 << (VP_TOSH + MVP_OFFSET))
106*44704f69SBart Van Assche #define MVP_LTO5   (1 << (VP_LTO5 + MVP_OFFSET))
107*44704f69SBart Van Assche #define MVP_LTO6   (1 << (VP_LTO6 + MVP_OFFSET))
108*44704f69SBart Van Assche 
109*44704f69SBart Van Assche #define OVP_LTO    (MVP_LTO5 | MVP_LTO6)
110*44704f69SBart Van Assche #define OVP_ALL    (~0)
111*44704f69SBart Van Assche 
112*44704f69SBart Van Assche 
113*44704f69SBart Van Assche #define PCB_STR_LEN 128
114*44704f69SBart Van Assche 
115*44704f69SBart Van Assche #define LOG_SENSE_PROBE_ALLOC_LEN 4
116*44704f69SBart Van Assche #define LOG_SENSE_DEF_TIMEOUT 64        /* seconds */
117*44704f69SBart Van Assche 
118*44704f69SBart Van Assche static uint8_t * rsp_buff;
119*44704f69SBart Van Assche static uint8_t * free_rsp_buff;
120*44704f69SBart Van Assche static int rsp_buff_sz = MX_ALLOC_LEN + 4;
121*44704f69SBart Van Assche static const int parr_sz = 4096;
122*44704f69SBart Van Assche 
123*44704f69SBart Van Assche static const char * const unknown_s = "unknown";
124*44704f69SBart Van Assche static const char * const not_avail = "not available";
125*44704f69SBart Van Assche static const char * const param_c = "Parameter code";
126*44704f69SBart Van Assche static const char * const param_c_sn = "parameter_code";
127*44704f69SBart Van Assche static const char * const as_s_s = "as_string";
128*44704f69SBart Van Assche static const char * const rstrict_s = "restricted";
129*44704f69SBart Van Assche static const char * const rsv_s = "reserved";
130*44704f69SBart Van Assche static const char * const vend_spec = "vendor specific";
131*44704f69SBart Van Assche static const char * const not_rep = "not reported";
132*44704f69SBart Van Assche static const char * const in_hex = "in hex";
133*44704f69SBart Van Assche static const char * const s_key = "sense key";
134*44704f69SBart Van Assche 
135*44704f69SBart Van Assche static struct option long_options[] = {
136*44704f69SBart Van Assche         {"All", no_argument, 0, 'A'},   /* equivalent to '-aa' */
137*44704f69SBart Van Assche         {"ALL", no_argument, 0, 'A'},   /* equivalent to '-aa' */
138*44704f69SBart Van Assche         {"all", no_argument, 0, 'a'},
139*44704f69SBart Van Assche         {"brief", no_argument, 0, 'b'},
140*44704f69SBart Van Assche         {"control", required_argument, 0, 'c'},
141*44704f69SBart Van Assche         {"enumerate", no_argument, 0, 'e'},
142*44704f69SBart Van Assche         {"exclude", no_argument, 0, 'E'},
143*44704f69SBart Van Assche         {"filter", required_argument, 0, 'f'},
144*44704f69SBart Van Assche         {"full", no_argument, 0, 'F'},
145*44704f69SBart Van Assche         {"help", no_argument, 0, 'h'},
146*44704f69SBart Van Assche         {"hex", no_argument, 0, 'H'},
147*44704f69SBart Van Assche         {"in", required_argument, 0, 'i'},
148*44704f69SBart Van Assche         {"inhex", required_argument, 0, 'i'},
149*44704f69SBart Van Assche         {"json", optional_argument, 0, 'j'},
150*44704f69SBart Van Assche         {"list", no_argument, 0, 'l'},
151*44704f69SBart Van Assche         {"maxlen", required_argument, 0, 'm'},
152*44704f69SBart Van Assche         {"name", no_argument, 0, 'n'},
153*44704f69SBart Van Assche         {"new", no_argument, 0, 'N'},
154*44704f69SBart Van Assche         {"no_inq", no_argument, 0, 'x'},
155*44704f69SBart Van Assche         {"no-inq", no_argument, 0, 'x'},
156*44704f69SBart Van Assche         {"old", no_argument, 0, 'O'},
157*44704f69SBart Van Assche         {"page", required_argument, 0, 'p'},
158*44704f69SBart Van Assche         {"paramp", required_argument, 0, 'P'},
159*44704f69SBart Van Assche         {"pcb", no_argument, 0, 'q'},
160*44704f69SBart Van Assche         {"ppc", no_argument, 0, 'Q'},
161*44704f69SBart Van Assche         {"pdt", required_argument, 0, 'D'},
162*44704f69SBart Van Assche         {"raw", no_argument, 0, 'r'},
163*44704f69SBart Van Assche         {"readonly", no_argument, 0, 'X'},
164*44704f69SBart Van Assche         {"reset", no_argument, 0, 'R'},
165*44704f69SBart Van Assche         {"sp", no_argument, 0, 's'},
166*44704f69SBart Van Assche         {"select", no_argument, 0, 'S'},
167*44704f69SBart Van Assche         {"temperature", no_argument, 0, 't'},
168*44704f69SBart Van Assche         {"transport", no_argument, 0, 'T'},
169*44704f69SBart Van Assche         {"undefined", no_argument, 0, 'u'},
170*44704f69SBart Van Assche         {"vendor", required_argument, 0, 'M'},
171*44704f69SBart Van Assche         {"verbose", no_argument, 0, 'v'},
172*44704f69SBart Van Assche         {"version", no_argument, 0, 'V'},
173*44704f69SBart Van Assche         {0, 0, 0, 0},
174*44704f69SBart Van Assche };
175*44704f69SBart Van Assche 
176*44704f69SBart Van Assche struct opts_t {
177*44704f69SBart Van Assche     bool do_full;
178*44704f69SBart Van Assche     bool do_name;
179*44704f69SBart Van Assche     bool do_pcb;
180*44704f69SBart Van Assche     bool do_ppc;
181*44704f69SBart Van Assche     bool do_raw;
182*44704f69SBart Van Assche     bool do_pcreset;
183*44704f69SBart Van Assche     bool do_select;
184*44704f69SBart Van Assche     bool do_sp;
185*44704f69SBart Van Assche     bool do_temperature;
186*44704f69SBart Van Assche     bool do_transport;
187*44704f69SBart Van Assche     bool exclude_vendor;
188*44704f69SBart Van Assche     bool filter_given;
189*44704f69SBart Van Assche     bool maxlen_given;
190*44704f69SBart Van Assche     bool o_readonly;
191*44704f69SBart Van Assche     bool opt_new;
192*44704f69SBart Van Assche     bool verbose_given;
193*44704f69SBart Van Assche     bool version_given;
194*44704f69SBart Van Assche     int do_all;
195*44704f69SBart Van Assche     int do_brief;
196*44704f69SBart Van Assche     int do_enumerate;
197*44704f69SBart Van Assche     int do_help;
198*44704f69SBart Van Assche     int do_hex;
199*44704f69SBart Van Assche     int do_list;
200*44704f69SBart Van Assche     int dstrhex_no_ascii;       /* value for dStrHex() no_ascii argument */
201*44704f69SBart Van Assche     int hex2str_oformat;        /* value for hex2str() oformat argument */
202*44704f69SBart Van Assche     int vend_prod_num;  /* one of the VP_* constants or -1 (def) */
203*44704f69SBart Van Assche     int deduced_vpn;    /* deduced vendor_prod_num; from INQUIRY, etc */
204*44704f69SBart Van Assche     int verbose;
205*44704f69SBart Van Assche     int filter;
206*44704f69SBart Van Assche     int page_control;
207*44704f69SBart Van Assche     int maxlen;
208*44704f69SBart Van Assche     int pg_code;
209*44704f69SBart Van Assche     int subpg_code;
210*44704f69SBart Van Assche     int paramp;
211*44704f69SBart Van Assche     int no_inq;
212*44704f69SBart Van Assche     int dev_pdt;        /* from device or --pdt=DT */
213*44704f69SBart Van Assche     int decod_subpg_code;
214*44704f69SBart Van Assche     int undefined_hex;  /* hex format of undefined/unrecognized fields */
215*44704f69SBart Van Assche     const char * device_name;
216*44704f69SBart Van Assche     const char * in_fn;
217*44704f69SBart Van Assche     const char * pg_arg;
218*44704f69SBart Van Assche     const char * vend_prod;
219*44704f69SBart Van Assche     const struct log_elem * lep;
220*44704f69SBart Van Assche     sgj_state json_st;
221*44704f69SBart Van Assche };
222*44704f69SBart Van Assche 
223*44704f69SBart Van Assche 
224*44704f69SBart Van Assche struct log_elem {
225*44704f69SBart Van Assche     int pg_code;
226*44704f69SBart Van Assche     int subpg_code;     /* only unless subpg_high>0 then this is only */
227*44704f69SBart Van Assche     int subpg_high;     /* when >0 this is high end of subpage range */
228*44704f69SBart Van Assche     int pdt;            /* -1 for all */
229*44704f69SBart Van Assche     int flags;          /* bit mask; or-ed with MVP_* constants */
230*44704f69SBart Van Assche     const char * name;
231*44704f69SBart Van Assche     const char * acron;
232*44704f69SBart Van Assche     bool (*show_pagep)(const uint8_t * resp, int len,
233*44704f69SBart Van Assche                        struct opts_t * op, sgj_opaque_p jop);
234*44704f69SBart Van Assche                         /* Returns true if done */
235*44704f69SBart Van Assche };
236*44704f69SBart Van Assche 
237*44704f69SBart Van Assche struct vp_name_t {
238*44704f69SBart Van Assche     int vend_prod_num;       /* vendor/product identifier */
239*44704f69SBart Van Assche     const char * acron;
240*44704f69SBart Van Assche     const char * name;
241*44704f69SBart Van Assche     const char * t10_vendorp;
242*44704f69SBart Van Assche     const char * t10_productp;
243*44704f69SBart Van Assche };
244*44704f69SBart Van Assche 
245*44704f69SBart Van Assche static const char * ls_s = "log_sense: ";
246*44704f69SBart Van Assche 
247*44704f69SBart Van Assche static bool show_supported_pgs_page(const uint8_t * resp, int len,
248*44704f69SBart Van Assche                                     struct opts_t * op, sgj_opaque_p jop);
249*44704f69SBart Van Assche static bool show_supported_pgs_sub_page(const uint8_t * resp, int len,
250*44704f69SBart Van Assche                                         struct opts_t * op, sgj_opaque_p jop);
251*44704f69SBart Van Assche static bool show_buffer_over_under_run_page(const uint8_t * resp, int len,
252*44704f69SBart Van Assche                                             struct opts_t * op,
253*44704f69SBart Van Assche                                             sgj_opaque_p jop);
254*44704f69SBart Van Assche static bool show_error_counter_page(const uint8_t * resp, int len,
255*44704f69SBart Van Assche                                     struct opts_t * op, sgj_opaque_p jop);
256*44704f69SBart Van Assche static bool show_non_medium_error_page(const uint8_t * resp, int len,
257*44704f69SBart Van Assche                                        struct opts_t * op, sgj_opaque_p jop);
258*44704f69SBart Van Assche static bool show_last_n_error_page(const uint8_t * resp, int len,
259*44704f69SBart Van Assche                                    struct opts_t * op, sgj_opaque_p jop);
260*44704f69SBart Van Assche static bool show_format_status_page(const uint8_t * resp, int len,
261*44704f69SBart Van Assche                                     struct opts_t * op, sgj_opaque_p jop);
262*44704f69SBart Van Assche static bool show_last_n_deferred_error_page(const uint8_t * resp, int len,
263*44704f69SBart Van Assche                                             struct opts_t * op,
264*44704f69SBart Van Assche                                             sgj_opaque_p jop);
265*44704f69SBart Van Assche static bool show_last_n_inq_data_ch_page(const uint8_t * resp, int len,
266*44704f69SBart Van Assche                                          struct opts_t * op,
267*44704f69SBart Van Assche                                          sgj_opaque_p jop);
268*44704f69SBart Van Assche static bool show_last_n_mode_pg_data_ch_page(const uint8_t * resp, int len,
269*44704f69SBart Van Assche                                              struct opts_t * op,
270*44704f69SBart Van Assche                                              sgj_opaque_p jop);
271*44704f69SBart Van Assche static bool show_lb_provisioning_page(const uint8_t * resp, int len,
272*44704f69SBart Van Assche                                       struct opts_t * op, sgj_opaque_p jop);
273*44704f69SBart Van Assche static bool show_sequential_access_page(const uint8_t * resp, int len,
274*44704f69SBart Van Assche                                         struct opts_t * op, sgj_opaque_p jop);
275*44704f69SBart Van Assche static bool show_temperature_page(const uint8_t * resp, int len,
276*44704f69SBart Van Assche                                   struct opts_t * op, sgj_opaque_p jop);
277*44704f69SBart Van Assche static bool show_start_stop_page(const uint8_t * resp, int len,
278*44704f69SBart Van Assche                                  struct opts_t * op, sgj_opaque_p jop);
279*44704f69SBart Van Assche static bool show_utilization_page(const uint8_t * resp, int len,
280*44704f69SBart Van Assche                                   struct opts_t * op, sgj_opaque_p jop);
281*44704f69SBart Van Assche static bool show_app_client_page(const uint8_t * resp, int len,
282*44704f69SBart Van Assche                                  struct opts_t * op, sgj_opaque_p jop);
283*44704f69SBart Van Assche static bool show_self_test_page(const uint8_t * resp, int len,
284*44704f69SBart Van Assche                                 struct opts_t * op, sgj_opaque_p jop);
285*44704f69SBart Van Assche static bool show_solid_state_media_page(const uint8_t * resp, int len,
286*44704f69SBart Van Assche                                         struct opts_t * op, sgj_opaque_p jop);
287*44704f69SBart Van Assche static bool show_device_stats_page(const uint8_t * resp, int len,
288*44704f69SBart Van Assche                                    struct opts_t * op, sgj_opaque_p jop);
289*44704f69SBart Van Assche static bool show_media_stats_page(const uint8_t * resp, int len,
290*44704f69SBart Van Assche                                   struct opts_t * op, sgj_opaque_p jop);
291*44704f69SBart Van Assche static bool show_dt_device_status_page(const uint8_t * resp, int len,
292*44704f69SBart Van Assche                                        struct opts_t * op, sgj_opaque_p jop);
293*44704f69SBart Van Assche static bool show_tapealert_response_page(const uint8_t * resp, int len,
294*44704f69SBart Van Assche                                          struct opts_t * op,
295*44704f69SBart Van Assche                                          sgj_opaque_p jop);
296*44704f69SBart Van Assche static bool show_requested_recovery_page(const uint8_t * resp, int len,
297*44704f69SBart Van Assche                                          struct opts_t * op,
298*44704f69SBart Van Assche                                          sgj_opaque_p jop);
299*44704f69SBart Van Assche static bool show_background_scan_results_page(const uint8_t * resp, int len,
300*44704f69SBart Van Assche                                               struct opts_t * op,
301*44704f69SBart Van Assche                                               sgj_opaque_p jop);
302*44704f69SBart Van Assche static bool show_zoned_block_dev_stats(const uint8_t * resp, int len,
303*44704f69SBart Van Assche                                        struct opts_t * op, sgj_opaque_p jop);
304*44704f69SBart Van Assche static bool show_pending_defects_page(const uint8_t * resp, int len,
305*44704f69SBart Van Assche                                       struct opts_t * op, sgj_opaque_p jop);
306*44704f69SBart Van Assche static bool show_background_op_page(const uint8_t * resp, int len,
307*44704f69SBart Van Assche                                     struct opts_t * op, sgj_opaque_p jop);
308*44704f69SBart Van Assche static bool show_lps_misalignment_page(const uint8_t * resp, int len,
309*44704f69SBart Van Assche                                        struct opts_t * op, sgj_opaque_p jop);
310*44704f69SBart Van Assche static bool show_element_stats_page(const uint8_t * resp, int len,
311*44704f69SBart Van Assche                                     struct opts_t * op, sgj_opaque_p jop);
312*44704f69SBart Van Assche static bool show_service_buffer_info_page(const uint8_t * resp, int len,
313*44704f69SBart Van Assche                                           struct opts_t * op,
314*44704f69SBart Van Assche                                           sgj_opaque_p jop);
315*44704f69SBart Van Assche static bool show_ata_pt_results_page(const uint8_t * resp, int len,
316*44704f69SBart Van Assche                                      struct opts_t * op, sgj_opaque_p jop);
317*44704f69SBart Van Assche static bool show_tape_diag_data_page(const uint8_t * resp, int len,
318*44704f69SBart Van Assche                                      struct opts_t * op, sgj_opaque_p jop);
319*44704f69SBart Van Assche static bool show_mchanger_diag_data_page(const uint8_t * resp, int len,
320*44704f69SBart Van Assche                                          struct opts_t * op,
321*44704f69SBart Van Assche                                          sgj_opaque_p jop);
322*44704f69SBart Van Assche static bool show_non_volatile_cache_page(const uint8_t * resp, int len,
323*44704f69SBart Van Assche                                          struct opts_t * op,
324*44704f69SBart Van Assche                                          sgj_opaque_p jop);
325*44704f69SBart Van Assche static bool show_volume_stats_pages(const uint8_t * resp, int len,
326*44704f69SBart Van Assche                                     struct opts_t * op, sgj_opaque_p jop);
327*44704f69SBart Van Assche static bool show_protocol_specific_port_page(const uint8_t * resp, int len,
328*44704f69SBart Van Assche                                              struct opts_t * op,
329*44704f69SBart Van Assche                                              sgj_opaque_p jop);
330*44704f69SBart Van Assche static bool show_stats_perform_pages(const uint8_t * resp, int len,
331*44704f69SBart Van Assche                                      struct opts_t * op, sgj_opaque_p jop);
332*44704f69SBart Van Assche static bool show_cache_stats_page(const uint8_t * resp, int len,
333*44704f69SBart Van Assche                                   struct opts_t * op, sgj_opaque_p jop);
334*44704f69SBart Van Assche static bool show_power_condition_transitions_page(const uint8_t * resp,
335*44704f69SBart Van Assche                                  int len, struct opts_t * op,
336*44704f69SBart Van Assche                                                   sgj_opaque_p jop);
337*44704f69SBart Van Assche static bool show_environmental_reporting_page(const uint8_t * resp, int len,
338*44704f69SBart Van Assche                                               struct opts_t * op,
339*44704f69SBart Van Assche                                               sgj_opaque_p jop);
340*44704f69SBart Van Assche static bool show_environmental_limits_page(const uint8_t * resp, int len,
341*44704f69SBart Van Assche                                            struct opts_t * op,
342*44704f69SBart Van Assche                                            sgj_opaque_p jop);
343*44704f69SBart Van Assche static bool show_cmd_dur_limits_page(const uint8_t * resp, int len,
344*44704f69SBart Van Assche                                      struct opts_t * op, sgj_opaque_p jop);
345*44704f69SBart Van Assche static bool show_data_compression_page(const uint8_t * resp, int len,
346*44704f69SBart Van Assche                                        struct opts_t * op, sgj_opaque_p jop);
347*44704f69SBart Van Assche static bool show_tape_alert_ssc_page(const uint8_t * resp, int len,
348*44704f69SBart Van Assche                                      struct opts_t * op, sgj_opaque_p jop);
349*44704f69SBart Van Assche static bool show_ie_page(const uint8_t * resp, int len,
350*44704f69SBart Van Assche                          struct opts_t * op, sgj_opaque_p jop);
351*44704f69SBart Van Assche static bool show_tape_usage_page(const uint8_t * resp, int len,
352*44704f69SBart Van Assche                                  struct opts_t * op, sgj_opaque_p jop);
353*44704f69SBart Van Assche static bool show_tape_capacity_page(const uint8_t * resp, int len,
354*44704f69SBart Van Assche                                      struct opts_t * op, sgj_opaque_p jop);
355*44704f69SBart Van Assche static bool show_seagate_cache_page(const uint8_t * resp, int len,
356*44704f69SBart Van Assche                                     struct opts_t * op, sgj_opaque_p jop);
357*44704f69SBart Van Assche static bool show_seagate_factory_page(const uint8_t * resp, int len,
358*44704f69SBart Van Assche                                       struct opts_t * op, sgj_opaque_p jop);
359*44704f69SBart Van Assche static bool show_hgst_perf_page(const uint8_t * resp, int len,
360*44704f69SBart Van Assche                                 struct opts_t * op, sgj_opaque_p jop);
361*44704f69SBart Van Assche static bool show_hgst_misc_page(const uint8_t * resp, int len,
362*44704f69SBart Van Assche                                 struct opts_t * op, sgj_opaque_p jop);
363*44704f69SBart Van Assche 
364*44704f69SBart Van Assche /* elements in page_number/subpage_number order */
365*44704f69SBart Van Assche static struct log_elem log_arr[] = {
366*44704f69SBart Van Assche     {SUPP_PAGES_LPAGE, 0, 0, -1, MVP_STD, "Supported log pages", "sp",
367*44704f69SBart Van Assche      show_supported_pgs_page},          /* 0, 0 */
368*44704f69SBart Van Assche     {SUPP_PAGES_LPAGE, SUPP_SPGS_SUBPG, 0, -1, MVP_STD, "Supported log pages "
369*44704f69SBart Van Assche      "and subpages", "ssp", show_supported_pgs_sub_page}, /* 0, 0xff */
370*44704f69SBart Van Assche     {BUFF_OVER_UNDER_LPAGE, 0, 0, -1, MVP_STD, "Buffer over-run/under-run",
371*44704f69SBart Van Assche      "bou", show_buffer_over_under_run_page},  /* 0x1, 0x0 */
372*44704f69SBart Van Assche     {WRITE_ERR_LPAGE, 0, 0, -1, MVP_STD, "Write error counters", "we",
373*44704f69SBart Van Assche      show_error_counter_page},          /* 0x2, 0x0 */
374*44704f69SBart Van Assche     {READ_ERR_LPAGE, 0, 0, -1, MVP_STD, "Read error counters", "re",
375*44704f69SBart Van Assche      show_error_counter_page},          /* 0x3, 0x0 */
376*44704f69SBart Van Assche     {READ_REV_ERR_LPAGE, 0, 0, -1, MVP_STD, "Read reverse error counters",
377*44704f69SBart Van Assche      "rre", show_error_counter_page},          /* 0x4, 0x0 */
378*44704f69SBart Van Assche     {VERIFY_ERR_LPAGE, 0, 0, -1, MVP_STD, "Verify error counters", "ve",
379*44704f69SBart Van Assche      show_error_counter_page},          /* 0x5, 0x0 */
380*44704f69SBart Van Assche     {NON_MEDIUM_LPAGE, 0, 0, -1, MVP_STD, "Non medium", "nm",
381*44704f69SBart Van Assche      show_non_medium_error_page},       /* 0x6, 0x0 */
382*44704f69SBart Van Assche     {LAST_N_ERR_LPAGE, 0, 0, -1, MVP_STD, "Last n error", "lne",
383*44704f69SBart Van Assche      show_last_n_error_page},           /* 0x7, 0x0 */
384*44704f69SBart Van Assche     {FORMAT_STATUS_LPAGE, 0, 0, 0, MVP_STD, "Format status", "fs",
385*44704f69SBart Van Assche      show_format_status_page},          /* 0x8, 0x0  SBC */
386*44704f69SBart Van Assche     {LAST_N_DEFERRED_LPAGE, 0, 0, -1, MVP_STD, "Last n deferred error", "lnd",
387*44704f69SBart Van Assche      show_last_n_deferred_error_page},  /* 0xb, 0x0 */
388*44704f69SBart Van Assche     {LAST_N_DEFERRED_LPAGE, LAST_N_INQUIRY_DATA_CH_SUBPG, 0, -1, MVP_STD,
389*44704f69SBart Van Assche      "Last n inquiry data changed", "lnic",
390*44704f69SBart Van Assche      show_last_n_inq_data_ch_page},     /* 0xb, 0x1 */
391*44704f69SBart Van Assche     {LAST_N_DEFERRED_LPAGE, LAST_N_MODE_PG_DATA_CH_SUBPG, 0, -1, MVP_STD,
392*44704f69SBart Van Assche      "Last n mode page data changed", "lnmc",
393*44704f69SBart Van Assche      show_last_n_mode_pg_data_ch_page}, /* 0xb, 0x2 */
394*44704f69SBart Van Assche     {LB_PROV_LPAGE, 0, 0, 0, MVP_STD, "Logical block provisioning", "lbp",
395*44704f69SBart Van Assche      show_lb_provisioning_page},        /* 0xc, 0x0  SBC */
396*44704f69SBart Van Assche     {0xc, 0, 0, PDT_TAPE, MVP_STD, "Sequential access device", "sad",
397*44704f69SBart Van Assche      show_sequential_access_page},      /* 0xc, 0x0  SSC */
398*44704f69SBart Van Assche     {TEMPERATURE_LPAGE, 0, 0, -1, MVP_STD, "Temperature", "temp",
399*44704f69SBart Van Assche      show_temperature_page},            /* 0xd, 0x0 */
400*44704f69SBart Van Assche     {TEMPERATURE_LPAGE, ENV_REPORTING_SUBPG, 0, -1, MVP_STD,  /* 0xd, 0x1 */
401*44704f69SBart Van Assche      "Environmental reporting", "enr", show_environmental_reporting_page},
402*44704f69SBart Van Assche     {TEMPERATURE_LPAGE, ENV_LIMITS_SUBPG, 0, -1, MVP_STD,     /* 0xd, 0x2 */
403*44704f69SBart Van Assche      "Environmental limits", "enl", show_environmental_limits_page},
404*44704f69SBart Van Assche     {START_STOP_LPAGE, 0, 0, -1, MVP_STD, "Start-stop cycle counter", "sscc",
405*44704f69SBart Van Assche      show_start_stop_page},             /* 0xe, 0x0 */
406*44704f69SBart Van Assche     {START_STOP_LPAGE, UTILIZATION_SUBPG, 0, 0, MVP_STD, "Utilization",
407*44704f69SBart Van Assche      "util", show_utilization_page},    /* 0xe, 0x1 SBC */    /* sbc4r04 */
408*44704f69SBart Van Assche     {APP_CLIENT_LPAGE, 0, 0, -1, MVP_STD, "Application client", "ac",
409*44704f69SBart Van Assche      show_app_client_page},             /* 0xf, 0x0 */
410*44704f69SBart Van Assche     {SELF_TEST_LPAGE, 0, 0, -1, MVP_STD, "Self test results", "str",
411*44704f69SBart Van Assche      show_self_test_page},              /* 0x10, 0x0 */
412*44704f69SBart Van Assche     {SOLID_STATE_MEDIA_LPAGE, 0, 0, 0, MVP_STD, "Solid state media", "ssm",
413*44704f69SBart Van Assche      show_solid_state_media_page},      /* 0x11, 0x0  SBC */
414*44704f69SBart Van Assche     {0x11, 0, 0, PDT_TAPE, MVP_STD, "DT Device status", "dtds",
415*44704f69SBart Van Assche      show_dt_device_status_page},       /* 0x11, 0x0  SSC,ADC */
416*44704f69SBart Van Assche     {0x12, 0, 0, PDT_TAPE, MVP_STD, "Tape alert response", "tar",
417*44704f69SBart Van Assche      show_tapealert_response_page},      /* 0x12, 0x0  SSC,ADC */
418*44704f69SBart Van Assche     {REQ_RECOVERY_LPAGE, 0, 0, PDT_TAPE, MVP_STD, "Requested recovery", "rr",
419*44704f69SBart Van Assche      show_requested_recovery_page},     /* 0x13, 0x0  SSC,ADC */
420*44704f69SBart Van Assche     {DEVICE_STATS_LPAGE, 0, 0, PDT_TAPE, MVP_STD, "Device statistics", "ds",
421*44704f69SBart Van Assche      show_device_stats_page},           /* 0x14, 0x0  SSC,ADC */
422*44704f69SBart Van Assche     {DEVICE_STATS_LPAGE, 0, 0, PDT_MCHANGER, MVP_STD,   /* 0x14, 0x0  SMC */
423*44704f69SBart Van Assche      "Media changer statistics", "mcs", show_media_stats_page},
424*44704f69SBart Van Assche     {DEVICE_STATS_LPAGE, ZONED_BLOCK_DEV_STATS_SUBPG,   /* 0x14,0x1 zbc2r01 */
425*44704f69SBart Van Assche      0, 0, MVP_STD, "Zoned block device statistics", "zbds",
426*44704f69SBart Van Assche      show_zoned_block_dev_stats},
427*44704f69SBart Van Assche     {BACKGROUND_SCAN_LPAGE, 0, 0, 0, MVP_STD, "Background scan results",
428*44704f69SBart Van Assche      "bsr", show_background_scan_results_page}, /* 0x15, 0x0  SBC */
429*44704f69SBart Van Assche     {BACKGROUND_SCAN_LPAGE, BACKGROUND_OP_SUBPG, 0, 0, MVP_STD,
430*44704f69SBart Van Assche      "Background operation", "bop", show_background_op_page},
431*44704f69SBart Van Assche                                         /* 0x15, 0x2  SBC */
432*44704f69SBart Van Assche     {BACKGROUND_SCAN_LPAGE, LPS_MISALIGNMENT_SUBPG, 0, 0, MVP_STD,
433*44704f69SBart Van Assche      "LPS misalignment", "lps", show_lps_misalignment_page},
434*44704f69SBart Van Assche                                         /* 0x15, 0x3  SBC-4 */
435*44704f69SBart Van Assche     {0x15, 0, 0, PDT_MCHANGER, MVP_STD, "Element statistics", "els",
436*44704f69SBart Van Assche      show_element_stats_page},          /* 0x15, 0x0  SMC */
437*44704f69SBart Van Assche     {0x15, 0, 0, PDT_ADC, MVP_STD, "Service buffers information", "sbi",
438*44704f69SBart Van Assche      show_service_buffer_info_page},    /* 0x15, 0x0  ADC */
439*44704f69SBart Van Assche     {BACKGROUND_SCAN_LPAGE, PENDING_DEFECTS_SUBPG, 0, 0, MVP_STD,
440*44704f69SBart Van Assche      "Pending defects", "pd", show_pending_defects_page}, /* 0x15, 0x1  SBC */
441*44704f69SBart Van Assche     {SAT_ATA_RESULTS_LPAGE, 0, 0, 0, MVP_STD, "ATA pass-through results",
442*44704f69SBart Van Assche      "aptr", show_ata_pt_results_page}, /* 0x16, 0x0  SAT */
443*44704f69SBart Van Assche     {0x16, 0, 0, PDT_TAPE, MVP_STD, "Tape diagnostic data", "tdd",
444*44704f69SBart Van Assche      show_tape_diag_data_page},         /* 0x16, 0x0  SSC */
445*44704f69SBart Van Assche     {0x16, 0, 0, PDT_MCHANGER, MVP_STD, "Media changer diagnostic data",
446*44704f69SBart Van Assche      "mcdd", show_mchanger_diag_data_page}, /* 0x16, 0x0  SMC */
447*44704f69SBart Van Assche     {0x17, 0, 0, 0, MVP_STD, "Non volatile cache", "nvc",
448*44704f69SBart Van Assche      show_non_volatile_cache_page},     /* 0x17, 0x0  SBC */
449*44704f69SBart Van Assche     {0x17, 0, 0xf, PDT_TAPE, MVP_STD, "Volume statistics", "vs",
450*44704f69SBart Van Assche      show_volume_stats_pages},          /* 0x17, 0x0...0xf  SSC */
451*44704f69SBart Van Assche     {PROTO_SPECIFIC_LPAGE, 0, 0, -1, MVP_STD, "Protocol specific port",
452*44704f69SBart Van Assche      "psp", show_protocol_specific_port_page},  /* 0x18, 0x0  */
453*44704f69SBart Van Assche     {STATS_LPAGE, 0, 0, -1, MVP_STD, "General Statistics and Performance",
454*44704f69SBart Van Assche      "gsp", show_stats_perform_pages},  /* 0x19, 0x0  */
455*44704f69SBart Van Assche     {STATS_LPAGE, 0x1, 0x1f, -1, MVP_STD, "Group Statistics and Performance",
456*44704f69SBart Van Assche      "grsp", show_stats_perform_pages}, /* 0x19, 0x1...0x1f  */
457*44704f69SBart Van Assche     {STATS_LPAGE, CACHE_STATS_SUBPG, 0, -1, MVP_STD,    /* 0x19, 0x20  */
458*44704f69SBart Van Assche      "Cache memory statistics", "cms", show_cache_stats_page},
459*44704f69SBart Van Assche     {STATS_LPAGE, CMD_DUR_LIMITS_SUBPG, 0, -1, MVP_STD, /* 0x19, 0x21  */
460*44704f69SBart Van Assche      "Command duration limits statistics", "cdl",
461*44704f69SBart Van Assche      show_cmd_dur_limits_page /* spc6r01 */ },
462*44704f69SBart Van Assche     {PCT_LPAGE, 0, 0, -1, MVP_STD, "Power condition transitions", "pct",
463*44704f69SBart Van Assche      show_power_condition_transitions_page}, /* 0x1a, 0  */
464*44704f69SBart Van Assche     {0x1b, 0, 0, PDT_TAPE, MVP_STD, "Data compression", "dc",
465*44704f69SBart Van Assche      show_data_compression_page},       /* 0x1b, 0  SSC */
466*44704f69SBart Van Assche     {0x2d, 0, 0, PDT_TAPE, MVP_STD, "Current service information", "csi",
467*44704f69SBart Van Assche      NULL},                             /* 0x2d, 0  SSC */
468*44704f69SBart Van Assche     {TAPE_ALERT_LPAGE, 0, 0, PDT_TAPE, MVP_STD, "Tape alert", "ta",
469*44704f69SBart Van Assche      show_tape_alert_ssc_page},         /* 0x2e, 0  SSC */
470*44704f69SBart Van Assche     {IE_LPAGE, 0, 0, -1, (MVP_STD | MVP_HITA),
471*44704f69SBart Van Assche      "Informational exceptions", "ie", show_ie_page},       /* 0x2f, 0  */
472*44704f69SBart Van Assche /* vendor specific */
473*44704f69SBart Van Assche     {0x30, 0, 0, PDT_DISK, MVP_HITA, "Performance counters (Hitachi)",
474*44704f69SBart Van Assche      "pc_hi", show_hgst_perf_page},     /* 0x30, 0  SBC */
475*44704f69SBart Van Assche     {0x30, 0, 0, PDT_TAPE, OVP_LTO, "Tape usage (lto-5, 6)", "tu_",
476*44704f69SBart Van Assche      show_tape_usage_page},             /* 0x30, 0  SSC */
477*44704f69SBart Van Assche     {0x31, 0, 0, PDT_TAPE, OVP_LTO, "Tape capacity (lto-5, 6)",
478*44704f69SBart Van Assche      "tc_", show_tape_capacity_page},   /* 0x31, 0  SSC */
479*44704f69SBart Van Assche     {0x32, 0, 0, PDT_TAPE, MVP_LTO5, "Data compression (lto-5)",
480*44704f69SBart Van Assche      "dc_", show_data_compression_page}, /* 0x32, 0  SSC; redirect to 0x1b */
481*44704f69SBart Van Assche     {0x33, 0, 0, PDT_TAPE, MVP_LTO5, "Write errors (lto-5)", "we_",
482*44704f69SBart Van Assche      NULL},                             /* 0x33, 0  SSC */
483*44704f69SBart Van Assche     {0x34, 0, 0, PDT_TAPE, MVP_LTO5, "Read forward errors (lto-5)",
484*44704f69SBart Van Assche      "rfe_", NULL},                             /* 0x34, 0  SSC */
485*44704f69SBart Van Assche     {0x35, 0, 0, PDT_TAPE, OVP_LTO, "DT Device Error (lto-5, 6)",
486*44704f69SBart Van Assche      "dtde_", NULL},                             /* 0x35, 0  SSC */
487*44704f69SBart Van Assche     {0x37, 0, 0, PDT_DISK, MVP_SEAG, "Cache (seagate)", "c_se",
488*44704f69SBart Van Assche      show_seagate_cache_page},          /* 0x37, 0  SBC */
489*44704f69SBart Van Assche     {0x37, 0, 0, PDT_DISK, MVP_HITA, "Miscellaneous (hitachi)", "mi_hi",
490*44704f69SBart Van Assche      show_hgst_misc_page},                             /* 0x37, 0  SBC */
491*44704f69SBart Van Assche     {0x37, 0, 0, PDT_TAPE, MVP_LTO5, "Performance characteristics "
492*44704f69SBart Van Assche      "(lto-5)", "pc_", NULL},                             /* 0x37, 0  SSC */
493*44704f69SBart Van Assche     {0x38, 0, 0, PDT_TAPE, MVP_LTO5, "Blocks/bytes transferred "
494*44704f69SBart Van Assche      "(lto-5)", "bbt_", NULL},                             /* 0x38, 0  SSC */
495*44704f69SBart Van Assche     {0x39, 0, 0, PDT_TAPE, MVP_LTO5, "Host port 0 interface errors "
496*44704f69SBart Van Assche      "(lto-5)", "hp0_", NULL},                             /* 0x39, 0  SSC */
497*44704f69SBart Van Assche     {0x3a, 0, 0, PDT_TAPE, MVP_LTO5, "Drive control verification "
498*44704f69SBart Van Assche      "(lto-5)", "dcv_", NULL},                             /* 0x3a, 0  SSC */
499*44704f69SBart Van Assche     {0x3b, 0, 0, PDT_TAPE, MVP_LTO5, "Host port 1 interface errors "
500*44704f69SBart Van Assche      "(lto-5)", "hp1_", NULL},                             /* 0x3b, 0  SSC */
501*44704f69SBart Van Assche     {0x3c, 0, 0, PDT_TAPE, MVP_LTO5, "Drive usage information "
502*44704f69SBart Van Assche      "(lto-5)", "dui_", NULL},                             /* 0x3c, 0  SSC */
503*44704f69SBart Van Assche     {0x3d, 0, 0, PDT_TAPE, MVP_LTO5, "Subsystem statistics (lto-5)",
504*44704f69SBart Van Assche      "ss_", NULL},                             /* 0x3d, 0  SSC */
505*44704f69SBart Van Assche     {0x3e, 0, 0, PDT_DISK, MVP_SEAG, "Factory (seagate)", "f_se",
506*44704f69SBart Van Assche      show_seagate_factory_page},        /* 0x3e, 0  SBC */
507*44704f69SBart Van Assche     {0x3e, 0, 0, PDT_DISK, MVP_HITA, "Factory (hitachi)", "f_hi",
508*44704f69SBart Van Assche      NULL},                             /* 0x3e, 0  SBC */
509*44704f69SBart Van Assche     {0x3e, 0, 0, PDT_TAPE, OVP_LTO, "Device Status (lto-5, 6)",
510*44704f69SBart Van Assche      "ds_", NULL},                             /* 0x3e, 0  SSC */
511*44704f69SBart Van Assche 
512*44704f69SBart Van Assche     {-1, -1, -1, -1, 0, NULL, "zzzzz", NULL},           /* end sentinel */
513*44704f69SBart Van Assche };
514*44704f69SBart Van Assche 
515*44704f69SBart Van Assche /* Supported vendor product codes */
516*44704f69SBart Van Assche /* Arrange in alphabetical order by acronym */
517*44704f69SBart Van Assche static struct vp_name_t vp_arr[] = {
518*44704f69SBart Van Assche     {VP_SEAG, "sea", "Seagate", "SEAGATE", NULL},
519*44704f69SBart Van Assche     {VP_HITA, "hit", "Hitachi", "HGST", NULL},
520*44704f69SBart Van Assche     {VP_HITA, "wdc", "WDC/Hitachi", "WDC", NULL},
521*44704f69SBart Van Assche     {VP_TOSH, "tos", "Toshiba", "TOSHIBA", NULL},
522*44704f69SBart Van Assche     {VP_LTO5, "lto5", "LTO-5 (tape drive consortium)", NULL, NULL},
523*44704f69SBart Van Assche     {VP_LTO6, "lto6", "LTO-6 (tape drive consortium)", NULL, NULL},
524*44704f69SBart Van Assche     {VP_ALL, "all", "enumerate all vendor specific", NULL, NULL},
525*44704f69SBart Van Assche     {0, NULL, NULL, NULL, NULL},
526*44704f69SBart Van Assche };
527*44704f69SBart Van Assche 
528*44704f69SBart Van Assche static char t10_vendor_str[10];
529*44704f69SBart Van Assche static char t10_product_str[18];
530*44704f69SBart Van Assche 
531*44704f69SBart Van Assche #ifdef SG_LIB_WIN32
532*44704f69SBart Van Assche static bool win32_spt_init_state = false;
533*44704f69SBart Van Assche static bool win32_spt_curr_state = false;
534*44704f69SBart Van Assche #endif
535*44704f69SBart Van Assche 
536*44704f69SBart Van Assche 
537*44704f69SBart Van Assche static void
usage(int hval)538*44704f69SBart Van Assche usage(int hval)
539*44704f69SBart Van Assche {
540*44704f69SBart Van Assche     if (1 == hval) {
541*44704f69SBart Van Assche         pr2serr(
542*44704f69SBart Van Assche            "Usage: sg_logs [-ALL] [--all] [--brief] [--control=PC] "
543*44704f69SBart Van Assche            "[--enumerate]\n"
544*44704f69SBart Van Assche            "               [--exclude] [--filter=FL] [--full] [--help] "
545*44704f69SBart Van Assche            "[--hex]\n"
546*44704f69SBart Van Assche            "               [--in=FN] [--json[=JO]] [--list] [--maxlen=LEN] "
547*44704f69SBart Van Assche            "[--name]\n"
548*44704f69SBart Van Assche            "               [--no_inq] [--page=PG] [--paramp=PP] [--pcb] "
549*44704f69SBart Van Assche            "[--ppc]\n"
550*44704f69SBart Van Assche            "               [--pdt=DT] [--raw] [--readonly] [--reset] "
551*44704f69SBart Van Assche            "[--select]\n"
552*44704f69SBart Van Assche            "               [--sp] [--temperature] [--transport] "
553*44704f69SBart Van Assche            "[--undefined]\n"
554*44704f69SBart Van Assche            "               [--vendor=VP] [--verbose] [--version] DEVICE\n"
555*44704f69SBart Van Assche            "  where the main options are:\n"
556*44704f69SBart Van Assche            "    --ALL|-A        fetch and decode all log pages and "
557*44704f69SBart Van Assche            "subpages\n"
558*44704f69SBart Van Assche            "    --all|-a        fetch and decode all log pages, but not "
559*44704f69SBart Van Assche            "subpages; use\n"
560*44704f69SBart Van Assche            "                    twice to fetch and decode all log pages "
561*44704f69SBart Van Assche            "and subpages\n"
562*44704f69SBart Van Assche            "    --brief|-b      shorten the output of some log pages\n"
563*44704f69SBart Van Assche            "    --enumerate|-e    enumerate known pages, ignore DEVICE. "
564*44704f69SBart Van Assche            "Sort order,\n"
565*44704f69SBart Van Assche            "                      '-e': all by acronym; '-ee': non-vendor "
566*44704f69SBart Van Assche            "by acronym;\n"
567*44704f69SBart Van Assche            "                      '-eee': all numerically; '-eeee': "
568*44704f69SBart Van Assche            "non-v numerically\n"
569*44704f69SBart Van Assche            "    --filter=FL|-f FL    FL is parameter code to display (def: "
570*44704f69SBart Van Assche            "all);\n"
571*44704f69SBart Van Assche            "                         with '-e' then FL>=0 enumerate that "
572*44704f69SBart Van Assche            "pdt + spc\n"
573*44704f69SBart Van Assche            "                         FL=-1 all (default), FL=-2 spc only\n"
574*44704f69SBart Van Assche            "    --full|-F       drill down in application client log page\n"
575*44704f69SBart Van Assche            "    --help|-h       print usage message then exit. Use twice "
576*44704f69SBart Van Assche            "for more help\n"
577*44704f69SBart Van Assche            "    --hex|-H        output response in hex (default: decode if "
578*44704f69SBart Van Assche            "known)\n"
579*44704f69SBart Van Assche            "    --in=FN|-i FN    FN is a filename containing a log page "
580*44704f69SBart Van Assche            "in ASCII hex\n"
581*44704f69SBart Van Assche            "                     or binary if --raw also given. --inhex=FN "
582*44704f69SBart Van Assche            "also accepted\n"
583*44704f69SBart Van Assche            "    --json[=JO]|-j[JO]    output in JSON instead of human "
584*44704f69SBart Van Assche             "readable\n"
585*44704f69SBart Van Assche             "                          test. Use --json=? for JSON help\n"
586*44704f69SBart Van Assche            "    --list|-l       list supported log pages; twice: list "
587*44704f69SBart Van Assche            "supported log\n"
588*44704f69SBart Van Assche            "                    pages and subpages page; thrice: merge of "
589*44704f69SBart Van Assche            "both pages\n"
590*44704f69SBart Van Assche            "    --page=PG|-p PG    PG is either log page acronym, PGN or "
591*44704f69SBart Van Assche            "PGN,SPGN\n"
592*44704f69SBart Van Assche            "                       where (S)PGN is a (sub) page number\n");
593*44704f69SBart Van Assche         pr2serr(
594*44704f69SBart Van Assche            "    --raw|-r        either output response in binary to stdout "
595*44704f69SBart Van Assche            "or, if\n"
596*44704f69SBart Van Assche            "                    '--in=FN' is given, FN is decoded as "
597*44704f69SBart Van Assche            "binary\n"
598*44704f69SBart Van Assche            "    --temperature|-t    decode temperature (log page 0xd or "
599*44704f69SBart Van Assche            "0x2f)\n"
600*44704f69SBart Van Assche            "    --transport|-T    decode transport (protocol specific port "
601*44704f69SBart Van Assche            "0x18) page\n"
602*44704f69SBart Van Assche            "    --vendor=VP|-M VP    vendor/product abbreviation [or "
603*44704f69SBart Van Assche            "number]\n"
604*44704f69SBart Van Assche            "    --verbose|-v    increase verbosity\n\n"
605*44704f69SBart Van Assche            "Performs a SCSI LOG SENSE (or LOG SELECT) command and decodes "
606*44704f69SBart Van Assche            "the response.\nIf only DEVICE is given then '-p sp' (supported "
607*44704f69SBart Van Assche            "pages) is assumed. Use\n'-e' to see known pages and their "
608*44704f69SBart Van Assche            "acronyms. For more help use '-hh'.\n");
609*44704f69SBart Van Assche     } else if (hval > 1) {
610*44704f69SBart Van Assche         pr2serr(
611*44704f69SBart Van Assche            "  where sg_logs' lesser used options are:\n"
612*44704f69SBart Van Assche            "    --control=PC|-c PC    page control(PC) (default: 1)\n"
613*44704f69SBart Van Assche            "                          0: current threshold, 1: current "
614*44704f69SBart Van Assche            "cumulative\n"
615*44704f69SBart Van Assche            "                          2: default threshold, 3: default "
616*44704f69SBart Van Assche            "cumulative\n"
617*44704f69SBart Van Assche            "    --exclude|-E    exclude vendor specific pages and "
618*44704f69SBart Van Assche            "parameters\n"
619*44704f69SBart Van Assche            "    --list|-l       list supported log page names (equivalent to "
620*44704f69SBart Van Assche            "'-p sp')\n"
621*44704f69SBart Van Assche            "                    use twice to list supported log page and "
622*44704f69SBart Van Assche            "subpage names\n"
623*44704f69SBart Van Assche            "    --maxlen=LEN|-m LEN    max response length (def: 0 "
624*44704f69SBart Van Assche            "-> everything)\n"
625*44704f69SBart Van Assche            "                           when > 1 will request LEN bytes\n"
626*44704f69SBart Van Assche            "    --name|-n       decode some pages into multiple name=value "
627*44704f69SBart Van Assche            "lines\n"
628*44704f69SBart Van Assche            "    --no_inq|-x     no initial INQUIRY output (twice: and no "
629*44704f69SBart Van Assche            "INQUIRY call)\n"
630*44704f69SBart Van Assche            "    --old|-O        use old interface (use as first option)\n"
631*44704f69SBart Van Assche            "    --paramp=PP|-P PP    place PP in parameter pointer field in "
632*44704f69SBart Van Assche            "cdb (def: 0)\n"
633*44704f69SBart Van Assche            "    --pcb|-q        show parameter control bytes in decoded "
634*44704f69SBart Van Assche            "output\n"
635*44704f69SBart Van Assche            "    --ppc|-Q        set the Parameter Pointer Control (PPC) bit "
636*44704f69SBart Van Assche            "(def: 0)\n"
637*44704f69SBart Van Assche            "    --pdt=DT|-D DT    DT is peripheral device type to use with "
638*44704f69SBart Van Assche            "'--in=FN'\n"
639*44704f69SBart Van Assche            "                      or when '--no_inq' is used\n"
640*44704f69SBart Van Assche            "    --readonly|-X    open DEVICE read-only (def: first "
641*44704f69SBart Van Assche            "read-write then if\n"
642*44704f69SBart Van Assche            "                     fails try open again read-only)\n"
643*44704f69SBart Van Assche            "    --reset|-R      reset log parameters (takes PC and SP into "
644*44704f69SBart Van Assche            "account)\n"
645*44704f69SBart Van Assche            "                    (uses PCR bit in LOG SELECT)\n"
646*44704f69SBart Van Assche            "    --select|-S     perform LOG SELECT (def: LOG SENSE)\n"
647*44704f69SBart Van Assche            "    --sp|-s         set the Saving Parameters (SP) bit (def: "
648*44704f69SBart Van Assche            "0)\n"
649*44704f69SBart Van Assche            "    --undefined|-u    hex format for undefined/unrecognized "
650*44704f69SBart Van Assche            "fields,\n"
651*44704f69SBart Van Assche            "                      use one or more times; format as per "
652*44704f69SBart Van Assche            "--hex\n"
653*44704f69SBart Van Assche            "    --version|-V    output version string then exit\n\n"
654*44704f69SBart Van Assche            "If DEVICE and --select are given, a LOG SELECT command will be "
655*44704f69SBart Van Assche            "issued.\nIf DEVICE is not given and '--in=FN' is given then FN "
656*44704f69SBart Van Assche            "will decoded as if\nit were a log page. The contents of FN "
657*44704f69SBart Van Assche            "generated by either a prior\n'sg_logs -HHH ...' invocation or "
658*44704f69SBart Van Assche            "by a text editor.\nLog pages defined in SPC are common "
659*44704f69SBart Van Assche            "to all device types.\n");
660*44704f69SBart Van Assche     }
661*44704f69SBart Van Assche }
662*44704f69SBart Van Assche 
663*44704f69SBart Van Assche static void
usage_old()664*44704f69SBart Van Assche usage_old()
665*44704f69SBart Van Assche {
666*44704f69SBart Van Assche     printf("Usage: sg_logs [-a] [-A] [-b] [-c=PC] [-D=DT] [-e] [-E] [-f=FL] "
667*44704f69SBart Van Assche            "[-F]\n"
668*44704f69SBart Van Assche            "               [-h] [-H] [-i=FN] [-l] [-L] [-m=LEN] [-M=VP] "
669*44704f69SBart Van Assche            "[-n] [-p=PG]\n"
670*44704f69SBart Van Assche            "               [-paramp=PP] [-pcb] [-ppc] [-r] [-select] [-sp] "
671*44704f69SBart Van Assche            "[-t] [-T]\n"
672*44704f69SBart Van Assche            "               [-u] [-v] [-V] [-x] [-X] [-?] DEVICE\n"
673*44704f69SBart Van Assche            "  where:\n"
674*44704f69SBart Van Assche            "    -a     fetch and decode all log pages\n"
675*44704f69SBart Van Assche            "    -A     fetch and decode all log pages and subpages\n"
676*44704f69SBart Van Assche            "    -b     shorten the output of some log pages\n"
677*44704f69SBart Van Assche            "    -c=PC    page control(PC) (default: 1)\n"
678*44704f69SBart Van Assche            "                  0: current threshold, 1: current cumulative\n"
679*44704f69SBart Van Assche            "                  2: default threshold, 3: default cumulative\n"
680*44704f69SBart Van Assche            "    -e     enumerate known log pages\n"
681*44704f69SBart Van Assche            "    -D=DT    DT is peripheral device type to use with "
682*44704f69SBart Van Assche            "'--in=FN'\n"
683*44704f69SBart Van Assche            "    -E     exclude vendor specific pages and parameters\n"
684*44704f69SBart Van Assche            "    -f=FL    filter match parameter code or pdt\n"
685*44704f69SBart Van Assche            "    -F     drill down in application client log page\n"
686*44704f69SBart Van Assche            "    -h     output in hex (default: decode if known)\n"
687*44704f69SBart Van Assche            "    -H     output in hex (same as '-h')\n"
688*44704f69SBart Van Assche            "    -i=FN    FN is a filename containing a log page "
689*44704f69SBart Van Assche            "in ASCII hex.\n"
690*44704f69SBart Van Assche            "    -l     list supported log page names (equivalent to "
691*44704f69SBart Van Assche            "'-p=0')\n"
692*44704f69SBart Van Assche            "    -L     list supported log page and subpages names "
693*44704f69SBart Van Assche            "(equivalent to\n"
694*44704f69SBart Van Assche            "           '-p=0,ff')\n"
695*44704f69SBart Van Assche            "    -m=LEN   max response length (decimal) (def: 0 "
696*44704f69SBart Van Assche            "-> everything)\n"
697*44704f69SBart Van Assche            "    -M=VP    vendor/product abbreviation [or number]\n"
698*44704f69SBart Van Assche            "    -n       decode some pages into multiple name=value "
699*44704f69SBart Van Assche            "lines\n"
700*44704f69SBart Van Assche            "    -N|--new    use new interface\n"
701*44704f69SBart Van Assche            "    -p=PG    PG is an acronym (def: 'sp')\n"
702*44704f69SBart Van Assche            "    -p=PGN    page code in hex (def: 0)\n"
703*44704f69SBart Van Assche            "    -p=PGN,SPGN    page and subpage codes in hex, (defs: 0,0)\n"
704*44704f69SBart Van Assche            "    -paramp=PP   (in hex) (def: 0)\n"
705*44704f69SBart Van Assche            "    -pcb     show parameter control bytes in decoded "
706*44704f69SBart Van Assche            "output\n");
707*44704f69SBart Van Assche     printf("    -ppc     set the Parameter Pointer Control (PPC) bit "
708*44704f69SBart Van Assche            "(def: 0)\n"
709*44704f69SBart Van Assche            "    -r       reset log parameters (takes PC and SP into "
710*44704f69SBart Van Assche            "account)\n"
711*44704f69SBart Van Assche            "             (uses PCR bit in LOG SELECT)\n"
712*44704f69SBart Van Assche            "    -select  perform LOG SELECT (def: LOG SENSE)\n"
713*44704f69SBart Van Assche            "    -sp      set the Saving Parameters (SP) bit (def: 0)\n"
714*44704f69SBart Van Assche            "    -t       outputs temperature log page (0xd)\n"
715*44704f69SBart Van Assche            "    -T       outputs transport (protocol specific port) log "
716*44704f69SBart Van Assche            "page (0x18)\n"
717*44704f69SBart Van Assche            "    -u       hex format for undefined/unrecognized fields\n"
718*44704f69SBart Van Assche            "    -v       increase verbosity\n"
719*44704f69SBart Van Assche            "    -V       output version string\n"
720*44704f69SBart Van Assche            "    -x       no initial INQUIRY output (twice: no INQUIRY call)\n"
721*44704f69SBart Van Assche            "    -X       open DEVICE read-only (def: first read-write then "
722*44704f69SBart Van Assche            "if fails\n"
723*44704f69SBart Van Assche            "             try open again with read-only)\n"
724*44704f69SBart Van Assche            "    -?       output this usage message\n\n"
725*44704f69SBart Van Assche            "Performs a SCSI LOG SENSE (or LOG SELECT) command\n");
726*44704f69SBart Van Assche }
727*44704f69SBart Van Assche 
728*44704f69SBart Van Assche /* Return vendor product mask given vendor product number */
729*44704f69SBart Van Assche static int
get_vp_mask(int vpn)730*44704f69SBart Van Assche get_vp_mask(int vpn)
731*44704f69SBart Van Assche {
732*44704f69SBart Van Assche     if (vpn < 0)
733*44704f69SBart Van Assche         return 0;
734*44704f69SBart Van Assche     else
735*44704f69SBart Van Assche         return (vpn >= (32 - MVP_OFFSET)) ?  OVP_ALL :
736*44704f69SBart Van Assche                                              (1 << (vpn + MVP_OFFSET));
737*44704f69SBart Van Assche }
738*44704f69SBart Van Assche 
739*44704f69SBart Van Assche static int
asort_comp(const void * lp,const void * rp)740*44704f69SBart Van Assche asort_comp(const void * lp, const void * rp)
741*44704f69SBart Van Assche {
742*44704f69SBart Van Assche     const struct log_elem * const * lepp =
743*44704f69SBart Van Assche                 (const struct log_elem * const *)lp;
744*44704f69SBart Van Assche     const struct log_elem * const * repp =
745*44704f69SBart Van Assche                 (const struct log_elem * const *)rp;
746*44704f69SBart Van Assche 
747*44704f69SBart Van Assche     return strcmp((*lepp)->acron, (*repp)->acron);
748*44704f69SBart Van Assche }
749*44704f69SBart Van Assche 
750*44704f69SBart Van Assche static void
enumerate_helper(const struct log_elem * lep,bool first,const struct opts_t * op)751*44704f69SBart Van Assche enumerate_helper(const struct log_elem * lep, bool first,
752*44704f69SBart Van Assche                  const struct opts_t * op)
753*44704f69SBart Van Assche {
754*44704f69SBart Van Assche     char b[80];
755*44704f69SBart Van Assche     char bb[80];
756*44704f69SBart Van Assche     const char * cp;
757*44704f69SBart Van Assche     bool vendor_lpage = ! (MVP_STD & lep->flags);
758*44704f69SBart Van Assche 
759*44704f69SBart Van Assche     if (first) {
760*44704f69SBart Van Assche         if (1 == op->verbose) {
761*44704f69SBart Van Assche             printf("acronym   pg[,spg]        name\n");
762*44704f69SBart Van Assche             printf("===============================================\n");
763*44704f69SBart Van Assche         } else if (2 == op->verbose) {
764*44704f69SBart Van Assche             printf("acronym   pg[,spg]        pdt   name\n");
765*44704f69SBart Van Assche             printf("===================================================\n");
766*44704f69SBart Van Assche         }
767*44704f69SBart Van Assche     }
768*44704f69SBart Van Assche     if ((0 == (op->do_enumerate % 2)) && vendor_lpage)
769*44704f69SBart Van Assche         return;     /* if do_enumerate is even then skip vendor pages */
770*44704f69SBart Van Assche     else if ((! op->filter_given) || (-1 == op->filter))
771*44704f69SBart Van Assche         ;           /* otherwise enumerate all lpages if no --filter= */
772*44704f69SBart Van Assche     else if (-2 == op->filter) {   /* skip non-SPC pages */
773*44704f69SBart Van Assche         if (lep->pdt >= 0)
774*44704f69SBart Van Assche             return;
775*44704f69SBart Van Assche     } else if (-10 == op->filter) {   /* skip non-disk like pages */
776*44704f69SBart Van Assche         if (sg_lib_pdt_decay(lep->pdt) != 0)
777*44704f69SBart Van Assche             return;
778*44704f69SBart Van Assche     } else if (-11 == op->filter) {   /* skip tape like device pages */
779*44704f69SBart Van Assche         if (sg_lib_pdt_decay(lep->pdt) != 1)
780*44704f69SBart Van Assche             return;
781*44704f69SBart Van Assche     } else if ((op->filter >= 0) && (op->filter <= 0x1f)) {
782*44704f69SBart Van Assche         if ((lep->pdt >= 0) && (lep->pdt != op->filter) &&
783*44704f69SBart Van Assche             (lep->pdt != sg_lib_pdt_decay(op->filter)))
784*44704f69SBart Van Assche             return;
785*44704f69SBart Van Assche     }
786*44704f69SBart Van Assche     if (op->vend_prod_num >= 0) {
787*44704f69SBart Van Assche         if (! (lep->flags & get_vp_mask(op->vend_prod_num)))
788*44704f69SBart Van Assche             return;
789*44704f69SBart Van Assche     }
790*44704f69SBart Van Assche     if (op->deduced_vpn >= 0) {
791*44704f69SBart Van Assche         if (! (lep->flags & get_vp_mask(op->deduced_vpn)))
792*44704f69SBart Van Assche             return;
793*44704f69SBart Van Assche     }
794*44704f69SBart Van Assche     if (lep->subpg_high > 0)
795*44704f69SBart Van Assche         snprintf(b, sizeof(b), "0x%x,0x%x->0x%x", lep->pg_code,
796*44704f69SBart Van Assche                  lep->subpg_code, lep->subpg_high);
797*44704f69SBart Van Assche     else if (lep->subpg_code > 0)
798*44704f69SBart Van Assche         snprintf(b, sizeof(b), "0x%x,0x%x", lep->pg_code,
799*44704f69SBart Van Assche                  lep->subpg_code);
800*44704f69SBart Van Assche     else
801*44704f69SBart Van Assche         snprintf(b, sizeof(b), "0x%x", lep->pg_code);
802*44704f69SBart Van Assche     snprintf(bb, sizeof(bb), "%-16s", b);
803*44704f69SBart Van Assche     cp = (op->verbose && (! lep->show_pagep)) ? " [hex only]" : "";
804*44704f69SBart Van Assche     if (op->verbose > 1) {
805*44704f69SBart Van Assche         if (lep->pdt < 0)
806*44704f69SBart Van Assche             printf("  %-8s%s-     %s%s\n", lep->acron, bb, lep->name, cp);
807*44704f69SBart Van Assche         else
808*44704f69SBart Van Assche             printf("  %-8s%s0x%02x  %s%s\n", lep->acron, bb, lep->pdt,
809*44704f69SBart Van Assche                    lep->name, cp);
810*44704f69SBart Van Assche     } else
811*44704f69SBart Van Assche         printf("  %-8s%s%s%s\n", lep->acron, bb, lep->name, cp);
812*44704f69SBart Van Assche }
813*44704f69SBart Van Assche 
814*44704f69SBart Van Assche static void
enumerate_pages(const struct opts_t * op)815*44704f69SBart Van Assche enumerate_pages(const struct opts_t * op)
816*44704f69SBart Van Assche {
817*44704f69SBart Van Assche     int j;
818*44704f69SBart Van Assche     struct log_elem * lep;
819*44704f69SBart Van Assche     struct log_elem ** lep_arr;
820*44704f69SBart Van Assche 
821*44704f69SBart Van Assche     if (op->do_enumerate < 3) { /* -e, -ee: sort by acronym */
822*44704f69SBart Van Assche         int k;
823*44704f69SBart Van Assche         struct log_elem ** lepp;
824*44704f69SBart Van Assche 
825*44704f69SBart Van Assche         for (k = 0, lep = log_arr; lep->pg_code >=0; ++lep, ++k)
826*44704f69SBart Van Assche             ;
827*44704f69SBart Van Assche         ++k;
828*44704f69SBart Van Assche         lep_arr = (struct log_elem **)calloc(k, sizeof(struct log_elem *));
829*44704f69SBart Van Assche         if (NULL == lep_arr) {
830*44704f69SBart Van Assche             pr2serr("%s: out of memory\n", __func__);
831*44704f69SBart Van Assche             return;
832*44704f69SBart Van Assche         }
833*44704f69SBart Van Assche         for (k = 0, lep = log_arr; lep->pg_code >=0; ++lep, ++k)
834*44704f69SBart Van Assche             lep_arr[k] = lep;
835*44704f69SBart Van Assche         lep_arr[k++] = lep;     /* put sentinel on end */
836*44704f69SBart Van Assche         qsort(lep_arr, k, sizeof(struct log_elem *), asort_comp);
837*44704f69SBart Van Assche         printf("Known log pages in acronym order:\n");
838*44704f69SBart Van Assche         for (lepp = lep_arr, j = 0; (*lepp)->pg_code >=0; ++lepp, ++j)
839*44704f69SBart Van Assche             enumerate_helper(*lepp, (0 == j), op);
840*44704f69SBart Van Assche         free(lep_arr);
841*44704f69SBart Van Assche     } else {    /* -eee, -eeee numeric sort (as per table) */
842*44704f69SBart Van Assche         printf("Known log pages in numerical order:\n");
843*44704f69SBart Van Assche         for (lep = log_arr, j = 0; lep->pg_code >=0; ++lep, ++j)
844*44704f69SBart Van Assche             enumerate_helper(lep, (0 == j), op);
845*44704f69SBart Van Assche     }
846*44704f69SBart Van Assche }
847*44704f69SBart Van Assche 
848*44704f69SBart Van Assche static const struct log_elem *
acron_search(const char * acron)849*44704f69SBart Van Assche acron_search(const char * acron)
850*44704f69SBart Van Assche {
851*44704f69SBart Van Assche     const struct log_elem * lep;
852*44704f69SBart Van Assche 
853*44704f69SBart Van Assche     for (lep = log_arr; lep->pg_code >=0; ++lep) {
854*44704f69SBart Van Assche         if (0 == strcmp(acron, lep->acron))
855*44704f69SBart Van Assche             return lep;
856*44704f69SBart Van Assche     }
857*44704f69SBart Van Assche     return NULL;
858*44704f69SBart Van Assche }
859*44704f69SBart Van Assche 
860*44704f69SBart Van Assche static int
find_vpn_by_acron(const char * vp_ap)861*44704f69SBart Van Assche find_vpn_by_acron(const char * vp_ap)
862*44704f69SBart Van Assche {
863*44704f69SBart Van Assche     const struct vp_name_t * vpp;
864*44704f69SBart Van Assche 
865*44704f69SBart Van Assche     for (vpp = vp_arr; vpp->acron; ++vpp) {
866*44704f69SBart Van Assche         size_t k;
867*44704f69SBart Van Assche         size_t len = strlen(vpp->acron);
868*44704f69SBart Van Assche 
869*44704f69SBart Van Assche         for (k = 0; k < len; ++k) {
870*44704f69SBart Van Assche             if (tolower((uint8_t)vp_ap[k]) != (uint8_t)vpp->acron[k])
871*44704f69SBart Van Assche                 break;
872*44704f69SBart Van Assche         }
873*44704f69SBart Van Assche         if (k < len)
874*44704f69SBart Van Assche             continue;
875*44704f69SBart Van Assche         return vpp->vend_prod_num;
876*44704f69SBart Van Assche     }
877*44704f69SBart Van Assche     return VP_NONE;
878*44704f69SBart Van Assche }
879*44704f69SBart Van Assche 
880*44704f69SBart Van Assche /* Find vendor product number using T10 VENDOR and PRODUCT ID fields in a
881*44704f69SBart Van Assche    INQUIRY response. */
882*44704f69SBart Van Assche static int
find_vpn_by_inquiry(void)883*44704f69SBart Van Assche find_vpn_by_inquiry(void)
884*44704f69SBart Van Assche {
885*44704f69SBart Van Assche     size_t len;
886*44704f69SBart Van Assche     size_t t10_v_len = strlen(t10_vendor_str);
887*44704f69SBart Van Assche     size_t t10_p_len = strlen(t10_product_str);
888*44704f69SBart Van Assche     const struct vp_name_t * vpp;
889*44704f69SBart Van Assche 
890*44704f69SBart Van Assche     if ((0 == t10_v_len) && (0 == t10_p_len))
891*44704f69SBart Van Assche         return VP_NONE;
892*44704f69SBart Van Assche     for (vpp = vp_arr; vpp->acron; ++vpp) {
893*44704f69SBart Van Assche         bool matched = false;
894*44704f69SBart Van Assche 
895*44704f69SBart Van Assche         if (vpp->t10_vendorp && (t10_v_len > 0)) {
896*44704f69SBart Van Assche             len = strlen(vpp->t10_vendorp);
897*44704f69SBart Van Assche             len = (len > t10_v_len) ? t10_v_len : len;
898*44704f69SBart Van Assche             if (strncmp(vpp->t10_vendorp, t10_vendor_str, len))
899*44704f69SBart Van Assche                 continue;
900*44704f69SBart Van Assche             matched = true;
901*44704f69SBart Van Assche         }
902*44704f69SBart Van Assche         if (vpp->t10_productp && (t10_p_len > 0)) {
903*44704f69SBart Van Assche             len = strlen(vpp->t10_productp);
904*44704f69SBart Van Assche             len = (len > t10_p_len) ? t10_p_len : len;
905*44704f69SBart Van Assche             if (strncmp(vpp->t10_productp, t10_product_str, len))
906*44704f69SBart Van Assche                 continue;
907*44704f69SBart Van Assche             matched = true;
908*44704f69SBart Van Assche         }
909*44704f69SBart Van Assche         if (matched)
910*44704f69SBart Van Assche             return vpp->vend_prod_num;
911*44704f69SBart Van Assche     }
912*44704f69SBart Van Assche     return VP_NONE;
913*44704f69SBart Van Assche }
914*44704f69SBart Van Assche 
915*44704f69SBart Van Assche static void
enumerate_vp(void)916*44704f69SBart Van Assche enumerate_vp(void)
917*44704f69SBart Van Assche {
918*44704f69SBart Van Assche     const struct vp_name_t * vpp;
919*44704f69SBart Van Assche     bool seen = false;
920*44704f69SBart Van Assche 
921*44704f69SBart Van Assche     for (vpp = vp_arr; vpp->acron; ++vpp) {
922*44704f69SBart Van Assche         if (vpp->name) {
923*44704f69SBart Van Assche             if (! seen) {
924*44704f69SBart Van Assche                 printf("\nVendor/product identifiers:\n");
925*44704f69SBart Van Assche                 seen = true;
926*44704f69SBart Van Assche             }
927*44704f69SBart Van Assche             printf("  %-10s %d      %s\n", vpp->acron,
928*44704f69SBart Van Assche                    vpp->vend_prod_num, vpp->name);
929*44704f69SBart Van Assche         }
930*44704f69SBart Van Assche     }
931*44704f69SBart Van Assche }
932*44704f69SBart Van Assche 
933*44704f69SBart Van Assche static const struct log_elem *
pg_subpg_pdt_search(int pg_code,int subpg_code,int pdt,int vpn)934*44704f69SBart Van Assche pg_subpg_pdt_search(int pg_code, int subpg_code, int pdt, int vpn)
935*44704f69SBart Van Assche {
936*44704f69SBart Van Assche     const struct log_elem * lep;
937*44704f69SBart Van Assche     int d_pdt;
938*44704f69SBart Van Assche     int vp_mask = get_vp_mask(vpn);
939*44704f69SBart Van Assche 
940*44704f69SBart Van Assche     d_pdt = sg_lib_pdt_decay(pdt);
941*44704f69SBart Van Assche     for (lep = log_arr; lep->pg_code >=0; ++lep) {
942*44704f69SBart Van Assche         if (pg_code == lep->pg_code) {
943*44704f69SBart Van Assche             if (subpg_code == lep->subpg_code) {
944*44704f69SBart Van Assche                 if ((MVP_STD & lep->flags) || (0 == vp_mask) ||
945*44704f69SBart Van Assche                     (vp_mask & lep->flags))
946*44704f69SBart Van Assche                     ;
947*44704f69SBart Van Assche                 else
948*44704f69SBart Van Assche                     continue;
949*44704f69SBart Van Assche                 if ((lep->pdt < 0) || (pdt == lep->pdt) || (pdt < 0))
950*44704f69SBart Van Assche                     return lep;
951*44704f69SBart Van Assche                 else if (d_pdt == lep->pdt)
952*44704f69SBart Van Assche                     return lep;
953*44704f69SBart Van Assche                 else if (pdt == sg_lib_pdt_decay(lep->pdt))
954*44704f69SBart Van Assche                     return lep;
955*44704f69SBart Van Assche             } else if ((lep->subpg_high > 0) &&
956*44704f69SBart Van Assche                      (subpg_code > lep->subpg_code) &&
957*44704f69SBart Van Assche                      (subpg_code <= lep->subpg_high))
958*44704f69SBart Van Assche                 return lep;
959*44704f69SBart Van Assche         }
960*44704f69SBart Van Assche     }
961*44704f69SBart Van Assche     return NULL;
962*44704f69SBart Van Assche }
963*44704f69SBart Van Assche 
964*44704f69SBart Van Assche static void
js_snakenv_ihexstr_nex(sgj_state * jsp,sgj_opaque_p jop,const char * conv2sname,int64_t val_i,bool hex_as_well,const char * str_name,const char * val_s,const char * nex_s)965*44704f69SBart Van Assche js_snakenv_ihexstr_nex(sgj_state * jsp, sgj_opaque_p jop,
966*44704f69SBart Van Assche                        const char * conv2sname, int64_t val_i,
967*44704f69SBart Van Assche                        bool hex_as_well, const char * str_name,
968*44704f69SBart Van Assche                        const char * val_s, const char * nex_s)
969*44704f69SBart Van Assche {
970*44704f69SBart Van Assche 
971*44704f69SBart Van Assche     if ((NULL == jsp) || (NULL == jop))
972*44704f69SBart Van Assche         return;
973*44704f69SBart Van Assche     if (sgj_is_snake_name(conv2sname))
974*44704f69SBart Van Assche         sgj_js_nv_ihexstr_nex(jsp, jop, conv2sname, val_i, hex_as_well,
975*44704f69SBart Van Assche                               str_name, val_s, nex_s);
976*44704f69SBart Van Assche     else {
977*44704f69SBart Van Assche         char b[128];
978*44704f69SBart Van Assche 
979*44704f69SBart Van Assche         sgj_convert_to_snake_name(conv2sname, b, sizeof(b));
980*44704f69SBart Van Assche         sgj_js_nv_ihexstr_nex(jsp, jop, b, val_i, hex_as_well, str_name,
981*44704f69SBart Van Assche                               val_s, nex_s);
982*44704f69SBart Van Assche     }
983*44704f69SBart Van Assche }
984*44704f69SBart Van Assche 
985*44704f69SBart Van Assche static void
usage_for(int hval,const struct opts_t * op)986*44704f69SBart Van Assche usage_for(int hval, const struct opts_t * op)
987*44704f69SBart Van Assche {
988*44704f69SBart Van Assche     if (op->opt_new)
989*44704f69SBart Van Assche         usage(hval);
990*44704f69SBart Van Assche     else
991*44704f69SBart Van Assche         usage_old();
992*44704f69SBart Van Assche }
993*44704f69SBart Van Assche 
994*44704f69SBart Van Assche /* Processes command line options according to new option format. Returns
995*44704f69SBart Van Assche  * 0 is ok, else SG_LIB_SYNTAX_ERROR is returned. */
996*44704f69SBart Van Assche static int
new_parse_cmd_line(struct opts_t * op,int argc,char * argv[])997*44704f69SBart Van Assche new_parse_cmd_line(struct opts_t * op, int argc, char * argv[])
998*44704f69SBart Van Assche {
999*44704f69SBart Van Assche     while (1) {
1000*44704f69SBart Van Assche         int c, n;
1001*44704f69SBart Van Assche         int option_index = 0;
1002*44704f69SBart Van Assche 
1003*44704f69SBart Van Assche         c = getopt_long(argc, argv, "aAbc:D:eEf:FhHi:j::lLm:M:nNOp:P:qQrRsStT"
1004*44704f69SBart Van Assche                         "uvVxX", long_options, &option_index);
1005*44704f69SBart Van Assche         if (c == -1)
1006*44704f69SBart Van Assche             break;
1007*44704f69SBart Van Assche 
1008*44704f69SBart Van Assche         switch (c) {
1009*44704f69SBart Van Assche         case 'a':
1010*44704f69SBart Van Assche             ++op->do_all;
1011*44704f69SBart Van Assche             break;
1012*44704f69SBart Van Assche         case 'A':
1013*44704f69SBart Van Assche             op->do_all += 2;
1014*44704f69SBart Van Assche             break;
1015*44704f69SBart Van Assche         case 'b':
1016*44704f69SBart Van Assche             ++op->do_brief;
1017*44704f69SBart Van Assche             break;
1018*44704f69SBart Van Assche         case 'c':
1019*44704f69SBart Van Assche             n = sg_get_num(optarg);
1020*44704f69SBart Van Assche             if ((n < 0) || (n > 3)) {
1021*44704f69SBart Van Assche                 pr2serr("bad argument to '--control='\n");
1022*44704f69SBart Van Assche                 usage(2);
1023*44704f69SBart Van Assche                 return SG_LIB_SYNTAX_ERROR;
1024*44704f69SBart Van Assche             }
1025*44704f69SBart Van Assche             op->page_control = n;
1026*44704f69SBart Van Assche             break;
1027*44704f69SBart Van Assche         case 'D':
1028*44704f69SBart Van Assche             if (0 == memcmp("-1", optarg, 3))
1029*44704f69SBart Van Assche                 op->dev_pdt = -1;
1030*44704f69SBart Van Assche             else {
1031*44704f69SBart Van Assche                 n = sg_get_num(optarg);
1032*44704f69SBart Van Assche                 if ((n < 0) || (n > 31)) {
1033*44704f69SBart Van Assche                     pr2serr("bad argument to '--pdt='\n");
1034*44704f69SBart Van Assche                     return SG_LIB_SYNTAX_ERROR;
1035*44704f69SBart Van Assche                 }
1036*44704f69SBart Van Assche                 op->dev_pdt = n;
1037*44704f69SBart Van Assche             }
1038*44704f69SBart Van Assche             break;
1039*44704f69SBart Van Assche         case 'e':
1040*44704f69SBart Van Assche             ++op->do_enumerate;
1041*44704f69SBart Van Assche             break;
1042*44704f69SBart Van Assche         case 'E':
1043*44704f69SBart Van Assche             op->exclude_vendor = true;
1044*44704f69SBart Van Assche             break;
1045*44704f69SBart Van Assche         case 'f':
1046*44704f69SBart Van Assche             if ('-' == optarg[0]) {
1047*44704f69SBart Van Assche                 n = sg_get_num(optarg + 1);
1048*44704f69SBart Van Assche                 if ((n < 0) || (n > 0x30)) {
1049*44704f69SBart Van Assche                     pr2serr("bad negated argument to '--filter='\n");
1050*44704f69SBart Van Assche                     return SG_LIB_SYNTAX_ERROR;
1051*44704f69SBart Van Assche                 }
1052*44704f69SBart Van Assche                 op->filter = -n;
1053*44704f69SBart Van Assche             } else {
1054*44704f69SBart Van Assche                 n = sg_get_num(optarg);
1055*44704f69SBart Van Assche                 if ((n < 0) || (n > 0xffff)) {
1056*44704f69SBart Van Assche                     pr2serr("bad argument to '--filter='\n");
1057*44704f69SBart Van Assche                     usage(1);
1058*44704f69SBart Van Assche                     return SG_LIB_SYNTAX_ERROR;
1059*44704f69SBart Van Assche                 }
1060*44704f69SBart Van Assche                 op->filter = n;
1061*44704f69SBart Van Assche             }
1062*44704f69SBart Van Assche             op->filter_given = true;
1063*44704f69SBart Van Assche             break;
1064*44704f69SBart Van Assche         case 'F':
1065*44704f69SBart Van Assche             op->do_full = true;
1066*44704f69SBart Van Assche             break;
1067*44704f69SBart Van Assche         case 'h':
1068*44704f69SBart Van Assche         case '?':
1069*44704f69SBart Van Assche             ++op->do_help;
1070*44704f69SBart Van Assche             break;
1071*44704f69SBart Van Assche         case 'H':
1072*44704f69SBart Van Assche             ++op->do_hex;
1073*44704f69SBart Van Assche             break;
1074*44704f69SBart Van Assche         case 'i':
1075*44704f69SBart Van Assche             op->in_fn = optarg;
1076*44704f69SBart Van Assche             break;
1077*44704f69SBart Van Assche         case 'j':
1078*44704f69SBart Van Assche            if (! sgj_init_state(&op->json_st, optarg)) {
1079*44704f69SBart Van Assche                 int bad_char = op->json_st.first_bad_char;
1080*44704f69SBart Van Assche                 char e[1500];
1081*44704f69SBart Van Assche 
1082*44704f69SBart Van Assche                 if (bad_char) {
1083*44704f69SBart Van Assche                     pr2serr("bad argument to --json= option, unrecognized "
1084*44704f69SBart Van Assche                             "character '%c'\n\n", bad_char);
1085*44704f69SBart Van Assche                 }
1086*44704f69SBart Van Assche                 sg_json_usage(0, e, sizeof(e));
1087*44704f69SBart Van Assche                 pr2serr("%s", e);
1088*44704f69SBart Van Assche                 return SG_LIB_SYNTAX_ERROR;
1089*44704f69SBart Van Assche             }
1090*44704f69SBart Van Assche             break;
1091*44704f69SBart Van Assche         case 'l':
1092*44704f69SBart Van Assche             ++op->do_list;
1093*44704f69SBart Van Assche             break;
1094*44704f69SBart Van Assche         case 'L':
1095*44704f69SBart Van Assche             op->do_list += 2;
1096*44704f69SBart Van Assche             break;
1097*44704f69SBart Van Assche         case 'm':
1098*44704f69SBart Van Assche             n = sg_get_num(optarg);
1099*44704f69SBart Van Assche             if ((n < 0) || (1 == n)) {
1100*44704f69SBart Van Assche                 pr2serr("bad argument to '--maxlen=', from 2 and up "
1101*44704f69SBart Van Assche                         "expected\n");
1102*44704f69SBart Van Assche                 usage(2);
1103*44704f69SBart Van Assche                 return SG_LIB_SYNTAX_ERROR;
1104*44704f69SBart Van Assche             } else if (n < 4) {
1105*44704f69SBart Van Assche                 pr2serr("Warning: setting '--maxlen' to 4\n");
1106*44704f69SBart Van Assche                 n = 4;
1107*44704f69SBart Van Assche             }
1108*44704f69SBart Van Assche             op->maxlen = n;
1109*44704f69SBart Van Assche             op->maxlen_given = true;
1110*44704f69SBart Van Assche             break;
1111*44704f69SBart Van Assche         case 'M':
1112*44704f69SBart Van Assche             if (op->vend_prod) {
1113*44704f69SBart Van Assche                 pr2serr("only one '--vendor=' option permitted\n");
1114*44704f69SBart Van Assche                 usage(2);
1115*44704f69SBart Van Assche                 return SG_LIB_SYNTAX_ERROR;
1116*44704f69SBart Van Assche             } else
1117*44704f69SBart Van Assche                 op->vend_prod = optarg;
1118*44704f69SBart Van Assche             break;
1119*44704f69SBart Van Assche         case 'n':
1120*44704f69SBart Van Assche             op->do_name = true;
1121*44704f69SBart Van Assche             break;
1122*44704f69SBart Van Assche         case 'N':
1123*44704f69SBart Van Assche             break;      /* ignore */
1124*44704f69SBart Van Assche         case 'O':
1125*44704f69SBart Van Assche             op->opt_new = false;
1126*44704f69SBart Van Assche             return 0;
1127*44704f69SBart Van Assche         case 'p':
1128*44704f69SBart Van Assche             op->pg_arg = optarg;
1129*44704f69SBart Van Assche             break;
1130*44704f69SBart Van Assche         case 'P':
1131*44704f69SBart Van Assche             n = sg_get_num(optarg);
1132*44704f69SBart Van Assche             if (n < 0) {
1133*44704f69SBart Van Assche                 pr2serr("bad argument to '--paramp='\n");
1134*44704f69SBart Van Assche                 usage(2);
1135*44704f69SBart Van Assche                 return SG_LIB_SYNTAX_ERROR;
1136*44704f69SBart Van Assche             }
1137*44704f69SBart Van Assche             op->paramp = n;
1138*44704f69SBart Van Assche             break;
1139*44704f69SBart Van Assche         case 'q':
1140*44704f69SBart Van Assche             op->do_pcb = true;
1141*44704f69SBart Van Assche             break;
1142*44704f69SBart Van Assche         case 'Q':       /* N.B. PPC bit obsoleted in SPC-4 rev 18 */
1143*44704f69SBart Van Assche             op->do_ppc = true;
1144*44704f69SBart Van Assche             break;
1145*44704f69SBart Van Assche         case 'r':
1146*44704f69SBart Van Assche             op->do_raw = true;
1147*44704f69SBart Van Assche             break;
1148*44704f69SBart Van Assche         case 'R':
1149*44704f69SBart Van Assche             op->do_pcreset = true;
1150*44704f69SBart Van Assche             op->do_select = true;
1151*44704f69SBart Van Assche             break;
1152*44704f69SBart Van Assche         case 's':
1153*44704f69SBart Van Assche             op->do_sp = true;
1154*44704f69SBart Van Assche             break;
1155*44704f69SBart Van Assche         case 'S':
1156*44704f69SBart Van Assche             op->do_select = true;
1157*44704f69SBart Van Assche             break;
1158*44704f69SBart Van Assche         case 't':
1159*44704f69SBart Van Assche             op->do_temperature = true;
1160*44704f69SBart Van Assche             break;
1161*44704f69SBart Van Assche         case 'T':
1162*44704f69SBart Van Assche             op->do_transport = true;
1163*44704f69SBart Van Assche             break;
1164*44704f69SBart Van Assche         case 'u':
1165*44704f69SBart Van Assche             ++op->undefined_hex;
1166*44704f69SBart Van Assche             break;
1167*44704f69SBart Van Assche         case 'v':
1168*44704f69SBart Van Assche             op->verbose_given = true;
1169*44704f69SBart Van Assche             ++op->verbose;
1170*44704f69SBart Van Assche             break;
1171*44704f69SBart Van Assche         case 'V':
1172*44704f69SBart Van Assche             op->version_given = true;
1173*44704f69SBart Van Assche             break;
1174*44704f69SBart Van Assche         case 'x':
1175*44704f69SBart Van Assche             ++op->no_inq;
1176*44704f69SBart Van Assche             break;
1177*44704f69SBart Van Assche         case 'X':
1178*44704f69SBart Van Assche             op->o_readonly = true;
1179*44704f69SBart Van Assche             break;
1180*44704f69SBart Van Assche         default:
1181*44704f69SBart Van Assche             pr2serr("unrecognised option code %c [0x%x]\n", c, c);
1182*44704f69SBart Van Assche             if (op->do_help)
1183*44704f69SBart Van Assche                 break;
1184*44704f69SBart Van Assche             usage(1);
1185*44704f69SBart Van Assche             return SG_LIB_SYNTAX_ERROR;
1186*44704f69SBart Van Assche         }
1187*44704f69SBart Van Assche     }
1188*44704f69SBart Van Assche     if (optind < argc) {
1189*44704f69SBart Van Assche         if (NULL == op->device_name) {
1190*44704f69SBart Van Assche             op->device_name = argv[optind];
1191*44704f69SBart Van Assche             ++optind;
1192*44704f69SBart Van Assche         }
1193*44704f69SBart Van Assche         if (optind < argc) {
1194*44704f69SBart Van Assche             for (; optind < argc; ++optind)
1195*44704f69SBart Van Assche                 pr2serr("Unexpected extra argument: %s\n", argv[optind]);
1196*44704f69SBart Van Assche             usage(1);
1197*44704f69SBart Van Assche             return SG_LIB_SYNTAX_ERROR;
1198*44704f69SBart Van Assche         }
1199*44704f69SBart Van Assche     }
1200*44704f69SBart Van Assche     return 0;
1201*44704f69SBart Van Assche }
1202*44704f69SBart Van Assche 
1203*44704f69SBart Van Assche /* Processes command line options according to old option format. Returns
1204*44704f69SBart Van Assche  * 0 is ok, else SG_LIB_SYNTAX_ERROR is returned. */
1205*44704f69SBart Van Assche static int
old_parse_cmd_line(struct opts_t * op,int argc,char * argv[])1206*44704f69SBart Van Assche old_parse_cmd_line(struct opts_t * op, int argc, char * argv[])
1207*44704f69SBart Van Assche {
1208*44704f69SBart Van Assche     bool jmp_out;
1209*44704f69SBart Van Assche     int k, num, n;
1210*44704f69SBart Van Assche     unsigned int u, uu;
1211*44704f69SBart Van Assche     const char * cp;
1212*44704f69SBart Van Assche 
1213*44704f69SBart Van Assche     for (k = 1; k < argc; ++k) {
1214*44704f69SBart Van Assche         int plen;
1215*44704f69SBart Van Assche 
1216*44704f69SBart Van Assche         cp = argv[k];
1217*44704f69SBart Van Assche         plen = strlen(cp);
1218*44704f69SBart Van Assche         if (plen <= 0)
1219*44704f69SBart Van Assche             continue;
1220*44704f69SBart Van Assche         if ('-' == *cp) {
1221*44704f69SBart Van Assche             for (--plen, ++cp, jmp_out = false; plen > 0; --plen, ++cp) {
1222*44704f69SBart Van Assche                 switch (*cp) {
1223*44704f69SBart Van Assche                 case 'a':
1224*44704f69SBart Van Assche                     ++op->do_all;
1225*44704f69SBart Van Assche                     break;
1226*44704f69SBart Van Assche                 case 'A':
1227*44704f69SBart Van Assche                     op->do_all += 2;
1228*44704f69SBart Van Assche                     break;
1229*44704f69SBart Van Assche                 case 'b':
1230*44704f69SBart Van Assche                     ++op->do_brief;
1231*44704f69SBart Van Assche                     break;
1232*44704f69SBart Van Assche                 case 'e':
1233*44704f69SBart Van Assche                     ++op->do_enumerate;
1234*44704f69SBart Van Assche                     break;
1235*44704f69SBart Van Assche                 case 'E':
1236*44704f69SBart Van Assche                     op->exclude_vendor = true;
1237*44704f69SBart Van Assche                     break;
1238*44704f69SBart Van Assche                 case 'F':
1239*44704f69SBart Van Assche                     op->do_full = true;
1240*44704f69SBart Van Assche                     break;
1241*44704f69SBart Van Assche                 case 'h':
1242*44704f69SBart Van Assche                 case 'H':
1243*44704f69SBart Van Assche                     ++op->do_hex;
1244*44704f69SBart Van Assche                     break;
1245*44704f69SBart Van Assche                 case 'l':
1246*44704f69SBart Van Assche                     ++op->do_list;
1247*44704f69SBart Van Assche                     break;
1248*44704f69SBart Van Assche                 case 'L':
1249*44704f69SBart Van Assche                     op->do_list += 2;
1250*44704f69SBart Van Assche                     break;
1251*44704f69SBart Van Assche                 case 'n':
1252*44704f69SBart Van Assche                     op->do_name = true;
1253*44704f69SBart Van Assche                     break;
1254*44704f69SBart Van Assche                 case 'N':
1255*44704f69SBart Van Assche                     op->opt_new = true;
1256*44704f69SBart Van Assche                     return 0;
1257*44704f69SBart Van Assche                 case 'O':
1258*44704f69SBart Van Assche                     break;
1259*44704f69SBart Van Assche                 case 'r':
1260*44704f69SBart Van Assche                     op->do_pcreset = true;
1261*44704f69SBart Van Assche                     op->do_select = true;
1262*44704f69SBart Van Assche                     break;
1263*44704f69SBart Van Assche                 case 't':
1264*44704f69SBart Van Assche                     op->do_temperature = true;
1265*44704f69SBart Van Assche                     break;
1266*44704f69SBart Van Assche                 case 'T':
1267*44704f69SBart Van Assche                     op->do_transport = true;
1268*44704f69SBart Van Assche                     break;
1269*44704f69SBart Van Assche                 case 'u':
1270*44704f69SBart Van Assche                     ++op->undefined_hex;
1271*44704f69SBart Van Assche                     break;
1272*44704f69SBart Van Assche                 case 'v':
1273*44704f69SBart Van Assche                     op->verbose_given = true;
1274*44704f69SBart Van Assche                     ++op->verbose;
1275*44704f69SBart Van Assche                     break;
1276*44704f69SBart Van Assche                 case 'V':
1277*44704f69SBart Van Assche                     op->version_given = true;
1278*44704f69SBart Van Assche                     break;
1279*44704f69SBart Van Assche                 case 'x':
1280*44704f69SBart Van Assche                     ++op->no_inq;
1281*44704f69SBart Van Assche                     break;
1282*44704f69SBart Van Assche                 case 'X':
1283*44704f69SBart Van Assche                     op->o_readonly = true;
1284*44704f69SBart Van Assche                     break;
1285*44704f69SBart Van Assche                 case '?':
1286*44704f69SBart Van Assche                     ++op->do_help;
1287*44704f69SBart Van Assche                     break;
1288*44704f69SBart Van Assche                 case '-':
1289*44704f69SBart Van Assche                     ++cp;
1290*44704f69SBart Van Assche                     jmp_out = true;
1291*44704f69SBart Van Assche                     break;
1292*44704f69SBart Van Assche                 default:
1293*44704f69SBart Van Assche                     jmp_out = true;
1294*44704f69SBart Van Assche                     break;
1295*44704f69SBart Van Assche                 }
1296*44704f69SBart Van Assche                 if (jmp_out)
1297*44704f69SBart Van Assche                     break;
1298*44704f69SBart Van Assche             }
1299*44704f69SBart Van Assche             if (plen <= 0)
1300*44704f69SBart Van Assche                 continue;
1301*44704f69SBart Van Assche             if (0 == strncmp("c=", cp, 2)) {
1302*44704f69SBart Van Assche                 num = sscanf(cp + 2, "%6x", &u);
1303*44704f69SBart Van Assche                 if ((1 != num) || (u > 3)) {
1304*44704f69SBart Van Assche                     pr2serr("Bad page control after '-c=' option [0..3]\n");
1305*44704f69SBart Van Assche                     usage_old();
1306*44704f69SBart Van Assche                     return SG_LIB_SYNTAX_ERROR;
1307*44704f69SBart Van Assche                 }
1308*44704f69SBart Van Assche                 op->page_control = u;
1309*44704f69SBart Van Assche             } else if (0 == strncmp("D=", cp, 2)) {
1310*44704f69SBart Van Assche                 n = sg_get_num(cp + 2);
1311*44704f69SBart Van Assche                 if ((n < 0) || (n > 31)) {
1312*44704f69SBart Van Assche                     pr2serr("Bad argument after '-D=' option\n");
1313*44704f69SBart Van Assche                     usage_old();
1314*44704f69SBart Van Assche                     return SG_LIB_SYNTAX_ERROR;
1315*44704f69SBart Van Assche                 }
1316*44704f69SBart Van Assche                 op->dev_pdt = n;
1317*44704f69SBart Van Assche             } else if (0 == strncmp("f=", cp, 2)) {
1318*44704f69SBart Van Assche                 n = sg_get_num(cp + 2);
1319*44704f69SBart Van Assche                 if ((n < 0) || (n > 0xffff)) {
1320*44704f69SBart Van Assche                     pr2serr("Bad argument after '-f=' option\n");
1321*44704f69SBart Van Assche                     usage_old();
1322*44704f69SBart Van Assche                     return SG_LIB_SYNTAX_ERROR;
1323*44704f69SBart Van Assche                 }
1324*44704f69SBart Van Assche                 op->filter = n;
1325*44704f69SBart Van Assche                 op->filter_given = true;
1326*44704f69SBart Van Assche             } else if (0 == strncmp("i=", cp, 2))
1327*44704f69SBart Van Assche                 op->in_fn = cp + 2;
1328*44704f69SBart Van Assche             else if (0 == strncmp("m=", cp, 2)) {
1329*44704f69SBart Van Assche                 num = sscanf(cp + 2, "%8d", &n);
1330*44704f69SBart Van Assche                 if ((1 != num) || (n < 0)) {
1331*44704f69SBart Van Assche                     pr2serr("Bad maximum response length after '-m=' "
1332*44704f69SBart Van Assche                             "option\n");
1333*44704f69SBart Van Assche                     usage_old();
1334*44704f69SBart Van Assche                     return SG_LIB_SYNTAX_ERROR;
1335*44704f69SBart Van Assche                 }
1336*44704f69SBart Van Assche                 op->maxlen_given = true;
1337*44704f69SBart Van Assche                 op->maxlen = n;
1338*44704f69SBart Van Assche             } else if (0 == strncmp("M=", cp, 2)) {
1339*44704f69SBart Van Assche                 if (op->vend_prod) {
1340*44704f69SBart Van Assche                     pr2serr("only one '-M=' option permitted\n");
1341*44704f69SBart Van Assche                     usage(2);
1342*44704f69SBart Van Assche                     return SG_LIB_SYNTAX_ERROR;
1343*44704f69SBart Van Assche                 } else
1344*44704f69SBart Van Assche                     op->vend_prod = cp + 2;
1345*44704f69SBart Van Assche             } else if (0 == strncmp("p=", cp, 2)) {
1346*44704f69SBart Van Assche                 const char * ccp = cp + 2;
1347*44704f69SBart Van Assche                 const struct log_elem * lep;
1348*44704f69SBart Van Assche 
1349*44704f69SBart Van Assche                 if (isalpha((uint8_t)ccp[0])) {
1350*44704f69SBart Van Assche                     char * xp;
1351*44704f69SBart Van Assche                     char b[80];
1352*44704f69SBart Van Assche 
1353*44704f69SBart Van Assche                     if (strlen(ccp) >= (sizeof(b) - 1)) {
1354*44704f69SBart Van Assche                         pr2serr("argument to '-p=' is too long\n");
1355*44704f69SBart Van Assche                         return SG_LIB_SYNTAX_ERROR;
1356*44704f69SBart Van Assche                     }
1357*44704f69SBart Van Assche                     strcpy(b, ccp);
1358*44704f69SBart Van Assche                     xp = (char *)strchr(b, ',');
1359*44704f69SBart Van Assche                     if (xp)
1360*44704f69SBart Van Assche                         *xp = '\0';
1361*44704f69SBart Van Assche                     lep = acron_search(b);
1362*44704f69SBart Van Assche                     if (NULL == lep) {
1363*44704f69SBart Van Assche                         pr2serr("bad argument to '--page=' no acronyn match "
1364*44704f69SBart Van Assche                                 "to '%s'\n", b);
1365*44704f69SBart Van Assche                         pr2serr("  Try using '-e' or'-ee' to see available "
1366*44704f69SBart Van Assche                                 "acronyns\n");
1367*44704f69SBart Van Assche                         return SG_LIB_SYNTAX_ERROR;
1368*44704f69SBart Van Assche                     }
1369*44704f69SBart Van Assche                     op->lep = lep;
1370*44704f69SBart Van Assche                     op->pg_code = lep->pg_code;
1371*44704f69SBart Van Assche                     if (xp) {
1372*44704f69SBart Van Assche                         n = sg_get_num_nomult(xp + 1);
1373*44704f69SBart Van Assche                         if ((n < 0) || (n > 255)) {
1374*44704f69SBart Van Assche                             pr2serr("Bad second value in argument to "
1375*44704f69SBart Van Assche                                     "'--page='\n");
1376*44704f69SBart Van Assche                             return SG_LIB_SYNTAX_ERROR;
1377*44704f69SBart Van Assche                         }
1378*44704f69SBart Van Assche                         op->subpg_code = n;
1379*44704f69SBart Van Assche                     } else
1380*44704f69SBart Van Assche                         op->subpg_code = lep->subpg_code;
1381*44704f69SBart Van Assche                 } else {
1382*44704f69SBart Van Assche                     /* numeric arg: either 'pg_num' or 'pg_num,subpg_num' */
1383*44704f69SBart Van Assche                     if (NULL == strchr(cp + 2, ',')) {
1384*44704f69SBart Van Assche                         num = sscanf(cp + 2, "%6x", &u);
1385*44704f69SBart Van Assche                         if ((1 != num) || (u > 63)) {
1386*44704f69SBart Van Assche                             pr2serr("Bad page code value after '-p=' "
1387*44704f69SBart Van Assche                                     "option\n");
1388*44704f69SBart Van Assche                             usage_old();
1389*44704f69SBart Van Assche                             return SG_LIB_SYNTAX_ERROR;
1390*44704f69SBart Van Assche                         }
1391*44704f69SBart Van Assche                         op->pg_code = u;
1392*44704f69SBart Van Assche                     } else if (2 == sscanf(cp + 2, "%4x,%4x", &u, &uu)) {
1393*44704f69SBart Van Assche                         if (uu > 255) {
1394*44704f69SBart Van Assche                             pr2serr("Bad sub page code value after '-p=' "
1395*44704f69SBart Van Assche                                     "option\n");
1396*44704f69SBart Van Assche                             usage_old();
1397*44704f69SBart Van Assche                             return SG_LIB_SYNTAX_ERROR;
1398*44704f69SBart Van Assche                         }
1399*44704f69SBart Van Assche                         op->pg_code = u;
1400*44704f69SBart Van Assche                         op->subpg_code = uu;
1401*44704f69SBart Van Assche                     } else {
1402*44704f69SBart Van Assche                         pr2serr("Bad page code, subpage code sequence after "
1403*44704f69SBart Van Assche                                 "'-p=' option\n");
1404*44704f69SBart Van Assche                         usage_old();
1405*44704f69SBart Van Assche                         return SG_LIB_SYNTAX_ERROR;
1406*44704f69SBart Van Assche                     }
1407*44704f69SBart Van Assche                 }
1408*44704f69SBart Van Assche             } else if (0 == strncmp("paramp=", cp, 7)) {
1409*44704f69SBart Van Assche                 num = sscanf(cp + 7, "%8x", &u);
1410*44704f69SBart Van Assche                 if ((1 != num) || (u > 0xffff)) {
1411*44704f69SBart Van Assche                     pr2serr("Bad parameter pointer after '-paramp=' "
1412*44704f69SBart Van Assche                             "option\n");
1413*44704f69SBart Van Assche                     usage_old();
1414*44704f69SBart Van Assche                     return SG_LIB_SYNTAX_ERROR;
1415*44704f69SBart Van Assche                 }
1416*44704f69SBart Van Assche                 op->paramp = u;
1417*44704f69SBart Van Assche             } else if (0 == strncmp("pcb", cp, 3))
1418*44704f69SBart Van Assche                 op->do_pcb = true;
1419*44704f69SBart Van Assche             else if (0 == strncmp("ppc", cp, 3))
1420*44704f69SBart Van Assche                 op->do_ppc = true;
1421*44704f69SBart Van Assche             else if (0 == strncmp("select", cp, 6))
1422*44704f69SBart Van Assche                 op->do_select = true;
1423*44704f69SBart Van Assche             else if (0 == strncmp("sp", cp, 2))
1424*44704f69SBart Van Assche                 op->do_sp = true;
1425*44704f69SBart Van Assche             else if (0 == strncmp("old", cp, 3))
1426*44704f69SBart Van Assche                 ;
1427*44704f69SBart Van Assche             else if (jmp_out) {
1428*44704f69SBart Van Assche                 pr2serr("Unrecognized option: %s\n", cp);
1429*44704f69SBart Van Assche                 usage_old();
1430*44704f69SBart Van Assche                 return SG_LIB_SYNTAX_ERROR;
1431*44704f69SBart Van Assche             }
1432*44704f69SBart Van Assche         } else if (0 == op->device_name)
1433*44704f69SBart Van Assche             op->device_name = cp;
1434*44704f69SBart Van Assche         else {
1435*44704f69SBart Van Assche             pr2serr("too many arguments, got: %s, not expecting: %s\n",
1436*44704f69SBart Van Assche                     op->device_name, cp);
1437*44704f69SBart Van Assche             usage_old();
1438*44704f69SBart Van Assche             return SG_LIB_SYNTAX_ERROR;
1439*44704f69SBart Van Assche         }
1440*44704f69SBart Van Assche     }
1441*44704f69SBart Van Assche     return 0;
1442*44704f69SBart Van Assche }
1443*44704f69SBart Van Assche 
1444*44704f69SBart Van Assche /* Process command line options. First check using new option format unless
1445*44704f69SBart Van Assche  * the SG3_UTILS_OLD_OPTS environment variable is defined which causes the
1446*44704f69SBart Van Assche  * old option format to be checked first. Both new and old format can be
1447*44704f69SBart Van Assche  * countermanded by a '-O' and '-N' options respectively. As soon as either
1448*44704f69SBart Van Assche  * of these options is detected (when processing the other format), processing
1449*44704f69SBart Van Assche  * stops and is restarted using the other format. Clear? */
1450*44704f69SBart Van Assche static int
parse_cmd_line(struct opts_t * op,int argc,char * argv[])1451*44704f69SBart Van Assche parse_cmd_line(struct opts_t * op, int argc, char * argv[])
1452*44704f69SBart Van Assche {
1453*44704f69SBart Van Assche     int res;
1454*44704f69SBart Van Assche     char * cp;
1455*44704f69SBart Van Assche 
1456*44704f69SBart Van Assche     cp = getenv("SG3_UTILS_OLD_OPTS");
1457*44704f69SBart Van Assche     if (cp) {
1458*44704f69SBart Van Assche         op->opt_new = false;
1459*44704f69SBart Van Assche         res = old_parse_cmd_line(op, argc, argv);
1460*44704f69SBart Van Assche         if ((0 == res) && op->opt_new)
1461*44704f69SBart Van Assche             res = new_parse_cmd_line(op, argc, argv);
1462*44704f69SBart Van Assche     } else {
1463*44704f69SBart Van Assche         op->opt_new = true;
1464*44704f69SBart Van Assche         res = new_parse_cmd_line(op, argc, argv);
1465*44704f69SBart Van Assche         if ((0 == res) && (0 == op->opt_new))
1466*44704f69SBart Van Assche             res = old_parse_cmd_line(op, argc, argv);
1467*44704f69SBart Van Assche     }
1468*44704f69SBart Van Assche     return res;
1469*44704f69SBart Van Assche }
1470*44704f69SBart Van Assche 
1471*44704f69SBart Van Assche static void
dStrRaw(const uint8_t * str,int len)1472*44704f69SBart Van Assche dStrRaw(const uint8_t * str, int len)
1473*44704f69SBart Van Assche {
1474*44704f69SBart Van Assche     int k;
1475*44704f69SBart Van Assche 
1476*44704f69SBart Van Assche     for (k = 0; k < len; ++k)
1477*44704f69SBart Van Assche         printf("%c", str[k]);
1478*44704f69SBart Van Assche }
1479*44704f69SBart Van Assche 
1480*44704f69SBart Van Assche /* Returns 'xp' with "unknown" if all bits set; otherwise decoded (big endian)
1481*44704f69SBart Van Assche  * number in 'xp'. Number rendered in decimal if pr_in_hex=false otherwise in
1482*44704f69SBart Van Assche  * hex with leading '0x' prepended. */
1483*44704f69SBart Van Assche static char *
num_or_unknown(const uint8_t * xp,int num_bytes,bool pr_in_hex,char * b,int blen)1484*44704f69SBart Van Assche num_or_unknown(const uint8_t * xp, int num_bytes /* max is 8 */,
1485*44704f69SBart Van Assche                bool pr_in_hex, char * b, int blen)
1486*44704f69SBart Van Assche {
1487*44704f69SBart Van Assche     if (sg_all_ffs(xp, num_bytes))
1488*44704f69SBart Van Assche         snprintf(b, blen, "%s", unknown_s);
1489*44704f69SBart Van Assche     else {
1490*44704f69SBart Van Assche         uint64_t num = sg_get_unaligned_be(num_bytes, xp);
1491*44704f69SBart Van Assche 
1492*44704f69SBart Van Assche         if (pr_in_hex)
1493*44704f69SBart Van Assche             snprintf(b, blen, "0x%" PRIx64, num);
1494*44704f69SBart Van Assche         else
1495*44704f69SBart Van Assche             snprintf(b, blen, "%" PRIu64, num);
1496*44704f69SBart Van Assche     }
1497*44704f69SBart Van Assche     return b;
1498*44704f69SBart Van Assche }
1499*44704f69SBart Van Assche 
1500*44704f69SBart Van Assche /* Call LOG SENSE twice: the first time ask for 4 byte response to determine
1501*44704f69SBart Van Assche    actual length of response; then a second time requesting the
1502*44704f69SBart Van Assche    min(actual_len, mx_resp_len) bytes. If the calculated length for the
1503*44704f69SBart Van Assche    second fetch is odd then it is incremented (perhaps should be made modulo
1504*44704f69SBart Van Assche    4 in the future for SAS). Returns 0 if ok, SG_LIB_CAT_INVALID_OP for
1505*44704f69SBart Van Assche    log_sense not supported, SG_LIB_CAT_ILLEGAL_REQ for bad field in log sense
1506*44704f69SBart Van Assche    command, SG_LIB_CAT_NOT_READY, SG_LIB_CAT_UNIT_ATTENTION,
1507*44704f69SBart Van Assche    SG_LIB_CAT_ABORTED_COMMAND and -1 for other errors. */
1508*44704f69SBart Van Assche static int
do_logs(int sg_fd,uint8_t * resp,int mx_resp_len,const struct opts_t * op)1509*44704f69SBart Van Assche do_logs(int sg_fd, uint8_t * resp, int mx_resp_len,
1510*44704f69SBart Van Assche         const struct opts_t * op)
1511*44704f69SBart Van Assche {
1512*44704f69SBart Van Assche     int calc_len, request_len, res, resid, vb;
1513*44704f69SBart Van Assche 
1514*44704f69SBart Van Assche #ifdef SG_LIB_WIN32
1515*44704f69SBart Van Assche #ifdef SG_LIB_WIN32_DIRECT
1516*44704f69SBart Van Assche     if (! win32_spt_init_state) {
1517*44704f69SBart Van Assche         if (win32_spt_curr_state) {
1518*44704f69SBart Van Assche             if (mx_resp_len < 16384) {
1519*44704f69SBart Van Assche                 scsi_pt_win32_direct(0);
1520*44704f69SBart Van Assche                 win32_spt_curr_state = false;
1521*44704f69SBart Van Assche             }
1522*44704f69SBart Van Assche         } else {
1523*44704f69SBart Van Assche             if (mx_resp_len >= 16384) {
1524*44704f69SBart Van Assche                 scsi_pt_win32_direct(SG_LIB_WIN32_DIRECT /* SPT direct */);
1525*44704f69SBart Van Assche                 win32_spt_curr_state = true;
1526*44704f69SBart Van Assche             }
1527*44704f69SBart Van Assche         }
1528*44704f69SBart Van Assche     }
1529*44704f69SBart Van Assche #endif
1530*44704f69SBart Van Assche #endif
1531*44704f69SBart Van Assche     memset(resp, 0, mx_resp_len);
1532*44704f69SBart Van Assche     vb = op->verbose;
1533*44704f69SBart Van Assche     if (op->maxlen > 1)
1534*44704f69SBart Van Assche         request_len = mx_resp_len;
1535*44704f69SBart Van Assche     else {
1536*44704f69SBart Van Assche         request_len = LOG_SENSE_PROBE_ALLOC_LEN;
1537*44704f69SBart Van Assche         if ((res = sg_ll_log_sense_v2(sg_fd, op->do_ppc, op->do_sp,
1538*44704f69SBart Van Assche                                       op->page_control, op->pg_code,
1539*44704f69SBart Van Assche                                       op->subpg_code, op->paramp,
1540*44704f69SBart Van Assche                                       resp, request_len, LOG_SENSE_DEF_TIMEOUT,
1541*44704f69SBart Van Assche                                       &resid, true /* noisy */, vb)))
1542*44704f69SBart Van Assche             return res;
1543*44704f69SBart Van Assche         if (resid > 0) {
1544*44704f69SBart Van Assche             res = SG_LIB_WILD_RESID;
1545*44704f69SBart Van Assche             goto resid_err;
1546*44704f69SBart Van Assche         }
1547*44704f69SBart Van Assche         calc_len = sg_get_unaligned_be16(resp + 2) + 4;
1548*44704f69SBart Van Assche         if ((! op->do_raw) && (vb > 1)) {
1549*44704f69SBart Van Assche             pr2serr("  Log sense (find length) response:\n");
1550*44704f69SBart Van Assche             hex2stderr(resp, LOG_SENSE_PROBE_ALLOC_LEN, 1);
1551*44704f69SBart Van Assche             pr2serr("  hence calculated response length=%d\n", calc_len);
1552*44704f69SBart Van Assche         }
1553*44704f69SBart Van Assche         if (op->pg_code != (0x3f & resp[0])) {
1554*44704f69SBart Van Assche             if (vb)
1555*44704f69SBart Van Assche                 pr2serr("Page code does not appear in first byte of "
1556*44704f69SBart Van Assche                         "response so it's suspect\n");
1557*44704f69SBart Van Assche             if (calc_len > 0x40) {
1558*44704f69SBart Van Assche                 calc_len = 0x40;
1559*44704f69SBart Van Assche                 if (vb)
1560*44704f69SBart Van Assche                     pr2serr("Trim response length to 64 bytes due to "
1561*44704f69SBart Van Assche                             "suspect response format\n");
1562*44704f69SBart Van Assche             }
1563*44704f69SBart Van Assche         }
1564*44704f69SBart Van Assche         /* Some HBAs don't like odd transfer lengths */
1565*44704f69SBart Van Assche         if (calc_len % 2)
1566*44704f69SBart Van Assche             calc_len += 1;
1567*44704f69SBart Van Assche         if (calc_len > mx_resp_len)
1568*44704f69SBart Van Assche             calc_len = mx_resp_len;
1569*44704f69SBart Van Assche         request_len = calc_len;
1570*44704f69SBart Van Assche     }
1571*44704f69SBart Van Assche     if ((res = sg_ll_log_sense_v2(sg_fd, op->do_ppc, op->do_sp,
1572*44704f69SBart Van Assche                                   op->page_control, op->pg_code,
1573*44704f69SBart Van Assche                                   op->subpg_code, op->paramp,
1574*44704f69SBart Van Assche                                   resp, request_len,
1575*44704f69SBart Van Assche                                   LOG_SENSE_DEF_TIMEOUT, &resid,
1576*44704f69SBart Van Assche                                   true /* noisy */, vb)))
1577*44704f69SBart Van Assche         return res;
1578*44704f69SBart Van Assche     if (resid > 0) {
1579*44704f69SBart Van Assche         request_len -= resid;
1580*44704f69SBart Van Assche         if (request_len < 4) {
1581*44704f69SBart Van Assche             request_len += resid;
1582*44704f69SBart Van Assche             res = SG_LIB_WILD_RESID;
1583*44704f69SBart Van Assche             goto resid_err;
1584*44704f69SBart Van Assche         }
1585*44704f69SBart Van Assche     }
1586*44704f69SBart Van Assche     if ((! op->do_raw) && (vb > 1)) {
1587*44704f69SBart Van Assche         pr2serr("  Log sense response:\n");
1588*44704f69SBart Van Assche         hex2stderr(resp, request_len, 1);
1589*44704f69SBart Van Assche     }
1590*44704f69SBart Van Assche     return 0;
1591*44704f69SBart Van Assche resid_err:
1592*44704f69SBart Van Assche     pr2serr("%s: request_len=%d, resid=%d, problems\n", __func__, request_len,
1593*44704f69SBart Van Assche             resid);
1594*44704f69SBart Van Assche     request_len -= resid;
1595*44704f69SBart Van Assche     if ((request_len > 0) && (! op->do_raw) && (vb > 1)) {
1596*44704f69SBart Van Assche         pr2serr("  Log sense (resid_err) response:\n");
1597*44704f69SBart Van Assche         hex2stderr(resp, request_len, 1);
1598*44704f69SBart Van Assche     }
1599*44704f69SBart Van Assche     return res;
1600*44704f69SBart Van Assche }
1601*44704f69SBart Van Assche 
1602*44704f69SBart Van Assche sgj_opaque_p
sg_log_js_hdr(sgj_state * jsp,sgj_opaque_p jop,const char * name,const uint8_t * log_hdrp)1603*44704f69SBart Van Assche sg_log_js_hdr(sgj_state * jsp, sgj_opaque_p jop, const char * name,
1604*44704f69SBart Van Assche               const uint8_t * log_hdrp)
1605*44704f69SBart Van Assche {
1606*44704f69SBart Van Assche     bool ds = !! (log_hdrp[0] & 0x80);
1607*44704f69SBart Van Assche     bool spf = !! (log_hdrp[0] & 0x40);
1608*44704f69SBart Van Assche     int pg = log_hdrp[0] & 0x3f;
1609*44704f69SBart Van Assche     int subpg = log_hdrp[1];
1610*44704f69SBart Van Assche     size_t nlen = strlen(name);
1611*44704f69SBart Van Assche     sgj_opaque_p jo2p;
1612*44704f69SBart Van Assche     char b[80];
1613*44704f69SBart Van Assche 
1614*44704f69SBart Van Assche     if ((nlen < 4) || (0 != strcmp("age", name + nlen - 3))) {
1615*44704f69SBart Van Assche         memcpy(b, name, nlen);
1616*44704f69SBart Van Assche         memcpy(b + nlen, " log page", 10);
1617*44704f69SBart Van Assche         jo2p = sgj_snake_named_subobject_r(jsp, jop, b);
1618*44704f69SBart Van Assche     } else
1619*44704f69SBart Van Assche         jo2p = sgj_snake_named_subobject_r(jsp, jop, name);
1620*44704f69SBart Van Assche 
1621*44704f69SBart Van Assche     sgj_js_nv_ihex_nex(jsp, jo2p, "ds", (int)ds, false, "Did not Save");
1622*44704f69SBart Van Assche     sgj_js_nv_ihex_nex(jsp, jo2p, "spf", (int)spf, NULL, "SubPage Format");
1623*44704f69SBart Van Assche     sgj_js_nv_ihex(jsp, jo2p, "page_code", pg);
1624*44704f69SBart Van Assche     sgj_js_nv_ihex(jsp, jo2p, "subpage_code", subpg);
1625*44704f69SBart Van Assche     return jo2p;
1626*44704f69SBart Van Assche }
1627*44704f69SBart Van Assche 
1628*44704f69SBart Van Assche 
1629*44704f69SBart Van Assche 
1630*44704f69SBart Van Assche /* DS made obsolete in spc4r03; TMC and ETC made obsolete in spc5r03. */
1631*44704f69SBart Van Assche static char *
get_pcb_str(int pcb,char * outp,int maxoutlen)1632*44704f69SBart Van Assche get_pcb_str(int pcb, char * outp, int maxoutlen)
1633*44704f69SBart Van Assche {
1634*44704f69SBart Van Assche     char buff[PCB_STR_LEN];
1635*44704f69SBart Van Assche     int n;
1636*44704f69SBart Van Assche 
1637*44704f69SBart Van Assche     n = sprintf(buff, "du=%d [ds=%d] tsd=%d [etc=%d] ", ((pcb & 0x80) ? 1 : 0),
1638*44704f69SBart Van Assche                 ((pcb & 0x40) ? 1 : 0), ((pcb & 0x20) ? 1 : 0),
1639*44704f69SBart Van Assche                 ((pcb & 0x10) ? 1 : 0));
1640*44704f69SBart Van Assche     if (pcb & 0x10)
1641*44704f69SBart Van Assche         n += sprintf(buff + n, "[tmc=%d] ", ((pcb & 0xc) >> 2));
1642*44704f69SBart Van Assche #if 1
1643*44704f69SBart Van Assche     n += sprintf(buff + n, "format+linking=%d  [0x%.2x]", pcb & 3,
1644*44704f69SBart Van Assche                  pcb);
1645*44704f69SBart Van Assche #else
1646*44704f69SBart Van Assche     if (pcb & 0x1)
1647*44704f69SBart Van Assche         n += sprintf(buff + n, "lbin=%d ", ((pcb & 0x2) >> 1));
1648*44704f69SBart Van Assche     n += sprintf(buff + n, "lp=%d  [0x%.2x]", pcb & 0x1, pcb);
1649*44704f69SBart Van Assche #endif
1650*44704f69SBart Van Assche     if (outp && (n < maxoutlen)) {
1651*44704f69SBart Van Assche         memcpy(outp, buff, n);
1652*44704f69SBart Van Assche         outp[n] = '\0';
1653*44704f69SBart Van Assche     } else if (outp && (maxoutlen > 0))
1654*44704f69SBart Van Assche         outp[0] = '\0';
1655*44704f69SBart Van Assche     return outp;
1656*44704f69SBart Van Assche }
1657*44704f69SBart Van Assche 
1658*44704f69SBart Van Assche static void
js_pcb(sgj_state * jsp,sgj_opaque_p jop,int pcb)1659*44704f69SBart Van Assche js_pcb(sgj_state * jsp, sgj_opaque_p jop, int pcb)
1660*44704f69SBart Van Assche {
1661*44704f69SBart Van Assche     sgj_opaque_p jo2p = sgj_snake_named_subobject_r(jsp, jop,
1662*44704f69SBart Van Assche                                                     "parameter_control_byte");
1663*44704f69SBart Van Assche 
1664*44704f69SBart Van Assche     sgj_js_nv_ihex_nex(jsp, jo2p, "du", (pcb & 0x80) ? 1 : 0, false,
1665*44704f69SBart Van Assche                        "Disable Update");
1666*44704f69SBart Van Assche     sgj_js_nv_ihex_nex(jsp, jo2p, "ds", (pcb & 0x40) ? 1 : 0, false,
1667*44704f69SBart Van Assche                        "Disable Save [obsolete]");
1668*44704f69SBart Van Assche     sgj_js_nv_ihex_nex(jsp, jo2p, "tsd", (pcb & 0x20) ? 1 : 0, false,
1669*44704f69SBart Van Assche                        "Target Save Disable");
1670*44704f69SBart Van Assche     sgj_js_nv_ihex_nex(jsp, jo2p, "etc", (pcb & 0x10) ? 1 : 0, false,
1671*44704f69SBart Van Assche                        "Enable Threshold Comparison [obsolete]");
1672*44704f69SBart Van Assche     sgj_js_nv_ihex_nex(jsp, jo2p, "tmc", (pcb & 0xc) >> 2, false,
1673*44704f69SBart Van Assche                        "Threshold Met Criteria [obsolete]");
1674*44704f69SBart Van Assche     sgj_js_nv_ihex_nex(jsp, jo2p, "format_and_linking", pcb & 0x3, false,
1675*44704f69SBart Van Assche                        NULL);
1676*44704f69SBart Van Assche }
1677*44704f69SBart Van Assche 
1678*44704f69SBart Van Assche /* SUPP_PAGES_LPAGE [0x0,0x0] <sp> */
1679*44704f69SBart Van Assche static bool
show_supported_pgs_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)1680*44704f69SBart Van Assche show_supported_pgs_page(const uint8_t * resp, int len,
1681*44704f69SBart Van Assche                         struct opts_t * op, sgj_opaque_p jop)
1682*44704f69SBart Van Assche {
1683*44704f69SBart Van Assche     int num, k;
1684*44704f69SBart Van Assche     const uint8_t * bp;
1685*44704f69SBart Van Assche     sgj_state * jsp = &op->json_st;
1686*44704f69SBart Van Assche     sgj_opaque_p jo2p, jo3p;
1687*44704f69SBart Van Assche     sgj_opaque_p jap = NULL;
1688*44704f69SBart Van Assche     char b[64];
1689*44704f69SBart Van Assche     static const char * slpgs = "Supported log pages";
1690*44704f69SBart Van Assche 
1691*44704f69SBart Van Assche     if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
1692*44704f69SBart Van Assche         sgj_pr_hr(jsp, "%s  [0x0]:\n", slpgs);  /* introduced in: SPC-2 */
1693*44704f69SBart Van Assche     num = len - 4;
1694*44704f69SBart Van Assche     bp = &resp[0] + 4;
1695*44704f69SBart Van Assche     if ((op->do_hex > 0) || op->do_raw) {
1696*44704f69SBart Van Assche         if (op->do_raw)
1697*44704f69SBart Van Assche             dStrRaw(resp, len);
1698*44704f69SBart Van Assche         else
1699*44704f69SBart Van Assche             hex2stdout(resp, len, op->dstrhex_no_ascii);
1700*44704f69SBart Van Assche         return true;
1701*44704f69SBart Van Assche     }
1702*44704f69SBart Van Assche     if (jsp->pr_as_json) {
1703*44704f69SBart Van Assche         jo2p = sg_log_js_hdr(jsp, jop, slpgs, resp);
1704*44704f69SBart Van Assche         jap = sgj_named_subarray_r(jsp, jo2p, "supported_pages_list");
1705*44704f69SBart Van Assche     }
1706*44704f69SBart Van Assche 
1707*44704f69SBart Van Assche     for (k = 0; k < num; ++k) {
1708*44704f69SBart Van Assche         int pg_code = bp[k] & 0x3f;
1709*44704f69SBart Van Assche         const struct log_elem * lep;
1710*44704f69SBart Van Assche 
1711*44704f69SBart Van Assche         snprintf(b, sizeof(b) - 1, "  0x%02x        ", pg_code);
1712*44704f69SBart Van Assche         lep = pg_subpg_pdt_search(pg_code, 0, op->dev_pdt, -1);
1713*44704f69SBart Van Assche         if (lep) {
1714*44704f69SBart Van Assche             if (op->do_brief > 1)
1715*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "    %s\n", lep->name);
1716*44704f69SBart Van Assche             else if (op->do_brief)
1717*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "%s%s\n", b, lep->name);
1718*44704f69SBart Van Assche             else
1719*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "%s%s [%s]\n", b, lep->name, lep->acron);
1720*44704f69SBart Van Assche         } else
1721*44704f69SBart Van Assche             sgj_pr_hr(jsp, "%s\n", b);
1722*44704f69SBart Van Assche         if (jsp->pr_as_json) {
1723*44704f69SBart Van Assche             jo3p = sgj_new_unattached_object_r(jsp);
1724*44704f69SBart Van Assche             sgj_js_nv_ihex(jsp, jo3p, "page_code", pg_code);
1725*44704f69SBart Van Assche             sgj_js_nv_s(jsp, jo3p, "name", lep ? lep->name : unknown_s);
1726*44704f69SBart Van Assche             sgj_js_nv_s(jsp, jo3p, "acronym", lep ? lep->acron : unknown_s);
1727*44704f69SBart Van Assche             sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
1728*44704f69SBart Van Assche         }
1729*44704f69SBart Van Assche     }
1730*44704f69SBart Van Assche     return true;
1731*44704f69SBart Van Assche }
1732*44704f69SBart Van Assche 
1733*44704f69SBart Van Assche /* SUPP_PAGES_LPAGE,SUPP_SPGS_SUBPG [0x0,0xff] <ssp> or all subpages of a
1734*44704f69SBart Van Assche  * given page code: [<pg_code>,0xff] where <pg_code> > 0 */
1735*44704f69SBart Van Assche static bool
show_supported_pgs_sub_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)1736*44704f69SBart Van Assche show_supported_pgs_sub_page(const uint8_t * resp, int len,
1737*44704f69SBart Van Assche                             struct opts_t * op, sgj_opaque_p jop)
1738*44704f69SBart Van Assche {
1739*44704f69SBart Van Assche     int num, k;
1740*44704f69SBart Van Assche     const uint8_t * bp;
1741*44704f69SBart Van Assche     const struct log_elem * lep = NULL;
1742*44704f69SBart Van Assche     sgj_state * jsp = &op->json_st;
1743*44704f69SBart Van Assche     sgj_opaque_p jo2p, jo3p;
1744*44704f69SBart Van Assche     sgj_opaque_p jap = NULL;
1745*44704f69SBart Van Assche     char b[64];
1746*44704f69SBart Van Assche     static const char * slpass = "Supported log pages and subpages";
1747*44704f69SBart Van Assche     static const char * sss = "Supported subpages";
1748*44704f69SBart Van Assche 
1749*44704f69SBart Van Assche     if (op->verbose || ((! op->do_raw) && (0 == op->do_hex))) {
1750*44704f69SBart Van Assche         if (op->pg_code > 0)
1751*44704f69SBart Van Assche             sgj_pr_hr(jsp, "%s  [0x%x, 0xff]:\n", sss, op->pg_code);
1752*44704f69SBart Van Assche         else
1753*44704f69SBart Van Assche             sgj_pr_hr(jsp, "%s  [0x0, 0xff]:\n", sss);
1754*44704f69SBart Van Assche     }
1755*44704f69SBart Van Assche     num = len - 4;
1756*44704f69SBart Van Assche     bp = &resp[0] + 4;
1757*44704f69SBart Van Assche     if ((op->do_hex > 0) || op->do_raw) {
1758*44704f69SBart Van Assche         if (op->do_raw)
1759*44704f69SBart Van Assche             dStrRaw(resp, len);
1760*44704f69SBart Van Assche         else
1761*44704f69SBart Van Assche             hex2stdout(resp, len, op->dstrhex_no_ascii);
1762*44704f69SBart Van Assche         return true;
1763*44704f69SBart Van Assche     }
1764*44704f69SBart Van Assche     if (jsp->pr_as_json) {
1765*44704f69SBart Van Assche         if (op->pg_code > 0) {
1766*44704f69SBart Van Assche             jo2p = sg_log_js_hdr(jsp, jop, sss, resp);
1767*44704f69SBart Van Assche             jap = sgj_named_subarray_r(jsp, jo2p,
1768*44704f69SBart Van Assche                                        "supported_subpage_descriptors");
1769*44704f69SBart Van Assche         } else {
1770*44704f69SBart Van Assche             jo2p = sg_log_js_hdr(jsp, jop, slpass, resp);
1771*44704f69SBart Van Assche             jap = sgj_named_subarray_r(jsp, jo2p,
1772*44704f69SBart Van Assche                                "supported_page_subpage_descriptors");
1773*44704f69SBart Van Assche         }
1774*44704f69SBart Van Assche     }
1775*44704f69SBart Van Assche 
1776*44704f69SBart Van Assche     for (k = 0; k < num; k += 2) {
1777*44704f69SBart Van Assche         bool pr_name = true;
1778*44704f69SBart Van Assche         int pg_code = bp[k];
1779*44704f69SBart Van Assche         int subpg_code = bp[k + 1];
1780*44704f69SBart Van Assche 
1781*44704f69SBart Van Assche         /* formerly ignored [pg, 0xff] when pg > 0, don't know why */
1782*44704f69SBart Van Assche         if (NOT_SPG_SUBPG == subpg_code)
1783*44704f69SBart Van Assche             snprintf(b, sizeof(b) - 1, "  0x%02x        ", pg_code);
1784*44704f69SBart Van Assche         else
1785*44704f69SBart Van Assche             snprintf(b, sizeof(b) - 1, "  0x%02x,0x%02x   ", pg_code,
1786*44704f69SBart Van Assche                      subpg_code);
1787*44704f69SBart Van Assche         if ((pg_code > 0) && (subpg_code == 0xff)) {
1788*44704f69SBart Van Assche             sgj_pr_hr(jsp, "%s\n", b);
1789*44704f69SBart Van Assche             pr_name = false;
1790*44704f69SBart Van Assche         } else {
1791*44704f69SBart Van Assche             lep = pg_subpg_pdt_search(pg_code, subpg_code, op->dev_pdt, -1);
1792*44704f69SBart Van Assche             if (lep) {
1793*44704f69SBart Van Assche                 if (op->do_brief > 1)
1794*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "    %s\n", lep->name);
1795*44704f69SBart Van Assche                 else if (op->do_brief)
1796*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "%s%s\n", b, lep->name);
1797*44704f69SBart Van Assche                 else
1798*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "%s%s [%s]\n", b, lep->name, lep->acron);
1799*44704f69SBart Van Assche             } else
1800*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "%s\n", b);
1801*44704f69SBart Van Assche         }
1802*44704f69SBart Van Assche         if (jsp->pr_as_json) {
1803*44704f69SBart Van Assche             jo3p = sgj_new_unattached_object_r(jsp);
1804*44704f69SBart Van Assche             sgj_js_nv_ihex(jsp, jo3p, "page_code", pg_code);
1805*44704f69SBart Van Assche             sgj_js_nv_ihex(jsp, jo3p, "subpage_code", subpg_code);
1806*44704f69SBart Van Assche             if (pr_name) {
1807*44704f69SBart Van Assche                 sgj_js_nv_s(jsp, jo3p, "name", lep ? lep->name : unknown_s);
1808*44704f69SBart Van Assche                 sgj_js_nv_s(jsp, jo3p, "acronym", lep ? lep->acron :
1809*44704f69SBart Van Assche                                                         unknown_s);
1810*44704f69SBart Van Assche             }
1811*44704f69SBart Van Assche             sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
1812*44704f69SBart Van Assche         }
1813*44704f69SBart Van Assche     }
1814*44704f69SBart Van Assche     return true;
1815*44704f69SBart Van Assche }
1816*44704f69SBart Van Assche 
1817*44704f69SBart Van Assche /* BUFF_OVER_UNDER_LPAGE [0x1] <bou>  introduced: SPC-2 */
1818*44704f69SBart Van Assche static bool
show_buffer_over_under_run_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)1819*44704f69SBart Van Assche show_buffer_over_under_run_page(const uint8_t * resp, int len,
1820*44704f69SBart Van Assche                                 struct opts_t * op, sgj_opaque_p jop)
1821*44704f69SBart Van Assche {
1822*44704f69SBart Van Assche     int num, pl, pc;
1823*44704f69SBart Van Assche     uint64_t count;
1824*44704f69SBart Van Assche     const uint8_t * bp;
1825*44704f69SBart Van Assche     const char * cp;
1826*44704f69SBart Van Assche     sgj_state * jsp = &op->json_st;
1827*44704f69SBart Van Assche     sgj_opaque_p jo2p;
1828*44704f69SBart Van Assche     sgj_opaque_p jo3p = NULL;
1829*44704f69SBart Van Assche     sgj_opaque_p jap = NULL;
1830*44704f69SBart Van Assche     char str[PCB_STR_LEN];
1831*44704f69SBart Van Assche     static const char * bourlp = "Buffer over-run/under-run log page";
1832*44704f69SBart Van Assche     static const char * orurc = "over_run_under_run_counter";
1833*44704f69SBart Van Assche 
1834*44704f69SBart Van Assche     if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
1835*44704f69SBart Van Assche         sgj_pr_hr(jsp, "%s  [0x1]\n", bourlp);
1836*44704f69SBart Van Assche     num = len - 4;
1837*44704f69SBart Van Assche     bp = &resp[0] + 4;
1838*44704f69SBart Van Assche     if (jsp->pr_as_json) {
1839*44704f69SBart Van Assche         jo2p = sg_log_js_hdr(jsp, jop, bourlp, resp);
1840*44704f69SBart Van Assche         jap = sgj_named_subarray_r(jsp, jo2p,
1841*44704f69SBart Van Assche                         "buffer_over_run_under_run_log_parameters");
1842*44704f69SBart Van Assche     }
1843*44704f69SBart Van Assche     while (num > 3) {
1844*44704f69SBart Van Assche         cp = NULL;
1845*44704f69SBart Van Assche         pl = bp[3] + 4;
1846*44704f69SBart Van Assche         count = (pl > 4) ? sg_get_unaligned_be(pl - 4, bp + 4) : 0;
1847*44704f69SBart Van Assche         pc = sg_get_unaligned_be16(bp + 0);
1848*44704f69SBart Van Assche         if (op->filter_given) {
1849*44704f69SBart Van Assche             if (pc != op->filter)
1850*44704f69SBart Van Assche                 goto skip;
1851*44704f69SBart Van Assche         }
1852*44704f69SBart Van Assche         if (op->do_raw) {
1853*44704f69SBart Van Assche             dStrRaw(bp, pl);
1854*44704f69SBart Van Assche             break;
1855*44704f69SBart Van Assche         } else if (op->do_hex) {
1856*44704f69SBart Van Assche             hex2stdout(bp, pl, op->dstrhex_no_ascii);
1857*44704f69SBart Van Assche             break;
1858*44704f69SBart Van Assche         }
1859*44704f69SBart Van Assche         if (jsp->pr_as_json) {
1860*44704f69SBart Van Assche             jo3p = sgj_new_unattached_object_r(jsp);
1861*44704f69SBart Van Assche             if (op->do_pcb)
1862*44704f69SBart Van Assche                 js_pcb(jsp, jo3p, bp[2]);
1863*44704f69SBart Van Assche         }
1864*44704f69SBart Van Assche 
1865*44704f69SBart Van Assche         switch (pc) {
1866*44704f69SBart Van Assche         case 0x0:
1867*44704f69SBart Van Assche             cp = "under-run";
1868*44704f69SBart Van Assche             break;
1869*44704f69SBart Van Assche         case 0x1:
1870*44704f69SBart Van Assche             cp = "over-run";
1871*44704f69SBart Van Assche             break;
1872*44704f69SBart Van Assche         case 0x2:
1873*44704f69SBart Van Assche             cp = "service delivery subsystem busy, under-run";
1874*44704f69SBart Van Assche             break;
1875*44704f69SBart Van Assche         case 0x3:
1876*44704f69SBart Van Assche             cp = "service delivery subsystem busy, over-run";
1877*44704f69SBart Van Assche             break;
1878*44704f69SBart Van Assche         case 0x4:
1879*44704f69SBart Van Assche             cp = "transfer too slow, under-run";
1880*44704f69SBart Van Assche             break;
1881*44704f69SBart Van Assche         case 0x5:
1882*44704f69SBart Van Assche             cp = "transfer too slow, over-run";
1883*44704f69SBart Van Assche             break;
1884*44704f69SBart Van Assche         case 0x20:
1885*44704f69SBart Van Assche             cp = "command, under-run";
1886*44704f69SBart Van Assche             break;
1887*44704f69SBart Van Assche         case 0x21:
1888*44704f69SBart Van Assche             cp = "command, over-run";
1889*44704f69SBart Van Assche             break;
1890*44704f69SBart Van Assche         case 0x22:
1891*44704f69SBart Van Assche             cp = "command, service delivery subsystem busy, under-run";
1892*44704f69SBart Van Assche             break;
1893*44704f69SBart Van Assche         case 0x23:
1894*44704f69SBart Van Assche             cp = "command, service delivery subsystem busy, over-run";
1895*44704f69SBart Van Assche             break;
1896*44704f69SBart Van Assche         case 0x24:
1897*44704f69SBart Van Assche             cp = "command, transfer too slow, under-run";
1898*44704f69SBart Van Assche             break;
1899*44704f69SBart Van Assche         case 0x25:
1900*44704f69SBart Van Assche             cp = "command, transfer too slow, over-run";
1901*44704f69SBart Van Assche             break;
1902*44704f69SBart Van Assche         case 0x40:
1903*44704f69SBart Van Assche             cp = "I_T nexus, under-run";
1904*44704f69SBart Van Assche             break;
1905*44704f69SBart Van Assche         case 0x41:
1906*44704f69SBart Van Assche             cp = "I_T nexus, over-run";
1907*44704f69SBart Van Assche             break;
1908*44704f69SBart Van Assche         case 0x42:
1909*44704f69SBart Van Assche             cp = "I_T nexus, service delivery subsystem busy, under-run";
1910*44704f69SBart Van Assche             break;
1911*44704f69SBart Van Assche         case 0x43:
1912*44704f69SBart Van Assche             cp = "I_T nexus, service delivery subsystem busy, over-run";
1913*44704f69SBart Van Assche             break;
1914*44704f69SBart Van Assche         case 0x44:
1915*44704f69SBart Van Assche             cp = "I_T nexus, transfer too slow, under-run";
1916*44704f69SBart Van Assche             break;
1917*44704f69SBart Van Assche         case 0x45:
1918*44704f69SBart Van Assche             cp = "I_T nexus, transfer too slow, over-run";
1919*44704f69SBart Van Assche             break;
1920*44704f69SBart Van Assche         case 0x80:
1921*44704f69SBart Van Assche             cp = "time, under-run";
1922*44704f69SBart Van Assche             break;
1923*44704f69SBart Van Assche         case 0x81:
1924*44704f69SBart Van Assche             cp = "time, over-run";
1925*44704f69SBart Van Assche             break;
1926*44704f69SBart Van Assche         case 0x82:
1927*44704f69SBart Van Assche             cp = "time, service delivery subsystem busy, under-run";
1928*44704f69SBart Van Assche             break;
1929*44704f69SBart Van Assche         case 0x83:
1930*44704f69SBart Van Assche             cp = "time, service delivery subsystem busy, over-run";
1931*44704f69SBart Van Assche             break;
1932*44704f69SBart Van Assche         case 0x84:
1933*44704f69SBart Van Assche             cp = "time, transfer too slow, under-run";
1934*44704f69SBart Van Assche             break;
1935*44704f69SBart Van Assche         case 0x85:
1936*44704f69SBart Van Assche             cp = "time, transfer too slow, over-run";
1937*44704f69SBart Van Assche             break;
1938*44704f69SBart Van Assche         default:
1939*44704f69SBart Van Assche             pr2serr("  undefined %s [0x%x], count = %" PRIu64 "\n",
1940*44704f69SBart Van Assche                     param_c, pc, count);
1941*44704f69SBart Van Assche             break;
1942*44704f69SBart Van Assche         }
1943*44704f69SBart Van Assche             sgj_js_nv_ihex(jsp, jo3p, param_c_sn, pc);
1944*44704f69SBart Van Assche         sgj_pr_hr(jsp, "  %s=0x%x\n", param_c, pc);
1945*44704f69SBart Van Assche         if (cp) {
1946*44704f69SBart Van Assche             sgj_pr_hr(jsp, "    %s = %" PRIu64 "\n", cp, count);
1947*44704f69SBart Van Assche             js_snakenv_ihexstr_nex(jsp, jo3p, param_c, pc, true,
1948*44704f69SBart Van Assche                                    NULL, cp, NULL);
1949*44704f69SBart Van Assche             sgj_js_nv_ihex(jsp, jo3p, orurc, count);
1950*44704f69SBart Van Assche         } else
1951*44704f69SBart Van Assche             sgj_pr_hr(jsp, "    counter = %" PRIu64 "\n", count);
1952*44704f69SBart Van Assche 
1953*44704f69SBart Van Assche         if (op->do_pcb)
1954*44704f69SBart Van Assche             sgj_pr_hr(jsp, "        <%s>\n", get_pcb_str(bp[2],
1955*44704f69SBart Van Assche                       str, sizeof(str)));
1956*44704f69SBart Van Assche         if (jsp->pr_as_json)
1957*44704f69SBart Van Assche             sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
1958*44704f69SBart Van Assche         if (op->filter_given)
1959*44704f69SBart Van Assche             break;
1960*44704f69SBart Van Assche skip:
1961*44704f69SBart Van Assche         num -= pl;
1962*44704f69SBart Van Assche         bp += pl;
1963*44704f69SBart Van Assche     }
1964*44704f69SBart Van Assche     return true;
1965*44704f69SBart Van Assche }
1966*44704f69SBart Van Assche 
1967*44704f69SBart Van Assche /* WRITE_ERR_LPAGE; READ_ERR_LPAGE; READ_REV_ERR_LPAGE; VERIFY_ERR_LPAGE */
1968*44704f69SBart Van Assche /* [0x2, 0x3, 0x4, 0x5] <we, re, rre, ve>  introduced: SPC-3 */
1969*44704f69SBart Van Assche static bool
show_error_counter_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)1970*44704f69SBart Van Assche show_error_counter_page(const uint8_t * resp, int len,
1971*44704f69SBart Van Assche                         struct opts_t * op, sgj_opaque_p jop)
1972*44704f69SBart Van Assche {
1973*44704f69SBart Van Assche     bool skip_out = false;
1974*44704f69SBart Van Assche     bool evsm_output = false;
1975*44704f69SBart Van Assche     int n, num, pl, pc, pg_code;
1976*44704f69SBart Van Assche     uint64_t val;
1977*44704f69SBart Van Assche     const uint8_t * bp;
1978*44704f69SBart Van Assche     const char * pg_cp = NULL;
1979*44704f69SBart Van Assche     const char * par_cp = NULL;
1980*44704f69SBart Van Assche     sgj_state * jsp = &op->json_st;
1981*44704f69SBart Van Assche     sgj_opaque_p jo2p;
1982*44704f69SBart Van Assche     sgj_opaque_p jo3p = NULL;
1983*44704f69SBart Van Assche     sgj_opaque_p jap = NULL;
1984*44704f69SBart Van Assche     char str[PCB_STR_LEN];
1985*44704f69SBart Van Assche     char b[128] SG_C_CPP_ZERO_INIT;
1986*44704f69SBart Van Assche     char d[128];
1987*44704f69SBart Van Assche     char e[64];
1988*44704f69SBart Van Assche     static const char * wec = "Write error counter";
1989*44704f69SBart Van Assche     static const char * rec = "Read error counter";
1990*44704f69SBart Van Assche     static const char * rrec = "Read reverse error counter";
1991*44704f69SBart Van Assche     static const char * vec = "Verify error counter";
1992*44704f69SBart Van Assche 
1993*44704f69SBart Van Assche     pg_code = resp[0] & 0x3f;
1994*44704f69SBart Van Assche     switch(pg_code) {
1995*44704f69SBart Van Assche     case WRITE_ERR_LPAGE:
1996*44704f69SBart Van Assche         pg_cp = wec;
1997*44704f69SBart Van Assche         break;
1998*44704f69SBart Van Assche     case READ_ERR_LPAGE:
1999*44704f69SBart Van Assche         pg_cp = rec;
2000*44704f69SBart Van Assche         break;
2001*44704f69SBart Van Assche     case READ_REV_ERR_LPAGE:
2002*44704f69SBart Van Assche         pg_cp = rrec;
2003*44704f69SBart Van Assche         break;
2004*44704f69SBart Van Assche     case VERIFY_ERR_LPAGE:
2005*44704f69SBart Van Assche         pg_cp = vec;
2006*44704f69SBart Van Assche         break;
2007*44704f69SBart Van Assche     default:
2008*44704f69SBart Van Assche         pr2serr("expecting error counter page, got page = 0x%x\n",
2009*44704f69SBart Van Assche                 pg_code);
2010*44704f69SBart Van Assche         return false;
2011*44704f69SBart Van Assche     }
2012*44704f69SBart Van Assche     if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
2013*44704f69SBart Van Assche         sgj_pr_hr(jsp, "%s log page  [0x%x]\n", pg_cp, pg_code);
2014*44704f69SBart Van Assche     if (jsp->pr_as_json) {
2015*44704f69SBart Van Assche         n = strlen(pg_cp);
2016*44704f69SBart Van Assche         memcpy(b, pg_cp, n);
2017*44704f69SBart Van Assche         memcpy(b + n, " log", 4);
2018*44704f69SBart Van Assche         n = strlen(b);
2019*44704f69SBart Van Assche         memcpy(b + n, " page", 5);
2020*44704f69SBart Van Assche         jo2p = sg_log_js_hdr(jsp, jop, b, resp);
2021*44704f69SBart Van Assche         memcpy(b + n, " parameters", 11);
2022*44704f69SBart Van Assche         sgj_convert_to_snake_name(b, d, sizeof(d) - 1);
2023*44704f69SBart Van Assche         jap = sgj_named_subarray_r(jsp, jo2p, d);
2024*44704f69SBart Van Assche     }
2025*44704f69SBart Van Assche     num = len - 4;
2026*44704f69SBart Van Assche     bp = &resp[0] + 4;
2027*44704f69SBart Van Assche     while (num > 3) {
2028*44704f69SBart Van Assche         pc = sg_get_unaligned_be16(bp + 0);
2029*44704f69SBart Van Assche         pl = bp[3] + 4;
2030*44704f69SBart Van Assche         if (op->filter_given) {
2031*44704f69SBart Van Assche             if (pc != op->filter)
2032*44704f69SBart Van Assche                 goto skip;
2033*44704f69SBart Van Assche         }
2034*44704f69SBart Van Assche         if (op->do_raw) {
2035*44704f69SBart Van Assche             dStrRaw(bp, pl);
2036*44704f69SBart Van Assche             break;
2037*44704f69SBart Van Assche         } else if (op->do_hex) {
2038*44704f69SBart Van Assche             hex2stdout(bp, pl, op->dstrhex_no_ascii);
2039*44704f69SBart Van Assche             break;
2040*44704f69SBart Van Assche         }
2041*44704f69SBart Van Assche         if (jsp->pr_as_json) {
2042*44704f69SBart Van Assche             jo3p = sgj_new_unattached_object_r(jsp);
2043*44704f69SBart Van Assche             if (op->do_pcb)
2044*44704f69SBart Van Assche                 js_pcb(jsp, jo3p, bp[2]);
2045*44704f69SBart Van Assche         }
2046*44704f69SBart Van Assche 
2047*44704f69SBart Van Assche         par_cp = NULL;
2048*44704f69SBart Van Assche         switch (pc) {
2049*44704f69SBart Van Assche         case 0:
2050*44704f69SBart Van Assche             par_cp = "Errors corrected without substantial delay";
2051*44704f69SBart Van Assche             break;
2052*44704f69SBart Van Assche         case 1:
2053*44704f69SBart Van Assche             par_cp = "Errors corrected with possible delays";
2054*44704f69SBart Van Assche             break;
2055*44704f69SBart Van Assche         case 2:
2056*44704f69SBart Van Assche             par_cp = "Total rewrites or rereads";
2057*44704f69SBart Van Assche             break;
2058*44704f69SBart Van Assche         case 3:
2059*44704f69SBart Van Assche             par_cp = "Total errors corrected";
2060*44704f69SBart Van Assche             break;
2061*44704f69SBart Van Assche         case 4:
2062*44704f69SBart Van Assche             par_cp = "Total times correction algorithm processed";
2063*44704f69SBart Van Assche             break;
2064*44704f69SBart Van Assche         case 5:
2065*44704f69SBart Van Assche             par_cp = "Total bytes processed";
2066*44704f69SBart Van Assche             break;
2067*44704f69SBart Van Assche         case 6:
2068*44704f69SBart Van Assche             par_cp = "Total uncorrected errors";
2069*44704f69SBart Van Assche             break;
2070*44704f69SBart Van Assche         default:
2071*44704f69SBart Van Assche             if (op->exclude_vendor) {
2072*44704f69SBart Van Assche                 skip_out = true;
2073*44704f69SBart Van Assche                 if ((op->verbose > 0) && (0 == op->do_brief) &&
2074*44704f69SBart Van Assche                     (! evsm_output)) {
2075*44704f69SBart Van Assche                     evsm_output = true;
2076*44704f69SBart Van Assche                     pr2serr("  %s parameter(s) being ignored\n", vend_spec);
2077*44704f69SBart Van Assche                 }
2078*44704f69SBart Van Assche             } else {
2079*44704f69SBart Van Assche                 if (0x8009 == pc)
2080*44704f69SBart Van Assche                     par_cp = "Track following errors [Hitachi]";
2081*44704f69SBart Van Assche                 else if (0x8015 == pc)
2082*44704f69SBart Van Assche                     par_cp = "Positioning errors [Hitachi]";
2083*44704f69SBart Van Assche                 else {
2084*44704f69SBart Van Assche                     snprintf(e, sizeof(e), "Reserved or %s [0x%x]", vend_spec,
2085*44704f69SBart Van Assche                              pc);
2086*44704f69SBart Van Assche                     par_cp = e;
2087*44704f69SBart Van Assche                 }
2088*44704f69SBart Van Assche             }
2089*44704f69SBart Van Assche             break;
2090*44704f69SBart Van Assche         }
2091*44704f69SBart Van Assche 
2092*44704f69SBart Van Assche         if (skip_out)
2093*44704f69SBart Van Assche             skip_out = false;
2094*44704f69SBart Van Assche         else if (par_cp) {
2095*44704f69SBart Van Assche             val = sg_get_unaligned_be(pl - 4, bp + 4);
2096*44704f69SBart Van Assche             if (val > ((uint64_t)1 << 40))
2097*44704f69SBart Van Assche                 snprintf(d, sizeof(d), "%" PRIu64 " [%" PRIu64 " TB]",
2098*44704f69SBart Van Assche                          val, (val / (1000UL * 1000 * 1000 * 1000)));
2099*44704f69SBart Van Assche             else if (val > ((uint64_t)1 << 30))
2100*44704f69SBart Van Assche                 snprintf(d, sizeof(d), "%" PRIu64 " [%" PRIu64 " GB]",
2101*44704f69SBart Van Assche                          val, (val / (1000UL * 1000 * 1000)));
2102*44704f69SBart Van Assche             else
2103*44704f69SBart Van Assche                 snprintf(d, sizeof(d), "%" PRIu64, val);
2104*44704f69SBart Van Assche             sgj_pr_hr(jsp, "  %s = %s\n", par_cp, d);
2105*44704f69SBart Van Assche             if (jsp->pr_as_json) {
2106*44704f69SBart Van Assche                 js_snakenv_ihexstr_nex(jsp, jo3p, param_c, pc, true,
2107*44704f69SBart Van Assche                                        NULL, par_cp, NULL);
2108*44704f69SBart Van Assche                 sgj_convert_to_snake_name(pg_cp, e, sizeof(e) - 1);
2109*44704f69SBart Van Assche                 n = strlen(e);
2110*44704f69SBart Van Assche                 memcpy(e + n, "_counter", 9); /* take trailing null */
2111*44704f69SBart Van Assche                 sgj_js_nv_ihexstr(jsp, jo3p, e, val, as_s_s, d);
2112*44704f69SBart Van Assche             }
2113*44704f69SBart Van Assche         }
2114*44704f69SBart Van Assche         if (op->do_pcb)
2115*44704f69SBart Van Assche             sgj_pr_hr(jsp, "        <%s>\n", get_pcb_str(bp[2],
2116*44704f69SBart Van Assche                       str, sizeof(str)));
2117*44704f69SBart Van Assche         if (jsp->pr_as_json)
2118*44704f69SBart Van Assche             sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
2119*44704f69SBart Van Assche         if (op->filter_given)
2120*44704f69SBart Van Assche             break;
2121*44704f69SBart Van Assche skip:
2122*44704f69SBart Van Assche         num -= pl;
2123*44704f69SBart Van Assche         bp += pl;
2124*44704f69SBart Van Assche     }
2125*44704f69SBart Van Assche     return true;
2126*44704f69SBart Van Assche }
2127*44704f69SBart Van Assche 
2128*44704f69SBart Van Assche /* NON_MEDIUM_LPAGE [0x6] <nm>  introduced: SPC-2 */
2129*44704f69SBart Van Assche static bool
show_non_medium_error_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)2130*44704f69SBart Van Assche show_non_medium_error_page(const uint8_t * resp, int len,
2131*44704f69SBart Van Assche                            struct opts_t * op, sgj_opaque_p jop)
2132*44704f69SBart Van Assche {
2133*44704f69SBart Van Assche     bool skip_out = false;
2134*44704f69SBart Van Assche     bool evsm_output = false;
2135*44704f69SBart Van Assche     int num, pl, pc;
2136*44704f69SBart Van Assche     uint64_t count;
2137*44704f69SBart Van Assche     const uint8_t * bp;
2138*44704f69SBart Van Assche     sgj_state * jsp = &op->json_st;
2139*44704f69SBart Van Assche     sgj_opaque_p jo2p;
2140*44704f69SBart Van Assche     sgj_opaque_p jo3p = NULL;
2141*44704f69SBart Van Assche     sgj_opaque_p jap = NULL;
2142*44704f69SBart Van Assche     char str[PCB_STR_LEN];
2143*44704f69SBart Van Assche     char b[128] SG_C_CPP_ZERO_INIT;
2144*44704f69SBart Van Assche     static const char * nmelp = "Non-medium error log page";
2145*44704f69SBart Van Assche     static const char * nmec = "Non-medium error count";
2146*44704f69SBart Van Assche 
2147*44704f69SBart Van Assche     if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
2148*44704f69SBart Van Assche         sgj_pr_hr(jsp, "%s  [0x6]\n", nmelp);
2149*44704f69SBart Van Assche     num = len - 4;
2150*44704f69SBart Van Assche     bp = &resp[0] + 4;
2151*44704f69SBart Van Assche     if (jsp->pr_as_json) {
2152*44704f69SBart Van Assche         jo2p = sg_log_js_hdr(jsp, jop, nmelp, resp);
2153*44704f69SBart Van Assche         jap = sgj_named_subarray_r(jsp, jo2p,
2154*44704f69SBart Van Assche                         "non_medium_error_log_parameters");
2155*44704f69SBart Van Assche     }
2156*44704f69SBart Van Assche     while (num > 3) {
2157*44704f69SBart Van Assche         pc = sg_get_unaligned_be16(bp + 0);
2158*44704f69SBart Van Assche         pl = bp[3] + 4;
2159*44704f69SBart Van Assche         if (op->filter_given) {
2160*44704f69SBart Van Assche             if (pc != op->filter)
2161*44704f69SBart Van Assche                 goto skip;
2162*44704f69SBart Van Assche         }
2163*44704f69SBart Van Assche         if (op->do_raw) {
2164*44704f69SBart Van Assche             dStrRaw(bp, pl);
2165*44704f69SBart Van Assche             break;
2166*44704f69SBart Van Assche         } else if (op->do_hex) {
2167*44704f69SBart Van Assche             hex2stdout(bp, pl, op->dstrhex_no_ascii);
2168*44704f69SBart Van Assche             break;
2169*44704f69SBart Van Assche         }
2170*44704f69SBart Van Assche         if (jsp->pr_as_json) {
2171*44704f69SBart Van Assche             jo3p = sgj_new_unattached_object_r(jsp);
2172*44704f69SBart Van Assche             if (op->do_pcb)
2173*44704f69SBart Van Assche                 js_pcb(jsp, jo3p, bp[2]);
2174*44704f69SBart Van Assche         }
2175*44704f69SBart Van Assche 
2176*44704f69SBart Van Assche         switch (pc) {
2177*44704f69SBart Van Assche         case 0:
2178*44704f69SBart Van Assche             snprintf(b, sizeof(b), "%s", nmec);
2179*44704f69SBart Van Assche             break;
2180*44704f69SBart Van Assche         default:
2181*44704f69SBart Van Assche             if (pc <= 0x7fff)
2182*44704f69SBart Van Assche                 snprintf(b, sizeof(b), "  Reserved [0x%x]", pc);
2183*44704f69SBart Van Assche             else {
2184*44704f69SBart Van Assche                 if (op->exclude_vendor) {
2185*44704f69SBart Van Assche                     skip_out = true;
2186*44704f69SBart Van Assche                     if ((op->verbose > 0) && (0 == op->do_brief) &&
2187*44704f69SBart Van Assche                         (! evsm_output)) {
2188*44704f69SBart Van Assche                         evsm_output = true;
2189*44704f69SBart Van Assche                         pr2serr("  %s parameter(s) being ignored\n",
2190*44704f69SBart Van Assche                                 vend_spec);
2191*44704f69SBart Van Assche                     }
2192*44704f69SBart Van Assche                 } else
2193*44704f69SBart Van Assche                     snprintf(b, sizeof(b), "%s [0x%x]", vend_spec, pc);
2194*44704f69SBart Van Assche             }
2195*44704f69SBart Van Assche             break;
2196*44704f69SBart Van Assche         }
2197*44704f69SBart Van Assche         if (skip_out)
2198*44704f69SBart Van Assche             skip_out = false;
2199*44704f69SBart Van Assche         else {
2200*44704f69SBart Van Assche             count = sg_get_unaligned_be(pl - 4, bp + 4);
2201*44704f69SBart Van Assche             sgj_pr_hr(jsp, "  %s = %" PRIu64 "\n", b, count);
2202*44704f69SBart Van Assche             js_snakenv_ihexstr_nex(jsp, jo3p, param_c, pc, true,
2203*44704f69SBart Van Assche                                    NULL, b, NULL);
2204*44704f69SBart Van Assche             js_snakenv_ihexstr_nex(jsp, jo3p, nmec, count, true, NULL, NULL,
2205*44704f69SBart Van Assche                                    NULL);
2206*44704f69SBart Van Assche         }
2207*44704f69SBart Van Assche         if (op->do_pcb)
2208*44704f69SBart Van Assche             sgj_pr_hr(jsp, "        <%s>\n", get_pcb_str(bp[2],
2209*44704f69SBart Van Assche                       str, sizeof(str)));
2210*44704f69SBart Van Assche         if (jsp->pr_as_json)
2211*44704f69SBart Van Assche             sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
2212*44704f69SBart Van Assche         if (op->filter_given)
2213*44704f69SBart Van Assche             break;
2214*44704f69SBart Van Assche skip:
2215*44704f69SBart Van Assche         num -= pl;
2216*44704f69SBart Van Assche         bp += pl;
2217*44704f69SBart Van Assche     }
2218*44704f69SBart Van Assche     return true;
2219*44704f69SBart Van Assche }
2220*44704f69SBart Van Assche 
2221*44704f69SBart Van Assche /* PCT_LPAGE [0x1a] <pct>  introduced: SPC-4 */
2222*44704f69SBart Van Assche static bool
show_power_condition_transitions_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)2223*44704f69SBart Van Assche show_power_condition_transitions_page(const uint8_t * resp, int len,
2224*44704f69SBart Van Assche                                       struct opts_t * op, sgj_opaque_p jop)
2225*44704f69SBart Van Assche {
2226*44704f69SBart Van Assche     bool partial;
2227*44704f69SBart Van Assche     int num, pl, pc;
2228*44704f69SBart Van Assche     uint64_t count;
2229*44704f69SBart Van Assche     const uint8_t * bp;
2230*44704f69SBart Van Assche     const char * cp;
2231*44704f69SBart Van Assche     sgj_state * jsp = &op->json_st;
2232*44704f69SBart Van Assche     sgj_opaque_p jo2p;
2233*44704f69SBart Van Assche     sgj_opaque_p jo3p = NULL;
2234*44704f69SBart Van Assche     sgj_opaque_p jap = NULL;
2235*44704f69SBart Van Assche     char str[PCB_STR_LEN];
2236*44704f69SBart Van Assche     char b[128];
2237*44704f69SBart Van Assche     char bb[64];
2238*44704f69SBart Van Assche     static const char * pctlp = "Power condition transitions log page";
2239*44704f69SBart Van Assche     static const char * att = "Accumulated transitions to";
2240*44704f69SBart Van Assche 
2241*44704f69SBart Van Assche     if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
2242*44704f69SBart Van Assche         sgj_pr_hr(jsp, "%s  [0x1a]\n", pctlp);
2243*44704f69SBart Van Assche     num = len - 4;
2244*44704f69SBart Van Assche     bp = &resp[0] + 4;
2245*44704f69SBart Van Assche     if (jsp->pr_as_json) {
2246*44704f69SBart Van Assche         jo2p = sg_log_js_hdr(jsp, jop, pctlp, resp);
2247*44704f69SBart Van Assche         jap = sgj_named_subarray_r(jsp, jo2p,
2248*44704f69SBart Van Assche                         "power_condition_transition_log_parameters");
2249*44704f69SBart Van Assche     }
2250*44704f69SBart Van Assche 
2251*44704f69SBart Van Assche     while (num > 3) {
2252*44704f69SBart Van Assche         pc = sg_get_unaligned_be16(bp + 0);
2253*44704f69SBart Van Assche         pl = bp[3] + 4;
2254*44704f69SBart Van Assche         if (op->filter_given) {
2255*44704f69SBart Van Assche             if (pc != op->filter)
2256*44704f69SBart Van Assche                 goto skip;
2257*44704f69SBart Van Assche         }
2258*44704f69SBart Van Assche         if (op->do_raw) {
2259*44704f69SBart Van Assche             dStrRaw(bp, pl);
2260*44704f69SBart Van Assche             break;
2261*44704f69SBart Van Assche         } else if (op->do_hex) {
2262*44704f69SBart Van Assche             hex2stdout(bp, pl, op->dstrhex_no_ascii);
2263*44704f69SBart Van Assche             break;
2264*44704f69SBart Van Assche         }
2265*44704f69SBart Van Assche         if (jsp->pr_as_json) {
2266*44704f69SBart Van Assche             jo3p = sgj_new_unattached_object_r(jsp);
2267*44704f69SBart Van Assche             if (op->do_pcb)
2268*44704f69SBart Van Assche                 js_pcb(jsp, jo3p, bp[2]);
2269*44704f69SBart Van Assche         }
2270*44704f69SBart Van Assche 
2271*44704f69SBart Van Assche         cp = NULL;
2272*44704f69SBart Van Assche         partial = true;
2273*44704f69SBart Van Assche         switch (pc) {
2274*44704f69SBart Van Assche         case 1:
2275*44704f69SBart Van Assche             cp = "active";
2276*44704f69SBart Van Assche             break;
2277*44704f69SBart Van Assche         case 2:
2278*44704f69SBart Van Assche             cp = "idle_a";
2279*44704f69SBart Van Assche             break;
2280*44704f69SBart Van Assche         case 3:
2281*44704f69SBart Van Assche             cp = "idle_b";
2282*44704f69SBart Van Assche             break;
2283*44704f69SBart Van Assche         case 4:
2284*44704f69SBart Van Assche             cp = "idle_c";
2285*44704f69SBart Van Assche             break;
2286*44704f69SBart Van Assche         case 8:
2287*44704f69SBart Van Assche             cp = "standby_z";
2288*44704f69SBart Van Assche             break;
2289*44704f69SBart Van Assche         case 9:
2290*44704f69SBart Van Assche             cp = "standby_y";
2291*44704f69SBart Van Assche             break;
2292*44704f69SBart Van Assche         default:
2293*44704f69SBart Van Assche             snprintf(bb, sizeof(bb), "Reserved [0x%x]", pc);
2294*44704f69SBart Van Assche             cp = bb;
2295*44704f69SBart Van Assche             partial = false;
2296*44704f69SBart Van Assche             break;
2297*44704f69SBart Van Assche         }
2298*44704f69SBart Van Assche         if (partial) {
2299*44704f69SBart Van Assche             snprintf(b, sizeof(b), "%s %s", att, cp);
2300*44704f69SBart Van Assche             cp = b;
2301*44704f69SBart Van Assche         }
2302*44704f69SBart Van Assche         count = sg_get_unaligned_be(pl - 4, bp + 4);
2303*44704f69SBart Van Assche         sgj_pr_hr(jsp, "  %s = %" PRIu64 "\n", cp, count);
2304*44704f69SBart Van Assche         if (op->do_pcb)
2305*44704f69SBart Van Assche             sgj_pr_hr(jsp, "        <%s>\n", get_pcb_str(bp[2],
2306*44704f69SBart Van Assche                       str, sizeof(str)));
2307*44704f69SBart Van Assche         if (jsp->pr_as_json) {
2308*44704f69SBart Van Assche             js_snakenv_ihexstr_nex(jsp, jo3p, cp, count, true,
2309*44704f69SBart Van Assche                                    NULL, NULL, "saturating counter");
2310*44704f69SBart Van Assche             sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
2311*44704f69SBart Van Assche         }
2312*44704f69SBart Van Assche         if (op->filter_given)
2313*44704f69SBart Van Assche             break;
2314*44704f69SBart Van Assche skip:
2315*44704f69SBart Van Assche         num -= pl;
2316*44704f69SBart Van Assche         bp += pl;
2317*44704f69SBart Van Assche     }
2318*44704f69SBart Van Assche     return true;
2319*44704f69SBart Van Assche }
2320*44704f69SBart Van Assche 
2321*44704f69SBart Van Assche static char *
temperature_str(int8_t t,bool reporting,char * b,int blen)2322*44704f69SBart Van Assche temperature_str(int8_t t, bool reporting, char * b, int blen)
2323*44704f69SBart Van Assche {
2324*44704f69SBart Van Assche     if (-128 == t) {
2325*44704f69SBart Van Assche         if (reporting)
2326*44704f69SBart Van Assche             snprintf(b, blen, "%s", not_avail);
2327*44704f69SBart Van Assche         else
2328*44704f69SBart Van Assche             snprintf(b, blen, "no limit");
2329*44704f69SBart Van Assche     } else
2330*44704f69SBart Van Assche         snprintf(b, blen, "%d C", t);
2331*44704f69SBart Van Assche     return b;
2332*44704f69SBart Van Assche }
2333*44704f69SBart Van Assche 
2334*44704f69SBart Van Assche static char *
humidity_str(uint8_t h,bool reporting,char * b,int blen)2335*44704f69SBart Van Assche humidity_str(uint8_t h, bool reporting, char * b, int blen)
2336*44704f69SBart Van Assche {
2337*44704f69SBart Van Assche     if (255 == h) {
2338*44704f69SBart Van Assche         if (reporting)
2339*44704f69SBart Van Assche             snprintf(b, blen, "%s", not_avail);
2340*44704f69SBart Van Assche         else
2341*44704f69SBart Van Assche             snprintf(b, blen, "no limit");
2342*44704f69SBart Van Assche     } else if (h <= 100)
2343*44704f69SBart Van Assche         snprintf(b, blen, "%u %%", h);
2344*44704f69SBart Van Assche     else
2345*44704f69SBart Van Assche         snprintf(b, blen, "%s value [%u]", rsv_s, h);
2346*44704f69SBart Van Assche     return b;
2347*44704f69SBart Van Assche }
2348*44704f69SBart Van Assche 
2349*44704f69SBart Van Assche /* ENV_REPORTING_SUBPG [0xd,0x1] <env> introduced: SPC-5 (rev 02). "mounted"
2350*44704f69SBart Van Assche  * changed to "other" in spc5r11 */
2351*44704f69SBart Van Assche static bool
show_environmental_reporting_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)2352*44704f69SBart Van Assche show_environmental_reporting_page(const uint8_t * resp, int len,
2353*44704f69SBart Van Assche                                   struct opts_t * op, sgj_opaque_p jop)
2354*44704f69SBart Van Assche {
2355*44704f69SBart Van Assche     int num, pl, pc, blen;
2356*44704f69SBart Van Assche     bool other_valid;
2357*44704f69SBart Van Assche     const uint8_t * bp;
2358*44704f69SBart Van Assche     sgj_state * jsp = &op->json_st;
2359*44704f69SBart Van Assche     sgj_opaque_p jo2p;
2360*44704f69SBart Van Assche     sgj_opaque_p jo3p = NULL;
2361*44704f69SBart Van Assche     sgj_opaque_p jap = NULL;
2362*44704f69SBart Van Assche     char str[PCB_STR_LEN];
2363*44704f69SBart Van Assche     char b[32];
2364*44704f69SBart Van Assche     static const char * erlp = "Environmental reporting log page";
2365*44704f69SBart Van Assche     static const char * temp = "Temperature";
2366*44704f69SBart Van Assche     static const char * lmaxt = "Lifetime maximum temperature";
2367*44704f69SBart Van Assche     static const char * lmint = "Lifetime minimum temperature";
2368*44704f69SBart Van Assche     static const char * maxtspo = "Maximum temperature since power on";
2369*44704f69SBart Van Assche     static const char * mintspo = "Minimum temperature since power on";
2370*44704f69SBart Van Assche     static const char * maxot = "Maximum other temperature";
2371*44704f69SBart Van Assche     static const char * minot = "Minimum other temperature";
2372*44704f69SBart Van Assche     static const char * relhum = "Relative humidity";
2373*44704f69SBart Van Assche     static const char * lmaxrh = "Lifetime maximum relative humidity";
2374*44704f69SBart Van Assche     static const char * lminrh = "Lifetime minimum relative humidity";
2375*44704f69SBart Van Assche     static const char * maxrhspo = "Maximum relative humidity since power on";
2376*44704f69SBart Van Assche     static const char * minrhspo = "Minimum relative humidity since power on";
2377*44704f69SBart Van Assche     static const char * maxorh = "Maximum other relative humidity";
2378*44704f69SBart Van Assche     static const char * minorh = "Minimum other relative humidity";
2379*44704f69SBart Van Assche 
2380*44704f69SBart Van Assche     blen = sizeof(b);
2381*44704f69SBart Van Assche     if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
2382*44704f69SBart Van Assche         sgj_pr_hr(jsp, "%s  [0xd,0x1]\n", erlp);
2383*44704f69SBart Van Assche     if (jsp->pr_as_json) {
2384*44704f69SBart Van Assche         jo2p = sg_log_js_hdr(jsp, jop, erlp, resp);
2385*44704f69SBart Van Assche         jap = sgj_named_subarray_r(jsp, jo2p,
2386*44704f69SBart Van Assche                                    "environmental_reporting_log_parameters");
2387*44704f69SBart Van Assche     }
2388*44704f69SBart Van Assche     num = len - 4;
2389*44704f69SBart Van Assche     bp = &resp[0] + 4;
2390*44704f69SBart Van Assche     while (num > 3) {
2391*44704f69SBart Van Assche         pc = sg_get_unaligned_be16(bp + 0);
2392*44704f69SBart Van Assche         pl = bp[3] + 4;
2393*44704f69SBart Van Assche         if (op->filter_given) {
2394*44704f69SBart Van Assche             if (pc != op->filter)
2395*44704f69SBart Van Assche                 goto skip;
2396*44704f69SBart Van Assche         }
2397*44704f69SBart Van Assche         if (op->do_raw) {
2398*44704f69SBart Van Assche             dStrRaw(bp, pl);
2399*44704f69SBart Van Assche             break;
2400*44704f69SBart Van Assche         } else if (op->do_hex) {
2401*44704f69SBart Van Assche             hex2stdout(bp, pl, op->dstrhex_no_ascii);
2402*44704f69SBart Van Assche             break;
2403*44704f69SBart Van Assche         }
2404*44704f69SBart Van Assche         if (jsp->pr_as_json) {
2405*44704f69SBart Van Assche             jo3p = sgj_new_unattached_object_r(jsp);
2406*44704f69SBart Van Assche             if (op->do_pcb)
2407*44704f69SBart Van Assche                 js_pcb(jsp, jo3p, bp[2]);
2408*44704f69SBart Van Assche         }
2409*44704f69SBart Van Assche         other_valid = !!(bp[4] & 1);
2410*44704f69SBart Van Assche         if (pc < 0x100) {
2411*44704f69SBart Van Assche             if (pl < 12)  {
2412*44704f69SBart Van Assche                 pr2serr("  <<expect parameter 0x%x to be at least 12 bytes "
2413*44704f69SBart Van Assche                         "long, got %d, skip>>\n", pc, pl);
2414*44704f69SBart Van Assche                 goto inner;
2415*44704f69SBart Van Assche             }
2416*44704f69SBart Van Assche             sgj_pr_hr(jsp, "  %s=0x%x\n", param_c, pc);
2417*44704f69SBart Van Assche             sgj_js_nv_ihex(jsp, jo3p, param_c_sn, pc);
2418*44704f69SBart Van Assche             sgj_pr_hr(jsp, "    OTV=%d\n", (int)other_valid);
2419*44704f69SBart Van Assche             sgj_js_nv_ihex_nex(jsp, jo3p, "otv",  (int)other_valid,
2420*44704f69SBart Van Assche                                false, "Other Temperature Valid");
2421*44704f69SBart Van Assche 
2422*44704f69SBart Van Assche             temperature_str(bp[5], true, b, blen);
2423*44704f69SBart Van Assche             sgj_pr_hr(jsp, "    %s: %s\n", temp, b);
2424*44704f69SBart Van Assche             js_snakenv_ihexstr_nex(jsp, jo3p, temp, bp[5], false,
2425*44704f69SBart Van Assche                                    NULL, b, "current [Celsius]");
2426*44704f69SBart Van Assche             temperature_str(bp[6], true, b, blen);
2427*44704f69SBart Van Assche             sgj_pr_hr(jsp, "    %s: %s\n", lmaxt, b);
2428*44704f69SBart Van Assche             js_snakenv_ihexstr_nex(jsp, jo3p, lmaxt, bp[6], false,
2429*44704f69SBart Van Assche                                    NULL, b, NULL);
2430*44704f69SBart Van Assche             temperature_str(bp[7], true, b, blen);
2431*44704f69SBart Van Assche             sgj_pr_hr(jsp, "    %s: %s\n", lmint, b);
2432*44704f69SBart Van Assche             js_snakenv_ihexstr_nex(jsp, jo3p, lmint, bp[7], false,
2433*44704f69SBart Van Assche                                    NULL, b, NULL);
2434*44704f69SBart Van Assche             temperature_str(bp[8], true, b, blen);
2435*44704f69SBart Van Assche             sgj_pr_hr(jsp, "    %s: %s\n", maxtspo, b);
2436*44704f69SBart Van Assche             js_snakenv_ihexstr_nex(jsp, jo3p, maxtspo, bp[8], false,
2437*44704f69SBart Van Assche                                    NULL, b, NULL);
2438*44704f69SBart Van Assche             temperature_str(bp[9], true, b, blen);
2439*44704f69SBart Van Assche             sgj_pr_hr(jsp, "    %s: %s\n", mintspo, b);
2440*44704f69SBart Van Assche             js_snakenv_ihexstr_nex(jsp, jo3p, mintspo, bp[9], false,
2441*44704f69SBart Van Assche                                    NULL, b, NULL);
2442*44704f69SBart Van Assche             if (other_valid) {
2443*44704f69SBart Van Assche                 temperature_str(bp[10], true, b, blen);
2444*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "    %s: %s\n", maxot, b);
2445*44704f69SBart Van Assche                 js_snakenv_ihexstr_nex(jsp, jo3p, maxot, bp[10], false,
2446*44704f69SBart Van Assche                                        NULL, b, NULL);
2447*44704f69SBart Van Assche                 temperature_str(bp[11], true, b, blen);
2448*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "    %s: %s\n", minot, b);
2449*44704f69SBart Van Assche                 js_snakenv_ihexstr_nex(jsp, jo3p, minot, bp[11], false,
2450*44704f69SBart Van Assche                                        NULL, b, NULL);
2451*44704f69SBart Van Assche             }
2452*44704f69SBart Van Assche         } else if (pc < 0x200) {
2453*44704f69SBart Van Assche             if (pl < 12)  {
2454*44704f69SBart Van Assche                 pr2serr("  <<expect parameter 0x%x to be at least 12 bytes "
2455*44704f69SBart Van Assche                         "long, got %d, skip>>\n", pc, pl);
2456*44704f69SBart Van Assche                 goto inner;
2457*44704f69SBart Van Assche             }
2458*44704f69SBart Van Assche             sgj_pr_hr(jsp, "  %s=0x%x\n", param_c, pc);
2459*44704f69SBart Van Assche             sgj_js_nv_ihex(jsp, jo3p, param_c_sn, pc);
2460*44704f69SBart Van Assche             sgj_pr_hr(jsp, "    ORHV=%d\n", (int)other_valid);
2461*44704f69SBart Van Assche             sgj_js_nv_ihex_nex(jsp, jo3p, "orhv",  (int)other_valid,
2462*44704f69SBart Van Assche                                false, "Other Relative Humidity Valid");
2463*44704f69SBart Van Assche 
2464*44704f69SBart Van Assche             humidity_str(bp[5], true, b, blen);
2465*44704f69SBart Van Assche             sgj_pr_hr(jsp, "    %s: %s\n", relhum, b);
2466*44704f69SBart Van Assche             js_snakenv_ihexstr_nex(jsp, jo3p, relhum, bp[5], false,
2467*44704f69SBart Van Assche                                    NULL, b, NULL);
2468*44704f69SBart Van Assche             humidity_str(bp[6], true, b, blen);
2469*44704f69SBart Van Assche             sgj_pr_hr(jsp, "    %s: %s\n", lmaxrh, b);
2470*44704f69SBart Van Assche             js_snakenv_ihexstr_nex(jsp, jo3p, lmaxrh, bp[6], false,
2471*44704f69SBart Van Assche                                    NULL, b, NULL);
2472*44704f69SBart Van Assche             humidity_str(bp[7], true, b, blen);
2473*44704f69SBart Van Assche             sgj_pr_hr(jsp, "    %s: %s\n", lminrh, b);
2474*44704f69SBart Van Assche             js_snakenv_ihexstr_nex(jsp, jo3p, lminrh, bp[7], false,
2475*44704f69SBart Van Assche                                    NULL, b, NULL);
2476*44704f69SBart Van Assche             humidity_str(bp[8], true, b, blen);
2477*44704f69SBart Van Assche             sgj_pr_hr(jsp, "    %s: %s\n", maxrhspo, b);
2478*44704f69SBart Van Assche             js_snakenv_ihexstr_nex(jsp, jo3p, maxrhspo, bp[8], false,
2479*44704f69SBart Van Assche                                    NULL, b, NULL);
2480*44704f69SBart Van Assche             humidity_str(bp[9], true, b, blen);
2481*44704f69SBart Van Assche             sgj_pr_hr(jsp, "    %s: %s\n", minrhspo, b);
2482*44704f69SBart Van Assche             js_snakenv_ihexstr_nex(jsp, jo3p, minrhspo, bp[9], false,
2483*44704f69SBart Van Assche                                    NULL, b, NULL);
2484*44704f69SBart Van Assche             if (other_valid) {
2485*44704f69SBart Van Assche                 humidity_str(bp[10], true, b, blen);
2486*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "    %s: %s\n", maxorh, b);
2487*44704f69SBart Van Assche                 js_snakenv_ihexstr_nex(jsp, jo3p, maxorh, bp[10], false,
2488*44704f69SBart Van Assche                                        NULL, b, NULL);
2489*44704f69SBart Van Assche                 humidity_str(bp[11], true, b, blen);
2490*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "    %s: %s\n", minorh, b);
2491*44704f69SBart Van Assche                 js_snakenv_ihexstr_nex(jsp, jo3p, minorh, bp[11], false,
2492*44704f69SBart Van Assche                                        NULL, b, NULL);
2493*44704f69SBart Van Assche             }
2494*44704f69SBart Van Assche         } else
2495*44704f69SBart Van Assche             sgj_pr_hr(jsp, "  <<unexpected %s 0x%x\n", param_c, pc);
2496*44704f69SBart Van Assche         if (op->do_pcb)
2497*44704f69SBart Van Assche             sgj_pr_hr(jsp, "        <%s>\n", get_pcb_str(bp[2], str,
2498*44704f69SBart Van Assche                       sizeof(str)));
2499*44704f69SBart Van Assche inner:
2500*44704f69SBart Van Assche         if (jsp->pr_as_json)
2501*44704f69SBart Van Assche             sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
2502*44704f69SBart Van Assche         if (op->filter_given)
2503*44704f69SBart Van Assche             break;
2504*44704f69SBart Van Assche skip:
2505*44704f69SBart Van Assche         num -= pl;
2506*44704f69SBart Van Assche         bp += pl;
2507*44704f69SBart Van Assche     }
2508*44704f69SBart Van Assche     return true;
2509*44704f69SBart Van Assche }
2510*44704f69SBart Van Assche 
2511*44704f69SBart Van Assche /* ENV_LIMITS_SUBPG [0xd,0x2] <enl> introduced: SPC-5 (rev 02) */
2512*44704f69SBart Van Assche static bool
show_environmental_limits_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)2513*44704f69SBart Van Assche show_environmental_limits_page(const uint8_t * resp, int len,
2514*44704f69SBart Van Assche                                struct opts_t * op, sgj_opaque_p jop)
2515*44704f69SBart Van Assche {
2516*44704f69SBart Van Assche     int num, pl, pc, blen;
2517*44704f69SBart Van Assche     const uint8_t * bp;
2518*44704f69SBart Van Assche     sgj_state * jsp = &op->json_st;
2519*44704f69SBart Van Assche     sgj_opaque_p jo2p;
2520*44704f69SBart Van Assche     sgj_opaque_p jo3p = NULL;
2521*44704f69SBart Van Assche     sgj_opaque_p jap = NULL;
2522*44704f69SBart Van Assche     char str[PCB_STR_LEN];
2523*44704f69SBart Van Assche     char b[32];
2524*44704f69SBart Van Assche     static const char * ellp = "Environmental limits log page";
2525*44704f69SBart Van Assche     static const char * hctlt = "High critical temperature limit trigger";
2526*44704f69SBart Van Assche     static const char * hctlr = "High critical temperature limit reset";
2527*44704f69SBart Van Assche     static const char * lctlr = "High critical temperature limit reset";
2528*44704f69SBart Van Assche     static const char * lctlt = "High critical temperature limit trigger";
2529*44704f69SBart Van Assche     static const char * hotlt = "High operating temperature limit trigger";
2530*44704f69SBart Van Assche     static const char * hotlr = "High operating temperature limit reset";
2531*44704f69SBart Van Assche     static const char * lotlr = "High operating temperature limit reset";
2532*44704f69SBart Van Assche     static const char * lotlt = "High operating temperature limit trigger";
2533*44704f69SBart Van Assche     static const char * hcrhlt =
2534*44704f69SBart Van Assche                 "High critical relative humidity limit trigger";
2535*44704f69SBart Van Assche     static const char * hcrhlr =
2536*44704f69SBart Van Assche                 "High critical relative humidity limit reset";
2537*44704f69SBart Van Assche     static const char * lcrhlr =
2538*44704f69SBart Van Assche                 "High critical relative humidity limit reset";
2539*44704f69SBart Van Assche     static const char * lcrhlt =
2540*44704f69SBart Van Assche                 "High critical relative humidity limit trigger";
2541*44704f69SBart Van Assche     static const char * horhlt =
2542*44704f69SBart Van Assche                 "High operating relative humidity limit trigger";
2543*44704f69SBart Van Assche     static const char * horhlr =
2544*44704f69SBart Van Assche                 "High operating relative humidity limit reset";
2545*44704f69SBart Van Assche     static const char * lorhlr =
2546*44704f69SBart Van Assche                 "High operating relative humidity limit reset";
2547*44704f69SBart Van Assche     static const char * lorhlt =
2548*44704f69SBart Van Assche                 "High operating relative humidity limit trigger";
2549*44704f69SBart Van Assche 
2550*44704f69SBart Van Assche     blen = sizeof(b);
2551*44704f69SBart Van Assche     if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
2552*44704f69SBart Van Assche         sgj_pr_hr(jsp, "%s  [0xd,0x2]\n", ellp);
2553*44704f69SBart Van Assche     if (jsp->pr_as_json) {
2554*44704f69SBart Van Assche         jo2p = sg_log_js_hdr(jsp, jop, ellp, resp);
2555*44704f69SBart Van Assche         jap = sgj_named_subarray_r(jsp, jo2p,
2556*44704f69SBart Van Assche                                    "environmental_limits_log_parameters");
2557*44704f69SBart Van Assche     }
2558*44704f69SBart Van Assche     num = len - 4;
2559*44704f69SBart Van Assche     bp = &resp[0] + 4;
2560*44704f69SBart Van Assche     while (num > 3) {
2561*44704f69SBart Van Assche         pc = sg_get_unaligned_be16(bp + 0);
2562*44704f69SBart Van Assche         pl = bp[3] + 4;
2563*44704f69SBart Van Assche         if (op->filter_given) {
2564*44704f69SBart Van Assche             if (pc != op->filter)
2565*44704f69SBart Van Assche                 goto skip;
2566*44704f69SBart Van Assche         }
2567*44704f69SBart Van Assche         if (op->do_raw) {
2568*44704f69SBart Van Assche             dStrRaw(bp, pl);
2569*44704f69SBart Van Assche             break;
2570*44704f69SBart Van Assche         } else if (op->do_hex) {
2571*44704f69SBart Van Assche             hex2stdout(bp, pl, op->dstrhex_no_ascii);
2572*44704f69SBart Van Assche             break;
2573*44704f69SBart Van Assche         }
2574*44704f69SBart Van Assche         if (jsp->pr_as_json) {
2575*44704f69SBart Van Assche             jo3p = sgj_new_unattached_object_r(jsp);
2576*44704f69SBart Van Assche             if (op->do_pcb)
2577*44704f69SBart Van Assche                 js_pcb(jsp, jo3p, bp[2]);
2578*44704f69SBart Van Assche         }
2579*44704f69SBart Van Assche         if (pc < 0x100) {
2580*44704f69SBart Van Assche             if (pl < 12)  {
2581*44704f69SBart Van Assche                 pr2serr("  <<expect parameter 0x%x to be at least 12 bytes "
2582*44704f69SBart Van Assche                         "long, got %d, skip>>\n", pc, pl);
2583*44704f69SBart Van Assche                 goto inner;
2584*44704f69SBart Van Assche             }
2585*44704f69SBart Van Assche             sgj_pr_hr(jsp, "  %s=0x%x\n", param_c, pc);
2586*44704f69SBart Van Assche             sgj_js_nv_ihex(jsp, jo3p, param_c_sn, pc);
2587*44704f69SBart Van Assche 
2588*44704f69SBart Van Assche             temperature_str(bp[4], true, b, blen);
2589*44704f69SBart Van Assche             sgj_pr_hr(jsp, "    %s: %s\n", hctlt, b);
2590*44704f69SBart Van Assche             js_snakenv_ihexstr_nex(jsp, jo3p, hctlt, bp[4], false,
2591*44704f69SBart Van Assche                                    NULL, b, "[Celsius]");
2592*44704f69SBart Van Assche             temperature_str(bp[5], true, b, blen);
2593*44704f69SBart Van Assche             sgj_pr_hr(jsp, "    %s: %s\n", hctlr, b);
2594*44704f69SBart Van Assche             js_snakenv_ihexstr_nex(jsp, jo3p, hctlr, bp[5], false,
2595*44704f69SBart Van Assche                                    NULL, b, NULL);
2596*44704f69SBart Van Assche             temperature_str(bp[6], true, b, blen);
2597*44704f69SBart Van Assche             sgj_pr_hr(jsp, "    %s: %s\n", lctlr, b);
2598*44704f69SBart Van Assche             js_snakenv_ihexstr_nex(jsp, jo3p, lctlr, bp[6], false,
2599*44704f69SBart Van Assche                                    NULL, b, NULL);
2600*44704f69SBart Van Assche             temperature_str(bp[7], true, b, blen);
2601*44704f69SBart Van Assche             sgj_pr_hr(jsp, "    %s: %s\n", lctlt, b);
2602*44704f69SBart Van Assche             js_snakenv_ihexstr_nex(jsp, jo3p, lctlt, bp[7], false,
2603*44704f69SBart Van Assche                                    NULL, b, NULL);
2604*44704f69SBart Van Assche             temperature_str(bp[8], true, b, blen);
2605*44704f69SBart Van Assche             sgj_pr_hr(jsp, "    %s: %s\n", hotlt, b);
2606*44704f69SBart Van Assche             js_snakenv_ihexstr_nex(jsp, jo3p, hotlt, bp[8], false,
2607*44704f69SBart Van Assche                                    NULL, b, NULL);
2608*44704f69SBart Van Assche             temperature_str(bp[9], true, b, blen);
2609*44704f69SBart Van Assche             sgj_pr_hr(jsp, "    %s: %s\n", hotlr, b);
2610*44704f69SBart Van Assche             js_snakenv_ihexstr_nex(jsp, jo3p, hotlr, bp[9], false,
2611*44704f69SBart Van Assche                                    NULL, b, NULL);
2612*44704f69SBart Van Assche             temperature_str(bp[10], true, b, blen);
2613*44704f69SBart Van Assche             sgj_pr_hr(jsp, "    %s: %s\n", lotlr, b);
2614*44704f69SBart Van Assche             js_snakenv_ihexstr_nex(jsp, jo3p, lotlr, bp[10], false,
2615*44704f69SBart Van Assche                                    NULL, b, NULL);
2616*44704f69SBart Van Assche             temperature_str(bp[11], true, b, blen);
2617*44704f69SBart Van Assche             sgj_pr_hr(jsp, "    %s: %s\n", lotlt, b);
2618*44704f69SBart Van Assche             js_snakenv_ihexstr_nex(jsp, jo3p, lotlt, bp[11], false,
2619*44704f69SBart Van Assche                                    NULL, b, NULL);
2620*44704f69SBart Van Assche         } else if (pc < 0x200) {
2621*44704f69SBart Van Assche             if (pl < 12)  {
2622*44704f69SBart Van Assche                 pr2serr("  <<expect parameter 0x%x to be at least 12 bytes "
2623*44704f69SBart Van Assche                         "long, got %d, skip>>\n", pc, pl);
2624*44704f69SBart Van Assche                 goto inner;
2625*44704f69SBart Van Assche             }
2626*44704f69SBart Van Assche             sgj_pr_hr(jsp, "  %s=0x%x\n", param_c, pc);
2627*44704f69SBart Van Assche             sgj_js_nv_ihex(jsp, jo3p, param_c_sn, pc);
2628*44704f69SBart Van Assche 
2629*44704f69SBart Van Assche             humidity_str(bp[4], true, b, blen);
2630*44704f69SBart Van Assche             sgj_pr_hr(jsp, "    %s: %s\n", hcrhlt, b);
2631*44704f69SBart Van Assche             js_snakenv_ihexstr_nex(jsp, jo3p, hcrhlt, bp[4], false,
2632*44704f69SBart Van Assche                                    NULL, b, "[percentage]");
2633*44704f69SBart Van Assche             humidity_str(bp[5], true, b, blen);
2634*44704f69SBart Van Assche             sgj_pr_hr(jsp, "    %s: %s\n", hcrhlr, b);
2635*44704f69SBart Van Assche             js_snakenv_ihexstr_nex(jsp, jo3p, hcrhlr, bp[5], false,
2636*44704f69SBart Van Assche                                    NULL, b, NULL);
2637*44704f69SBart Van Assche             humidity_str(bp[6], true, b, blen);
2638*44704f69SBart Van Assche             sgj_pr_hr(jsp, "    %s: %s\n", lcrhlr, b);
2639*44704f69SBart Van Assche             js_snakenv_ihexstr_nex(jsp, jo3p, lcrhlr, bp[6], false,
2640*44704f69SBart Van Assche                                    NULL, b, NULL);
2641*44704f69SBart Van Assche             humidity_str(bp[7], true, b, blen);
2642*44704f69SBart Van Assche             sgj_pr_hr(jsp, "    %s: %s\n", lcrhlt, b);
2643*44704f69SBart Van Assche             js_snakenv_ihexstr_nex(jsp, jo3p, lcrhlt, bp[7], false,
2644*44704f69SBart Van Assche                                    NULL, b, NULL);
2645*44704f69SBart Van Assche             humidity_str(bp[8], true, b, blen);
2646*44704f69SBart Van Assche             sgj_pr_hr(jsp, "    %s: %s\n", horhlt, b);
2647*44704f69SBart Van Assche             js_snakenv_ihexstr_nex(jsp, jo3p, horhlt, bp[8], false,
2648*44704f69SBart Van Assche                                    NULL, b, NULL);
2649*44704f69SBart Van Assche             humidity_str(bp[9], true, b, blen);
2650*44704f69SBart Van Assche             sgj_pr_hr(jsp, "    %s: %s\n", horhlr, b);
2651*44704f69SBart Van Assche             js_snakenv_ihexstr_nex(jsp, jo3p, horhlr, bp[9], false,
2652*44704f69SBart Van Assche                                    NULL, b, NULL);
2653*44704f69SBart Van Assche             humidity_str(bp[10], true, b, blen);
2654*44704f69SBart Van Assche             sgj_pr_hr(jsp, "    %s: %s\n", lorhlr, b);
2655*44704f69SBart Van Assche             js_snakenv_ihexstr_nex(jsp, jo3p, lorhlr, bp[10], false,
2656*44704f69SBart Van Assche                                    NULL, b, NULL);
2657*44704f69SBart Van Assche             humidity_str(bp[11], true, b, blen);
2658*44704f69SBart Van Assche             sgj_pr_hr(jsp, "    %s: %s\n", lorhlt, b);
2659*44704f69SBart Van Assche             js_snakenv_ihexstr_nex(jsp, jo3p, lorhlt, bp[11], false,
2660*44704f69SBart Van Assche                                    NULL, b, NULL);
2661*44704f69SBart Van Assche         } else
2662*44704f69SBart Van Assche              sgj_pr_hr(jsp, "  <<unexpected %s 0x%x\n", param_c, pc);
2663*44704f69SBart Van Assche         if (op->do_pcb)
2664*44704f69SBart Van Assche             sgj_pr_hr(jsp, "        <%s>\n", get_pcb_str(bp[2],
2665*44704f69SBart Van Assche                       str, sizeof(str)));
2666*44704f69SBart Van Assche inner:
2667*44704f69SBart Van Assche         if (jsp->pr_as_json)
2668*44704f69SBart Van Assche             sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
2669*44704f69SBart Van Assche         if (op->filter_given)
2670*44704f69SBart Van Assche             break;
2671*44704f69SBart Van Assche skip:
2672*44704f69SBart Van Assche         num -= pl;
2673*44704f69SBart Van Assche         bp += pl;
2674*44704f69SBart Van Assche     }
2675*44704f69SBart Van Assche     return true;
2676*44704f69SBart Van Assche }
2677*44704f69SBart Van Assche 
2678*44704f69SBart Van Assche /* CMD_DUR_LIMITS_SUBPG [0x19,0x21] <cdl>
2679*44704f69SBart Van Assche  * introduced: SPC-6 rev 1, significantly changed rev 6 */
2680*44704f69SBart Van Assche static bool
show_cmd_dur_limits_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)2681*44704f69SBart Van Assche show_cmd_dur_limits_page(const uint8_t * resp, int len,
2682*44704f69SBart Van Assche                          struct opts_t * op, sgj_opaque_p jop)
2683*44704f69SBart Van Assche {
2684*44704f69SBart Van Assche     int num, pl, pc;
2685*44704f69SBart Van Assche     uint32_t count, noitmc_v, noatmc_v, noitatmc_v, noc_v;
2686*44704f69SBart Van Assche     const uint8_t * bp;
2687*44704f69SBart Van Assche     const char * cp;
2688*44704f69SBart Van Assche     const char * thp;
2689*44704f69SBart Van Assche     sgj_state * jsp = &op->json_st;
2690*44704f69SBart Van Assche     sgj_opaque_p jo2p;
2691*44704f69SBart Van Assche     sgj_opaque_p jo3p = NULL;
2692*44704f69SBart Van Assche     sgj_opaque_p jap = NULL;
2693*44704f69SBart Van Assche     char str[PCB_STR_LEN];
2694*44704f69SBart Van Assche     char b[144];
2695*44704f69SBart Van Assche     static const char * cdllp = "Command duration limits statistics log page";
2696*44704f69SBart Van Assche     static const char * t2cdld = "T2 command duration limit descriptor";
2697*44704f69SBart Van Assche     static const char * cdlt2amp = "CDL T2A mode page";
2698*44704f69SBart Van Assche     static const char * cdlt2bmp = "CDL T2B mode page";
2699*44704f69SBart Van Assche     static const char * first_7[] = {"First", "Second", "Third", "Fourth",
2700*44704f69SBart Van Assche                                      "Fifth", "Sixth", "Seventh"};
2701*44704f69SBart Van Assche     static const char * noitmc = "Number of inactive target miss commands";
2702*44704f69SBart Van Assche     static const char * noatmc = "Number of active target miss commands";
2703*44704f69SBart Van Assche     static const char * noitatmc =
2704*44704f69SBart Van Assche         "Number of inactive target and active target miss commands";
2705*44704f69SBart Van Assche     static const char * noc = "Number of commands";
2706*44704f69SBart Van Assche 
2707*44704f69SBart Van Assche     if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
2708*44704f69SBart Van Assche         sgj_pr_hr(jsp, "%s  [0x19,0x21]\n", cdllp);
2709*44704f69SBart Van Assche     num = len - 4;
2710*44704f69SBart Van Assche     bp = &resp[0] + 4;
2711*44704f69SBart Van Assche     if (jsp->pr_as_json) {
2712*44704f69SBart Van Assche         jo2p = sg_log_js_hdr(jsp, jop, cdllp, resp);
2713*44704f69SBart Van Assche         jap = sgj_named_subarray_r(jsp, jo2p,
2714*44704f69SBart Van Assche                         "command_duration_limits_statistcs_log_parameters");
2715*44704f69SBart Van Assche     }
2716*44704f69SBart Van Assche 
2717*44704f69SBart Van Assche     while (num > 3) {
2718*44704f69SBart Van Assche         pc = sg_get_unaligned_be16(bp + 0);
2719*44704f69SBart Van Assche         pl = bp[3] + 4;         /* parameter length */
2720*44704f69SBart Van Assche         if (op->filter_given) {
2721*44704f69SBart Van Assche             if (pc != op->filter)
2722*44704f69SBart Van Assche                 goto skip;
2723*44704f69SBart Van Assche         }
2724*44704f69SBart Van Assche         if (op->do_raw) {
2725*44704f69SBart Van Assche             dStrRaw(bp, pl);
2726*44704f69SBart Van Assche             break;
2727*44704f69SBart Van Assche         } else if (op->do_hex) {
2728*44704f69SBart Van Assche             hex2stdout(bp, pl, op->dstrhex_no_ascii);
2729*44704f69SBart Van Assche             break;
2730*44704f69SBart Van Assche         }
2731*44704f69SBart Van Assche         if (jsp->pr_as_json) {
2732*44704f69SBart Van Assche             jo3p = sgj_new_unattached_object_r(jsp);
2733*44704f69SBart Van Assche             if (op->do_pcb)
2734*44704f69SBart Van Assche                 js_pcb(jsp, jo3p, bp[2]);
2735*44704f69SBart Van Assche         }
2736*44704f69SBart Van Assche 
2737*44704f69SBart Van Assche         switch (pc) {
2738*44704f69SBart Van Assche         case 0x1:
2739*44704f69SBart Van Assche             /* spc6r06: table 349 name "Number of READ commands" seems to
2740*44704f69SBart Van Assche              * be wrong. Use what surrounding text and table 347 suggest */
2741*44704f69SBart Van Assche             cp = "Achievable latency target";
2742*44704f69SBart Van Assche             count =  sg_get_unaligned_be32(bp + 4);
2743*44704f69SBart Van Assche             sgj_pr_hr(jsp, "  %s = %" PRIu32 "\n", cp, count);
2744*44704f69SBart Van Assche             if (jsp->pr_as_json) {
2745*44704f69SBart Van Assche                 sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, cp);
2746*44704f69SBart Van Assche                 js_snakenv_ihexstr_nex(jsp, jop, cp, count, true, NULL, NULL,
2747*44704f69SBart Van Assche                                        "unit: microsecond");
2748*44704f69SBart Van Assche             }
2749*44704f69SBart Van Assche             break;
2750*44704f69SBart Van Assche         case 0x11:
2751*44704f69SBart Van Assche         case 0x12:
2752*44704f69SBart Van Assche         case 0x13:
2753*44704f69SBart Van Assche         case 0x14:
2754*44704f69SBart Van Assche         case 0x15:
2755*44704f69SBart Van Assche         case 0x16:
2756*44704f69SBart Van Assche         case 0x17:
2757*44704f69SBart Van Assche             sgj_pr_hr(jsp, "  %s code 0x%x restricted\n", param_c, pc);
2758*44704f69SBart Van Assche             if (jsp->pr_as_json)
2759*44704f69SBart Van Assche                 sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, rstrict_s);
2760*44704f69SBart Van Assche             break;
2761*44704f69SBart Van Assche         case 0x21:
2762*44704f69SBart Van Assche         case 0x22:
2763*44704f69SBart Van Assche         case 0x23:
2764*44704f69SBart Van Assche         case 0x24:
2765*44704f69SBart Van Assche         case 0x25:
2766*44704f69SBart Van Assche         case 0x26:
2767*44704f69SBart Van Assche         case 0x27:
2768*44704f69SBart Van Assche             thp = first_7[pc - 0x21];
2769*44704f69SBart Van Assche             sgj_pr_hr(jsp, "  %s %s for %s [pc=0x%x]:\n", thp, t2cdld,
2770*44704f69SBart Van Assche                       cdlt2amp, pc);
2771*44704f69SBart Van Assche             noitmc_v = sg_get_unaligned_be32(bp + 4);
2772*44704f69SBart Van Assche             sgj_pr_hr(jsp, "    %s = %u\n", noitmc, noitmc_v);
2773*44704f69SBart Van Assche             noatmc_v = sg_get_unaligned_be32(bp + 8);
2774*44704f69SBart Van Assche             sgj_pr_hr(jsp, "    %s = %u\n", noatmc, noatmc_v);
2775*44704f69SBart Van Assche             noitatmc_v = sg_get_unaligned_be32(bp + 12);
2776*44704f69SBart Van Assche             sgj_pr_hr(jsp, "    %s = %u\n", noitatmc, noitatmc_v);
2777*44704f69SBart Van Assche             noc_v = sg_get_unaligned_be32(bp + 16);
2778*44704f69SBart Van Assche             sgj_pr_hr(jsp, "    %s = %u\n", noc, noc_v);
2779*44704f69SBart Van Assche             if (jsp->pr_as_json) {
2780*44704f69SBart Van Assche                 snprintf(b, sizeof(b), "%s %s for %s", thp, t2cdld, cdlt2amp);
2781*44704f69SBart Van Assche                 sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, b);
2782*44704f69SBart Van Assche 
2783*44704f69SBart Van Assche                 js_snakenv_ihexstr_nex(jsp, jop, noitmc, noitmc_v, true, NULL,
2784*44704f69SBart Van Assche                                        NULL, NULL);
2785*44704f69SBart Van Assche                 js_snakenv_ihexstr_nex(jsp, jop, noatmc, noatmc_v, true, NULL,
2786*44704f69SBart Van Assche                                        NULL, NULL);
2787*44704f69SBart Van Assche                 js_snakenv_ihexstr_nex(jsp, jop, noitatmc, noitatmc_v, true,
2788*44704f69SBart Van Assche                                        NULL, NULL, NULL);
2789*44704f69SBart Van Assche                 js_snakenv_ihexstr_nex(jsp, jop, noc, noc_v, true, NULL,
2790*44704f69SBart Van Assche                                        NULL, NULL);
2791*44704f69SBart Van Assche             }
2792*44704f69SBart Van Assche             break;
2793*44704f69SBart Van Assche         case 0x31:
2794*44704f69SBart Van Assche         case 0x32:
2795*44704f69SBart Van Assche         case 0x33:
2796*44704f69SBart Van Assche         case 0x34:
2797*44704f69SBart Van Assche         case 0x35:
2798*44704f69SBart Van Assche         case 0x36:
2799*44704f69SBart Van Assche         case 0x37:
2800*44704f69SBart Van Assche             sgj_pr_hr(jsp, "  %s 0x%x restricted\n", param_c, pc);
2801*44704f69SBart Van Assche             if (jsp->pr_as_json)
2802*44704f69SBart Van Assche                 sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, rstrict_s);
2803*44704f69SBart Van Assche             break;
2804*44704f69SBart Van Assche         case 0x41:
2805*44704f69SBart Van Assche         case 0x42:
2806*44704f69SBart Van Assche         case 0x43:
2807*44704f69SBart Van Assche         case 0x44:
2808*44704f69SBart Van Assche         case 0x45:
2809*44704f69SBart Van Assche         case 0x46:
2810*44704f69SBart Van Assche         case 0x47:
2811*44704f69SBart Van Assche             /* This short form introduced in draft spc6r06 */
2812*44704f69SBart Van Assche             thp = first_7[pc - 0x41];
2813*44704f69SBart Van Assche             sgj_pr_hr(jsp, "  %s %s for %s [pc=0x%x]:\n", thp, t2cdld,
2814*44704f69SBart Van Assche                       cdlt2bmp, pc);
2815*44704f69SBart Van Assche             noitmc_v = sg_get_unaligned_be32(bp + 4);
2816*44704f69SBart Van Assche             sgj_pr_hr(jsp, "    %s = %u\n", noitmc, noitmc_v);
2817*44704f69SBart Van Assche             noatmc_v = sg_get_unaligned_be32(bp + 8);
2818*44704f69SBart Van Assche             sgj_pr_hr(jsp, "    %s = %u\n", noatmc, noatmc_v);
2819*44704f69SBart Van Assche             noitatmc_v = sg_get_unaligned_be32(bp + 12);
2820*44704f69SBart Van Assche             sgj_pr_hr(jsp, "    %s = %u\n", noitatmc, noitatmc_v);
2821*44704f69SBart Van Assche             noc_v = sg_get_unaligned_be32(bp + 16);
2822*44704f69SBart Van Assche             sgj_pr_hr(jsp, "    %s = %u\n", noc, noc_v);
2823*44704f69SBart Van Assche             if (jsp->pr_as_json) {
2824*44704f69SBart Van Assche                 snprintf(b, sizeof(b), "%s %s for %s", thp, t2cdld, cdlt2amp);
2825*44704f69SBart Van Assche                 sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, b);
2826*44704f69SBart Van Assche 
2827*44704f69SBart Van Assche                 js_snakenv_ihexstr_nex(jsp, jop, noitmc, noitmc_v, true, NULL,
2828*44704f69SBart Van Assche                                        NULL, NULL);
2829*44704f69SBart Van Assche                 js_snakenv_ihexstr_nex(jsp, jop, noatmc, noatmc_v, true, NULL,
2830*44704f69SBart Van Assche                                        NULL, NULL);
2831*44704f69SBart Van Assche                 js_snakenv_ihexstr_nex(jsp, jop, noitatmc, noitatmc_v, true,
2832*44704f69SBart Van Assche                                        NULL, NULL, NULL);
2833*44704f69SBart Van Assche                 js_snakenv_ihexstr_nex(jsp, jop, noc, noc_v, true, NULL,
2834*44704f69SBart Van Assche                                        NULL, NULL);
2835*44704f69SBart Van Assche             }
2836*44704f69SBart Van Assche 
2837*44704f69SBart Van Assche             break;
2838*44704f69SBart Van Assche         default:
2839*44704f69SBart Van Assche              sgj_pr_hr(jsp, "  <<unexpected %s 0x%x\n", param_c, pc);
2840*44704f69SBart Van Assche             break;
2841*44704f69SBart Van Assche         }
2842*44704f69SBart Van Assche         if (op->do_pcb)
2843*44704f69SBart Van Assche             sgj_pr_hr(jsp, "        <%s>\n", get_pcb_str(bp[2],
2844*44704f69SBart Van Assche                       str, sizeof(str)));
2845*44704f69SBart Van Assche         if (jsp->pr_as_json)
2846*44704f69SBart Van Assche             sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
2847*44704f69SBart Van Assche         if (op->filter_given)
2848*44704f69SBart Van Assche             break;
2849*44704f69SBart Van Assche skip:
2850*44704f69SBart Van Assche         num -= pl;
2851*44704f69SBart Van Assche         bp += pl;
2852*44704f69SBart Van Assche     }
2853*44704f69SBart Van Assche     return true;
2854*44704f69SBart Van Assche }
2855*44704f69SBart Van Assche 
2856*44704f69SBart Van Assche /* Tape usage: Vendor specific (LTO-5 and LTO-6): 0x30 */
2857*44704f69SBart Van Assche static bool
show_tape_usage_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)2858*44704f69SBart Van Assche show_tape_usage_page(const uint8_t * resp, int len, struct opts_t * op,
2859*44704f69SBart Van Assche                      sgj_opaque_p jop)
2860*44704f69SBart Van Assche {
2861*44704f69SBart Van Assche     int k, num, extra;
2862*44704f69SBart Van Assche     unsigned int n;
2863*44704f69SBart Van Assche     uint64_t ull;
2864*44704f69SBart Van Assche     const uint8_t * bp;
2865*44704f69SBart Van Assche     char str[PCB_STR_LEN];
2866*44704f69SBart Van Assche 
2867*44704f69SBart Van Assche if (jop) { };
2868*44704f69SBart Van Assche     num = len - 4;
2869*44704f69SBart Van Assche     bp = &resp[0] + 4;
2870*44704f69SBart Van Assche     if (num < 4) {
2871*44704f69SBart Van Assche         pr2serr("badly formed tape usage page\n");
2872*44704f69SBart Van Assche         return false;
2873*44704f69SBart Van Assche     }
2874*44704f69SBart Van Assche     if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
2875*44704f69SBart Van Assche         printf("Tape usage page  (LTO-5 and LTO-6 specific) [0x30]\n");
2876*44704f69SBart Van Assche     for (k = num; k > 0; k -= extra, bp += extra) {
2877*44704f69SBart Van Assche         int pc = sg_get_unaligned_be16(bp + 0);
2878*44704f69SBart Van Assche 
2879*44704f69SBart Van Assche         extra = bp[3] + 4;
2880*44704f69SBart Van Assche         if (op->filter_given) {
2881*44704f69SBart Van Assche             if (pc != op->filter)
2882*44704f69SBart Van Assche                 continue;
2883*44704f69SBart Van Assche         }
2884*44704f69SBart Van Assche         if (op->do_raw) {
2885*44704f69SBart Van Assche             dStrRaw(bp, extra);
2886*44704f69SBart Van Assche             break;
2887*44704f69SBart Van Assche         } else if (op->do_hex) {
2888*44704f69SBart Van Assche             hex2stdout(bp, extra, op->dstrhex_no_ascii);
2889*44704f69SBart Van Assche             break;
2890*44704f69SBart Van Assche         }
2891*44704f69SBart Van Assche         ull = n = 0;
2892*44704f69SBart Van Assche         switch (bp[3]) {
2893*44704f69SBart Van Assche         case 2:
2894*44704f69SBart Van Assche             n = sg_get_unaligned_be16(bp + 4);
2895*44704f69SBart Van Assche             break;
2896*44704f69SBart Van Assche         case 4:
2897*44704f69SBart Van Assche             n = sg_get_unaligned_be32(bp + 4);
2898*44704f69SBart Van Assche             break;
2899*44704f69SBart Van Assche         case 8:
2900*44704f69SBart Van Assche             ull = sg_get_unaligned_be64(bp + 4);
2901*44704f69SBart Van Assche             break;
2902*44704f69SBart Van Assche         }
2903*44704f69SBart Van Assche         switch (pc) {
2904*44704f69SBart Van Assche         case 0x01:
2905*44704f69SBart Van Assche             if (extra == 8)
2906*44704f69SBart Van Assche                 printf("  Thread count: %u", n);
2907*44704f69SBart Van Assche             break;
2908*44704f69SBart Van Assche         case 0x02:
2909*44704f69SBart Van Assche             if (extra == 12)
2910*44704f69SBart Van Assche                 printf("  Total data sets written: %" PRIu64, ull);
2911*44704f69SBart Van Assche             break;
2912*44704f69SBart Van Assche         case 0x03:
2913*44704f69SBart Van Assche             if (extra == 8)
2914*44704f69SBart Van Assche                 printf("  Total write retries: %u", n);
2915*44704f69SBart Van Assche             break;
2916*44704f69SBart Van Assche         case 0x04:
2917*44704f69SBart Van Assche             if (extra == 6)
2918*44704f69SBart Van Assche                 printf("  Total unrecovered write errors: %u", n);
2919*44704f69SBart Van Assche             break;
2920*44704f69SBart Van Assche         case 0x05:
2921*44704f69SBart Van Assche             if (extra == 6)
2922*44704f69SBart Van Assche                 printf("  Total suspended writes: %u", n);
2923*44704f69SBart Van Assche             break;
2924*44704f69SBart Van Assche         case 0x06:
2925*44704f69SBart Van Assche             if (extra == 6)
2926*44704f69SBart Van Assche                 printf("  Total fatal suspended writes: %u", n);
2927*44704f69SBart Van Assche             break;
2928*44704f69SBart Van Assche         case 0x07:
2929*44704f69SBart Van Assche             if (extra == 12)
2930*44704f69SBart Van Assche                 printf("  Total data sets read: %" PRIu64, ull);
2931*44704f69SBart Van Assche             break;
2932*44704f69SBart Van Assche         case 0x08:
2933*44704f69SBart Van Assche             if (extra == 8)
2934*44704f69SBart Van Assche                 printf("  Total read retries: %u", n);
2935*44704f69SBart Van Assche             break;
2936*44704f69SBart Van Assche         case 0x09:
2937*44704f69SBart Van Assche             if (extra == 6)
2938*44704f69SBart Van Assche                 printf("  Total unrecovered read errors: %u", n);
2939*44704f69SBart Van Assche             break;
2940*44704f69SBart Van Assche         case 0x0a:
2941*44704f69SBart Van Assche             if (extra == 6)
2942*44704f69SBart Van Assche                 printf("  Total suspended reads: %u", n);
2943*44704f69SBart Van Assche             break;
2944*44704f69SBart Van Assche         case 0x0b:
2945*44704f69SBart Van Assche             if (extra == 6)
2946*44704f69SBart Van Assche                 printf("  Total fatal suspended reads: %u", n);
2947*44704f69SBart Van Assche             break;
2948*44704f69SBart Van Assche         default:
2949*44704f69SBart Van Assche             printf("  unknown %s = 0x%x, contents in hex:\n", param_c, pc);
2950*44704f69SBart Van Assche             hex2stdout(bp, extra, 1);
2951*44704f69SBart Van Assche             break;
2952*44704f69SBart Van Assche         }
2953*44704f69SBart Van Assche         printf("\n");
2954*44704f69SBart Van Assche         if (op->do_pcb)
2955*44704f69SBart Van Assche             printf("        <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
2956*44704f69SBart Van Assche         if (op->filter_given)
2957*44704f69SBart Van Assche             break;
2958*44704f69SBart Van Assche     }
2959*44704f69SBart Van Assche     return true;
2960*44704f69SBart Van Assche }
2961*44704f69SBart Van Assche 
2962*44704f69SBart Van Assche /* 0x30 */
2963*44704f69SBart Van Assche static bool
show_hgst_perf_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)2964*44704f69SBart Van Assche show_hgst_perf_page(const uint8_t * resp, int len, struct opts_t * op,
2965*44704f69SBart Van Assche                     sgj_opaque_p jop)
2966*44704f69SBart Van Assche {
2967*44704f69SBart Van Assche     bool valid = false;
2968*44704f69SBart Van Assche     int num, pl;
2969*44704f69SBart Van Assche     const uint8_t * bp;
2970*44704f69SBart Van Assche     char str[PCB_STR_LEN];
2971*44704f69SBart Van Assche 
2972*44704f69SBart Van Assche if (jop) { };
2973*44704f69SBart Van Assche     if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
2974*44704f69SBart Van Assche         printf("HGST/WDC performance counters page [0x30]\n");
2975*44704f69SBart Van Assche     num = len - 4;
2976*44704f69SBart Van Assche     if (num < 0x30) {
2977*44704f69SBart Van Assche         printf("HGST/WDC performance counters page too short (%d) < 48\n",
2978*44704f69SBart Van Assche                num);
2979*44704f69SBart Van Assche         return valid;
2980*44704f69SBart Van Assche     }
2981*44704f69SBart Van Assche     bp = &resp[0] + 4;
2982*44704f69SBart Van Assche     while (num > 3) {
2983*44704f69SBart Van Assche         int pc = sg_get_unaligned_be16(bp + 0);
2984*44704f69SBart Van Assche 
2985*44704f69SBart Van Assche         pl = bp[3] + 4;
2986*44704f69SBart Van Assche         if (op->filter_given) {
2987*44704f69SBart Van Assche             if (pc != op->filter)
2988*44704f69SBart Van Assche                 goto skip;
2989*44704f69SBart Van Assche         }
2990*44704f69SBart Van Assche         if (op->do_raw) {
2991*44704f69SBart Van Assche             dStrRaw(bp, pl);
2992*44704f69SBart Van Assche             break;
2993*44704f69SBart Van Assche         } else if (op->do_hex) {
2994*44704f69SBart Van Assche             hex2stdout(bp, pl, op->dstrhex_no_ascii);
2995*44704f69SBart Van Assche             break;
2996*44704f69SBart Van Assche         }
2997*44704f69SBart Van Assche         switch (pc) {
2998*44704f69SBart Van Assche         case 0:
2999*44704f69SBart Van Assche             valid = true;
3000*44704f69SBart Van Assche             printf("  Zero Seeks = %u\n", sg_get_unaligned_be16(bp + 4));
3001*44704f69SBart Van Assche             printf("  Seeks >= 2/3 = %u\n", sg_get_unaligned_be16(bp + 6));
3002*44704f69SBart Van Assche             printf("  Seeks >= 1/3 and < 2/3 = %u\n",
3003*44704f69SBart Van Assche                    sg_get_unaligned_be16(bp + 8));
3004*44704f69SBart Van Assche             printf("  Seeks >= 1/6 and < 1/3 = %u\n",
3005*44704f69SBart Van Assche                    sg_get_unaligned_be16(bp + 10));
3006*44704f69SBart Van Assche             printf("  Seeks >= 1/12 and < 1/6 = %u\n",
3007*44704f69SBart Van Assche                    sg_get_unaligned_be16(bp + 12));
3008*44704f69SBart Van Assche             printf("  Seeks > 0 and < 1/12 = %u\n",
3009*44704f69SBart Van Assche                    sg_get_unaligned_be16(bp + 14));
3010*44704f69SBart Van Assche             printf("  Overrun Counter = %u\n",
3011*44704f69SBart Van Assche                    sg_get_unaligned_be16(bp + 20));
3012*44704f69SBart Van Assche             printf("  Underrun Counter = %u\n",
3013*44704f69SBart Van Assche                    sg_get_unaligned_be16(bp + 22));
3014*44704f69SBart Van Assche             printf("  Device Cache Full Read Hits = %u\n",
3015*44704f69SBart Van Assche                    sg_get_unaligned_be32(bp + 24));
3016*44704f69SBart Van Assche             printf("  Device Cache Partial Read Hits = %u\n",
3017*44704f69SBart Van Assche                    sg_get_unaligned_be32(bp + 28));
3018*44704f69SBart Van Assche             printf("  Device Cache Write Hits = %u\n",
3019*44704f69SBart Van Assche                    sg_get_unaligned_be32(bp + 32));
3020*44704f69SBart Van Assche             printf("  Device Cache Fast Writes = %u\n",
3021*44704f69SBart Van Assche                    sg_get_unaligned_be32(bp + 36));
3022*44704f69SBart Van Assche             printf("  Device Cache Read Misses = %u\n",
3023*44704f69SBart Van Assche                    sg_get_unaligned_be32(bp + 40));
3024*44704f69SBart Van Assche             break;
3025*44704f69SBart Van Assche         default:
3026*44704f69SBart Van Assche             valid = false;
3027*44704f69SBart Van Assche             printf("  Unknown HGST/WDC %s = 0x%x", param_c, pc);
3028*44704f69SBart Van Assche             break;
3029*44704f69SBart Van Assche         }
3030*44704f69SBart Van Assche         if (op->do_pcb)
3031*44704f69SBart Van Assche             printf("        <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
3032*44704f69SBart Van Assche         if (op->filter_given)
3033*44704f69SBart Van Assche             break;
3034*44704f69SBart Van Assche skip:
3035*44704f69SBart Van Assche         num -= pl;
3036*44704f69SBart Van Assche         bp += pl;
3037*44704f69SBart Van Assche     }
3038*44704f69SBart Van Assche     return valid;
3039*44704f69SBart Van Assche }
3040*44704f69SBart Van Assche 
3041*44704f69SBart Van Assche /* Tape capacity: vendor specific (LTO-5 and LTO-6 ?): 0x31 */
3042*44704f69SBart Van Assche static bool
show_tape_capacity_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)3043*44704f69SBart Van Assche show_tape_capacity_page(const uint8_t * resp, int len,
3044*44704f69SBart Van Assche                         struct opts_t * op, sgj_opaque_p jop)
3045*44704f69SBart Van Assche {
3046*44704f69SBart Van Assche     int k, num, extra;
3047*44704f69SBart Van Assche     unsigned int n;
3048*44704f69SBart Van Assche     const uint8_t * bp;
3049*44704f69SBart Van Assche     char str[PCB_STR_LEN];
3050*44704f69SBart Van Assche 
3051*44704f69SBart Van Assche if (jop) { };
3052*44704f69SBart Van Assche     num = len - 4;
3053*44704f69SBart Van Assche     bp = &resp[0] + 4;
3054*44704f69SBart Van Assche     if (num < 4) {
3055*44704f69SBart Van Assche         pr2serr("badly formed tape capacity page\n");
3056*44704f69SBart Van Assche         return false;
3057*44704f69SBart Van Assche     }
3058*44704f69SBart Van Assche     if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
3059*44704f69SBart Van Assche         printf("Tape capacity page  (LTO-5 and LTO-6 specific) [0x31]\n");
3060*44704f69SBart Van Assche     for (k = num; k > 0; k -= extra, bp += extra) {
3061*44704f69SBart Van Assche         int pc = sg_get_unaligned_be16(bp + 0);
3062*44704f69SBart Van Assche 
3063*44704f69SBart Van Assche         extra = bp[3] + 4;
3064*44704f69SBart Van Assche         if (op->filter_given) {
3065*44704f69SBart Van Assche             if (pc != op->filter)
3066*44704f69SBart Van Assche                 continue;
3067*44704f69SBart Van Assche         }
3068*44704f69SBart Van Assche         if (op->do_raw) {
3069*44704f69SBart Van Assche             dStrRaw(bp, extra);
3070*44704f69SBart Van Assche             break;
3071*44704f69SBart Van Assche         } else if (op->do_hex) {
3072*44704f69SBart Van Assche             hex2stdout(bp, extra, op->dstrhex_no_ascii);
3073*44704f69SBart Van Assche             break;
3074*44704f69SBart Van Assche         }
3075*44704f69SBart Van Assche         if (extra != 8)
3076*44704f69SBart Van Assche             continue;
3077*44704f69SBart Van Assche         n = sg_get_unaligned_be32(bp + 4);
3078*44704f69SBart Van Assche         switch (pc) {
3079*44704f69SBart Van Assche         case 0x01:
3080*44704f69SBart Van Assche             printf("  Main partition remaining capacity (in MiB): %u", n);
3081*44704f69SBart Van Assche             break;
3082*44704f69SBart Van Assche         case 0x02:
3083*44704f69SBart Van Assche             printf("  Alternate partition remaining capacity (in MiB): %u", n);
3084*44704f69SBart Van Assche             break;
3085*44704f69SBart Van Assche         case 0x03:
3086*44704f69SBart Van Assche             printf("  Main partition maximum capacity (in MiB): %u", n);
3087*44704f69SBart Van Assche             break;
3088*44704f69SBart Van Assche         case 0x04:
3089*44704f69SBart Van Assche             printf("  Alternate partition maximum capacity (in MiB): %u", n);
3090*44704f69SBart Van Assche             break;
3091*44704f69SBart Van Assche         default:
3092*44704f69SBart Van Assche             printf("  unknown %s = 0x%x, contents in hex:\n", param_c, pc);
3093*44704f69SBart Van Assche             hex2stdout(bp, extra, 1);
3094*44704f69SBart Van Assche             break;
3095*44704f69SBart Van Assche         }
3096*44704f69SBart Van Assche         printf("\n");
3097*44704f69SBart Van Assche         if (op->do_pcb)
3098*44704f69SBart Van Assche             printf("        <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
3099*44704f69SBart Van Assche         if (op->filter_given)
3100*44704f69SBart Van Assche             break;
3101*44704f69SBart Van Assche     }
3102*44704f69SBart Van Assche     return true;
3103*44704f69SBart Van Assche }
3104*44704f69SBart Van Assche 
3105*44704f69SBart Van Assche /* Data compression: originally vendor specific 0x32 (LTO-5), then
3106*44704f69SBart Van Assche  * ssc-4 standardizes it at 0x1b <dc> */
3107*44704f69SBart Van Assche static bool
show_data_compression_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)3108*44704f69SBart Van Assche show_data_compression_page(const uint8_t * resp, int len,
3109*44704f69SBart Van Assche                            struct opts_t * op, sgj_opaque_p jop)
3110*44704f69SBart Van Assche {
3111*44704f69SBart Van Assche     int k, j, pl, num, extra, pc, pg_code;
3112*44704f69SBart Van Assche     uint64_t n;
3113*44704f69SBart Van Assche     const uint8_t * bp;
3114*44704f69SBart Van Assche     char str[PCB_STR_LEN];
3115*44704f69SBart Van Assche 
3116*44704f69SBart Van Assche if (jop) { };
3117*44704f69SBart Van Assche     pg_code = resp[0] & 0x3f;
3118*44704f69SBart Van Assche     num = len - 4;
3119*44704f69SBart Van Assche     bp = &resp[0] + 4;
3120*44704f69SBart Van Assche     if (num < 4) {
3121*44704f69SBart Van Assche         pr2serr("badly formed data compression page\n");
3122*44704f69SBart Van Assche         return false;
3123*44704f69SBart Van Assche     }
3124*44704f69SBart Van Assche     if (op->verbose || ((! op->do_raw) && (0 == op->do_hex))) {
3125*44704f69SBart Van Assche         if (0x1b == pg_code)
3126*44704f69SBart Van Assche             printf("Data compression page  (ssc-4) [0x1b]\n");
3127*44704f69SBart Van Assche         else
3128*44704f69SBart Van Assche             printf("Data compression page  (LTO-5 specific) [0x%x]\n",
3129*44704f69SBart Van Assche                    pg_code);
3130*44704f69SBart Van Assche     }
3131*44704f69SBart Van Assche     for (k = num; k > 0; k -= extra, bp += extra) {
3132*44704f69SBart Van Assche         pc = sg_get_unaligned_be16(bp + 0);
3133*44704f69SBart Van Assche         pl = bp[3];
3134*44704f69SBart Van Assche         extra = pl + 4;
3135*44704f69SBart Van Assche         if (op->filter_given) {
3136*44704f69SBart Van Assche             if (pc != op->filter)
3137*44704f69SBart Van Assche                 continue;
3138*44704f69SBart Van Assche         }
3139*44704f69SBart Van Assche         if (op->do_raw) {
3140*44704f69SBart Van Assche             dStrRaw(bp, extra);
3141*44704f69SBart Van Assche             break;
3142*44704f69SBart Van Assche         } else if (op->do_hex) {
3143*44704f69SBart Van Assche             hex2stdout(bp, extra, op->dstrhex_no_ascii);
3144*44704f69SBart Van Assche             break;
3145*44704f69SBart Van Assche         }
3146*44704f69SBart Van Assche         if ((0 == pl) || (pl > 8)) {
3147*44704f69SBart Van Assche             printf("badly formed data compression log parameter\n");
3148*44704f69SBart Van Assche             printf("  %s = 0x%x, contents in hex:\n", param_c, pc);
3149*44704f69SBart Van Assche             hex2stdout(bp, extra, op->dstrhex_no_ascii);
3150*44704f69SBart Van Assche             goto skip_para;
3151*44704f69SBart Van Assche         }
3152*44704f69SBart Van Assche         /* variable length integer, max length 8 bytes */
3153*44704f69SBart Van Assche         for (j = 0, n = 0; j < pl; ++j) {
3154*44704f69SBart Van Assche             if (j > 0)
3155*44704f69SBart Van Assche                 n <<= 8;
3156*44704f69SBart Van Assche             n |= bp[4 + j];
3157*44704f69SBart Van Assche         }
3158*44704f69SBart Van Assche         switch (pc) {
3159*44704f69SBart Van Assche         case 0x00:
3160*44704f69SBart Van Assche             printf("  Read compression ratio x100: %" PRIu64 , n);
3161*44704f69SBart Van Assche             break;
3162*44704f69SBart Van Assche         case 0x01:
3163*44704f69SBart Van Assche             printf("  Write compression ratio x100: %" PRIu64 , n);
3164*44704f69SBart Van Assche             break;
3165*44704f69SBart Van Assche         case 0x02:
3166*44704f69SBart Van Assche             printf("  Megabytes transferred to server: %" PRIu64 , n);
3167*44704f69SBart Van Assche             break;
3168*44704f69SBart Van Assche         case 0x03:
3169*44704f69SBart Van Assche             printf("  Bytes transferred to server: %" PRIu64 , n);
3170*44704f69SBart Van Assche             break;
3171*44704f69SBart Van Assche         case 0x04:
3172*44704f69SBart Van Assche             printf("  Megabytes read from tape: %" PRIu64 , n);
3173*44704f69SBart Van Assche             break;
3174*44704f69SBart Van Assche         case 0x05:
3175*44704f69SBart Van Assche             printf("  Bytes read from tape: %" PRIu64 , n);
3176*44704f69SBart Van Assche             break;
3177*44704f69SBart Van Assche         case 0x06:
3178*44704f69SBart Van Assche             printf("  Megabytes transferred from server: %" PRIu64 , n);
3179*44704f69SBart Van Assche             break;
3180*44704f69SBart Van Assche         case 0x07:
3181*44704f69SBart Van Assche             printf("  Bytes transferred from server: %" PRIu64 , n);
3182*44704f69SBart Van Assche             break;
3183*44704f69SBart Van Assche         case 0x08:
3184*44704f69SBart Van Assche             printf("  Megabytes written to tape: %" PRIu64 , n);
3185*44704f69SBart Van Assche             break;
3186*44704f69SBart Van Assche         case 0x09:
3187*44704f69SBart Van Assche             printf("  Bytes written to tape: %" PRIu64 , n);
3188*44704f69SBart Van Assche             break;
3189*44704f69SBart Van Assche         case 0x100:
3190*44704f69SBart Van Assche             printf("  Data compression enabled: 0x%" PRIx64, n);
3191*44704f69SBart Van Assche             break;
3192*44704f69SBart Van Assche         default:
3193*44704f69SBart Van Assche             printf("  unknown %s = 0x%x, contents in hex:\n", param_c, pc);
3194*44704f69SBart Van Assche             hex2stdout(bp, extra, op->dstrhex_no_ascii);
3195*44704f69SBart Van Assche             break;
3196*44704f69SBart Van Assche         }
3197*44704f69SBart Van Assche skip_para:
3198*44704f69SBart Van Assche         printf("\n");
3199*44704f69SBart Van Assche         if (op->do_pcb)
3200*44704f69SBart Van Assche             printf("        <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
3201*44704f69SBart Van Assche         if (op->filter_given)
3202*44704f69SBart Van Assche             break;
3203*44704f69SBart Van Assche     }
3204*44704f69SBart Van Assche     return true;
3205*44704f69SBart Van Assche }
3206*44704f69SBart Van Assche 
3207*44704f69SBart Van Assche /* LAST_N_ERR_LPAGE [0x7] <lne>  introduced: SPC-2 */
3208*44704f69SBart Van Assche static bool
show_last_n_error_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)3209*44704f69SBart Van Assche show_last_n_error_page(const uint8_t * resp, int len,
3210*44704f69SBart Van Assche                        struct opts_t * op, sgj_opaque_p jop)
3211*44704f69SBart Van Assche {
3212*44704f69SBart Van Assche     int k, num, pl;
3213*44704f69SBart Van Assche     const uint8_t * bp;
3214*44704f69SBart Van Assche     sgj_state * jsp = &op->json_st;
3215*44704f69SBart Van Assche     sgj_opaque_p jo2p;
3216*44704f69SBart Van Assche     sgj_opaque_p jo3p = NULL;
3217*44704f69SBart Van Assche     sgj_opaque_p jap = NULL;
3218*44704f69SBart Van Assche     char str[PCB_STR_LEN];
3219*44704f69SBart Van Assche     char b[256];
3220*44704f69SBart Van Assche     static const char * lneelp = "Last n error events log page";
3221*44704f69SBart Van Assche     static const char * eed = "error_event_data";
3222*44704f69SBart Van Assche 
3223*44704f69SBart Van Assche     num = len - 4;
3224*44704f69SBart Van Assche     bp = &resp[0] + 4;
3225*44704f69SBart Van Assche     if (num < 4) {
3226*44704f69SBart Van Assche         sgj_pr_hr(jsp, "No error events logged\n");
3227*44704f69SBart Van Assche         return true;
3228*44704f69SBart Van Assche     }
3229*44704f69SBart Van Assche     if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
3230*44704f69SBart Van Assche         sgj_pr_hr(jsp, "%s  [0x7]\n", lneelp);
3231*44704f69SBart Van Assche     if (jsp->pr_as_json) {
3232*44704f69SBart Van Assche         jo2p = sg_log_js_hdr(jsp, jop, lneelp, resp);
3233*44704f69SBart Van Assche         jap = sgj_named_subarray_r(jsp, jo2p, "error_event_log_parameters");
3234*44704f69SBart Van Assche     }
3235*44704f69SBart Van Assche 
3236*44704f69SBart Van Assche     for (k = num; k > 0; k -= pl, bp += pl) {
3237*44704f69SBart Van Assche         uint16_t pc;
3238*44704f69SBart Van Assche 
3239*44704f69SBart Van Assche         if (k < 3) {
3240*44704f69SBart Van Assche             pr2serr("short %s\n", lneelp);
3241*44704f69SBart Van Assche             return false;
3242*44704f69SBart Van Assche         }
3243*44704f69SBart Van Assche         pl = bp[3] + 4;
3244*44704f69SBart Van Assche         pc = sg_get_unaligned_be16(bp + 0);
3245*44704f69SBart Van Assche         if (op->filter_given) {
3246*44704f69SBart Van Assche             if (pc != op->filter)
3247*44704f69SBart Van Assche                 continue;
3248*44704f69SBart Van Assche         }
3249*44704f69SBart Van Assche         if (op->do_raw) {
3250*44704f69SBart Van Assche             dStrRaw(bp, pl);
3251*44704f69SBart Van Assche             break;
3252*44704f69SBart Van Assche         } else if (op->do_hex) {
3253*44704f69SBart Van Assche             hex2stdout(bp, pl, op->dstrhex_no_ascii);
3254*44704f69SBart Van Assche             break;
3255*44704f69SBart Van Assche         }
3256*44704f69SBart Van Assche         if (jsp->pr_as_json) {
3257*44704f69SBart Van Assche             jo3p = sgj_new_unattached_object_r(jsp);
3258*44704f69SBart Van Assche             if (op->do_pcb)
3259*44704f69SBart Van Assche                 js_pcb(jsp, jo3p, bp[2]);
3260*44704f69SBart Van Assche             sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, NULL);
3261*44704f69SBart Van Assche         }
3262*44704f69SBart Van Assche 
3263*44704f69SBart Van Assche         sgj_pr_hr(jsp, "  Error event %u [0x%x]:\n", pc, pc);
3264*44704f69SBart Van Assche         if (pl > 4) {
3265*44704f69SBart Van Assche             if ((bp[2] & 0x1) && (bp[2] & 0x2)) {
3266*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "    [binary]:\n");
3267*44704f69SBart Van Assche                 hex2str(bp + 4, pl - 4, "    ", op->hex2str_oformat,
3268*44704f69SBart Van Assche                         sizeof(b), b);
3269*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "%s\n", b);
3270*44704f69SBart Van Assche                 if (jsp->pr_as_json)
3271*44704f69SBart Van Assche                     sgj_js_nv_hex_bytes(jsp, jo3p, eed, bp + 4, pl - 4);
3272*44704f69SBart Van Assche             } else if (0x01 == (bp[2] & 0x3)) {  /* ASCII */
3273*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "    %.*s\n", pl - 4, (const char *)(bp + 4));
3274*44704f69SBart Van Assche                 if (jsp->pr_as_json)
3275*44704f69SBart Van Assche                     sgj_js_nv_s_len(jsp, jo3p, eed,
3276*44704f69SBart Van Assche                                     (const char *)(bp + 4), pl - 4);
3277*44704f69SBart Van Assche             } else {
3278*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "    [data counter?? (LP bit should be "
3279*44704f69SBart Van Assche                           "set)]:\n");
3280*44704f69SBart Van Assche                 hex2str(bp + 4, pl - 4, "    ", op->hex2str_oformat,
3281*44704f69SBart Van Assche                         sizeof(b), b);
3282*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "%s\n", b);
3283*44704f69SBart Van Assche                 if (jsp->pr_as_json)
3284*44704f69SBart Van Assche                     sgj_js_nv_hex_bytes(jsp, jo3p, eed, bp + 4, pl - 4);
3285*44704f69SBart Van Assche             }
3286*44704f69SBart Van Assche         }
3287*44704f69SBart Van Assche         if (op->do_pcb)
3288*44704f69SBart Van Assche             sgj_pr_hr(jsp, "        <%s>\n", get_pcb_str(bp[2],
3289*44704f69SBart Van Assche                       str, sizeof(str)));
3290*44704f69SBart Van Assche         if (jsp->pr_as_json)
3291*44704f69SBart Van Assche             sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
3292*44704f69SBart Van Assche         if (op->filter_given)
3293*44704f69SBart Van Assche             break;
3294*44704f69SBart Van Assche     }
3295*44704f69SBart Van Assche     return true;
3296*44704f69SBart Van Assche }
3297*44704f69SBart Van Assche 
3298*44704f69SBart Van Assche /* LAST_N_DEFERRED_LPAGE [0xb] <lnd>  introduced: SPC-2 */
3299*44704f69SBart Van Assche static bool
show_last_n_deferred_error_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)3300*44704f69SBart Van Assche show_last_n_deferred_error_page(const uint8_t * resp, int len,
3301*44704f69SBart Van Assche                                 struct opts_t * op, sgj_opaque_p jop)
3302*44704f69SBart Van Assche {
3303*44704f69SBart Van Assche     int k, n, num, pl;
3304*44704f69SBart Van Assche     const uint8_t * bp;
3305*44704f69SBart Van Assche     sgj_state * jsp = &op->json_st;
3306*44704f69SBart Van Assche     sgj_opaque_p jo2p, jo4p;
3307*44704f69SBart Van Assche     sgj_opaque_p jo3p = NULL;
3308*44704f69SBart Van Assche     sgj_opaque_p jap = NULL;
3309*44704f69SBart Van Assche     char str[PCB_STR_LEN];
3310*44704f69SBart Van Assche     char b[512];
3311*44704f69SBart Van Assche     static const char * lndeoaelp =
3312*44704f69SBart Van Assche                 "Last n deferred errors or asynchronous events log page";
3313*44704f69SBart Van Assche     static const char * deoae = "Deferred error or asynchronous event";
3314*44704f69SBart Van Assche     static const char * sd = "sense_data";
3315*44704f69SBart Van Assche 
3316*44704f69SBart Van Assche     num = len - 4;
3317*44704f69SBart Van Assche     bp = &resp[0] + 4;
3318*44704f69SBart Van Assche     if (num < 4) {
3319*44704f69SBart Van Assche         pr2serr("No deferred errors logged\n");
3320*44704f69SBart Van Assche         return true;
3321*44704f69SBart Van Assche     }
3322*44704f69SBart Van Assche     if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
3323*44704f69SBart Van Assche         sgj_pr_hr(jsp, "%s  [0xb]\n", lndeoaelp);
3324*44704f69SBart Van Assche     if (jsp->pr_as_json) {
3325*44704f69SBart Van Assche         jo2p = sg_log_js_hdr(jsp, jop, lndeoaelp, resp);
3326*44704f69SBart Van Assche         jap = sgj_named_subarray_r(jsp, jo2p,
3327*44704f69SBart Van Assche                 "deferred_error_or_asynchronous_event_log_parameters");
3328*44704f69SBart Van Assche     }
3329*44704f69SBart Van Assche 
3330*44704f69SBart Van Assche     for (k = num; k > 0; k -= pl, bp += pl) {
3331*44704f69SBart Van Assche         int pc;
3332*44704f69SBart Van Assche 
3333*44704f69SBart Van Assche         if (k < 3) {
3334*44704f69SBart Van Assche             pr2serr("short %s\n", lndeoaelp);
3335*44704f69SBart Van Assche             return false;
3336*44704f69SBart Van Assche         }
3337*44704f69SBart Van Assche         pl = bp[3] + 4;
3338*44704f69SBart Van Assche         pc = sg_get_unaligned_be16(bp + 0);
3339*44704f69SBart Van Assche         if (op->filter_given) {
3340*44704f69SBart Van Assche             if (pc != op->filter)
3341*44704f69SBart Van Assche                 continue;
3342*44704f69SBart Van Assche         }
3343*44704f69SBart Van Assche         if (op->do_raw) {
3344*44704f69SBart Van Assche             dStrRaw(bp, pl);
3345*44704f69SBart Van Assche             break;
3346*44704f69SBart Van Assche         } else if (op->do_hex) {
3347*44704f69SBart Van Assche             hex2stdout(bp, pl, op->dstrhex_no_ascii);
3348*44704f69SBart Van Assche             break;
3349*44704f69SBart Van Assche         }
3350*44704f69SBart Van Assche         if (jsp->pr_as_json) {
3351*44704f69SBart Van Assche             jo3p = sgj_new_unattached_object_r(jsp);
3352*44704f69SBart Van Assche             if (op->do_pcb)
3353*44704f69SBart Van Assche                 js_pcb(jsp, jo3p, bp[2]);
3354*44704f69SBart Van Assche             sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, deoae);
3355*44704f69SBart Van Assche         }
3356*44704f69SBart Van Assche         sgj_pr_hr(jsp, "  %s [0x%x]:\n", deoae, pc);
3357*44704f69SBart Van Assche         if (op->do_brief > 0) {
3358*44704f69SBart Van Assche             hex2stdout(bp + 4, pl - 4, op->dstrhex_no_ascii);
3359*44704f69SBart Van Assche             hex2str(bp + 4, pl - 4, "    ", op->hex2str_oformat,
3360*44704f69SBart Van Assche                     sizeof(b), b);
3361*44704f69SBart Van Assche             sgj_pr_hr(jsp, "%s\n", b);
3362*44704f69SBart Van Assche             if (jsp->pr_as_json)
3363*44704f69SBart Van Assche                 sgj_js_nv_hex_bytes(jsp, jo3p, sd, bp + 4, pl - 4);
3364*44704f69SBart Van Assche         } else {
3365*44704f69SBart Van Assche 
3366*44704f69SBart Van Assche             n = sg_get_sense_str("    ", bp + 4, pl - 4,  false, sizeof(b),
3367*44704f69SBart Van Assche                                  b);
3368*44704f69SBart Van Assche             sgj_pr_hr(jsp, "%.*s\n", n, b);
3369*44704f69SBart Van Assche             if (jsp->pr_as_json) {
3370*44704f69SBart Van Assche                 jo4p = sgj_named_subobject_r(jsp, jo3p, sd);
3371*44704f69SBart Van Assche                 sgj_js_sense(jsp, jo4p, bp + 4, pl - 4);
3372*44704f69SBart Van Assche             }
3373*44704f69SBart Van Assche         }
3374*44704f69SBart Van Assche         if (op->do_pcb)
3375*44704f69SBart Van Assche             sgj_pr_hr(jsp, "        <%s>\n", get_pcb_str(bp[2],
3376*44704f69SBart Van Assche                       str, sizeof(str)));
3377*44704f69SBart Van Assche         if (jsp->pr_as_json)
3378*44704f69SBart Van Assche             sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
3379*44704f69SBart Van Assche         if (op->filter_given)
3380*44704f69SBart Van Assche             break;
3381*44704f69SBart Van Assche     }
3382*44704f69SBart Van Assche     return true;
3383*44704f69SBart Van Assche }
3384*44704f69SBart Van Assche 
3385*44704f69SBart Van Assche static const char * clgc = "Change list generation code";
3386*44704f69SBart Van Assche static const char * cgn = "Changed generation number";
3387*44704f69SBart Van Assche 
3388*44704f69SBart Van Assche /* LAST_N_INQUIRY_DATA_CH_SUBPG [0xb,0x1] <lnic> introduced: SPC-5 (rev 17) */
3389*44704f69SBart Van Assche static bool
show_last_n_inq_data_ch_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)3390*44704f69SBart Van Assche show_last_n_inq_data_ch_page(const uint8_t * resp, int len,
3391*44704f69SBart Van Assche                              struct opts_t * op, sgj_opaque_p jop)
3392*44704f69SBart Van Assche {
3393*44704f69SBart Van Assche     bool vpd;
3394*44704f69SBart Van Assche     int j, num, pl, vpd_pg;
3395*44704f69SBart Van Assche     uint32_t k, n;
3396*44704f69SBart Van Assche     const uint8_t * bp;
3397*44704f69SBart Van Assche     const char * vpd_pg_name = NULL;
3398*44704f69SBart Van Assche     sgj_state * jsp = &op->json_st;
3399*44704f69SBart Van Assche     sgj_opaque_p jo2p, jo4p;
3400*44704f69SBart Van Assche     sgj_opaque_p jo3p = NULL;
3401*44704f69SBart Van Assche     sgj_opaque_p jap = NULL;
3402*44704f69SBart Van Assche     sgj_opaque_p ja2p;
3403*44704f69SBart Van Assche     char str[PCB_STR_LEN];
3404*44704f69SBart Van Assche     char b[128];
3405*44704f69SBart Van Assche     static const char * lnidclp = "Last n inquiry data changed log page";
3406*44704f69SBart Van Assche     static const char * idci = "Inquiry data changed indicator";
3407*44704f69SBart Van Assche 
3408*44704f69SBart Van Assche     if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
3409*44704f69SBart Van Assche         sgj_pr_hr(jsp, "%s  [0xb,0x1]\n", lnidclp);
3410*44704f69SBart Van Assche     num = len - 4;
3411*44704f69SBart Van Assche     bp = &resp[0] + 4;
3412*44704f69SBart Van Assche     if (jsp->pr_as_json) {
3413*44704f69SBart Van Assche         jo2p = sg_log_js_hdr(jsp, jop, lnidclp, resp);
3414*44704f69SBart Van Assche         jap = sgj_named_subarray_r(jsp, jo2p,
3415*44704f69SBart Van Assche                                    "inquiry_data_changed_log_parameters");
3416*44704f69SBart Van Assche     }
3417*44704f69SBart Van Assche 
3418*44704f69SBart Van Assche     while (num > 3) {
3419*44704f69SBart Van Assche         int pc = sg_get_unaligned_be16(bp + 0);
3420*44704f69SBart Van Assche 
3421*44704f69SBart Van Assche         pl = bp[3] + 4;
3422*44704f69SBart Van Assche         if (op->filter_given) {
3423*44704f69SBart Van Assche             if (pc != op->filter)
3424*44704f69SBart Van Assche                 goto skip;
3425*44704f69SBart Van Assche         }
3426*44704f69SBart Van Assche         if (op->do_raw) {
3427*44704f69SBart Van Assche             dStrRaw(bp, pl);
3428*44704f69SBart Van Assche             break;
3429*44704f69SBart Van Assche         } else if (op->do_hex) {
3430*44704f69SBart Van Assche             hex2stdout(bp, pl, op->dstrhex_no_ascii);
3431*44704f69SBart Van Assche             break;
3432*44704f69SBart Van Assche         }
3433*44704f69SBart Van Assche         if (jsp->pr_as_json) {
3434*44704f69SBart Van Assche             jo3p = sgj_new_unattached_object_r(jsp);
3435*44704f69SBart Van Assche             if (op->do_pcb)
3436*44704f69SBart Van Assche                 js_pcb(jsp, jo3p, bp[2]);
3437*44704f69SBart Van Assche             sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL,
3438*44704f69SBart Van Assche                               0 == pc ? clgc : idci);
3439*44704f69SBart Van Assche         }
3440*44704f69SBart Van Assche         if (0 == pc) {
3441*44704f69SBart Van Assche             if (pl < 8)  {
3442*44704f69SBart Van Assche                 pr2serr("  <<expect parameter 0x%x to be at least 8 bytes "
3443*44704f69SBart Van Assche                         "long, got %d, skip>>\n", pc, pl);
3444*44704f69SBart Van Assche                 goto skip;
3445*44704f69SBart Van Assche             }
3446*44704f69SBart Van Assche             sgj_pr_hr(jsp, "  %s [pc=0x0]:\n", clgc);
3447*44704f69SBart Van Assche             for (j = 4, k = 1; j < pl; j +=4, ++k) {
3448*44704f69SBart Van Assche                 n = sg_get_unaligned_be32(bp + j);
3449*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "    %s [0x%x]: %u\n", cgn, k, n);
3450*44704f69SBart Van Assche             }
3451*44704f69SBart Van Assche             if (jsp->pr_as_json) {
3452*44704f69SBart Van Assche                 ja2p = sgj_named_subarray_r(jsp, jo3p,
3453*44704f69SBart Van Assche                                             "changed_generation_numbers");
3454*44704f69SBart Van Assche                 for (j = 4, k = 1; j < pl; j +=4, ++k) {
3455*44704f69SBart Van Assche                     jo4p = sgj_new_unattached_object_r(jsp);
3456*44704f69SBart Van Assche                     n = sg_get_unaligned_be32(bp + j);
3457*44704f69SBart Van Assche                     js_snakenv_ihexstr_nex(jsp, jo4p, cgn, n, true, NULL,
3458*44704f69SBart Van Assche                                            NULL, NULL);
3459*44704f69SBart Van Assche                     sgj_js_nv_o(jsp, ja2p, NULL /* name */, jo4p);
3460*44704f69SBart Van Assche                 }
3461*44704f69SBart Van Assche             }
3462*44704f69SBart Van Assche         } else {        /* pc > 0x0 */
3463*44704f69SBart Van Assche             int m;
3464*44704f69SBart Van Assche             const int nn = sg_lib_names_mode_len;
3465*44704f69SBart Van Assche             struct sg_lib_simple_value_name_t * nvp = sg_lib_names_vpd_arr;
3466*44704f69SBart Van Assche 
3467*44704f69SBart Van Assche             snprintf(b, sizeof(b), "  %s 0x%x, ", param_c, pc);
3468*44704f69SBart Van Assche             vpd = !! (1 & *(bp + 4));
3469*44704f69SBart Van Assche             vpd_pg = *(bp + 5);
3470*44704f69SBart Van Assche             if (vpd) {
3471*44704f69SBart Van Assche                 for (m = 0; m < nn; ++m, ++nvp) {
3472*44704f69SBart Van Assche                     if (nvp->value == vpd_pg)
3473*44704f69SBart Van Assche                         break;
3474*44704f69SBart Van Assche                 }
3475*44704f69SBart Van Assche                 vpd_pg_name = (m < nn) ? nvp->name : NULL;
3476*44704f69SBart Van Assche             } else
3477*44704f69SBart Van Assche                 vpd_pg_name = "Standard INQUIRY";
3478*44704f69SBart Van Assche 
3479*44704f69SBart Van Assche             if (jsp->pr_as_json) {
3480*44704f69SBart Van Assche                 sgj_js_nv_i(jsp, jo3p, "vpd", (int)vpd);
3481*44704f69SBart Van Assche                 sgj_js_nv_ihex(jsp, jo3p, "changed_page_code", vpd_pg);
3482*44704f69SBart Van Assche                 if (vpd_pg_name)
3483*44704f69SBart Van Assche                     sgj_js_nv_s(jsp, jo3p, "changed_page_name", vpd_pg_name);
3484*44704f69SBart Van Assche             }
3485*44704f69SBart Van Assche             if (vpd) {
3486*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "%sVPD page 0x%x changed\n", b, vpd_pg);
3487*44704f69SBart Van Assche                 if (0 == op->do_brief) {
3488*44704f69SBart Van Assche                     if (vpd_pg_name)
3489*44704f69SBart Van Assche                         sgj_pr_hr(jsp, "    name: %s\n", vpd_pg_name);
3490*44704f69SBart Van Assche                 }
3491*44704f69SBart Van Assche             } else
3492*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "%sStandard INQUIRY data changed\n", b);
3493*44704f69SBart Van Assche         }
3494*44704f69SBart Van Assche         if (op->do_pcb)
3495*44704f69SBart Van Assche             sgj_pr_hr(jsp, "        <%s>\n", get_pcb_str(bp[2],
3496*44704f69SBart Van Assche                       str, sizeof(str)));
3497*44704f69SBart Van Assche skip:
3498*44704f69SBart Van Assche         if (jsp->pr_as_json)
3499*44704f69SBart Van Assche             sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
3500*44704f69SBart Van Assche         if (op->filter_given)
3501*44704f69SBart Van Assche             break;
3502*44704f69SBart Van Assche         num -= pl;
3503*44704f69SBart Van Assche         bp += pl;
3504*44704f69SBart Van Assche     }
3505*44704f69SBart Van Assche     return true;
3506*44704f69SBart Van Assche }
3507*44704f69SBart Van Assche 
3508*44704f69SBart Van Assche /* LAST_N_MODE_PG_DATA_CH_SUBPG [0xb,0x2] <lnmc> introduced: SPC-5 (rev 17) */
3509*44704f69SBart Van Assche static bool
show_last_n_mode_pg_data_ch_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)3510*44704f69SBart Van Assche show_last_n_mode_pg_data_ch_page(const uint8_t * resp, int len,
3511*44704f69SBart Van Assche                                  struct opts_t * op, sgj_opaque_p jop)
3512*44704f69SBart Van Assche {
3513*44704f69SBart Van Assche     bool spf;
3514*44704f69SBart Van Assche     int j, k, num, pl, pg_code, spg_code;
3515*44704f69SBart Van Assche     uint32_t n;
3516*44704f69SBart Van Assche     const uint8_t * bp;
3517*44704f69SBart Van Assche     const char * mode_pg_name = NULL;
3518*44704f69SBart Van Assche     sgj_state * jsp = &op->json_st;
3519*44704f69SBart Van Assche     sgj_opaque_p jo2p, jo4p;
3520*44704f69SBart Van Assche     sgj_opaque_p jo3p = NULL;
3521*44704f69SBart Van Assche     sgj_opaque_p jap = NULL;
3522*44704f69SBart Van Assche     sgj_opaque_p ja2p;
3523*44704f69SBart Van Assche     char str[PCB_STR_LEN];
3524*44704f69SBart Van Assche     char b[128];
3525*44704f69SBart Van Assche     static const char * lnmpdclp = "Last n mode page data changed log page";
3526*44704f69SBart Van Assche     static const char * mpdci = "Mode page data changed indicator";
3527*44704f69SBart Van Assche 
3528*44704f69SBart Van Assche     if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
3529*44704f69SBart Van Assche         sgj_pr_hr(jsp, "%s  [0xb,0x2]\n", lnmpdclp);
3530*44704f69SBart Van Assche     num = len - 4;
3531*44704f69SBart Van Assche     bp = &resp[0] + 4;
3532*44704f69SBart Van Assche     if (jsp->pr_as_json) {
3533*44704f69SBart Van Assche         jo2p = sg_log_js_hdr(jsp, jop, lnmpdclp, resp);
3534*44704f69SBart Van Assche         jap = sgj_named_subarray_r(jsp, jo2p,
3535*44704f69SBart Van Assche                                    "mode_page_data_changed_log_parameters");
3536*44704f69SBart Van Assche     }
3537*44704f69SBart Van Assche 
3538*44704f69SBart Van Assche     while (num > 3) {
3539*44704f69SBart Van Assche         int pc = sg_get_unaligned_be16(bp + 0);
3540*44704f69SBart Van Assche 
3541*44704f69SBart Van Assche         pl = bp[3] + 4;
3542*44704f69SBart Van Assche         if (op->filter_given) {
3543*44704f69SBart Van Assche             if (pc != op->filter)
3544*44704f69SBart Van Assche                 goto skip;
3545*44704f69SBart Van Assche         }
3546*44704f69SBart Van Assche         if (op->do_raw) {
3547*44704f69SBart Van Assche             dStrRaw(bp, pl);
3548*44704f69SBart Van Assche             break;
3549*44704f69SBart Van Assche         } else if (op->do_hex) {
3550*44704f69SBart Van Assche             hex2stdout(bp, pl, op->dstrhex_no_ascii);
3551*44704f69SBart Van Assche             break;
3552*44704f69SBart Van Assche         }
3553*44704f69SBart Van Assche         if (jsp->pr_as_json) {
3554*44704f69SBart Van Assche             jo3p = sgj_new_unattached_object_r(jsp);
3555*44704f69SBart Van Assche             if (op->do_pcb)
3556*44704f69SBart Van Assche                 js_pcb(jsp, jo3p, bp[2]);
3557*44704f69SBart Van Assche             sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL,
3558*44704f69SBart Van Assche                               0 == pc ? clgc : mpdci);
3559*44704f69SBart Van Assche         }
3560*44704f69SBart Van Assche         if (0 == pc) {  /* Same as LAST_N_INQUIRY_DATA_CH_SUBPG [0xb,0x1] */
3561*44704f69SBart Van Assche             if (pl < 8)  {
3562*44704f69SBart Van Assche                 pr2serr("  <<expect parameter 0x%x to be at least 8 bytes "
3563*44704f69SBart Van Assche                         "long, got %d, skip>>\n", pc, pl);
3564*44704f69SBart Van Assche                 goto skip;
3565*44704f69SBart Van Assche             }
3566*44704f69SBart Van Assche             sgj_pr_hr(jsp, "  %s [pc=0x0]:\n", clgc);
3567*44704f69SBart Van Assche             for (j = 4, k = 1; j < pl; j +=4, ++k) {
3568*44704f69SBart Van Assche                 n = sg_get_unaligned_be32(bp + j);
3569*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "    %s [0x%x]: %u\n", cgn, k, n);
3570*44704f69SBart Van Assche             }
3571*44704f69SBart Van Assche             if (jsp->pr_as_json) {
3572*44704f69SBart Van Assche                 ja2p = sgj_named_subarray_r(jsp, jo3p,
3573*44704f69SBart Van Assche                                             "changed_generation_numbers");
3574*44704f69SBart Van Assche                 for (j = 4, k = 1; j < pl; j +=4, ++k) {
3575*44704f69SBart Van Assche                     jo4p = sgj_new_unattached_object_r(jsp);
3576*44704f69SBart Van Assche                     n = sg_get_unaligned_be32(bp + j);
3577*44704f69SBart Van Assche                     js_snakenv_ihexstr_nex(jsp, jo4p, cgn, n, true, NULL,
3578*44704f69SBart Van Assche                                            NULL, NULL);
3579*44704f69SBart Van Assche                     sgj_js_nv_o(jsp, ja2p, NULL /* name */, jo4p);
3580*44704f69SBart Van Assche                 }
3581*44704f69SBart Van Assche             }
3582*44704f69SBart Van Assche         } else {        /* pc > 0x0 */
3583*44704f69SBart Van Assche             int k, val;
3584*44704f69SBart Van Assche             const int nn = sg_lib_names_mode_len;
3585*44704f69SBart Van Assche             struct sg_lib_simple_value_name_t * nmp = sg_lib_names_mode_arr;
3586*44704f69SBart Van Assche 
3587*44704f69SBart Van Assche             snprintf(b, sizeof(b), "  %s 0x%x, ", param_c, pc);
3588*44704f69SBart Van Assche             spf = !! (0x40 & *(bp + 4));
3589*44704f69SBart Van Assche             pg_code = 0x3f & *(bp + 4);
3590*44704f69SBart Van Assche             spg_code = *(bp + 5);
3591*44704f69SBart Van Assche             if (spf)       /* SPF bit set */
3592*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "%smode page 0x%x,0%x changed\n", b, pg_code,
3593*44704f69SBart Van Assche                           spg_code);
3594*44704f69SBart Van Assche             else
3595*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "%smode page 0x%x changed\n", b, pg_code);
3596*44704f69SBart Van Assche 
3597*44704f69SBart Van Assche             val = (pg_code << 8) | spg_code;
3598*44704f69SBart Van Assche             for (k = 0; k < nn; ++k, ++nmp) {
3599*44704f69SBart Van Assche                 if (nmp->value == val)
3600*44704f69SBart Van Assche                     break;
3601*44704f69SBart Van Assche             }
3602*44704f69SBart Van Assche             mode_pg_name = (k < nn) ? nmp->name : NULL;
3603*44704f69SBart Van Assche             if ((0 == op->do_brief) && mode_pg_name)
3604*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "    name: %s\n", nmp->name);
3605*44704f69SBart Van Assche             if (jsp->pr_as_json) {
3606*44704f69SBart Van Assche                 sgj_js_nv_i(jsp, jo3p, "spf", (int)spf);
3607*44704f69SBart Van Assche                 sgj_js_nv_ihex(jsp, jo3p, "mode_page_code", pg_code);
3608*44704f69SBart Van Assche                 sgj_js_nv_ihex(jsp, jo3p, "subpage_code", spg_code);
3609*44704f69SBart Van Assche                 if (mode_pg_name)
3610*44704f69SBart Van Assche                     sgj_js_nv_s(jsp, jo3p, "mode_page_name", mode_pg_name);
3611*44704f69SBart Van Assche             }
3612*44704f69SBart Van Assche         }
3613*44704f69SBart Van Assche         if (op->do_pcb)
3614*44704f69SBart Van Assche             sgj_pr_hr(jsp, "        <%s>\n", get_pcb_str(bp[2],
3615*44704f69SBart Van Assche                       str, sizeof(str)));
3616*44704f69SBart Van Assche skip:
3617*44704f69SBart Van Assche         if (jsp->pr_as_json)
3618*44704f69SBart Van Assche             sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
3619*44704f69SBart Van Assche         if (op->filter_given)
3620*44704f69SBart Van Assche             break;
3621*44704f69SBart Van Assche         num -= pl;
3622*44704f69SBart Van Assche         bp += pl;
3623*44704f69SBart Van Assche     }
3624*44704f69SBart Van Assche     return true;
3625*44704f69SBart Van Assche }
3626*44704f69SBart Van Assche 
3627*44704f69SBart Van Assche static const char * self_test_code[] = {
3628*44704f69SBart Van Assche     "default", "background short", "background extended", rsv_s,
3629*44704f69SBart Van Assche     "aborted background", "foreground short", "foreground extended",
3630*44704f69SBart Van Assche     rsv_s};
3631*44704f69SBart Van Assche 
3632*44704f69SBart Van Assche static const char * self_test_result[] = {
3633*44704f69SBart Van Assche     "completed without error",
3634*44704f69SBart Van Assche     "aborted by SEND DIAGNOSTIC",
3635*44704f69SBart Van Assche     "aborted other than by SEND DIAGNOSTIC",
3636*44704f69SBart Van Assche     "unknown error, unable to complete",
3637*44704f69SBart Van Assche     "self test completed with failure in test segment (which one unknown)",
3638*44704f69SBart Van Assche     "first segment in self test failed",
3639*44704f69SBart Van Assche     "second segment in self test failed",
3640*44704f69SBart Van Assche     "another segment in self test failed",
3641*44704f69SBart Van Assche     rsv_s, rsv_s, rsv_s, rsv_s, rsv_s, rsv_s,
3642*44704f69SBart Van Assche     rsv_s,
3643*44704f69SBart Van Assche     "self test in progress"};
3644*44704f69SBart Van Assche 
3645*44704f69SBart Van Assche /* SELF_TEST_LPAGE [0x10] <str>  introduced: SPC-3 */
3646*44704f69SBart Van Assche static bool
show_self_test_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)3647*44704f69SBart Van Assche show_self_test_page(const uint8_t * resp, int len, struct opts_t * op,
3648*44704f69SBart Van Assche                     sgj_opaque_p jop)
3649*44704f69SBart Van Assche {
3650*44704f69SBart Van Assche     bool addr_all_ffs;
3651*44704f69SBart Van Assche     int k, num, res, st_c;
3652*44704f69SBart Van Assche     unsigned int v;
3653*44704f69SBart Van Assche     uint32_t n;
3654*44704f69SBart Van Assche     uint64_t ull;
3655*44704f69SBart Van Assche     const uint8_t * bp;
3656*44704f69SBart Van Assche     sgj_state * jsp = &op->json_st;
3657*44704f69SBart Van Assche     sgj_opaque_p jo2p;
3658*44704f69SBart Van Assche     sgj_opaque_p jo3p = NULL;
3659*44704f69SBart Van Assche     sgj_opaque_p jap = NULL;
3660*44704f69SBart Van Assche     char str[PCB_STR_LEN];
3661*44704f69SBart Van Assche     char b[80];
3662*44704f69SBart Van Assche     static const char * strlp = "Self-test results log page";
3663*44704f69SBart Van Assche     static const char * stc_s = "Self-test code";
3664*44704f69SBart Van Assche     static const char * str_s = "Self-test result";
3665*44704f69SBart Van Assche     static const char * stn_s = "Self-test number";
3666*44704f69SBart Van Assche     static const char * apoh = "Accumulated power on hours";
3667*44704f69SBart Van Assche 
3668*44704f69SBart Van Assche     num = len - 4;
3669*44704f69SBart Van Assche     if (num < 0x190) {
3670*44704f69SBart Van Assche         pr2serr("short %s [length 0x%x rather than 0x190 bytes]\n", strlp,
3671*44704f69SBart Van Assche                  num);
3672*44704f69SBart Van Assche         return false;
3673*44704f69SBart Van Assche     }
3674*44704f69SBart Van Assche     if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
3675*44704f69SBart Van Assche         sgj_pr_hr(jsp, "%s  [0x10]\n", strlp);
3676*44704f69SBart Van Assche     if (jsp->pr_as_json) {
3677*44704f69SBart Van Assche         jo2p = sg_log_js_hdr(jsp, jop, strlp, resp);
3678*44704f69SBart Van Assche         jap = sgj_named_subarray_r(jsp, jo2p,
3679*44704f69SBart Van Assche                                    "self_test_results_log_parameters");
3680*44704f69SBart Van Assche     }
3681*44704f69SBart Van Assche 
3682*44704f69SBart Van Assche     for (k = 0, bp = resp + 4; k < 20; ++k, bp += 20 ) {
3683*44704f69SBart Van Assche         int pc = sg_get_unaligned_be16(bp + 0);
3684*44704f69SBart Van Assche         int pl = bp[3] + 4;
3685*44704f69SBart Van Assche 
3686*44704f69SBart Van Assche         if (op->filter_given) {
3687*44704f69SBart Van Assche             if (pc != op->filter)
3688*44704f69SBart Van Assche                 continue;
3689*44704f69SBart Van Assche         }
3690*44704f69SBart Van Assche         if (op->do_raw) {
3691*44704f69SBart Van Assche             dStrRaw(bp, pl);
3692*44704f69SBart Van Assche             break;
3693*44704f69SBart Van Assche         } else if (op->do_hex) {
3694*44704f69SBart Van Assche             hex2stdout(bp, pl, op->dstrhex_no_ascii);
3695*44704f69SBart Van Assche             break;
3696*44704f69SBart Van Assche         }
3697*44704f69SBart Van Assche         if (jsp->pr_as_json) {
3698*44704f69SBart Van Assche             jo3p = sgj_new_unattached_object_r(jsp);
3699*44704f69SBart Van Assche             if (op->do_pcb)
3700*44704f69SBart Van Assche                 js_pcb(jsp, jo3p, bp[2]);
3701*44704f69SBart Van Assche             sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL,
3702*44704f69SBart Van Assche                               "Self-test results");
3703*44704f69SBart Van Assche         }
3704*44704f69SBart Van Assche         n = sg_get_unaligned_be16(bp + 6);
3705*44704f69SBart Van Assche         if ((0 == n) && (0 == bp[4])) {
3706*44704f69SBart Van Assche             if (jsp->pr_as_json)
3707*44704f69SBart Van Assche                 sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
3708*44704f69SBart Van Assche             break;
3709*44704f69SBart Van Assche         }
3710*44704f69SBart Van Assche         sgj_pr_hr(jsp, "  %s = %d, accumulated power-on hours = %d\n",
3711*44704f69SBart Van Assche                   param_c, pc, n);
3712*44704f69SBart Van Assche         st_c = (bp[4] >> 5) & 0x7;
3713*44704f69SBart Van Assche         sgj_pr_hr(jsp, "    %s: %s [%d]\n", stc_s, self_test_code[st_c],
3714*44704f69SBart Van Assche                   st_c);
3715*44704f69SBart Van Assche         res = bp[4] & 0xf;
3716*44704f69SBart Van Assche         sgj_pr_hr(jsp, "    %s: %s [%d]\n", str_s, self_test_result[res],
3717*44704f69SBart Van Assche                   res);
3718*44704f69SBart Van Assche         if (bp[5])
3719*44704f69SBart Van Assche             sgj_pr_hr(jsp, "    %s = %d\n", stn_s, (int)bp[5]);
3720*44704f69SBart Van Assche         ull = sg_get_unaligned_be64(bp + 8);
3721*44704f69SBart Van Assche 
3722*44704f69SBart Van Assche         addr_all_ffs = sg_all_ffs(bp + 8, 8);
3723*44704f69SBart Van Assche         if (! addr_all_ffs) {
3724*44704f69SBart Van Assche             addr_all_ffs = false;
3725*44704f69SBart Van Assche             if ((res > 0) && ( res < 0xf))
3726*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "    address of first error = 0x%" PRIx64 "\n",
3727*44704f69SBart Van Assche                           ull);
3728*44704f69SBart Van Assche         }
3729*44704f69SBart Van Assche             addr_all_ffs = false;
3730*44704f69SBart Van Assche         v = bp[16] & 0xf;
3731*44704f69SBart Van Assche         if (v) {
3732*44704f69SBart Van Assche             if (op->do_brief)
3733*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "    %s = 0x%x , asc = 0x%x, ascq = 0x%x\n",
3734*44704f69SBart Van Assche                           s_key, v, bp[17], bp[18]);
3735*44704f69SBart Van Assche             else {
3736*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "    %s = 0x%x [%s]\n", s_key, v,
3737*44704f69SBart Van Assche                           sg_get_sense_key_str(v, sizeof(b), b));
3738*44704f69SBart Van Assche 
3739*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "      asc = 0x%x, ascq = 0x%x [%s]\n",
3740*44704f69SBart Van Assche                           bp[17], bp[18], sg_get_asc_ascq_str(bp[17], bp[18],
3741*44704f69SBart Van Assche                           sizeof(b), b));
3742*44704f69SBart Van Assche             }
3743*44704f69SBart Van Assche         }
3744*44704f69SBart Van Assche         if (op->do_pcb)
3745*44704f69SBart Van Assche             sgj_pr_hr(jsp, "        <%s>\n", get_pcb_str(bp[2],
3746*44704f69SBart Van Assche                       str, sizeof(str)));
3747*44704f69SBart Van Assche         if (jsp->pr_as_json) {
3748*44704f69SBart Van Assche             js_snakenv_ihexstr_nex(jsp, jo3p, stc_s, st_c, true, NULL,
3749*44704f69SBart Van Assche                                    self_test_code[st_c], NULL);
3750*44704f69SBart Van Assche             js_snakenv_ihexstr_nex(jsp, jo3p, str_s, res, true, NULL,
3751*44704f69SBart Van Assche                                     self_test_result[res], NULL);
3752*44704f69SBart Van Assche             js_snakenv_ihexstr_nex(jsp, jo3p, stn_s, bp[5], false, NULL,
3753*44704f69SBart Van Assche                                    NULL, "segment number that failed");
3754*44704f69SBart Van Assche             js_snakenv_ihexstr_nex(jsp, jo3p, apoh, n, true, NULL,
3755*44704f69SBart Van Assche                    (0xffff == n ? "65535 hours or more" : NULL), NULL);
3756*44704f69SBart Van Assche             sgj_js_nv_ihexstr(jsp, jo3p, "address_of_first_failure", pc, NULL,
3757*44704f69SBart Van Assche                               addr_all_ffs ? "no errors detected" : NULL);
3758*44704f69SBart Van Assche             sgj_js_nv_ihexstr(jsp, jo3p, "sense_key", v, NULL,
3759*44704f69SBart Van Assche                               sg_get_sense_key_str(v, sizeof(b), b));
3760*44704f69SBart Van Assche             sgj_js_nv_ihexstr(jsp, jo3p, "additional_sense_code", bp[17],
3761*44704f69SBart Van Assche                               NULL, NULL);
3762*44704f69SBart Van Assche             sgj_js_nv_ihexstr(jsp, jo3p, "additional_sense_code_qualifier",
3763*44704f69SBart Van Assche                               bp[18], NULL, sg_get_asc_ascq_str(bp[17],
3764*44704f69SBart Van Assche                               bp[18], sizeof(b), b));
3765*44704f69SBart Van Assche             sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
3766*44704f69SBart Van Assche         }
3767*44704f69SBart Van Assche         if (op->filter_given)
3768*44704f69SBart Van Assche             break;
3769*44704f69SBart Van Assche     }
3770*44704f69SBart Van Assche     return true;
3771*44704f69SBart Van Assche }
3772*44704f69SBart Van Assche 
3773*44704f69SBart Van Assche /* TEMPERATURE_LPAGE [0xd] <temp>  introduced: SPC-3
3774*44704f69SBart Van Assche  * N.B. The ENV_REPORTING_SUBPG [0xd,0x1] and the ENV_LIMITS_SUBPG [0xd,0x2]
3775*44704f69SBart Van Assche  * (both added SPC-5) are a superset of this page. */
3776*44704f69SBart Van Assche static bool
show_temperature_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)3777*44704f69SBart Van Assche show_temperature_page(const uint8_t * resp, int len, struct opts_t * op,
3778*44704f69SBart Van Assche                       sgj_opaque_p jop)
3779*44704f69SBart Van Assche {
3780*44704f69SBart Van Assche     int k, num, extra;
3781*44704f69SBart Van Assche     const uint8_t * bp;
3782*44704f69SBart Van Assche     sgj_state * jsp = &op->json_st;
3783*44704f69SBart Van Assche     sgj_opaque_p jo2p;
3784*44704f69SBart Van Assche     sgj_opaque_p jo3p = NULL;
3785*44704f69SBart Van Assche     sgj_opaque_p jap = NULL;
3786*44704f69SBart Van Assche     char str[PCB_STR_LEN];
3787*44704f69SBart Van Assche     static const char * tlp = "Temperature log page";
3788*44704f69SBart Van Assche     static const char * ctemp = "Current temperature";
3789*44704f69SBart Van Assche     static const char * rtemp = "Reference temperature";
3790*44704f69SBart Van Assche 
3791*44704f69SBart Van Assche     num = len - 4;
3792*44704f69SBart Van Assche     bp = &resp[0] + 4;
3793*44704f69SBart Van Assche     if (num < 4) {
3794*44704f69SBart Van Assche         pr2serr("badly formed Temperature page\n");
3795*44704f69SBart Van Assche         return false;
3796*44704f69SBart Van Assche     }
3797*44704f69SBart Van Assche     if (op->verbose || ((! op->do_raw) && (0 == op->do_hex))) {
3798*44704f69SBart Van Assche         if (! op->do_temperature)
3799*44704f69SBart Van Assche             sgj_pr_hr(jsp, "%s  [0xd]\n", tlp);
3800*44704f69SBart Van Assche     }
3801*44704f69SBart Van Assche     if (jsp->pr_as_json) {
3802*44704f69SBart Van Assche         jo2p = sg_log_js_hdr(jsp, jop, tlp, resp);
3803*44704f69SBart Van Assche         jap = sgj_named_subarray_r(jsp, jo2p, "temperature_log_parameters");
3804*44704f69SBart Van Assche     }
3805*44704f69SBart Van Assche 
3806*44704f69SBart Van Assche     for (k = num; k > 0; k -= extra, bp += extra) {
3807*44704f69SBart Van Assche         int pc;
3808*44704f69SBart Van Assche 
3809*44704f69SBart Van Assche         if (k < 3) {
3810*44704f69SBart Van Assche             pr2serr("short Temperature page\n");
3811*44704f69SBart Van Assche             return true;
3812*44704f69SBart Van Assche         }
3813*44704f69SBart Van Assche         extra = bp[3] + 4;
3814*44704f69SBart Van Assche         pc = sg_get_unaligned_be16(bp + 0);
3815*44704f69SBart Van Assche         if (op->filter_given) {
3816*44704f69SBart Van Assche             if (pc != op->filter)
3817*44704f69SBart Van Assche                 continue;
3818*44704f69SBart Van Assche         }
3819*44704f69SBart Van Assche         if (op->do_raw) {
3820*44704f69SBart Van Assche             dStrRaw(bp, extra);
3821*44704f69SBart Van Assche             goto skip;
3822*44704f69SBart Van Assche         } else if (op->do_hex) {
3823*44704f69SBart Van Assche             hex2stdout(bp, extra, op->dstrhex_no_ascii);
3824*44704f69SBart Van Assche             goto skip;
3825*44704f69SBart Van Assche         }
3826*44704f69SBart Van Assche         if (jsp->pr_as_json) {
3827*44704f69SBart Van Assche             jo3p = sgj_new_unattached_object_r(jsp);
3828*44704f69SBart Van Assche             if (op->do_pcb)
3829*44704f69SBart Van Assche                 js_pcb(jsp, jo3p, bp[2]);
3830*44704f69SBart Van Assche             sgj_js_nv_ihex(jsp, jo3p, param_c_sn, pc);
3831*44704f69SBart Van Assche         }
3832*44704f69SBart Van Assche 
3833*44704f69SBart Van Assche         switch (pc) {
3834*44704f69SBart Van Assche         case 0:
3835*44704f69SBart Van Assche             if ((extra > 5) && (k > 5)) {
3836*44704f69SBart Van Assche                 if (0 == bp[5])
3837*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "  %s = 0 C (or less)\n", ctemp);
3838*44704f69SBart Van Assche                 else if (bp[5] < 0xff)
3839*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "  %s = %d C\n", ctemp, bp[5]);
3840*44704f69SBart Van Assche                 else
3841*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "  %s = <%s>\n", ctemp, not_avail);
3842*44704f69SBart Van Assche                 if (jsp->pr_as_json) {
3843*44704f69SBart Van Assche                     const char * cp = NULL;
3844*44704f69SBart Van Assche 
3845*44704f69SBart Van Assche                     if (0 == bp[5])
3846*44704f69SBart Van Assche                         cp = "0 or less Celsius";
3847*44704f69SBart Van Assche                     else if (0xff == bp[5])
3848*44704f69SBart Van Assche                         cp = "temperature not available";
3849*44704f69SBart Van Assche                     js_snakenv_ihexstr_nex(jsp, jo3p, "temperature", bp[5],
3850*44704f69SBart Van Assche                                            false, NULL, cp,
3851*44704f69SBart Van Assche                                            "current [unit: celsius]");
3852*44704f69SBart Van Assche                 }
3853*44704f69SBart Van Assche             }
3854*44704f69SBart Van Assche             break;
3855*44704f69SBart Van Assche         case 1:
3856*44704f69SBart Van Assche             if ((extra > 5) && (k > 5)) {
3857*44704f69SBart Van Assche                 if (bp[5] < 0xff)
3858*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "  %s = %d C\n", rtemp, bp[5]);
3859*44704f69SBart Van Assche                 else
3860*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "  %s = <%s>\n", rtemp, not_avail);
3861*44704f69SBart Van Assche                 if (jsp->pr_as_json) {
3862*44704f69SBart Van Assche                     const char * cp;
3863*44704f69SBart Van Assche 
3864*44704f69SBart Van Assche                     if (0 == bp[5])
3865*44704f69SBart Van Assche                         cp = "in C (or less)";
3866*44704f69SBart Van Assche                     else if (0xff == bp[5])
3867*44704f69SBart Van Assche                         cp = not_avail;
3868*44704f69SBart Van Assche                     else
3869*44704f69SBart Van Assche                         cp = "in C";
3870*44704f69SBart Van Assche                     sgj_js_nv_ihex_nex(jsp, jo3p, "reference_temperature",
3871*44704f69SBart Van Assche                                        bp[5], true, cp);
3872*44704f69SBart Van Assche                 }
3873*44704f69SBart Van Assche             }
3874*44704f69SBart Van Assche             break;
3875*44704f69SBart Van Assche         default:
3876*44704f69SBart Van Assche             if (! op->do_temperature) {
3877*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  unknown %s = 0x%x, contents in hex:\n",
3878*44704f69SBart Van Assche                           param_c, pc);
3879*44704f69SBart Van Assche                 hex2stdout(bp, extra, op->dstrhex_no_ascii);
3880*44704f69SBart Van Assche             } else {
3881*44704f69SBart Van Assche                 if (jsp->pr_as_json)
3882*44704f69SBart Van Assche                     sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
3883*44704f69SBart Van Assche                 continue;
3884*44704f69SBart Van Assche             }
3885*44704f69SBart Van Assche             break;
3886*44704f69SBart Van Assche         }
3887*44704f69SBart Van Assche         if (jsp->pr_as_json)
3888*44704f69SBart Van Assche             sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
3889*44704f69SBart Van Assche         if (op->do_pcb)
3890*44704f69SBart Van Assche             sgj_pr_hr(jsp, "        <%s>\n", get_pcb_str(bp[2], str,
3891*44704f69SBart Van Assche                       sizeof(str)));
3892*44704f69SBart Van Assche skip:
3893*44704f69SBart Van Assche         if (op->filter_given)
3894*44704f69SBart Van Assche             break;
3895*44704f69SBart Van Assche     }
3896*44704f69SBart Van Assche     return true;
3897*44704f69SBart Van Assche }
3898*44704f69SBart Van Assche 
3899*44704f69SBart Van Assche /* START_STOP_LPAGE [0xe] <sscc>  introduced: SPC-3 */
3900*44704f69SBart Van Assche static bool
show_start_stop_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)3901*44704f69SBart Van Assche show_start_stop_page(const uint8_t * resp, int len, struct opts_t * op,
3902*44704f69SBart Van Assche                      sgj_opaque_p jop)
3903*44704f69SBart Van Assche {
3904*44704f69SBart Van Assche     int k, num, extra;
3905*44704f69SBart Van Assche     uint32_t val;
3906*44704f69SBart Van Assche     const uint8_t * bp;
3907*44704f69SBart Van Assche     sgj_state * jsp = &op->json_st;
3908*44704f69SBart Van Assche     sgj_opaque_p jo2p;
3909*44704f69SBart Van Assche     sgj_opaque_p jo3p = NULL;
3910*44704f69SBart Van Assche     sgj_opaque_p jap = NULL;
3911*44704f69SBart Van Assche     char str[PCB_STR_LEN];
3912*44704f69SBart Van Assche     char b[256];
3913*44704f69SBart Van Assche     static const char * sscclp = "Start-stop cycle counter log page";
3914*44704f69SBart Van Assche     static const char * dom = "Date of manufacture";
3915*44704f69SBart Van Assche     static const char * ad = "Accounting date";
3916*44704f69SBart Van Assche     static const char * sccodl = "Specified cycle count over device lifetime";
3917*44704f69SBart Van Assche     static const char * assc = "Accumulated start-stop cycles";
3918*44704f69SBart Van Assche     static const char * slucodl =
3919*44704f69SBart Van Assche                         "Specified load-unload count over device lifetime";
3920*44704f69SBart Van Assche     static const char * aluc = "Accumulated load-unload cycles";
3921*44704f69SBart Van Assche 
3922*44704f69SBart Van Assche     num = len - 4;
3923*44704f69SBart Van Assche     bp = &resp[0] + 4;
3924*44704f69SBart Van Assche     if (num < 4) {
3925*44704f69SBart Van Assche         pr2serr("badly formed Start-stop cycle counter page\n");
3926*44704f69SBart Van Assche         return false;
3927*44704f69SBart Van Assche     }
3928*44704f69SBart Van Assche     if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
3929*44704f69SBart Van Assche         sgj_pr_hr(jsp, "%s  [0xe]\n", sscclp);
3930*44704f69SBart Van Assche     if (jsp->pr_as_json) {
3931*44704f69SBart Van Assche         jo2p = sg_log_js_hdr(jsp, jop, sscclp, resp);
3932*44704f69SBart Van Assche         jap = sgj_named_subarray_r(jsp, jo2p,
3933*44704f69SBart Van Assche                                    "start_stop_cycle_log_parameters");
3934*44704f69SBart Van Assche     }
3935*44704f69SBart Van Assche 
3936*44704f69SBart Van Assche     for (k = num; k > 0; k -= extra, bp += extra) {
3937*44704f69SBart Van Assche         int pc;
3938*44704f69SBart Van Assche 
3939*44704f69SBart Van Assche         if (k < 3) {
3940*44704f69SBart Van Assche             pr2serr("short %s\n", sscclp);
3941*44704f69SBart Van Assche             return false;
3942*44704f69SBart Van Assche         }
3943*44704f69SBart Van Assche         extra = bp[3] + 4;
3944*44704f69SBart Van Assche         pc = sg_get_unaligned_be16(bp + 0);
3945*44704f69SBart Van Assche         if (op->filter_given) {
3946*44704f69SBart Van Assche             if (pc != op->filter)
3947*44704f69SBart Van Assche                 continue;
3948*44704f69SBart Van Assche         }
3949*44704f69SBart Van Assche         if (op->do_raw) {
3950*44704f69SBart Van Assche             dStrRaw(bp, extra);
3951*44704f69SBart Van Assche             goto skip;
3952*44704f69SBart Van Assche         } else if (op->do_hex) {
3953*44704f69SBart Van Assche             hex2stdout(bp, extra, op->dstrhex_no_ascii);
3954*44704f69SBart Van Assche             goto skip;
3955*44704f69SBart Van Assche         }
3956*44704f69SBart Van Assche         if (jsp->pr_as_json) {
3957*44704f69SBart Van Assche             jo3p = sgj_new_unattached_object_r(jsp);
3958*44704f69SBart Van Assche             if (op->do_pcb)
3959*44704f69SBart Van Assche                 js_pcb(jsp, jo3p, bp[2]);
3960*44704f69SBart Van Assche         }
3961*44704f69SBart Van Assche 
3962*44704f69SBart Van Assche         switch (pc) {
3963*44704f69SBart Van Assche         case 1:
3964*44704f69SBart Van Assche             if (10 == extra) {
3965*44704f69SBart Van Assche                  sgj_pr_hr(jsp, "  %s, year: %.4s, week: %.2s\n", dom,
3966*44704f69SBart Van Assche                        bp + 4, bp + 8);
3967*44704f69SBart Van Assche                 if (jsp->pr_as_json) {
3968*44704f69SBart Van Assche                     sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL,
3969*44704f69SBart Van Assche                                       "Date of manufacture");
3970*44704f69SBart Van Assche                     sgj_js_nv_s_len(jsp, jo3p, "year_of_manufacture",
3971*44704f69SBart Van Assche                                     (const char *)(bp + 4), 4);
3972*44704f69SBart Van Assche                     sgj_js_nv_s_len(jsp, jo3p, "week_of_manufacture",
3973*44704f69SBart Van Assche                                     (const char *)(bp + 8), 2);
3974*44704f69SBart Van Assche                 }
3975*44704f69SBart Van Assche             } else if (op->verbose) {
3976*44704f69SBart Van Assche                 pr2serr("%s parameter length strange: %d\n", dom, extra - 4);
3977*44704f69SBart Van Assche                 hex2stderr(bp, extra, 1);
3978*44704f69SBart Van Assche             }
3979*44704f69SBart Van Assche             break;
3980*44704f69SBart Van Assche         case 2:
3981*44704f69SBart Van Assche             if (10 == extra) {
3982*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  %s, year: %.4s, week: %.2s\n", ad, bp + 4,
3983*44704f69SBart Van Assche                           bp + 8);
3984*44704f69SBart Van Assche                 if (jsp->pr_as_json) {
3985*44704f69SBart Van Assche                     sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL,
3986*44704f69SBart Van Assche                                       "Accounting date");
3987*44704f69SBart Van Assche                     sgj_js_nv_s_len(jsp, jo3p, "year_of_manufacture",
3988*44704f69SBart Van Assche                                     (const char *)(bp + 4), 4);
3989*44704f69SBart Van Assche                     sgj_js_nv_s_len(jsp, jo3p, "week_of_manufacture",
3990*44704f69SBart Van Assche                                     (const char *)(bp + 8), 2);
3991*44704f69SBart Van Assche                 }
3992*44704f69SBart Van Assche             } else if (op->verbose) {
3993*44704f69SBart Van Assche                 pr2serr("%s parameter length strange: %d\n", ad, extra - 4);
3994*44704f69SBart Van Assche                 hex2stderr(bp, extra, 1);
3995*44704f69SBart Van Assche             }
3996*44704f69SBart Van Assche             break;
3997*44704f69SBart Van Assche         case 3:
3998*44704f69SBart Van Assche             if (extra > 7) {
3999*44704f69SBart Van Assche                 val = sg_get_unaligned_be32(bp + 4);
4000*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  %s = %u\n", sccodl, val);
4001*44704f69SBart Van Assche                 if (jsp->pr_as_json) {
4002*44704f69SBart Van Assche                     sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL,
4003*44704f69SBart Van Assche                                       sccodl);
4004*44704f69SBart Van Assche                     js_snakenv_ihexstr_nex(jsp, jo3p, sccodl, val, false,
4005*44704f69SBart Van Assche                                            NULL, NULL, NULL);
4006*44704f69SBart Van Assche                 }
4007*44704f69SBart Van Assche             }
4008*44704f69SBart Van Assche             break;
4009*44704f69SBart Van Assche         case 4:
4010*44704f69SBart Van Assche             if (extra > 7) {
4011*44704f69SBart Van Assche                 val = sg_get_unaligned_be32(bp + 4);
4012*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  %s = %u\n", assc, val);
4013*44704f69SBart Van Assche                 if (jsp->pr_as_json) {
4014*44704f69SBart Van Assche                     sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL,
4015*44704f69SBart Van Assche                                       assc);
4016*44704f69SBart Van Assche                     js_snakenv_ihexstr_nex(jsp, jo3p, assc, val, false,
4017*44704f69SBart Van Assche                                            NULL, NULL, NULL);
4018*44704f69SBart Van Assche                 }
4019*44704f69SBart Van Assche             }
4020*44704f69SBart Van Assche             break;
4021*44704f69SBart Van Assche         case 5:
4022*44704f69SBart Van Assche             if (extra > 7) {
4023*44704f69SBart Van Assche                 val = sg_get_unaligned_be32(bp + 4);
4024*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  %s = %u\n", slucodl, val);
4025*44704f69SBart Van Assche                 if (jsp->pr_as_json) {
4026*44704f69SBart Van Assche                     sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL,
4027*44704f69SBart Van Assche                                       slucodl);
4028*44704f69SBart Van Assche                     js_snakenv_ihexstr_nex(jsp, jo3p, slucodl, val, false,
4029*44704f69SBart Van Assche                                            NULL, NULL, NULL);
4030*44704f69SBart Van Assche                 }
4031*44704f69SBart Van Assche             }
4032*44704f69SBart Van Assche             break;
4033*44704f69SBart Van Assche         case 6:
4034*44704f69SBart Van Assche             if (extra > 7) {
4035*44704f69SBart Van Assche                 val = sg_get_unaligned_be32(bp + 4);
4036*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  %s = %u\n", aluc, val);
4037*44704f69SBart Van Assche                 if (jsp->pr_as_json) {
4038*44704f69SBart Van Assche                     sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, aluc);
4039*44704f69SBart Van Assche                     js_snakenv_ihexstr_nex(jsp, jo3p, aluc, val, false,
4040*44704f69SBart Van Assche                                            NULL, NULL, NULL);
4041*44704f69SBart Van Assche                 }
4042*44704f69SBart Van Assche             }
4043*44704f69SBart Van Assche             break;
4044*44704f69SBart Van Assche         default:
4045*44704f69SBart Van Assche             sgj_pr_hr(jsp, "  unknown %s = 0x%x, contents in hex:\n",
4046*44704f69SBart Van Assche                       param_c, pc);
4047*44704f69SBart Van Assche             hex2str(bp, extra, "    ", op->hex2str_oformat, sizeof(b), b);
4048*44704f69SBart Van Assche             sgj_pr_hr(jsp, "%s\n", b);
4049*44704f69SBart Van Assche             if (jsp->pr_as_json) {
4050*44704f69SBart Van Assche                 sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, unknown_s);
4051*44704f69SBart Van Assche                 sgj_js_nv_hex_bytes(jsp, jo3p, in_hex, bp, extra);
4052*44704f69SBart Van Assche             }
4053*44704f69SBart Van Assche             break;
4054*44704f69SBart Van Assche         }
4055*44704f69SBart Van Assche         if (jsp->pr_as_json)
4056*44704f69SBart Van Assche             sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
4057*44704f69SBart Van Assche         if (op->do_pcb)
4058*44704f69SBart Van Assche             sgj_pr_hr(jsp, "        <%s>\n", get_pcb_str(bp[2], str,
4059*44704f69SBart Van Assche                       sizeof(str)));
4060*44704f69SBart Van Assche skip:
4061*44704f69SBart Van Assche         if (op->filter_given)
4062*44704f69SBart Van Assche             break;
4063*44704f69SBart Van Assche     }
4064*44704f69SBart Van Assche     return true;
4065*44704f69SBart Van Assche }
4066*44704f69SBart Van Assche 
4067*44704f69SBart Van Assche /* APP_CLIENT_LPAGE [0xf] <ac>  introduced: SPC-3 */
4068*44704f69SBart Van Assche static bool
show_app_client_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)4069*44704f69SBart Van Assche show_app_client_page(const uint8_t * resp, int len, struct opts_t * op,
4070*44704f69SBart Van Assche                      sgj_opaque_p jop)
4071*44704f69SBart Van Assche {
4072*44704f69SBart Van Assche     int k, n, num, extra;
4073*44704f69SBart Van Assche     char * mp;
4074*44704f69SBart Van Assche     const uint8_t * bp;
4075*44704f69SBart Van Assche     sgj_state * jsp = &op->json_st;
4076*44704f69SBart Van Assche     sgj_opaque_p jo2p = NULL;
4077*44704f69SBart Van Assche     sgj_opaque_p jo3p = NULL;
4078*44704f69SBart Van Assche     sgj_opaque_p jap = NULL;
4079*44704f69SBart Van Assche     char str[PCB_STR_LEN];
4080*44704f69SBart Van Assche     static const char * aclp = "Application Client log page";
4081*44704f69SBart Van Assche     static const char * guac = "General Usage Application Client";
4082*44704f69SBart Van Assche 
4083*44704f69SBart Van Assche     num = len - 4;
4084*44704f69SBart Van Assche     bp = &resp[0] + 4;
4085*44704f69SBart Van Assche     if (num < 4) {
4086*44704f69SBart Van Assche         pr2serr("badly formed %s\n", aclp);
4087*44704f69SBart Van Assche         return false;
4088*44704f69SBart Van Assche     }
4089*44704f69SBart Van Assche     if (op->verbose || ((! op->do_raw) && (op->do_hex == 0)))
4090*44704f69SBart Van Assche         sgj_pr_hr(jsp, "%s  [0xf]\n", aclp);
4091*44704f69SBart Van Assche     if (jsp->pr_as_json)
4092*44704f69SBart Van Assche         jo2p = sg_log_js_hdr(jsp, jop, aclp, resp);
4093*44704f69SBart Van Assche     if ((0 == op->filter_given) && (! op->do_full)) {
4094*44704f69SBart Van Assche         if ((len > 128) && (0 == op->do_hex) && (0 == op->undefined_hex)) {
4095*44704f69SBart Van Assche             char d[256];
4096*44704f69SBart Van Assche 
4097*44704f69SBart Van Assche             hex2str(resp, 64, "  ", op->hex2str_oformat, sizeof(d), d);
4098*44704f69SBart Van Assche             sgj_pr_hr(jsp, "%s", d);
4099*44704f69SBart Van Assche             sgj_pr_hr(jsp, "  .....  [truncated after 64 of %d bytes (use "
4100*44704f69SBart Van Assche                       "'-H' to see the rest)]\n", len);
4101*44704f69SBart Van Assche             if (jsp->pr_as_json) {
4102*44704f69SBart Van Assche                 sgj_js_nv_ihex(jsp, jo2p, "actual_length", len);
4103*44704f69SBart Van Assche                 sgj_js_nv_ihex(jsp, jo2p, "truncated_length", 64);
4104*44704f69SBart Van Assche                 sgj_js_nv_hex_bytes(jsp, jo2p, in_hex, resp, 64);
4105*44704f69SBart Van Assche             }
4106*44704f69SBart Van Assche         } else {
4107*44704f69SBart Van Assche             n = len * 4 + 32;
4108*44704f69SBart Van Assche             mp = malloc(n);
4109*44704f69SBart Van Assche             if (mp) {
4110*44704f69SBart Van Assche                 hex2str(resp, len, "  ", op->hex2str_oformat, n, mp);
4111*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "%s", mp);
4112*44704f69SBart Van Assche                 if (jsp->pr_as_json) {
4113*44704f69SBart Van Assche                     sgj_js_nv_ihex(jsp, jo2p, "length", len);
4114*44704f69SBart Van Assche                     sgj_js_nv_hex_bytes(jsp, jo2p, in_hex, resp, len);
4115*44704f69SBart Van Assche                 }
4116*44704f69SBart Van Assche                 free(mp);
4117*44704f69SBart Van Assche             }
4118*44704f69SBart Van Assche         }
4119*44704f69SBart Van Assche         return true;
4120*44704f69SBart Van Assche     }
4121*44704f69SBart Van Assche     if (jsp->pr_as_json)
4122*44704f69SBart Van Assche         jap = sgj_named_subarray_r(jsp, jo2p,
4123*44704f69SBart Van Assche                                    "application_client_log_parameters");
4124*44704f69SBart Van Assche 
4125*44704f69SBart Van Assche     /* here if filter_given set or --full given */
4126*44704f69SBart Van Assche     for (k = num; k > 0; k -= extra, bp += extra) {
4127*44704f69SBart Van Assche         int pc;
4128*44704f69SBart Van Assche         char d[1024];
4129*44704f69SBart Van Assche 
4130*44704f69SBart Van Assche         if (k < 3) {
4131*44704f69SBart Van Assche             pr2serr("short %s\n", aclp);
4132*44704f69SBart Van Assche             return true;
4133*44704f69SBart Van Assche         }
4134*44704f69SBart Van Assche         extra = bp[3] + 4;
4135*44704f69SBart Van Assche         pc = sg_get_unaligned_be16(bp + 0);
4136*44704f69SBart Van Assche         if (op->filter_given) {
4137*44704f69SBart Van Assche             if (pc != op->filter)
4138*44704f69SBart Van Assche                 continue;
4139*44704f69SBart Van Assche         }
4140*44704f69SBart Van Assche         if (op->do_raw) {
4141*44704f69SBart Van Assche             dStrRaw(bp, extra);
4142*44704f69SBart Van Assche             break;
4143*44704f69SBart Van Assche         }
4144*44704f69SBart Van Assche         if (jsp->pr_as_json) {
4145*44704f69SBart Van Assche             jo3p = sgj_new_unattached_object_r(jsp);
4146*44704f69SBart Van Assche             if (op->do_pcb)
4147*44704f69SBart Van Assche                 js_pcb(jsp, jo3p, bp[2]);
4148*44704f69SBart Van Assche         }
4149*44704f69SBart Van Assche         sgj_pr_hr(jsp, "  %s = %d [0x%x] %s\n", param_c, pc, pc,
4150*44704f69SBart Van Assche                   (pc <= 0xfff) ? guac : "");
4151*44704f69SBart Van Assche         hex2str(bp, extra, "    ", op->hex2str_oformat, sizeof(d), d);
4152*44704f69SBart Van Assche         sgj_pr_hr(jsp, "%s", d);
4153*44704f69SBart Van Assche         if (jsp->pr_as_json) {
4154*44704f69SBart Van Assche             sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL,
4155*44704f69SBart Van Assche                               (pc <= 0xfff) ? guac : NULL);
4156*44704f69SBart Van Assche             sgj_js_nv_hex_bytes(jsp, jo3p, in_hex, bp, extra);
4157*44704f69SBart Van Assche             sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
4158*44704f69SBart Van Assche         }
4159*44704f69SBart Van Assche         if (op->do_pcb)
4160*44704f69SBart Van Assche             sgj_pr_hr(jsp, "        <%s>\n", get_pcb_str(bp[2], str,
4161*44704f69SBart Van Assche                       sizeof(str)));
4162*44704f69SBart Van Assche         if (op->filter_given)
4163*44704f69SBart Van Assche             break;
4164*44704f69SBart Van Assche     }
4165*44704f69SBart Van Assche     return true;
4166*44704f69SBart Van Assche }
4167*44704f69SBart Van Assche 
4168*44704f69SBart Van Assche /* IE_LPAGE [0x2f] <ie> "Informational Exceptions"  introduced: SPC-3
4169*44704f69SBart Van Assche  * Previously known as "SMART Status and Temperature Reading" lpage.  */
4170*44704f69SBart Van Assche static bool
show_ie_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)4171*44704f69SBart Van Assche show_ie_page(const uint8_t * resp, int len, struct opts_t * op,
4172*44704f69SBart Van Assche              sgj_opaque_p jop)
4173*44704f69SBart Van Assche {
4174*44704f69SBart Van Assche     bool skip = false;
4175*44704f69SBart Van Assche     int k, num, param_len;
4176*44704f69SBart Van Assche     const uint8_t * bp;
4177*44704f69SBart Van Assche     const char * cp;
4178*44704f69SBart Van Assche     sgj_state * jsp = &op->json_st;
4179*44704f69SBart Van Assche     sgj_opaque_p jo2p;
4180*44704f69SBart Van Assche     sgj_opaque_p jo3p = NULL;
4181*44704f69SBart Van Assche     sgj_opaque_p jap = NULL;
4182*44704f69SBart Van Assche     char str[PCB_STR_LEN];
4183*44704f69SBart Van Assche     char b[512];
4184*44704f69SBart Van Assche     char bb[64];
4185*44704f69SBart Van Assche     bool full, decoded;
4186*44704f69SBart Van Assche     static const char * ielp = "Informational exceptions log page";
4187*44704f69SBart Van Assche     static const char * ieasc =
4188*44704f69SBart Van Assche                          "informational_exceptions_additional_sense_code";
4189*44704f69SBart Van Assche     static const char * ct = "Current temperature";
4190*44704f69SBart Van Assche     static const char * tt = "Threshold temperature";
4191*44704f69SBart Van Assche     static const char * mt = "Maximum temperature";
4192*44704f69SBart Van Assche     static const char * ce = "common extension";
4193*44704f69SBart Van Assche 
4194*44704f69SBart Van Assche     full = ! op->do_temperature;
4195*44704f69SBart Van Assche     num = len - 4;
4196*44704f69SBart Van Assche     bp = &resp[0] + 4;
4197*44704f69SBart Van Assche     if (num < 4) {
4198*44704f69SBart Van Assche         pr2serr("badly formed %s\n", ielp);
4199*44704f69SBart Van Assche         return false;
4200*44704f69SBart Van Assche     }
4201*44704f69SBart Van Assche     if (op->verbose || ((! op->do_raw) && (0 == op->do_hex))) {
4202*44704f69SBart Van Assche         if (full)
4203*44704f69SBart Van Assche             sgj_pr_hr(jsp, "%s  [0x2f]\n", ielp);
4204*44704f69SBart Van Assche     }
4205*44704f69SBart Van Assche     if (jsp->pr_as_json) {
4206*44704f69SBart Van Assche         jo2p = sg_log_js_hdr(jsp, jop, ielp, resp);
4207*44704f69SBart Van Assche         jap = sgj_named_subarray_r(jsp, jo2p,
4208*44704f69SBart Van Assche                            "informational_exceptions_log_parameters");
4209*44704f69SBart Van Assche     }
4210*44704f69SBart Van Assche 
4211*44704f69SBart Van Assche     for (k = num; k > 0; k -= param_len, bp += param_len) {
4212*44704f69SBart Van Assche         int pc;
4213*44704f69SBart Van Assche 
4214*44704f69SBart Van Assche         if (k < 3) {
4215*44704f69SBart Van Assche             pr2serr("short %s\n", ielp);
4216*44704f69SBart Van Assche             return false;
4217*44704f69SBart Van Assche         }
4218*44704f69SBart Van Assche         param_len = bp[3] + 4;
4219*44704f69SBart Van Assche         pc = sg_get_unaligned_be16(bp + 0);
4220*44704f69SBart Van Assche         if (op->filter_given) {
4221*44704f69SBart Van Assche             if (pc != op->filter)
4222*44704f69SBart Van Assche                 continue;
4223*44704f69SBart Van Assche         }
4224*44704f69SBart Van Assche         if (op->do_raw) {
4225*44704f69SBart Van Assche             dStrRaw(bp, param_len);
4226*44704f69SBart Van Assche             goto skip;
4227*44704f69SBart Van Assche         } else if (op->do_hex) {
4228*44704f69SBart Van Assche             hex2stdout(bp, param_len, op->dstrhex_no_ascii);
4229*44704f69SBart Van Assche             goto skip;
4230*44704f69SBart Van Assche         }
4231*44704f69SBart Van Assche         if (jsp->pr_as_json) {
4232*44704f69SBart Van Assche             jo3p = sgj_new_unattached_object_r(jsp);
4233*44704f69SBart Van Assche             if (op->do_pcb)
4234*44704f69SBart Van Assche                 js_pcb(jsp, jo3p, bp[2]);
4235*44704f69SBart Van Assche         }
4236*44704f69SBart Van Assche         decoded = true;
4237*44704f69SBart Van Assche         cp = NULL;
4238*44704f69SBart Van Assche 
4239*44704f69SBart Van Assche         switch (pc) {
4240*44704f69SBart Van Assche         case 0x0:
4241*44704f69SBart Van Assche             if (param_len > 5) {
4242*44704f69SBart Van Assche                 bool na;
4243*44704f69SBart Van Assche                 uint8_t t;
4244*44704f69SBart Van Assche 
4245*44704f69SBart Van Assche                 if (full) {
4246*44704f69SBart Van Assche                      sgj_pr_hr(jsp, "  IE asc = 0x%x, ascq = 0x%x\n", bp[4],
4247*44704f69SBart Van Assche                                bp[5]);
4248*44704f69SBart Van Assche                     if (bp[4] || bp[5])
4249*44704f69SBart Van Assche                         if(sg_get_asc_ascq_str(bp[4], bp[5], sizeof(b), b))
4250*44704f69SBart Van Assche                              sgj_pr_hr(jsp, "    [%s]\n", b);
4251*44704f69SBart Van Assche                     if (jsp->pr_as_json) {
4252*44704f69SBart Van Assche                         sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL,
4253*44704f69SBart Van Assche                                           "Informational exceptions general");
4254*44704f69SBart Van Assche                         sgj_js_nv_ihexstr(jsp, jo3p, ieasc, bp[4], NULL,
4255*44704f69SBart Van Assche                                           NULL);
4256*44704f69SBart Van Assche                         snprintf(b, sizeof(b), "%s_qualifier", ieasc);
4257*44704f69SBart Van Assche                         sgj_js_nv_ihexstr(jsp, jo3p, b, bp[5], NULL,
4258*44704f69SBart Van Assche                                           sg_get_asc_ascq_str(bp[4], bp[5],
4259*44704f69SBart Van Assche                                           sizeof(bb), bb));
4260*44704f69SBart Van Assche                     }
4261*44704f69SBart Van Assche                 }
4262*44704f69SBart Van Assche                 if (param_len <= 6)
4263*44704f69SBart Van Assche                     break;
4264*44704f69SBart Van Assche                 t = bp[6];
4265*44704f69SBart Van Assche                 na = (0xff == t);
4266*44704f69SBart Van Assche                 if (na)
4267*44704f69SBart Van Assche                     snprintf(b, sizeof(b), "%u C", t);
4268*44704f69SBart Van Assche                 else
4269*44704f69SBart Van Assche                     snprintf(b, sizeof(b), "<%s>", unknown_s);
4270*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "    %s = %s\n", ct, b);
4271*44704f69SBart Van Assche                 if (jsp->pr_as_json)
4272*44704f69SBart Van Assche                     js_snakenv_ihexstr_nex(jsp, jo3p, ct, t, true,
4273*44704f69SBart Van Assche                                            NULL, na ? unknown_s : NULL,
4274*44704f69SBart Van Assche                                            "[unit: celsius]");
4275*44704f69SBart Van Assche                 if (param_len > 7) {
4276*44704f69SBart Van Assche                     t = bp[7];
4277*44704f69SBart Van Assche                     na = (0xff == t);
4278*44704f69SBart Van Assche                     if (na)
4279*44704f69SBart Van Assche                         snprintf(b, sizeof(b), "%u C", t);
4280*44704f69SBart Van Assche                     else
4281*44704f69SBart Van Assche                         snprintf(b, sizeof(b), "<%s>", unknown_s);
4282*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "    %s = %s  [%s]\n", tt, b, ce);
4283*44704f69SBart Van Assche                     if (jsp->pr_as_json)
4284*44704f69SBart Van Assche                         js_snakenv_ihexstr_nex(jsp, jo3p, tt, t, true, NULL,
4285*44704f69SBart Van Assche                                                na ? unknown_s : NULL, ce);
4286*44704f69SBart Van Assche                     t = bp[8];
4287*44704f69SBart Van Assche                     if ((param_len > 8) && (t >= bp[6])) {
4288*44704f69SBart Van Assche                         na = (0xff == t);
4289*44704f69SBart Van Assche                         if (na)
4290*44704f69SBart Van Assche                             snprintf(b, sizeof(b), "%u C", t);
4291*44704f69SBart Van Assche                         else
4292*44704f69SBart Van Assche                             snprintf(b, sizeof(b), "<%s>", unknown_s);
4293*44704f69SBart Van Assche                         sgj_pr_hr(jsp, "    %s = %s  [%s]\n", mt, b, ce);
4294*44704f69SBart Van Assche                         if (jsp->pr_as_json)
4295*44704f69SBart Van Assche                             js_snakenv_ihexstr_nex(jsp, jo3p, mt, t, true,
4296*44704f69SBart Van Assche                                                    NULL,
4297*44704f69SBart Van Assche                                                    na ? unknown_s : NULL, ce);
4298*44704f69SBart Van Assche                     }
4299*44704f69SBart Van Assche                 }
4300*44704f69SBart Van Assche             }
4301*44704f69SBart Van Assche             decoded = true;
4302*44704f69SBart Van Assche             break;
4303*44704f69SBart Van Assche         default:
4304*44704f69SBart Van Assche             if (op->do_brief > 0) {
4305*44704f69SBart Van Assche                 cp = NULL;
4306*44704f69SBart Van Assche                 skip = true;
4307*44704f69SBart Van Assche                 break;
4308*44704f69SBart Van Assche             }
4309*44704f69SBart Van Assche             if (VP_HITA == op->vend_prod_num) {
4310*44704f69SBart Van Assche                 switch (pc) {
4311*44704f69SBart Van Assche                 case 0x1:
4312*44704f69SBart Van Assche                     cp = "Remaining reserve 1";
4313*44704f69SBart Van Assche                     break;
4314*44704f69SBart Van Assche                 case 0x2:
4315*44704f69SBart Van Assche                     cp = "Remaining reserve XOR";
4316*44704f69SBart Van Assche                     break;
4317*44704f69SBart Van Assche                 case 0x3:
4318*44704f69SBart Van Assche                     cp = "XOR depletion";
4319*44704f69SBart Van Assche                     break;
4320*44704f69SBart Van Assche                 case 0x4:
4321*44704f69SBart Van Assche                     cp = "Volatile memory backup failure";
4322*44704f69SBart Van Assche                     break;
4323*44704f69SBart Van Assche                 case 0x5:
4324*44704f69SBart Van Assche                     cp = "Wear indicator";
4325*44704f69SBart Van Assche                     break;
4326*44704f69SBart Van Assche                 case 0x6:
4327*44704f69SBart Van Assche                     cp = "System area wear indicator";
4328*44704f69SBart Van Assche                     break;
4329*44704f69SBart Van Assche                 case 0x7:
4330*44704f69SBart Van Assche                     cp = "Channel hangs";
4331*44704f69SBart Van Assche                     break;
4332*44704f69SBart Van Assche                 case 0x8:
4333*44704f69SBart Van Assche                     cp = "Flash scan failure";
4334*44704f69SBart Van Assche                     break;
4335*44704f69SBart Van Assche                 default:
4336*44704f69SBart Van Assche                     decoded = false;
4337*44704f69SBart Van Assche                     break;
4338*44704f69SBart Van Assche                 }
4339*44704f69SBart Van Assche                 if (cp) {
4340*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "  %s:\n", cp);
4341*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "    SMART sense_code=0x%x sense_qualifier"
4342*44704f69SBart Van Assche                               "=0x%x threshold=%d%% trip=%d\n", bp[4], bp[5],
4343*44704f69SBart Van Assche                               bp[6], bp[7]);
4344*44704f69SBart Van Assche                     if (jsp->pr_as_json) {
4345*44704f69SBart Van Assche                         sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL,
4346*44704f69SBart Van Assche                                           cp);
4347*44704f69SBart Van Assche                         sgj_js_nv_ihex(jsp, jo3p, "smart_sense_code", bp[4]);
4348*44704f69SBart Van Assche                         sgj_js_nv_ihex(jsp, jo3p, "smart_sense_qualifier",
4349*44704f69SBart Van Assche                                        bp[5]);
4350*44704f69SBart Van Assche                         sgj_js_nv_ihex(jsp, jo3p, "smart_threshold", bp[6]);
4351*44704f69SBart Van Assche                         sgj_js_nv_ihex(jsp, jo3p, "smart_trip", bp[7]);
4352*44704f69SBart Van Assche                     }
4353*44704f69SBart Van Assche                 }
4354*44704f69SBart Van Assche             } else {
4355*44704f69SBart Van Assche                 decoded = false;
4356*44704f69SBart Van Assche                 if (jsp->pr_as_json)
4357*44704f69SBart Van Assche                     sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL,
4358*44704f69SBart Van Assche                                       unknown_s);
4359*44704f69SBart Van Assche             }
4360*44704f69SBart Van Assche             break;
4361*44704f69SBart Van Assche         }               /* end of switch statement */
4362*44704f69SBart Van Assche         if (skip)
4363*44704f69SBart Van Assche             skip = false;
4364*44704f69SBart Van Assche         else if ((! decoded) && full) {
4365*44704f69SBart Van Assche             hex2str(bp, param_len, "    ", op->hex2str_oformat, sizeof(b), b);
4366*44704f69SBart Van Assche             sgj_pr_hr(jsp, "  %s = 0x%x, contents in hex:\n%s", param_c, pc,
4367*44704f69SBart Van Assche                       b);
4368*44704f69SBart Van Assche         }
4369*44704f69SBart Van Assche 
4370*44704f69SBart Van Assche         if (jsp->pr_as_json)
4371*44704f69SBart Van Assche             sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
4372*44704f69SBart Van Assche         if (op->do_pcb)
4373*44704f69SBart Van Assche             sgj_pr_hr(jsp, "        <%s>\n", get_pcb_str(bp[2], str,
4374*44704f69SBart Van Assche                       sizeof(str)));
4375*44704f69SBart Van Assche skip:
4376*44704f69SBart Van Assche         if (op->filter_given)
4377*44704f69SBart Van Assche             break;
4378*44704f69SBart Van Assche     }           /* end of for loop */
4379*44704f69SBart Van Assche     return true;
4380*44704f69SBart Van Assche }
4381*44704f69SBart Van Assche 
4382*44704f69SBart Van Assche /* called for SAS port of PROTO_SPECIFIC_LPAGE [0x18] */
4383*44704f69SBart Van Assche static const char *
show_sas_phy_event_info(int pes,unsigned int val,unsigned int thresh_val,char * b,int blen)4384*44704f69SBart Van Assche show_sas_phy_event_info(int pes, unsigned int val, unsigned int thresh_val,
4385*44704f69SBart Van Assche                         char * b, int blen)
4386*44704f69SBart Van Assche {
4387*44704f69SBart Van Assche     int n = 0;
4388*44704f69SBart Van Assche     unsigned int u;
4389*44704f69SBart Van Assche     const char * cp = "";
4390*44704f69SBart Van Assche     static const char * pvdt = "Peak value detector threshold";
4391*44704f69SBart Van Assche 
4392*44704f69SBart Van Assche     switch (pes) {
4393*44704f69SBart Van Assche     case 0:
4394*44704f69SBart Van Assche         cp = "No event";
4395*44704f69SBart Van Assche         snprintf(b, blen, "%s", cp);
4396*44704f69SBart Van Assche         break;
4397*44704f69SBart Van Assche     case 0x1:
4398*44704f69SBart Van Assche         cp = "Invalid word count";
4399*44704f69SBart Van Assche         snprintf(b, blen, "%s: %u", cp, val);
4400*44704f69SBart Van Assche         break;
4401*44704f69SBart Van Assche     case 0x2:
4402*44704f69SBart Van Assche         cp = "Running disparity error count";
4403*44704f69SBart Van Assche         snprintf(b, blen, "%s: %u", cp, val);
4404*44704f69SBart Van Assche         break;
4405*44704f69SBart Van Assche     case 0x3:
4406*44704f69SBart Van Assche         cp = "Loss of dword synchronization count";
4407*44704f69SBart Van Assche         snprintf(b, blen, "%s: %u", cp, val);
4408*44704f69SBart Van Assche         break;
4409*44704f69SBart Van Assche     case 0x4:
4410*44704f69SBart Van Assche         cp = "Phy reset problem count";
4411*44704f69SBart Van Assche         snprintf(b, blen, "%s: %u", cp, val);
4412*44704f69SBart Van Assche         break;
4413*44704f69SBart Van Assche     case 0x5:
4414*44704f69SBart Van Assche         cp = "Elasticity buffer overflow count";
4415*44704f69SBart Van Assche         snprintf(b, blen, "%s: %u", cp, val);
4416*44704f69SBart Van Assche         break;
4417*44704f69SBart Van Assche     case 0x6:
4418*44704f69SBart Van Assche         cp = "Received ERROR count";
4419*44704f69SBart Van Assche         snprintf(b, blen, "%s: %u", cp, val);
4420*44704f69SBart Van Assche         break;
4421*44704f69SBart Van Assche     case 0x7:
4422*44704f69SBart Van Assche         cp = "Invalid SPL packet count";
4423*44704f69SBart Van Assche         snprintf(b, blen, "%s: %u", cp, val);
4424*44704f69SBart Van Assche         break;
4425*44704f69SBart Van Assche     case 0x8:
4426*44704f69SBart Van Assche         cp = "Loss of SPL packet synchronization count";
4427*44704f69SBart Van Assche         snprintf(b, blen, "%s: %u", cp, val);
4428*44704f69SBart Van Assche         break;
4429*44704f69SBart Van Assche     case 0x20:
4430*44704f69SBart Van Assche         cp = "Received address frame error count";
4431*44704f69SBart Van Assche         snprintf(b, blen, "%s: %u", cp, val);
4432*44704f69SBart Van Assche         break;
4433*44704f69SBart Van Assche     case 0x21:
4434*44704f69SBart Van Assche         cp = "Transmitted abandon-class OPEN_REJECT count";
4435*44704f69SBart Van Assche         snprintf(b, blen, "%s: %u", cp, val);
4436*44704f69SBart Van Assche         break;
4437*44704f69SBart Van Assche     case 0x22:
4438*44704f69SBart Van Assche         cp =  "Received abandon-class OPEN_REJECT count";
4439*44704f69SBart Van Assche         snprintf(b, blen, "%s: %u", cp, val);
4440*44704f69SBart Van Assche         break;
4441*44704f69SBart Van Assche     case 0x23:
4442*44704f69SBart Van Assche         cp = "Transmitted retry-class OPEN_REJECT count";
4443*44704f69SBart Van Assche         snprintf(b, blen, "%s: %u", cp, val);
4444*44704f69SBart Van Assche         break;
4445*44704f69SBart Van Assche     case 0x24:
4446*44704f69SBart Van Assche         cp = "Received retry-class OPEN_REJECT count";
4447*44704f69SBart Van Assche         snprintf(b, blen, "%s: %u", cp, val);
4448*44704f69SBart Van Assche         break;
4449*44704f69SBart Van Assche     case 0x25:
4450*44704f69SBart Van Assche         cp = "Received AIP (WAITING ON PARTIAL) count";
4451*44704f69SBart Van Assche         snprintf(b, blen, "%s: %u", cp, val);
4452*44704f69SBart Van Assche         break;
4453*44704f69SBart Van Assche     case 0x26:
4454*44704f69SBart Van Assche         cp = "Received AIP (WAITING ON CONNECTION) count";
4455*44704f69SBart Van Assche         snprintf(b, blen, "%s: %u", cp, val);
4456*44704f69SBart Van Assche         break;
4457*44704f69SBart Van Assche     case 0x27:
4458*44704f69SBart Van Assche         cp = "Transmitted BREAK count";
4459*44704f69SBart Van Assche         snprintf(b, blen, "%s: %u", cp, val);
4460*44704f69SBart Van Assche         break;
4461*44704f69SBart Van Assche     case 0x28:
4462*44704f69SBart Van Assche         cp = "Received BREAK count";
4463*44704f69SBart Van Assche         snprintf(b, blen, "%s: %u", cp, val);
4464*44704f69SBart Van Assche         break;
4465*44704f69SBart Van Assche     case 0x29:
4466*44704f69SBart Van Assche         cp = "Break timeout count";
4467*44704f69SBart Van Assche         snprintf(b, blen, "%s: %u", cp, val);
4468*44704f69SBart Van Assche         break;
4469*44704f69SBart Van Assche     case 0x2a:
4470*44704f69SBart Van Assche         cp =  "Connection count";
4471*44704f69SBart Van Assche         snprintf(b, blen, "%s: %u", cp, val);
4472*44704f69SBart Van Assche         break;
4473*44704f69SBart Van Assche     case 0x2b:
4474*44704f69SBart Van Assche         cp = "Peak transmitted pathway blocked count";
4475*44704f69SBart Van Assche         n = sg_scnpr(b, blen, "%s: %u", cp, val & 0xff);
4476*44704f69SBart Van Assche         sg_scnpr(b + n, blen - n, "\t%s: %u", pvdt, thresh_val & 0xff);
4477*44704f69SBart Van Assche         break;
4478*44704f69SBart Van Assche     case 0x2c:
4479*44704f69SBart Van Assche         cp = "Peak transmitted arbitration wait time";
4480*44704f69SBart Van Assche         u = val & 0xffff;
4481*44704f69SBart Van Assche         if (u < 0x8000)
4482*44704f69SBart Van Assche             n = sg_scnpr(b, blen, "%s (us): %u", cp, u);
4483*44704f69SBart Van Assche         else
4484*44704f69SBart Van Assche             n = sg_scnpr(b, blen, "%s (ms): %u", cp, 33 + (u - 0x8000));
4485*44704f69SBart Van Assche         u = thresh_val & 0xffff;
4486*44704f69SBart Van Assche         if (u < 0x8000)
4487*44704f69SBart Van Assche             sg_scnpr(b + n, blen - n, "\t%s (us): %u", pvdt, u);
4488*44704f69SBart Van Assche         else
4489*44704f69SBart Van Assche             sg_scnpr(b + n, blen - n, "\t%s (ms): %u", pvdt,
4490*44704f69SBart Van Assche                      33 + (u - 0x8000));
4491*44704f69SBart Van Assche         break;
4492*44704f69SBart Van Assche     case 0x2d:
4493*44704f69SBart Van Assche         cp = "Peak arbitration time";
4494*44704f69SBart Van Assche         n = sg_scnpr(b, blen, "%s (us): %u", cp, val);
4495*44704f69SBart Van Assche         sg_scnpr(b + n, blen - n, "\t%s: %u", pvdt, thresh_val);
4496*44704f69SBart Van Assche         break;
4497*44704f69SBart Van Assche     case 0x2e:
4498*44704f69SBart Van Assche         cp = "Peak connection time";
4499*44704f69SBart Van Assche         n = sg_scnpr(b, blen, "%s (us): %u", cp, val);
4500*44704f69SBart Van Assche         sg_scnpr(b + n, blen - n, "\t%s: %u", pvdt, thresh_val);
4501*44704f69SBart Van Assche         break;
4502*44704f69SBart Van Assche     case 0x2f:
4503*44704f69SBart Van Assche         cp = "Persistent connection count";
4504*44704f69SBart Van Assche         snprintf(b, blen, "%s: %u", cp, val);
4505*44704f69SBart Van Assche         break;
4506*44704f69SBart Van Assche     case 0x40:
4507*44704f69SBart Van Assche         cp = "Transmitted SSP frame count";
4508*44704f69SBart Van Assche         snprintf(b, blen, "%s: %u", cp, val);
4509*44704f69SBart Van Assche         break;
4510*44704f69SBart Van Assche     case 0x41:
4511*44704f69SBart Van Assche         cp = "Received SSP frame count";
4512*44704f69SBart Van Assche         snprintf(b, blen, "%s: %u", cp, val);
4513*44704f69SBart Van Assche         break;
4514*44704f69SBart Van Assche     case 0x42:
4515*44704f69SBart Van Assche         cp = "Transmitted SSP frame error count";
4516*44704f69SBart Van Assche         snprintf(b, blen, "%s: %u", cp, val);
4517*44704f69SBart Van Assche         break;
4518*44704f69SBart Van Assche     case 0x43:
4519*44704f69SBart Van Assche         cp = "Received SSP frame error count";
4520*44704f69SBart Van Assche         snprintf(b, blen, "%s: %u", cp, val);
4521*44704f69SBart Van Assche         break;
4522*44704f69SBart Van Assche     case 0x44:
4523*44704f69SBart Van Assche         cp = "Transmitted CREDIT_BLOCKED count";
4524*44704f69SBart Van Assche         snprintf(b, blen, "%s: %u", cp, val);
4525*44704f69SBart Van Assche         break;
4526*44704f69SBart Van Assche     case 0x45:
4527*44704f69SBart Van Assche         cp = "Received CREDIT_BLOCKED count";
4528*44704f69SBart Van Assche         snprintf(b, blen, "%s: %u", cp, val);
4529*44704f69SBart Van Assche         break;
4530*44704f69SBart Van Assche     case 0x50:
4531*44704f69SBart Van Assche         cp = "Transmitted SATA frame count";
4532*44704f69SBart Van Assche         snprintf(b, blen, "%s: %u", cp, val);
4533*44704f69SBart Van Assche         break;
4534*44704f69SBart Van Assche     case 0x51:
4535*44704f69SBart Van Assche         cp = "Received SATA frame count";
4536*44704f69SBart Van Assche         snprintf(b, blen, "%s: %u", cp, val);
4537*44704f69SBart Van Assche         break;
4538*44704f69SBart Van Assche     case 0x52:
4539*44704f69SBart Van Assche         cp = "SATA flow control buffer overflow count";
4540*44704f69SBart Van Assche         snprintf(b, blen, "%s: %u", cp, val);
4541*44704f69SBart Van Assche         break;
4542*44704f69SBart Van Assche     case 0x60:
4543*44704f69SBart Van Assche         cp = "Transmitted SMP frame count";
4544*44704f69SBart Van Assche         snprintf(b, blen, "%s: %u", cp, val);
4545*44704f69SBart Van Assche         break;
4546*44704f69SBart Van Assche     case 0x61:
4547*44704f69SBart Van Assche         cp = "Received SMP frame count";
4548*44704f69SBart Van Assche         snprintf(b, blen, "%s: %u", cp, val);
4549*44704f69SBart Van Assche         break;
4550*44704f69SBart Van Assche     case 0x63:
4551*44704f69SBart Van Assche         cp = "Received SMP frame error count";
4552*44704f69SBart Van Assche         snprintf(b, blen, "%s: %u", cp, val);
4553*44704f69SBart Van Assche         break;
4554*44704f69SBart Van Assche     default:
4555*44704f69SBart Van Assche         cp = "";
4556*44704f69SBart Van Assche         snprintf(b, blen, "Unknown phy event source: %d, val=%u, "
4557*44704f69SBart Van Assche                  "thresh_val=%u", pes, val, thresh_val);
4558*44704f69SBart Van Assche         break;
4559*44704f69SBart Van Assche     }
4560*44704f69SBart Van Assche     return cp;
4561*44704f69SBart Van Assche }
4562*44704f69SBart Van Assche 
4563*44704f69SBart Van Assche static const char * sas_link_rate_arr[16] = {
4564*44704f69SBart Van Assche     "phy enabled; unknown rate",
4565*44704f69SBart Van Assche     "phy disabled",
4566*44704f69SBart Van Assche     "phy enabled; speed negotiation failed",
4567*44704f69SBart Van Assche     "phy enabled; SATA spinup hold state",
4568*44704f69SBart Van Assche     "phy enabled; port selector",
4569*44704f69SBart Van Assche     "phy enabled; reset in progress",
4570*44704f69SBart Van Assche     "phy enabled; unsupported phy attached",
4571*44704f69SBart Van Assche     "reserved [0x7]",
4572*44704f69SBart Van Assche     "1.5 Gbps",                 /* 0x8 */
4573*44704f69SBart Van Assche     "3 Gbps",
4574*44704f69SBart Van Assche     "6 Gbps",
4575*44704f69SBart Van Assche     "12 Gbps",
4576*44704f69SBart Van Assche     "22.5 Gbps",
4577*44704f69SBart Van Assche     "reserved [0xd]",
4578*44704f69SBart Van Assche     "reserved [0xe]",
4579*44704f69SBart Van Assche     "reserved [0xf]",
4580*44704f69SBart Van Assche };
4581*44704f69SBart Van Assche 
4582*44704f69SBart Van Assche static char *
sas_negot_link_rate(int lrate,char * b,int blen)4583*44704f69SBart Van Assche sas_negot_link_rate(int lrate, char * b, int blen)
4584*44704f69SBart Van Assche {
4585*44704f69SBart Van Assche     int mask = 0xf;
4586*44704f69SBart Van Assche 
4587*44704f69SBart Van Assche     if (~mask & lrate)
4588*44704f69SBart Van Assche         snprintf(b, blen, "bad link_rate value=0x%x\n", lrate);
4589*44704f69SBart Van Assche     else
4590*44704f69SBart Van Assche         snprintf(b, blen, "%s", sas_link_rate_arr[lrate]);
4591*44704f69SBart Van Assche     return b;
4592*44704f69SBart Van Assche }
4593*44704f69SBart Van Assche 
4594*44704f69SBart Van Assche /* helper for SAS port of PROTO_SPECIFIC_LPAGE [0x18] */
4595*44704f69SBart Van Assche static void
show_sas_port_param(const uint8_t * bp,int param_len,struct opts_t * op,sgj_opaque_p jop)4596*44704f69SBart Van Assche show_sas_port_param(const uint8_t * bp, int param_len, struct opts_t * op,
4597*44704f69SBart Van Assche                     sgj_opaque_p jop)
4598*44704f69SBart Van Assche {
4599*44704f69SBart Van Assche     int j, m, nphys, t, spld_len, pi;
4600*44704f69SBart Van Assche     uint64_t ull;
4601*44704f69SBart Van Assche     unsigned int ui, ui2, ui3, ui4;
4602*44704f69SBart Van Assche     char * cp;
4603*44704f69SBart Van Assche     const char * ccp;
4604*44704f69SBart Van Assche     const char * cc2p;
4605*44704f69SBart Van Assche     const char * cc3p;
4606*44704f69SBart Van Assche     const char * cc4p;
4607*44704f69SBart Van Assche     const uint8_t * vcp;
4608*44704f69SBart Van Assche     sgj_state * jsp = &op->json_st;
4609*44704f69SBart Van Assche     sgj_opaque_p jo2p = NULL;
4610*44704f69SBart Van Assche     sgj_opaque_p jo3p = NULL;
4611*44704f69SBart Van Assche     sgj_opaque_p jap = NULL;
4612*44704f69SBart Van Assche     sgj_opaque_p ja2p = NULL;
4613*44704f69SBart Van Assche     char b[160];
4614*44704f69SBart Van Assche     char s[80];
4615*44704f69SBart Van Assche     static char * rtpi = "Relative target port identifier";
4616*44704f69SBart Van Assche     static char * psplpfstp =
4617*44704f69SBart Van Assche                 "Protocol Specific Port log parameter for SAS target port";
4618*44704f69SBart Van Assche     static char * at = "attached";
4619*44704f69SBart Van Assche     static char * ip = "initiator_port";
4620*44704f69SBart Van Assche     static char * tp = "target_port";
4621*44704f69SBart Van Assche     static char * pvdt = "peak_value_detector_threshold";
4622*44704f69SBart Van Assche     static const int sz = sizeof(s);
4623*44704f69SBart Van Assche     static const int blen = sizeof(b);
4624*44704f69SBart Van Assche 
4625*44704f69SBart Van Assche     t = sg_get_unaligned_be16(bp + 0);
4626*44704f69SBart Van Assche     if (op->do_name)
4627*44704f69SBart Van Assche         sgj_pr_hr(jsp, " rel_target_port=%d\n", t);
4628*44704f69SBart Van Assche     else
4629*44704f69SBart Van Assche         sgj_pr_hr(jsp, " %s = %d\n", rtpi, t);
4630*44704f69SBart Van Assche     if (op->do_name)
4631*44704f69SBart Van Assche         sgj_pr_hr(jsp, "  gen_code=%d\n", bp[6]);
4632*44704f69SBart Van Assche     else
4633*44704f69SBart Van Assche         sgj_pr_hr(jsp, "  generation code = %d\n", bp[6]);
4634*44704f69SBart Van Assche     nphys = bp[7];
4635*44704f69SBart Van Assche     if (op->do_name)
4636*44704f69SBart Van Assche         sgj_pr_hr(jsp, "  num_phys=%d\n", nphys);
4637*44704f69SBart Van Assche     else
4638*44704f69SBart Van Assche         sgj_pr_hr(jsp, "  number of phys = %d\n", nphys);
4639*44704f69SBart Van Assche     if (jsp->pr_as_json) {
4640*44704f69SBart Van Assche         js_snakenv_ihexstr_nex(jsp, jop, param_c , t, true,
4641*44704f69SBart Van Assche                                NULL, psplpfstp, rtpi);
4642*44704f69SBart Van Assche         pi = 0xf & bp[4];
4643*44704f69SBart Van Assche         sgj_js_nv_ihexstr(jsp, jop, "protocol_identifier", pi, NULL,
4644*44704f69SBart Van Assche                           sg_get_trans_proto_str(pi, blen, b));
4645*44704f69SBart Van Assche         sgj_js_nv_ihex(jsp, jop, "generation_code", bp[6]);
4646*44704f69SBart Van Assche         sgj_js_nv_ihex(jsp, jop, "number_of_phys", bp[7]);
4647*44704f69SBart Van Assche         jap = sgj_named_subarray_r(jsp, jop, "sas_phy_log_descriptor_list");
4648*44704f69SBart Van Assche     }
4649*44704f69SBart Van Assche 
4650*44704f69SBart Van Assche     for (j = 0, vcp = bp + 8; j < (param_len - 8);
4651*44704f69SBart Van Assche          vcp += spld_len, j += spld_len) {
4652*44704f69SBart Van Assche         if (jsp->pr_as_json) {
4653*44704f69SBart Van Assche             jo2p = sgj_new_unattached_object_r(jsp);
4654*44704f69SBart Van Assche             if (op->do_pcb)
4655*44704f69SBart Van Assche                 js_pcb(jsp, jo2p, vcp[2]);
4656*44704f69SBart Van Assche         }
4657*44704f69SBart Van Assche         if (op->do_name)
4658*44704f69SBart Van Assche             sgj_pr_hr(jsp, "    phy_id=%d\n", vcp[1]);
4659*44704f69SBart Van Assche         else
4660*44704f69SBart Van Assche             sgj_haj_vi(jsp, jo2p, 2, "phy identifier", SGJ_SEP_EQUAL_1_SPACE,
4661*44704f69SBart Van Assche                        vcp[1], true);
4662*44704f69SBart Van Assche         spld_len = vcp[3];
4663*44704f69SBart Van Assche         if (spld_len < 44)
4664*44704f69SBart Van Assche             spld_len = 48;      /* in SAS-1 and SAS-1.1 vcp[3]==0 */
4665*44704f69SBart Van Assche         else
4666*44704f69SBart Van Assche             spld_len += 4;
4667*44704f69SBart Van Assche         if (op->do_name) {
4668*44704f69SBart Van Assche             t = ((0x70 & vcp[4]) >> 4);
4669*44704f69SBart Van Assche             sgj_pr_hr(jsp, "      att_dev_type=%d\n", t);
4670*44704f69SBart Van Assche             sgj_pr_hr(jsp, "      att_iport_mask=0x%x\n", vcp[6]);
4671*44704f69SBart Van Assche             sgj_pr_hr(jsp, "      att_phy_id=%d\n", vcp[24]);
4672*44704f69SBart Van Assche             sgj_pr_hr(jsp, "      att_reason=0x%x\n", (vcp[4] & 0xf));
4673*44704f69SBart Van Assche             ull = sg_get_unaligned_be64(vcp + 16);
4674*44704f69SBart Van Assche             sgj_pr_hr(jsp, "      att_sas_addr=0x%" PRIx64 "\n", ull);
4675*44704f69SBart Van Assche             sgj_pr_hr(jsp, "      att_tport_mask=0x%x\n", vcp[7]);
4676*44704f69SBart Van Assche             ui = sg_get_unaligned_be32(vcp + 32);
4677*44704f69SBart Van Assche             sgj_pr_hr(jsp, "      inv_dwords=%u\n", ui);
4678*44704f69SBart Van Assche             ui = sg_get_unaligned_be32(vcp + 40);
4679*44704f69SBart Van Assche             sgj_pr_hr(jsp, "      loss_dword_sync=%u\n", ui);
4680*44704f69SBart Van Assche             sgj_pr_hr(jsp, "      neg_log_lrate=%d\n", 0xf & vcp[5]);
4681*44704f69SBart Van Assche             ui = sg_get_unaligned_be32(vcp + 44);
4682*44704f69SBart Van Assche             sgj_pr_hr(jsp, "      phy_reset_probs=%u\n", ui);
4683*44704f69SBart Van Assche             ui = sg_get_unaligned_be32(vcp + 36);
4684*44704f69SBart Van Assche             sgj_pr_hr(jsp, "      running_disparity=%u\n", ui);
4685*44704f69SBart Van Assche             sgj_pr_hr(jsp, "      reason=0x%x\n", (vcp[5] & 0xf0) >> 4);
4686*44704f69SBart Van Assche             ull = sg_get_unaligned_be64(vcp + 8);
4687*44704f69SBart Van Assche             sgj_pr_hr(jsp, "      sas_addr=0x%" PRIx64 "\n", ull);
4688*44704f69SBart Van Assche         } else {
4689*44704f69SBart Van Assche             t = ((0x70 & vcp[4]) >> 4);
4690*44704f69SBart Van Assche             /* attached SAS device type. In SAS-1.1 case 2 was an edge
4691*44704f69SBart Van Assche              * expander; in SAS-2 case 3 is marked as obsolete. */
4692*44704f69SBart Van Assche             switch (t) {
4693*44704f69SBart Van Assche             case 0: snprintf(s, sz, "no device %s", at); break;
4694*44704f69SBart Van Assche             case 1: snprintf(s, sz, "SAS or SATA device"); break;
4695*44704f69SBart Van Assche             case 2: snprintf(s, sz, "expander device"); break;
4696*44704f69SBart Van Assche             case 3: snprintf(s, sz, "expander device (fanout)"); break;
4697*44704f69SBart Van Assche             default: snprintf(s, sz, "%s [%d]", rsv_s, t); break;
4698*44704f69SBart Van Assche             }
4699*44704f69SBart Van Assche             /* the word 'SAS' in following added in spl4r01 */
4700*44704f69SBart Van Assche             sgj_pr_hr(jsp, "    %s SAS device type: %s\n", at, s);
4701*44704f69SBart Van Assche             if (jsp->pr_as_json)
4702*44704f69SBart Van Assche                 sgj_js_nv_ihexstr(jsp, jo2p, "attached_sas_device_type", t,
4703*44704f69SBart Van Assche                                   NULL, s);
4704*44704f69SBart Van Assche             t = 0xf & vcp[4];
4705*44704f69SBart Van Assche             switch (t) {
4706*44704f69SBart Van Assche             case 0: snprintf(s, sz, "%s", unknown_s); break;
4707*44704f69SBart Van Assche             case 1: snprintf(s, sz, "power on"); break;
4708*44704f69SBart Van Assche             case 2: snprintf(s, sz, "hard reset"); break;
4709*44704f69SBart Van Assche             case 3: snprintf(s, sz, "SMP phy control function"); break;
4710*44704f69SBart Van Assche             case 4: snprintf(s, sz, "loss of dword synchronization"); break;
4711*44704f69SBart Van Assche             case 5: snprintf(s, sz, "mux mix up"); break;
4712*44704f69SBart Van Assche             case 6: snprintf(s, sz, "I_T nexus loss timeout for STP/SATA");
4713*44704f69SBart Van Assche                 break;
4714*44704f69SBart Van Assche             case 7: snprintf(s, sz, "break timeout timer expired"); break;
4715*44704f69SBart Van Assche             case 8: snprintf(s, sz, "phy test function stopped"); break;
4716*44704f69SBart Van Assche             case 9: snprintf(s, sz, "expander device reduced functionality");
4717*44704f69SBart Van Assche                  break;
4718*44704f69SBart Van Assche             default: snprintf(s, sz, "%s [0x%x]", rsv_s, t); break;
4719*44704f69SBart Van Assche             }
4720*44704f69SBart Van Assche             sgj_pr_hr(jsp, "    %s reason: %s\n", at, s);
4721*44704f69SBart Van Assche             if (jsp->pr_as_json)
4722*44704f69SBart Van Assche                 sgj_js_nv_ihexstr(jsp, jo2p, "attached_reason", t, NULL, s);
4723*44704f69SBart Van Assche             t = (vcp[5] & 0xf0) >> 4;
4724*44704f69SBart Van Assche             switch (t) {
4725*44704f69SBart Van Assche             case 0: snprintf(s, sz, "%s", unknown_s); break;
4726*44704f69SBart Van Assche             case 1: snprintf(s, sz, "power on"); break;
4727*44704f69SBart Van Assche             case 2: snprintf(s, sz, "hard reset"); break;
4728*44704f69SBart Van Assche             case 3: snprintf(s, sz, "SMP phy control function"); break;
4729*44704f69SBart Van Assche             case 4: snprintf(s, sz, "loss of dword synchronization"); break;
4730*44704f69SBart Van Assche             case 5: snprintf(s, sz, "mux mix up"); break;
4731*44704f69SBart Van Assche             case 6: snprintf(s, sz, "I_T nexus loss timeout for STP/SATA");
4732*44704f69SBart Van Assche                 break;
4733*44704f69SBart Van Assche             case 7: snprintf(s, sz, "break timeout timer expired"); break;
4734*44704f69SBart Van Assche             case 8: snprintf(s, sz, "phy test function stopped"); break;
4735*44704f69SBart Van Assche             case 9: snprintf(s, sz, "expander device reduced functionality");
4736*44704f69SBart Van Assche                  break;
4737*44704f69SBart Van Assche             default: snprintf(s, sz, "%s [0x%x]", rsv_s, t); break;
4738*44704f69SBart Van Assche             }
4739*44704f69SBart Van Assche             sgj_pr_hr(jsp, "    reason: %s\n", s);
4740*44704f69SBart Van Assche             if (jsp->pr_as_json)
4741*44704f69SBart Van Assche                 sgj_js_nv_ihexstr(jsp, jo2p, "reason", t, NULL, s);
4742*44704f69SBart Van Assche             t = (0xf & vcp[5]);
4743*44704f69SBart Van Assche             ccp = "negotiated logical link rate";
4744*44704f69SBart Van Assche             cc2p = sas_negot_link_rate(t, s, sz);
4745*44704f69SBart Van Assche             sgj_pr_hr(jsp, "    %s: %s\n", ccp, cc2p);
4746*44704f69SBart Van Assche             if (jsp->pr_as_json) {
4747*44704f69SBart Van Assche                 sgj_convert_to_snake_name(ccp, b, blen);
4748*44704f69SBart Van Assche                 sgj_js_nv_ihexstr(jsp, jo2p, b, t, NULL, cc2p);
4749*44704f69SBart Van Assche             }
4750*44704f69SBart Van Assche 
4751*44704f69SBart Van Assche             sgj_pr_hr(jsp, "    %s initiator port: ssp=%d stp=%d smp=%d\n",
4752*44704f69SBart Van Assche                       at, !! (vcp[6] & 8), !! (vcp[6] & 4), !! (vcp[6] & 2));
4753*44704f69SBart Van Assche             if (jsp->pr_as_json) {
4754*44704f69SBart Van Assche                 snprintf(b, blen, "%s_ssp_%s", at, ip);
4755*44704f69SBart Van Assche                 sgj_js_nv_i(jsp, jo2p, b, !! (vcp[6] & 8));
4756*44704f69SBart Van Assche                 snprintf(b, blen, "%s_stp_%s", at, ip);
4757*44704f69SBart Van Assche                 sgj_js_nv_i(jsp, jo2p, b, !! (vcp[6] & 4));
4758*44704f69SBart Van Assche                 snprintf(b, blen, "%s_smp_%s", at, ip);
4759*44704f69SBart Van Assche                 sgj_js_nv_i(jsp, jo2p, b, !! (vcp[6] & 2));
4760*44704f69SBart Van Assche             }
4761*44704f69SBart Van Assche             sgj_pr_hr(jsp, "    %s target port: ssp=%d stp=%d smp=%d\n", at,
4762*44704f69SBart Van Assche                       !! (vcp[7] & 8), !! (vcp[7] & 4), !! (vcp[7] & 2));
4763*44704f69SBart Van Assche             if (jsp->pr_as_json) {
4764*44704f69SBart Van Assche                 snprintf(b, blen, "%s_ssp_%s", at, tp);
4765*44704f69SBart Van Assche                 sgj_js_nv_i(jsp, jo2p, b, !! (vcp[7] & 8));
4766*44704f69SBart Van Assche                 snprintf(b, blen, "%s_stp_%s", at, tp);
4767*44704f69SBart Van Assche                 sgj_js_nv_i(jsp, jo2p, b, !! (vcp[7] & 4));
4768*44704f69SBart Van Assche                 snprintf(b, blen, "%s_smp_%s", at, tp);
4769*44704f69SBart Van Assche                 sgj_js_nv_i(jsp, jo2p, b, !! (vcp[7] & 2));
4770*44704f69SBart Van Assche             }
4771*44704f69SBart Van Assche             ull = sg_get_unaligned_be64(vcp + 8);
4772*44704f69SBart Van Assche             sgj_pr_hr(jsp, "    SAS address = 0x%" PRIx64 "\n", ull);
4773*44704f69SBart Van Assche             if (jsp->pr_as_json)
4774*44704f69SBart Van Assche                 sgj_js_nv_ihex(jsp, jo2p, "sas_address", ull);
4775*44704f69SBart Van Assche             ull = sg_get_unaligned_be64(vcp + 16);
4776*44704f69SBart Van Assche             sgj_pr_hr(jsp, "    %s SAS address = 0x%" PRIx64 "\n", at, ull);
4777*44704f69SBart Van Assche             if (jsp->pr_as_json)
4778*44704f69SBart Van Assche                 sgj_js_nv_ihex(jsp, jo2p, "attached_sas_address", ull);
4779*44704f69SBart Van Assche             ccp = "attached phy identifier";
4780*44704f69SBart Van Assche             sgj_haj_vi(jsp, jo2p, 4, ccp, SGJ_SEP_EQUAL_1_SPACE, vcp[24],
4781*44704f69SBart Van Assche                        true);
4782*44704f69SBart Van Assche             ccp = "Invalid DWORD count";
4783*44704f69SBart Van Assche             ui = sg_get_unaligned_be32(vcp + 32);
4784*44704f69SBart Van Assche             cc2p = "Running disparity error count";
4785*44704f69SBart Van Assche             ui2 = sg_get_unaligned_be32(vcp + 36);
4786*44704f69SBart Van Assche             cc3p = "Loss of DWORD synchronization count";
4787*44704f69SBart Van Assche             ui3 = sg_get_unaligned_be32(vcp + 40);
4788*44704f69SBart Van Assche             cc4p = "Phy reset problem count";
4789*44704f69SBart Van Assche             ui4 = sg_get_unaligned_be32(vcp + 44);
4790*44704f69SBart Van Assche             if (jsp->pr_as_json) {
4791*44704f69SBart Van Assche                 sgj_convert_to_snake_name(ccp, b, blen);
4792*44704f69SBart Van Assche                 sgj_js_nv_ihex(jsp, jo2p, b, ui);
4793*44704f69SBart Van Assche                 sgj_convert_to_snake_name(cc2p, b, blen);
4794*44704f69SBart Van Assche                 sgj_js_nv_ihex(jsp, jo2p, b, ui2);
4795*44704f69SBart Van Assche                 sgj_convert_to_snake_name(cc3p, b, blen);
4796*44704f69SBart Van Assche                 sgj_js_nv_ihex(jsp, jo2p, b, ui3);
4797*44704f69SBart Van Assche                 sgj_convert_to_snake_name(cc4p, b, blen);
4798*44704f69SBart Van Assche                 sgj_js_nv_ihex(jsp, jo2p, b, ui4);
4799*44704f69SBart Van Assche             } else {
4800*44704f69SBart Van Assche                 if (0 == op->do_brief) {
4801*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "    %s = %u\n", ccp, ui);
4802*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "    %s = %u\n", cc2p, ui2);
4803*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "    %s = %u\n", cc3p, ui3);
4804*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "    %s = %u\n", cc4p, ui4);
4805*44704f69SBart Van Assche                 }
4806*44704f69SBart Van Assche             }
4807*44704f69SBart Van Assche         }
4808*44704f69SBart Van Assche         if (op->do_brief > 0)
4809*44704f69SBart Van Assche             goto skip;
4810*44704f69SBart Van Assche         if (spld_len > 51) {
4811*44704f69SBart Van Assche             int num_ped;
4812*44704f69SBart Van Assche             const uint8_t * xcp;
4813*44704f69SBart Van Assche 
4814*44704f69SBart Van Assche             num_ped = vcp[51];
4815*44704f69SBart Van Assche             if (op->verbose > 1)
4816*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "    <<Phy event descriptors: %d, spld_len: "
4817*44704f69SBart Van Assche                           "%d, calc_ped: %d>>\n", num_ped, spld_len,
4818*44704f69SBart Van Assche                           (spld_len - 52) / 12);
4819*44704f69SBart Van Assche             if (num_ped > 0) {
4820*44704f69SBart Van Assche                 if (op->do_name) {
4821*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "      phy_event_desc_num=%d\n", num_ped);
4822*44704f69SBart Van Assche                     return;      /* don't decode at this stage */
4823*44704f69SBart Van Assche                 } else
4824*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "    Phy event descriptors:\n");
4825*44704f69SBart Van Assche             }
4826*44704f69SBart Van Assche             if (jsp->pr_as_json) {
4827*44704f69SBart Van Assche                 sgj_js_nv_i(jsp, jo2p, "number_of_phy_event_descriptors",
4828*44704f69SBart Van Assche                             num_ped);
4829*44704f69SBart Van Assche                 if (num_ped > 0)
4830*44704f69SBart Van Assche                     ja2p = sgj_named_subarray_r(jsp, jo2p,
4831*44704f69SBart Van Assche                                                 "phy_event_descriptor_list");
4832*44704f69SBart Van Assche             }
4833*44704f69SBart Van Assche             xcp = vcp + 52;
4834*44704f69SBart Van Assche             for (m = 0; m < (num_ped * 12); m += 12, xcp += 12) {
4835*44704f69SBart Van Assche                 int pes = xcp[3];
4836*44704f69SBart Van Assche                 unsigned int pvdt_v;
4837*44704f69SBart Van Assche 
4838*44704f69SBart Van Assche                 if (jsp->pr_as_json)
4839*44704f69SBart Van Assche                     jo3p = sgj_new_unattached_object_r(jsp);
4840*44704f69SBart Van Assche                 ui = sg_get_unaligned_be32(xcp + 4);
4841*44704f69SBart Van Assche                 pvdt_v = sg_get_unaligned_be32(xcp + 8);
4842*44704f69SBart Van Assche                 ccp = show_sas_phy_event_info(pes, ui, pvdt_v, b, blen);
4843*44704f69SBart Van Assche                 if (0 == strlen(ccp)) {
4844*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "      %s\n", b);    /* unknown pvdt_v */
4845*44704f69SBart Van Assche                     if (jsp->pr_as_json) {
4846*44704f69SBart Van Assche                         int n;
4847*44704f69SBart Van Assche 
4848*44704f69SBart Van Assche                         snprintf(s, sz, "%s_pes_0x%x", unknown_s, pes);
4849*44704f69SBart Van Assche                         sgj_js_nv_ihex(jsp, jo3p, s, ui);
4850*44704f69SBart Van Assche                         n = strlen(s);
4851*44704f69SBart Van Assche                         sg_scnpr(s + n, sz - n, "_%s", "threshold");
4852*44704f69SBart Van Assche                         sgj_js_nv_ihex(jsp, jo3p, s, pvdt_v);
4853*44704f69SBart Van Assche                     }
4854*44704f69SBart Van Assche                 } else {
4855*44704f69SBart Van Assche                     if (jsp->pr_as_json) {
4856*44704f69SBart Van Assche                         sgj_convert_to_snake_name(ccp, s, sz);
4857*44704f69SBart Van Assche                         sgj_js_nv_ihex(jsp, jo3p, s, ui);
4858*44704f69SBart Van Assche                         if (0x2b == pes)
4859*44704f69SBart Van Assche                             sgj_js_nv_ihex(jsp, jo3p, pvdt, pvdt_v);
4860*44704f69SBart Van Assche                         else if (0x2c == pes)
4861*44704f69SBart Van Assche                             sgj_js_nv_ihex(jsp, jo3p, pvdt, pvdt_v);
4862*44704f69SBart Van Assche                         else if (0x2d == pes)
4863*44704f69SBart Van Assche                             sgj_js_nv_ihex(jsp, jo3p, pvdt, pvdt_v);
4864*44704f69SBart Van Assche                         else if (0x2e == pes)
4865*44704f69SBart Van Assche                             sgj_js_nv_ihex(jsp, jo3p, pvdt, pvdt_v);
4866*44704f69SBart Van Assche                     } else {
4867*44704f69SBart Van Assche                         cp = strchr(b, '\t');
4868*44704f69SBart Van Assche                         if (cp) {
4869*44704f69SBart Van Assche                             *cp = '\0';
4870*44704f69SBart Van Assche                             sgj_pr_hr(jsp, "      %s\n", b);
4871*44704f69SBart Van Assche                             sgj_pr_hr(jsp, "      %s\n", cp + 1);
4872*44704f69SBart Van Assche                         } else
4873*44704f69SBart Van Assche                             sgj_pr_hr(jsp, "      %s\n", b);
4874*44704f69SBart Van Assche                     }
4875*44704f69SBart Van Assche                 }
4876*44704f69SBart Van Assche                 if (jsp->pr_as_json)
4877*44704f69SBart Van Assche                     sgj_js_nv_o(jsp, ja2p, NULL /* name */, jo3p);
4878*44704f69SBart Van Assche             }
4879*44704f69SBart Van Assche         } else if (op->verbose)
4880*44704f69SBart Van Assche            printf("    <<No phy event descriptors>>\n");
4881*44704f69SBart Van Assche skip:
4882*44704f69SBart Van Assche         if (jsp->pr_as_json)
4883*44704f69SBart Van Assche             sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p);
4884*44704f69SBart Van Assche     }   /* end of for loop over phys with this relative port */
4885*44704f69SBart Van Assche }
4886*44704f69SBart Van Assche 
4887*44704f69SBart Van Assche /* PROTO_SPECIFIC_LPAGE [0x18] <psp> */
4888*44704f69SBart Van Assche static bool
show_protocol_specific_port_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)4889*44704f69SBart Van Assche show_protocol_specific_port_page(const uint8_t * resp, int len,
4890*44704f69SBart Van Assche                                  struct opts_t * op, sgj_opaque_p jop)
4891*44704f69SBart Van Assche {
4892*44704f69SBart Van Assche     int k, num, pl, pid;
4893*44704f69SBart Van Assche     const uint8_t * bp;
4894*44704f69SBart Van Assche     sgj_state * jsp = &op->json_st;
4895*44704f69SBart Van Assche     sgj_opaque_p jo2p;
4896*44704f69SBart Van Assche     sgj_opaque_p jo3p = NULL;
4897*44704f69SBart Van Assche     sgj_opaque_p jap = NULL;
4898*44704f69SBart Van Assche     char b[128];
4899*44704f69SBart Van Assche     static const char * psplp = "Protocol specific port log page";
4900*44704f69SBart Van Assche     static const char * fss = "for SAS SSP";
4901*44704f69SBart Van Assche 
4902*44704f69SBart Van Assche     num = len - 4;
4903*44704f69SBart Van Assche     if (op->verbose || ((! op->do_raw) && (0 == op->do_hex))) {
4904*44704f69SBart Van Assche         if (op->do_name)
4905*44704f69SBart Van Assche             sgj_pr_hr(jsp, "log_page=0x%x\n", PROTO_SPECIFIC_LPAGE);
4906*44704f69SBart Van Assche         else
4907*44704f69SBart Van Assche             sgj_pr_hr(jsp, "%s  [0x18]\n", psplp);
4908*44704f69SBart Van Assche     }
4909*44704f69SBart Van Assche     if (jsp->pr_as_json) {
4910*44704f69SBart Van Assche         jo2p = sg_log_js_hdr(jsp, jop, psplp, resp);
4911*44704f69SBart Van Assche         jap = sgj_named_subarray_r(jsp, jo2p,
4912*44704f69SBart Van Assche                            "protocol_specific_port_log_parameter_list");
4913*44704f69SBart Van Assche     }
4914*44704f69SBart Van Assche 
4915*44704f69SBart Van Assche     for (k = 0, bp = resp + 4; k < num; ) {
4916*44704f69SBart Van Assche         int pc = sg_get_unaligned_be16(bp + 0);
4917*44704f69SBart Van Assche 
4918*44704f69SBart Van Assche         pl = bp[3] + 4;
4919*44704f69SBart Van Assche         if (op->filter_given) {
4920*44704f69SBart Van Assche             if (pc != op->filter)
4921*44704f69SBart Van Assche                 goto skip;
4922*44704f69SBart Van Assche         }
4923*44704f69SBart Van Assche         if (op->do_raw) {
4924*44704f69SBart Van Assche             dStrRaw(bp, pl);
4925*44704f69SBart Van Assche             goto skip;
4926*44704f69SBart Van Assche         } else if (op->do_hex) {
4927*44704f69SBart Van Assche             hex2stdout(bp, pl, op->dstrhex_no_ascii);
4928*44704f69SBart Van Assche             goto skip;
4929*44704f69SBart Van Assche         }
4930*44704f69SBart Van Assche         pid = 0xf & bp[4];
4931*44704f69SBart Van Assche         if (6 != pid) {
4932*44704f69SBart Van Assche             pr2serr("Protocol identifier: %d, only support SAS (SPL) which "
4933*44704f69SBart Van Assche                     "is 6\n", pid);
4934*44704f69SBart Van Assche             return false;   /* only decode SAS log page */
4935*44704f69SBart Van Assche         }
4936*44704f69SBart Van Assche         if (jsp->pr_as_json) {
4937*44704f69SBart Van Assche             jo3p = sgj_new_unattached_object_r(jsp);
4938*44704f69SBart Van Assche             if (op->do_pcb)
4939*44704f69SBart Van Assche                 js_pcb(jsp, jo3p, bp[2]);
4940*44704f69SBart Van Assche         }
4941*44704f69SBart Van Assche         if ((0 == k) && (! op->do_name))
4942*44704f69SBart Van Assche              sgj_pr_hr(jsp, "%s %s  [0x18]\n", psplp, fss);
4943*44704f69SBart Van Assche         /* call helper */
4944*44704f69SBart Van Assche         show_sas_port_param(bp, pl, op, jo3p);
4945*44704f69SBart Van Assche         if (jsp->pr_as_json)
4946*44704f69SBart Van Assche             sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
4947*44704f69SBart Van Assche         if ((op->do_pcb) && (! op->do_name))
4948*44704f69SBart Van Assche             sgj_pr_hr(jsp, "        <%s>\n", get_pcb_str(bp[2], b,
4949*44704f69SBart Van Assche                       sizeof(b)));
4950*44704f69SBart Van Assche         if (op->filter_given)
4951*44704f69SBart Van Assche             break;
4952*44704f69SBart Van Assche skip:
4953*44704f69SBart Van Assche         k += pl;
4954*44704f69SBart Van Assche         bp += pl;
4955*44704f69SBart Van Assche     }
4956*44704f69SBart Van Assche     return true;
4957*44704f69SBart Van Assche }
4958*44704f69SBart Van Assche 
4959*44704f69SBart Van Assche /* Returns true if processed page, false otherwise */
4960*44704f69SBart Van Assche /* STATS_LPAGE [0x19], subpages: 0x0 to 0x1f <gsp,grsp>  introduced: SPC-4 */
4961*44704f69SBart Van Assche static bool
show_stats_perform_pages(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)4962*44704f69SBart Van Assche show_stats_perform_pages(const uint8_t * resp, int len,
4963*44704f69SBart Van Assche                          struct opts_t * op, sgj_opaque_p jop)
4964*44704f69SBart Van Assche {
4965*44704f69SBart Van Assche     bool nam, spf;
4966*44704f69SBart Van Assche     int k, num, param_len, param_code, subpg_code, extra;
4967*44704f69SBart Van Assche     uint64_t ull;
4968*44704f69SBart Van Assche     const uint8_t * bp;
4969*44704f69SBart Van Assche     const char * ccp;
4970*44704f69SBart Van Assche     const char * pg_name;
4971*44704f69SBart Van Assche     sgj_state * jsp = &op->json_st;
4972*44704f69SBart Van Assche     sgj_opaque_p jo2p;
4973*44704f69SBart Van Assche     sgj_opaque_p jo3p = NULL;
4974*44704f69SBart Van Assche     sgj_opaque_p jap = NULL;
4975*44704f69SBart Van Assche     char str[PCB_STR_LEN];
4976*44704f69SBart Van Assche     static const char * gsaplp =
4977*44704f69SBart Van Assche                 "General statistics and performance log page";
4978*44704f69SBart Van Assche     static const char * gr_saplp =
4979*44704f69SBart Van Assche                 "Group statistics and performance log page";
4980*44704f69SBart Van Assche 
4981*44704f69SBart Van Assche // yyyyyyyyyyyyyyyyyy
4982*44704f69SBart Van Assche     nam = op->do_name;
4983*44704f69SBart Van Assche     num = len - 4;
4984*44704f69SBart Van Assche     bp = resp + 4;
4985*44704f69SBart Van Assche     spf = !!(resp[0] & 0x40);
4986*44704f69SBart Van Assche     subpg_code = spf ? resp[1] : NOT_SPG_SUBPG;
4987*44704f69SBart Van Assche     if (0 == subpg_code)
4988*44704f69SBart Van Assche         pg_name = gsaplp;
4989*44704f69SBart Van Assche     else if (subpg_code < 0x20)
4990*44704f69SBart Van Assche         pg_name = gr_saplp;
4991*44704f69SBart Van Assche     else
4992*44704f69SBart Van Assche         pg_name = "Unknown subpage";
4993*44704f69SBart Van Assche     if (op->verbose || ((! op->do_raw) && (0 == op->do_hex))) {
4994*44704f69SBart Van Assche         if (nam) {
4995*44704f69SBart Van Assche              sgj_pr_hr(jsp, "log_page=0x%x\n", STATS_LPAGE);
4996*44704f69SBart Van Assche             if (subpg_code > 0)
4997*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "log_subpage=0x%x\n", subpg_code);
4998*44704f69SBart Van Assche         } else {
4999*44704f69SBart Van Assche             if (0 == subpg_code)
5000*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "%s  [0x19]\n", gsaplp);
5001*44704f69SBart Van Assche             else if (subpg_code < 0x20)
5002*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "%s (%d)  [0x19,0x%x]\n", gr_saplp, subpg_code,
5003*44704f69SBart Van Assche                           subpg_code);
5004*44704f69SBart Van Assche             else
5005*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "%s: %d  [0x19,0x%x]\n", pg_name, subpg_code,
5006*44704f69SBart Van Assche                           subpg_code);
5007*44704f69SBart Van Assche         }
5008*44704f69SBart Van Assche     }
5009*44704f69SBart Van Assche     if (jsp->pr_as_json)
5010*44704f69SBart Van Assche         jo2p = sg_log_js_hdr(jsp, jop, pg_name, resp);
5011*44704f69SBart Van Assche     if (subpg_code > 31)
5012*44704f69SBart Van Assche         return false;
5013*44704f69SBart Van Assche     if (jsp->pr_as_json)
5014*44704f69SBart Van Assche         jap = sgj_named_subarray_r(jsp, jo2p, 0 == subpg_code ?
5015*44704f69SBart Van Assche                         "general_statistics_and_performance_log_parameters" :
5016*44704f69SBart Van Assche                         "group_statistics_and_performance_log_parameters");
5017*44704f69SBart Van Assche     if (0 == subpg_code) { /* General statistics and performance log page */
5018*44704f69SBart Van Assche         if (num < 0x5c)
5019*44704f69SBart Van Assche             return false;
5020*44704f69SBart Van Assche         for (k = num; k > 0; k -= extra, bp += extra) {
5021*44704f69SBart Van Assche             unsigned int ui;
5022*44704f69SBart Van Assche 
5023*44704f69SBart Van Assche             if (k < 3)
5024*44704f69SBart Van Assche                 return false;
5025*44704f69SBart Van Assche             param_len = bp[3];
5026*44704f69SBart Van Assche             extra = param_len + 4;
5027*44704f69SBart Van Assche             param_code = sg_get_unaligned_be16(bp + 0);
5028*44704f69SBart Van Assche             if (op->filter_given) {
5029*44704f69SBart Van Assche                 if (param_code != op->filter)
5030*44704f69SBart Van Assche                     continue;
5031*44704f69SBart Van Assche             }
5032*44704f69SBart Van Assche             if (op->do_raw) {
5033*44704f69SBart Van Assche                 dStrRaw(bp, extra);
5034*44704f69SBart Van Assche                 goto skip;
5035*44704f69SBart Van Assche             } else if (op->do_hex) {
5036*44704f69SBart Van Assche                 hex2stdout(bp, extra, op->dstrhex_no_ascii);
5037*44704f69SBart Van Assche                 goto skip;
5038*44704f69SBart Van Assche             }
5039*44704f69SBart Van Assche             if (jsp->pr_as_json) {
5040*44704f69SBart Van Assche                 jo3p = sgj_new_unattached_object_r(jsp);
5041*44704f69SBart Van Assche                 if (op->do_pcb)
5042*44704f69SBart Van Assche                     js_pcb(jsp, jo3p, bp[2]);
5043*44704f69SBart Van Assche             }
5044*44704f69SBart Van Assche 
5045*44704f69SBart Van Assche             switch (param_code) {
5046*44704f69SBart Van Assche             case 1:     /* Statistics and performance log parameter */
5047*44704f69SBart Van Assche                 ccp = nam ? "parameter_code=1" : "Statistics and performance "
5048*44704f69SBart Van Assche                         "log parameter";
5049*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "%s\n", ccp);
5050*44704f69SBart Van Assche                 ull = sg_get_unaligned_be64(bp + 4);
5051*44704f69SBart Van Assche                 ccp = nam ? "read_commands=" : "number of read commands = ";
5052*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  %s%" PRIu64 "\n", ccp, ull);
5053*44704f69SBart Van Assche                 ull = sg_get_unaligned_be64(bp + 12);
5054*44704f69SBart Van Assche                 ccp = nam ? "write_commands=" : "number of write commands = ";
5055*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  %s%" PRIu64 "\n", ccp, ull);
5056*44704f69SBart Van Assche                 ull = sg_get_unaligned_be64(bp + 20);
5057*44704f69SBart Van Assche                 ccp = nam ? "lb_received="
5058*44704f69SBart Van Assche                           : "number of logical blocks received = ";
5059*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  %s%" PRIu64 "\n", ccp, ull);
5060*44704f69SBart Van Assche                 ull = sg_get_unaligned_be64(bp + 28);
5061*44704f69SBart Van Assche                 ccp = nam ? "lb_transmitted="
5062*44704f69SBart Van Assche                           : "number of logical blocks transmitted = ";
5063*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  %s%" PRIu64 "\n", ccp, ull);
5064*44704f69SBart Van Assche                 ull = sg_get_unaligned_be64(bp + 36);
5065*44704f69SBart Van Assche                 ccp = nam ? "read_proc_intervals="
5066*44704f69SBart Van Assche                           : "read command processing intervals = ";
5067*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  %s%" PRIu64 "\n", ccp, ull);
5068*44704f69SBart Van Assche                 ull = sg_get_unaligned_be64(bp + 44);
5069*44704f69SBart Van Assche                 ccp = nam ? "write_proc_intervals="
5070*44704f69SBart Van Assche                           : "write command processing intervals = ";
5071*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  %s%" PRIu64 "\n", ccp, ull);
5072*44704f69SBart Van Assche                 ull = sg_get_unaligned_be64(bp + 52);
5073*44704f69SBart Van Assche                 ccp = nam ? "weight_rw_commands=" : "weighted number of "
5074*44704f69SBart Van Assche                                 "read commands plus write commands = ";
5075*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  %s%" PRIu64 "\n", ccp, ull);
5076*44704f69SBart Van Assche                 ull = sg_get_unaligned_be64(bp + 60);
5077*44704f69SBart Van Assche                 ccp = nam ? "weight_rw_processing=" : "weighted read command "
5078*44704f69SBart Van Assche                                 "processing plus write command processing = ";
5079*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  %s%" PRIu64 "\n", ccp, ull);
5080*44704f69SBart Van Assche                 break;
5081*44704f69SBart Van Assche             case 2:     /* Idle time log parameter */
5082*44704f69SBart Van Assche                 ccp = nam ? "parameter_code=2" : "Idle time log parameter";
5083*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "%s\n", ccp);
5084*44704f69SBart Van Assche                 ull = sg_get_unaligned_be64(bp + 4);
5085*44704f69SBart Van Assche                 ccp = nam ? "idle_time_intervals=" : "idle time "
5086*44704f69SBart Van Assche                                 "intervals = ";
5087*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  %s%" PRIu64 "\n", ccp, ull);
5088*44704f69SBart Van Assche                 break;
5089*44704f69SBart Van Assche             case 3:     /* Time interval log parameter for general stats */
5090*44704f69SBart Van Assche                 ccp = nam ? "parameter_code=3" : "Time interval log "
5091*44704f69SBart Van Assche                         "parameter for general stats";
5092*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "%s\n", ccp);
5093*44704f69SBart Van Assche                 ui = sg_get_unaligned_be32(bp + 4);
5094*44704f69SBart Van Assche                 ccp = nam ? "time_interval_neg_exp=" : "time interval "
5095*44704f69SBart Van Assche                                 "negative exponent = ";
5096*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  %s%u\n", ccp, ui);
5097*44704f69SBart Van Assche                 ui = sg_get_unaligned_be32(bp + 8);
5098*44704f69SBart Van Assche                 ccp = nam ? "time_interval_int=" : "time interval "
5099*44704f69SBart Van Assche                                 "integer = ";
5100*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  %s%u\n", ccp, ui);
5101*44704f69SBart Van Assche                 break;
5102*44704f69SBart Van Assche             case 4:     /* FUA statistics and performance log parameter */
5103*44704f69SBart Van Assche                 ccp = nam ? "parameter_code=4" : "Force unit access "
5104*44704f69SBart Van Assche                         "statistics and performance log parameter ";
5105*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "%s\n", ccp);
5106*44704f69SBart Van Assche                 ull = sg_get_unaligned_be64(bp + 4);
5107*44704f69SBart Van Assche                 ccp = nam ? "read_fua_commands=" : "number of read FUA "
5108*44704f69SBart Van Assche                                 "commands = ";
5109*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  %s%" PRIu64 "\n", ccp, ull);
5110*44704f69SBart Van Assche                 ull = sg_get_unaligned_be64(bp + 12);
5111*44704f69SBart Van Assche                 ccp = nam ? "write_fua_commands=" : "number of write FUA "
5112*44704f69SBart Van Assche                                 "commands = ";
5113*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  %s%" PRIu64 "\n", ccp, ull);
5114*44704f69SBart Van Assche                 ull = sg_get_unaligned_be64(bp + 20);
5115*44704f69SBart Van Assche                 ccp = nam ? "read_fua_nv_commands="
5116*44704f69SBart Van Assche                           : "number of read FUA_NV commands = ";
5117*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  %s%" PRIu64 "\n", ccp, ull);
5118*44704f69SBart Van Assche                 ull = sg_get_unaligned_be64(bp + 28);
5119*44704f69SBart Van Assche                 ccp = nam ? "write_fua_nv_commands="
5120*44704f69SBart Van Assche                           : "number of write FUA_NV commands = ";
5121*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  %s%" PRIu64 "\n", ccp, ull);
5122*44704f69SBart Van Assche                 ull = sg_get_unaligned_be64(bp + 36);
5123*44704f69SBart Van Assche                 ccp = nam ? "read_fua_proc_intervals="
5124*44704f69SBart Van Assche                           : "read FUA command processing intervals = ";
5125*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  %s%" PRIu64 "\n", ccp, ull);
5126*44704f69SBart Van Assche                 ull = sg_get_unaligned_be64(bp + 44);
5127*44704f69SBart Van Assche                 ccp = nam ? "write_fua_proc_intervals="
5128*44704f69SBart Van Assche                           : "write FUA command processing intervals = ";
5129*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  %s%" PRIu64 "\n", ccp, ull);
5130*44704f69SBart Van Assche                 ull = sg_get_unaligned_be64(bp + 52);
5131*44704f69SBart Van Assche                 ccp = nam ? "read_fua_nv_proc_intervals="
5132*44704f69SBart Van Assche                           : "read FUA_NV command processing intervals = ";
5133*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  %s%" PRIu64 "\n", ccp, ull);
5134*44704f69SBart Van Assche                 ull = sg_get_unaligned_be64(bp + 60);
5135*44704f69SBart Van Assche                 ccp = nam ? "write_fua_nv_proc_intervals="
5136*44704f69SBart Van Assche                           : "write FUA_NV command processing intervals = ";
5137*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  %s%" PRIu64 "\n", ccp, ull);
5138*44704f69SBart Van Assche                 break;
5139*44704f69SBart Van Assche             case 6:     /* Time interval log parameter for cache stats */
5140*44704f69SBart Van Assche                 ccp = nam ? "parameter_code=6" : "Time interval log "
5141*44704f69SBart Van Assche                         "parameter for cache stats";
5142*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "%s\n", ccp);
5143*44704f69SBart Van Assche                 ull = sg_get_unaligned_be64(bp + 4);
5144*44704f69SBart Van Assche                 ccp = nam ? "time_interval_neg_exp=" : "time interval "
5145*44704f69SBart Van Assche                                 "negative exponent = ";
5146*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  %s%" PRIu64 "\n", ccp, ull);
5147*44704f69SBart Van Assche                 ull = sg_get_unaligned_be64(bp + 8);
5148*44704f69SBart Van Assche                 ccp = nam ? "time_interval_int=" : "time interval "
5149*44704f69SBart Van Assche                                 "integer = ";
5150*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  %s%" PRIu64 "\n", ccp, ull);
5151*44704f69SBart Van Assche                 break;
5152*44704f69SBart Van Assche             default:
5153*44704f69SBart Van Assche                 if (nam) {
5154*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "parameter_code=%d\n", param_code);
5155*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "  unknown=1\n");
5156*44704f69SBart Van Assche                 } else
5157*44704f69SBart Van Assche                     pr2serr("show_performance...  unknown %s %d\n", param_c,
5158*44704f69SBart Van Assche                             param_code);
5159*44704f69SBart Van Assche                 if (op->verbose)
5160*44704f69SBart Van Assche                     hex2stderr(bp, extra, 1);
5161*44704f69SBart Van Assche                 break;
5162*44704f69SBart Van Assche             }
5163*44704f69SBart Van Assche             if (jsp->pr_as_json)
5164*44704f69SBart Van Assche                 sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
5165*44704f69SBart Van Assche             if ((op->do_pcb) && (! op->do_name))
5166*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "    <%s>\n", get_pcb_str(bp[2], str,
5167*44704f69SBart Van Assche                           sizeof(str)));
5168*44704f69SBart Van Assche skip:
5169*44704f69SBart Van Assche             if (op->filter_given)
5170*44704f69SBart Van Assche                 break;
5171*44704f69SBart Van Assche         }
5172*44704f69SBart Van Assche     } else {    /* Group statistics and performance (n) log page */
5173*44704f69SBart Van Assche         if (num < 0x34)
5174*44704f69SBart Van Assche             return false;
5175*44704f69SBart Van Assche         for (k = num; k > 0; k -= extra, bp += extra) {
5176*44704f69SBart Van Assche             if (k < 3)
5177*44704f69SBart Van Assche                 return false;
5178*44704f69SBart Van Assche             param_len = bp[3];
5179*44704f69SBart Van Assche             extra = param_len + 4;
5180*44704f69SBart Van Assche             param_code = sg_get_unaligned_be16(bp + 0);
5181*44704f69SBart Van Assche             if (op->filter_given) {
5182*44704f69SBart Van Assche                 if (param_code != op->filter)
5183*44704f69SBart Van Assche                     continue;
5184*44704f69SBart Van Assche             }
5185*44704f69SBart Van Assche             if (op->do_raw) {
5186*44704f69SBart Van Assche                 dStrRaw(bp, extra);
5187*44704f69SBart Van Assche                 goto skip2;
5188*44704f69SBart Van Assche             } else if (op->do_hex) {
5189*44704f69SBart Van Assche                 hex2stdout(bp, extra, op->dstrhex_no_ascii);
5190*44704f69SBart Van Assche                 goto skip2;
5191*44704f69SBart Van Assche             }
5192*44704f69SBart Van Assche             if (jsp->pr_as_json) {
5193*44704f69SBart Van Assche                 jo3p = sgj_new_unattached_object_r(jsp);
5194*44704f69SBart Van Assche                 if (op->do_pcb)
5195*44704f69SBart Van Assche                     js_pcb(jsp, jo3p, bp[2]);
5196*44704f69SBart Van Assche             }
5197*44704f69SBart Van Assche 
5198*44704f69SBart Van Assche             switch (param_code) {
5199*44704f69SBart Van Assche             case 1:     /* Group n Statistics and performance log parameter */
5200*44704f69SBart Van Assche                 if (nam)
5201*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "parameter_code=1\n");
5202*44704f69SBart Van Assche                 else
5203*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "Group %d Statistics and performance log "
5204*44704f69SBart Van Assche                            "parameter\n", subpg_code);
5205*44704f69SBart Van Assche                 ull = sg_get_unaligned_be64(bp + 4);
5206*44704f69SBart Van Assche                 ccp = nam ? "gn_read_commands=" : "group n number of read "
5207*44704f69SBart Van Assche                                 "commands = ";
5208*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  %s%" PRIu64 "\n", ccp, ull);
5209*44704f69SBart Van Assche                 ull = sg_get_unaligned_be64(bp + 12);
5210*44704f69SBart Van Assche                 ccp = nam ? "gn_write_commands=" : "group n number of write "
5211*44704f69SBart Van Assche                                 "commands = ";
5212*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  %s%" PRIu64 "\n", ccp, ull);
5213*44704f69SBart Van Assche                 ull = sg_get_unaligned_be64(bp + 20);
5214*44704f69SBart Van Assche                 ccp = nam ? "gn_lb_received="
5215*44704f69SBart Van Assche                           : "group n number of logical blocks received = ";
5216*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  %s%" PRIu64 "\n", ccp, ull);
5217*44704f69SBart Van Assche                 ull = sg_get_unaligned_be64(bp + 28);
5218*44704f69SBart Van Assche                 ccp = nam ? "gn_lb_transmitted="
5219*44704f69SBart Van Assche                           : "group n number of logical blocks transmitted = ";
5220*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  %s%" PRIu64 "\n", ccp, ull);
5221*44704f69SBart Van Assche                 ull = sg_get_unaligned_be64(bp + 36);
5222*44704f69SBart Van Assche                 ccp = nam ? "gn_read_proc_intervals="
5223*44704f69SBart Van Assche                           : "group n read command processing intervals = ";
5224*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  %s%" PRIu64 "\n", ccp, ull);
5225*44704f69SBart Van Assche                 ull = sg_get_unaligned_be64(bp + 44);
5226*44704f69SBart Van Assche                 ccp = nam ? "gn_write_proc_intervals="
5227*44704f69SBart Van Assche                           : "group n write command processing intervals = ";
5228*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  %s%" PRIu64 "\n", ccp, ull);
5229*44704f69SBart Van Assche                 break;
5230*44704f69SBart Van Assche             case 4: /* Group n FUA statistics and performance log parameter */
5231*44704f69SBart Van Assche                 ccp = nam ? "parameter_code=4" : "Group n force unit access "
5232*44704f69SBart Van Assche                         "statistics and performance log parameter";
5233*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "%s\n", ccp);
5234*44704f69SBart Van Assche                 ull = sg_get_unaligned_be64(bp + 4);
5235*44704f69SBart Van Assche                 ccp = nam ? "gn_read_fua_commands="
5236*44704f69SBart Van Assche                           : "group n number of read FUA commands = ";
5237*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  %s%" PRIu64 "\n", ccp, ull);
5238*44704f69SBart Van Assche                 ull = sg_get_unaligned_be64(bp + 12);
5239*44704f69SBart Van Assche                 ccp = nam ? "gn_write_fua_commands="
5240*44704f69SBart Van Assche                           : "group n number of write FUA commands = ";
5241*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  %s%" PRIu64 "\n", ccp, ull);
5242*44704f69SBart Van Assche                 ull = sg_get_unaligned_be64(bp + 20);
5243*44704f69SBart Van Assche                 ccp = nam ? "gn_read_fua_nv_commands="
5244*44704f69SBart Van Assche                           : "group n number of read FUA_NV commands = ";
5245*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  %s%" PRIu64 "\n", ccp, ull);
5246*44704f69SBart Van Assche                 ull = sg_get_unaligned_be64(bp + 28);
5247*44704f69SBart Van Assche                 ccp = nam ? "gn_write_fua_nv_commands="
5248*44704f69SBart Van Assche                           : "group n number of write FUA_NV commands = ";
5249*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  %s%" PRIu64 "\n", ccp, ull);
5250*44704f69SBart Van Assche                 ull = sg_get_unaligned_be64(bp + 36);
5251*44704f69SBart Van Assche                 ccp = nam ? "gn_read_fua_proc_intervals="
5252*44704f69SBart Van Assche                           : "group n read FUA command processing intervals = ";
5253*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  %s%" PRIu64 "\n", ccp, ull);
5254*44704f69SBart Van Assche                 ull = sg_get_unaligned_be64(bp + 44);
5255*44704f69SBart Van Assche                 ccp = nam ? "gn_write_fua_proc_intervals=" : "group n write "
5256*44704f69SBart Van Assche                             "FUA command processing intervals = ";
5257*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  %s%" PRIu64 "\n", ccp, ull);
5258*44704f69SBart Van Assche                 ull = sg_get_unaligned_be64(bp + 52);
5259*44704f69SBart Van Assche                 ccp = nam ? "gn_read_fua_nv_proc_intervals=" : "group n "
5260*44704f69SBart Van Assche                             "read FUA_NV command processing intervals = ";
5261*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  %s%" PRIu64 "\n", ccp, ull);
5262*44704f69SBart Van Assche                 ull = sg_get_unaligned_be64(bp + 60);
5263*44704f69SBart Van Assche                 ccp = nam ? "gn_write_fua_nv_proc_intervals=" : "group n "
5264*44704f69SBart Van Assche                             "write FUA_NV command processing intervals = ";
5265*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  %s%" PRIu64 "\n", ccp, ull);
5266*44704f69SBart Van Assche                 break;
5267*44704f69SBart Van Assche             default:
5268*44704f69SBart Van Assche                 if (nam) {
5269*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "parameter_code=%d\n", param_code);
5270*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "  unknown=1\n");
5271*44704f69SBart Van Assche                 } else
5272*44704f69SBart Van Assche                     pr2serr("show_performance...  unknown %s %d\n", param_c,
5273*44704f69SBart Van Assche                             param_code);
5274*44704f69SBart Van Assche                 if (op->verbose)
5275*44704f69SBart Van Assche                     hex2stderr(bp, extra, 1);
5276*44704f69SBart Van Assche                 break;
5277*44704f69SBart Van Assche             }
5278*44704f69SBart Van Assche             if (jsp->pr_as_json)
5279*44704f69SBart Van Assche                 sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
5280*44704f69SBart Van Assche             if ((op->do_pcb) && (! op->do_name))
5281*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "    <%s>\n", get_pcb_str(bp[2], str,
5282*44704f69SBart Van Assche                           sizeof(str)));
5283*44704f69SBart Van Assche skip2:
5284*44704f69SBart Van Assche             if (op->filter_given)
5285*44704f69SBart Van Assche                 break;
5286*44704f69SBart Van Assche         }
5287*44704f69SBart Van Assche     }
5288*44704f69SBart Van Assche     return true;
5289*44704f69SBart Van Assche }
5290*44704f69SBart Van Assche 
5291*44704f69SBart Van Assche /* Returns true if processed page, false otherwise */
5292*44704f69SBart Van Assche /* STATS_LPAGE [0x19], CACHE_STATS_SUBPG [0x20] <cms>  introduced: SPC-4 */
5293*44704f69SBart Van Assche static bool
show_cache_stats_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)5294*44704f69SBart Van Assche show_cache_stats_page(const uint8_t * resp, int len, struct opts_t * op,
5295*44704f69SBart Van Assche                       sgj_opaque_p jop)
5296*44704f69SBart Van Assche {
5297*44704f69SBart Van Assche     int k, num, subpg_code, extra;
5298*44704f69SBart Van Assche     bool nam, spf;
5299*44704f69SBart Van Assche     unsigned int ui;
5300*44704f69SBart Van Assche     const uint8_t * bp;
5301*44704f69SBart Van Assche     const char * ccp;
5302*44704f69SBart Van Assche     uint64_t ull;
5303*44704f69SBart Van Assche     char str[PCB_STR_LEN];
5304*44704f69SBart Van Assche 
5305*44704f69SBart Van Assche if (jop) { };
5306*44704f69SBart Van Assche     nam = op->do_name;
5307*44704f69SBart Van Assche     num = len - 4;
5308*44704f69SBart Van Assche     bp = resp + 4;
5309*44704f69SBart Van Assche     if (num < 4) {
5310*44704f69SBart Van Assche         pr2serr("badly formed Cache memory statistics page\n");
5311*44704f69SBart Van Assche         return false;
5312*44704f69SBart Van Assche     }
5313*44704f69SBart Van Assche     spf = !!(resp[0] & 0x40);
5314*44704f69SBart Van Assche     subpg_code = spf ? resp[1] : NOT_SPG_SUBPG;
5315*44704f69SBart Van Assche     if (op->verbose || ((! op->do_raw) && (0 == op->do_hex))) {
5316*44704f69SBart Van Assche         if (nam) {
5317*44704f69SBart Van Assche             printf("log_page=0x%x\n", STATS_LPAGE);
5318*44704f69SBart Van Assche             if (subpg_code > 0)
5319*44704f69SBart Van Assche                 printf("log_subpage=0x%x\n", subpg_code);
5320*44704f69SBart Van Assche         } else
5321*44704f69SBart Van Assche             printf("Cache memory statistics page  [0x19,0x20]\n");
5322*44704f69SBart Van Assche     }
5323*44704f69SBart Van Assche 
5324*44704f69SBart Van Assche     for (k = num; k > 0; k -= extra, bp += extra) {
5325*44704f69SBart Van Assche         int pc;
5326*44704f69SBart Van Assche 
5327*44704f69SBart Van Assche         if (k < 3) {
5328*44704f69SBart Van Assche             pr2serr("short Cache memory statistics page\n");
5329*44704f69SBart Van Assche             return false;
5330*44704f69SBart Van Assche         }
5331*44704f69SBart Van Assche         if (8 != bp[3]) {
5332*44704f69SBart Van Assche             printf("Cache memory statistics page parameter length not "
5333*44704f69SBart Van Assche                    "8\n");
5334*44704f69SBart Van Assche             return false;
5335*44704f69SBart Van Assche         }
5336*44704f69SBart Van Assche         extra = bp[3] + 4;
5337*44704f69SBart Van Assche         pc = sg_get_unaligned_be16(bp + 0);
5338*44704f69SBart Van Assche         if (op->filter_given) {
5339*44704f69SBart Van Assche             if (pc != op->filter)
5340*44704f69SBart Van Assche                 continue;
5341*44704f69SBart Van Assche         }
5342*44704f69SBart Van Assche         if (op->do_raw) {
5343*44704f69SBart Van Assche             dStrRaw(bp, extra);
5344*44704f69SBart Van Assche             goto skip;
5345*44704f69SBart Van Assche         } else if (op->do_hex) {
5346*44704f69SBart Van Assche             hex2stdout(bp, extra, op->dstrhex_no_ascii);
5347*44704f69SBart Van Assche             goto skip;
5348*44704f69SBart Van Assche         }
5349*44704f69SBart Van Assche         switch (pc) {
5350*44704f69SBart Van Assche         case 1:     /* Read cache memory hits log parameter */
5351*44704f69SBart Van Assche             ccp = nam ? "parameter_code=1" :
5352*44704f69SBart Van Assche                         "Read cache memory hits log parameter";
5353*44704f69SBart Van Assche             printf("%s\n", ccp);
5354*44704f69SBart Van Assche             ull = sg_get_unaligned_be64(bp + 4);
5355*44704f69SBart Van Assche             ccp = nam ? "read_cache_memory_hits=" :
5356*44704f69SBart Van Assche                         "read cache memory hits = ";
5357*44704f69SBart Van Assche             printf("  %s%" PRIu64 "\n", ccp, ull);
5358*44704f69SBart Van Assche             break;
5359*44704f69SBart Van Assche         case 2:     /* Reads to cache memory log parameter */
5360*44704f69SBart Van Assche             ccp = nam ? "parameter_code=2" :
5361*44704f69SBart Van Assche                         "Reads to cache memory log parameter";
5362*44704f69SBart Van Assche             printf("%s\n", ccp);
5363*44704f69SBart Van Assche             ull = sg_get_unaligned_be64(bp + 4);
5364*44704f69SBart Van Assche             ccp = nam ? "reads_to_cache_memory=" :
5365*44704f69SBart Van Assche                         "reads to cache memory = ";
5366*44704f69SBart Van Assche             printf("  %s%" PRIu64 "\n", ccp, ull);
5367*44704f69SBart Van Assche             break;
5368*44704f69SBart Van Assche         case 3:     /* Write cache memory hits log parameter */
5369*44704f69SBart Van Assche             ccp = nam ? "parameter_code=3" :
5370*44704f69SBart Van Assche                         "Write cache memory hits log parameter";
5371*44704f69SBart Van Assche             printf("%s\n", ccp);
5372*44704f69SBart Van Assche             ull = sg_get_unaligned_be64(bp + 4);
5373*44704f69SBart Van Assche             ccp = nam ? "write_cache_memory_hits=" :
5374*44704f69SBart Van Assche                         "write cache memory hits = ";
5375*44704f69SBart Van Assche             printf("  %s%" PRIu64 "\n", ccp, ull);
5376*44704f69SBart Van Assche             break;
5377*44704f69SBart Van Assche         case 4:     /* Writes from cache memory log parameter */
5378*44704f69SBart Van Assche             ccp = nam ? "parameter_code=4" :
5379*44704f69SBart Van Assche                         "Writes from cache memory log parameter";
5380*44704f69SBart Van Assche             printf("%s\n", ccp);
5381*44704f69SBart Van Assche             ull = sg_get_unaligned_be64(bp + 4);
5382*44704f69SBart Van Assche             ccp = nam ? "writes_from_cache_memory=" :
5383*44704f69SBart Van Assche                         "writes from cache memory = ";
5384*44704f69SBart Van Assche             printf("  %s%" PRIu64 "\n", ccp, ull);
5385*44704f69SBart Van Assche             break;
5386*44704f69SBart Van Assche         case 5:     /* Time from last hard reset log parameter */
5387*44704f69SBart Van Assche             ccp = nam ? "parameter_code=5" :
5388*44704f69SBart Van Assche                         "Time from last hard reset log parameter";
5389*44704f69SBart Van Assche             printf("%s\n", ccp);
5390*44704f69SBart Van Assche             ull = sg_get_unaligned_be64(bp + 4);
5391*44704f69SBart Van Assche             ccp = nam ? "time_from_last_hard_reset=" :
5392*44704f69SBart Van Assche                         "time from last hard reset = ";
5393*44704f69SBart Van Assche             printf("  %s%" PRIu64 "\n", ccp, ull);
5394*44704f69SBart Van Assche             break;
5395*44704f69SBart Van Assche         case 6:     /* Time interval log parameter for cache stats */
5396*44704f69SBart Van Assche             ccp = nam ? "parameter_code=6" :
5397*44704f69SBart Van Assche                         "Time interval log parameter";
5398*44704f69SBart Van Assche             printf("%s\n", ccp);
5399*44704f69SBart Van Assche             ui = sg_get_unaligned_be32(bp + 4);
5400*44704f69SBart Van Assche             ccp = nam ? "time_interval_neg_exp=" : "time interval "
5401*44704f69SBart Van Assche                             "negative exponent = ";
5402*44704f69SBart Van Assche             printf("  %s%u\n", ccp, ui);
5403*44704f69SBart Van Assche             ui = sg_get_unaligned_be32(bp + 8);
5404*44704f69SBart Van Assche             ccp = nam ? "time_interval_int=" : "time interval "
5405*44704f69SBart Van Assche                             "integer = ";
5406*44704f69SBart Van Assche             printf("  %s%u\n", ccp, ui);
5407*44704f69SBart Van Assche             break;
5408*44704f69SBart Van Assche         default:
5409*44704f69SBart Van Assche             if (nam) {
5410*44704f69SBart Van Assche                 printf("parameter_code=%d\n", pc);
5411*44704f69SBart Van Assche                 printf("  unknown=1\n");
5412*44704f69SBart Van Assche             } else
5413*44704f69SBart Van Assche                 pr2serr("show_performance...  unknown %s %d\n", param_c,
5414*44704f69SBart Van Assche                         pc);
5415*44704f69SBart Van Assche             if (op->verbose)
5416*44704f69SBart Van Assche                 hex2stderr(bp, extra, 1);
5417*44704f69SBart Van Assche             break;
5418*44704f69SBart Van Assche         }
5419*44704f69SBart Van Assche         if ((op->do_pcb) && (! op->do_name))
5420*44704f69SBart Van Assche             printf("    <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
5421*44704f69SBart Van Assche skip:
5422*44704f69SBart Van Assche         if (op->filter_given)
5423*44704f69SBart Van Assche             break;
5424*44704f69SBart Van Assche     }
5425*44704f69SBart Van Assche     return true;
5426*44704f69SBart Van Assche }
5427*44704f69SBart Van Assche 
5428*44704f69SBart Van Assche /* FORMAT_STATUS_LPAGE [0x8] <fs>  introduced: SBC-2 */
5429*44704f69SBart Van Assche static bool
show_format_status_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)5430*44704f69SBart Van Assche show_format_status_page(const uint8_t * resp, int len,
5431*44704f69SBart Van Assche                         struct opts_t * op, sgj_opaque_p jop)
5432*44704f69SBart Van Assche {
5433*44704f69SBart Van Assche     bool is_count, is_not_avail;
5434*44704f69SBart Van Assche     int k, num, pl, pc;
5435*44704f69SBart Van Assche     uint64_t ull;
5436*44704f69SBart Van Assche     const char * cp = "";
5437*44704f69SBart Van Assche     const uint8_t * bp;
5438*44704f69SBart Van Assche     const uint8_t * xp;
5439*44704f69SBart Van Assche     sgj_state * jsp = &op->json_st;
5440*44704f69SBart Van Assche     sgj_opaque_p jo2p;
5441*44704f69SBart Van Assche     sgj_opaque_p jo3p = NULL;
5442*44704f69SBart Van Assche     sgj_opaque_p jap = NULL;
5443*44704f69SBart Van Assche     char str[PCB_STR_LEN];
5444*44704f69SBart Van Assche     char b[512];
5445*44704f69SBart Van Assche     static const char * fslp = "Format status log page";
5446*44704f69SBart Van Assche     static const char * fso = "Format status out";
5447*44704f69SBart Van Assche     static const char * fso_sn = "format_status_out";
5448*44704f69SBart Van Assche 
5449*44704f69SBart Van Assche     if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
5450*44704f69SBart Van Assche         sgj_pr_hr(jsp, "%s  [0x8]\n", fslp);
5451*44704f69SBart Van Assche     num = len - 4;
5452*44704f69SBart Van Assche     bp = &resp[0] + 4;
5453*44704f69SBart Van Assche     if (jsp->pr_as_json) {
5454*44704f69SBart Van Assche         jo2p = sg_log_js_hdr(jsp, jop, fslp, resp);
5455*44704f69SBart Van Assche         jap = sgj_named_subarray_r(jsp, jo2p, "format_status_log_parameters");
5456*44704f69SBart Van Assche     }
5457*44704f69SBart Van Assche 
5458*44704f69SBart Van Assche 
5459*44704f69SBart Van Assche     while (num > 3) {
5460*44704f69SBart Van Assche         pc = sg_get_unaligned_be16(bp + 0);
5461*44704f69SBart Van Assche         pl = bp[3] + 4;
5462*44704f69SBart Van Assche         if (op->filter_given) {
5463*44704f69SBart Van Assche             if (pc != op->filter)
5464*44704f69SBart Van Assche                 goto skip;
5465*44704f69SBart Van Assche         }
5466*44704f69SBart Van Assche         if (op->do_raw) {
5467*44704f69SBart Van Assche             dStrRaw(bp, pl);
5468*44704f69SBart Van Assche             goto filter_chk;
5469*44704f69SBart Van Assche         } else if (op->do_hex) {
5470*44704f69SBart Van Assche             hex2stdout(bp, pl, op->dstrhex_no_ascii);
5471*44704f69SBart Van Assche             goto filter_chk;
5472*44704f69SBart Van Assche         }
5473*44704f69SBart Van Assche         if (jsp->pr_as_json) {
5474*44704f69SBart Van Assche             jo3p = sgj_new_unattached_object_r(jsp);
5475*44704f69SBart Van Assche             if (op->do_pcb)
5476*44704f69SBart Van Assche                 js_pcb(jsp, jo3p, bp[2]);
5477*44704f69SBart Van Assche         }
5478*44704f69SBart Van Assche         is_count = true;
5479*44704f69SBart Van Assche 
5480*44704f69SBart Van Assche         switch (pc) {
5481*44704f69SBart Van Assche         case 0:
5482*44704f69SBart Van Assche             is_not_avail = false;
5483*44704f69SBart Van Assche             if (pl < 5)
5484*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  %s: <empty>\n", fso);
5485*44704f69SBart Van Assche             else {
5486*44704f69SBart Van Assche                 if (sg_all_ffs(bp + 4, pl - 4)) {
5487*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "  %s: <%s>\n", fso, not_avail);
5488*44704f69SBart Van Assche                     is_not_avail = true;
5489*44704f69SBart Van Assche                 } else {
5490*44704f69SBart Van Assche                     hex2str(bp + 4, pl - 4, "    ", op->hex2str_oformat,
5491*44704f69SBart Van Assche                             sizeof(b), b);
5492*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "  %s:\n%s", fso, b);
5493*44704f69SBart Van Assche 
5494*44704f69SBart Van Assche 
5495*44704f69SBart Van Assche                 }
5496*44704f69SBart Van Assche             }
5497*44704f69SBart Van Assche             if (jsp->pr_as_json) {
5498*44704f69SBart Van Assche                 sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, fso);
5499*44704f69SBart Van Assche                 if (is_not_avail)
5500*44704f69SBart Van Assche                     sgj_js_nv_ihexstr(jsp, jo3p, fso_sn, 0, NULL, not_avail);
5501*44704f69SBart Van Assche                 else
5502*44704f69SBart Van Assche                     sgj_js_nv_hex_bytes(jsp, jo3p,  fso_sn, bp + 4, pl - 4);
5503*44704f69SBart Van Assche             }
5504*44704f69SBart Van Assche             is_count = false;
5505*44704f69SBart Van Assche             break;
5506*44704f69SBart Van Assche         case 1:
5507*44704f69SBart Van Assche             cp = "Grown defects during certification";
5508*44704f69SBart Van Assche             break;
5509*44704f69SBart Van Assche         case 2:
5510*44704f69SBart Van Assche             cp = "Total blocks reassigned during format";
5511*44704f69SBart Van Assche             break;
5512*44704f69SBart Van Assche         case 3:
5513*44704f69SBart Van Assche             cp = "Total new blocks reassigned";
5514*44704f69SBart Van Assche             break;
5515*44704f69SBart Van Assche         case 4:
5516*44704f69SBart Van Assche             cp = "Power on minutes since format";
5517*44704f69SBart Van Assche             break;
5518*44704f69SBart Van Assche         default:
5519*44704f69SBart Van Assche             sgj_pr_hr(jsp, "  Unknown Format %s = 0x%x\n", param_c, pc);
5520*44704f69SBart Van Assche             is_count = false;
5521*44704f69SBart Van Assche             hex2fp(bp, pl, "    ", op->hex2str_oformat, stdout);
5522*44704f69SBart Van Assche             if (jsp->pr_as_json) {
5523*44704f69SBart Van Assche                 sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, unknown_s);
5524*44704f69SBart Van Assche                 sgj_js_nv_hex_bytes(jsp, jo3p,  in_hex, bp, pl);
5525*44704f69SBart Van Assche             }
5526*44704f69SBart Van Assche             break;
5527*44704f69SBart Van Assche         }
5528*44704f69SBart Van Assche         if (is_count) {
5529*44704f69SBart Van Assche             k = pl - 4;
5530*44704f69SBart Van Assche             xp = bp + 4;
5531*44704f69SBart Van Assche             is_not_avail = false;
5532*44704f69SBart Van Assche             ull = 0;
5533*44704f69SBart Van Assche             if (sg_all_ffs(xp, k)) {
5534*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  %s: <%s>\n", cp, not_avail);
5535*44704f69SBart Van Assche                 is_not_avail = true;
5536*44704f69SBart Van Assche             } else {
5537*44704f69SBart Van Assche                 if (k > (int)sizeof(ull)) {
5538*44704f69SBart Van Assche                     xp += (k - sizeof(ull));
5539*44704f69SBart Van Assche                     k = sizeof(ull);
5540*44704f69SBart Van Assche                 }
5541*44704f69SBart Van Assche                 ull = sg_get_unaligned_be(k, xp);
5542*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  %s = %" PRIu64 "\n", cp, ull);
5543*44704f69SBart Van Assche             }
5544*44704f69SBart Van Assche             if (jsp->pr_as_json) {
5545*44704f69SBart Van Assche                 sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, cp);
5546*44704f69SBart Van Assche                 sgj_convert_to_snake_name(cp, b, sizeof(b));
5547*44704f69SBart Van Assche                 if (is_not_avail)
5548*44704f69SBart Van Assche                     sgj_js_nv_ihexstr(jsp, jo3p, b, 0, NULL, not_avail);
5549*44704f69SBart Van Assche                 else
5550*44704f69SBart Van Assche                     sgj_js_nv_ihex(jsp, jo3p, b, ull);
5551*44704f69SBart Van Assche             }
5552*44704f69SBart Van Assche         }
5553*44704f69SBart Van Assche         if (jsp->pr_as_json)
5554*44704f69SBart Van Assche             sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
5555*44704f69SBart Van Assche         if ((op->do_pcb) && (! op->do_name))
5556*44704f69SBart Van Assche             sgj_pr_hr(jsp, "        <%s>\n", get_pcb_str(bp[2], str,
5557*44704f69SBart Van Assche                       sizeof(str)));
5558*44704f69SBart Van Assche filter_chk:
5559*44704f69SBart Van Assche         if (op->filter_given)
5560*44704f69SBart Van Assche             break;
5561*44704f69SBart Van Assche skip:
5562*44704f69SBart Van Assche         num -= pl;
5563*44704f69SBart Van Assche         bp += pl;
5564*44704f69SBart Van Assche     }
5565*44704f69SBart Van Assche     return true;
5566*44704f69SBart Van Assche }
5567*44704f69SBart Van Assche 
5568*44704f69SBart Van Assche /* Non-volatile cache page [0x17] <nvc>  introduced: SBC-2
5569*44704f69SBart Van Assche  * Standard vacillates between "non-volatile" and "nonvolatile" */
5570*44704f69SBart Van Assche static bool
show_non_volatile_cache_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)5571*44704f69SBart Van Assche show_non_volatile_cache_page(const uint8_t * resp, int len,
5572*44704f69SBart Van Assche                              struct opts_t * op, sgj_opaque_p jop)
5573*44704f69SBart Van Assche {
5574*44704f69SBart Van Assche     int j, num, pl, pc;
5575*44704f69SBart Van Assche     const char * cp;
5576*44704f69SBart Van Assche     const char * c2p;
5577*44704f69SBart Van Assche     const uint8_t * bp;
5578*44704f69SBart Van Assche     sgj_state * jsp = &op->json_st;
5579*44704f69SBart Van Assche     sgj_opaque_p jo2p;
5580*44704f69SBart Van Assche     sgj_opaque_p jo3p = NULL;
5581*44704f69SBart Van Assche     sgj_opaque_p jap = NULL;
5582*44704f69SBart Van Assche     char str[PCB_STR_LEN];
5583*44704f69SBart Van Assche     char b[96];
5584*44704f69SBart Van Assche     static const char * nvclp = "Non-volatile cache log page";
5585*44704f69SBart Van Assche     static const char * ziinv = "0 (i.e. it is now volatile)";
5586*44704f69SBart Van Assche     static const char * indef = "indefinite";
5587*44704f69SBart Van Assche 
5588*44704f69SBart Van Assche     if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
5589*44704f69SBart Van Assche          sgj_pr_hr(jsp, "%s  [0x17]\n", nvclp);
5590*44704f69SBart Van Assche     num = len - 4;
5591*44704f69SBart Van Assche     bp = &resp[0] + 4;
5592*44704f69SBart Van Assche     if (jsp->pr_as_json) {
5593*44704f69SBart Van Assche         jo2p = sg_log_js_hdr(jsp, jop, nvclp, resp);
5594*44704f69SBart Van Assche         jap = sgj_named_subarray_r(jsp, jo2p,
5595*44704f69SBart Van Assche                                    "nonvolatile_cache_log_parameters");
5596*44704f69SBart Van Assche     }
5597*44704f69SBart Van Assche 
5598*44704f69SBart Van Assche     while (num > 3) {
5599*44704f69SBart Van Assche         pc = sg_get_unaligned_be16(bp + 0);
5600*44704f69SBart Van Assche         pl = bp[3] + 4;
5601*44704f69SBart Van Assche         if (op->filter_given) {
5602*44704f69SBart Van Assche             if (pc != op->filter)
5603*44704f69SBart Van Assche                 goto skip;
5604*44704f69SBart Van Assche         }
5605*44704f69SBart Van Assche         if (op->do_raw) {
5606*44704f69SBart Van Assche             dStrRaw(bp, pl);
5607*44704f69SBart Van Assche             goto filter_chk;
5608*44704f69SBart Van Assche         } else if (op->do_hex) {
5609*44704f69SBart Van Assche             hex2stdout(bp, pl, op->dstrhex_no_ascii);
5610*44704f69SBart Van Assche             goto filter_chk;
5611*44704f69SBart Van Assche         }
5612*44704f69SBart Van Assche         if (jsp->pr_as_json) {
5613*44704f69SBart Van Assche             jo3p = sgj_new_unattached_object_r(jsp);
5614*44704f69SBart Van Assche             if (op->do_pcb)
5615*44704f69SBart Van Assche                 js_pcb(jsp, jo3p, bp[2]);
5616*44704f69SBart Van Assche         }
5617*44704f69SBart Van Assche 
5618*44704f69SBart Van Assche         cp = NULL;
5619*44704f69SBart Van Assche         switch (pc) {
5620*44704f69SBart Van Assche         case 0:
5621*44704f69SBart Van Assche             cp = "Remaining nonvolatile time";
5622*44704f69SBart Van Assche             c2p = NULL;
5623*44704f69SBart Van Assche             j = sg_get_unaligned_be24(bp + 5);
5624*44704f69SBart Van Assche             switch (j) {
5625*44704f69SBart Van Assche             case 0:
5626*44704f69SBart Van Assche                 c2p = ziinv;
5627*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  %s: %s\n", cp, c2p);
5628*44704f69SBart Van Assche                 break;
5629*44704f69SBart Van Assche             case 1:
5630*44704f69SBart Van Assche                 c2p = unknown_s;
5631*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  %s: <%s>\n", cp, c2p);
5632*44704f69SBart Van Assche                 break;
5633*44704f69SBart Van Assche             case 0xffffff:
5634*44704f69SBart Van Assche                 c2p = indef;
5635*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  %s: <%s>\n", cp, c2p);
5636*44704f69SBart Van Assche                 break;
5637*44704f69SBart Van Assche             default:
5638*44704f69SBart Van Assche                 snprintf(b, sizeof(b), "%d minutes [%d:%d]", j, (j / 60),
5639*44704f69SBart Van Assche                          (j % 60));
5640*44704f69SBart Van Assche                 c2p = b;
5641*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  %s: %s\n", cp, c2p);
5642*44704f69SBart Van Assche                 break;
5643*44704f69SBart Van Assche             }
5644*44704f69SBart Van Assche             break;
5645*44704f69SBart Van Assche         case 1:
5646*44704f69SBart Van Assche             cp = "Maximum non-volatile time";
5647*44704f69SBart Van Assche             c2p = NULL;
5648*44704f69SBart Van Assche             j = sg_get_unaligned_be24(bp + 5);
5649*44704f69SBart Van Assche             switch (j) {
5650*44704f69SBart Van Assche             case 0:
5651*44704f69SBart Van Assche                 c2p = ziinv;
5652*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  %s: %s\n", cp, c2p);
5653*44704f69SBart Van Assche                 break;
5654*44704f69SBart Van Assche             case 1:
5655*44704f69SBart Van Assche                 c2p = rsv_s;
5656*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  %s: <%s>\n", cp, c2p);
5657*44704f69SBart Van Assche                 break;
5658*44704f69SBart Van Assche             case 0xffffff:
5659*44704f69SBart Van Assche                 c2p = indef;
5660*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  %s: <%s>\n", cp, c2p);
5661*44704f69SBart Van Assche                 break;
5662*44704f69SBart Van Assche             default:
5663*44704f69SBart Van Assche                 snprintf(b, sizeof(b), "%d minutes [%d:%d]", j, (j / 60),
5664*44704f69SBart Van Assche                          (j % 60));
5665*44704f69SBart Van Assche                 c2p = b;
5666*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  %s: %s\n", cp, c2p);
5667*44704f69SBart Van Assche                 break;
5668*44704f69SBart Van Assche             }
5669*44704f69SBart Van Assche             break;
5670*44704f69SBart Van Assche         default:
5671*44704f69SBart Van Assche             sgj_pr_hr(jsp, "  Unknown %s = 0x%x\n", param_c, pc);
5672*44704f69SBart Van Assche             hex2stdout(bp, pl, op->dstrhex_no_ascii);
5673*44704f69SBart Van Assche             break;
5674*44704f69SBart Van Assche         }
5675*44704f69SBart Van Assche         if (jsp->pr_as_json) {
5676*44704f69SBart Van Assche             sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL,
5677*44704f69SBart Van Assche                               cp ? cp : unknown_s);
5678*44704f69SBart Van Assche             if (cp)
5679*44704f69SBart Van Assche                 js_snakenv_ihexstr_nex(jsp, jo3p, cp , j, true,
5680*44704f69SBart Van Assche                                        NULL, c2p, NULL);
5681*44704f69SBart Van Assche             else if (pl > 4)
5682*44704f69SBart Van Assche                 sgj_js_nv_hex_bytes(jsp, jo3p, in_hex, bp + 4, pl - 4);
5683*44704f69SBart Van Assche 
5684*44704f69SBart Van Assche             sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
5685*44704f69SBart Van Assche         }
5686*44704f69SBart Van Assche         if ((op->do_pcb) && (! op->do_name))
5687*44704f69SBart Van Assche             sgj_pr_hr(jsp, "        <%s>\n", get_pcb_str(bp[2], str,
5688*44704f69SBart Van Assche                       sizeof(str)));
5689*44704f69SBart Van Assche filter_chk:
5690*44704f69SBart Van Assche         if (op->filter_given)
5691*44704f69SBart Van Assche             break;
5692*44704f69SBart Van Assche skip:
5693*44704f69SBart Van Assche         num -= pl;
5694*44704f69SBart Van Assche         bp += pl;
5695*44704f69SBart Van Assche     }
5696*44704f69SBart Van Assche     return true;
5697*44704f69SBart Van Assche }
5698*44704f69SBart Van Assche 
5699*44704f69SBart Van Assche /* LB_PROV_LPAGE [0xc] <lbp> introduced: SBC-3 */
5700*44704f69SBart Van Assche static bool
show_lb_provisioning_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)5701*44704f69SBart Van Assche show_lb_provisioning_page(const uint8_t * resp, int len,
5702*44704f69SBart Van Assche                           struct opts_t * op, sgj_opaque_p jop)
5703*44704f69SBart Van Assche {
5704*44704f69SBart Van Assche     bool evsm_output = false;
5705*44704f69SBart Van Assche     int num, pl, pc;
5706*44704f69SBart Van Assche     const uint8_t * bp;
5707*44704f69SBart Van Assche     const char * cp;
5708*44704f69SBart Van Assche     char str[PCB_STR_LEN];
5709*44704f69SBart Van Assche 
5710*44704f69SBart Van Assche if (jop) { };
5711*44704f69SBart Van Assche     if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
5712*44704f69SBart Van Assche         printf("Logical block provisioning page  [0xc]\n");
5713*44704f69SBart Van Assche     num = len - 4;
5714*44704f69SBart Van Assche     bp = &resp[0] + 4;
5715*44704f69SBart Van Assche     while (num > 3) {
5716*44704f69SBart Van Assche         pc = sg_get_unaligned_be16(bp + 0);
5717*44704f69SBart Van Assche         pl = bp[3] + 4;
5718*44704f69SBart Van Assche         if (op->filter_given) {
5719*44704f69SBart Van Assche             if (pc != op->filter)
5720*44704f69SBart Van Assche                 goto skip;
5721*44704f69SBart Van Assche         }
5722*44704f69SBart Van Assche         if (op->do_raw) {
5723*44704f69SBart Van Assche             dStrRaw(bp, pl);
5724*44704f69SBart Van Assche             goto filter_chk;
5725*44704f69SBart Van Assche         } else if (op->do_hex) {
5726*44704f69SBart Van Assche             hex2stdout(bp, pl, op->dstrhex_no_ascii);
5727*44704f69SBart Van Assche             goto filter_chk;
5728*44704f69SBart Van Assche         }
5729*44704f69SBart Van Assche         switch (pc) {
5730*44704f69SBart Van Assche         case 0x1:
5731*44704f69SBart Van Assche             cp = "  Available LBA mapping threshold";
5732*44704f69SBart Van Assche             break;
5733*44704f69SBart Van Assche         case 0x2:
5734*44704f69SBart Van Assche             cp = "  Used LBA mapping threshold";
5735*44704f69SBart Van Assche             break;
5736*44704f69SBart Van Assche         case 0x3:
5737*44704f69SBart Van Assche             cp = "  Available provisioning resource percentage";
5738*44704f69SBart Van Assche             break;
5739*44704f69SBart Van Assche         case 0x100:
5740*44704f69SBart Van Assche             cp = "  De-duplicated LBA";
5741*44704f69SBart Van Assche             break;
5742*44704f69SBart Van Assche         case 0x101:
5743*44704f69SBart Van Assche             cp = "  Compressed LBA";
5744*44704f69SBart Van Assche             break;
5745*44704f69SBart Van Assche         case 0x102:
5746*44704f69SBart Van Assche             cp = "  Total efficiency LBA";
5747*44704f69SBart Van Assche             break;
5748*44704f69SBart Van Assche         default:
5749*44704f69SBart Van Assche             cp = NULL;
5750*44704f69SBart Van Assche             break;
5751*44704f69SBart Van Assche         }
5752*44704f69SBart Van Assche         if (cp) {
5753*44704f69SBart Van Assche             if ((pl < 8) || (num < 8)) {
5754*44704f69SBart Van Assche                 if (num < 8)
5755*44704f69SBart Van Assche                     pr2serr("\n    truncated by response length, expected at "
5756*44704f69SBart Van Assche                             "least 8 bytes\n");
5757*44704f69SBart Van Assche                 else
5758*44704f69SBart Van Assche                     pr2serr("\n    parameter length >= 8 expected, got %d\n",
5759*44704f69SBart Van Assche                             pl);
5760*44704f69SBart Van Assche                 break;
5761*44704f69SBart Van Assche             }
5762*44704f69SBart Van Assche             if (0x3 == pc)      /* resource percentage log parameter */
5763*44704f69SBart Van Assche                 printf("  %s: %u %%\n", cp, sg_get_unaligned_be16(bp + 4));
5764*44704f69SBart Van Assche             else                /* resource count log parameters */
5765*44704f69SBart Van Assche                 printf("  %s resource count: %u\n", cp,
5766*44704f69SBart Van Assche                        sg_get_unaligned_be32(bp + 4));
5767*44704f69SBart Van Assche             if (pl > 8) {
5768*44704f69SBart Van Assche                 switch (bp[8] & 0x3) {      /* SCOPE field */
5769*44704f69SBart Van Assche                 case 0: cp = not_rep; break;
5770*44704f69SBart Van Assche                 case 1: cp = "dedicated to lu"; break;
5771*44704f69SBart Van Assche                 case 2: cp = "not dedicated to lu"; break;
5772*44704f69SBart Van Assche                 case 3: cp = rsv_s; break;
5773*44704f69SBart Van Assche                 }
5774*44704f69SBart Van Assche                 printf("    Scope: %s\n", cp);
5775*44704f69SBart Van Assche             }
5776*44704f69SBart Van Assche         } else if ((pc >= 0xfff0) && (pc <= 0xffff)) {
5777*44704f69SBart Van Assche             if (op->exclude_vendor) {
5778*44704f69SBart Van Assche                 if ((op->verbose > 0) && (0 == op->do_brief) &&
5779*44704f69SBart Van Assche                     (! evsm_output)) {
5780*44704f69SBart Van Assche                     evsm_output = true;
5781*44704f69SBart Van Assche                     printf("  %s parameter(s) being ignored\n", vend_spec);
5782*44704f69SBart Van Assche                 }
5783*44704f69SBart Van Assche             } else {
5784*44704f69SBart Van Assche                 printf("  %s [0x%x]:", vend_spec, pc);
5785*44704f69SBart Van Assche                 hex2stdout(bp, ((pl < num) ? pl : num), op->dstrhex_no_ascii);
5786*44704f69SBart Van Assche             }
5787*44704f69SBart Van Assche         } else {
5788*44704f69SBart Van Assche             printf("  Reserved [%s=0x%x]:\n", param_c_sn, pc);
5789*44704f69SBart Van Assche             hex2stdout(bp, ((pl < num) ? pl : num), op->dstrhex_no_ascii);
5790*44704f69SBart Van Assche         }
5791*44704f69SBart Van Assche         if (op->do_pcb)
5792*44704f69SBart Van Assche             printf("        <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
5793*44704f69SBart Van Assche filter_chk:
5794*44704f69SBart Van Assche         if (op->filter_given)
5795*44704f69SBart Van Assche             break;
5796*44704f69SBart Van Assche skip:
5797*44704f69SBart Van Assche         num -= pl;
5798*44704f69SBart Van Assche         bp += pl;
5799*44704f69SBart Van Assche     }
5800*44704f69SBart Van Assche     return true;
5801*44704f69SBart Van Assche }
5802*44704f69SBart Van Assche 
5803*44704f69SBart Van Assche /* UTILIZATION_SUBPG [0xe,0x1] <util>  introduced: SBC-4 */
5804*44704f69SBart Van Assche static bool
show_utilization_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)5805*44704f69SBart Van Assche show_utilization_page(const uint8_t * resp, int len, struct opts_t * op,
5806*44704f69SBart Van Assche                       sgj_opaque_p jop)
5807*44704f69SBart Van Assche {
5808*44704f69SBart Van Assche     int num, pl, pc, k;
5809*44704f69SBart Van Assche     const uint8_t * bp;
5810*44704f69SBart Van Assche     char str[PCB_STR_LEN];
5811*44704f69SBart Van Assche 
5812*44704f69SBart Van Assche if (jop) { };
5813*44704f69SBart Van Assche     if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
5814*44704f69SBart Van Assche         printf("Utilization page  [0xe,0x1]\n");
5815*44704f69SBart Van Assche     num = len - 4;
5816*44704f69SBart Van Assche     bp = &resp[0] + 4;
5817*44704f69SBart Van Assche     while (num > 3) {
5818*44704f69SBart Van Assche         pc = sg_get_unaligned_be16(bp + 0);
5819*44704f69SBart Van Assche         pl = bp[3] + 4;
5820*44704f69SBart Van Assche         if (op->filter_given) {
5821*44704f69SBart Van Assche             if (pc != op->filter)
5822*44704f69SBart Van Assche                 goto skip;
5823*44704f69SBart Van Assche         }
5824*44704f69SBart Van Assche         if (op->do_raw) {
5825*44704f69SBart Van Assche             dStrRaw(bp, pl);
5826*44704f69SBart Van Assche             goto filter_chk;
5827*44704f69SBart Van Assche         } else if (op->do_hex) {
5828*44704f69SBart Van Assche             hex2stdout(bp, pl, op->dstrhex_no_ascii);
5829*44704f69SBart Van Assche             goto filter_chk;
5830*44704f69SBart Van Assche         }
5831*44704f69SBart Van Assche         switch (pc) {
5832*44704f69SBart Van Assche         case 0x0:
5833*44704f69SBart Van Assche             printf("  Workload utilization:");
5834*44704f69SBart Van Assche             if ((pl < 6) || (num < 6)) {
5835*44704f69SBart Van Assche                 if (num < 6)
5836*44704f69SBart Van Assche                     pr2serr("\n    truncated by response length, expected "
5837*44704f69SBart Van Assche                             "at least 6 bytes\n");
5838*44704f69SBart Van Assche                 else
5839*44704f69SBart Van Assche                     pr2serr("\n    parameter length >= 6 expected, got %d\n",
5840*44704f69SBart Van Assche                             pl);
5841*44704f69SBart Van Assche                 break;
5842*44704f69SBart Van Assche             }
5843*44704f69SBart Van Assche             k = sg_get_unaligned_be16(bp + 4);
5844*44704f69SBart Van Assche             printf(" %d.%02d %%\n", k / 100, k % 100);
5845*44704f69SBart Van Assche             break;
5846*44704f69SBart Van Assche         case 0x1:
5847*44704f69SBart Van Assche             printf("  Utilization usage rate based on date and time:");
5848*44704f69SBart Van Assche             if ((pl < 6) || (num < 6)) {
5849*44704f69SBart Van Assche                 if (num < 6)
5850*44704f69SBart Van Assche                     pr2serr("\n    truncated by response length, expected "
5851*44704f69SBart Van Assche                             "at least 6 bytes\n");
5852*44704f69SBart Van Assche                 else
5853*44704f69SBart Van Assche                     pr2serr("\n    parameter length >= 6 expected, got %d\n",
5854*44704f69SBart Van Assche                             pl);
5855*44704f69SBart Van Assche                 break;
5856*44704f69SBart Van Assche             }
5857*44704f69SBart Van Assche             printf(" %d %%\n", bp[4]);
5858*44704f69SBart Van Assche             break;
5859*44704f69SBart Van Assche         default:
5860*44704f69SBart Van Assche             printf("  Reserved [parameter_code=0x%x]:\n", pc);
5861*44704f69SBart Van Assche             hex2stdout(bp, ((pl < num) ? pl : num), op->dstrhex_no_ascii);
5862*44704f69SBart Van Assche             break;
5863*44704f69SBart Van Assche         }
5864*44704f69SBart Van Assche         if (op->do_pcb)
5865*44704f69SBart Van Assche             printf("        <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
5866*44704f69SBart Van Assche filter_chk:
5867*44704f69SBart Van Assche         if (op->filter_given)
5868*44704f69SBart Van Assche             break;
5869*44704f69SBart Van Assche skip:
5870*44704f69SBart Van Assche         num -= pl;
5871*44704f69SBart Van Assche         bp += pl;
5872*44704f69SBart Van Assche     }
5873*44704f69SBart Van Assche     return true;
5874*44704f69SBart Van Assche }
5875*44704f69SBart Van Assche 
5876*44704f69SBart Van Assche /* SOLID_STATE_MEDIA_LPAGE [0x11] <ssm>  introduced: SBC-3 */
5877*44704f69SBart Van Assche static bool
show_solid_state_media_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)5878*44704f69SBart Van Assche show_solid_state_media_page(const uint8_t * resp, int len,
5879*44704f69SBart Van Assche                             struct opts_t * op, sgj_opaque_p jop)
5880*44704f69SBart Van Assche {
5881*44704f69SBart Van Assche     int num, pl, pc;
5882*44704f69SBart Van Assche     const uint8_t * bp;
5883*44704f69SBart Van Assche     sgj_state * jsp = &op->json_st;
5884*44704f69SBart Van Assche     sgj_opaque_p jo2p;
5885*44704f69SBart Van Assche     sgj_opaque_p jo3p = NULL;
5886*44704f69SBart Van Assche     sgj_opaque_p jap = NULL;
5887*44704f69SBart Van Assche     char str[PCB_STR_LEN];
5888*44704f69SBart Van Assche     static const char * ssmlp = "Solid state media log page";
5889*44704f69SBart Van Assche     static const char * puei = "Percentage used endurance indicator";
5890*44704f69SBart Van Assche 
5891*44704f69SBart Van Assche     if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
5892*44704f69SBart Van Assche         sgj_pr_hr(jsp, "%s  [0x11]\n", ssmlp);
5893*44704f69SBart Van Assche     if (jsp->pr_as_json) {
5894*44704f69SBart Van Assche         jo2p = sg_log_js_hdr(jsp, jop, ssmlp, resp);
5895*44704f69SBart Van Assche         jap = sgj_named_subarray_r(jsp, jo2p,
5896*44704f69SBart Van Assche                            "solid_state_media_log_parameters");
5897*44704f69SBart Van Assche     }
5898*44704f69SBart Van Assche     num = len - 4;
5899*44704f69SBart Van Assche     bp = &resp[0] + 4;
5900*44704f69SBart Van Assche     while (num > 3) {
5901*44704f69SBart Van Assche         pc = sg_get_unaligned_be16(bp + 0);
5902*44704f69SBart Van Assche         pl = bp[3] + 4;
5903*44704f69SBart Van Assche         if (op->filter_given) {
5904*44704f69SBart Van Assche             if (pc != op->filter)
5905*44704f69SBart Van Assche                 goto skip;
5906*44704f69SBart Van Assche         }
5907*44704f69SBart Van Assche         if (op->do_raw) {
5908*44704f69SBart Van Assche             dStrRaw(bp, pl);
5909*44704f69SBart Van Assche             goto filter_chk;
5910*44704f69SBart Van Assche         } else if (op->do_hex) {
5911*44704f69SBart Van Assche             hex2stdout(bp, pl, op->dstrhex_no_ascii);
5912*44704f69SBart Van Assche             goto filter_chk;
5913*44704f69SBart Van Assche         }
5914*44704f69SBart Van Assche         if (jsp->pr_as_json) {
5915*44704f69SBart Van Assche             jo3p = sgj_new_unattached_object_r(jsp);
5916*44704f69SBart Van Assche             if (op->do_pcb)
5917*44704f69SBart Van Assche                 js_pcb(jsp, jo3p, bp[2]);
5918*44704f69SBart Van Assche         }
5919*44704f69SBart Van Assche 
5920*44704f69SBart Van Assche         switch (pc) {
5921*44704f69SBart Van Assche         case 0x1:
5922*44704f69SBart Van Assche             if ((pl < 8) || (num < 8)) {
5923*44704f69SBart Van Assche                 if (num < 8)
5924*44704f69SBart Van Assche                     pr2serr("\n    truncated by response length, expected "
5925*44704f69SBart Van Assche                             "at least 8 bytes\n");
5926*44704f69SBart Van Assche                 else
5927*44704f69SBart Van Assche                     pr2serr("\n    parameter length >= 8 expected, got %d\n",
5928*44704f69SBart Van Assche                             pl);
5929*44704f69SBart Van Assche                 break;
5930*44704f69SBart Van Assche             }
5931*44704f69SBart Van Assche             sgj_pr_hr(jsp, "  %s: %u %%\n", puei, bp[7]);
5932*44704f69SBart Van Assche             if (jsp->pr_as_json) {
5933*44704f69SBart Van Assche                 js_snakenv_ihexstr_nex(jsp, jo3p, param_c, pc, true,
5934*44704f69SBart Van Assche                                        NULL, puei, NULL);
5935*44704f69SBart Van Assche                 js_snakenv_ihexstr_nex(jsp, jo3p, puei, bp[7], false,
5936*44704f69SBart Van Assche                                        NULL, NULL, NULL);
5937*44704f69SBart Van Assche             }
5938*44704f69SBart Van Assche             break;
5939*44704f69SBart Van Assche         default:
5940*44704f69SBart Van Assche             printf("  Reserved [parameter_code=0x%x]:\n", pc);
5941*44704f69SBart Van Assche             hex2stdout(bp, ((pl < num) ? pl : num), op->dstrhex_no_ascii);
5942*44704f69SBart Van Assche             break;
5943*44704f69SBart Van Assche         }
5944*44704f69SBart Van Assche         if (jsp->pr_as_json)
5945*44704f69SBart Van Assche             sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
5946*44704f69SBart Van Assche         if (op->do_pcb)
5947*44704f69SBart Van Assche             sgj_pr_hr(jsp, "        <%s>\n", get_pcb_str(bp[2], str,
5948*44704f69SBart Van Assche                       sizeof(str)));
5949*44704f69SBart Van Assche filter_chk:
5950*44704f69SBart Van Assche         if (op->filter_given)
5951*44704f69SBart Van Assche             break;
5952*44704f69SBart Van Assche skip:
5953*44704f69SBart Van Assche         num -= pl;
5954*44704f69SBart Van Assche         bp += pl;
5955*44704f69SBart Van Assche     }
5956*44704f69SBart Van Assche     return true;
5957*44704f69SBart Van Assche }
5958*44704f69SBart Van Assche 
5959*44704f69SBart Van Assche static const char * dt_dev_activity[] = {
5960*44704f69SBart Van Assche     "No DT device activity",
5961*44704f69SBart Van Assche     "Cleaning operation in progress",
5962*44704f69SBart Van Assche     "Volume is being loaded",
5963*44704f69SBart Van Assche     "Volume is being unloaded",
5964*44704f69SBart Van Assche     "Other medium activity",
5965*44704f69SBart Van Assche     "Reading from medium",
5966*44704f69SBart Van Assche     "Writing to medium",
5967*44704f69SBart Van Assche     "Locating medium",
5968*44704f69SBart Van Assche     "Rewinding medium", /* 8 */
5969*44704f69SBart Van Assche     "Erasing volume",
5970*44704f69SBart Van Assche     "Formatting volume",
5971*44704f69SBart Van Assche     "Calibrating",
5972*44704f69SBart Van Assche     "Other DT device activity",
5973*44704f69SBart Van Assche     "Microcode update in progress",
5974*44704f69SBart Van Assche     "Reading encrypted from medium",
5975*44704f69SBart Van Assche     "Writing encrypted to medium",
5976*44704f69SBart Van Assche     "Diagnostic operation in progress", /* 10 */
5977*44704f69SBart Van Assche };
5978*44704f69SBart Van Assche 
5979*44704f69SBart Van Assche /* DT device status [0x11] <dtds> (ssc, adc) */
5980*44704f69SBart Van Assche static bool
show_dt_device_status_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)5981*44704f69SBart Van Assche show_dt_device_status_page(const uint8_t * resp, int len,
5982*44704f69SBart Van Assche                            struct opts_t * op, sgj_opaque_p jop)
5983*44704f69SBart Van Assche {
5984*44704f69SBart Van Assche     bool evsm_output = false;
5985*44704f69SBart Van Assche     int num, pl, pc, j;
5986*44704f69SBart Van Assche     const uint8_t * bp;
5987*44704f69SBart Van Assche     char str[PCB_STR_LEN];
5988*44704f69SBart Van Assche     char b[512];
5989*44704f69SBart Van Assche 
5990*44704f69SBart Van Assche if (jop) { };
5991*44704f69SBart Van Assche     if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
5992*44704f69SBart Van Assche         printf("DT device status page (ssc-3, adc-3) [0x11]\n");
5993*44704f69SBart Van Assche     num = len - 4;
5994*44704f69SBart Van Assche     bp = &resp[0] + 4;
5995*44704f69SBart Van Assche     while (num > 3) {
5996*44704f69SBart Van Assche         pc = sg_get_unaligned_be16(bp + 0);
5997*44704f69SBart Van Assche         pl = bp[3] + 4;
5998*44704f69SBart Van Assche         if (op->filter_given) {
5999*44704f69SBart Van Assche             if (pc != op->filter)
6000*44704f69SBart Van Assche                 goto skip;
6001*44704f69SBart Van Assche         }
6002*44704f69SBart Van Assche         if (op->do_raw) {
6003*44704f69SBart Van Assche             dStrRaw(bp, pl);
6004*44704f69SBart Van Assche             goto filter_chk;
6005*44704f69SBart Van Assche         } else if (op->do_hex) {
6006*44704f69SBart Van Assche             hex2stdout(bp, pl, op->dstrhex_no_ascii);
6007*44704f69SBart Van Assche             goto filter_chk;
6008*44704f69SBart Van Assche         }
6009*44704f69SBart Van Assche         switch (pc) {
6010*44704f69SBart Van Assche         case 0x0:
6011*44704f69SBart Van Assche             printf("  Very high frequency data:\n");
6012*44704f69SBart Van Assche             if ((pl < 8) || (num < 8)) {
6013*44704f69SBart Van Assche                 if (num < 8)
6014*44704f69SBart Van Assche                     pr2serr("    truncated by response length, expected at "
6015*44704f69SBart Van Assche                             "least 8 bytes\n");
6016*44704f69SBart Van Assche                 else
6017*44704f69SBart Van Assche                     pr2serr("    parameter length >= 8 expected, got %d\n",
6018*44704f69SBart Van Assche                             pl);
6019*44704f69SBart Van Assche                 break;
6020*44704f69SBart Van Assche             }
6021*44704f69SBart Van Assche             printf("  PAMR=%d HUI=%d MACC=%d CMPR=%d ", !!(0x80 & bp[4]),
6022*44704f69SBart Van Assche                    !!(0x40 & bp[4]), !!(0x20 & bp[4]), !!(0x10 & bp[4]));
6023*44704f69SBart Van Assche             printf("WRTP=%d CRQST=%d CRQRD=%d DINIT=%d\n", !!(0x8 & bp[4]),
6024*44704f69SBart Van Assche                    !!(0x4 & bp[4]), !!(0x2 & bp[4]), !!(0x1 & bp[4]));
6025*44704f69SBart Van Assche             printf("  INXTN=%d RAA=%d MPRSNT=%d ", !!(0x80 & bp[5]),
6026*44704f69SBart Van Assche                    !!(0x20 & bp[5]), !!(0x10 & bp[5]));
6027*44704f69SBart Van Assche             printf("MSTD=%d MTHRD=%d MOUNTED=%d\n",
6028*44704f69SBart Van Assche                    !!(0x4 & bp[5]), !!(0x2 & bp[5]), !!(0x1 & bp[5]));
6029*44704f69SBart Van Assche             printf("  DT device activity: ");
6030*44704f69SBart Van Assche             j = bp[6];
6031*44704f69SBart Van Assche             if (j < (int)SG_ARRAY_SIZE(dt_dev_activity))
6032*44704f69SBart Van Assche                 printf("%s\n", dt_dev_activity[j]);
6033*44704f69SBart Van Assche             else if (j < 0x80)
6034*44704f69SBart Van Assche                 printf("Reserved [0x%x]\n", j);
6035*44704f69SBart Van Assche             else
6036*44704f69SBart Van Assche                 printf("%s [0x%x]\n", vend_spec, j);
6037*44704f69SBart Van Assche             printf("  VS=%d TDDEC=%d EPP=%d ", !!(0x80 & bp[7]),
6038*44704f69SBart Van Assche                    !!(0x20 & bp[7]), !!(0x10 & bp[7]));
6039*44704f69SBart Van Assche             printf("ESR=%d RRQST=%d INTFC=%d TAFC=%d\n", !!(0x8 & bp[7]),
6040*44704f69SBart Van Assche                    !!(0x4 & bp[7]), !!(0x2 & bp[7]), !!(0x1 & bp[7]));
6041*44704f69SBart Van Assche             break;
6042*44704f69SBart Van Assche         case 0x1:
6043*44704f69SBart Van Assche             printf("  Very high frequency polling delay: ");
6044*44704f69SBart Van Assche             if ((pl < 6) || (num < 6)) {
6045*44704f69SBart Van Assche                 if (num < 6)
6046*44704f69SBart Van Assche                     pr2serr("\n    truncated by response length, expected at "
6047*44704f69SBart Van Assche                             "least 6 bytes\n");
6048*44704f69SBart Van Assche                 else
6049*44704f69SBart Van Assche                     pr2serr("\n    parameter length >= 6 expected, got %d\n",
6050*44704f69SBart Van Assche                             pl);
6051*44704f69SBart Van Assche                 break;
6052*44704f69SBart Van Assche             }
6053*44704f69SBart Van Assche             printf(" %d milliseconds\n", sg_get_unaligned_be16(bp + 4));
6054*44704f69SBart Van Assche             break;
6055*44704f69SBart Van Assche         case 0x2:
6056*44704f69SBart Van Assche             printf("   DT device ADC data encryption control status (hex "
6057*44704f69SBart Van Assche                    "only now):\n");
6058*44704f69SBart Van Assche             if ((pl < 12) || (num < 12)) {
6059*44704f69SBart Van Assche                 if (num < 12)
6060*44704f69SBart Van Assche                     pr2serr("    truncated by response length, expected at "
6061*44704f69SBart Van Assche                             "least 12 bytes\n");
6062*44704f69SBart Van Assche                 else
6063*44704f69SBart Van Assche                     pr2serr("    parameter length >= 12 expected, got %d\n",
6064*44704f69SBart Van Assche                             pl);
6065*44704f69SBart Van Assche                 break;
6066*44704f69SBart Van Assche             }
6067*44704f69SBart Van Assche             hex2fp(bp + 4, 8, "      ", op->hex2str_oformat, stdout);
6068*44704f69SBart Van Assche             break;
6069*44704f69SBart Van Assche         case 0x3:
6070*44704f69SBart Van Assche             printf("   Key management error data (hex only now):\n");
6071*44704f69SBart Van Assche             if ((pl < 16) || (num < 16)) {
6072*44704f69SBart Van Assche                 if (num < 16)
6073*44704f69SBart Van Assche                     pr2serr("    truncated by response length, expected at "
6074*44704f69SBart Van Assche                             "least 16 bytes\n");
6075*44704f69SBart Van Assche                 else
6076*44704f69SBart Van Assche                     pr2serr("    parameter length >= 16 expected, got %d\n",
6077*44704f69SBart Van Assche                             pl);
6078*44704f69SBart Van Assche                 break;
6079*44704f69SBart Van Assche             }
6080*44704f69SBart Van Assche             hex2fp(bp + 4, 12, "      ", op->hex2str_oformat, stdout);
6081*44704f69SBart Van Assche             break;
6082*44704f69SBart Van Assche         default:
6083*44704f69SBart Van Assche             if ((pc >= 0x101) && (pc <= 0x1ff)) {
6084*44704f69SBart Van Assche                 printf("  Primary port %d status:\n", pc - 0x100);
6085*44704f69SBart Van Assche                 if (12 == bp[3]) { /* if length of desc is 12, assume SAS */
6086*44704f69SBart Van Assche                     printf("    SAS: negotiated physical link rate: %s\n",
6087*44704f69SBart Van Assche                            sas_negot_link_rate((0xf & (bp[4] >> 4)), b,
6088*44704f69SBart Van Assche                                                sizeof(b)));
6089*44704f69SBart Van Assche                     printf("    signal=%d, pic=%d, ", !!(0x2 & bp[4]),
6090*44704f69SBart Van Assche                            !!(0x1 & bp[4]));
6091*44704f69SBart Van Assche                     printf("hashed SAS addr: 0x%u\n",
6092*44704f69SBart Van Assche                             sg_get_unaligned_be24(bp + 5));
6093*44704f69SBart Van Assche                     printf("    SAS addr: 0x%" PRIx64 "\n",
6094*44704f69SBart Van Assche                             sg_get_unaligned_be64(bp + 8));
6095*44704f69SBart Van Assche                 } else {
6096*44704f69SBart Van Assche                     printf("    non-SAS transport, in hex:\n");
6097*44704f69SBart Van Assche                     hex2fp(bp + 4, ((pl < num) ? pl : num) - 4, "      ",
6098*44704f69SBart Van Assche                            op->hex2str_oformat, stdout);
6099*44704f69SBart Van Assche                 }
6100*44704f69SBart Van Assche             } else if (pc >= 0x8000) {
6101*44704f69SBart Van Assche                 if (op->exclude_vendor) {
6102*44704f69SBart Van Assche                     if ((op->verbose > 0) && (0 == op->do_brief) &&
6103*44704f69SBart Van Assche                         (! evsm_output)) {
6104*44704f69SBart Van Assche                         evsm_output = true;
6105*44704f69SBart Van Assche                         printf("  %s parameter(s) being ignored\n",
6106*44704f69SBart Van Assche                                vend_spec);
6107*44704f69SBart Van Assche                     }
6108*44704f69SBart Van Assche                 } else {
6109*44704f69SBart Van Assche                     printf("  %s [%s=0x%x]:\n", vend_spec, param_c_sn, pc);
6110*44704f69SBart Van Assche                     hex2fp(bp, ((pl < num) ? pl : num), "    ",
6111*44704f69SBart Van Assche                            op->hex2str_oformat, stdout);
6112*44704f69SBart Van Assche                 }
6113*44704f69SBart Van Assche             } else {
6114*44704f69SBart Van Assche                 printf("  Reserved [%s=0x%x]:\n", param_c_sn, pc);
6115*44704f69SBart Van Assche                 hex2fp(bp, ((pl < num) ? pl : num), "    ",
6116*44704f69SBart Van Assche                         op->hex2str_oformat, stdout);
6117*44704f69SBart Van Assche             }
6118*44704f69SBart Van Assche             break;
6119*44704f69SBart Van Assche         }
6120*44704f69SBart Van Assche         if (op->do_pcb)
6121*44704f69SBart Van Assche             printf("        <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
6122*44704f69SBart Van Assche filter_chk:
6123*44704f69SBart Van Assche         if (op->filter_given)
6124*44704f69SBart Van Assche             break;
6125*44704f69SBart Van Assche skip:
6126*44704f69SBart Van Assche         num -= pl;
6127*44704f69SBart Van Assche         bp += pl;
6128*44704f69SBart Van Assche     }
6129*44704f69SBart Van Assche     return true;
6130*44704f69SBart Van Assche }
6131*44704f69SBart Van Assche 
6132*44704f69SBart Van Assche /* TapeAlert response [0x12] <tar> (adc,ssc) */
6133*44704f69SBart Van Assche static bool
show_tapealert_response_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)6134*44704f69SBart Van Assche show_tapealert_response_page(const uint8_t * resp, int len,
6135*44704f69SBart Van Assche                              struct opts_t * op, sgj_opaque_p jop)
6136*44704f69SBart Van Assche {
6137*44704f69SBart Van Assche     bool evsm_output = false;
6138*44704f69SBart Van Assche     int num, pl, pc, k, mod, div;
6139*44704f69SBart Van Assche     const uint8_t * bp;
6140*44704f69SBart Van Assche     char str[PCB_STR_LEN];
6141*44704f69SBart Van Assche 
6142*44704f69SBart Van Assche if (jop) { };
6143*44704f69SBart Van Assche     if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
6144*44704f69SBart Van Assche         printf("TapeAlert response page (ssc-3, adc-3) [0x12]\n");
6145*44704f69SBart Van Assche     num = len - 4;
6146*44704f69SBart Van Assche     bp = &resp[0] + 4;
6147*44704f69SBart Van Assche     while (num > 3) {
6148*44704f69SBart Van Assche         pc = sg_get_unaligned_be16(bp + 0);
6149*44704f69SBart Van Assche         pl = bp[3] + 4;
6150*44704f69SBart Van Assche         if (op->filter_given) {
6151*44704f69SBart Van Assche             if (pc != op->filter)
6152*44704f69SBart Van Assche                 goto skip;
6153*44704f69SBart Van Assche         }
6154*44704f69SBart Van Assche         if (op->do_raw) {
6155*44704f69SBart Van Assche             dStrRaw(bp, pl);
6156*44704f69SBart Van Assche             goto filter_chk;
6157*44704f69SBart Van Assche         } else if (op->do_hex) {
6158*44704f69SBart Van Assche             hex2stdout(bp, pl, op->dstrhex_no_ascii);
6159*44704f69SBart Van Assche             goto filter_chk;
6160*44704f69SBart Van Assche         }
6161*44704f69SBart Van Assche         switch (pc) {
6162*44704f69SBart Van Assche         case 0x0:
6163*44704f69SBart Van Assche             if (pl < 12) {
6164*44704f69SBart Van Assche 
6165*44704f69SBart Van Assche             }
6166*44704f69SBart Van Assche             for (k = 1; k < 0x41; ++k) {
6167*44704f69SBart Van Assche                 mod = ((k - 1) % 8);
6168*44704f69SBart Van Assche                 div = (k - 1) / 8;
6169*44704f69SBart Van Assche                 if (0 == mod) {
6170*44704f69SBart Van Assche                     if (div > 0)
6171*44704f69SBart Van Assche                         printf("\n");
6172*44704f69SBart Van Assche                     printf("  Flag%02Xh: %d", k, !! (bp[4 + div] & 0x80));
6173*44704f69SBart Van Assche                 } else
6174*44704f69SBart Van Assche                     printf("  %02Xh: %d", k,
6175*44704f69SBart Van Assche                            !! (bp[4 + div] & (1 << (7 - mod))));
6176*44704f69SBart Van Assche             }
6177*44704f69SBart Van Assche             printf("\n");
6178*44704f69SBart Van Assche             break;
6179*44704f69SBart Van Assche         default:
6180*44704f69SBart Van Assche             if (pc <= 0x8000) {
6181*44704f69SBart Van Assche                 printf("  Reserved [parameter_code=0x%x]:\n", pc);
6182*44704f69SBart Van Assche                 hex2fp(bp, ((pl < num) ? pl : num), "    ",
6183*44704f69SBart Van Assche                         op->hex2str_oformat, stdout);
6184*44704f69SBart Van Assche             } else {
6185*44704f69SBart Van Assche                 if (op->exclude_vendor) {
6186*44704f69SBart Van Assche                     if ((op->verbose > 0) && (0 == op->do_brief) &&
6187*44704f69SBart Van Assche                         (! evsm_output)) {
6188*44704f69SBart Van Assche                         evsm_output = true;
6189*44704f69SBart Van Assche                         printf("  %s parameter(s) being ignored\n",
6190*44704f69SBart Van Assche                                vend_spec);
6191*44704f69SBart Van Assche                     }
6192*44704f69SBart Van Assche                 } else {
6193*44704f69SBart Van Assche                     printf("  %s [%s=0x%x]:\n", vend_spec, param_c_sn, pc);
6194*44704f69SBart Van Assche                     hex2fp(bp, ((pl < num) ? pl : num), "    ",
6195*44704f69SBart Van Assche                            op->hex2str_oformat, stdout);
6196*44704f69SBart Van Assche                 }
6197*44704f69SBart Van Assche             }
6198*44704f69SBart Van Assche             break;
6199*44704f69SBart Van Assche         }
6200*44704f69SBart Van Assche         if (op->do_pcb)
6201*44704f69SBart Van Assche             printf("        <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
6202*44704f69SBart Van Assche filter_chk:
6203*44704f69SBart Van Assche         if (op->filter_given)
6204*44704f69SBart Van Assche             break;
6205*44704f69SBart Van Assche skip:
6206*44704f69SBart Van Assche         num -= pl;
6207*44704f69SBart Van Assche         bp += pl;
6208*44704f69SBart Van Assche     }
6209*44704f69SBart Van Assche     return true;
6210*44704f69SBart Van Assche }
6211*44704f69SBart Van Assche 
6212*44704f69SBart Van Assche #define NUM_REQ_REC_ARR_ELEMS 16
6213*44704f69SBart Van Assche static const char * req_rec_arr[NUM_REQ_REC_ARR_ELEMS] = {
6214*44704f69SBart Van Assche     "Recovery not requested",
6215*44704f69SBart Van Assche     "Recovery requested, no recovery procedure defined",
6216*44704f69SBart Van Assche     "Instruct operator to push volume",
6217*44704f69SBart Van Assche     "Instruct operator to remove and re-insert volume",
6218*44704f69SBart Van Assche     "Issue UNLOAD command. Instruct operator to remove and re-insert volume",
6219*44704f69SBart Van Assche     "Instruct operator to power cycle target device",
6220*44704f69SBart Van Assche     "Issue LOAD command",
6221*44704f69SBart Van Assche     "Issue UNLOAD command",
6222*44704f69SBart Van Assche     "Issue LOGICAL UNIT RESET task management function",        /* 0x8 */
6223*44704f69SBart Van Assche     "No recovery procedure defined. Contact service organization",
6224*44704f69SBart Van Assche     "Issue UNLOAD command. Instruct operator to remove and quarantine "
6225*44704f69SBart Van Assche         "volume",
6226*44704f69SBart Van Assche     "Instruct operator to not insert a volume. Contact service organization",
6227*44704f69SBart Van Assche     "Issue UNLOAD command. Instruct operator to remove volume. Contact "
6228*44704f69SBart Van Assche         "service organization",
6229*44704f69SBart Van Assche     "Request creation of target device error log",
6230*44704f69SBart Van Assche     "Retrieve a target device error log",
6231*44704f69SBart Van Assche     "Modify configuration to all microcode update and instruct operator to "
6232*44704f69SBart Van Assche         "re-insert volume",     /* 0xf */
6233*44704f69SBart Van Assche };
6234*44704f69SBart Van Assche 
6235*44704f69SBart Van Assche /* REQ_RECOVERY_LPAGE Requested recovery [0x13] <rr> (ssc) */
6236*44704f69SBart Van Assche static bool
show_requested_recovery_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)6237*44704f69SBart Van Assche show_requested_recovery_page(const uint8_t * resp, int len,
6238*44704f69SBart Van Assche                              struct opts_t * op, sgj_opaque_p jop)
6239*44704f69SBart Van Assche {
6240*44704f69SBart Van Assche     bool evsm_output = false;
6241*44704f69SBart Van Assche     int num, pl, pc, j, k;
6242*44704f69SBart Van Assche     const uint8_t * bp;
6243*44704f69SBart Van Assche     char str[PCB_STR_LEN];
6244*44704f69SBart Van Assche 
6245*44704f69SBart Van Assche if (jop) { };
6246*44704f69SBart Van Assche     if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
6247*44704f69SBart Van Assche         printf("Requested recovery page (ssc-3) [0x13]\n");
6248*44704f69SBart Van Assche     num = len - 4;
6249*44704f69SBart Van Assche     bp = &resp[0] + 4;
6250*44704f69SBart Van Assche     while (num > 3) {
6251*44704f69SBart Van Assche         pc = sg_get_unaligned_be16(bp + 0);
6252*44704f69SBart Van Assche         pl = bp[3] + 4;
6253*44704f69SBart Van Assche         if (op->filter_given) {
6254*44704f69SBart Van Assche             if (pc != op->filter)
6255*44704f69SBart Van Assche                 goto skip;
6256*44704f69SBart Van Assche         }
6257*44704f69SBart Van Assche         if (op->do_raw) {
6258*44704f69SBart Van Assche             dStrRaw(bp, pl);
6259*44704f69SBart Van Assche             goto filter_chk;
6260*44704f69SBart Van Assche         } else if (op->do_hex) {
6261*44704f69SBart Van Assche             hex2stdout(bp, pl, op->dstrhex_no_ascii);
6262*44704f69SBart Van Assche             goto filter_chk;
6263*44704f69SBart Van Assche         }
6264*44704f69SBart Van Assche         switch (pc) {
6265*44704f69SBart Van Assche         case 0x0:
6266*44704f69SBart Van Assche             printf("  Recovery procedures:\n");
6267*44704f69SBart Van Assche             for (k = 4; k < pl; ++ k) {
6268*44704f69SBart Van Assche                 j = bp[k];
6269*44704f69SBart Van Assche                 if (j < NUM_REQ_REC_ARR_ELEMS)
6270*44704f69SBart Van Assche                     printf("    %s\n", req_rec_arr[j]);
6271*44704f69SBart Van Assche                 else if (j < 0x80)
6272*44704f69SBart Van Assche                     printf("    Reserved [0x%x]\n", j);
6273*44704f69SBart Van Assche                 else
6274*44704f69SBart Van Assche                     printf("    Vendor specific [0x%x]\n", j);
6275*44704f69SBart Van Assche             }
6276*44704f69SBart Van Assche             break;
6277*44704f69SBart Van Assche         default:
6278*44704f69SBart Van Assche             if (pc <= 0x8000) {
6279*44704f69SBart Van Assche                 printf("  Reserved [parameter_code=0x%x]:\n", pc);
6280*44704f69SBart Van Assche                 hex2fp(bp, ((pl < num) ? pl : num), "    ",
6281*44704f69SBart Van Assche                         op->hex2str_oformat, stdout);
6282*44704f69SBart Van Assche             } else {
6283*44704f69SBart Van Assche                 if (op->exclude_vendor) {
6284*44704f69SBart Van Assche                     if ((op->verbose > 0) && (0 == op->do_brief) &&
6285*44704f69SBart Van Assche                         (! evsm_output)) {
6286*44704f69SBart Van Assche                         evsm_output = true;
6287*44704f69SBart Van Assche                         printf("  Vendor specific parameter(s) being "
6288*44704f69SBart Van Assche                                "ignored\n");
6289*44704f69SBart Van Assche                     }
6290*44704f69SBart Van Assche                 } else {
6291*44704f69SBart Van Assche                     printf("  Vendor specific [parameter_code=0x%x]:\n", pc);
6292*44704f69SBart Van Assche                     hex2fp(bp, ((pl < num) ? pl : num), "    ",
6293*44704f69SBart Van Assche                             op->hex2str_oformat, stdout);
6294*44704f69SBart Van Assche                 }
6295*44704f69SBart Van Assche             }
6296*44704f69SBart Van Assche             break;
6297*44704f69SBart Van Assche         }
6298*44704f69SBart Van Assche         if (op->do_pcb)
6299*44704f69SBart Van Assche             printf("        <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
6300*44704f69SBart Van Assche filter_chk:
6301*44704f69SBart Van Assche         if (op->filter_given)
6302*44704f69SBart Van Assche             break;
6303*44704f69SBart Van Assche skip:
6304*44704f69SBart Van Assche         num -= pl;
6305*44704f69SBart Van Assche         bp += pl;
6306*44704f69SBart Van Assche     }
6307*44704f69SBart Van Assche     return true;
6308*44704f69SBart Van Assche }
6309*44704f69SBart Van Assche 
6310*44704f69SBart Van Assche /* SAT_ATA_RESULTS_LPAGE (SAT-2) [0x16] <aptr> */
6311*44704f69SBart Van Assche static bool
show_ata_pt_results_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)6312*44704f69SBart Van Assche show_ata_pt_results_page(const uint8_t * resp, int len,
6313*44704f69SBart Van Assche                          struct opts_t * op, sgj_opaque_p jop)
6314*44704f69SBart Van Assche {
6315*44704f69SBart Van Assche     int num, pl, pc;
6316*44704f69SBart Van Assche     const uint8_t * bp;
6317*44704f69SBart Van Assche     const uint8_t * dp;
6318*44704f69SBart Van Assche     char str[PCB_STR_LEN];
6319*44704f69SBart Van Assche 
6320*44704f69SBart Van Assche if (jop) { };
6321*44704f69SBart Van Assche     if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
6322*44704f69SBart Van Assche         printf("ATA pass-through results page (sat-2) [0x16]\n");
6323*44704f69SBart Van Assche     num = len - 4;
6324*44704f69SBart Van Assche     bp = &resp[0] + 4;
6325*44704f69SBart Van Assche     while (num > 3) {
6326*44704f69SBart Van Assche         pc = sg_get_unaligned_be16(bp + 0);
6327*44704f69SBart Van Assche         pl = bp[3] + 4;
6328*44704f69SBart Van Assche         if (op->filter_given) {
6329*44704f69SBart Van Assche             if (pc != op->filter)
6330*44704f69SBart Van Assche                 goto skip;
6331*44704f69SBart Van Assche         }
6332*44704f69SBart Van Assche         if (op->do_raw) {
6333*44704f69SBart Van Assche             dStrRaw(bp, pl);
6334*44704f69SBart Van Assche             goto filter_chk;
6335*44704f69SBart Van Assche         } else if (op->do_hex) {
6336*44704f69SBart Van Assche             hex2stdout(bp, pl, op->dstrhex_no_ascii);
6337*44704f69SBart Van Assche             goto filter_chk;
6338*44704f69SBart Van Assche         }
6339*44704f69SBart Van Assche         if ((pc < 0xf) && (pl > 17)) {
6340*44704f69SBart Van Assche             int extend, count;
6341*44704f69SBart Van Assche 
6342*44704f69SBart Van Assche             printf("  Log_index=0x%x (parameter_code=0x%x)\n", pc + 1, pc);
6343*44704f69SBart Van Assche             dp = bp + 4;       /* dp is start of ATA Return descriptor
6344*44704f69SBart Van Assche                                  * which is 14 bytes long */
6345*44704f69SBart Van Assche             extend = dp[2] & 1;
6346*44704f69SBart Van Assche             count = dp[5] + (extend ? (dp[4] << 8) : 0);
6347*44704f69SBart Van Assche             printf("    extend=%d  error=0x%x count=0x%x\n", extend,
6348*44704f69SBart Van Assche                    dp[3], count);
6349*44704f69SBart Van Assche             if (extend)
6350*44704f69SBart Van Assche                 printf("    lba=0x%02x%02x%02x%02x%02x%02x\n", dp[10], dp[8],
6351*44704f69SBart Van Assche                        dp[6], dp[11], dp[9], dp[7]);
6352*44704f69SBart Van Assche             else
6353*44704f69SBart Van Assche                 printf("    lba=0x%02x%02x%02x\n", dp[11], dp[9], dp[7]);
6354*44704f69SBart Van Assche             printf("    device=0x%x  status=0x%x\n", dp[12], dp[13]);
6355*44704f69SBart Van Assche         } else if (pl > 17) {
6356*44704f69SBart Van Assche             printf("  Reserved [parameter_code=0x%x]:\n", pc);
6357*44704f69SBart Van Assche             hex2fp(bp, ((pl < num) ? pl : num), "    ",
6358*44704f69SBart Van Assche                    op->hex2str_oformat, stdout);
6359*44704f69SBart Van Assche         } else {
6360*44704f69SBart Van Assche             printf("  short parameter length: %d [parameter_code=0x%x]:\n",
6361*44704f69SBart Van Assche                    pl, pc);
6362*44704f69SBart Van Assche             hex2fp(bp, ((pl < num) ? pl : num), "    ",
6363*44704f69SBart Van Assche                    op->hex2str_oformat, stdout);
6364*44704f69SBart Van Assche         }
6365*44704f69SBart Van Assche         if (op->do_pcb)
6366*44704f69SBart Van Assche             printf("        <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
6367*44704f69SBart Van Assche filter_chk:
6368*44704f69SBart Van Assche         if (op->filter_given)
6369*44704f69SBart Van Assche             break;
6370*44704f69SBart Van Assche skip:
6371*44704f69SBart Van Assche         num -= pl;
6372*44704f69SBart Van Assche         bp += pl;
6373*44704f69SBart Van Assche     }
6374*44704f69SBart Van Assche     return true;
6375*44704f69SBart Van Assche }
6376*44704f69SBart Van Assche 
6377*44704f69SBart Van Assche static const char * bms_status[] = {
6378*44704f69SBart Van Assche     "no background scans active",
6379*44704f69SBart Van Assche     "background medium scan is active",
6380*44704f69SBart Van Assche     "background pre-scan is active",
6381*44704f69SBart Van Assche     "background scan halted due to fatal error",
6382*44704f69SBart Van Assche     "background scan halted due to a vendor specific pattern of error",
6383*44704f69SBart Van Assche     "background scan halted due to medium formatted without P-List",
6384*44704f69SBart Van Assche     "background scan halted - vendor specific cause",
6385*44704f69SBart Van Assche     "background scan halted due to temperature out of range",
6386*44704f69SBart Van Assche     ("background scan enabled, none active (waiting for BMS interval timer "
6387*44704f69SBart Van Assche         "to expire)"),  /* clang warns about this, add parens to quieten */
6388*44704f69SBart Van Assche     "background scan halted - scan results list full",
6389*44704f69SBart Van Assche     "background scan halted - pre-scan time limit timer expired" /* 10 */,
6390*44704f69SBart Van Assche };
6391*44704f69SBart Van Assche 
6392*44704f69SBart Van Assche static const char * reassign_status[] = {
6393*44704f69SBart Van Assche     "Reserved [0x0]",
6394*44704f69SBart Van Assche     "Reassignment pending receipt of Reassign or Write command",
6395*44704f69SBart Van Assche     "Logical block successfully reassigned by device server",
6396*44704f69SBart Van Assche     "Reserved [0x3]",
6397*44704f69SBart Van Assche     "Reassignment by device server failed",
6398*44704f69SBart Van Assche     "Logical block recovered by device server via rewrite",
6399*44704f69SBart Van Assche     "Logical block reassigned by application client, has valid data",
6400*44704f69SBart Van Assche     "Logical block reassigned by application client, contains no valid data",
6401*44704f69SBart Van Assche     "Logical block unsuccessfully reassigned by application client", /* 8 */
6402*44704f69SBart Van Assche };
6403*44704f69SBart Van Assche 
6404*44704f69SBart Van Assche /* Background scan results [0x15,0] <bsr> for disk  introduced: SBC-3 */
6405*44704f69SBart Van Assche static bool
show_background_scan_results_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)6406*44704f69SBart Van Assche show_background_scan_results_page(const uint8_t * resp, int len,
6407*44704f69SBart Van Assche                                   struct opts_t * op, sgj_opaque_p jop)
6408*44704f69SBart Van Assche {
6409*44704f69SBart Van Assche     bool skip_out = false;
6410*44704f69SBart Van Assche     bool evsm_output = false;
6411*44704f69SBart Van Assche     bool ok;
6412*44704f69SBart Van Assche     int j, m, n, num, pl, pc;
6413*44704f69SBart Van Assche     const uint8_t * bp;
6414*44704f69SBart Van Assche     double d;
6415*44704f69SBart Van Assche     sgj_state * jsp = &op->json_st;
6416*44704f69SBart Van Assche     sgj_opaque_p jo2p;
6417*44704f69SBart Van Assche     sgj_opaque_p jo3p = NULL;
6418*44704f69SBart Van Assche     sgj_opaque_p jap = NULL;
6419*44704f69SBart Van Assche     char str[PCB_STR_LEN];
6420*44704f69SBart Van Assche     char b[144];
6421*44704f69SBart Van Assche     char e[80];
6422*44704f69SBart Van Assche     static const int blen = sizeof(b);
6423*44704f69SBart Van Assche     static const int elen = sizeof(e);
6424*44704f69SBart Van Assche     static const char * bsrlp = "Background scan results log page";
6425*44704f69SBart Van Assche     static const char * bss = "Background scan status";
6426*44704f69SBart Van Assche     static const char * bms = "Background medium scan";
6427*44704f69SBart Van Assche     static const char * bsr = "Background scan results";
6428*44704f69SBart Van Assche     static const char * bs = "background scan";
6429*44704f69SBart Van Assche     static const char * ms = "Medium scan";
6430*44704f69SBart Van Assche     static const char * apom = "Accumulated power on minutes";
6431*44704f69SBart Van Assche     static const char * rs = "Reassign status";
6432*44704f69SBart Van Assche 
6433*44704f69SBart Van Assche     if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
6434*44704f69SBart Van Assche         sgj_pr_hr(jsp, "%s  [0x15]\n", bsrlp);
6435*44704f69SBart Van Assche     num = len - 4;
6436*44704f69SBart Van Assche     bp = &resp[0] + 4;
6437*44704f69SBart Van Assche     if (jsp->pr_as_json) {
6438*44704f69SBart Van Assche         jo2p = sg_log_js_hdr(jsp, jop, bsrlp, resp);
6439*44704f69SBart Van Assche         jap = sgj_named_subarray_r(jsp, jo2p, "background_scan_parameters");
6440*44704f69SBart Van Assche     }
6441*44704f69SBart Van Assche 
6442*44704f69SBart Van Assche     while (num > 3) {
6443*44704f69SBart Van Assche         pc = sg_get_unaligned_be16(bp + 0);
6444*44704f69SBart Van Assche         pl = bp[3] + 4;
6445*44704f69SBart Van Assche         if (op->filter_given) {
6446*44704f69SBart Van Assche             if (pc != op->filter)
6447*44704f69SBart Van Assche                 goto skip;
6448*44704f69SBart Van Assche         }
6449*44704f69SBart Van Assche         if (op->do_raw) {
6450*44704f69SBart Van Assche             dStrRaw(bp, pl);
6451*44704f69SBart Van Assche             goto filter_chk;
6452*44704f69SBart Van Assche         } else if (op->do_hex) {
6453*44704f69SBart Van Assche             hex2stdout(bp, pl, op->dstrhex_no_ascii);
6454*44704f69SBart Van Assche             goto filter_chk;
6455*44704f69SBart Van Assche         }
6456*44704f69SBart Van Assche         if (jsp->pr_as_json) {
6457*44704f69SBart Van Assche             jo3p = sgj_new_unattached_object_r(jsp);
6458*44704f69SBart Van Assche             if (op->do_pcb)
6459*44704f69SBart Van Assche                 js_pcb(jsp, jo3p, bp[2]);
6460*44704f69SBart Van Assche         }
6461*44704f69SBart Van Assche 
6462*44704f69SBart Van Assche         switch (pc) {
6463*44704f69SBart Van Assche         case 0:
6464*44704f69SBart Van Assche             sgj_pr_hr(jsp, "  Status parameters:\n");
6465*44704f69SBart Van Assche             if (jsp->pr_as_json)
6466*44704f69SBart Van Assche                 sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, bss);
6467*44704f69SBart Van Assche             if ((pl < 16) || (num < 16)) {
6468*44704f69SBart Van Assche                 if (num < 16)
6469*44704f69SBart Van Assche                     pr2serr("    truncated by response length, expected at "
6470*44704f69SBart Van Assche                             "least 16 bytes\n");
6471*44704f69SBart Van Assche                 else
6472*44704f69SBart Van Assche                     pr2serr("    parameter length >= 16 expected, got %d\n",
6473*44704f69SBart Van Assche                             pl);
6474*44704f69SBart Van Assche                 break;
6475*44704f69SBart Van Assche             }
6476*44704f69SBart Van Assche             sg_scnpr(b, blen, "    %s: ", apom);
6477*44704f69SBart Van Assche             j = sg_get_unaligned_be32(bp + 4);
6478*44704f69SBart Van Assche             sgj_pr_hr(jsp, "%s%d [h:m  %d:%d]\n", b, j, (j / 60), (j % 60));
6479*44704f69SBart Van Assche             if (jsp->pr_as_json)
6480*44704f69SBart Van Assche                 js_snakenv_ihexstr_nex(jsp, jo3p, apom, j, false, NULL, NULL,
6481*44704f69SBart Van Assche                                        NULL);
6482*44704f69SBart Van Assche             sg_scnpr(b, blen, "    Status: ");
6483*44704f69SBart Van Assche             j = bp[9];
6484*44704f69SBart Van Assche             ok = (j < (int)SG_ARRAY_SIZE(bms_status));
6485*44704f69SBart Van Assche             if (ok)
6486*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "%s%s\n", b, bms_status[j]);
6487*44704f69SBart Van Assche             else
6488*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "%sunknown [0x%x] %s value\n", b, j, bss);
6489*44704f69SBart Van Assche             if (jsp->pr_as_json)
6490*44704f69SBart Van Assche                 js_snakenv_ihexstr_nex(jsp, jo3p, bss, j, true, NULL,
6491*44704f69SBart Van Assche                                        ok ? bms_status[j] : unknown_s, NULL);
6492*44704f69SBart Van Assche             j = sg_get_unaligned_be16(bp + 10);
6493*44704f69SBart Van Assche             snprintf(b, blen, "Number of %ss performed", bs);
6494*44704f69SBart Van Assche             sgj_pr_hr(jsp, "    %s: %d\n", b, j);
6495*44704f69SBart Van Assche             if (jsp->pr_as_json)
6496*44704f69SBart Van Assche                 js_snakenv_ihexstr_nex(jsp, jo3p, b, j, true, NULL, NULL,
6497*44704f69SBart Van Assche                                        NULL);
6498*44704f69SBart Van Assche             j = sg_get_unaligned_be16(bp + 12);
6499*44704f69SBart Van Assche             snprintf(b, blen, "%s progress", bms);
6500*44704f69SBart Van Assche             d = (100.0 * j / 65536.0);
6501*44704f69SBart Van Assche #ifdef SG_LIB_MINGW
6502*44704f69SBart Van Assche             snprintf(e, elen, "%g %%", d);
6503*44704f69SBart Van Assche #else
6504*44704f69SBart Van Assche             snprintf(e, elen, "%.2f %%", d);
6505*44704f69SBart Van Assche #endif
6506*44704f69SBart Van Assche             sgj_pr_hr(jsp, "    %s: %s\n", b, e);
6507*44704f69SBart Van Assche             if (jsp->pr_as_json)
6508*44704f69SBart Van Assche                 js_snakenv_ihexstr_nex(jsp, jo3p, b, j, true, NULL, e,
6509*44704f69SBart Van Assche                                        NULL);
6510*44704f69SBart Van Assche             j = sg_get_unaligned_be16(bp + 14);
6511*44704f69SBart Van Assche             snprintf(b, blen, "Number of %ss performed", bms);
6512*44704f69SBart Van Assche 
6513*44704f69SBart Van Assche             ok = (j > 0);
6514*44704f69SBart Van Assche             if (ok)
6515*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "    %s: %d\n", b, j);
6516*44704f69SBart Van Assche             else
6517*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "    %s: 0 [%s]\n", b, not_rep);
6518*44704f69SBart Van Assche             if (jsp->pr_as_json)
6519*44704f69SBart Van Assche                 js_snakenv_ihexstr_nex(jsp, jo3p, b, j, true, NULL,
6520*44704f69SBart Van Assche                                        ok ? NULL : not_rep, NULL);
6521*44704f69SBart Van Assche             break;
6522*44704f69SBart Van Assche         default:
6523*44704f69SBart Van Assche             if (pc > 0x800) {
6524*44704f69SBart Van Assche                 if (jsp->pr_as_json)
6525*44704f69SBart Van Assche                     sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL,
6526*44704f69SBart Van Assche                                       (pc >= 0x8000) ? vend_spec : NULL);
6527*44704f69SBart Van Assche                 if ((pc >= 0x8000) && (pc <= 0xafff)) {
6528*44704f69SBart Van Assche                     if (op->exclude_vendor) {
6529*44704f69SBart Van Assche                         skip_out = true;
6530*44704f69SBart Van Assche                         if ((op->verbose > 0) && (0 == op->do_brief) &&
6531*44704f69SBart Van Assche                             (! evsm_output)) {
6532*44704f69SBart Van Assche                             evsm_output = true;
6533*44704f69SBart Van Assche                             sgj_pr_hr(jsp, "  %s parameter(s) being "
6534*44704f69SBart Van Assche                                       "ignored\n", vend_spec);
6535*44704f69SBart Van Assche                         }
6536*44704f69SBart Van Assche                     } else
6537*44704f69SBart Van Assche                         sgj_pr_hr(jsp, "  %s parameter # %d [0x%x], %s\n",
6538*44704f69SBart Van Assche                                   ms, pc, pc, vend_spec);
6539*44704f69SBart Van Assche                 } else
6540*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "  %s parameter # %d [0x%x], %s\n", ms, pc,
6541*44704f69SBart Van Assche                               pc, rsv_s);
6542*44704f69SBart Van Assche                 if (skip_out)
6543*44704f69SBart Van Assche                     skip_out = false;
6544*44704f69SBart Van Assche                 else
6545*44704f69SBart Van Assche                     hex2fp(bp, ((pl < num) ? pl : num), "    ",
6546*44704f69SBart Van Assche                            op->hex2str_oformat, stdout);
6547*44704f69SBart Van Assche                 break;
6548*44704f69SBart Van Assche             } else {
6549*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "  %s parameter # %d [0x%x]\n", ms, pc, pc);
6550*44704f69SBart Van Assche                 if (jsp->pr_as_json)
6551*44704f69SBart Van Assche                     sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, bsr);
6552*44704f69SBart Van Assche             }
6553*44704f69SBart Van Assche             if ((pl < 24) || (num < 24)) {
6554*44704f69SBart Van Assche                 if (num < 24)
6555*44704f69SBart Van Assche                     pr2serr("    truncated by response length, expected at "
6556*44704f69SBart Van Assche                             "least 24 bytes\n");
6557*44704f69SBart Van Assche                 else
6558*44704f69SBart Van Assche                     pr2serr("    parameter length >= 24 expected, got %d\n",
6559*44704f69SBart Van Assche                             pl);
6560*44704f69SBart Van Assche                 break;
6561*44704f69SBart Van Assche             }
6562*44704f69SBart Van Assche             j = sg_get_unaligned_be32(bp + 4);
6563*44704f69SBart Van Assche             n = (j % 60);
6564*44704f69SBart Van Assche             sgj_pr_hr(jsp, "    %s when error detected: %d [%d:%d]\n", apom,
6565*44704f69SBart Van Assche                       j, (j / 60), n);
6566*44704f69SBart Van Assche             if (jsp->pr_as_json) {
6567*44704f69SBart Van Assche                 snprintf(b, blen, "%d hours, %d minute%s", (j / 60), n,
6568*44704f69SBart Van Assche                          n != 1 ? "s" : "");
6569*44704f69SBart Van Assche                 js_snakenv_ihexstr_nex(jsp, jo3p, apom, j, true, NULL, b,
6570*44704f69SBart Van Assche                                        "when error detected [unit: minute]");
6571*44704f69SBart Van Assche             }
6572*44704f69SBart Van Assche             j = (bp[8] >> 4) & 0xf;
6573*44704f69SBart Van Assche             ok = (j < (int)SG_ARRAY_SIZE(reassign_status));
6574*44704f69SBart Van Assche             if (ok)
6575*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "    %s: %s\n", rs, reassign_status[j]);
6576*44704f69SBart Van Assche             else
6577*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "    %s: %s [0x%x]\n", rs, rsv_s, j);
6578*44704f69SBart Van Assche             if (jsp->pr_as_json)
6579*44704f69SBart Van Assche                 js_snakenv_ihexstr_nex(jsp, jo3p, rs, j, true, NULL,
6580*44704f69SBart Van Assche                                        ok ? reassign_status[j] : NULL, NULL);
6581*44704f69SBart Van Assche             n = 0xf & b[8];
6582*44704f69SBart Van Assche             sgj_pr_hr(jsp, "    %s: %s  [sk,asc,ascq: 0x%x,0x%x,0x%x]\n",
6583*44704f69SBart Van Assche                       s_key, sg_get_sense_key_str(n, blen, b), n, bp[9],
6584*44704f69SBart Van Assche                                                   bp[10]);
6585*44704f69SBart Van Assche             if (bp[9] || bp[10])
6586*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "      %s\n",
6587*44704f69SBart Van Assche                           sg_get_asc_ascq_str(bp[9], bp[10], blen, b));
6588*44704f69SBart Van Assche             if (jsp->pr_as_json) {
6589*44704f69SBart Van Assche                 sgj_js_nv_ihexstr(jsp, jo3p, "sense_key", n, NULL,
6590*44704f69SBart Van Assche                                   sg_get_sense_key_str(n, blen, b));
6591*44704f69SBart Van Assche                 sgj_js_nv_ihexstr(jsp, jo3p, "additional_sense_code", bp[9],
6592*44704f69SBart Van Assche                                   NULL, NULL);
6593*44704f69SBart Van Assche                 sgj_js_nv_ihexstr(jsp, jo3p, "additional_sense_code_qualifier",
6594*44704f69SBart Van Assche                                   bp[10], NULL, sg_get_asc_ascq_str(bp[9],
6595*44704f69SBart Van Assche                                   bp[10], blen, b));
6596*44704f69SBart Van Assche             }
6597*44704f69SBart Van Assche             if (op->verbose) {
6598*44704f69SBart Van Assche                 n = sg_scnpr(b, blen, "    vendor bytes [11 -> 15]: ");
6599*44704f69SBart Van Assche                 for (m = 0; m < 5; ++m)
6600*44704f69SBart Van Assche                     n += sg_scnpr(b + n, blen - n, "0x%02x ", bp[11 + m]);
6601*44704f69SBart Van Assche                  sgj_pr_hr(jsp, "%s\n", b);
6602*44704f69SBart Van Assche             }
6603*44704f69SBart Van Assche             n = sg_scnpr(b, blen, "    LBA (associated with medium error): "
6604*44704f69SBart Van Assche                          "0x");
6605*44704f69SBart Van Assche             if (sg_all_zeros(bp + 16, 8))
6606*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "%s0\n", b);
6607*44704f69SBart Van Assche             else {
6608*44704f69SBart Van Assche                 for (m = 0; m < 8; ++m)
6609*44704f69SBart Van Assche                     n += sg_scnpr(b + n, blen - n, "%02x", bp[16 + m]);
6610*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "%s\n", b);
6611*44704f69SBart Van Assche             }
6612*44704f69SBart Van Assche             if (jsp->pr_as_json)
6613*44704f69SBart Van Assche                 js_snakenv_ihexstr_nex(jsp, jo3p, "logical_block_address",
6614*44704f69SBart Van Assche                                        sg_get_unaligned_be64(bp + 16), true,
6615*44704f69SBart Van Assche                                        NULL, NULL, "of medium error");
6616*44704f69SBart Van Assche             break;
6617*44704f69SBart Van Assche         }               /* end of switch statement block */
6618*44704f69SBart Van Assche         if (jsp->pr_as_json)
6619*44704f69SBart Van Assche             sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
6620*44704f69SBart Van Assche         if (op->do_pcb)
6621*44704f69SBart Van Assche             sgj_pr_hr(jsp, "        <%s>\n", get_pcb_str(bp[2], str,
6622*44704f69SBart Van Assche                       sizeof(str)));
6623*44704f69SBart Van Assche filter_chk:
6624*44704f69SBart Van Assche         if (op->filter_given)
6625*44704f69SBart Van Assche             break;
6626*44704f69SBart Van Assche skip:
6627*44704f69SBart Van Assche         num -= pl;
6628*44704f69SBart Van Assche         bp += pl;
6629*44704f69SBart Van Assche     }
6630*44704f69SBart Van Assche     return true;
6631*44704f69SBart Van Assche }
6632*44704f69SBart Van Assche 
6633*44704f69SBart Van Assche /* ZONED_BLOCK_DEV_STATS_SUBPG [0x14,0x1] <zbds>  introduced: zbc2r01 */
6634*44704f69SBart Van Assche static bool
show_zoned_block_dev_stats(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)6635*44704f69SBart Van Assche show_zoned_block_dev_stats(const uint8_t * resp, int len,
6636*44704f69SBart Van Assche                            struct opts_t * op, sgj_opaque_p jop)
6637*44704f69SBart Van Assche {
6638*44704f69SBart Van Assche     bool trunc, bad_pl;
6639*44704f69SBart Van Assche     int num, pl, pc;
6640*44704f69SBart Van Assche     const uint8_t * bp;
6641*44704f69SBart Van Assche     char str[PCB_STR_LEN];
6642*44704f69SBart Van Assche 
6643*44704f69SBart Van Assche if (jop) { };
6644*44704f69SBart Van Assche     if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
6645*44704f69SBart Van Assche         printf("Zoned block device statistics page  [0x14,0x1]\n");
6646*44704f69SBart Van Assche     num = len - 4;
6647*44704f69SBart Van Assche     bp = &resp[0] + 4;
6648*44704f69SBart Van Assche     while (num > 3) {
6649*44704f69SBart Van Assche         trunc = false;
6650*44704f69SBart Van Assche         bad_pl = false;
6651*44704f69SBart Van Assche         pc = sg_get_unaligned_be16(bp + 0);
6652*44704f69SBart Van Assche         pl = bp[3] + 4;
6653*44704f69SBart Van Assche         if (4 == pl)    /* DC HC560 has empty descriptors */
6654*44704f69SBart Van Assche             goto skip;
6655*44704f69SBart Van Assche         if (op->filter_given) {
6656*44704f69SBart Van Assche             if (pc != op->filter)
6657*44704f69SBart Van Assche                 goto skip;
6658*44704f69SBart Van Assche         }
6659*44704f69SBart Van Assche         if (op->do_raw) {
6660*44704f69SBart Van Assche             dStrRaw(bp, pl);
6661*44704f69SBart Van Assche             goto filter_chk;
6662*44704f69SBart Van Assche         } else if (op->do_hex) {
6663*44704f69SBart Van Assche             hex2stdout(bp, pl, op->dstrhex_no_ascii);
6664*44704f69SBart Van Assche             goto filter_chk;
6665*44704f69SBart Van Assche         }
6666*44704f69SBart Van Assche         switch (pc) {
6667*44704f69SBart Van Assche         case 0x0:
6668*44704f69SBart Van Assche             if ((pl < 8) || (num < 8)) {
6669*44704f69SBart Van Assche                 if (num < 8)
6670*44704f69SBart Van Assche                     trunc = true;
6671*44704f69SBart Van Assche                 else
6672*44704f69SBart Van Assche                     bad_pl = true;
6673*44704f69SBart Van Assche             } else
6674*44704f69SBart Van Assche                 printf("  Maximum open zones: %" PRIu32 "\n",
6675*44704f69SBart Van Assche                        sg_get_unaligned_be32(bp + 8));
6676*44704f69SBart Van Assche             break;
6677*44704f69SBart Van Assche         case 0x1:
6678*44704f69SBart Van Assche             if ((pl < 8) || (num < 8)) {
6679*44704f69SBart Van Assche                 if (num < 8)
6680*44704f69SBart Van Assche                     trunc = true;
6681*44704f69SBart Van Assche                 else
6682*44704f69SBart Van Assche                     bad_pl = true;
6683*44704f69SBart Van Assche             } else
6684*44704f69SBart Van Assche                 printf("  Maximum explicitly open zones: %" PRIu32 "\n",
6685*44704f69SBart Van Assche                        sg_get_unaligned_be32(bp + 8));
6686*44704f69SBart Van Assche             break;
6687*44704f69SBart Van Assche         case 0x2:
6688*44704f69SBart Van Assche             if ((pl < 8) || (num < 8)) {
6689*44704f69SBart Van Assche                 if (num < 8)
6690*44704f69SBart Van Assche                     trunc = true;
6691*44704f69SBart Van Assche                 else
6692*44704f69SBart Van Assche                     bad_pl = true;
6693*44704f69SBart Van Assche             } else
6694*44704f69SBart Van Assche                 printf("  Maximum implicitly open zones: %" PRIu32 "\n",
6695*44704f69SBart Van Assche                        sg_get_unaligned_be32(bp + 8));
6696*44704f69SBart Van Assche             break;
6697*44704f69SBart Van Assche         case 0x3:
6698*44704f69SBart Van Assche             if ((pl < 8) || (num < 8)) {
6699*44704f69SBart Van Assche                 if (num < 8)
6700*44704f69SBart Van Assche                     trunc = true;
6701*44704f69SBart Van Assche                 else
6702*44704f69SBart Van Assche                     bad_pl = true;
6703*44704f69SBart Van Assche             } else
6704*44704f69SBart Van Assche                 printf("  Minimum empty zones: %" PRIu32 "\n",
6705*44704f69SBart Van Assche                        sg_get_unaligned_be32(bp + 8));
6706*44704f69SBart Van Assche             break;
6707*44704f69SBart Van Assche         case 0x4:
6708*44704f69SBart Van Assche             if ((pl < 8) || (num < 8)) {
6709*44704f69SBart Van Assche                 if (num < 8)
6710*44704f69SBart Van Assche                     trunc = true;
6711*44704f69SBart Van Assche                 else
6712*44704f69SBart Van Assche                     bad_pl = true;
6713*44704f69SBart Van Assche             } else
6714*44704f69SBart Van Assche                 printf("  Maximum non-sequential zones: %" PRIu32 "\n",
6715*44704f69SBart Van Assche                        sg_get_unaligned_be32(bp + 8));
6716*44704f69SBart Van Assche             break;
6717*44704f69SBart Van Assche         case 0x5:
6718*44704f69SBart Van Assche             if ((pl < 8) || (num < 8)) {
6719*44704f69SBart Van Assche                 if (num < 8)
6720*44704f69SBart Van Assche                     trunc = true;
6721*44704f69SBart Van Assche                 else
6722*44704f69SBart Van Assche                     bad_pl = true;
6723*44704f69SBart Van Assche             } else
6724*44704f69SBart Van Assche                 printf("  Zones emptied: %" PRIu32 "\n",
6725*44704f69SBart Van Assche                        sg_get_unaligned_be32(bp + 8));
6726*44704f69SBart Van Assche             break;
6727*44704f69SBart Van Assche         case 0x6:
6728*44704f69SBart Van Assche             if ((pl < 8) || (num < 8)) {
6729*44704f69SBart Van Assche                 if (num < 8)
6730*44704f69SBart Van Assche                     trunc = true;
6731*44704f69SBart Van Assche                 else
6732*44704f69SBart Van Assche                     bad_pl = true;
6733*44704f69SBart Van Assche             } else
6734*44704f69SBart Van Assche                 printf("  Suboptimal write commands: %" PRIu32 "\n",
6735*44704f69SBart Van Assche                        sg_get_unaligned_be32(bp + 8));
6736*44704f69SBart Van Assche             break;
6737*44704f69SBart Van Assche         case 0x7:
6738*44704f69SBart Van Assche             if ((pl < 8) || (num < 8)) {
6739*44704f69SBart Van Assche                 if (num < 8)
6740*44704f69SBart Van Assche                     trunc = true;
6741*44704f69SBart Van Assche                 else
6742*44704f69SBart Van Assche                     bad_pl = true;
6743*44704f69SBart Van Assche             } else
6744*44704f69SBart Van Assche                 printf("  Commands exceeding optimal limit: %" PRIu32 "\n",
6745*44704f69SBart Van Assche                        sg_get_unaligned_be32(bp + 8));
6746*44704f69SBart Van Assche             break;
6747*44704f69SBart Van Assche         case 0x8:
6748*44704f69SBart Van Assche             if ((pl < 8) || (num < 8)) {
6749*44704f69SBart Van Assche                 if (num < 8)
6750*44704f69SBart Van Assche                     trunc = true;
6751*44704f69SBart Van Assche                 else
6752*44704f69SBart Van Assche                     bad_pl = true;
6753*44704f69SBart Van Assche             } else
6754*44704f69SBart Van Assche                 printf("  Failed explicit opens: %" PRIu32 "\n",
6755*44704f69SBart Van Assche                        sg_get_unaligned_be32(bp + 8));
6756*44704f69SBart Van Assche             break;
6757*44704f69SBart Van Assche         case 0x9:
6758*44704f69SBart Van Assche             if ((pl < 8) || (num < 8)) {
6759*44704f69SBart Van Assche                 if (num < 8)
6760*44704f69SBart Van Assche                     trunc = true;
6761*44704f69SBart Van Assche                 else
6762*44704f69SBart Van Assche                     bad_pl = true;
6763*44704f69SBart Van Assche             } else
6764*44704f69SBart Van Assche                 printf("  Read rule violations: %" PRIu32 "\n",
6765*44704f69SBart Van Assche                        sg_get_unaligned_be32(bp + 8));
6766*44704f69SBart Van Assche             break;
6767*44704f69SBart Van Assche         case 0xa:
6768*44704f69SBart Van Assche             if ((pl < 8) || (num < 8)) {
6769*44704f69SBart Van Assche                 if (num < 8)
6770*44704f69SBart Van Assche                     trunc = true;
6771*44704f69SBart Van Assche                 else
6772*44704f69SBart Van Assche                     bad_pl = true;
6773*44704f69SBart Van Assche             } else
6774*44704f69SBart Van Assche                 printf("  Write rule violations: %" PRIu32 "\n",
6775*44704f69SBart Van Assche                        sg_get_unaligned_be32(bp + 8));
6776*44704f69SBart Van Assche             break;
6777*44704f69SBart Van Assche         case 0xb:       /* added zbc2r04 */
6778*44704f69SBart Van Assche             if ((pl < 8) || (num < 8)) {
6779*44704f69SBart Van Assche                 if (num < 8)
6780*44704f69SBart Van Assche                     trunc = true;
6781*44704f69SBart Van Assche                 else
6782*44704f69SBart Van Assche                     bad_pl = true;
6783*44704f69SBart Van Assche             } else
6784*44704f69SBart Van Assche                 printf("  Maximum implicitly open or before required zones: "
6785*44704f69SBart Van Assche                        "%" PRIu32 "\n", sg_get_unaligned_be32(bp + 8));
6786*44704f69SBart Van Assche             break;
6787*44704f69SBart Van Assche         default:
6788*44704f69SBart Van Assche             printf("  Reserved [parameter_code=0x%x]:\n", pc);
6789*44704f69SBart Van Assche             hex2fp(bp, ((pl < num) ? pl : num), "    ",
6790*44704f69SBart Van Assche                    op->hex2str_oformat, stdout);
6791*44704f69SBart Van Assche             break;
6792*44704f69SBart Van Assche         }
6793*44704f69SBart Van Assche         if (trunc)
6794*44704f69SBart Van Assche             pr2serr("    truncated by response length, expected at least "
6795*44704f69SBart Van Assche                     "8 bytes\n");
6796*44704f69SBart Van Assche         if (bad_pl)
6797*44704f69SBart Van Assche             pr2serr("    parameter length >= 8 expected, got %d\n", pl);
6798*44704f69SBart Van Assche         if (op->do_pcb)
6799*44704f69SBart Van Assche             printf("        <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
6800*44704f69SBart Van Assche filter_chk:
6801*44704f69SBart Van Assche         if (op->filter_given)
6802*44704f69SBart Van Assche             break;
6803*44704f69SBart Van Assche skip:
6804*44704f69SBart Van Assche         num -= pl;
6805*44704f69SBart Van Assche         bp += pl;
6806*44704f69SBart Van Assche     }
6807*44704f69SBart Van Assche     return true;
6808*44704f69SBart Van Assche }
6809*44704f69SBart Van Assche 
6810*44704f69SBart Van Assche /* PENDING_DEFECTS_SUBPG [0x15,0x1] <pd>  introduced: SBC-4 */
6811*44704f69SBart Van Assche static bool
show_pending_defects_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)6812*44704f69SBart Van Assche show_pending_defects_page(const uint8_t * resp, int len,
6813*44704f69SBart Van Assche                           struct opts_t * op, sgj_opaque_p jop)
6814*44704f69SBart Van Assche {
6815*44704f69SBart Van Assche     int num, pl, pc;
6816*44704f69SBart Van Assche     uint32_t count;
6817*44704f69SBart Van Assche     const uint8_t * bp;
6818*44704f69SBart Van Assche     char str[PCB_STR_LEN];
6819*44704f69SBart Van Assche 
6820*44704f69SBart Van Assche if (jop) { };
6821*44704f69SBart Van Assche     if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
6822*44704f69SBart Van Assche         printf("Pending defects page  [0x15,0x1]\n");
6823*44704f69SBart Van Assche     num = len - 4;
6824*44704f69SBart Van Assche     bp = &resp[0] + 4;
6825*44704f69SBart Van Assche     while (num > 3) {
6826*44704f69SBart Van Assche         pc = sg_get_unaligned_be16(bp + 0);
6827*44704f69SBart Van Assche         pl = bp[3] + 4;
6828*44704f69SBart Van Assche         if (op->filter_given) {
6829*44704f69SBart Van Assche             if (pc != op->filter)
6830*44704f69SBart Van Assche                 goto skip;
6831*44704f69SBart Van Assche         }
6832*44704f69SBart Van Assche         if (op->do_raw) {
6833*44704f69SBart Van Assche             dStrRaw(bp, pl);
6834*44704f69SBart Van Assche             goto filter_chk;
6835*44704f69SBart Van Assche         } else if (op->do_hex) {
6836*44704f69SBart Van Assche             hex2stdout(bp, pl, op->dstrhex_no_ascii);
6837*44704f69SBart Van Assche             goto filter_chk;
6838*44704f69SBart Van Assche         }
6839*44704f69SBart Van Assche         switch (pc) {
6840*44704f69SBart Van Assche         case 0x0:
6841*44704f69SBart Van Assche             printf("  Pending defect count: ");
6842*44704f69SBart Van Assche             if ((pl < 8) || (num < 8)) {
6843*44704f69SBart Van Assche                 if (num < 8)
6844*44704f69SBart Van Assche                     pr2serr("\n    truncated by response length, expected "
6845*44704f69SBart Van Assche                             "at least 8 bytes\n");
6846*44704f69SBart Van Assche                 else
6847*44704f69SBart Van Assche                     pr2serr("\n    parameter length >= 8 expected, got %d\n",
6848*44704f69SBart Van Assche                             pl);
6849*44704f69SBart Van Assche                 break;
6850*44704f69SBart Van Assche             }
6851*44704f69SBart Van Assche             count = sg_get_unaligned_be32(bp + 4);
6852*44704f69SBart Van Assche             if (0 == count) {
6853*44704f69SBart Van Assche                 printf("0\n");
6854*44704f69SBart Van Assche                 break;
6855*44704f69SBart Van Assche             }
6856*44704f69SBart Van Assche             printf("%3u  |     LBA            Accumulated power_on\n", count);
6857*44704f69SBart Van Assche             printf("-----------------------------|---------------");
6858*44704f69SBart Van Assche             printf("-----------hours---------\n");
6859*44704f69SBart Van Assche             break;
6860*44704f69SBart Van Assche         default:
6861*44704f69SBart Van Assche             printf("  Pending defect %4d:  ", pc);
6862*44704f69SBart Van Assche             if ((pl < 16) || (num < 16)) {
6863*44704f69SBart Van Assche                 if (num < 16)
6864*44704f69SBart Van Assche                     pr2serr("\n    truncated by response length, expected "
6865*44704f69SBart Van Assche                             "at least 16 bytes\n");
6866*44704f69SBart Van Assche                 else
6867*44704f69SBart Van Assche                     pr2serr("\n    parameter length >= 16 expected, got %d\n",
6868*44704f69SBart Van Assche                             pl);
6869*44704f69SBart Van Assche                 break;
6870*44704f69SBart Van Assche             }
6871*44704f69SBart Van Assche             printf("        0x%-16" PRIx64 "      %5u\n",
6872*44704f69SBart Van Assche                    sg_get_unaligned_be64(bp + 8),
6873*44704f69SBart Van Assche                    sg_get_unaligned_be32(bp + 4));
6874*44704f69SBart Van Assche             break;
6875*44704f69SBart Van Assche         }
6876*44704f69SBart Van Assche         if (op->do_pcb)
6877*44704f69SBart Van Assche             printf("        <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
6878*44704f69SBart Van Assche filter_chk:
6879*44704f69SBart Van Assche         if (op->filter_given)
6880*44704f69SBart Van Assche             break;
6881*44704f69SBart Van Assche skip:
6882*44704f69SBart Van Assche         num -= pl;
6883*44704f69SBart Van Assche         bp += pl;
6884*44704f69SBart Van Assche     }
6885*44704f69SBart Van Assche     return true;
6886*44704f69SBart Van Assche }
6887*44704f69SBart Van Assche 
6888*44704f69SBart Van Assche /* BACKGROUND_OP_SUBPG [0x15,0x2] <bop>  introduced: SBC-4 rev 7 */
6889*44704f69SBart Van Assche static bool
show_background_op_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)6890*44704f69SBart Van Assche show_background_op_page(const uint8_t * resp, int len,
6891*44704f69SBart Van Assche                         struct opts_t * op, sgj_opaque_p jop)
6892*44704f69SBart Van Assche {
6893*44704f69SBart Van Assche     int num, pl, pc;
6894*44704f69SBart Van Assche     const uint8_t * bp;
6895*44704f69SBart Van Assche     char str[PCB_STR_LEN];
6896*44704f69SBart Van Assche 
6897*44704f69SBart Van Assche if (jop) { };
6898*44704f69SBart Van Assche     if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
6899*44704f69SBart Van Assche         printf("Background operation page  [0x15,0x2]\n");
6900*44704f69SBart Van Assche     num = len - 4;
6901*44704f69SBart Van Assche     bp = &resp[0] + 4;
6902*44704f69SBart Van Assche     while (num > 3) {
6903*44704f69SBart Van Assche         pc = sg_get_unaligned_be16(bp + 0);
6904*44704f69SBart Van Assche         pl = bp[3] + 4;
6905*44704f69SBart Van Assche         if (op->filter_given) {
6906*44704f69SBart Van Assche             if (pc != op->filter)
6907*44704f69SBart Van Assche                 goto skip;
6908*44704f69SBart Van Assche         }
6909*44704f69SBart Van Assche         if (op->do_raw) {
6910*44704f69SBart Van Assche             dStrRaw(bp, pl);
6911*44704f69SBart Van Assche             goto filter_chk;
6912*44704f69SBart Van Assche         } else if (op->do_hex) {
6913*44704f69SBart Van Assche             hex2stdout(bp, pl, op->dstrhex_no_ascii);
6914*44704f69SBart Van Assche             goto filter_chk;
6915*44704f69SBart Van Assche         }
6916*44704f69SBart Van Assche         switch (pc) {
6917*44704f69SBart Van Assche         case 0x0:
6918*44704f69SBart Van Assche             printf("  Background operation:");
6919*44704f69SBart Van Assche             if ((pl < 8) || (num < 8)) {
6920*44704f69SBart Van Assche                 if (num < 8)
6921*44704f69SBart Van Assche                     pr2serr("\n    truncated by response length, expected "
6922*44704f69SBart Van Assche                             "at least 8 bytes\n");
6923*44704f69SBart Van Assche                 else
6924*44704f69SBart Van Assche                     pr2serr("\n    parameter length >= 8 expected, got %d\n",
6925*44704f69SBart Van Assche                             pl);
6926*44704f69SBart Van Assche                 break;
6927*44704f69SBart Van Assche             }
6928*44704f69SBart Van Assche             printf(" BO_STATUS=%d\n", bp[4]);
6929*44704f69SBart Van Assche             break;
6930*44704f69SBart Van Assche         default:
6931*44704f69SBart Van Assche             printf("  Reserved [parameter_code=0x%x]:\n", pc);
6932*44704f69SBart Van Assche             hex2fp(bp, ((pl < num) ? pl : num), "    ",
6933*44704f69SBart Van Assche                    op->hex2str_oformat, stdout);
6934*44704f69SBart Van Assche             break;
6935*44704f69SBart Van Assche         }
6936*44704f69SBart Van Assche         if (op->do_pcb)
6937*44704f69SBart Van Assche             printf("        <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
6938*44704f69SBart Van Assche filter_chk:
6939*44704f69SBart Van Assche         if (op->filter_given)
6940*44704f69SBart Van Assche             break;
6941*44704f69SBart Van Assche skip:
6942*44704f69SBart Van Assche         num -= pl;
6943*44704f69SBart Van Assche         bp += pl;
6944*44704f69SBart Van Assche     }
6945*44704f69SBart Van Assche     return true;
6946*44704f69SBart Van Assche }
6947*44704f69SBart Van Assche 
6948*44704f69SBart Van Assche /* LPS misalignment page [0x15,0x3] <lps>  introduced: SBC-4 rev 10
6949*44704f69SBart Van Assche    LPS: "Long Physical Sector" a term from an ATA feature set */
6950*44704f69SBart Van Assche static bool
show_lps_misalignment_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)6951*44704f69SBart Van Assche show_lps_misalignment_page(const uint8_t * resp, int len,
6952*44704f69SBart Van Assche                            struct opts_t * op, sgj_opaque_p jop)
6953*44704f69SBart Van Assche {
6954*44704f69SBart Van Assche     int num, pl, pc;
6955*44704f69SBart Van Assche     const uint8_t * bp;
6956*44704f69SBart Van Assche     char str[PCB_STR_LEN];
6957*44704f69SBart Van Assche 
6958*44704f69SBart Van Assche if (jop) { };
6959*44704f69SBart Van Assche     if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
6960*44704f69SBart Van Assche         printf("LPS misalignment page  [0x15,0x3]\n");
6961*44704f69SBart Van Assche     num = len - 4;
6962*44704f69SBart Van Assche     bp = &resp[0] + 4;
6963*44704f69SBart Van Assche     while (num > 3) {
6964*44704f69SBart Van Assche         pc = sg_get_unaligned_be16(bp + 0);
6965*44704f69SBart Van Assche         pl = bp[3] + 4;
6966*44704f69SBart Van Assche         if (op->filter_given) {
6967*44704f69SBart Van Assche             if (pc != op->filter)
6968*44704f69SBart Van Assche                 goto skip;
6969*44704f69SBart Van Assche         }
6970*44704f69SBart Van Assche         if (op->do_raw) {
6971*44704f69SBart Van Assche             dStrRaw(bp, pl);
6972*44704f69SBart Van Assche             goto filter_chk;
6973*44704f69SBart Van Assche         } else if (op->do_hex) {
6974*44704f69SBart Van Assche             hex2stdout(bp, pl, op->dstrhex_no_ascii);
6975*44704f69SBart Van Assche             goto filter_chk;
6976*44704f69SBart Van Assche         }
6977*44704f69SBart Van Assche         switch (pc) {
6978*44704f69SBart Van Assche         case 0x0:
6979*44704f69SBart Van Assche             printf("  LPS misalignment count: ");
6980*44704f69SBart Van Assche             if (4 == bp[3])
6981*44704f69SBart Van Assche                 printf("max lpsm: %" PRIu16 ", count=%" PRIu16 "\n",
6982*44704f69SBart Van Assche                        sg_get_unaligned_be16(bp + 4),
6983*44704f69SBart Van Assche                        sg_get_unaligned_be16(bp + 6));
6984*44704f69SBart Van Assche             else
6985*44704f69SBart Van Assche                 printf("<unexpected pc=0 parameter length=%d>\n", bp[4]);
6986*44704f69SBart Van Assche             break;
6987*44704f69SBart Van Assche         default:
6988*44704f69SBart Van Assche             if (pc <= 0xf000) {         /* parameter codes 0x1 to 0xf000 */
6989*44704f69SBart Van Assche                 if (8 == bp[3])
6990*44704f69SBart Van Assche                     printf("  LBA of misaligned block: 0x%" PRIx64 "\n",
6991*44704f69SBart Van Assche                            sg_get_unaligned_be64(bp + 4));
6992*44704f69SBart Van Assche                 else
6993*44704f69SBart Van Assche                     printf("<unexpected pc=0x%x parameter length=%d>\n",
6994*44704f69SBart Van Assche                            pc, bp[4]);
6995*44704f69SBart Van Assche             } else {
6996*44704f69SBart Van Assche                 printf("<unexpected pc=0x%x>\n", pc);
6997*44704f69SBart Van Assche                 hex2fp(bp, ((pl < num) ? pl : num), "    ",
6998*44704f69SBart Van Assche                        op->hex2str_oformat, stdout);
6999*44704f69SBart Van Assche             }
7000*44704f69SBart Van Assche             break;
7001*44704f69SBart Van Assche         }
7002*44704f69SBart Van Assche         if (op->do_pcb)
7003*44704f69SBart Van Assche             printf("        <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
7004*44704f69SBart Van Assche filter_chk:
7005*44704f69SBart Van Assche         if (op->filter_given)
7006*44704f69SBart Van Assche             break;
7007*44704f69SBart Van Assche skip:
7008*44704f69SBart Van Assche         num -= pl;
7009*44704f69SBart Van Assche         bp += pl;
7010*44704f69SBart Van Assche     }
7011*44704f69SBart Van Assche     return true;
7012*44704f69SBart Van Assche }
7013*44704f69SBart Van Assche 
7014*44704f69SBart Van Assche /* Service buffer information [0x15] <sbi> (adc) */
7015*44704f69SBart Van Assche static bool
show_service_buffer_info_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)7016*44704f69SBart Van Assche show_service_buffer_info_page(const uint8_t * resp, int len,
7017*44704f69SBart Van Assche                               struct opts_t * op, sgj_opaque_p jop)
7018*44704f69SBart Van Assche {
7019*44704f69SBart Van Assche     bool evsm_output = false;
7020*44704f69SBart Van Assche     int num, pl, pc;
7021*44704f69SBart Van Assche     const uint8_t * bp;
7022*44704f69SBart Van Assche     char str[PCB_STR_LEN];
7023*44704f69SBart Van Assche 
7024*44704f69SBart Van Assche if (jop) { };
7025*44704f69SBart Van Assche     if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
7026*44704f69SBart Van Assche         printf("Service buffer information page (adc-3) [0x15]\n");
7027*44704f69SBart Van Assche     num = len - 4;
7028*44704f69SBart Van Assche     bp = &resp[0] + 4;
7029*44704f69SBart Van Assche     while (num > 3) {
7030*44704f69SBart Van Assche         pc = sg_get_unaligned_be16(bp + 0);
7031*44704f69SBart Van Assche         pl = bp[3] + 4;
7032*44704f69SBart Van Assche         if (op->filter_given) {
7033*44704f69SBart Van Assche             if (pc != op->filter)
7034*44704f69SBart Van Assche                 goto skip;
7035*44704f69SBart Van Assche         }
7036*44704f69SBart Van Assche         if (op->do_raw) {
7037*44704f69SBart Van Assche             dStrRaw(bp, pl);
7038*44704f69SBart Van Assche             goto filter_chk;
7039*44704f69SBart Van Assche         } else if (op->do_hex) {
7040*44704f69SBart Van Assche             hex2stdout(bp, pl, op->dstrhex_no_ascii);
7041*44704f69SBart Van Assche             goto filter_chk;
7042*44704f69SBart Van Assche         }
7043*44704f69SBart Van Assche         if (pc < 0x100) {
7044*44704f69SBart Van Assche             printf("  Service buffer identifier: 0x%x\n", pc);
7045*44704f69SBart Van Assche             printf("    Buffer id: 0x%x, tu=%d, nmp=%d, nmm=%d, "
7046*44704f69SBart Van Assche                    "offline=%d\n", bp[4], !!(0x10 & bp[5]),
7047*44704f69SBart Van Assche                    !!(0x8 & bp[5]), !!(0x4 & bp[5]), !!(0x2 & bp[5]));
7048*44704f69SBart Van Assche             printf("    pd=%d, code_set: %s, Service buffer title:\n",
7049*44704f69SBart Van Assche                    !!(0x1 & bp[5]), sg_get_desig_code_set_str(0xf & bp[6]));
7050*44704f69SBart Van Assche             printf("      %.*s\n", pl - 8, bp + 8);
7051*44704f69SBart Van Assche         } else if (pc < 0x8000) {
7052*44704f69SBart Van Assche             printf("  parameter_code=0x%x, Reserved, parameter in hex:\n",
7053*44704f69SBart Van Assche                    pc);
7054*44704f69SBart Van Assche             hex2fp(bp + 4, pl - 4, "    ", op->hex2str_oformat, stdout);
7055*44704f69SBart Van Assche         } else {
7056*44704f69SBart Van Assche             if (op->exclude_vendor) {
7057*44704f69SBart Van Assche                 if ((op->verbose > 0) && (0 == op->do_brief) &&
7058*44704f69SBart Van Assche                     (! evsm_output)) {
7059*44704f69SBart Van Assche                     evsm_output = true;
7060*44704f69SBart Van Assche                     printf("  Vendor specific parameter(s) being "
7061*44704f69SBart Van Assche                            "ignored\n");
7062*44704f69SBart Van Assche                 }
7063*44704f69SBart Van Assche             } else {
7064*44704f69SBart Van Assche                 printf("  parameter_code=0x%x, Vendor-specific, parameter in "
7065*44704f69SBart Van Assche                        "hex:\n", pc);
7066*44704f69SBart Van Assche                 hex2fp(bp + 4, pl - 4, "    ", op->hex2str_oformat, stdout);
7067*44704f69SBart Van Assche             }
7068*44704f69SBart Van Assche         }
7069*44704f69SBart Van Assche         if (op->do_pcb)
7070*44704f69SBart Van Assche             printf("        <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
7071*44704f69SBart Van Assche filter_chk:
7072*44704f69SBart Van Assche         if (op->filter_given)
7073*44704f69SBart Van Assche             break;
7074*44704f69SBart Van Assche skip:
7075*44704f69SBart Van Assche         num -= pl;
7076*44704f69SBart Van Assche         bp += pl;
7077*44704f69SBart Van Assche     }
7078*44704f69SBart Van Assche     return true;
7079*44704f69SBart Van Assche }
7080*44704f69SBart Van Assche 
7081*44704f69SBart Van Assche /* Sequential access device page [0xc] <sad> for tape */
7082*44704f69SBart Van Assche static bool
show_sequential_access_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)7083*44704f69SBart Van Assche show_sequential_access_page(const uint8_t * resp, int len,
7084*44704f69SBart Van Assche                             struct opts_t * op, sgj_opaque_p jop)
7085*44704f69SBart Van Assche {
7086*44704f69SBart Van Assche     bool evsm_output = false;
7087*44704f69SBart Van Assche     int num, pl, pc;
7088*44704f69SBart Van Assche     const uint8_t * bp;
7089*44704f69SBart Van Assche     uint64_t ull, gbytes;
7090*44704f69SBart Van Assche     bool all_set;
7091*44704f69SBart Van Assche     char str[PCB_STR_LEN];
7092*44704f69SBart Van Assche 
7093*44704f69SBart Van Assche if (jop) { };
7094*44704f69SBart Van Assche     if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
7095*44704f69SBart Van Assche         printf("Sequential access device page (ssc-3)\n");
7096*44704f69SBart Van Assche     num = len - 4;
7097*44704f69SBart Van Assche     bp = &resp[0] + 4;
7098*44704f69SBart Van Assche     while (num > 3) {
7099*44704f69SBart Van Assche         pc = sg_get_unaligned_be16(bp + 0);
7100*44704f69SBart Van Assche         pl = bp[3] + 4;
7101*44704f69SBart Van Assche         if (op->filter_given) {
7102*44704f69SBart Van Assche             if (pc != op->filter)
7103*44704f69SBart Van Assche                 goto skip;
7104*44704f69SBart Van Assche         }
7105*44704f69SBart Van Assche         if (op->do_raw) {
7106*44704f69SBart Van Assche             dStrRaw(bp, pl);
7107*44704f69SBart Van Assche             goto filter_chk;
7108*44704f69SBart Van Assche         } else if (op->do_hex) {
7109*44704f69SBart Van Assche             hex2stdout(bp, pl, op->dstrhex_no_ascii);
7110*44704f69SBart Van Assche             goto filter_chk;
7111*44704f69SBart Van Assche         }
7112*44704f69SBart Van Assche         ull = sg_get_unaligned_be(pl - 4, bp + 4);
7113*44704f69SBart Van Assche         all_set = sg_all_ffs(bp + 4, pl - 4);
7114*44704f69SBart Van Assche         gbytes = ull / 1000000000;
7115*44704f69SBart Van Assche         switch (pc) {
7116*44704f69SBart Van Assche         case 0:
7117*44704f69SBart Van Assche             printf("  Data bytes received with WRITE commands: %" PRIu64
7118*44704f69SBart Van Assche                    " GB", gbytes);
7119*44704f69SBart Van Assche             if (op->verbose)
7120*44704f69SBart Van Assche                 printf(" [%" PRIu64 " bytes]", ull);
7121*44704f69SBart Van Assche             printf("\n");
7122*44704f69SBart Van Assche             break;
7123*44704f69SBart Van Assche         case 1:
7124*44704f69SBart Van Assche             printf("  Data bytes written to media by WRITE commands: %" PRIu64
7125*44704f69SBart Van Assche                    " GB", gbytes);
7126*44704f69SBart Van Assche             if (op->verbose)
7127*44704f69SBart Van Assche                 printf(" [%" PRIu64 " bytes]", ull);
7128*44704f69SBart Van Assche             printf("\n");
7129*44704f69SBart Van Assche             break;
7130*44704f69SBart Van Assche         case 2:
7131*44704f69SBart Van Assche             printf("  Data bytes read from media by READ commands: %" PRIu64
7132*44704f69SBart Van Assche                    " GB", gbytes);
7133*44704f69SBart Van Assche             if (op->verbose)
7134*44704f69SBart Van Assche                 printf(" [%" PRIu64 " bytes]", ull);
7135*44704f69SBart Van Assche             printf("\n");
7136*44704f69SBart Van Assche             break;
7137*44704f69SBart Van Assche         case 3:
7138*44704f69SBart Van Assche             printf("  Data bytes transferred by READ commands: %" PRIu64
7139*44704f69SBart Van Assche                    " GB", gbytes);
7140*44704f69SBart Van Assche             if (op->verbose)
7141*44704f69SBart Van Assche                 printf(" [%" PRIu64 " bytes]", ull);
7142*44704f69SBart Van Assche             printf("\n");
7143*44704f69SBart Van Assche             break;
7144*44704f69SBart Van Assche         case 4:
7145*44704f69SBart Van Assche             if (! all_set)
7146*44704f69SBart Van Assche                 printf("  Native capacity from BOP to EOD: %" PRIu64 " MB\n",
7147*44704f69SBart Van Assche                        ull);
7148*44704f69SBart Van Assche             break;
7149*44704f69SBart Van Assche         case 5:
7150*44704f69SBart Van Assche             if (! all_set)
7151*44704f69SBart Van Assche                 printf("  Native capacity from BOP to EW of current "
7152*44704f69SBart Van Assche                        "partition: %" PRIu64 " MB\n", ull);
7153*44704f69SBart Van Assche             break;
7154*44704f69SBart Van Assche         case 6:
7155*44704f69SBart Van Assche             if (! all_set)
7156*44704f69SBart Van Assche                 printf("  Minimum native capacity from EW to EOP of current "
7157*44704f69SBart Van Assche                        "partition: %" PRIu64 " MB\n", ull);
7158*44704f69SBart Van Assche             break;
7159*44704f69SBart Van Assche         case 7:
7160*44704f69SBart Van Assche             if (! all_set)
7161*44704f69SBart Van Assche                 printf("  Native capacity from BOP to current position: %"
7162*44704f69SBart Van Assche                        PRIu64 " MB\n", ull);
7163*44704f69SBart Van Assche             break;
7164*44704f69SBart Van Assche         case 8:
7165*44704f69SBart Van Assche             if (! all_set)
7166*44704f69SBart Van Assche                 printf("  Maximum native capacity in device object buffer: %"
7167*44704f69SBart Van Assche                        PRIu64 " MB\n", ull);
7168*44704f69SBart Van Assche             break;
7169*44704f69SBart Van Assche         case 0x100:
7170*44704f69SBart Van Assche             if (ull > 0)
7171*44704f69SBart Van Assche                 printf("  Cleaning action required\n");
7172*44704f69SBart Van Assche             else
7173*44704f69SBart Van Assche                 printf("  Cleaning action not required (or completed)\n");
7174*44704f69SBart Van Assche             if (op->verbose)
7175*44704f69SBart Van Assche                 printf("    cleaning value: %" PRIu64 "\n", ull);
7176*44704f69SBart Van Assche             break;
7177*44704f69SBart Van Assche         default:
7178*44704f69SBart Van Assche             if (pc >= 0x8000) {
7179*44704f69SBart Van Assche                 if (op->exclude_vendor) {
7180*44704f69SBart Van Assche                     if ((op->verbose > 0) && (0 == op->do_brief) &&
7181*44704f69SBart Van Assche                         (! evsm_output)) {
7182*44704f69SBart Van Assche                         evsm_output = true;
7183*44704f69SBart Van Assche                         printf("  Vendor specific parameter(s) being "
7184*44704f69SBart Van Assche                                "ignored\n");
7185*44704f69SBart Van Assche                     }
7186*44704f69SBart Van Assche                 } else
7187*44704f69SBart Van Assche                     printf("  Vendor specific parameter [0x%x] value: %"
7188*44704f69SBart Van Assche                            PRIu64 "\n", pc, ull);
7189*44704f69SBart Van Assche             } else
7190*44704f69SBart Van Assche                 printf("  Reserved parameter [0x%x] value: %" PRIu64 "\n",
7191*44704f69SBart Van Assche                        pc, ull);
7192*44704f69SBart Van Assche             break;
7193*44704f69SBart Van Assche         }
7194*44704f69SBart Van Assche         if (op->do_pcb)
7195*44704f69SBart Van Assche             printf("        <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
7196*44704f69SBart Van Assche filter_chk:
7197*44704f69SBart Van Assche         if (op->filter_given)
7198*44704f69SBart Van Assche             break;
7199*44704f69SBart Van Assche skip:
7200*44704f69SBart Van Assche         num -= pl;
7201*44704f69SBart Van Assche         bp += pl;
7202*44704f69SBart Van Assche     }
7203*44704f69SBart Van Assche     return true;
7204*44704f69SBart Van Assche }
7205*44704f69SBart Van Assche 
7206*44704f69SBart Van Assche /* Device statistics 0x14 <ds> for tape and ADC */
7207*44704f69SBart Van Assche static bool
show_device_stats_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)7208*44704f69SBart Van Assche show_device_stats_page(const uint8_t * resp, int len,
7209*44704f69SBart Van Assche                        struct opts_t * op, sgj_opaque_p jop)
7210*44704f69SBart Van Assche {
7211*44704f69SBart Van Assche     bool evsm_output = false;
7212*44704f69SBart Van Assche     int num, pl, pc;
7213*44704f69SBart Van Assche     const uint8_t * bp;
7214*44704f69SBart Van Assche     char str[PCB_STR_LEN];
7215*44704f69SBart Van Assche 
7216*44704f69SBart Van Assche if (jop) { };
7217*44704f69SBart Van Assche     if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
7218*44704f69SBart Van Assche         printf("Device statistics page (ssc-3 and adc)\n");
7219*44704f69SBart Van Assche     num = len - 4;
7220*44704f69SBart Van Assche     bp = &resp[0] + 4;
7221*44704f69SBart Van Assche     while (num > 3) {
7222*44704f69SBart Van Assche         pc = sg_get_unaligned_be16(bp + 0);
7223*44704f69SBart Van Assche         pl = bp[3] + 4;
7224*44704f69SBart Van Assche         if (op->filter_given) {
7225*44704f69SBart Van Assche             if (pc != op->filter)
7226*44704f69SBart Van Assche                 goto skip;
7227*44704f69SBart Van Assche         }
7228*44704f69SBart Van Assche         if (op->do_raw) {
7229*44704f69SBart Van Assche             dStrRaw(bp, pl);
7230*44704f69SBart Van Assche              goto filter_chk;
7231*44704f69SBart Van Assche         } else if (op->do_hex) {
7232*44704f69SBart Van Assche             hex2stdout(bp, pl, op->dstrhex_no_ascii);
7233*44704f69SBart Van Assche              goto filter_chk;
7234*44704f69SBart Van Assche         }
7235*44704f69SBart Van Assche         if (pc < 0x1000) {
7236*44704f69SBart Van Assche             bool vl_num = true;
7237*44704f69SBart Van Assche 
7238*44704f69SBart Van Assche             switch (pc) {
7239*44704f69SBart Van Assche             case 0:
7240*44704f69SBart Van Assche                 printf("  Lifetime media loads:");
7241*44704f69SBart Van Assche                 break;
7242*44704f69SBart Van Assche             case 1:
7243*44704f69SBart Van Assche                 printf("  Lifetime cleaning operations:");
7244*44704f69SBart Van Assche                 break;
7245*44704f69SBart Van Assche             case 2:
7246*44704f69SBart Van Assche                 printf("  Lifetime power on hours:");
7247*44704f69SBart Van Assche                 break;
7248*44704f69SBart Van Assche             case 3:
7249*44704f69SBart Van Assche                 printf("  Lifetime media motion (head) hours:");
7250*44704f69SBart Van Assche                 break;
7251*44704f69SBart Van Assche             case 4:
7252*44704f69SBart Van Assche                 printf("  Lifetime metres of tape processed:");
7253*44704f69SBart Van Assche                 break;
7254*44704f69SBart Van Assche             case 5:
7255*44704f69SBart Van Assche                 printf("  Lifetime media motion (head) hours when "
7256*44704f69SBart Van Assche                        "incompatible media last loaded:");
7257*44704f69SBart Van Assche                 break;
7258*44704f69SBart Van Assche             case 6:
7259*44704f69SBart Van Assche                 printf("  Lifetime power on hours when last temperature "
7260*44704f69SBart Van Assche                        "condition occurred:");
7261*44704f69SBart Van Assche                 break;
7262*44704f69SBart Van Assche             case 7:
7263*44704f69SBart Van Assche                 printf("  Lifetime power on hours when last power "
7264*44704f69SBart Van Assche                        "consumption condition occurred:");
7265*44704f69SBart Van Assche                 break;
7266*44704f69SBart Van Assche             case 8:
7267*44704f69SBart Van Assche                 printf("  Media motion (head) hours since last successful "
7268*44704f69SBart Van Assche                        "cleaning operation:");
7269*44704f69SBart Van Assche                 break;
7270*44704f69SBart Van Assche             case 9:
7271*44704f69SBart Van Assche                 printf("  Media motion (head) hours since 2nd to last "
7272*44704f69SBart Van Assche                        "successful cleaning:");
7273*44704f69SBart Van Assche                 break;
7274*44704f69SBart Van Assche             case 0xa:
7275*44704f69SBart Van Assche                 printf("  Media motion (head) hours since 3rd to last "
7276*44704f69SBart Van Assche                        "successful cleaning:");
7277*44704f69SBart Van Assche                 break;
7278*44704f69SBart Van Assche             case 0xb:
7279*44704f69SBart Van Assche                 printf("  Lifetime power on hours when last operator "
7280*44704f69SBart Van Assche                        "initiated forced reset\n    and/or emergency "
7281*44704f69SBart Van Assche                        "eject occurred:");
7282*44704f69SBart Van Assche                 break;
7283*44704f69SBart Van Assche             case 0xc:
7284*44704f69SBart Van Assche                 printf("  Lifetime power cycles:");
7285*44704f69SBart Van Assche                 break;
7286*44704f69SBart Van Assche             case 0xd:
7287*44704f69SBart Van Assche                 printf("  Volume loads since last parameter reset:");
7288*44704f69SBart Van Assche                 break;
7289*44704f69SBart Van Assche             case 0xe:
7290*44704f69SBart Van Assche                 printf("  Hard write errors:");
7291*44704f69SBart Van Assche                 break;
7292*44704f69SBart Van Assche             case 0xf:
7293*44704f69SBart Van Assche                 printf("  Hard read errors:");
7294*44704f69SBart Van Assche                 break;
7295*44704f69SBart Van Assche             case 0x10:
7296*44704f69SBart Van Assche                 printf("  Duty cycle sample time (ms):");
7297*44704f69SBart Van Assche                 break;
7298*44704f69SBart Van Assche             case 0x11:
7299*44704f69SBart Van Assche                 printf("  Read duty cycle:");
7300*44704f69SBart Van Assche                 break;
7301*44704f69SBart Van Assche             case 0x12:
7302*44704f69SBart Van Assche                 printf("  Write duty cycle:");
7303*44704f69SBart Van Assche                 break;
7304*44704f69SBart Van Assche             case 0x13:
7305*44704f69SBart Van Assche                 printf("  Activity duty cycle:");
7306*44704f69SBart Van Assche                 break;
7307*44704f69SBart Van Assche             case 0x14:
7308*44704f69SBart Van Assche                 printf("  Volume not present duty cycle:");
7309*44704f69SBart Van Assche                 break;
7310*44704f69SBart Van Assche             case 0x15:
7311*44704f69SBart Van Assche                 printf("  Ready duty cycle:");
7312*44704f69SBart Van Assche                 break;
7313*44704f69SBart Van Assche             case 0x16:
7314*44704f69SBart Van Assche                 printf("  MBs transferred from app client in duty cycle "
7315*44704f69SBart Van Assche                        "sample time:");
7316*44704f69SBart Van Assche                 break;
7317*44704f69SBart Van Assche             case 0x17:
7318*44704f69SBart Van Assche                 printf("  MBs transferred to app client in duty cycle "
7319*44704f69SBart Van Assche                        "sample time:");
7320*44704f69SBart Van Assche                 break;
7321*44704f69SBart Van Assche             case 0x40:
7322*44704f69SBart Van Assche                 printf("  Drive manufacturer's serial number:");
7323*44704f69SBart Van Assche                 break;
7324*44704f69SBart Van Assche             case 0x41:
7325*44704f69SBart Van Assche                 printf("  Drive serial number:");
7326*44704f69SBart Van Assche                 break;
7327*44704f69SBart Van Assche             case 0x42:          /* added ssc5r02b */
7328*44704f69SBart Van Assche                 vl_num = false;
7329*44704f69SBart Van Assche                 printf("  Manufacturing date (yyyymmdd): %.*s\n", pl - 4,
7330*44704f69SBart Van Assche                        bp + 4);
7331*44704f69SBart Van Assche                 break;
7332*44704f69SBart Van Assche             case 0x43:          /* added ssc5r02b */
7333*44704f69SBart Van Assche                 vl_num = false;
7334*44704f69SBart Van Assche                 printf("  Manufacturing date (yyyyww): %.*s\n", pl - 4,
7335*44704f69SBart Van Assche                        bp + 4);
7336*44704f69SBart Van Assche                 break;
7337*44704f69SBart Van Assche             case 0x80:
7338*44704f69SBart Van Assche                 printf("  Medium removal prevented:");
7339*44704f69SBart Van Assche                 break;
7340*44704f69SBart Van Assche             case 0x81:
7341*44704f69SBart Van Assche                 printf("  Maximum recommended mechanism temperature "
7342*44704f69SBart Van Assche                        "exceeded:");
7343*44704f69SBart Van Assche                 break;
7344*44704f69SBart Van Assche             default:
7345*44704f69SBart Van Assche                 vl_num = false;
7346*44704f69SBart Van Assche                 printf("  Reserved %s [0x%x] data in hex:\n", param_c, pc);
7347*44704f69SBart Van Assche                 hex2fp(bp + 4, pl - 4, "    ", op->hex2str_oformat, stdout);
7348*44704f69SBart Van Assche                 break;
7349*44704f69SBart Van Assche             }
7350*44704f69SBart Van Assche             if (vl_num)
7351*44704f69SBart Van Assche                 printf(" %" PRIu64 "\n", sg_get_unaligned_be(pl - 4, bp + 4));
7352*44704f69SBart Van Assche         } else {        /* parameter_code >= 0x1000 */
7353*44704f69SBart Van Assche             int k;
7354*44704f69SBart Van Assche             const uint8_t * p = bp + 4;
7355*44704f69SBart Van Assche 
7356*44704f69SBart Van Assche             switch (pc) {
7357*44704f69SBart Van Assche             case 0x1000:
7358*44704f69SBart Van Assche                 printf("  Media motion (head) hours for each medium type:\n");
7359*44704f69SBart Van Assche                 for (k = 0; ((pl - 4) - k) >= 8; k += 8, p += 8)
7360*44704f69SBart Van Assche                     printf("    [%d] Density code: %u, Medium type: 0x%x, "
7361*44704f69SBart Van Assche                            "hours: %u\n", ((k / 8) + 1), p[2], p[3],
7362*44704f69SBart Van Assche                            sg_get_unaligned_be32(p + 4));
7363*44704f69SBart Van Assche                 break;
7364*44704f69SBart Van Assche             default:
7365*44704f69SBart Van Assche                 if (pc >= 0x8000) {
7366*44704f69SBart Van Assche                     if (op->exclude_vendor) {
7367*44704f69SBart Van Assche                         if ((op->verbose > 0) && (0 == op->do_brief) &&
7368*44704f69SBart Van Assche                             (! evsm_output)) {
7369*44704f69SBart Van Assche                             evsm_output = true;
7370*44704f69SBart Van Assche                             printf("  Vendor specific parameter(s) being "
7371*44704f69SBart Van Assche                                    "ignored\n");
7372*44704f69SBart Van Assche                         }
7373*44704f69SBart Van Assche                     } else
7374*44704f69SBart Van Assche                         printf("  Vendor specific parameter [0x%x], dump in "
7375*44704f69SBart Van Assche                                "hex:\n", pc);
7376*44704f69SBart Van Assche                 } else {
7377*44704f69SBart Van Assche                     printf("  Reserved parameter [0x%x], dump in hex:\n", pc);
7378*44704f69SBart Van Assche                     hex2fp(bp + 4, pl - 4, "    ", op->hex2str_oformat,
7379*44704f69SBart Van Assche                            stdout);
7380*44704f69SBart Van Assche                 }
7381*44704f69SBart Van Assche                 break;
7382*44704f69SBart Van Assche             }
7383*44704f69SBart Van Assche         }
7384*44704f69SBart Van Assche         if (op->do_pcb)
7385*44704f69SBart Van Assche             printf("        <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
7386*44704f69SBart Van Assche filter_chk:
7387*44704f69SBart Van Assche         if (op->filter_given)
7388*44704f69SBart Van Assche             break;
7389*44704f69SBart Van Assche skip:
7390*44704f69SBart Van Assche         num -= pl;
7391*44704f69SBart Van Assche         bp += pl;
7392*44704f69SBart Van Assche     }
7393*44704f69SBart Van Assche     return true;
7394*44704f69SBart Van Assche }
7395*44704f69SBart Van Assche 
7396*44704f69SBart Van Assche /* Media changer statistics 0x14 <mcs> for media changer */
7397*44704f69SBart Van Assche static bool
show_media_stats_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)7398*44704f69SBart Van Assche show_media_stats_page(const uint8_t * resp, int len, struct opts_t * op,
7399*44704f69SBart Van Assche                       sgj_opaque_p jop)
7400*44704f69SBart Van Assche {
7401*44704f69SBart Van Assche     int num, pl, pc;
7402*44704f69SBart Van Assche     const uint8_t * bp;
7403*44704f69SBart Van Assche     uint64_t ull;
7404*44704f69SBart Van Assche     char str[PCB_STR_LEN];
7405*44704f69SBart Van Assche 
7406*44704f69SBart Van Assche if (jop) { };
7407*44704f69SBart Van Assche     if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
7408*44704f69SBart Van Assche         printf("Media statistics page (smc-3)\n");
7409*44704f69SBart Van Assche     num = len - 4;
7410*44704f69SBart Van Assche     bp = &resp[0] + 4;
7411*44704f69SBart Van Assche     while (num > 3) {
7412*44704f69SBart Van Assche         pc = sg_get_unaligned_be16(bp + 0);
7413*44704f69SBart Van Assche         pl = bp[3] + 4;
7414*44704f69SBart Van Assche         if (op->filter_given) {
7415*44704f69SBart Van Assche             if (pc != op->filter)
7416*44704f69SBart Van Assche                 goto skip;
7417*44704f69SBart Van Assche         }
7418*44704f69SBart Van Assche         if (op->do_raw) {
7419*44704f69SBart Van Assche             dStrRaw(bp, pl);
7420*44704f69SBart Van Assche             goto filter_chk;
7421*44704f69SBart Van Assche         } else if (op->do_hex) {
7422*44704f69SBart Van Assche             hex2stdout(bp, pl, op->dstrhex_no_ascii);
7423*44704f69SBart Van Assche             goto filter_chk;
7424*44704f69SBart Van Assche         }
7425*44704f69SBart Van Assche         ull = sg_get_unaligned_be(pl - 4, bp + 4);
7426*44704f69SBart Van Assche         switch (pc) {
7427*44704f69SBart Van Assche         case 0:
7428*44704f69SBart Van Assche             printf("  Number of moves: %" PRIu64 "\n", ull);
7429*44704f69SBart Van Assche             break;
7430*44704f69SBart Van Assche         case 1:
7431*44704f69SBart Van Assche             printf("  Number of picks: %" PRIu64 "\n", ull);
7432*44704f69SBart Van Assche             break;
7433*44704f69SBart Van Assche         case 2:
7434*44704f69SBart Van Assche             printf("  Number of pick retries: %" PRIu64 "\n", ull);
7435*44704f69SBart Van Assche             break;
7436*44704f69SBart Van Assche         case 3:
7437*44704f69SBart Van Assche             printf("  Number of places: %" PRIu64 "\n", ull);
7438*44704f69SBart Van Assche             break;
7439*44704f69SBart Van Assche         case 4:
7440*44704f69SBart Van Assche             printf("  Number of place retries: %" PRIu64 "\n", ull);
7441*44704f69SBart Van Assche             break;
7442*44704f69SBart Van Assche         case 5:
7443*44704f69SBart Van Assche             printf("  Number of volume tags read by volume "
7444*44704f69SBart Van Assche                    "tag reader: %" PRIu64 "\n", ull);
7445*44704f69SBart Van Assche             break;
7446*44704f69SBart Van Assche         case 6:
7447*44704f69SBart Van Assche             printf("  Number of invalid volume tags returned by "
7448*44704f69SBart Van Assche                    "volume tag reader: %" PRIu64 "\n", ull);
7449*44704f69SBart Van Assche             break;
7450*44704f69SBart Van Assche         case 7:
7451*44704f69SBart Van Assche             printf("  Number of library door opens: %" PRIu64 "\n", ull);
7452*44704f69SBart Van Assche             break;
7453*44704f69SBart Van Assche         case 8:
7454*44704f69SBart Van Assche             printf("  Number of import/export door opens: %" PRIu64 "\n",
7455*44704f69SBart Van Assche                    ull);
7456*44704f69SBart Van Assche             break;
7457*44704f69SBart Van Assche         case 9:
7458*44704f69SBart Van Assche             printf("  Number of physical inventory scans: %" PRIu64 "\n",
7459*44704f69SBart Van Assche                    ull);
7460*44704f69SBart Van Assche             break;
7461*44704f69SBart Van Assche         case 0xa:
7462*44704f69SBart Van Assche             printf("  Number of medium transport unrecovered errors: "
7463*44704f69SBart Van Assche                    "%" PRIu64 "\n", ull);
7464*44704f69SBart Van Assche             break;
7465*44704f69SBart Van Assche         case 0xb:
7466*44704f69SBart Van Assche             printf("  Number of medium transport recovered errors: "
7467*44704f69SBart Van Assche                    "%" PRIu64 "\n", ull);
7468*44704f69SBart Van Assche             break;
7469*44704f69SBart Van Assche         case 0xc:
7470*44704f69SBart Van Assche             printf("  Number of medium transport X axis translation "
7471*44704f69SBart Van Assche                    "unrecovered errors: %" PRIu64 "\n", ull);
7472*44704f69SBart Van Assche             break;
7473*44704f69SBart Van Assche         case 0xd:
7474*44704f69SBart Van Assche             printf("  Number of medium transport X axis translation "
7475*44704f69SBart Van Assche                    "recovered errors: %" PRIu64 "\n", ull);
7476*44704f69SBart Van Assche             break;
7477*44704f69SBart Van Assche         case 0xe:
7478*44704f69SBart Van Assche             printf("  Number of medium transport Y axis translation "
7479*44704f69SBart Van Assche                    "unrecovered errors: %" PRIu64 "\n", ull);
7480*44704f69SBart Van Assche             break;
7481*44704f69SBart Van Assche         case 0xf:
7482*44704f69SBart Van Assche             printf("  Number of medium transport Y axis translation "
7483*44704f69SBart Van Assche                    "recovered errors: %" PRIu64 "\n", ull);
7484*44704f69SBart Van Assche             break;
7485*44704f69SBart Van Assche         case 0x10:
7486*44704f69SBart Van Assche             printf("  Number of medium transport Z axis translation "
7487*44704f69SBart Van Assche                    "unrecovered errors: %" PRIu64 "\n", ull);
7488*44704f69SBart Van Assche             break;
7489*44704f69SBart Van Assche         case 0x11:
7490*44704f69SBart Van Assche             printf("  Number of medium transport Z axis translation "
7491*44704f69SBart Van Assche                    "recovered errors: %" PRIu64 "\n", ull);
7492*44704f69SBart Van Assche             break;
7493*44704f69SBart Van Assche         case 0x12:
7494*44704f69SBart Van Assche             printf("  Number of medium transport rotational translation "
7495*44704f69SBart Van Assche                    "unrecovered errors: %" PRIu64 "\n", ull);
7496*44704f69SBart Van Assche             break;
7497*44704f69SBart Van Assche         case 0x13:
7498*44704f69SBart Van Assche             printf("  Number of medium transport rotational translation "
7499*44704f69SBart Van Assche                    "recovered errors: %" PRIu64 "\n", ull);
7500*44704f69SBart Van Assche             break;
7501*44704f69SBart Van Assche         case 0x14:
7502*44704f69SBart Van Assche             printf("  Number of medium transport inversion translation "
7503*44704f69SBart Van Assche                    "unrecovered errors: %" PRIu64 "\n", ull);
7504*44704f69SBart Van Assche             break;
7505*44704f69SBart Van Assche         case 0x15:
7506*44704f69SBart Van Assche             printf("  Number of medium transport inversion translation "
7507*44704f69SBart Van Assche                    "recovered errors: %" PRIu64 "\n", ull);
7508*44704f69SBart Van Assche             break;
7509*44704f69SBart Van Assche         case 0x16:
7510*44704f69SBart Van Assche             printf("  Number of medium transport auxiliary translation "
7511*44704f69SBart Van Assche                    "unrecovered errors: %" PRIu64 "\n", ull);
7512*44704f69SBart Van Assche             break;
7513*44704f69SBart Van Assche         case 0x17:
7514*44704f69SBart Van Assche             printf("  Number of medium transport auxiliary translation "
7515*44704f69SBart Van Assche                    "recovered errors: %" PRIu64 "\n", ull);
7516*44704f69SBart Van Assche             break;
7517*44704f69SBart Van Assche         default:
7518*44704f69SBart Van Assche             printf("  Reserved parameter [0x%x] value: %" PRIu64 "\n",
7519*44704f69SBart Van Assche                    pc, ull);
7520*44704f69SBart Van Assche             break;
7521*44704f69SBart Van Assche         }
7522*44704f69SBart Van Assche         if (op->do_pcb)
7523*44704f69SBart Van Assche             printf("        <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
7524*44704f69SBart Van Assche filter_chk:
7525*44704f69SBart Van Assche         if (op->filter_given)
7526*44704f69SBart Van Assche             break;
7527*44704f69SBart Van Assche skip:
7528*44704f69SBart Van Assche         num -= pl;
7529*44704f69SBart Van Assche         bp += pl;
7530*44704f69SBart Van Assche     }
7531*44704f69SBart Van Assche     return true;
7532*44704f69SBart Van Assche }
7533*44704f69SBart Van Assche 
7534*44704f69SBart Van Assche /* Element statistics page, 0x15 <els> for SMC */
7535*44704f69SBart Van Assche static bool
show_element_stats_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)7536*44704f69SBart Van Assche show_element_stats_page(const uint8_t * resp, int len,
7537*44704f69SBart Van Assche                         struct opts_t * op, sgj_opaque_p jop)
7538*44704f69SBart Van Assche {
7539*44704f69SBart Van Assche     int num, pl, pc;
7540*44704f69SBart Van Assche     unsigned int v;
7541*44704f69SBart Van Assche     const uint8_t * bp;
7542*44704f69SBart Van Assche     char str[PCB_STR_LEN];
7543*44704f69SBart Van Assche 
7544*44704f69SBart Van Assche if (jop) { };
7545*44704f69SBart Van Assche     if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
7546*44704f69SBart Van Assche         printf("Element statistics page (smc-3) [0x15]\n");
7547*44704f69SBart Van Assche     num = len - 4;
7548*44704f69SBart Van Assche     bp = &resp[0] + 4;
7549*44704f69SBart Van Assche     while (num > 3) {
7550*44704f69SBart Van Assche         pc = sg_get_unaligned_be16(bp + 0);
7551*44704f69SBart Van Assche         pl = bp[3] + 4;
7552*44704f69SBart Van Assche         if (op->filter_given) {
7553*44704f69SBart Van Assche             if (pc != op->filter)
7554*44704f69SBart Van Assche                 goto skip;
7555*44704f69SBart Van Assche         }
7556*44704f69SBart Van Assche         if (op->do_raw) {
7557*44704f69SBart Van Assche             dStrRaw(bp, pl);
7558*44704f69SBart Van Assche             goto filter_chk;
7559*44704f69SBart Van Assche         } else if (op->do_hex) {
7560*44704f69SBart Van Assche             hex2stdout(bp, pl, op->dstrhex_no_ascii);
7561*44704f69SBart Van Assche             goto filter_chk;
7562*44704f69SBart Van Assche         }
7563*44704f69SBart Van Assche         printf("  Element address: %d\n", pc);
7564*44704f69SBart Van Assche         v = sg_get_unaligned_be32(bp + 4);
7565*44704f69SBart Van Assche         printf("    Number of places: %u\n", v);
7566*44704f69SBart Van Assche         v = sg_get_unaligned_be32(bp + 8);
7567*44704f69SBart Van Assche         printf("    Number of place retries: %u\n", v);
7568*44704f69SBart Van Assche         v = sg_get_unaligned_be32(bp + 12);
7569*44704f69SBart Van Assche         printf("    Number of picks: %u\n", v);
7570*44704f69SBart Van Assche         v = sg_get_unaligned_be32(bp + 16);
7571*44704f69SBart Van Assche         printf("    Number of pick retries: %u\n", v);
7572*44704f69SBart Van Assche         v = sg_get_unaligned_be32(bp + 20);
7573*44704f69SBart Van Assche         printf("    Number of determined volume identifiers: %u\n", v);
7574*44704f69SBart Van Assche         v = sg_get_unaligned_be32(bp + 24);
7575*44704f69SBart Van Assche         printf("    Number of unreadable volume identifiers: %u\n", v);
7576*44704f69SBart Van Assche         if (op->do_pcb)
7577*44704f69SBart Van Assche             printf("        <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
7578*44704f69SBart Van Assche filter_chk:
7579*44704f69SBart Van Assche         if (op->filter_given)
7580*44704f69SBart Van Assche             break;
7581*44704f69SBart Van Assche skip:
7582*44704f69SBart Van Assche         num -= pl;
7583*44704f69SBart Van Assche         bp += pl;
7584*44704f69SBart Van Assche     }
7585*44704f69SBart Van Assche     return true;
7586*44704f69SBart Van Assche }
7587*44704f69SBart Van Assche 
7588*44704f69SBart Van Assche /* Tape diagnostic data [0x16] <tdd> for tape */
7589*44704f69SBart Van Assche static bool
show_tape_diag_data_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)7590*44704f69SBart Van Assche show_tape_diag_data_page(const uint8_t * resp, int len,
7591*44704f69SBart Van Assche                          struct opts_t * op, sgj_opaque_p jop)
7592*44704f69SBart Van Assche {
7593*44704f69SBart Van Assche     int k, n, num, pl, pc;
7594*44704f69SBart Van Assche     unsigned int v;
7595*44704f69SBart Van Assche     const uint8_t * bp;
7596*44704f69SBart Van Assche     char str[PCB_STR_LEN];
7597*44704f69SBart Van Assche     char b[512];
7598*44704f69SBart Van Assche 
7599*44704f69SBart Van Assche if (jop) { };
7600*44704f69SBart Van Assche     if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
7601*44704f69SBart Van Assche         printf("Tape diagnostics data page (ssc-3) [0x16]\n");
7602*44704f69SBart Van Assche     num = len - 4;
7603*44704f69SBart Van Assche     bp = &resp[0] + 4;
7604*44704f69SBart Van Assche     while (num > 3) {
7605*44704f69SBart Van Assche         pc = sg_get_unaligned_be16(bp + 0);
7606*44704f69SBart Van Assche         pl = bp[3] + 4;
7607*44704f69SBart Van Assche         if (op->filter_given) {
7608*44704f69SBart Van Assche             if (pc != op->filter)
7609*44704f69SBart Van Assche                 goto skip;
7610*44704f69SBart Van Assche         }
7611*44704f69SBart Van Assche         if (op->do_raw) {
7612*44704f69SBart Van Assche             dStrRaw(bp, pl);
7613*44704f69SBart Van Assche             goto filter_chk;
7614*44704f69SBart Van Assche         } else if (op->do_hex) {
7615*44704f69SBart Van Assche             hex2stdout(bp, pl, op->dstrhex_no_ascii);
7616*44704f69SBart Van Assche             goto filter_chk;
7617*44704f69SBart Van Assche         }
7618*44704f69SBart Van Assche         printf("  %s: %d\n", param_c, pc);
7619*44704f69SBart Van Assche         printf("    Density code: 0x%x\n", bp[6]);
7620*44704f69SBart Van Assche         printf("    Medium type: 0x%x\n", bp[7]);
7621*44704f69SBart Van Assche         v = sg_get_unaligned_be32(bp + 8);
7622*44704f69SBart Van Assche         printf("    Lifetime media motion hours: %u\n", v);
7623*44704f69SBart Van Assche         printf("    Repeat: %d\n", !!(bp[13] & 0x80));
7624*44704f69SBart Van Assche         v = bp[13] & 0xf;
7625*44704f69SBart Van Assche         printf("    Sense key: 0x%x [%s]\n", v,
7626*44704f69SBart Van Assche                sg_get_sense_key_str(v, sizeof(b), b));
7627*44704f69SBart Van Assche         printf("    Additional sense code: 0x%x\n", bp[14]);
7628*44704f69SBart Van Assche         printf("    Additional sense code qualifier: 0x%x\n", bp[15]);
7629*44704f69SBart Van Assche         if (bp[14] || bp[15])
7630*44704f69SBart Van Assche             printf("      [%s]\n", sg_get_asc_ascq_str(bp[14], bp[15],
7631*44704f69SBart Van Assche                    sizeof(b), b));
7632*44704f69SBart Van Assche         v = sg_get_unaligned_be32(bp + 16);
7633*44704f69SBart Van Assche         printf("    Vendor specific code qualifier: 0x%x\n", v);
7634*44704f69SBart Van Assche         v = sg_get_unaligned_be32(bp + 20);
7635*44704f69SBart Van Assche         printf("    Product revision level: %u\n", v);
7636*44704f69SBart Van Assche         v = sg_get_unaligned_be32(bp + 24);
7637*44704f69SBart Van Assche         printf("    Hours since last clean: %u\n", v);
7638*44704f69SBart Van Assche         printf("    Operation code: 0x%x\n", bp[28]);
7639*44704f69SBart Van Assche         printf("    Service action: 0x%x\n", bp[29] & 0xf);
7640*44704f69SBart Van Assche         // Check Medium id number for all zeros
7641*44704f69SBart Van Assche         // ssc4r03.pdf does not define this field, why? xxxxxx
7642*44704f69SBart Van Assche         if (sg_all_zeros(bp + 32, 32))
7643*44704f69SBart Van Assche             printf("    Medium id number is 32 bytes of zero\n");
7644*44704f69SBart Van Assche         else {
7645*44704f69SBart Van Assche             hex2str(bp + 32, 32, "      ", 0 /* with ASCII */, sizeof(b), b);
7646*44704f69SBart Van Assche             printf("    Medium id number (in hex):\n%s", b);
7647*44704f69SBart Van Assche         }
7648*44704f69SBart Van Assche         printf("    Timestamp origin: 0x%x\n", bp[64] & 0xf);
7649*44704f69SBart Van Assche         // Check Timestamp for all zeros
7650*44704f69SBart Van Assche         if (sg_all_zeros(bp + 66, 6))
7651*44704f69SBart Van Assche             printf("    Timestamp is all zeros:\n");
7652*44704f69SBart Van Assche         else {
7653*44704f69SBart Van Assche             hex2str(bp + 66, 6, NULL, op->hex2str_oformat, sizeof(b), b);
7654*44704f69SBart Van Assche             printf("    Timestamp: %s", b);
7655*44704f69SBart Van Assche         }
7656*44704f69SBart Van Assche         if (pl > 72) {
7657*44704f69SBart Van Assche             n = pl - 72;
7658*44704f69SBart Van Assche             k = hex2str(bp + 72, n, "      ", op->hex2str_oformat,
7659*44704f69SBart Van Assche                         sizeof(b), b);
7660*44704f69SBart Van Assche             printf("    Vendor specific:\n");
7661*44704f69SBart Van Assche             printf("%s", b);
7662*44704f69SBart Van Assche             if (k >= (int)sizeof(b) - 1)
7663*44704f69SBart Van Assche                 printf("      <truncated>\n");
7664*44704f69SBart Van Assche         }
7665*44704f69SBart Van Assche         if (op->do_pcb)
7666*44704f69SBart Van Assche             printf("        <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
7667*44704f69SBart Van Assche filter_chk:
7668*44704f69SBart Van Assche         if (op->filter_given)
7669*44704f69SBart Van Assche             break;
7670*44704f69SBart Van Assche skip:
7671*44704f69SBart Van Assche         num -= pl;
7672*44704f69SBart Van Assche         bp += pl;
7673*44704f69SBart Van Assche     }
7674*44704f69SBart Van Assche     return true;
7675*44704f69SBart Van Assche }
7676*44704f69SBart Van Assche 
7677*44704f69SBart Van Assche /* Media changer diagnostic data [0x16] <mcdd> for media changer */
7678*44704f69SBart Van Assche static bool
show_mchanger_diag_data_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)7679*44704f69SBart Van Assche show_mchanger_diag_data_page(const uint8_t * resp, int len,
7680*44704f69SBart Van Assche                              struct opts_t * op, sgj_opaque_p jop)
7681*44704f69SBart Van Assche {
7682*44704f69SBart Van Assche     int num, pl, pc;
7683*44704f69SBart Van Assche     unsigned int v;
7684*44704f69SBart Van Assche     const uint8_t * bp;
7685*44704f69SBart Van Assche     char str[PCB_STR_LEN];
7686*44704f69SBart Van Assche     char b[512];
7687*44704f69SBart Van Assche 
7688*44704f69SBart Van Assche if (jop) { };
7689*44704f69SBart Van Assche     if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
7690*44704f69SBart Van Assche         printf("Media changer diagnostics data page (smc-3) [0x16]\n");
7691*44704f69SBart Van Assche     num = len - 4;
7692*44704f69SBart Van Assche     bp = &resp[0] + 4;
7693*44704f69SBart Van Assche     while (num > 3) {
7694*44704f69SBart Van Assche         pc = sg_get_unaligned_be16(bp + 0);
7695*44704f69SBart Van Assche         pl = bp[3] + 4;
7696*44704f69SBart Van Assche         if (op->filter_given) {
7697*44704f69SBart Van Assche             if (pc != op->filter)
7698*44704f69SBart Van Assche                 goto skip;
7699*44704f69SBart Van Assche         }
7700*44704f69SBart Van Assche         if (op->do_raw) {
7701*44704f69SBart Van Assche             dStrRaw(bp, pl);
7702*44704f69SBart Van Assche             goto filter_chk;
7703*44704f69SBart Van Assche         } else if (op->do_hex) {
7704*44704f69SBart Van Assche             hex2stdout(bp, pl, op->dstrhex_no_ascii);
7705*44704f69SBart Van Assche             goto filter_chk;
7706*44704f69SBart Van Assche         }
7707*44704f69SBart Van Assche         printf("  %s: %d\n", param_c, pc);
7708*44704f69SBart Van Assche         printf("    Repeat: %d\n", !!(bp[5] & 0x80));
7709*44704f69SBart Van Assche         v = bp[5] & 0xf;
7710*44704f69SBart Van Assche         printf("    Sense key: 0x%x [%s]\n", v,
7711*44704f69SBart Van Assche                sg_get_sense_key_str(v, sizeof(b), b));
7712*44704f69SBart Van Assche         printf("    Additional sense code: 0x%x\n", bp[6]);
7713*44704f69SBart Van Assche         printf("    Additional sense code qualifier: 0x%x\n", bp[7]);
7714*44704f69SBart Van Assche         if (bp[6] || bp[7])
7715*44704f69SBart Van Assche             printf("      [%s]\n", sg_get_asc_ascq_str(bp[6], bp[7],
7716*44704f69SBart Van Assche                    sizeof(b), b));
7717*44704f69SBart Van Assche         v = sg_get_unaligned_be32(bp + 8);
7718*44704f69SBart Van Assche         printf("    Vendor specific code qualifier: 0x%x\n", v);
7719*44704f69SBart Van Assche         v = sg_get_unaligned_be32(bp + 12);
7720*44704f69SBart Van Assche         printf("    Product revision level: %u\n", v);
7721*44704f69SBart Van Assche         v = sg_get_unaligned_be32(bp + 16);
7722*44704f69SBart Van Assche         printf("    Number of moves: %u\n", v);
7723*44704f69SBart Van Assche         v = sg_get_unaligned_be32(bp + 20);
7724*44704f69SBart Van Assche         printf("    Number of pick: %u\n", v);
7725*44704f69SBart Van Assche         v = sg_get_unaligned_be32(bp + 24);
7726*44704f69SBart Van Assche         printf("    Number of pick retries: %u\n", v);
7727*44704f69SBart Van Assche         v = sg_get_unaligned_be32(bp + 28);
7728*44704f69SBart Van Assche         printf("    Number of places: %u\n", v);
7729*44704f69SBart Van Assche         v = sg_get_unaligned_be32(bp + 32);
7730*44704f69SBart Van Assche         printf("    Number of place retries: %u\n", v);
7731*44704f69SBart Van Assche         v = sg_get_unaligned_be32(bp + 36);
7732*44704f69SBart Van Assche         printf("    Number of determined volume identifiers: %u\n", v);
7733*44704f69SBart Van Assche         v = sg_get_unaligned_be32(bp + 40);
7734*44704f69SBart Van Assche         printf("    Number of unreadable volume identifiers: %u\n", v);
7735*44704f69SBart Van Assche         printf("    Operation code: 0x%x\n", bp[44]);
7736*44704f69SBart Van Assche         printf("    Service action: 0x%x\n", bp[45] & 0xf);
7737*44704f69SBart Van Assche         printf("    Media changer error type: 0x%x\n", bp[46]);
7738*44704f69SBart Van Assche         printf("    MTAV: %d\n", !!(bp[47] & 0x8));
7739*44704f69SBart Van Assche         printf("    IAV: %d\n", !!(bp[47] & 0x4));
7740*44704f69SBart Van Assche         printf("    LSAV: %d\n", !!(bp[47] & 0x2));
7741*44704f69SBart Van Assche         printf("    DAV: %d\n", !!(bp[47] & 0x1));
7742*44704f69SBart Van Assche         v = sg_get_unaligned_be16(bp + 48);
7743*44704f69SBart Van Assche         printf("    Medium transport address: 0x%x\n", v);
7744*44704f69SBart Van Assche         v = sg_get_unaligned_be16(bp + 50);
7745*44704f69SBart Van Assche         printf("    Initial address: 0x%x\n", v);
7746*44704f69SBart Van Assche         v = sg_get_unaligned_be16(bp + 52);
7747*44704f69SBart Van Assche         printf("    Last successful address: 0x%x\n", v);
7748*44704f69SBart Van Assche         v = sg_get_unaligned_be16(bp + 54);
7749*44704f69SBart Van Assche         printf("    Destination address: 0x%x\n", v);
7750*44704f69SBart Van Assche         if (pl > 91) {
7751*44704f69SBart Van Assche             printf("    Volume tag information:\n");
7752*44704f69SBart Van Assche             hex2fp(bp + 56, 36, "    ", op->hex2str_oformat, stdout);
7753*44704f69SBart Van Assche         }
7754*44704f69SBart Van Assche         if (pl > 99) {
7755*44704f69SBart Van Assche             printf("    Timestamp origin: 0x%x\n", bp[92] & 0xf);
7756*44704f69SBart Van Assche             printf("    Timestamp:\n");
7757*44704f69SBart Van Assche             hex2fp(bp + 94, 6, "    ", op->hex2str_oformat, stdout);
7758*44704f69SBart Van Assche         }
7759*44704f69SBart Van Assche         if (op->do_pcb)
7760*44704f69SBart Van Assche             printf("        <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
7761*44704f69SBart Van Assche filter_chk:
7762*44704f69SBart Van Assche         if (op->filter_given)
7763*44704f69SBart Van Assche             break;
7764*44704f69SBart Van Assche skip:
7765*44704f69SBart Van Assche         num -= pl;
7766*44704f69SBart Van Assche         bp += pl;
7767*44704f69SBart Van Assche     }
7768*44704f69SBart Van Assche     return true;
7769*44704f69SBart Van Assche }
7770*44704f69SBart Van Assche 
7771*44704f69SBart Van Assche /* Helper for show_volume_stats_pages() */
7772*44704f69SBart Van Assche static void
volume_stats_partition(const uint8_t * xp,int len,bool pr_in_hex)7773*44704f69SBart Van Assche volume_stats_partition(const uint8_t * xp, int len, bool pr_in_hex)
7774*44704f69SBart Van Assche {
7775*44704f69SBart Van Assche     uint64_t ull;
7776*44704f69SBart Van Assche 
7777*44704f69SBart Van Assche     while (len > 3) {
7778*44704f69SBart Van Assche         bool all_ffs, ffs_last_fe;
7779*44704f69SBart Van Assche         int dl, pn;
7780*44704f69SBart Van Assche 
7781*44704f69SBart Van Assche         dl = xp[0] + 1;
7782*44704f69SBart Van Assche         if (dl < 3)
7783*44704f69SBart Van Assche             return;
7784*44704f69SBart Van Assche         pn = sg_get_unaligned_be16(xp + 2);
7785*44704f69SBart Van Assche         ffs_last_fe = false;
7786*44704f69SBart Van Assche         all_ffs = false;
7787*44704f69SBart Van Assche         if (sg_all_ffs(xp + 4, dl - 3)) {
7788*44704f69SBart Van Assche             switch (xp[4 + dl - 3]) {
7789*44704f69SBart Van Assche             case 0xff:
7790*44704f69SBart Van Assche                 all_ffs = true;
7791*44704f69SBart Van Assche                 break;
7792*44704f69SBart Van Assche             case 0xfe:
7793*44704f69SBart Van Assche                 ffs_last_fe = true;
7794*44704f69SBart Van Assche                 break;
7795*44704f69SBart Van Assche             default:
7796*44704f69SBart Van Assche                 break;
7797*44704f69SBart Van Assche             }
7798*44704f69SBart Van Assche         }
7799*44704f69SBart Van Assche         if (! (all_ffs || ffs_last_fe)) {
7800*44704f69SBart Van Assche             ull = sg_get_unaligned_be(dl - 4, xp + 4);
7801*44704f69SBart Van Assche             if (pr_in_hex)
7802*44704f69SBart Van Assche                 printf("    partition number: %d, partition record data "
7803*44704f69SBart Van Assche                        "counter: 0x%" PRIx64 "\n", pn, ull);
7804*44704f69SBart Van Assche             else
7805*44704f69SBart Van Assche                 printf("    partition number: %d, partition record data "
7806*44704f69SBart Van Assche                        "counter: %" PRIu64 "\n", pn, ull);
7807*44704f69SBart Van Assche         } else if (all_ffs)
7808*44704f69SBart Van Assche             printf("    partition number: %d, partition record data "
7809*44704f69SBart Van Assche                    "counter is all 0xFFs\n", pn);
7810*44704f69SBart Van Assche         else    /* ffs_last_fe is true */
7811*44704f69SBart Van Assche             printf("    partition number: %d, partition record data "
7812*44704f69SBart Van Assche                    "counter is all 0xFFs apart\n    from a trailing "
7813*44704f69SBart Van Assche                    "0xFE\n", pn);
7814*44704f69SBart Van Assche         xp += dl;
7815*44704f69SBart Van Assche         len -= dl;
7816*44704f69SBart Van Assche     }
7817*44704f69SBart Van Assche }
7818*44704f69SBart Van Assche 
7819*44704f69SBart Van Assche /* Helper for show_volume_stats_pages() */
7820*44704f69SBart Van Assche static void
volume_stats_history(const uint8_t * xp,int len)7821*44704f69SBart Van Assche volume_stats_history(const uint8_t * xp, int len)
7822*44704f69SBart Van Assche {
7823*44704f69SBart Van Assche     while (len > 3) {
7824*44704f69SBart Van Assche         int dl, mhi;
7825*44704f69SBart Van Assche 
7826*44704f69SBart Van Assche         dl = xp[0] + 1;
7827*44704f69SBart Van Assche         if (dl < 4)
7828*44704f69SBart Van Assche             return;
7829*44704f69SBart Van Assche         mhi = sg_get_unaligned_be16(xp + 2);
7830*44704f69SBart Van Assche         if (dl < 12)
7831*44704f69SBart Van Assche             printf("    index: %d\n", mhi);
7832*44704f69SBart Van Assche         else if (12 == dl)
7833*44704f69SBart Van Assche             printf("    index: %d, vendor: %.8s\n", mhi, xp + 4);
7834*44704f69SBart Van Assche         else
7835*44704f69SBart Van Assche             printf("    index: %d, vendor: %.8s, unit serial number: %.*s\n",
7836*44704f69SBart Van Assche                    mhi, xp + 4, dl - 12, xp + 12);
7837*44704f69SBart Van Assche         xp += dl;
7838*44704f69SBart Van Assche         len -= dl;
7839*44704f69SBart Van Assche     }
7840*44704f69SBart Van Assche }
7841*44704f69SBart Van Assche 
7842*44704f69SBart Van Assche /* Volume Statistics log page and subpages (ssc-4) [0x17, 0x0-0xf] <vs> */
7843*44704f69SBart Van Assche static bool
show_volume_stats_pages(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)7844*44704f69SBart Van Assche show_volume_stats_pages(const uint8_t * resp, int len,
7845*44704f69SBart Van Assche                        struct opts_t * op, sgj_opaque_p jop)
7846*44704f69SBart Van Assche {
7847*44704f69SBart Van Assche     bool skip_out = false;
7848*44704f69SBart Van Assche     bool evsm_output = false;
7849*44704f69SBart Van Assche     int num, pl, pc, subpg_code;
7850*44704f69SBart Van Assche     bool spf;
7851*44704f69SBart Van Assche     const uint8_t * bp;
7852*44704f69SBart Van Assche     char str[PCB_STR_LEN];
7853*44704f69SBart Van Assche     char b[512];
7854*44704f69SBart Van Assche 
7855*44704f69SBart Van Assche if (jop) { };
7856*44704f69SBart Van Assche     spf = !!(resp[0] & 0x40);
7857*44704f69SBart Van Assche     subpg_code = spf ? resp[1] : NOT_SPG_SUBPG;
7858*44704f69SBart Van Assche     if (op->verbose || ((! op->do_raw) && (0 == op->do_hex))) {
7859*44704f69SBart Van Assche         if (subpg_code < 0x10)
7860*44704f69SBart Van Assche             printf("Volume statistics page (ssc-4), subpage=%d\n",
7861*44704f69SBart Van Assche                    subpg_code);
7862*44704f69SBart Van Assche         else {
7863*44704f69SBart Van Assche             printf("Volume statistics page (ssc-4), subpage=%d; Reserved, "
7864*44704f69SBart Van Assche                    "skip\n", subpg_code);
7865*44704f69SBart Van Assche             return false;
7866*44704f69SBart Van Assche         }
7867*44704f69SBart Van Assche     }
7868*44704f69SBart Van Assche     num = len - 4;
7869*44704f69SBart Van Assche     bp = &resp[0] + 4;
7870*44704f69SBart Van Assche     while (num > 3) {
7871*44704f69SBart Van Assche         pc = sg_get_unaligned_be16(bp + 0);
7872*44704f69SBart Van Assche         pl = bp[3] + 4;
7873*44704f69SBart Van Assche         if (op->filter_given) {
7874*44704f69SBart Van Assche             if (pc != op->filter)
7875*44704f69SBart Van Assche                 goto skip;
7876*44704f69SBart Van Assche         }
7877*44704f69SBart Van Assche         if (op->do_raw) {
7878*44704f69SBart Van Assche             dStrRaw(bp, pl);
7879*44704f69SBart Van Assche             goto filter_chk;
7880*44704f69SBart Van Assche         } else if (op->do_hex) {
7881*44704f69SBart Van Assche             hex2stdout(bp, pl, op->dstrhex_no_ascii);
7882*44704f69SBart Van Assche             goto filter_chk;
7883*44704f69SBart Van Assche         }
7884*44704f69SBart Van Assche 
7885*44704f69SBart Van Assche         switch (pc) {
7886*44704f69SBart Van Assche         case 0:
7887*44704f69SBart Van Assche             printf("  Page valid: %" PRIu64 "\n",
7888*44704f69SBart Van Assche                    sg_get_unaligned_be(pl - 4, bp + 4));
7889*44704f69SBart Van Assche             break;
7890*44704f69SBart Van Assche         case 1:
7891*44704f69SBart Van Assche             printf("  Thread count: %" PRIu64 "\n",
7892*44704f69SBart Van Assche                    sg_get_unaligned_be(pl - 4, bp + 4));
7893*44704f69SBart Van Assche             break;
7894*44704f69SBart Van Assche         case 2:
7895*44704f69SBart Van Assche             printf("  Total data sets written: %" PRIu64 "\n",
7896*44704f69SBart Van Assche                    sg_get_unaligned_be(pl - 4, bp + 4));
7897*44704f69SBart Van Assche             break;
7898*44704f69SBart Van Assche         case 3:
7899*44704f69SBart Van Assche             printf("  Total write retries: %" PRIu64 "\n",
7900*44704f69SBart Van Assche                    sg_get_unaligned_be(pl - 4, bp + 4));
7901*44704f69SBart Van Assche             break;
7902*44704f69SBart Van Assche         case 4:
7903*44704f69SBart Van Assche             printf("  Total unrecovered write errors: %" PRIu64 "\n",
7904*44704f69SBart Van Assche                    sg_get_unaligned_be(pl - 4, bp + 4));
7905*44704f69SBart Van Assche             break;
7906*44704f69SBart Van Assche         case 5:
7907*44704f69SBart Van Assche             printf("  Total suspended writes: %" PRIu64 "\n",
7908*44704f69SBart Van Assche                    sg_get_unaligned_be(pl - 4, bp + 4));
7909*44704f69SBart Van Assche             break;
7910*44704f69SBart Van Assche         case 6:
7911*44704f69SBart Van Assche             printf("  Total fatal suspended writes: %" PRIu64 "\n",
7912*44704f69SBart Van Assche                    sg_get_unaligned_be(pl - 4, bp + 4));
7913*44704f69SBart Van Assche             break;
7914*44704f69SBart Van Assche         case 7:
7915*44704f69SBart Van Assche             printf("  Total data sets read: %" PRIu64 "\n",
7916*44704f69SBart Van Assche                    sg_get_unaligned_be(pl - 4, bp + 4));
7917*44704f69SBart Van Assche             break;
7918*44704f69SBart Van Assche         case 8:
7919*44704f69SBart Van Assche             printf("  Total read retries: %" PRIu64 "\n",
7920*44704f69SBart Van Assche                    sg_get_unaligned_be(pl - 4, bp + 4));
7921*44704f69SBart Van Assche             break;
7922*44704f69SBart Van Assche         case 9:
7923*44704f69SBart Van Assche             printf("  Total unrecovered read errors: %" PRIu64 "\n",
7924*44704f69SBart Van Assche                    sg_get_unaligned_be(pl - 4, bp + 4));
7925*44704f69SBart Van Assche             break;
7926*44704f69SBart Van Assche         case 0xa:
7927*44704f69SBart Van Assche             printf("  Total suspended reads: %" PRIu64 "\n",
7928*44704f69SBart Van Assche                    sg_get_unaligned_be(pl - 4, bp + 4));
7929*44704f69SBart Van Assche             break;
7930*44704f69SBart Van Assche         case 0xb:
7931*44704f69SBart Van Assche             printf("  Total fatal suspended reads: %" PRIu64 "\n",
7932*44704f69SBart Van Assche                    sg_get_unaligned_be(pl - 4, bp + 4));
7933*44704f69SBart Van Assche             break;
7934*44704f69SBart Van Assche         case 0xc:
7935*44704f69SBart Van Assche             printf("  Last mount unrecovered write errors: %" PRIu64 "\n",
7936*44704f69SBart Van Assche                    sg_get_unaligned_be(pl - 4, bp + 4));
7937*44704f69SBart Van Assche             break;
7938*44704f69SBart Van Assche         case 0xd:
7939*44704f69SBart Van Assche             printf("  Last mount unrecovered read errors: %" PRIu64 "\n",
7940*44704f69SBart Van Assche                    sg_get_unaligned_be(pl - 4, bp + 4));
7941*44704f69SBart Van Assche             break;
7942*44704f69SBart Van Assche         case 0xe:
7943*44704f69SBart Van Assche             printf("  Last mount megabytes written: %" PRIu64 "\n",
7944*44704f69SBart Van Assche                    sg_get_unaligned_be(pl - 4, bp + 4));
7945*44704f69SBart Van Assche             break;
7946*44704f69SBart Van Assche         case 0xf:
7947*44704f69SBart Van Assche             printf("  Last mount megabytes read: %" PRIu64 "\n",
7948*44704f69SBart Van Assche                    sg_get_unaligned_be(pl - 4, bp + 4));
7949*44704f69SBart Van Assche             break;
7950*44704f69SBart Van Assche         case 0x10:
7951*44704f69SBart Van Assche             printf("  Lifetime megabytes written: %" PRIu64 "\n",
7952*44704f69SBart Van Assche                    sg_get_unaligned_be(pl - 4, bp + 4));
7953*44704f69SBart Van Assche             break;
7954*44704f69SBart Van Assche         case 0x11:
7955*44704f69SBart Van Assche             printf("  Lifetime megabytes read: %" PRIu64 "\n",
7956*44704f69SBart Van Assche                    sg_get_unaligned_be(pl - 4, bp + 4));
7957*44704f69SBart Van Assche             break;
7958*44704f69SBart Van Assche         case 0x12:
7959*44704f69SBart Van Assche             printf("  Last load write compression ratio: %" PRIu64 "\n",
7960*44704f69SBart Van Assche                    sg_get_unaligned_be(pl - 4, bp + 4));
7961*44704f69SBart Van Assche             break;
7962*44704f69SBart Van Assche         case 0x13:
7963*44704f69SBart Van Assche             printf("  Last load read compression ratio: %" PRIu64 "\n",
7964*44704f69SBart Van Assche                    sg_get_unaligned_be(pl - 4, bp + 4));
7965*44704f69SBart Van Assche             break;
7966*44704f69SBart Van Assche         case 0x14:
7967*44704f69SBart Van Assche             printf("  Medium mount time: %" PRIu64 "\n",
7968*44704f69SBart Van Assche                    sg_get_unaligned_be(pl - 4, bp + 4));
7969*44704f69SBart Van Assche             break;
7970*44704f69SBart Van Assche         case 0x15:
7971*44704f69SBart Van Assche             printf("  Medium ready time: %" PRIu64 "\n",
7972*44704f69SBart Van Assche                    sg_get_unaligned_be(pl - 4, bp + 4));
7973*44704f69SBart Van Assche             break;
7974*44704f69SBart Van Assche         case 0x16:
7975*44704f69SBart Van Assche             printf("  Total native capacity [MB]: %s\n",
7976*44704f69SBart Van Assche                    num_or_unknown(bp + 4, pl - 4, false, b, sizeof(b)));
7977*44704f69SBart Van Assche             break;
7978*44704f69SBart Van Assche         case 0x17:
7979*44704f69SBart Van Assche             printf("  Total used native capacity [MB]: %s\n",
7980*44704f69SBart Van Assche                    num_or_unknown(bp + 4, pl - 4, false, b, sizeof(b)));
7981*44704f69SBart Van Assche             break;
7982*44704f69SBart Van Assche         case 0x1a:
7983*44704f69SBart Van Assche             printf("  Volume stop writes of forward wraps: %" PRIu64 "\n",
7984*44704f69SBart Van Assche                    sg_get_unaligned_be(pl - 4, bp + 4));
7985*44704f69SBart Van Assche             break;
7986*44704f69SBart Van Assche         case 0x1b:
7987*44704f69SBart Van Assche             printf("  Volume stop writes of backward wraps: %" PRIu64 "\n",
7988*44704f69SBart Van Assche                    sg_get_unaligned_be(pl - 4, bp + 4));
7989*44704f69SBart Van Assche             break;
7990*44704f69SBart Van Assche         case 0x40:
7991*44704f69SBart Van Assche             printf("  Volume serial number: %.*s\n", pl - 4, bp + 4);
7992*44704f69SBart Van Assche             break;
7993*44704f69SBart Van Assche         case 0x41:
7994*44704f69SBart Van Assche             printf("  Tape lot identifier: %.*s\n", pl - 4, bp + 4);
7995*44704f69SBart Van Assche             break;
7996*44704f69SBart Van Assche         case 0x42:
7997*44704f69SBart Van Assche             printf("  Volume barcode: %.*s\n", pl - 4, bp + 4);
7998*44704f69SBart Van Assche             break;
7999*44704f69SBart Van Assche         case 0x43:
8000*44704f69SBart Van Assche             printf("  Volume manufacturer: %.*s\n", pl - 4, bp + 4);
8001*44704f69SBart Van Assche             break;
8002*44704f69SBart Van Assche         case 0x44:
8003*44704f69SBart Van Assche             printf("  Volume license code: %.*s\n", pl - 4, bp + 4);
8004*44704f69SBart Van Assche             break;
8005*44704f69SBart Van Assche         case 0x45:
8006*44704f69SBart Van Assche             printf("  Volume personality: %.*s\n", pl - 4, bp + 4);
8007*44704f69SBart Van Assche             break;
8008*44704f69SBart Van Assche         case 0x80:
8009*44704f69SBart Van Assche             printf("  Write protect: %s\n",
8010*44704f69SBart Van Assche                    num_or_unknown(bp + 4, pl - 4, false, b, sizeof(b)));
8011*44704f69SBart Van Assche             break;
8012*44704f69SBart Van Assche         case 0x81:
8013*44704f69SBart Van Assche             printf("  WORM: %s\n",
8014*44704f69SBart Van Assche                    num_or_unknown(bp + 4, pl - 4, false, b, sizeof(b)));
8015*44704f69SBart Van Assche             break;
8016*44704f69SBart Van Assche         case 0x82:
8017*44704f69SBart Van Assche             printf("  Maximum recommended tape path temperature exceeded: "
8018*44704f69SBart Van Assche                    "%s\n", num_or_unknown(bp + 4, pl - 4, false, b,
8019*44704f69SBart Van Assche                                           sizeof(b)));
8020*44704f69SBart Van Assche             break;
8021*44704f69SBart Van Assche         case 0x100:
8022*44704f69SBart Van Assche             printf("  Volume write mounts: %" PRIu64 "\n",
8023*44704f69SBart Van Assche                    sg_get_unaligned_be(pl - 4, bp + 4));
8024*44704f69SBart Van Assche             break;
8025*44704f69SBart Van Assche         case 0x101:
8026*44704f69SBart Van Assche             printf("  Beginning of medium passes: %" PRIu64 "\n",
8027*44704f69SBart Van Assche                    sg_get_unaligned_be(pl - 4, bp + 4));
8028*44704f69SBart Van Assche             break;
8029*44704f69SBart Van Assche         case 0x102:
8030*44704f69SBart Van Assche             printf("  Middle of medium passes: %" PRIu64 "\n",
8031*44704f69SBart Van Assche                    sg_get_unaligned_be(pl - 4, bp + 4));
8032*44704f69SBart Van Assche             break;
8033*44704f69SBart Van Assche         case 0x200:
8034*44704f69SBart Van Assche             printf("  Logical position of first encrypted logical object:\n");
8035*44704f69SBart Van Assche             volume_stats_partition(bp + 4, pl - 4, true);
8036*44704f69SBart Van Assche             break;
8037*44704f69SBart Van Assche         case 0x201:
8038*44704f69SBart Van Assche             printf("  Logical position of first unencrypted logical object "
8039*44704f69SBart Van Assche                    "after first\n  encrypted logical object:\n");
8040*44704f69SBart Van Assche             volume_stats_partition(bp + 4, pl - 4, true);
8041*44704f69SBart Van Assche             break;
8042*44704f69SBart Van Assche         case 0x202:
8043*44704f69SBart Van Assche             printf("  Native capacity partition(s) [MB]:\n");
8044*44704f69SBart Van Assche             volume_stats_partition(bp + 4, pl - 4, false);
8045*44704f69SBart Van Assche             break;
8046*44704f69SBart Van Assche         case 0x203:
8047*44704f69SBart Van Assche             printf("  Used native capacity partition(s) [MB]:\n");
8048*44704f69SBart Van Assche             volume_stats_partition(bp + 4, pl - 4, false);
8049*44704f69SBart Van Assche             break;
8050*44704f69SBart Van Assche         case 0x204:
8051*44704f69SBart Van Assche             printf("  Remaining native capacity partition(s) [MB]:\n");
8052*44704f69SBart Van Assche             volume_stats_partition(bp + 4, pl - 4, false);
8053*44704f69SBart Van Assche             break;
8054*44704f69SBart Van Assche         case 0x300:
8055*44704f69SBart Van Assche             printf("  Mount history:\n");
8056*44704f69SBart Van Assche             volume_stats_history(bp + 4, pl - 4);
8057*44704f69SBart Van Assche             break;
8058*44704f69SBart Van Assche 
8059*44704f69SBart Van Assche         default:
8060*44704f69SBart Van Assche             if (pc >= 0xf000) {
8061*44704f69SBart Van Assche                     if (op->exclude_vendor) {
8062*44704f69SBart Van Assche                     skip_out = true;
8063*44704f69SBart Van Assche                     if ((op->verbose > 0) && (0 == op->do_brief) &&
8064*44704f69SBart Van Assche                         (! evsm_output)) {
8065*44704f69SBart Van Assche                         evsm_output = true;
8066*44704f69SBart Van Assche                         printf("  Vendor specific parameter(s) being "
8067*44704f69SBart Van Assche                                "ignored\n");
8068*44704f69SBart Van Assche                     }
8069*44704f69SBart Van Assche                 } else
8070*44704f69SBart Van Assche                     printf("  Vendor specific %s (0x%x), payload in hex\n",
8071*44704f69SBart Van Assche                            param_c, pc);
8072*44704f69SBart Van Assche             } else
8073*44704f69SBart Van Assche                 printf("  Reserved %s (0x%x), payload in hex\n", param_c, pc);
8074*44704f69SBart Van Assche             if (skip_out)
8075*44704f69SBart Van Assche                 skip_out = false;
8076*44704f69SBart Van Assche             else
8077*44704f69SBart Van Assche                 hex2fp(bp + 4, pl - 4, "    ", op->hex2str_oformat, stdout);
8078*44704f69SBart Van Assche             break;
8079*44704f69SBart Van Assche         }
8080*44704f69SBart Van Assche         if (op->do_pcb)
8081*44704f69SBart Van Assche             printf("        <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
8082*44704f69SBart Van Assche filter_chk:
8083*44704f69SBart Van Assche         if (op->filter_given)
8084*44704f69SBart Van Assche             break;
8085*44704f69SBart Van Assche skip:
8086*44704f69SBart Van Assche         num -= pl;
8087*44704f69SBart Van Assche         bp += pl;
8088*44704f69SBart Van Assche     }
8089*44704f69SBart Van Assche     return true;
8090*44704f69SBart Van Assche }
8091*44704f69SBart Van Assche 
8092*44704f69SBart Van Assche /* TAPE_ALERT_LPAGE [0x2e] <ta> */
8093*44704f69SBart Van Assche static bool
show_tape_alert_ssc_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)8094*44704f69SBart Van Assche show_tape_alert_ssc_page(const uint8_t * resp, int len,
8095*44704f69SBart Van Assche                          struct opts_t * op, sgj_opaque_p jop)
8096*44704f69SBart Van Assche {
8097*44704f69SBart Van Assche     int num, pl, pc, flag;
8098*44704f69SBart Van Assche     const uint8_t * bp;
8099*44704f69SBart Van Assche     char str[PCB_STR_LEN];
8100*44704f69SBart Van Assche 
8101*44704f69SBart Van Assche if (jop) { };
8102*44704f69SBart Van Assche     /* N.B. the Tape alert log page for smc-3 is different */
8103*44704f69SBart Van Assche     if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
8104*44704f69SBart Van Assche         printf("Tape alert page (ssc-3) [0x2e]\n");
8105*44704f69SBart Van Assche     num = len - 4;
8106*44704f69SBart Van Assche     bp = &resp[0] + 4;
8107*44704f69SBart Van Assche     while (num > 3) {
8108*44704f69SBart Van Assche         pc = sg_get_unaligned_be16(bp + 0);
8109*44704f69SBart Van Assche         pl = bp[3] + 4;
8110*44704f69SBart Van Assche         if (op->filter_given) {
8111*44704f69SBart Van Assche             if (pc != op->filter)
8112*44704f69SBart Van Assche                 goto skip;
8113*44704f69SBart Van Assche         }
8114*44704f69SBart Van Assche         if (op->do_raw) {
8115*44704f69SBart Van Assche             dStrRaw(bp, pl);
8116*44704f69SBart Van Assche             goto filter_chk;
8117*44704f69SBart Van Assche         } else if (op->do_hex) {
8118*44704f69SBart Van Assche             hex2stdout(bp, pl, op->dstrhex_no_ascii);
8119*44704f69SBart Van Assche             goto filter_chk;
8120*44704f69SBart Van Assche         }
8121*44704f69SBart Van Assche         flag = bp[4] & 1;
8122*44704f69SBart Van Assche         if (op->verbose && (0 == op->do_brief) && flag)
8123*44704f69SBart Van Assche             printf("  >>>> ");
8124*44704f69SBart Van Assche         if ((0 == op->do_brief) || op->verbose || flag) {
8125*44704f69SBart Van Assche             if (NULL == sg_lib_tapealert_strs[0])
8126*44704f69SBart Van Assche                 printf("  No string available for code 0x%x, flag: %d\n",
8127*44704f69SBart Van Assche                        pc, flag);
8128*44704f69SBart Van Assche             else if (pc <= 0x40)
8129*44704f69SBart Van Assche                 printf("  %s: %d\n", sg_lib_tapealert_strs[pc], flag);
8130*44704f69SBart Van Assche             else
8131*44704f69SBart Van Assche                 printf("  Reserved %s 0x%x, flag: %d\n", param_c, pc, flag);
8132*44704f69SBart Van Assche         }
8133*44704f69SBart Van Assche         if (op->do_pcb)
8134*44704f69SBart Van Assche             printf("        <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
8135*44704f69SBart Van Assche filter_chk:
8136*44704f69SBart Van Assche         if (op->filter_given)
8137*44704f69SBart Van Assche             break;
8138*44704f69SBart Van Assche skip:
8139*44704f69SBart Van Assche         num -= pl;
8140*44704f69SBart Van Assche         bp += pl;
8141*44704f69SBart Van Assche     }
8142*44704f69SBart Van Assche     return true;
8143*44704f69SBart Van Assche }
8144*44704f69SBart Van Assche 
8145*44704f69SBart Van Assche /* 0x37 */
8146*44704f69SBart Van Assche static bool
show_seagate_cache_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)8147*44704f69SBart Van Assche show_seagate_cache_page(const uint8_t * resp, int len,
8148*44704f69SBart Van Assche                         struct opts_t * op, sgj_opaque_p jop)
8149*44704f69SBart Van Assche {
8150*44704f69SBart Van Assche     bool skip = false;
8151*44704f69SBart Van Assche     int num, pl, pc;
8152*44704f69SBart Van Assche     int bsti = 0;
8153*44704f69SBart Van Assche     const uint8_t * bp;
8154*44704f69SBart Van Assche     char str[PCB_STR_LEN];
8155*44704f69SBart Van Assche 
8156*44704f69SBart Van Assche if (jop) { };
8157*44704f69SBart Van Assche     if (op->verbose || ((! op->do_raw) && (0 == op->do_hex))) {
8158*44704f69SBart Van Assche         if (resp[1] > 0) {
8159*44704f69SBart Van Assche             printf("Suspicious page 0x37, SPF=0 but subpage=0x%x\n", resp[1]);
8160*44704f69SBart Van Assche             if (op->verbose)
8161*44704f69SBart Van Assche                 printf("... try vendor=wdc\n");
8162*44704f69SBart Van Assche             if (op->do_brief > 0)
8163*44704f69SBart Van Assche                 return true;
8164*44704f69SBart Van Assche         } else
8165*44704f69SBart Van Assche             printf("Seagate cache page [0x37]\n");
8166*44704f69SBart Van Assche     }
8167*44704f69SBart Van Assche     num = len - 4;
8168*44704f69SBart Van Assche     bp = &resp[0] + 4;
8169*44704f69SBart Van Assche     while (num > 3) {
8170*44704f69SBart Van Assche         pc = sg_get_unaligned_be16(bp + 0);
8171*44704f69SBart Van Assche         pl = bp[3] + 4;
8172*44704f69SBart Van Assche         if (op->filter_given) {
8173*44704f69SBart Van Assche             if (pc != op->filter)
8174*44704f69SBart Van Assche                 goto skip;
8175*44704f69SBart Van Assche         }
8176*44704f69SBart Van Assche         if (op->do_raw) {
8177*44704f69SBart Van Assche             dStrRaw(bp, pl);
8178*44704f69SBart Van Assche             goto filter_chk;
8179*44704f69SBart Van Assche         } else if (op->do_hex) {
8180*44704f69SBart Van Assche             hex2stdout(bp, pl, op->dstrhex_no_ascii);
8181*44704f69SBart Van Assche             goto filter_chk;
8182*44704f69SBart Van Assche         }
8183*44704f69SBart Van Assche         switch (pc) {
8184*44704f69SBart Van Assche         case 0:
8185*44704f69SBart Van Assche             ++bsti;
8186*44704f69SBart Van Assche             if (bsti < 2)
8187*44704f69SBart Van Assche                 printf("  Blocks sent to initiator");
8188*44704f69SBart Van Assche             else
8189*44704f69SBart Van Assche                 skip = true;
8190*44704f69SBart Van Assche             break;
8191*44704f69SBart Van Assche         case 1:
8192*44704f69SBart Van Assche             printf("  Blocks received from initiator");
8193*44704f69SBart Van Assche             break;
8194*44704f69SBart Van Assche         case 2:
8195*44704f69SBart Van Assche             printf("  Blocks read from cache and sent to initiator");
8196*44704f69SBart Van Assche             break;
8197*44704f69SBart Van Assche         case 3:
8198*44704f69SBart Van Assche             printf("  Number of read and write commands whose size "
8199*44704f69SBart Van Assche                    "<= segment size");
8200*44704f69SBart Van Assche             break;
8201*44704f69SBart Van Assche         case 4:
8202*44704f69SBart Van Assche             printf("  Number of read and write commands whose size "
8203*44704f69SBart Van Assche                    "> segment size");
8204*44704f69SBart Van Assche             break;
8205*44704f69SBart Van Assche         default:
8206*44704f69SBart Van Assche             printf("  Unknown Seagate %s = 0x%x", param_c, pc);
8207*44704f69SBart Van Assche             break;
8208*44704f69SBart Van Assche         }
8209*44704f69SBart Van Assche         if (skip)
8210*44704f69SBart Van Assche             skip = false;
8211*44704f69SBart Van Assche         else {
8212*44704f69SBart Van Assche             printf(" = %" PRIu64 "", sg_get_unaligned_be(pl - 4, bp + 4));
8213*44704f69SBart Van Assche             printf("\n");
8214*44704f69SBart Van Assche             if (op->do_pcb)
8215*44704f69SBart Van Assche                 printf("        <%s>\n", get_pcb_str(bp[2], str,
8216*44704f69SBart Van Assche                        sizeof(str)));
8217*44704f69SBart Van Assche         }
8218*44704f69SBart Van Assche filter_chk:
8219*44704f69SBart Van Assche         if (op->filter_given)
8220*44704f69SBart Van Assche             break;
8221*44704f69SBart Van Assche skip:
8222*44704f69SBart Van Assche         num -= pl;
8223*44704f69SBart Van Assche         bp += pl;
8224*44704f69SBart Van Assche     }
8225*44704f69SBart Van Assche     return true;
8226*44704f69SBart Van Assche }
8227*44704f69SBart Van Assche 
8228*44704f69SBart Van Assche /* 0x37 */
8229*44704f69SBart Van Assche static bool
show_hgst_misc_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)8230*44704f69SBart Van Assche show_hgst_misc_page(const uint8_t * resp, int len, struct opts_t * op,
8231*44704f69SBart Van Assche                     sgj_opaque_p jop)
8232*44704f69SBart Van Assche {
8233*44704f69SBart Van Assche     bool valid = false;
8234*44704f69SBart Van Assche     int num, pl, pc;
8235*44704f69SBart Van Assche     const uint8_t * bp;
8236*44704f69SBart Van Assche     char str[PCB_STR_LEN];
8237*44704f69SBart Van Assche 
8238*44704f69SBart Van Assche if (jop) { };
8239*44704f69SBart Van Assche     if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
8240*44704f69SBart Van Assche         printf("HGST/WDC miscellaneous page [0x37, 0x%x]\n",
8241*44704f69SBart Van Assche                op->decod_subpg_code);
8242*44704f69SBart Van Assche     num = len - 4;
8243*44704f69SBart Van Assche     if (num < 0x30) {
8244*44704f69SBart Van Assche         printf("HGST/WDC miscellaneous page too short (%d) < 48\n", num);
8245*44704f69SBart Van Assche         return valid;
8246*44704f69SBart Van Assche     }
8247*44704f69SBart Van Assche     bp = &resp[0] + 4;
8248*44704f69SBart Van Assche     while (num > 3) {
8249*44704f69SBart Van Assche         pc = sg_get_unaligned_be16(bp + 0);
8250*44704f69SBart Van Assche         pl = bp[3] + 4;
8251*44704f69SBart Van Assche         if (op->filter_given) {
8252*44704f69SBart Van Assche             if (pc != op->filter)
8253*44704f69SBart Van Assche                 goto skip;
8254*44704f69SBart Van Assche         }
8255*44704f69SBart Van Assche         if (op->do_raw) {
8256*44704f69SBart Van Assche             dStrRaw(bp, pl);
8257*44704f69SBart Van Assche             goto filter_chk;
8258*44704f69SBart Van Assche         } else if (op->do_hex) {
8259*44704f69SBart Van Assche             hex2stdout(bp, pl, op->dstrhex_no_ascii);
8260*44704f69SBart Van Assche             goto filter_chk;
8261*44704f69SBart Van Assche         }
8262*44704f69SBart Van Assche         switch (pc) {
8263*44704f69SBart Van Assche         case 0:
8264*44704f69SBart Van Assche             valid = true;
8265*44704f69SBart Van Assche             printf("  Power on hours = %u\n", sg_get_unaligned_be32(bp + 4));
8266*44704f69SBart Van Assche             printf("  Total Bytes Read = %" PRIu64 "\n",
8267*44704f69SBart Van Assche                    sg_get_unaligned_be64(bp + 8));
8268*44704f69SBart Van Assche             printf("  Total Bytes Written = %" PRIu64 "\n",
8269*44704f69SBart Van Assche                    sg_get_unaligned_be64(bp + 16));
8270*44704f69SBart Van Assche             printf("  Max Drive Temp (Celsius) = %u\n", bp[24]);
8271*44704f69SBart Van Assche             printf("  GList Size = %u\n", sg_get_unaligned_be16(bp + 25));
8272*44704f69SBart Van Assche             printf("  Number of Information Exceptions = %u\n", bp[27]);
8273*44704f69SBart Van Assche             printf("  MED EXC = %u\n", !! (0x80 & bp[28]));
8274*44704f69SBart Van Assche             printf("  HDW EXC = %u\n", !! (0x40 & bp[28]));
8275*44704f69SBart Van Assche             printf("  Total Read Commands = %" PRIu64 "\n",
8276*44704f69SBart Van Assche                    sg_get_unaligned_be64(bp + 29));
8277*44704f69SBart Van Assche             printf("  Total Write Commands = %" PRIu64 "\n",
8278*44704f69SBart Van Assche                    sg_get_unaligned_be64(bp + 37));
8279*44704f69SBart Van Assche             printf("  Flash Correction Count = %u\n",
8280*44704f69SBart Van Assche                    sg_get_unaligned_be16(bp + 46));
8281*44704f69SBart Van Assche             break;
8282*44704f69SBart Van Assche         default:
8283*44704f69SBart Van Assche             valid = false;
8284*44704f69SBart Van Assche             printf("  Unknown HGST/WDC %s = 0x%x", param_c, pc);
8285*44704f69SBart Van Assche             break;
8286*44704f69SBart Van Assche         }
8287*44704f69SBart Van Assche         if (op->do_pcb)
8288*44704f69SBart Van Assche             printf("        <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
8289*44704f69SBart Van Assche filter_chk:
8290*44704f69SBart Van Assche         if (op->filter_given)
8291*44704f69SBart Van Assche             break;
8292*44704f69SBart Van Assche skip:
8293*44704f69SBart Van Assche         num -= pl;
8294*44704f69SBart Van Assche         bp += pl;
8295*44704f69SBart Van Assche     }
8296*44704f69SBart Van Assche     return valid;
8297*44704f69SBart Van Assche }
8298*44704f69SBart Van Assche 
8299*44704f69SBart Van Assche /* 0x3e */
8300*44704f69SBart Van Assche static bool
show_seagate_factory_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)8301*44704f69SBart Van Assche show_seagate_factory_page(const uint8_t * resp, int len,
8302*44704f69SBart Van Assche                           struct opts_t * op, sgj_opaque_p jop)
8303*44704f69SBart Van Assche {
8304*44704f69SBart Van Assche     bool valid = false;
8305*44704f69SBart Van Assche     int num, pl, pc;
8306*44704f69SBart Van Assche     const uint8_t * bp;
8307*44704f69SBart Van Assche     uint64_t ull;
8308*44704f69SBart Van Assche     char str[PCB_STR_LEN];
8309*44704f69SBart Van Assche 
8310*44704f69SBart Van Assche if (jop) { };
8311*44704f69SBart Van Assche     if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
8312*44704f69SBart Van Assche         printf("Seagate/Hitachi factory page [0x3e]\n");
8313*44704f69SBart Van Assche     num = len - 4;
8314*44704f69SBart Van Assche     bp = &resp[0] + 4;
8315*44704f69SBart Van Assche     while (num > 3) {
8316*44704f69SBart Van Assche         pc = sg_get_unaligned_be16(bp + 0);
8317*44704f69SBart Van Assche         pl = bp[3] + 4;
8318*44704f69SBart Van Assche         if (op->filter_given) {
8319*44704f69SBart Van Assche             if (pc != op->filter)
8320*44704f69SBart Van Assche                 goto skip;
8321*44704f69SBart Van Assche         }
8322*44704f69SBart Van Assche         if (op->do_raw) {
8323*44704f69SBart Van Assche             dStrRaw(bp, pl);
8324*44704f69SBart Van Assche             goto filter_chk;
8325*44704f69SBart Van Assche         } else if (op->do_hex) {
8326*44704f69SBart Van Assche             hex2stdout(bp, pl, op->dstrhex_no_ascii);
8327*44704f69SBart Van Assche             goto filter_chk;
8328*44704f69SBart Van Assche         }
8329*44704f69SBart Van Assche         valid = true;
8330*44704f69SBart Van Assche         switch (pc) {
8331*44704f69SBart Van Assche         case 0:
8332*44704f69SBart Van Assche             printf("  number of hours powered up");
8333*44704f69SBart Van Assche             break;
8334*44704f69SBart Van Assche         case 8:
8335*44704f69SBart Van Assche             printf("  number of minutes until next internal SMART test");
8336*44704f69SBart Van Assche             break;
8337*44704f69SBart Van Assche         default:
8338*44704f69SBart Van Assche             valid = false;
8339*44704f69SBart Van Assche             printf("  Unknown Seagate/Hitachi %s = 0x%x", param_c, pc);
8340*44704f69SBart Van Assche             break;
8341*44704f69SBart Van Assche         }
8342*44704f69SBart Van Assche         if (valid) {
8343*44704f69SBart Van Assche             ull = sg_get_unaligned_be(pl - 4, bp + 4);
8344*44704f69SBart Van Assche             if (0 == pc)
8345*44704f69SBart Van Assche                 printf(" = %.2f", ((double)ull) / 60.0 );
8346*44704f69SBart Van Assche             else
8347*44704f69SBart Van Assche                 printf(" = %" PRIu64 "", ull);
8348*44704f69SBart Van Assche         }
8349*44704f69SBart Van Assche         printf("\n");
8350*44704f69SBart Van Assche         if (op->do_pcb)
8351*44704f69SBart Van Assche             printf("        <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
8352*44704f69SBart Van Assche filter_chk:
8353*44704f69SBart Van Assche         if (op->filter_given)
8354*44704f69SBart Van Assche             break;
8355*44704f69SBart Van Assche skip:
8356*44704f69SBart Van Assche         num -= pl;
8357*44704f69SBart Van Assche         bp += pl;
8358*44704f69SBart Van Assche     }
8359*44704f69SBart Van Assche     return true;
8360*44704f69SBart Van Assche }
8361*44704f69SBart Van Assche 
8362*44704f69SBart Van Assche static void
decode_page_contents(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)8363*44704f69SBart Van Assche decode_page_contents(const uint8_t * resp, int len, struct opts_t * op,
8364*44704f69SBart Van Assche                      sgj_opaque_p jop)
8365*44704f69SBart Van Assche {
8366*44704f69SBart Van Assche     int pg_code, subpg_code, vpn;
8367*44704f69SBart Van Assche     bool spf;
8368*44704f69SBart Van Assche     bool done = false;
8369*44704f69SBart Van Assche     const struct log_elem * lep;
8370*44704f69SBart Van Assche 
8371*44704f69SBart Van Assche     if (len < 3) {
8372*44704f69SBart Van Assche         pr2serr("%s: response has bad length: %d\n", __func__, len);
8373*44704f69SBart Van Assche         return;
8374*44704f69SBart Van Assche     }
8375*44704f69SBart Van Assche     spf = !!(resp[0] & 0x40);
8376*44704f69SBart Van Assche     pg_code = resp[0] & 0x3f;
8377*44704f69SBart Van Assche     if ((VP_HITA == op->vend_prod_num) && (pg_code >= 0x30))
8378*44704f69SBart Van Assche         subpg_code = resp[1];   /* Hitachi don't set SPF on VS pages */
8379*44704f69SBart Van Assche     else
8380*44704f69SBart Van Assche         subpg_code = spf ? resp[1] : NOT_SPG_SUBPG;
8381*44704f69SBart Van Assche     op->decod_subpg_code = subpg_code;
8382*44704f69SBart Van Assche     if ((SUPP_SPGS_SUBPG == subpg_code) && (SUPP_PAGES_LPAGE != pg_code)) {
8383*44704f69SBart Van Assche         done = show_supported_pgs_sub_page(resp, len, op, jop);
8384*44704f69SBart Van Assche         if (done)
8385*44704f69SBart Van Assche             return;
8386*44704f69SBart Van Assche     }
8387*44704f69SBart Van Assche     vpn = (op->vend_prod_num >= 0) ? op->vend_prod_num : op->deduced_vpn;
8388*44704f69SBart Van Assche     lep = pg_subpg_pdt_search(pg_code, subpg_code, op->dev_pdt, vpn);
8389*44704f69SBart Van Assche 
8390*44704f69SBart Van Assche     /* Below is the indirect function call to all the show_* functions */
8391*44704f69SBart Van Assche     if (lep && lep->show_pagep)
8392*44704f69SBart Van Assche         done = (*lep->show_pagep)(resp, len, op, jop);
8393*44704f69SBart Van Assche 
8394*44704f69SBart Van Assche     if (! done) {
8395*44704f69SBart Van Assche         if (0 == op->do_hex) {
8396*44704f69SBart Van Assche             static const char * unable_s = "Unable to decode page = 0x";
8397*44704f69SBart Van Assche 
8398*44704f69SBart Van Assche             if (subpg_code > 0)
8399*44704f69SBart Van Assche                 printf("%s%x, subpage = 0x%x, here is hex:\n", unable_s,
8400*44704f69SBart Van Assche                        pg_code, subpg_code);
8401*44704f69SBart Van Assche             else
8402*44704f69SBart Van Assche                 printf("%s%x, here is hex:\n", unable_s, pg_code);
8403*44704f69SBart Van Assche         }
8404*44704f69SBart Van Assche         if ((len > 128) && (0 == op->do_hex)) {
8405*44704f69SBart Van Assche             hex2fp(resp, 64, "  ", op->hex2str_oformat, stdout);
8406*44704f69SBart Van Assche             printf("  .....  [truncated after 64 of %d bytes (use '-H' to "
8407*44704f69SBart Van Assche                    "see the rest)]\n", len);
8408*44704f69SBart Van Assche         } else {
8409*44704f69SBart Van Assche             if (0 == op->do_hex)
8410*44704f69SBart Van Assche                 hex2fp(resp, len, "  ", op->hex2str_oformat, stdout);
8411*44704f69SBart Van Assche             else
8412*44704f69SBart Van Assche                 hex2stdout(resp, len, op->dstrhex_no_ascii);
8413*44704f69SBart Van Assche         }
8414*44704f69SBart Van Assche     }
8415*44704f69SBart Van Assche }
8416*44704f69SBart Van Assche 
8417*44704f69SBart Van Assche /* Tries to fetch the TEMPERATURE_LPAGE [0xd] page first. If that fails
8418*44704f69SBart Van Assche  * tries to get the Informational Exceptions (IE_LPAGE) page. */
8419*44704f69SBart Van Assche static int
fetchTemperature(int sg_fd,uint8_t * resp,int max_len,struct opts_t * op,sgj_opaque_p jop)8420*44704f69SBart Van Assche fetchTemperature(int sg_fd, uint8_t * resp, int max_len, struct opts_t * op,
8421*44704f69SBart Van Assche                  sgj_opaque_p jop)
8422*44704f69SBart Van Assche {
8423*44704f69SBart Van Assche     int len;
8424*44704f69SBart Van Assche     int res = 0;
8425*44704f69SBart Van Assche 
8426*44704f69SBart Van Assche     op->pg_code = TEMPERATURE_LPAGE;
8427*44704f69SBart Van Assche     op->subpg_code = NOT_SPG_SUBPG;
8428*44704f69SBart Van Assche     res = do_logs(sg_fd, resp, max_len, op);
8429*44704f69SBart Van Assche     if (0 == res) {
8430*44704f69SBart Van Assche         len = sg_get_unaligned_be16(resp + 2) + 4;
8431*44704f69SBart Van Assche         if (op->do_raw)
8432*44704f69SBart Van Assche             dStrRaw(resp, len);
8433*44704f69SBart Van Assche         else if (op->do_hex)
8434*44704f69SBart Van Assche             hex2stdout(resp, len, op->dstrhex_no_ascii);
8435*44704f69SBart Van Assche         else
8436*44704f69SBart Van Assche             show_temperature_page(resp, len, op, jop);
8437*44704f69SBart Van Assche     } else if (SG_LIB_CAT_NOT_READY == res)
8438*44704f69SBart Van Assche         pr2serr("Device not ready\n");
8439*44704f69SBart Van Assche     else {
8440*44704f69SBart Van Assche         op->pg_code = IE_LPAGE;
8441*44704f69SBart Van Assche         res = do_logs(sg_fd, resp, max_len, op);
8442*44704f69SBart Van Assche         if (0 == res) {
8443*44704f69SBart Van Assche             len = sg_get_unaligned_be16(resp + 2) + 4;
8444*44704f69SBart Van Assche             if (op->do_raw)
8445*44704f69SBart Van Assche                 dStrRaw(resp, len);
8446*44704f69SBart Van Assche             else if (op->do_hex)
8447*44704f69SBart Van Assche                 hex2stdout(resp, len, op->dstrhex_no_ascii);
8448*44704f69SBart Van Assche             else
8449*44704f69SBart Van Assche                 show_ie_page(resp, len, op, jop);
8450*44704f69SBart Van Assche         } else
8451*44704f69SBart Van Assche             pr2serr("Unable to find temperature in either Temperature or "
8452*44704f69SBart Van Assche                     "IE log page\n");
8453*44704f69SBart Van Assche     }
8454*44704f69SBart Van Assche     sg_cmds_close_device(sg_fd);
8455*44704f69SBart Van Assche     return (res >= 0) ? res : SG_LIB_CAT_OTHER;
8456*44704f69SBart Van Assche }
8457*44704f69SBart Van Assche 
8458*44704f69SBart Van Assche /* Returns 0 if successful else SG_LIB_SYNTAX_ERROR. */
8459*44704f69SBart Van Assche static int
decode_pg_arg(struct opts_t * op)8460*44704f69SBart Van Assche decode_pg_arg(struct opts_t * op)
8461*44704f69SBart Van Assche {
8462*44704f69SBart Van Assche     int nn;
8463*44704f69SBart Van Assche     const struct log_elem * lep;
8464*44704f69SBart Van Assche     char * cp;
8465*44704f69SBart Van Assche 
8466*44704f69SBart Van Assche     if (isalpha((uint8_t)op->pg_arg[0])) {
8467*44704f69SBart Van Assche         char b[80];
8468*44704f69SBart Van Assche 
8469*44704f69SBart Van Assche         if (strlen(op->pg_arg) >= (sizeof(b) - 1)) {
8470*44704f69SBart Van Assche             pr2serr("argument to '--page=' is too long\n");
8471*44704f69SBart Van Assche             return SG_LIB_SYNTAX_ERROR;
8472*44704f69SBart Van Assche         }
8473*44704f69SBart Van Assche         strcpy(b, op->pg_arg);
8474*44704f69SBart Van Assche         cp = (char *)strchr(b, ',');
8475*44704f69SBart Van Assche         if (cp)
8476*44704f69SBart Van Assche             *cp = '\0';
8477*44704f69SBart Van Assche         lep = acron_search(b);
8478*44704f69SBart Van Assche         if (NULL == lep) {
8479*44704f69SBart Van Assche             pr2serr("bad argument to '--page=' no acronyn match to "
8480*44704f69SBart Van Assche                     "'%s'\n", b);
8481*44704f69SBart Van Assche             pr2serr("  Try using '-e' or'-ee' to see available "
8482*44704f69SBart Van Assche                     "acronyns\n");
8483*44704f69SBart Van Assche             return SG_LIB_SYNTAX_ERROR;
8484*44704f69SBart Van Assche         }
8485*44704f69SBart Van Assche         op->lep = lep;
8486*44704f69SBart Van Assche         op->pg_code = lep->pg_code;
8487*44704f69SBart Van Assche         if (cp) {
8488*44704f69SBart Van Assche             nn = sg_get_num_nomult(cp + 1);
8489*44704f69SBart Van Assche             if ((nn < 0) || (nn > 255)) {
8490*44704f69SBart Van Assche                 pr2serr("Bad second value in argument to "
8491*44704f69SBart Van Assche                         "'--page='\n");
8492*44704f69SBart Van Assche                 return SG_LIB_SYNTAX_ERROR;
8493*44704f69SBart Van Assche             }
8494*44704f69SBart Van Assche             op->subpg_code = nn;
8495*44704f69SBart Van Assche         } else
8496*44704f69SBart Van Assche             op->subpg_code = lep->subpg_code;
8497*44704f69SBart Van Assche     } else { /* numeric arg: either 'pg_num' or 'pg_num,subpg_num' */
8498*44704f69SBart Van Assche         int n;
8499*44704f69SBart Van Assche 
8500*44704f69SBart Van Assche         cp = (char *)strchr(op->pg_arg, ',');
8501*44704f69SBart Van Assche         n = sg_get_num_nomult(op->pg_arg);
8502*44704f69SBart Van Assche         if ((n < 0) || (n > 63)) {
8503*44704f69SBart Van Assche             pr2serr("Bad argument to '--page='\n");
8504*44704f69SBart Van Assche             usage(1);
8505*44704f69SBart Van Assche             return SG_LIB_SYNTAX_ERROR;
8506*44704f69SBart Van Assche         }
8507*44704f69SBart Van Assche         if (cp) {
8508*44704f69SBart Van Assche             nn = sg_get_num_nomult(cp + 1);
8509*44704f69SBart Van Assche             if ((nn < 0) || (nn > 255)) {
8510*44704f69SBart Van Assche                 pr2serr("Bad second value in argument to "
8511*44704f69SBart Van Assche                         "'--page='\n");
8512*44704f69SBart Van Assche                 usage(1);
8513*44704f69SBart Van Assche                 return SG_LIB_SYNTAX_ERROR;
8514*44704f69SBart Van Assche             }
8515*44704f69SBart Van Assche         } else
8516*44704f69SBart Van Assche             nn = 0;
8517*44704f69SBart Van Assche         op->pg_code = n;
8518*44704f69SBart Van Assche         op->subpg_code = nn;
8519*44704f69SBart Van Assche     }
8520*44704f69SBart Van Assche     return 0;
8521*44704f69SBart Van Assche }
8522*44704f69SBart Van Assche 
8523*44704f69SBart Van Assche /* Since the Supported subpages page is sitting in the rsp_buff which is
8524*44704f69SBart Van Assche  * MX_ALLOC_LEN bytes long (~ 64 KB) then move it (from rsp_buff+0 to
8525*44704f69SBart Van Assche  * rsp_buff+pg_len-1) to the top end of that buffer. Then there is room
8526*44704f69SBart Van Assche  * to merge supp_pgs_rsp with the supported subpages with the result back
8527*44704f69SBart Van Assche  * at the bottom of rsp_buff. The new length of the merged subpages page
8528*44704f69SBart Van Assche  * (excluding its 4 byte header) is returned.
8529*44704f69SBart Van Assche  * Assumes both pages are in ascending order (as required by SPC-4). */
8530*44704f69SBart Van Assche static int
merge_both_supported(const uint8_t * supp_pgs_p,int su_p_pg_len,int pg_len)8531*44704f69SBart Van Assche merge_both_supported(const uint8_t * supp_pgs_p, int su_p_pg_len, int pg_len)
8532*44704f69SBart Van Assche {
8533*44704f69SBart Van Assche     uint8_t pg;
8534*44704f69SBart Van Assche     int k, kp, ks;
8535*44704f69SBart Van Assche     int max_blen = (2 * su_p_pg_len) + pg_len;
8536*44704f69SBart Van Assche     uint8_t * m_buff = rsp_buff + (rsp_buff_sz - pg_len);
8537*44704f69SBart Van Assche     uint8_t * r_buff = rsp_buff + 4;
8538*44704f69SBart Van Assche 
8539*44704f69SBart Van Assche     if (pg_len > 0)
8540*44704f69SBart Van Assche         memmove(m_buff, rsp_buff + 4, pg_len);
8541*44704f69SBart Van Assche     for (k = 0, kp = 0, ks = 0; k < max_blen; k += 2) {
8542*44704f69SBart Van Assche         if (kp < su_p_pg_len)
8543*44704f69SBart Van Assche             pg = supp_pgs_p[kp];
8544*44704f69SBart Van Assche         else
8545*44704f69SBart Van Assche             pg = 0xff;
8546*44704f69SBart Van Assche         if (ks < pg_len) {
8547*44704f69SBart Van Assche             if (m_buff[ks] < pg) {
8548*44704f69SBart Van Assche                 r_buff[k] = m_buff[ks];
8549*44704f69SBart Van Assche                 r_buff[k + 1] = m_buff[ks + 1];
8550*44704f69SBart Van Assche                 ks += 2;
8551*44704f69SBart Van Assche             } else if ((m_buff[ks] == pg) && (m_buff[ks + 1] == 0)) {
8552*44704f69SBart Van Assche                 r_buff[k] = m_buff[ks];
8553*44704f69SBart Van Assche                 r_buff[k + 1] = m_buff[ks + 1];
8554*44704f69SBart Van Assche                 ks += 2;
8555*44704f69SBart Van Assche                 ++kp;
8556*44704f69SBart Van Assche             } else {
8557*44704f69SBart Van Assche                 r_buff[k] = pg;
8558*44704f69SBart Van Assche                 r_buff[k + 1] = 0;
8559*44704f69SBart Van Assche                 ++kp;
8560*44704f69SBart Van Assche             }
8561*44704f69SBart Van Assche         } else {
8562*44704f69SBart Van Assche             if (0xff == pg)
8563*44704f69SBart Van Assche                 break;
8564*44704f69SBart Van Assche             r_buff[k] = pg;
8565*44704f69SBart Van Assche             r_buff[k + 1] = 0;
8566*44704f69SBart Van Assche             ++kp;
8567*44704f69SBart Van Assche         }
8568*44704f69SBart Van Assche     }
8569*44704f69SBart Van Assche     sg_put_unaligned_be16(k, rsp_buff + 2);
8570*44704f69SBart Van Assche     return k;
8571*44704f69SBart Van Assche }
8572*44704f69SBart Van Assche 
8573*44704f69SBart Van Assche 
8574*44704f69SBart Van Assche int
main(int argc,char * argv[])8575*44704f69SBart Van Assche main(int argc, char * argv[])
8576*44704f69SBart Van Assche {
8577*44704f69SBart Van Assche     bool as_json;
8578*44704f69SBart Van Assche     int k, nn, pg_len, res, vb;
8579*44704f69SBart Van Assche     int resp_len = 0;
8580*44704f69SBart Van Assche     int su_p_pg_len = 0;
8581*44704f69SBart Van Assche     int in_len = -1;
8582*44704f69SBart Van Assche     int sg_fd = -1;
8583*44704f69SBart Van Assche     int ret = 0;
8584*44704f69SBart Van Assche     uint8_t * parr;
8585*44704f69SBart Van Assche     uint8_t * free_parr = NULL;
8586*44704f69SBart Van Assche     struct opts_t * op;
8587*44704f69SBart Van Assche     sgj_state * jsp;
8588*44704f69SBart Van Assche     sgj_opaque_p jop = NULL;
8589*44704f69SBart Van Assche     struct sg_simple_inquiry_resp inq_out;
8590*44704f69SBart Van Assche     struct opts_t opts SG_C_CPP_ZERO_INIT;
8591*44704f69SBart Van Assche     uint8_t supp_pgs_rsp[256];
8592*44704f69SBart Van Assche     char b[128];
8593*44704f69SBart Van Assche     static const int blen = sizeof(b);
8594*44704f69SBart Van Assche 
8595*44704f69SBart Van Assche     op = &opts;
8596*44704f69SBart Van Assche     /* N.B. some disks only give data for current cumulative */
8597*44704f69SBart Van Assche     op->page_control = 1;
8598*44704f69SBart Van Assche     op->dev_pdt = -1;
8599*44704f69SBart Van Assche     op->vend_prod_num = VP_NONE;
8600*44704f69SBart Van Assche     op->deduced_vpn = VP_NONE;
8601*44704f69SBart Van Assche     res = parse_cmd_line(op, argc, argv);
8602*44704f69SBart Van Assche     if (res)
8603*44704f69SBart Van Assche         return SG_LIB_SYNTAX_ERROR;
8604*44704f69SBart Van Assche     if (op->do_help) {
8605*44704f69SBart Van Assche         usage_for(op->do_help, op);
8606*44704f69SBart Van Assche         return 0;
8607*44704f69SBart Van Assche     }
8608*44704f69SBart Van Assche     jsp = &op->json_st;
8609*44704f69SBart Van Assche     as_json = jsp->pr_as_json;
8610*44704f69SBart Van Assche     if (as_json) {
8611*44704f69SBart Van Assche         if (op->do_name) {
8612*44704f69SBart Van Assche             pr2serr(">>> The --json option is superior to the --name "
8613*44704f69SBart Van Assche                     "option.\n");
8614*44704f69SBart Van Assche             pr2serr(">>> Ignoring the --name option.\n");
8615*44704f69SBart Van Assche             op->do_name = false;
8616*44704f69SBart Van Assche         }
8617*44704f69SBart Van Assche         jop = sgj_start_r(MY_NAME, version_str, argc, argv, jsp);
8618*44704f69SBart Van Assche     }
8619*44704f69SBart Van Assche #ifdef DEBUG
8620*44704f69SBart Van Assche     pr2serr("In DEBUG mode, ");
8621*44704f69SBart Van Assche     if (op->verbose_given && op->version_given) {
8622*44704f69SBart Van Assche         pr2serr("but override: '-vV' given, zero verbose and continue\n");
8623*44704f69SBart Van Assche         op->verbose_given = false;
8624*44704f69SBart Van Assche         op->version_given = false;
8625*44704f69SBart Van Assche         op->verbose = 0;
8626*44704f69SBart Van Assche     } else if (! op->verbose_given) {
8627*44704f69SBart Van Assche         pr2serr("set '-vv'\n");
8628*44704f69SBart Van Assche         op->verbose = 2;
8629*44704f69SBart Van Assche     } else
8630*44704f69SBart Van Assche         pr2serr("keep verbose=%d\n", op->verbose);
8631*44704f69SBart Van Assche #else
8632*44704f69SBart Van Assche     if (op->verbose_given && op->version_given)
8633*44704f69SBart Van Assche         pr2serr("Not in DEBUG mode, so '-vV' has no special action\n");
8634*44704f69SBart Van Assche #endif
8635*44704f69SBart Van Assche     if (op->version_given) {
8636*44704f69SBart Van Assche         pr2serr("Version string: %s\n", version_str);
8637*44704f69SBart Van Assche         return 0;
8638*44704f69SBart Van Assche     }
8639*44704f69SBart Van Assche     if (op->do_hex > 0) {
8640*44704f69SBart Van Assche         if (op->do_hex > 2) {
8641*44704f69SBart Van Assche             op->dstrhex_no_ascii = -1;
8642*44704f69SBart Van Assche             op->hex2str_oformat = 1;
8643*44704f69SBart Van Assche         } else {
8644*44704f69SBart Van Assche             op->dstrhex_no_ascii = (1 == op->do_hex);
8645*44704f69SBart Van Assche             op->hex2str_oformat = (1 == op->do_hex);
8646*44704f69SBart Van Assche         }
8647*44704f69SBart Van Assche     } else {
8648*44704f69SBart Van Assche         if (op->undefined_hex > 0) {
8649*44704f69SBart Van Assche             if (op->undefined_hex > 2) {
8650*44704f69SBart Van Assche                 op->dstrhex_no_ascii = -1;
8651*44704f69SBart Van Assche                 op->hex2str_oformat = 1;
8652*44704f69SBart Van Assche             } else {
8653*44704f69SBart Van Assche                 op->dstrhex_no_ascii = (1 == op->undefined_hex);
8654*44704f69SBart Van Assche                 op->hex2str_oformat = (1 == op->undefined_hex);
8655*44704f69SBart Van Assche             }
8656*44704f69SBart Van Assche         } else {       /* default when no --hex nor --undefined */
8657*44704f69SBart Van Assche             op->dstrhex_no_ascii = -1;
8658*44704f69SBart Van Assche             op->hex2str_oformat = 1;
8659*44704f69SBart Van Assche         }
8660*44704f69SBart Van Assche     }
8661*44704f69SBart Van Assche     vb = op->verbose;
8662*44704f69SBart Van Assche     if (op->vend_prod) {
8663*44704f69SBart Van Assche         if (0 == memcmp("-1", op->vend_prod,3))
8664*44704f69SBart Van Assche             k = VP_NONE;
8665*44704f69SBart Van Assche         else if (isdigit((uint8_t)op->vend_prod[0]))
8666*44704f69SBart Van Assche             k = sg_get_num_nomult(op->vend_prod);
8667*44704f69SBart Van Assche         else
8668*44704f69SBart Van Assche             k = find_vpn_by_acron(op->vend_prod);
8669*44704f69SBart Van Assche         op->vend_prod_num = k;
8670*44704f69SBart Van Assche         if (VP_ALL == k)
8671*44704f69SBart Van Assche             ;
8672*44704f69SBart Van Assche         else if ((k < 0) || (k > (32 - MVP_OFFSET))) {
8673*44704f69SBart Van Assche             pr2serr("Bad vendor/product acronym after '--vendor=' "
8674*44704f69SBart Van Assche                     " ('-M ') option\n");
8675*44704f69SBart Van Assche             enumerate_vp();
8676*44704f69SBart Van Assche             return SG_LIB_SYNTAX_ERROR;
8677*44704f69SBart Van Assche         }
8678*44704f69SBart Van Assche     }
8679*44704f69SBart Van Assche     if (op->do_enumerate > 0) {
8680*44704f69SBart Van Assche         if (op->device_name && vb)
8681*44704f69SBart Van Assche             pr2serr("Warning: device: %s is being ignored\n",
8682*44704f69SBart Van Assche                     op->device_name);
8683*44704f69SBart Van Assche         enumerate_pages(op);
8684*44704f69SBart Van Assche         return 0;
8685*44704f69SBart Van Assche     }
8686*44704f69SBart Van Assche     if (op->in_fn) {
8687*44704f69SBart Van Assche         if (op->maxlen_given) {
8688*44704f69SBart Van Assche             if (op->maxlen > MX_INLEN_ALLOC_LEN) {
8689*44704f69SBart Van Assche                 pr2serr("bad argument to '--maxlen=' when --in= given, from "
8690*44704f69SBart Van Assche                         "2 to %d (inclusive) expected\n", MX_INLEN_ALLOC_LEN);
8691*44704f69SBart Van Assche                 return SG_LIB_SYNTAX_ERROR;
8692*44704f69SBart Van Assche             }
8693*44704f69SBart Van Assche             rsp_buff_sz = op->maxlen;
8694*44704f69SBart Van Assche         } else
8695*44704f69SBart Van Assche             rsp_buff_sz = DEF_INLEN_ALLOC_LEN;
8696*44704f69SBart Van Assche     } else {
8697*44704f69SBart Van Assche         if (op->maxlen_given) {
8698*44704f69SBart Van Assche             if (op->maxlen > MX_ALLOC_LEN) {
8699*44704f69SBart Van Assche                 pr2serr("bad argument to '--maxlen=', from 2 to 65535 "
8700*44704f69SBart Van Assche                         "(inclusive) expected\n");
8701*44704f69SBart Van Assche                 return SG_LIB_SYNTAX_ERROR;
8702*44704f69SBart Van Assche             }
8703*44704f69SBart Van Assche             rsp_buff_sz = op->maxlen;
8704*44704f69SBart Van Assche         }
8705*44704f69SBart Van Assche     }
8706*44704f69SBart Van Assche     rsp_buff = sg_memalign(rsp_buff_sz, 0 /* page aligned */, &free_rsp_buff,
8707*44704f69SBart Van Assche                            false);
8708*44704f69SBart Van Assche     if (NULL == rsp_buff) {
8709*44704f69SBart Van Assche         pr2serr("Unable to allocate %d bytes on the heap\n", rsp_buff_sz);
8710*44704f69SBart Van Assche         ret = sg_convert_errno(ENOMEM);
8711*44704f69SBart Van Assche         goto err_out;
8712*44704f69SBart Van Assche     }
8713*44704f69SBart Van Assche     if (NULL == op->device_name) {
8714*44704f69SBart Van Assche         if (op->in_fn) {
8715*44704f69SBart Van Assche             bool found = false;
8716*44704f69SBart Van Assche             bool r_spf = false;
8717*44704f69SBart Van Assche             uint16_t u;
8718*44704f69SBart Van Assche             int pg_code, subpg_code, pdt, n;
8719*44704f69SBart Van Assche             const struct log_elem * lep;
8720*44704f69SBart Van Assche             const uint8_t * bp;
8721*44704f69SBart Van Assche 
8722*44704f69SBart Van Assche             if ((ret = sg_f2hex_arr(op->in_fn, op->do_raw, false, rsp_buff,
8723*44704f69SBart Van Assche                                     &in_len, rsp_buff_sz)))
8724*44704f69SBart Van Assche                 goto err_out;
8725*44704f69SBart Van Assche             if (vb > 2)
8726*44704f69SBart Van Assche                 pr2serr("Read %d [0x%x] bytes of user supplied data\n",
8727*44704f69SBart Van Assche                         in_len, in_len);
8728*44704f69SBart Van Assche             if (op->do_raw)
8729*44704f69SBart Van Assche                 op->do_raw = false;    /* can interfere on decode */
8730*44704f69SBart Van Assche             if (in_len < 4) {
8731*44704f69SBart Van Assche                 pr2serr("--in=%s only decoded %d bytes (needs 4 at least)\n",
8732*44704f69SBart Van Assche                         op->in_fn, in_len);
8733*44704f69SBart Van Assche                 ret = SG_LIB_SYNTAX_ERROR;
8734*44704f69SBart Van Assche                 goto err_out;
8735*44704f69SBart Van Assche             }
8736*44704f69SBart Van Assche             if (op->pg_arg) {
8737*44704f69SBart Van Assche                 char b[144];
8738*44704f69SBart Van Assche                 char * cp;
8739*44704f69SBart Van Assche 
8740*44704f69SBart Van Assche                 strcpy(b, op->pg_arg);
8741*44704f69SBart Van Assche                 cp = (char *)strchr(b, ',');
8742*44704f69SBart Van Assche                 if (cp)
8743*44704f69SBart Van Assche                     *cp = '\0';
8744*44704f69SBart Van Assche                 lep = acron_search(b);
8745*44704f69SBart Van Assche                 if (NULL == lep) {
8746*44704f69SBart Van Assche                     pr2serr("bad argument to '--page=' no acronyn match to "
8747*44704f69SBart Van Assche                             "'%s'\n", b);
8748*44704f69SBart Van Assche                     pr2serr("  Try using '-e' or'-ee' to see available "
8749*44704f69SBart Van Assche                             "acronyns\n");
8750*44704f69SBart Van Assche                     return SG_LIB_SYNTAX_ERROR;
8751*44704f69SBart Van Assche                 }
8752*44704f69SBart Van Assche                 op->lep = lep;
8753*44704f69SBart Van Assche                 op->pg_code = lep->pg_code;
8754*44704f69SBart Van Assche                 op->subpg_code = lep->subpg_code;
8755*44704f69SBart Van Assche                 if (op->subpg_code > 0)
8756*44704f69SBart Van Assche                     r_spf = true;
8757*44704f69SBart Van Assche             }
8758*44704f69SBart Van Assche 
8759*44704f69SBart Van Assche             for (bp = rsp_buff, k = 0; k < in_len; bp += n, k += n) {
8760*44704f69SBart Van Assche                 bool spf = !! (bp[0] & 0x40);
8761*44704f69SBart Van Assche 
8762*44704f69SBart Van Assche                 pg_code = bp[0] & 0x3f;
8763*44704f69SBart Van Assche                 subpg_code = spf ? bp[1] : NOT_SPG_SUBPG;
8764*44704f69SBart Van Assche                 u = sg_get_unaligned_be16(bp + 2);
8765*44704f69SBart Van Assche                 n = u + 4;
8766*44704f69SBart Van Assche                 if (n > (in_len - k)) {
8767*44704f69SBart Van Assche                     pr2serr("bytes decoded remaining (%d) less than lpage "
8768*44704f69SBart Van Assche                             "length (%d), try decoding anyway\n", in_len - k,
8769*44704f69SBart Van Assche                             n);
8770*44704f69SBart Van Assche                     n = in_len - k;
8771*44704f69SBart Van Assche                 }
8772*44704f69SBart Van Assche                 if (op->pg_arg) {
8773*44704f69SBart Van Assche                     if ((NOT_SPG_SUBPG == op->subpg_code) && spf) {
8774*44704f69SBart Van Assche                         continue;
8775*44704f69SBart Van Assche                     } else if ((! spf) && (! r_spf)) {
8776*44704f69SBart Van Assche                         if (pg_code != op->pg_code)
8777*44704f69SBart Van Assche                             continue;
8778*44704f69SBart Van Assche                     } else if ((SUPP_SPGS_SUBPG == op->subpg_code) &&
8779*44704f69SBart Van Assche                              (SUPP_PAGES_LPAGE != op->pg_code)) {
8780*44704f69SBart Van Assche                         if (pg_code != op->pg_code)
8781*44704f69SBart Van Assche                             continue;
8782*44704f69SBart Van Assche                     } else if ((SUPP_SPGS_SUBPG != op->subpg_code) &&
8783*44704f69SBart Van Assche                                (SUPP_PAGES_LPAGE == op->pg_code)) {
8784*44704f69SBart Van Assche                         if (subpg_code != op->subpg_code)
8785*44704f69SBart Van Assche                             continue;
8786*44704f69SBart Van Assche                     } else if ((SUPP_SPGS_SUBPG != op->subpg_code) &&
8787*44704f69SBart Van Assche                                (SUPP_PAGES_LPAGE != op->pg_code)) {
8788*44704f69SBart Van Assche                         if ((pg_code != op->pg_code) ||
8789*44704f69SBart Van Assche                             (subpg_code != op->subpg_code))
8790*44704f69SBart Van Assche                             continue;
8791*44704f69SBart Van Assche                     }
8792*44704f69SBart Van Assche                 }
8793*44704f69SBart Van Assche                 if (op->exclude_vendor && (pg_code >= 0x30))
8794*44704f69SBart Van Assche                     continue;
8795*44704f69SBart Van Assche                 found = true;
8796*44704f69SBart Van Assche                 if (op->do_hex > 2) {
8797*44704f69SBart Van Assche                      hex2fp(bp, n, NULL, op->hex2str_oformat, stdout);
8798*44704f69SBart Van Assche                      continue;
8799*44704f69SBart Van Assche                 }
8800*44704f69SBart Van Assche                 pdt = op->dev_pdt;
8801*44704f69SBart Van Assche                 lep = pg_subpg_pdt_search(pg_code, subpg_code, pdt,
8802*44704f69SBart Van Assche                                           op->vend_prod_num);
8803*44704f69SBart Van Assche                 if (lep) {
8804*44704f69SBart Van Assche                     /* Below is the indirect function call to all the
8805*44704f69SBart Van Assche                      * show_* functions */
8806*44704f69SBart Van Assche                     if (lep->show_pagep)
8807*44704f69SBart Van Assche                         (*lep->show_pagep)(bp, n, op, jop);
8808*44704f69SBart Van Assche                     else
8809*44704f69SBart Van Assche                         sgj_pr_hr(jsp, "Unable to decode %s [%s]\n",
8810*44704f69SBart Van Assche                                   lep->name, lep->acron);
8811*44704f69SBart Van Assche                 } else {
8812*44704f69SBart Van Assche                     nn = sg_scnpr(b, blen, "Unable to decode page=0x%x",
8813*44704f69SBart Van Assche                                   pg_code);
8814*44704f69SBart Van Assche                     if (subpg_code > 0)
8815*44704f69SBart Van Assche                         sg_scnpr(b + nn, blen - nn, ", subpage=0x%x",
8816*44704f69SBart Van Assche                                  subpg_code);
8817*44704f69SBart Van Assche                     if (pdt >= 0)
8818*44704f69SBart Van Assche                         sg_scnpr(b + nn, blen - nn, ", pdt=0x%x\n", pdt);
8819*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "%s\n", b);
8820*44704f69SBart Van Assche                 }
8821*44704f69SBart Van Assche             }           /* end of page/subpage search loop */
8822*44704f69SBart Van Assche             if (op->pg_arg && (! found)) {
8823*44704f69SBart Van Assche                 nn = sg_scnpr(b, blen, "Unable to find page=0x%x",
8824*44704f69SBart Van Assche                               op->pg_code);
8825*44704f69SBart Van Assche                 if (op->subpg_code > 0)
8826*44704f69SBart Van Assche                     sg_scnpr(b + nn, blen - nn, ", subpage=0x%x",
8827*44704f69SBart Van Assche                              op->subpg_code);
8828*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "%s\n", b);
8829*44704f69SBart Van Assche                 if (jsp->pr_as_json)
8830*44704f69SBart Van Assche                     sgj_js_nv_i(jsp, jop, "page_not_found", 1);
8831*44704f69SBart Van Assche             }
8832*44704f69SBart Van Assche             ret = 0;
8833*44704f69SBart Van Assche             goto err_out;
8834*44704f69SBart Van Assche         }
8835*44704f69SBart Van Assche         if (op->pg_arg) {         /* do this for 'sg_logs -p xxx' */
8836*44704f69SBart Van Assche             ret = decode_pg_arg(op);
8837*44704f69SBart Van Assche             if (ret)
8838*44704f69SBart Van Assche                 goto err_out;
8839*44704f69SBart Van Assche         }
8840*44704f69SBart Van Assche         pr2serr("No DEVICE argument given\n\n");
8841*44704f69SBart Van Assche         usage_for(1, op);
8842*44704f69SBart Van Assche         ret = SG_LIB_FILE_ERROR;
8843*44704f69SBart Van Assche         goto err_out;
8844*44704f69SBart Van Assche     }
8845*44704f69SBart Van Assche     if (op->do_select) {
8846*44704f69SBart Van Assche         if (op->do_temperature) {
8847*44704f69SBart Van Assche             pr2serr("--select cannot be used with --temperature\n");
8848*44704f69SBart Van Assche             ret = SG_LIB_CONTRADICT;
8849*44704f69SBart Van Assche             goto err_out;
8850*44704f69SBart Van Assche         }
8851*44704f69SBart Van Assche         if (op->do_transport) {
8852*44704f69SBart Van Assche             pr2serr("--select cannot be used with --transport\n");
8853*44704f69SBart Van Assche             ret = SG_LIB_CONTRADICT;
8854*44704f69SBart Van Assche             goto err_out;
8855*44704f69SBart Van Assche         }
8856*44704f69SBart Van Assche     } else if (op->do_raw) {
8857*44704f69SBart Van Assche         if (sg_set_binary_mode(STDOUT_FILENO) < 0) {
8858*44704f69SBart Van Assche             perror("sg_set_binary_mode");
8859*44704f69SBart Van Assche             ret = SG_LIB_FILE_ERROR;
8860*44704f69SBart Van Assche             goto err_out;
8861*44704f69SBart Van Assche         }
8862*44704f69SBart Van Assche     }
8863*44704f69SBart Van Assche     if (op->do_all) {
8864*44704f69SBart Van Assche         if (op->do_select) {
8865*44704f69SBart Van Assche             pr2serr("--all conflicts with --select\n");
8866*44704f69SBart Van Assche             ret = SG_LIB_CONTRADICT;
8867*44704f69SBart Van Assche             goto err_out;
8868*44704f69SBart Van Assche         }
8869*44704f69SBart Van Assche     }
8870*44704f69SBart Van Assche     if (op->in_fn) {
8871*44704f69SBart Van Assche         if (! op->do_select) {
8872*44704f69SBart Van Assche             pr2serr("--in=FN can only be used with --select when DEVICE "
8873*44704f69SBart Van Assche                     "given\n");
8874*44704f69SBart Van Assche             ret = SG_LIB_CONTRADICT;
8875*44704f69SBart Van Assche             goto err_out;
8876*44704f69SBart Van Assche         }
8877*44704f69SBart Van Assche         if ((ret = sg_f2hex_arr(op->in_fn, op->do_raw, false, rsp_buff,
8878*44704f69SBart Van Assche                                 &in_len, rsp_buff_sz)))
8879*44704f69SBart Van Assche             goto err_out;
8880*44704f69SBart Van Assche         if (vb > 2)
8881*44704f69SBart Van Assche             pr2serr("Read %d [0x%x] bytes of user supplied data\n", in_len,
8882*44704f69SBart Van Assche                     in_len);
8883*44704f69SBart Van Assche     }
8884*44704f69SBart Van Assche     if (op->pg_arg) {
8885*44704f69SBart Van Assche         if (op->do_all) {
8886*44704f69SBart Van Assche             if (0 == op->do_brief)
8887*44704f69SBart Van Assche                 pr2serr(">>> warning: --page=%s ignored when --all given\n",
8888*44704f69SBart Van Assche                         op->pg_arg);
8889*44704f69SBart Van Assche         } else {
8890*44704f69SBart Van Assche             ret = decode_pg_arg(op);
8891*44704f69SBart Van Assche             if (ret)
8892*44704f69SBart Van Assche                 goto err_out;
8893*44704f69SBart Van Assche         }
8894*44704f69SBart Van Assche     }
8895*44704f69SBart Van Assche 
8896*44704f69SBart Van Assche #ifdef SG_LIB_WIN32
8897*44704f69SBart Van Assche #ifdef SG_LIB_WIN32_DIRECT
8898*44704f69SBart Van Assche     win32_spt_init_state = !! scsi_pt_win32_spt_state();
8899*44704f69SBart Van Assche     if (vb > 4)
8900*44704f69SBart Van Assche         pr2serr("Initial win32 SPT interface state: %s\n",
8901*44704f69SBart Van Assche                 win32_spt_init_state ? "direct" : "indirect");
8902*44704f69SBart Van Assche #endif
8903*44704f69SBart Van Assche #endif
8904*44704f69SBart Van Assche     sg_fd = sg_cmds_open_device(op->device_name, op->o_readonly, vb);
8905*44704f69SBart Van Assche     if ((sg_fd < 0) && (! op->o_readonly))
8906*44704f69SBart Van Assche         sg_fd = sg_cmds_open_device(op->device_name, true /* ro */, vb);
8907*44704f69SBart Van Assche     if (sg_fd < 0) {
8908*44704f69SBart Van Assche         pr2serr("error opening file: %s: %s \n", op->device_name,
8909*44704f69SBart Van Assche                 safe_strerror(-sg_fd));
8910*44704f69SBart Van Assche         ret = sg_convert_errno(-sg_fd);
8911*44704f69SBart Van Assche         goto err_out;
8912*44704f69SBart Van Assche     }
8913*44704f69SBart Van Assche     if (op->do_list || op->do_all) {
8914*44704f69SBart Van Assche         op->pg_code = SUPP_PAGES_LPAGE;
8915*44704f69SBart Van Assche         if ((op->do_list > 1) || (op->do_all > 1))
8916*44704f69SBart Van Assche             op->subpg_code = SUPP_SPGS_SUBPG;
8917*44704f69SBart Van Assche     }
8918*44704f69SBart Van Assche     if (op->do_transport) {
8919*44704f69SBart Van Assche         if ((op->pg_code > 0) || (op->subpg_code > 0) ||
8920*44704f69SBart Van Assche             op->do_temperature) {
8921*44704f69SBart Van Assche             pr2serr("'-T' should not be mixed with options implying other "
8922*44704f69SBart Van Assche                     "pages\n");
8923*44704f69SBart Van Assche             ret = SG_LIB_FILE_ERROR;
8924*44704f69SBart Van Assche             goto err_out;
8925*44704f69SBart Van Assche         }
8926*44704f69SBart Van Assche         op->pg_code = PROTO_SPECIFIC_LPAGE;
8927*44704f69SBart Van Assche     }
8928*44704f69SBart Van Assche 
8929*44704f69SBart Van Assche     memset(&inq_out, 0, sizeof(inq_out));
8930*44704f69SBart Van Assche     if (op->no_inq < 2) {
8931*44704f69SBart Van Assche         if (sg_simple_inquiry(sg_fd, &inq_out, true, vb)) {
8932*44704f69SBart Van Assche             pr2serr("%s doesn't respond to a SCSI INQUIRY\n",
8933*44704f69SBart Van Assche                     op->device_name);
8934*44704f69SBart Van Assche             ret = SG_LIB_CAT_OTHER;
8935*44704f69SBart Van Assche             goto err_out;
8936*44704f69SBart Van Assche         }
8937*44704f69SBart Van Assche         op->dev_pdt = inq_out.peripheral_type;
8938*44704f69SBart Van Assche         if ((! op->do_raw) && (0 == op->do_hex) && (! op->do_name) &&
8939*44704f69SBart Van Assche             (0 == op->no_inq) && (0 == op->do_brief))
8940*44704f69SBart Van Assche             sgj_pr_hr(jsp, "    %.8s  %.16s  %.4s\n", inq_out.vendor,
8941*44704f69SBart Van Assche                       inq_out.product, inq_out.revision);
8942*44704f69SBart Van Assche         memcpy(t10_vendor_str, inq_out.vendor, 8);
8943*44704f69SBart Van Assche         memcpy(t10_product_str, inq_out.product, 16);
8944*44704f69SBart Van Assche         if (VP_NONE == op->vend_prod_num)
8945*44704f69SBart Van Assche             op->deduced_vpn = find_vpn_by_inquiry();
8946*44704f69SBart Van Assche     }
8947*44704f69SBart Van Assche 
8948*44704f69SBart Van Assche     if (op->do_temperature) {
8949*44704f69SBart Van Assche         ret = fetchTemperature(sg_fd, rsp_buff, SHORT_RESP_LEN, op, jop);
8950*44704f69SBart Van Assche         goto err_out;
8951*44704f69SBart Van Assche     }
8952*44704f69SBart Van Assche     if (op->do_select) {
8953*44704f69SBart Van Assche         k = sg_ll_log_select(sg_fd, op->do_pcreset, op->do_sp,
8954*44704f69SBart Van Assche                              op->page_control, op->pg_code, op->subpg_code,
8955*44704f69SBart Van Assche                              rsp_buff, ((in_len > 0) ? in_len : 0), true, vb);
8956*44704f69SBart Van Assche         if (k) {
8957*44704f69SBart Van Assche             if (SG_LIB_CAT_NOT_READY == k)
8958*44704f69SBart Van Assche                 pr2serr("log_select: device not ready\n");
8959*44704f69SBart Van Assche             else if (SG_LIB_CAT_ILLEGAL_REQ == k)
8960*44704f69SBart Van Assche                 pr2serr("log_select: field in cdb illegal\n");
8961*44704f69SBart Van Assche             else if (SG_LIB_CAT_INVALID_OP == k)
8962*44704f69SBart Van Assche                 pr2serr("log_select: not supported\n");
8963*44704f69SBart Van Assche             else if (SG_LIB_CAT_UNIT_ATTENTION == k)
8964*44704f69SBart Van Assche                 pr2serr("log_select: unit attention\n");
8965*44704f69SBart Van Assche             else if (SG_LIB_CAT_ABORTED_COMMAND == k)
8966*44704f69SBart Van Assche                 pr2serr("log_select: aborted command\n");
8967*44704f69SBart Van Assche             else
8968*44704f69SBart Van Assche                 pr2serr("log_select: failed (%d), try '-v' for more "
8969*44704f69SBart Van Assche                         "information\n", k);
8970*44704f69SBart Van Assche         }
8971*44704f69SBart Van Assche         ret = (k >= 0) ?  k : SG_LIB_CAT_OTHER;
8972*44704f69SBart Van Assche         goto err_out;
8973*44704f69SBart Van Assche     }
8974*44704f69SBart Van Assche     if (op->do_list > 2) {
8975*44704f69SBart Van Assche         const int supp_pgs_blen = sizeof(supp_pgs_rsp);
8976*44704f69SBart Van Assche 
8977*44704f69SBart Van Assche         op->subpg_code = NOT_SPG_SUBPG;
8978*44704f69SBart Van Assche         res = do_logs(sg_fd, supp_pgs_rsp, supp_pgs_blen, op);
8979*44704f69SBart Van Assche         if (res != 0)
8980*44704f69SBart Van Assche             goto bad;
8981*44704f69SBart Van Assche         su_p_pg_len = sg_get_unaligned_be16(supp_pgs_rsp + 2);
8982*44704f69SBart Van Assche         if ((su_p_pg_len + 4) > supp_pgs_blen) {
8983*44704f69SBart Van Assche             pr2serr("Supported log pages log page is too long [%d], exit\n",
8984*44704f69SBart Van Assche                     su_p_pg_len);
8985*44704f69SBart Van Assche             res = SG_LIB_CAT_OTHER;
8986*44704f69SBart Van Assche             goto bad;
8987*44704f69SBart Van Assche         }
8988*44704f69SBart Van Assche         op->subpg_code = SUPP_SPGS_SUBPG;
8989*44704f69SBart Van Assche     }
8990*44704f69SBart Van Assche     resp_len = (op->maxlen > 0) ? op->maxlen : MX_ALLOC_LEN;
8991*44704f69SBart Van Assche     res = do_logs(sg_fd, rsp_buff, resp_len, op);
8992*44704f69SBart Van Assche     if (0 == res) {
8993*44704f69SBart Van Assche         pg_len = sg_get_unaligned_be16(rsp_buff + 2);
8994*44704f69SBart Van Assche         if ((pg_len + 4) > resp_len) {
8995*44704f69SBart Van Assche             pr2serr("Only fetched %d bytes of response (available: %d "
8996*44704f69SBart Van Assche                     "bytes)\n    truncate output\n",
8997*44704f69SBart Van Assche                    resp_len, pg_len + 4);
8998*44704f69SBart Van Assche             pg_len = resp_len - 4;
8999*44704f69SBart Van Assche         }
9000*44704f69SBart Van Assche         goto good;
9001*44704f69SBart Van Assche     }
9002*44704f69SBart Van Assche bad:
9003*44704f69SBart Van Assche     if (SG_LIB_CAT_INVALID_OP == res)
9004*44704f69SBart Van Assche         pr2serr("%snot supported\n", ls_s);
9005*44704f69SBart Van Assche     else if (SG_LIB_CAT_NOT_READY == res)
9006*44704f69SBart Van Assche         pr2serr("%sdevice not ready\n", ls_s);
9007*44704f69SBart Van Assche     else if (SG_LIB_CAT_ILLEGAL_REQ == res) {
9008*44704f69SBart Van Assche         if ((op->do_list > 2) && (SUPP_SPGS_SUBPG == op->subpg_code)) {
9009*44704f69SBart Van Assche             rsp_buff[0] = 0x40;
9010*44704f69SBart Van Assche             rsp_buff[1] = SUPP_SPGS_SUBPG;
9011*44704f69SBart Van Assche             pg_len = 0;
9012*44704f69SBart Van Assche             res = 0;
9013*44704f69SBart Van Assche             if (op->verbose)
9014*44704f69SBart Van Assche                 pr2serr("%sfield in cdb illegal in [0,0xff], "
9015*44704f69SBart Van Assche                         "continue with merge\n", ls_s);
9016*44704f69SBart Van Assche             goto good;
9017*44704f69SBart Van Assche         } else
9018*44704f69SBart Van Assche             pr2serr("%sfield in cdb illegal\n", ls_s);
9019*44704f69SBart Van Assche     } else if (SG_LIB_CAT_UNIT_ATTENTION == res)
9020*44704f69SBart Van Assche         pr2serr("%sunit attention\n", ls_s);
9021*44704f69SBart Van Assche     else if (SG_LIB_CAT_ABORTED_COMMAND == res)
9022*44704f69SBart Van Assche         pr2serr("%saborted command\n", ls_s);
9023*44704f69SBart Van Assche     else if (SG_LIB_TRANSPORT_ERROR == res)
9024*44704f69SBart Van Assche         pr2serr("%stransport error\n", ls_s);
9025*44704f69SBart Van Assche     else
9026*44704f69SBart Van Assche         pr2serr("%sother error [%d]\n", ls_s, res);
9027*44704f69SBart Van Assche     ret = res;
9028*44704f69SBart Van Assche     goto err_out;
9029*44704f69SBart Van Assche 
9030*44704f69SBart Van Assche good:
9031*44704f69SBart Van Assche     if (op->do_list > 2)
9032*44704f69SBart Van Assche         pg_len = merge_both_supported(supp_pgs_rsp + 4, su_p_pg_len, pg_len);
9033*44704f69SBart Van Assche 
9034*44704f69SBart Van Assche     if (0 == op->do_all) {
9035*44704f69SBart Van Assche         if (op->filter_given) {
9036*44704f69SBart Van Assche             if (op->do_hex > 2)
9037*44704f69SBart Van Assche                 hex2stdout(rsp_buff, pg_len + 4, op->dstrhex_no_ascii);
9038*44704f69SBart Van Assche             else
9039*44704f69SBart Van Assche                 decode_page_contents(rsp_buff, pg_len + 4, op, jop);
9040*44704f69SBart Van Assche         } else if (op->do_raw)
9041*44704f69SBart Van Assche             dStrRaw(rsp_buff, pg_len + 4);
9042*44704f69SBart Van Assche         else if (op->do_hex > 1)
9043*44704f69SBart Van Assche             hex2stdout(rsp_buff, pg_len + 4, op->dstrhex_no_ascii);
9044*44704f69SBart Van Assche         else if (pg_len > 1) {
9045*44704f69SBart Van Assche             if (op->do_hex) {
9046*44704f69SBart Van Assche                 if (rsp_buff[0] & 0x40)
9047*44704f69SBart Van Assche                     printf("Log page code=0x%x,0x%x, DS=%d, SPF=1, "
9048*44704f69SBart Van Assche                            "page_len=0x%x\n", rsp_buff[0] & 0x3f, rsp_buff[1],
9049*44704f69SBart Van Assche                            !!(rsp_buff[0] & 0x80), pg_len);
9050*44704f69SBart Van Assche                 else
9051*44704f69SBart Van Assche                     printf("Log page code=0x%x, DS=%d, SPF=0, page_len=0x%x\n",
9052*44704f69SBart Van Assche                            rsp_buff[0] & 0x3f, !!(rsp_buff[0] & 0x80), pg_len);
9053*44704f69SBart Van Assche                 hex2stdout(rsp_buff, pg_len + 4, op->dstrhex_no_ascii);
9054*44704f69SBart Van Assche             }
9055*44704f69SBart Van Assche             else
9056*44704f69SBart Van Assche                 decode_page_contents(rsp_buff, pg_len + 4, op, jop);
9057*44704f69SBart Van Assche         }
9058*44704f69SBart Van Assche     }
9059*44704f69SBart Van Assche     ret = res;
9060*44704f69SBart Van Assche 
9061*44704f69SBart Van Assche     if (op->do_all && (pg_len > 1)) {
9062*44704f69SBart Van Assche         int my_len = pg_len;
9063*44704f69SBart Van Assche         bool spf;
9064*44704f69SBart Van Assche 
9065*44704f69SBart Van Assche         parr = sg_memalign(parr_sz, 0, &free_parr, false);
9066*44704f69SBart Van Assche         if (NULL == parr) {
9067*44704f69SBart Van Assche             pr2serr("Unable to allocate heap for parr\n");
9068*44704f69SBart Van Assche             ret = sg_convert_errno(ENOMEM);
9069*44704f69SBart Van Assche             goto err_out;
9070*44704f69SBart Van Assche         }
9071*44704f69SBart Van Assche         spf = !!(rsp_buff[0] & 0x40);
9072*44704f69SBart Van Assche         if (my_len > parr_sz) {
9073*44704f69SBart Van Assche             pr2serr("Unexpectedly large page_len=%d, trim to %d\n", my_len,
9074*44704f69SBart Van Assche                     parr_sz);
9075*44704f69SBart Van Assche             my_len = parr_sz;
9076*44704f69SBart Van Assche         }
9077*44704f69SBart Van Assche         memcpy(parr, rsp_buff + 4, my_len);
9078*44704f69SBart Van Assche         for (k = 0; k < my_len; ++k) {
9079*44704f69SBart Van Assche             op->pg_code = parr[k] & 0x3f;
9080*44704f69SBart Van Assche             if (spf)
9081*44704f69SBart Van Assche                 op->subpg_code = parr[++k];
9082*44704f69SBart Van Assche             else
9083*44704f69SBart Van Assche                 op->subpg_code = NOT_SPG_SUBPG;
9084*44704f69SBart Van Assche 
9085*44704f69SBart Van Assche             /* Some devices include [pg_code, 0xff] for all pg_code > 0 */
9086*44704f69SBart Van Assche             if ((op->pg_code > 0) && (SUPP_SPGS_SUBPG == op->subpg_code))
9087*44704f69SBart Van Assche                 continue;       /* skip since no new information */
9088*44704f69SBart Van Assche             if ((op->pg_code >= 0x30) && op->exclude_vendor)
9089*44704f69SBart Van Assche                 continue;
9090*44704f69SBart Van Assche             if (! op->do_raw)
9091*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "\n");
9092*44704f69SBart Van Assche             res = do_logs(sg_fd, rsp_buff, resp_len, op);
9093*44704f69SBart Van Assche             if (0 == res) {
9094*44704f69SBart Van Assche                 pg_len = sg_get_unaligned_be16(rsp_buff + 2);
9095*44704f69SBart Van Assche                 if ((pg_len + 4) > resp_len) {
9096*44704f69SBart Van Assche                     pr2serr("Only fetched %d bytes of response, truncate "
9097*44704f69SBart Van Assche                             "output\n", resp_len);
9098*44704f69SBart Van Assche                     pg_len = resp_len - 4;
9099*44704f69SBart Van Assche                 }
9100*44704f69SBart Van Assche                 if (op->do_raw && (! op->filter_given))
9101*44704f69SBart Van Assche                     dStrRaw(rsp_buff, pg_len + 4);
9102*44704f69SBart Van Assche                 else if (op->do_hex > 4)
9103*44704f69SBart Van Assche                     decode_page_contents(rsp_buff, pg_len + 4, op, jop);
9104*44704f69SBart Van Assche                 else if (op->do_hex > 1)
9105*44704f69SBart Van Assche                     hex2stdout(rsp_buff, pg_len + 4, op->dstrhex_no_ascii);
9106*44704f69SBart Van Assche                 else if (1 == op->do_hex) {
9107*44704f69SBart Van Assche                     if (0 == op->do_brief) {
9108*44704f69SBart Van Assche                         if (rsp_buff[0] & 0x40)
9109*44704f69SBart Van Assche                             printf("Log page code=0x%x,0x%x, DS=%d, SPF=1, "
9110*44704f69SBart Van Assche                                    "page_len=0x%x\n", rsp_buff[0] & 0x3f,
9111*44704f69SBart Van Assche                                    rsp_buff[1], !!(rsp_buff[0] & 0x80),
9112*44704f69SBart Van Assche                                    pg_len);
9113*44704f69SBart Van Assche                         else
9114*44704f69SBart Van Assche                             printf("Log page code=0x%x, DS=%d, SPF=0, "
9115*44704f69SBart Van Assche                                    "page_len=0x%x\n", rsp_buff[0] & 0x3f,
9116*44704f69SBart Van Assche                                    !!(rsp_buff[0] & 0x80), pg_len);
9117*44704f69SBart Van Assche                     }
9118*44704f69SBart Van Assche                     hex2stdout(rsp_buff, pg_len + 4, op->dstrhex_no_ascii);
9119*44704f69SBart Van Assche                 }
9120*44704f69SBart Van Assche                 else
9121*44704f69SBart Van Assche                     decode_page_contents(rsp_buff, pg_len + 4, op, jop);
9122*44704f69SBart Van Assche             } else if (SG_LIB_CAT_INVALID_OP == res)
9123*44704f69SBart Van Assche                 pr2serr("%spage=0x%x,0x%x not supported\n", ls_s,
9124*44704f69SBart Van Assche                         op->pg_code, op->subpg_code);
9125*44704f69SBart Van Assche             else if (SG_LIB_CAT_NOT_READY == res)
9126*44704f69SBart Van Assche                 pr2serr("%sdevice not ready\n", ls_s);
9127*44704f69SBart Van Assche             else if (SG_LIB_CAT_ILLEGAL_REQ == res)
9128*44704f69SBart Van Assche                 pr2serr("%sfield in cdb illegal [page=0x%x,0x%x]\n", ls_s,
9129*44704f69SBart Van Assche                         op->pg_code, op->subpg_code);
9130*44704f69SBart Van Assche             else if (SG_LIB_CAT_UNIT_ATTENTION == res)
9131*44704f69SBart Van Assche                 pr2serr("%sunit attention\n", ls_s);
9132*44704f69SBart Van Assche             else if (SG_LIB_CAT_ABORTED_COMMAND == res)
9133*44704f69SBart Van Assche                 pr2serr("%saborted command\n", ls_s);
9134*44704f69SBart Van Assche             else
9135*44704f69SBart Van Assche                 pr2serr("%sfailed, try '-v' for more information\n", ls_s);
9136*44704f69SBart Van Assche         }
9137*44704f69SBart Van Assche     }
9138*44704f69SBart Van Assche err_out:
9139*44704f69SBart Van Assche     if (free_rsp_buff)
9140*44704f69SBart Van Assche         free(free_rsp_buff);
9141*44704f69SBart Van Assche     if (free_parr)
9142*44704f69SBart Van Assche         free(free_parr);
9143*44704f69SBart Van Assche     if (sg_fd >= 0)
9144*44704f69SBart Van Assche         sg_cmds_close_device(sg_fd);
9145*44704f69SBart Van Assche     if (0 == vb) {
9146*44704f69SBart Van Assche         if (! sg_if_can2stderr("sg_logs failed: ", ret))
9147*44704f69SBart Van Assche             pr2serr("Some error occurred, try again with '-v' or '-vv' for "
9148*44704f69SBart Van Assche                     "more information\n");
9149*44704f69SBart Van Assche     }
9150*44704f69SBart Van Assche     if (as_json) {
9151*44704f69SBart Van Assche         if (0 == op->do_hex)
9152*44704f69SBart Van Assche             sgj_js2file(jsp, NULL, ret, stdout);
9153*44704f69SBart Van Assche         sgj_finish(jsp);
9154*44704f69SBart Van Assche     }
9155*44704f69SBart Van Assche     return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
9156*44704f69SBart Van Assche }
9157