xref: /aosp_15_r20/external/sg3_utils/src/sg_rep_zones.c (revision 44704f698541f6367e81f991ef8bb54ccbf3fc18)
1*44704f69SBart Van Assche /*
2*44704f69SBart Van Assche  * Copyright (c) 2014-2022 Douglas Gilbert.
3*44704f69SBart Van Assche  * All rights reserved.
4*44704f69SBart Van Assche  * Use of this source code is governed by a BSD-style
5*44704f69SBart Van Assche  * license that can be found in the BSD_LICENSE file.
6*44704f69SBart Van Assche  *
7*44704f69SBart Van Assche  * SPDX-License-Identifier: BSD-2-Clause
8*44704f69SBart Van Assche  */
9*44704f69SBart Van Assche 
10*44704f69SBart Van Assche #include <unistd.h>
11*44704f69SBart Van Assche #include <fcntl.h>
12*44704f69SBart Van Assche #include <stdio.h>
13*44704f69SBart Van Assche #include <stdlib.h>
14*44704f69SBart Van Assche #include <stdarg.h>
15*44704f69SBart Van Assche #include <stdbool.h>
16*44704f69SBart Van Assche #include <string.h>
17*44704f69SBart Van Assche #include <limits.h>
18*44704f69SBart Van Assche #include <errno.h>
19*44704f69SBart Van Assche #include <ctype.h>
20*44704f69SBart Van Assche #include <getopt.h>
21*44704f69SBart Van Assche #define __STDC_FORMAT_MACROS 1
22*44704f69SBart Van Assche #include <inttypes.h>
23*44704f69SBart Van Assche 
24*44704f69SBart Van Assche #ifdef HAVE_CONFIG_H
25*44704f69SBart Van Assche #include "config.h"
26*44704f69SBart Van Assche #endif
27*44704f69SBart Van Assche 
28*44704f69SBart Van Assche #include "sg_lib.h"
29*44704f69SBart Van Assche #include "sg_lib_data.h"
30*44704f69SBart Van Assche #include "sg_pt.h"
31*44704f69SBart Van Assche #include "sg_cmds_basic.h"
32*44704f69SBart Van Assche #include "sg_unaligned.h"
33*44704f69SBart Van Assche #include "sg_pr2serr.h"
34*44704f69SBart Van Assche 
35*44704f69SBart Van Assche /* A utility program originally written for the Linux OS SCSI subsystem.
36*44704f69SBart Van Assche  *
37*44704f69SBart Van Assche  *
38*44704f69SBart Van Assche  * This program issues the SCSI REPORT ZONES, REPORT ZONE DOMAINS or REPORT
39*44704f69SBart Van Assche  * REALMS command to the given SCSI device and decodes the response.
40*44704f69SBart Van Assche  * Based on zbc2r12.pdf
41*44704f69SBart Van Assche  */
42*44704f69SBart Van Assche 
43*44704f69SBart Van Assche static const char * version_str = "1.42 20220807";
44*44704f69SBart Van Assche 
45*44704f69SBart Van Assche #define MY_NAME "sg_rep_zones"
46*44704f69SBart Van Assche 
47*44704f69SBart Van Assche #define WILD_RZONES_BUFF_LEN (1 << 28)
48*44704f69SBart Van Assche #define MAX_RZONES_BUFF_LEN (2 * 1024 * 1024)
49*44704f69SBart Van Assche #define DEF_RZONES_BUFF_LEN (1024 * 16)
50*44704f69SBart Van Assche #define RCAP16_REPLY_LEN 32
51*44704f69SBart Van Assche 
52*44704f69SBart Van Assche #define SG_ZONING_IN_CMDLEN 16
53*44704f69SBart Van Assche #define REPORT_ZONES_DESC_LEN 64
54*44704f69SBart Van Assche #define SENSE_BUFF_LEN 64       /* Arbitrary, could be larger */
55*44704f69SBart Van Assche #define DEF_PT_TIMEOUT  60      /* 60 seconds */
56*44704f69SBart Van Assche 
57*44704f69SBart Van Assche /* Three zone service actions supported by this utility */
58*44704f69SBart Van Assche enum zone_report_sa_e {
59*44704f69SBart Van Assche     REPORT_ZONES_SA = 0x0,
60*44704f69SBart Van Assche     REPORT_REALMS_SA = 0x6,
61*44704f69SBart Van Assche     REPORT_ZONE_DOMAINS_SA = 0x7
62*44704f69SBart Van Assche };
63*44704f69SBart Van Assche 
64*44704f69SBart Van Assche struct opts_t {
65*44704f69SBart Van Assche     bool do_brief;
66*44704f69SBart Van Assche     bool do_force;
67*44704f69SBart Van Assche     bool do_partial;
68*44704f69SBart Van Assche     bool do_raw;
69*44704f69SBart Van Assche     bool do_realms;
70*44704f69SBart Van Assche     bool do_zdomains;
71*44704f69SBart Van Assche     bool maxlen_given;
72*44704f69SBart Van Assche     bool o_readonly;
73*44704f69SBart Van Assche     bool statistics;
74*44704f69SBart Van Assche     bool verbose_given;
75*44704f69SBart Van Assche     bool version_given;
76*44704f69SBart Van Assche     bool wp_only;
77*44704f69SBart Van Assche     enum zone_report_sa_e serv_act;
78*44704f69SBart Van Assche     int do_help;
79*44704f69SBart Van Assche     int do_hex;
80*44704f69SBart Van Assche     int do_num;
81*44704f69SBart Van Assche     int find_zt;        /* negative values: find first not equal to */
82*44704f69SBart Van Assche     int maxlen;
83*44704f69SBart Van Assche     int reporting_opt;
84*44704f69SBart Van Assche     int vb;
85*44704f69SBart Van Assche     uint64_t st_lba;
86*44704f69SBart Van Assche     const char * in_fn;
87*44704f69SBart Van Assche     sgj_state json_st;
88*44704f69SBart Van Assche };
89*44704f69SBart Van Assche 
90*44704f69SBart Van Assche struct zt_num2abbrev_t {
91*44704f69SBart Van Assche     int ztn;
92*44704f69SBart Van Assche     const char * abbrev;
93*44704f69SBart Van Assche };
94*44704f69SBart Van Assche 
95*44704f69SBart Van Assche static struct option long_options[] = {
96*44704f69SBart Van Assche         {"brief", no_argument, 0, 'b'}, /* only header and last descriptor */
97*44704f69SBart Van Assche         {"domain", no_argument, 0, 'd'},
98*44704f69SBart Van Assche         {"domains", no_argument, 0, 'd'},
99*44704f69SBart Van Assche         {"force", no_argument, 0, 'f'},
100*44704f69SBart Van Assche         {"find", required_argument, 0, 'F'},
101*44704f69SBart Van Assche         {"help", no_argument, 0, 'h'},
102*44704f69SBart Van Assche         {"hex", no_argument, 0, 'H'},
103*44704f69SBart Van Assche         {"in", required_argument, 0, 'i'},      /* silent, same as --inhex= */
104*44704f69SBart Van Assche         {"inhex", required_argument, 0, 'i'},
105*44704f69SBart Van Assche         {"json", optional_argument, 0, 'j'},
106*44704f69SBart Van Assche         {"locator", required_argument, 0, 'l'},
107*44704f69SBart Van Assche         {"maxlen", required_argument, 0, 'm'},
108*44704f69SBart Van Assche         {"num", required_argument, 0, 'n'},
109*44704f69SBart Van Assche         {"partial", no_argument, 0, 'p'},
110*44704f69SBart Van Assche         {"raw", no_argument, 0, 'r'},
111*44704f69SBart Van Assche         {"readonly", no_argument, 0, 'R'},
112*44704f69SBart Van Assche         {"realm", no_argument, 0, 'e'},
113*44704f69SBart Van Assche         {"realms", no_argument, 0, 'e'},
114*44704f69SBart Van Assche         {"report", required_argument, 0, 'o'},
115*44704f69SBart Van Assche         {"start", required_argument, 0, 's'},
116*44704f69SBart Van Assche         {"statistics", no_argument, 0, 'S'},
117*44704f69SBart Van Assche         {"stats", no_argument, 0, 'S'},
118*44704f69SBart Van Assche         {"verbose", no_argument, 0, 'v'},
119*44704f69SBart Van Assche         {"version", no_argument, 0, 'V'},
120*44704f69SBart Van Assche         {"wp", no_argument, 0, 'w'},
121*44704f69SBart Van Assche         {0, 0, 0, 0},
122*44704f69SBart Van Assche };
123*44704f69SBart Van Assche 
124*44704f69SBart Van Assche /* Zone types */
125*44704f69SBart Van Assche static struct zt_num2abbrev_t zt_num2abbrev[] = {
126*44704f69SBart Van Assche     {0, "none"},
127*44704f69SBart Van Assche     {1, "c"},           /* conventionial */
128*44704f69SBart Van Assche     {2, "swr"},         /* sequential write required */
129*44704f69SBart Van Assche     {3, "swp"},         /* sequential write preferred */
130*44704f69SBart Van Assche     {4, "sobr"},        /* sequential or before required */
131*44704f69SBart Van Assche     {5, "g"},           /* gap */
132*44704f69SBart Van Assche     {-1, NULL},         /* sentinel */
133*44704f69SBart Van Assche };
134*44704f69SBart Van Assche 
135*44704f69SBart Van Assche static const char * zn_dnum_s = "zone descriptor number: ";
136*44704f69SBart Van Assche 
137*44704f69SBart Van Assche static const char * meaning_s = "meaning";
138*44704f69SBart Van Assche 
139*44704f69SBart Van Assche 
140*44704f69SBart Van Assche static void
prn_zone_type_abbrevs(void)141*44704f69SBart Van Assche prn_zone_type_abbrevs(void)
142*44704f69SBart Van Assche {
143*44704f69SBart Van Assche     const struct zt_num2abbrev_t * n2ap = zt_num2abbrev;
144*44704f69SBart Van Assche     char b[32];
145*44704f69SBart Van Assche 
146*44704f69SBart Van Assche     pr2serr("Zone type number\tAbbreviation\tName\n");
147*44704f69SBart Van Assche     pr2serr("----------------\t------------\t----\n");
148*44704f69SBart Van Assche     for ( ; n2ap->abbrev; ++n2ap) {
149*44704f69SBart Van Assche         if (n2ap == zt_num2abbrev)
150*44704f69SBart Van Assche             pr2serr("\t%d\t\t%s\t\t[reserved]\n",
151*44704f69SBart Van Assche                     n2ap->ztn, n2ap->abbrev);
152*44704f69SBart Van Assche         else
153*44704f69SBart Van Assche             pr2serr("\t%d\t\t%s\t\t%s\n", n2ap->ztn, n2ap->abbrev,
154*44704f69SBart Van Assche                     sg_get_zone_type_str(n2ap->ztn, sizeof(b), b));
155*44704f69SBart Van Assche     }
156*44704f69SBart Van Assche }
157*44704f69SBart Van Assche 
158*44704f69SBart Van Assche static void
usage(int h)159*44704f69SBart Van Assche usage(int h)
160*44704f69SBart Van Assche {
161*44704f69SBart Van Assche     if (h > 1) goto h_twoormore;
162*44704f69SBart Van Assche     pr2serr("Usage: "
163*44704f69SBart Van Assche             "sg_rep_zones  [--domain] [--find=ZT] [--force] [--help] "
164*44704f69SBart Van Assche             "[--hex]\n"
165*44704f69SBart Van Assche             "                     [--inhex=FN] [--json[=JO]] "
166*44704f69SBart Van Assche             "[--locator=LBA]\n"
167*44704f69SBart Van Assche             "                     [--maxlen=LEN] [--num=NUM] [--partial] "
168*44704f69SBart Van Assche             "[--raw]\n"
169*44704f69SBart Van Assche             "                     [--readonly] [--realm] [--report=OPT] "
170*44704f69SBart Van Assche             "[--start=LBA]\n"
171*44704f69SBart Van Assche             "                     [--statistics] [--verbose] [--version] "
172*44704f69SBart Van Assche             "[--wp]\n"
173*44704f69SBart Van Assche             "                     DEVICE\n");
174*44704f69SBart Van Assche     pr2serr("  where:\n"
175*44704f69SBart Van Assche             "    --domain|-d        sends a REPORT ZONE DOMAINS command\n"
176*44704f69SBart Van Assche             "    --find=ZT|-F ZT    find first zone with ZT zone type, "
177*44704f69SBart Van Assche             "starting at LBA\n"
178*44704f69SBart Van Assche             "                       if first character of ZT is - or !, "
179*44704f69SBart Van Assche             "find first\n"
180*44704f69SBart Van Assche             "                       zone that is not ZT\n"
181*44704f69SBart Van Assche             "    --force|-f         bypass some sanity checks when decoding "
182*44704f69SBart Van Assche             "response\n"
183*44704f69SBart Van Assche             "    --help|-h          print out usage message, use twice for "
184*44704f69SBart Van Assche             "more help\n"
185*44704f69SBart Van Assche             "    --hex|-H           output response in hexadecimal; used "
186*44704f69SBart Van Assche             "twice\n"
187*44704f69SBart Van Assche             "                       shows decoded values in hex\n"
188*44704f69SBart Van Assche             "    --inhex=FN|-i FN    decode contents of FN, ignore DEVICE\n"
189*44704f69SBart Van Assche             "    --json[=JO]|-j[JO]    output in JSON instead of human "
190*44704f69SBart Van Assche             "readable text.\n"
191*44704f69SBart Van Assche             "                          Use --json=? for JSON help\n"
192*44704f69SBart Van Assche             "    --locator=LBA|-l LBA    similar to --start= option\n"
193*44704f69SBart Van Assche             "    --maxlen=LEN|-m LEN    max response length (allocation "
194*44704f69SBart Van Assche             "length in cdb)\n"
195*44704f69SBart Van Assche             "                           (def: 0 -> 8192 bytes)\n"
196*44704f69SBart Van Assche             "    --num=NUM|-n NUM    number of zones to output (def: 0 -> "
197*44704f69SBart Van Assche             "all)\n"
198*44704f69SBart Van Assche             "    --partial|-p       sets PARTIAL bit in cdb (def: 0 -> "
199*44704f69SBart Van Assche             "zone list\n"
200*44704f69SBart Van Assche             "                       length not altered by allocation length "
201*44704f69SBart Van Assche             "in cdb)\n"
202*44704f69SBart Van Assche             "    --raw|-r           output response in binary\n"
203*44704f69SBart Van Assche             "    --readonly|-R      open DEVICE read-only (def: read-write)\n"
204*44704f69SBart Van Assche             "    --realm|-e         sends a REPORT REALMS command\n"
205*44704f69SBart Van Assche             "    --report=OPT|-o OP    reporting options (def: 0: all "
206*44704f69SBart Van Assche             "zones)\n"
207*44704f69SBart Van Assche             "    --start=LBA|-s LBA    report zones from the LBA (def: 0)\n"
208*44704f69SBart Van Assche             "                          need not be a zone starting LBA\n"
209*44704f69SBart Van Assche             "    --statistics|-S    gather statistics by reviewing zones\n"
210*44704f69SBart Van Assche             "    --verbose|-v       increase verbosity\n"
211*44704f69SBart Van Assche             "    --version|-V       print version string and exit\n"
212*44704f69SBart Van Assche             "    --wp|-w            output write pointer only\n\n"
213*44704f69SBart Van Assche             "Sends a SCSI REPORT ZONES, REPORT ZONE DOMAINS or REPORT REALMS "
214*44704f69SBart Van Assche             "command.\nBy default sends a REPORT ZONES command. Give help "
215*44704f69SBart Van Assche             "option twice\n(e.g. '-hh') to see reporting options "
216*44704f69SBart Van Assche             "enumerated.\n");
217*44704f69SBart Van Assche     return;
218*44704f69SBart Van Assche h_twoormore:
219*44704f69SBart Van Assche     pr2serr("Reporting options for REPORT ZONES:\n"
220*44704f69SBart Van Assche             "    0x0    list all zones\n"
221*44704f69SBart Van Assche             "    0x1    list zones with a zone condition of EMPTY\n"
222*44704f69SBart Van Assche             "    0x2    list zones with a zone condition of IMPLICITLY "
223*44704f69SBart Van Assche             "OPENED\n"
224*44704f69SBart Van Assche             "    0x3    list zones with a zone condition of EXPLICITLY "
225*44704f69SBart Van Assche             "OPENED\n"
226*44704f69SBart Van Assche             "    0x4    list zones with a zone condition of CLOSED\n"
227*44704f69SBart Van Assche             "    0x5    list zones with a zone condition of FULL\n"
228*44704f69SBart Van Assche             "    0x6    list zones with a zone condition of READ ONLY\n"
229*44704f69SBart Van Assche             "    0x7    list zones with a zone condition of OFFLINE\n"
230*44704f69SBart Van Assche             "    0x8    list zones with a zone condition of INACTIVE\n"
231*44704f69SBart Van Assche             "    0x10   list zones with RWP Recommended set to true\n"
232*44704f69SBart Van Assche             "    0x11   list zones with Non-sequential write resources "
233*44704f69SBart Van Assche             "active set to true\n"
234*44704f69SBart Van Assche             "    0x3e   list zones except those with zone type: GAP\n"
235*44704f69SBart Van Assche             "    0x3f   list zones with a zone condition of NOT WRITE "
236*44704f69SBart Van Assche             "POINTER\n\n");
237*44704f69SBart Van Assche     pr2serr("Reporting options for REPORT ZONE DOMAINS:\n"
238*44704f69SBart Van Assche             "    0x0    list all zone domains\n"
239*44704f69SBart Van Assche             "    0x1    list all zone domains in which all zones are active\n"
240*44704f69SBart Van Assche             "    0x2    list all zone domains that contain active zones\n"
241*44704f69SBart Van Assche             "    0x3    list all zone domains that do not contain any active "
242*44704f69SBart Van Assche             "zones\n\n");
243*44704f69SBart Van Assche     pr2serr("Reporting options for REPORT REALMS:\n"
244*44704f69SBart Van Assche             "    0x0    list all realms\n"
245*44704f69SBart Van Assche             "    0x1    list all realms that contain active Sequential Or "
246*44704f69SBart Van Assche             "Before Required zones\n"
247*44704f69SBart Van Assche             "    0x2    list all realms that contain active Sequential Write "
248*44704f69SBart Van Assche             "Required zones\n"
249*44704f69SBart Van Assche             "    0x3    list all realms that contain active Sequential Write "
250*44704f69SBart Van Assche             "Preferred zones\n");
251*44704f69SBart Van Assche     pr2serr("\n");
252*44704f69SBart Van Assche     prn_zone_type_abbrevs();
253*44704f69SBart Van Assche }
254*44704f69SBart Van Assche 
255*44704f69SBart Van Assche /* Invokes a SCSI REPORT ZONES, REPORT ZONE DOMAINS or REPORT REALMS command
256*44704f69SBart Van Assche  * (see ZBC and ZBC-2).  Return of 0 -> success, various SG_LIB_CAT_* positive
257*44704f69SBart Van Assche  * values or -1 -> other errors */
258*44704f69SBart Van Assche static int
sg_ll_report_zzz(int sg_fd,enum zone_report_sa_e serv_act,uint64_t zs_lba,bool partial,int report_opts,void * resp,int mx_resp_len,int * residp,bool noisy,int vb)259*44704f69SBart Van Assche sg_ll_report_zzz(int sg_fd, enum zone_report_sa_e serv_act, uint64_t zs_lba,
260*44704f69SBart Van Assche                  bool partial, int report_opts, void * resp, int mx_resp_len,
261*44704f69SBart Van Assche                  int * residp, bool noisy, int vb)
262*44704f69SBart Van Assche {
263*44704f69SBart Van Assche     int ret, res, sense_cat;
264*44704f69SBart Van Assche     uint8_t rz_cdb[SG_ZONING_IN_CMDLEN] =
265*44704f69SBart Van Assche           {SG_ZONING_IN, REPORT_ZONES_SA, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
266*44704f69SBart Van Assche            0, 0, 0, 0};
267*44704f69SBart Van Assche     uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT;
268*44704f69SBart Van Assche     struct sg_pt_base * ptvp;
269*44704f69SBart Van Assche 
270*44704f69SBart Van Assche     rz_cdb[1] = (uint8_t)serv_act;
271*44704f69SBart Van Assche     sg_put_unaligned_be64(zs_lba, rz_cdb + 2);
272*44704f69SBart Van Assche     sg_put_unaligned_be32((uint32_t)mx_resp_len, rz_cdb + 10);
273*44704f69SBart Van Assche     rz_cdb[14] = report_opts & 0x3f;
274*44704f69SBart Van Assche     if (partial)
275*44704f69SBart Van Assche         rz_cdb[14] |= 0x80;
276*44704f69SBart Van Assche     if (vb) {
277*44704f69SBart Van Assche         char b[128];
278*44704f69SBart Van Assche 
279*44704f69SBart Van Assche         pr2serr("    %s\n", sg_get_command_str(rz_cdb, SG_ZONING_IN_CMDLEN,
280*44704f69SBart Van Assche                                                true, sizeof(b), b));
281*44704f69SBart Van Assche     }
282*44704f69SBart Van Assche     ptvp = construct_scsi_pt_obj();
283*44704f69SBart Van Assche     if (NULL == ptvp) {
284*44704f69SBart Van Assche         pr2serr("%s: out of memory\n", __func__);
285*44704f69SBart Van Assche         return -1;
286*44704f69SBart Van Assche     }
287*44704f69SBart Van Assche     set_scsi_pt_cdb(ptvp, rz_cdb, sizeof(rz_cdb));
288*44704f69SBart Van Assche     set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
289*44704f69SBart Van Assche     set_scsi_pt_data_in(ptvp, (uint8_t *)resp, mx_resp_len);
290*44704f69SBart Van Assche     res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, vb);
291*44704f69SBart Van Assche     ret = sg_cmds_process_resp(ptvp, "report zone/domain/realm", res, noisy,
292*44704f69SBart Van Assche                                vb, &sense_cat);
293*44704f69SBart Van Assche     if (-1 == ret) {
294*44704f69SBart Van Assche         if (get_scsi_pt_transport_err(ptvp))
295*44704f69SBart Van Assche             ret = SG_LIB_TRANSPORT_ERROR;
296*44704f69SBart Van Assche         else
297*44704f69SBart Van Assche             ret = sg_convert_errno(get_scsi_pt_os_err(ptvp));
298*44704f69SBart Van Assche     } else if (-2 == ret) {
299*44704f69SBart Van Assche         switch (sense_cat) {
300*44704f69SBart Van Assche         case SG_LIB_CAT_RECOVERED:
301*44704f69SBart Van Assche         case SG_LIB_CAT_NO_SENSE:
302*44704f69SBart Van Assche             ret = 0;
303*44704f69SBart Van Assche             break;
304*44704f69SBart Van Assche         default:
305*44704f69SBart Van Assche             ret = sense_cat;
306*44704f69SBart Van Assche             break;
307*44704f69SBart Van Assche         }
308*44704f69SBart Van Assche     } else
309*44704f69SBart Van Assche         ret = 0;
310*44704f69SBart Van Assche     if (residp)
311*44704f69SBart Van Assche         *residp = get_scsi_pt_resid(ptvp);
312*44704f69SBart Van Assche     destruct_scsi_pt_obj(ptvp);
313*44704f69SBart Van Assche     return ret;
314*44704f69SBart Van Assche }
315*44704f69SBart Van Assche 
316*44704f69SBart Van Assche static void
dStrRaw(const uint8_t * str,int len)317*44704f69SBart Van Assche dStrRaw(const uint8_t * str, int len)
318*44704f69SBart Van Assche {
319*44704f69SBart Van Assche     int k;
320*44704f69SBart Van Assche 
321*44704f69SBart Van Assche     for (k = 0; k < len; ++k)
322*44704f69SBart Van Assche         printf("%c", str[k]);
323*44704f69SBart Van Assche }
324*44704f69SBart Van Assche 
325*44704f69SBart Van Assche static const char *
zone_condition_str(int zc,char * b,int blen,int vb)326*44704f69SBart Van Assche zone_condition_str(int zc, char * b, int blen, int vb)
327*44704f69SBart Van Assche {
328*44704f69SBart Van Assche     const char * cp;
329*44704f69SBart Van Assche 
330*44704f69SBart Van Assche     if (NULL == b)
331*44704f69SBart Van Assche         return "zone_condition_str: NULL ptr)";
332*44704f69SBart Van Assche     switch (zc) {
333*44704f69SBart Van Assche     case 0:
334*44704f69SBart Van Assche         cp = "Not write pointer";
335*44704f69SBart Van Assche         break;
336*44704f69SBart Van Assche     case 1:
337*44704f69SBart Van Assche         cp = "Empty";
338*44704f69SBart Van Assche         break;
339*44704f69SBart Van Assche     case 2:
340*44704f69SBart Van Assche         cp = "Implicitly opened";
341*44704f69SBart Van Assche         break;
342*44704f69SBart Van Assche     case 3:
343*44704f69SBart Van Assche         cp = "Explicitly opened";
344*44704f69SBart Van Assche         break;
345*44704f69SBart Van Assche     case 4:
346*44704f69SBart Van Assche         cp = "Closed";
347*44704f69SBart Van Assche         break;
348*44704f69SBart Van Assche     case 5:
349*44704f69SBart Van Assche         cp = "Inactive";
350*44704f69SBart Van Assche         break;
351*44704f69SBart Van Assche     case 0xd:
352*44704f69SBart Van Assche         cp = "Read only";
353*44704f69SBart Van Assche         break;
354*44704f69SBart Van Assche     case 0xe:
355*44704f69SBart Van Assche         cp = "Full";
356*44704f69SBart Van Assche         break;
357*44704f69SBart Van Assche     case 0xf:
358*44704f69SBart Van Assche         cp = "Offline";
359*44704f69SBart Van Assche         break;
360*44704f69SBart Van Assche     default:
361*44704f69SBart Van Assche         cp = NULL;
362*44704f69SBart Van Assche         break;
363*44704f69SBart Van Assche     }
364*44704f69SBart Van Assche     if (cp) {
365*44704f69SBart Van Assche         if (vb)
366*44704f69SBart Van Assche             snprintf(b, blen, "%s [0x%x]", cp, zc);
367*44704f69SBart Van Assche         else
368*44704f69SBart Van Assche             snprintf(b, blen, "%s", cp);
369*44704f69SBart Van Assche     } else
370*44704f69SBart Van Assche         snprintf(b, blen, "Reserved [0x%x]", zc);
371*44704f69SBart Van Assche     return b;
372*44704f69SBart Van Assche }
373*44704f69SBart Van Assche 
374*44704f69SBart Van Assche static const char * same_desc_arr[16] = {
375*44704f69SBart Van Assche     "zone type and length may differ in each descriptor",
376*44704f69SBart Van Assche     "zone type and length same in each descriptor",
377*44704f69SBart Van Assche     "zone type and length same apart from length in last descriptor",
378*44704f69SBart Van Assche     "zone type for each descriptor may be different",
379*44704f69SBart Van Assche     "Reserved [0x4]", "Reserved [0x5]", "Reserved [0x6]", "Reserved [0x7]",
380*44704f69SBart Van Assche     "Reserved [0x8]", "Reserved [0x9]", "Reserved [0xa]", "Reserved [0xb]",
381*44704f69SBart Van Assche     "Reserved [0xc]", "Reserved [0xd]", "Reserved [0xe]", "Reserved [0xf]",
382*44704f69SBart Van Assche };
383*44704f69SBart Van Assche 
384*44704f69SBart Van Assche static uint64_t
prt_a_zn_desc(const uint8_t * bp,const struct opts_t * op,sgj_state * jsp,sgj_opaque_p jop)385*44704f69SBart Van Assche prt_a_zn_desc(const uint8_t *bp, const struct opts_t * op,
386*44704f69SBart Van Assche               sgj_state * jsp, sgj_opaque_p jop)
387*44704f69SBart Van Assche {
388*44704f69SBart Van Assche     uint8_t zt, zc;
389*44704f69SBart Van Assche     uint64_t lba, len, wp;
390*44704f69SBart Van Assche     char b[80];
391*44704f69SBart Van Assche 
392*44704f69SBart Van Assche     jop = jop ? jop : jsp->basep;
393*44704f69SBart Van Assche     zt = bp[0] & 0xf;
394*44704f69SBart Van Assche     zc = (bp[1] >> 4) & 0xf;
395*44704f69SBart Van Assche     sg_get_zone_type_str(zt, sizeof(b), b);
396*44704f69SBart Van Assche     sgj_pr_hr(jsp, "   Zone type: %s\n", b);
397*44704f69SBart Van Assche     sgj_js_nv_istr(jsp, jop, "zone_type", zt, meaning_s, b);
398*44704f69SBart Van Assche     zone_condition_str(zc, b, sizeof(b), op->vb);
399*44704f69SBart Van Assche     sgj_pr_hr(jsp, "   Zone condition: %s\n", b);
400*44704f69SBart Van Assche     sgj_js_nv_istr(jsp, jop, "zone_condition", zc, meaning_s, b);
401*44704f69SBart Van Assche     sgj_haj_vi(jsp, jop, 3, "PUEP", SGJ_SEP_COLON_1_SPACE,
402*44704f69SBart Van Assche                !!(bp[1] & 0x4), false);
403*44704f69SBart Van Assche     sgj_haj_vi(jsp, jop, 3, "NON_SEQ", SGJ_SEP_COLON_1_SPACE,
404*44704f69SBart Van Assche                !!(bp[1] & 0x2), false);
405*44704f69SBart Van Assche     sgj_haj_vi(jsp, jop, 3, "RESET", SGJ_SEP_COLON_1_SPACE,
406*44704f69SBart Van Assche                !!(bp[1] & 0x1), false);
407*44704f69SBart Van Assche     len = sg_get_unaligned_be64(bp + 8);
408*44704f69SBart Van Assche     sgj_pr_hr(jsp, "   Zone Length: 0x%" PRIx64 "\n", len);
409*44704f69SBart Van Assche     sgj_js_nv_ihex(jsp, jop, "zone_length", (int64_t)len);
410*44704f69SBart Van Assche     lba = sg_get_unaligned_be64(bp + 16);
411*44704f69SBart Van Assche     sgj_pr_hr(jsp, "   Zone start LBA: 0x%" PRIx64 "\n", lba);
412*44704f69SBart Van Assche     sgj_js_nv_ihex(jsp, jop, "zone_start_lba", (int64_t)lba);
413*44704f69SBart Van Assche     wp = sg_get_unaligned_be64(bp + 24);
414*44704f69SBart Van Assche     if (sg_all_ffs((const uint8_t *)&wp, sizeof(wp)))
415*44704f69SBart Van Assche         sgj_pr_hr(jsp, "   Write pointer LBA: -1\n");
416*44704f69SBart Van Assche     else
417*44704f69SBart Van Assche         sgj_pr_hr(jsp, "   Write pointer LBA: 0x%" PRIx64 "\n", wp);
418*44704f69SBart Van Assche     sgj_js_nv_ihex(jsp, jop, "write_pointer_lba", (int64_t)wp);
419*44704f69SBart Van Assche     return lba + len;
420*44704f69SBart Van Assche }
421*44704f69SBart Van Assche 
422*44704f69SBart Van Assche static int
decode_rep_zones(const uint8_t * rzBuff,int act_len,uint32_t decod_len,const struct opts_t * op,sgj_state * jsp)423*44704f69SBart Van Assche decode_rep_zones(const uint8_t * rzBuff, int act_len, uint32_t decod_len,
424*44704f69SBart Van Assche                  const struct opts_t * op, sgj_state * jsp)
425*44704f69SBart Van Assche {
426*44704f69SBart Van Assche     bool as_json = jsp ? jsp->pr_as_json : false;
427*44704f69SBart Van Assche     int k, same, num_zd;
428*44704f69SBart Van Assche     uint64_t wp, ul, mx_lba;
429*44704f69SBart Van Assche     sgj_opaque_p jop = jsp ? jsp->basep : NULL;
430*44704f69SBart Van Assche     sgj_opaque_p jap = NULL;
431*44704f69SBart Van Assche     const uint8_t * bp;
432*44704f69SBart Van Assche 
433*44704f69SBart Van Assche     if ((uint32_t)act_len < decod_len) {
434*44704f69SBart Van Assche         num_zd = (act_len >= 64) ? ((act_len - 64) / REPORT_ZONES_DESC_LEN)
435*44704f69SBart Van Assche                                  : 0;
436*44704f69SBart Van Assche         if (act_len == op->maxlen) {
437*44704f69SBart Van Assche             if (op->maxlen_given)
438*44704f69SBart Van Assche                 pr2serr("decode length [%u bytes] may be constrained by "
439*44704f69SBart Van Assche                         "given --maxlen value, try increasing\n", decod_len);
440*44704f69SBart Van Assche             else
441*44704f69SBart Van Assche                 pr2serr("perhaps --maxlen=%u needs to be used\n", decod_len);
442*44704f69SBart Van Assche         } else if (op->in_fn)
443*44704f69SBart Van Assche             pr2serr("perhaps %s has been truncated\n", op->in_fn);
444*44704f69SBart Van Assche     } else
445*44704f69SBart Van Assche         num_zd = (decod_len - 64) / REPORT_ZONES_DESC_LEN;
446*44704f69SBart Van Assche     same = rzBuff[4] & 0xf;
447*44704f69SBart Van Assche     mx_lba = sg_get_unaligned_be64(rzBuff + 8);
448*44704f69SBart Van Assche     if (op->wp_only) {
449*44704f69SBart Van Assche         ;
450*44704f69SBart Van Assche     } else if (op->do_hex) {
451*44704f69SBart Van Assche         hex2stdout(rzBuff, 64, -1);
452*44704f69SBart Van Assche         printf("\n");
453*44704f69SBart Van Assche     } else {
454*44704f69SBart Van Assche         uint64_t rzslbag = sg_get_unaligned_be64(rzBuff + 16);
455*44704f69SBart Van Assche         static const char * rzslbag_s = "Reported zone starting LBA "
456*44704f69SBart Van Assche                                         "granularity";
457*44704f69SBart Van Assche 
458*44704f69SBart Van Assche         sgj_pr_hr(jsp, "  Same=%d: %s\n", same, same_desc_arr[same]);
459*44704f69SBart Van Assche         sgj_js_nv_istr(jsp, jop, "same", same, meaning_s,
460*44704f69SBart Van Assche                        same_desc_arr[same]);
461*44704f69SBart Van Assche         sgj_pr_hr(jsp, "  Maximum LBA: 0x%" PRIx64 "\n\n", mx_lba);
462*44704f69SBart Van Assche         sgj_js_nv_ihex(jsp, jop, "maximum_lba", mx_lba);
463*44704f69SBart Van Assche         sgj_pr_hr(jsp, "  %s: 0x%" PRIx64 "\n\n", rzslbag_s, rzslbag);
464*44704f69SBart Van Assche         sgj_js_nv_ihex(jsp, jop, rzslbag_s, rzslbag);
465*44704f69SBart Van Assche     }
466*44704f69SBart Van Assche     if (op->do_num > 0)
467*44704f69SBart Van Assche             num_zd = (num_zd > op->do_num) ? op->do_num : num_zd;
468*44704f69SBart Van Assche     if (((uint32_t)act_len < decod_len) &&
469*44704f69SBart Van Assche         ((num_zd * REPORT_ZONES_DESC_LEN) + 64 > act_len)) {
470*44704f69SBart Van Assche         pr2serr("Skip due to truncated response, try using --num= to a "
471*44704f69SBart Van Assche                 "value less than %d\n", num_zd);
472*44704f69SBart Van Assche         return SG_LIB_CAT_MALFORMED;
473*44704f69SBart Van Assche     }
474*44704f69SBart Van Assche     if (op->do_brief && (num_zd > 0)) {
475*44704f69SBart Van Assche         bp = rzBuff + 64 + ((num_zd - 1) * REPORT_ZONES_DESC_LEN);
476*44704f69SBart Van Assche         if (op->do_hex) {
477*44704f69SBart Van Assche             if (op->wp_only)
478*44704f69SBart Van Assche                 hex2stdout(bp + 24, 8, -1);
479*44704f69SBart Van Assche             else
480*44704f69SBart Van Assche                 hex2stdout(bp, 64, -1);
481*44704f69SBart Van Assche             return 0;
482*44704f69SBart Van Assche         }
483*44704f69SBart Van Assche         sgj_pr_hr(jsp, "From last descriptor in this response:\n");
484*44704f69SBart Van Assche         sgj_pr_hr(jsp, " %s%d\n", zn_dnum_s, num_zd - 1);
485*44704f69SBart Van Assche         sgj_js_nv_i(jsp, jop, "zone_descriptor_index", num_zd - 1);
486*44704f69SBart Van Assche         ul = prt_a_zn_desc(bp, op, jsp, jop);
487*44704f69SBart Van Assche         if (ul > mx_lba)
488*44704f69SBart Van Assche             sgj_pr_hr(jsp, "   >> This zone seems to be the last one\n");
489*44704f69SBart Van Assche         else
490*44704f69SBart Van Assche             sgj_pr_hr(jsp, "   >> Probable next Zone start LBA: 0x%" PRIx64
491*44704f69SBart Van Assche                       "\n", ul);
492*44704f69SBart Van Assche         return 0;
493*44704f69SBart Van Assche     }
494*44704f69SBart Van Assche     if (as_json)
495*44704f69SBart Van Assche         jap = sgj_named_subarray_r(jsp, NULL, "zone_descriptors_list");
496*44704f69SBart Van Assche     for (k = 0, bp = rzBuff + 64; k < num_zd;
497*44704f69SBart Van Assche          ++k, bp += REPORT_ZONES_DESC_LEN) {
498*44704f69SBart Van Assche         sgj_opaque_p jo2p;
499*44704f69SBart Van Assche 
500*44704f69SBart Van Assche         if (! op->wp_only)
501*44704f69SBart Van Assche              sgj_pr_hr(jsp, " %s%d\n", zn_dnum_s, k);
502*44704f69SBart Van Assche         if (op->do_hex) {
503*44704f69SBart Van Assche             hex2stdout(bp, 64, -1);
504*44704f69SBart Van Assche             continue;
505*44704f69SBart Van Assche         }
506*44704f69SBart Van Assche         if (op->wp_only) {
507*44704f69SBart Van Assche             if (op->do_hex)
508*44704f69SBart Van Assche                 hex2stdout(bp + 24, 8, -1);
509*44704f69SBart Van Assche             else {
510*44704f69SBart Van Assche                 wp = sg_get_unaligned_be64(bp + 24);
511*44704f69SBart Van Assche                 if (sg_all_ffs((const uint8_t *)&wp, sizeof(wp)))
512*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "-1\n");
513*44704f69SBart Van Assche                 else
514*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "0x%" PRIx64 "\n", wp);
515*44704f69SBart Van Assche                 jo2p = sgj_new_unattached_object_r(jsp);
516*44704f69SBart Van Assche                 sgj_js_nv_ihex(jsp, jo2p, "write_pointer_lba", (int64_t)wp);
517*44704f69SBart Van Assche                 sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p);
518*44704f69SBart Van Assche             }
519*44704f69SBart Van Assche             continue;
520*44704f69SBart Van Assche         }
521*44704f69SBart Van Assche         jo2p = sgj_new_unattached_object_r(jsp);
522*44704f69SBart Van Assche         prt_a_zn_desc(bp, op, jsp, jo2p);
523*44704f69SBart Van Assche         sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p);
524*44704f69SBart Van Assche     }
525*44704f69SBart Van Assche     if ((op->do_num == 0) && (! op->wp_only) && (! op->do_hex)) {
526*44704f69SBart Van Assche         if ((64 + (REPORT_ZONES_DESC_LEN * (uint32_t)num_zd)) < decod_len)
527*44704f69SBart Van Assche             sgj_pr_hr(jsp, "\n>>> Beware: Zone list truncated, may need "
528*44704f69SBart Van Assche                       "another call\n");
529*44704f69SBart Van Assche     }
530*44704f69SBart Van Assche     return 0;
531*44704f69SBart Van Assche }
532*44704f69SBart Van Assche 
533*44704f69SBart Van Assche static int
decode_rep_realms(const uint8_t * rzBuff,int act_len,const struct opts_t * op,sgj_state * jsp)534*44704f69SBart Van Assche decode_rep_realms(const uint8_t * rzBuff, int act_len,
535*44704f69SBart Van Assche                   const struct opts_t * op, sgj_state * jsp)
536*44704f69SBart Van Assche {
537*44704f69SBart Van Assche     uint32_t k, realms_count, derived_realms_count, r_desc_len,
538*44704f69SBart Van Assche              zdomains_count;
539*44704f69SBart Van Assche     uint64_t nr_locator;
540*44704f69SBart Van Assche     const uint8_t * bp;
541*44704f69SBart Van Assche     sgj_opaque_p jop = jsp ? jsp->basep : NULL;
542*44704f69SBart Van Assche     sgj_opaque_p jap = NULL;
543*44704f69SBart Van Assche     sgj_opaque_p ja2p = NULL;
544*44704f69SBart Van Assche 
545*44704f69SBart Van Assche     if (act_len < 12) {
546*44704f69SBart Van Assche         pr2serr("need more than 12 bytes to decode, got %u\n", act_len);
547*44704f69SBart Van Assche         return SG_LIB_CAT_MALFORMED;
548*44704f69SBart Van Assche     }
549*44704f69SBart Van Assche     realms_count = sg_get_unaligned_be32(rzBuff + 4);
550*44704f69SBart Van Assche     r_desc_len = sg_get_unaligned_be32(rzBuff + 8);
551*44704f69SBart Van Assche     if (act_len < 20)
552*44704f69SBart Van Assche         nr_locator = sg_get_unaligned_be64(rzBuff + 12);
553*44704f69SBart Van Assche     else
554*44704f69SBart Van Assche         nr_locator = 0;
555*44704f69SBart Van Assche     sgj_haj_vi(jsp, jop, 0, "Realms_count", SGJ_SEP_EQUAL_NO_SPACE,
556*44704f69SBart Van Assche                realms_count, true);
557*44704f69SBart Van Assche     sgj_haj_vi(jsp, jop, 0, "Realms_descriptor_length",
558*44704f69SBart Van Assche                SGJ_SEP_EQUAL_NO_SPACE, r_desc_len, true);
559*44704f69SBart Van Assche     sgj_pr_hr(jsp, "Next_realm_locator=0x%" PRIx64 "\n", nr_locator);
560*44704f69SBart Van Assche     sgj_js_nv_ihex(jsp, jop, "Next_realm_locator", nr_locator);
561*44704f69SBart Van Assche     if ((realms_count < 1) || (act_len < (64 + 16)) || (r_desc_len < 16)) {
562*44704f69SBart Van Assche         if (op->vb) {
563*44704f69SBart Van Assche             pr2serr("%s: exiting early because ", __func__);
564*44704f69SBart Van Assche             if (realms_count < 1)
565*44704f69SBart Van Assche                 pr2serr("realms_count is zero\n");
566*44704f69SBart Van Assche             else if (r_desc_len < 16)
567*44704f69SBart Van Assche                 pr2serr("realms descriptor length less than 16\n");
568*44704f69SBart Van Assche             else
569*44704f69SBart Van Assche                 pr2serr("actual_length (%u) too short\n", act_len);
570*44704f69SBart Van Assche         }
571*44704f69SBart Van Assche         return 0;
572*44704f69SBart Van Assche     }
573*44704f69SBart Van Assche     derived_realms_count = (act_len - 64) / r_desc_len;
574*44704f69SBart Van Assche     if (derived_realms_count > realms_count) {
575*44704f69SBart Van Assche         if (op->vb)
576*44704f69SBart Van Assche             pr2serr("%s: derived_realms_count [%u] > realms_count [%u]\n",
577*44704f69SBart Van Assche                     __func__, derived_realms_count, realms_count);
578*44704f69SBart Van Assche     } else if (derived_realms_count < realms_count) {
579*44704f69SBart Van Assche         if (op->vb)
580*44704f69SBart Van Assche             pr2serr("%s: derived_realms_count [%u] < realms_count [%u], "
581*44704f69SBart Van Assche                     "use former\n", __func__, derived_realms_count,
582*44704f69SBart Van Assche                     realms_count);
583*44704f69SBart Van Assche         realms_count = derived_realms_count;
584*44704f69SBart Van Assche     }
585*44704f69SBart Van Assche     zdomains_count = (r_desc_len - 16) / 16;
586*44704f69SBart Van Assche 
587*44704f69SBart Van Assche     if (op->do_num > 0)
588*44704f69SBart Van Assche             realms_count = (realms_count > (uint32_t)op->do_num) ?
589*44704f69SBart Van Assche                                 (uint32_t)op->do_num : realms_count;
590*44704f69SBart Van Assche     jap = sgj_named_subarray_r(jsp, jop, "realm_descriptors_list");
591*44704f69SBart Van Assche 
592*44704f69SBart Van Assche     for (k = 0, bp = rzBuff + 64; k < realms_count; ++k, bp += r_desc_len) {
593*44704f69SBart Van Assche         uint32_t j;
594*44704f69SBart Van Assche         uint16_t restrictions;
595*44704f69SBart Van Assche         const uint8_t * zp;
596*44704f69SBart Van Assche         sgj_opaque_p jo2p;
597*44704f69SBart Van Assche 
598*44704f69SBart Van Assche         jo2p = sgj_new_unattached_object_r(jsp);
599*44704f69SBart Van Assche         sgj_haj_vi(jsp, jo2p, 1, "Realms_id", SGJ_SEP_EQUAL_NO_SPACE,
600*44704f69SBart Van Assche                    sg_get_unaligned_be32(bp + 0), true);
601*44704f69SBart Van Assche         if (op->do_hex) {
602*44704f69SBart Van Assche             hex2stdout(bp, r_desc_len, -1);
603*44704f69SBart Van Assche             continue;
604*44704f69SBart Van Assche         }
605*44704f69SBart Van Assche         restrictions = sg_get_unaligned_be16(bp + 4);
606*44704f69SBart Van Assche         sgj_pr_hr(jsp, "   realm_restrictions=0x%hu\n", restrictions);
607*44704f69SBart Van Assche         sgj_js_nv_ihex(jsp, jo2p, "realm_restrictions", restrictions);
608*44704f69SBart Van Assche         sgj_haj_vi(jsp, jo2p, 3, "active_zone_domain_id",
609*44704f69SBart Van Assche                    SGJ_SEP_EQUAL_NO_SPACE, bp[7], true);
610*44704f69SBart Van Assche 
611*44704f69SBart Van Assche         ja2p = sgj_named_subarray_r(jsp, jo2p,
612*44704f69SBart Van Assche                                     "realm_start_end_descriptors_list");
613*44704f69SBart Van Assche         for (j = 0, zp = bp + 16; j < zdomains_count; ++j, zp += 16) {
614*44704f69SBart Van Assche             uint64_t lba;
615*44704f69SBart Van Assche             sgj_opaque_p jo3p;
616*44704f69SBart Van Assche 
617*44704f69SBart Van Assche             jo3p = sgj_new_unattached_object_r(jsp);
618*44704f69SBart Van Assche             sgj_pr_hr(jsp, "   zone_domain=%u\n", j);
619*44704f69SBart Van Assche             sgj_js_nv_i(jsp, jo3p, "corresponding_zone_domain_id", j);
620*44704f69SBart Van Assche             lba = sg_get_unaligned_be64(zp + 0);
621*44704f69SBart Van Assche             sgj_pr_hr(jsp, "     starting_lba=0x%" PRIx64 "\n", lba);
622*44704f69SBart Van Assche             sgj_js_nv_ihex(jsp, jo3p, "realm_starting_lba", (int64_t)lba);
623*44704f69SBart Van Assche             lba = sg_get_unaligned_be64(zp + 8);
624*44704f69SBart Van Assche             sgj_pr_hr(jsp, "     ending_lba=0x%" PRIx64 "\n", lba);
625*44704f69SBart Van Assche             sgj_js_nv_ihex(jsp, jo3p, "realm_ending_lba", (int64_t)lba);
626*44704f69SBart Van Assche             sgj_js_nv_o(jsp, ja2p, NULL /* name */, jo3p);
627*44704f69SBart Van Assche         }
628*44704f69SBart Van Assche         sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p);
629*44704f69SBart Van Assche     }
630*44704f69SBart Van Assche     return 0;
631*44704f69SBart Van Assche }
632*44704f69SBart Van Assche 
633*44704f69SBart Van Assche static int
decode_rep_zdomains(const uint8_t * rzBuff,int act_len,const struct opts_t * op,sgj_state * jsp)634*44704f69SBart Van Assche decode_rep_zdomains(const uint8_t * rzBuff, int act_len,
635*44704f69SBart Van Assche                    const struct opts_t * op, sgj_state * jsp)
636*44704f69SBart Van Assche {
637*44704f69SBart Van Assche     uint32_t k, zd_len, zd_ret_len, zdoms_sup, zdoms_rep, zd_rep_opts;
638*44704f69SBart Van Assche     uint32_t num, der_zdoms;
639*44704f69SBart Van Assche     uint64_t zd_locator;
640*44704f69SBart Van Assche     sgj_opaque_p jop = jsp ? jsp->basep : NULL;
641*44704f69SBart Van Assche     sgj_opaque_p jap = NULL;
642*44704f69SBart Van Assche     const uint8_t * bp;
643*44704f69SBart Van Assche 
644*44704f69SBart Van Assche     if (act_len < 12) {
645*44704f69SBart Van Assche         pr2serr("need more than 12 bytes to decode, got %u\n", act_len);
646*44704f69SBart Van Assche         return SG_LIB_CAT_MALFORMED;
647*44704f69SBart Van Assche     }
648*44704f69SBart Van Assche     zd_len = sg_get_unaligned_be32(rzBuff + 0);
649*44704f69SBart Van Assche     zd_ret_len = sg_get_unaligned_be32(rzBuff + 4);
650*44704f69SBart Van Assche     zdoms_sup = rzBuff[8];
651*44704f69SBart Van Assche     zdoms_rep = rzBuff[9];
652*44704f69SBart Van Assche     zd_rep_opts = rzBuff[10];
653*44704f69SBart Van Assche     if (act_len < 24)
654*44704f69SBart Van Assche         zd_locator = sg_get_unaligned_be64(rzBuff + 16);
655*44704f69SBart Van Assche     else
656*44704f69SBart Van Assche         zd_locator = 0;
657*44704f69SBart Van Assche     sgj_haj_vi(jsp, jop, 0, "Zone_domains_returned_list_length=",
658*44704f69SBart Van Assche                SGJ_SEP_EQUAL_NO_SPACE, zd_ret_len, true);
659*44704f69SBart Van Assche     sgj_haj_vi(jsp, jop, 0, "Zone_domains_supported",
660*44704f69SBart Van Assche                SGJ_SEP_EQUAL_NO_SPACE, zdoms_sup, true);
661*44704f69SBart Van Assche     sgj_haj_vi(jsp, jop, 0, "Zone_domains_reported",
662*44704f69SBart Van Assche                SGJ_SEP_EQUAL_NO_SPACE, zdoms_rep, true);
663*44704f69SBart Van Assche     sgj_pr_hr(jsp, "Reporting_options=0x%x\n", zd_rep_opts);
664*44704f69SBart Van Assche     sgj_js_nv_ihex(jsp, jop, "Reporting_options", zd_rep_opts);
665*44704f69SBart Van Assche     sgj_pr_hr(jsp, "Zone_domain_locator=0x%" PRIx64 "\n", zd_locator);
666*44704f69SBart Van Assche     sgj_js_nv_ihex(jsp, jop, "Zone_domain_locator", zd_locator);
667*44704f69SBart Van Assche 
668*44704f69SBart Van Assche     der_zdoms = zd_len / 96;
669*44704f69SBart Van Assche     if (op->vb > 1)
670*44704f69SBart Van Assche         pr2serr("Derived zdomains=%u\n", der_zdoms);
671*44704f69SBart Van Assche     num = ((der_zdoms < zdoms_rep) ? der_zdoms : zdoms_rep) * 96;
672*44704f69SBart Van Assche     jap = sgj_named_subarray_r(jsp, jop, "zone_domain_descriptors_list");
673*44704f69SBart Van Assche 
674*44704f69SBart Van Assche     for (k = 0, bp = rzBuff + 64; k < num; k += 96, bp += 96) {
675*44704f69SBart Van Assche         uint64_t lba;
676*44704f69SBart Van Assche         sgj_opaque_p jo2p;
677*44704f69SBart Van Assche 
678*44704f69SBart Van Assche         jo2p = sgj_new_unattached_object_r(jsp);
679*44704f69SBart Van Assche         sgj_haj_vi(jsp, jo2p, 3, "zone_domain",
680*44704f69SBart Van Assche                    SGJ_SEP_EQUAL_NO_SPACE, bp[0], true);
681*44704f69SBart Van Assche         lba = sg_get_unaligned_be64(bp + 16);
682*44704f69SBart Van Assche         sgj_pr_hr(jsp, "     zone_count=%" PRIu64 "\n", lba);
683*44704f69SBart Van Assche         sgj_js_nv_ihex(jsp, jo2p, "zone_count", lba);
684*44704f69SBart Van Assche         lba = sg_get_unaligned_be64(bp + 24);
685*44704f69SBart Van Assche         sgj_pr_hr(jsp, "     starting_lba=0x%" PRIx64 "\n", lba);
686*44704f69SBart Van Assche         sgj_js_nv_ihex(jsp, jo2p, "starting_lba", lba);
687*44704f69SBart Van Assche         lba = sg_get_unaligned_be64(bp + 32);
688*44704f69SBart Van Assche         sgj_pr_hr(jsp, "     ending_lba=0x%" PRIx64 "\n", lba);
689*44704f69SBart Van Assche         sgj_js_nv_ihex(jsp, jo2p, "ending_lba", lba);
690*44704f69SBart Van Assche         sgj_pr_hr(jsp, "     zone_domain_zone_type=0x%x\n", bp[40]);
691*44704f69SBart Van Assche         sgj_js_nv_ihex(jsp, jo2p, "zone_domain_zone_type", bp[40]);
692*44704f69SBart Van Assche         sgj_haj_vi(jsp, jo2p, 5, "VZDZT", SGJ_SEP_EQUAL_NO_SPACE,
693*44704f69SBart Van Assche                    !!(0x2 & bp[42]), false);
694*44704f69SBart Van Assche         sgj_haj_vi(jsp, jo2p, 5, "SRB", SGJ_SEP_EQUAL_NO_SPACE,
695*44704f69SBart Van Assche                    !!(0x1 & bp[42]), false);
696*44704f69SBart Van Assche         sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p);
697*44704f69SBart Van Assche     }
698*44704f69SBart Van Assche     return 0;
699*44704f69SBart Van Assche }
700*44704f69SBart Van Assche 
701*44704f69SBart Van Assche static int
find_report_zones(int sg_fd,uint8_t * rzBuff,const char * cmd_name,struct opts_t * op,sgj_state * jsp)702*44704f69SBart Van Assche find_report_zones(int sg_fd, uint8_t * rzBuff, const char * cmd_name,
703*44704f69SBart Van Assche                   struct opts_t * op, sgj_state * jsp)
704*44704f69SBart Van Assche {
705*44704f69SBart Van Assche     bool as_json = (jsp && (0 == op->do_hex)) ?  jsp->pr_as_json : false;
706*44704f69SBart Van Assche     bool found = false;
707*44704f69SBart Van Assche     uint8_t zt;
708*44704f69SBart Van Assche     int k, res, resid, rlen, num_zd, num_rem;
709*44704f69SBart Van Assche     uint32_t zn_dnum = 0;
710*44704f69SBart Van Assche     uint64_t slba = op->st_lba;
711*44704f69SBart Van Assche     uint64_t mx_lba = 0;
712*44704f69SBart Van Assche     const uint8_t * bp = rzBuff;
713*44704f69SBart Van Assche     char b[96];
714*44704f69SBart Van Assche 
715*44704f69SBart Van Assche     num_rem = op->do_num ? op->do_num : INT_MAX;
716*44704f69SBart Van Assche     for ( ; num_rem > 0; num_rem -= num_zd) {
717*44704f69SBart Van Assche         resid = 0;
718*44704f69SBart Van Assche         if (sg_fd >= 0) {
719*44704f69SBart Van Assche             res = sg_ll_report_zzz(sg_fd, REPORT_ZONES_SA, slba,
720*44704f69SBart Van Assche                                    true /* set partial */, op->reporting_opt,
721*44704f69SBart Van Assche                                    rzBuff, op->maxlen, &resid, true, op->vb);
722*44704f69SBart Van Assche             if (res) {
723*44704f69SBart Van Assche                 if (SG_LIB_CAT_INVALID_OP == res)
724*44704f69SBart Van Assche                     pr2serr("%s: %s%u, %s command not supported\n", __func__,
725*44704f69SBart Van Assche                             zn_dnum_s, zn_dnum, cmd_name);
726*44704f69SBart Van Assche                 else {
727*44704f69SBart Van Assche                     sg_get_category_sense_str(res, sizeof(b), b, op->vb);
728*44704f69SBart Van Assche                     pr2serr("%s: %s%u, %s command: %s\n", __func__,
729*44704f69SBart Van Assche                             zn_dnum_s, zn_dnum, cmd_name, b);
730*44704f69SBart Van Assche                 }
731*44704f69SBart Van Assche                 break;
732*44704f69SBart Van Assche             }
733*44704f69SBart Van Assche         } else
734*44704f69SBart Van Assche             res = 0;
735*44704f69SBart Van Assche         rlen = op->maxlen - resid;
736*44704f69SBart Van Assche         if (rlen <= 64)
737*44704f69SBart Van Assche             break;
738*44704f69SBart Van Assche         mx_lba = sg_get_unaligned_be64(rzBuff + 8);
739*44704f69SBart Van Assche         num_zd = (rlen - 64) / REPORT_ZONES_DESC_LEN;
740*44704f69SBart Van Assche         if (num_zd > num_rem)
741*44704f69SBart Van Assche             num_zd = num_rem;
742*44704f69SBart Van Assche         for (k = 0, bp = rzBuff + 64; k < num_zd;
743*44704f69SBart Van Assche              ++k, bp += REPORT_ZONES_DESC_LEN, ++zn_dnum) {
744*44704f69SBart Van Assche             zt = 0xf & bp[0];
745*44704f69SBart Van Assche             if (op->find_zt > 0) {
746*44704f69SBart Van Assche                 if ((uint8_t)op->find_zt == zt )
747*44704f69SBart Van Assche                     break;
748*44704f69SBart Van Assche             } else if (op->find_zt < 0) {
749*44704f69SBart Van Assche                 if ((uint8_t)(-op->find_zt) != zt )
750*44704f69SBart Van Assche                     break;
751*44704f69SBart Van Assche             }
752*44704f69SBart Van Assche             slba = sg_get_unaligned_be64(bp + 16) +
753*44704f69SBart Van Assche                    sg_get_unaligned_be64(bp + 8);
754*44704f69SBart Van Assche         }
755*44704f69SBart Van Assche         if (k < num_zd) {
756*44704f69SBart Van Assche             found = true;
757*44704f69SBart Van Assche             break;
758*44704f69SBart Van Assche         } else if ((slba > mx_lba) || (sg_fd < 0))
759*44704f69SBart Van Assche             break;
760*44704f69SBart Van Assche     }           /* end of outer for loop */
761*44704f69SBart Van Assche     if (res == 0) {
762*44704f69SBart Van Assche         sgj_opaque_p jo2p = as_json ?
763*44704f69SBart Van Assche                 sgj_named_subobject_r(jsp, NULL, "find_condition") : NULL;
764*44704f69SBart Van Assche 
765*44704f69SBart Van Assche         if (found) {
766*44704f69SBart Van Assche             if (op->do_hex) {
767*44704f69SBart Van Assche                 hex2stdout(rzBuff, 64, -1);
768*44704f69SBart Van Assche                 printf("\n");
769*44704f69SBart Van Assche                 hex2stdout(bp, 64, -1);
770*44704f69SBart Van Assche             } else {
771*44704f69SBart Van Assche                 sgj_pr_hr(jsp, "Condition met at:\n");
772*44704f69SBart Van Assche                 sgj_pr_hr(jsp, " %s: %d\n", zn_dnum_s, zn_dnum);
773*44704f69SBart Van Assche                 sgj_js_nv_b(jsp, jo2p, "met", true);
774*44704f69SBart Van Assche                 sgj_js_nv_i(jsp, jo2p, "zone_descriptor_index", zn_dnum);
775*44704f69SBart Van Assche                 prt_a_zn_desc(bp, op, jsp, jo2p);
776*44704f69SBart Van Assche             }
777*44704f69SBart Van Assche         } else {
778*44704f69SBart Van Assche             if (op->do_hex) {
779*44704f69SBart Van Assche                 memset(b, 0xff, 64);
780*44704f69SBart Van Assche                 hex2stdout((const uint8_t *)b, 64, -1);
781*44704f69SBart Van Assche             } else {
782*44704f69SBart Van Assche                 sgj_js_nv_b(jsp, jo2p, "met", false);
783*44704f69SBart Van Assche                 sgj_js_nv_i(jsp, jo2p, "zone_descriptor_index", zn_dnum);
784*44704f69SBart Van Assche                 if (num_rem < 1)
785*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "Condition NOT met, checked %d zones; "
786*44704f69SBart Van Assche                               "next %s%u\n", op->do_num, zn_dnum_s, zn_dnum);
787*44704f69SBart Van Assche                 else
788*44704f69SBart Van Assche                     sgj_pr_hr(jsp, "Condition NOT met; next %s%u\n",
789*44704f69SBart Van Assche                               zn_dnum_s, zn_dnum);
790*44704f69SBart Van Assche             }
791*44704f69SBart Van Assche         }
792*44704f69SBart Van Assche     }
793*44704f69SBart Van Assche     return res;
794*44704f69SBart Van Assche }
795*44704f69SBart Van Assche 
796*44704f69SBart Van Assche struct statistics_t {
797*44704f69SBart Van Assche     uint32_t zt_conv_num;
798*44704f69SBart Van Assche     uint32_t zt_swr_num;
799*44704f69SBart Van Assche     uint32_t zt_swp_num;
800*44704f69SBart Van Assche     uint32_t zt_sob_num;
801*44704f69SBart Van Assche     uint32_t zt_gap_num;
802*44704f69SBart Van Assche     uint32_t zt_unk_num;
803*44704f69SBart Van Assche 
804*44704f69SBart Van Assche     uint32_t zc_nwp_num;
805*44704f69SBart Van Assche     uint32_t zc_mt_num;
806*44704f69SBart Van Assche     uint32_t zc_iop_num;
807*44704f69SBart Van Assche     uint32_t zc_eop_num;
808*44704f69SBart Van Assche     uint32_t zc_cl_num;
809*44704f69SBart Van Assche     uint32_t zc_ina_num;
810*44704f69SBart Van Assche     uint32_t zc_ro_num;
811*44704f69SBart Van Assche     uint32_t zc_full_num;
812*44704f69SBart Van Assche     uint32_t zc_off_num;
813*44704f69SBart Van Assche     uint32_t zc_unk_num;
814*44704f69SBart Van Assche 
815*44704f69SBart Van Assche     /* The following LBAs have 1 added to them, initialized to 0 */
816*44704f69SBart Van Assche     uint64_t zt_swr_1st_lba1;
817*44704f69SBart Van Assche     uint64_t zt_swp_1st_lba1;
818*44704f69SBart Van Assche     uint64_t zt_sob_1st_lba1;
819*44704f69SBart Van Assche     uint64_t zt_gap_1st_lba1;
820*44704f69SBart Van Assche 
821*44704f69SBart Van Assche     uint64_t zc_nwp_1st_lba1;
822*44704f69SBart Van Assche     uint64_t zc_mt_1st_lba1;
823*44704f69SBart Van Assche     uint64_t zc_iop_1st_lba1;
824*44704f69SBart Van Assche     uint64_t zc_eop_1st_lba1;
825*44704f69SBart Van Assche     uint64_t zc_cl_1st_lba1;
826*44704f69SBart Van Assche     uint64_t zc_ina_1st_lba1;
827*44704f69SBart Van Assche     uint64_t zc_ro_1st_lba1;
828*44704f69SBart Van Assche     uint64_t zc_full_1st_lba1;
829*44704f69SBart Van Assche     uint64_t zc_off_1st_lba1;
830*44704f69SBart Van Assche 
831*44704f69SBart Van Assche     uint64_t wp_max_lba1;       /* ... that isn't Zone start LBA */
832*44704f69SBart Van Assche     uint64_t wp_blk_num;        /* sum of (zwp - zs_lba) */
833*44704f69SBart Van Assche     uint64_t conv_blk_num;      /* sum of (z_blks) of zt=conv */
834*44704f69SBart Van Assche };
835*44704f69SBart Van Assche 
836*44704f69SBart Van Assche static int
gather_statistics(int sg_fd,uint8_t * rzBuff,const char * cmd_name,struct opts_t * op)837*44704f69SBart Van Assche gather_statistics(int sg_fd, uint8_t * rzBuff, const char * cmd_name,
838*44704f69SBart Van Assche                   struct opts_t * op)
839*44704f69SBart Van Assche {
840*44704f69SBart Van Assche     uint8_t zt, zc;
841*44704f69SBart Van Assche     int k, res, resid, rlen, num_zd, num_rem;
842*44704f69SBart Van Assche     uint32_t zn_dnum = 0;
843*44704f69SBart Van Assche     uint64_t slba = op->st_lba;
844*44704f69SBart Van Assche     uint64_t mx_lba = 0;
845*44704f69SBart Van Assche     uint64_t zs_lba, zwp, z_blks;
846*44704f69SBart Van Assche     const uint8_t * bp = rzBuff;
847*44704f69SBart Van Assche     struct statistics_t st SG_C_CPP_ZERO_INIT;
848*44704f69SBart Van Assche     char b[96];
849*44704f69SBart Van Assche 
850*44704f69SBart Van Assche     if (op->serv_act != REPORT_ZONES_SA) {
851*44704f69SBart Van Assche         pr2serr("%s: do not support statistics for %s yet\n", __func__,
852*44704f69SBart Van Assche                 cmd_name);
853*44704f69SBart Van Assche         return SG_LIB_SYNTAX_ERROR;
854*44704f69SBart Van Assche     }
855*44704f69SBart Van Assche 
856*44704f69SBart Van Assche     num_rem = op->do_num ? op->do_num : INT_MAX;
857*44704f69SBart Van Assche     for ( ; num_rem > 0; num_rem -= num_zd) {
858*44704f69SBart Van Assche         resid = 0;
859*44704f69SBart Van Assche         zs_lba = slba;
860*44704f69SBart Van Assche         if (sg_fd >= 0) {
861*44704f69SBart Van Assche             res = sg_ll_report_zzz(sg_fd, REPORT_ZONES_SA, slba,
862*44704f69SBart Van Assche                                    true /* set partial */, op->reporting_opt,
863*44704f69SBart Van Assche                                    rzBuff, op->maxlen, &resid, true, op->vb);
864*44704f69SBart Van Assche             if (res) {
865*44704f69SBart Van Assche                 if (SG_LIB_CAT_INVALID_OP == res)
866*44704f69SBart Van Assche                     pr2serr("%s: %s%u, %s command not supported\n", __func__,
867*44704f69SBart Van Assche                             zn_dnum_s, zn_dnum, cmd_name);
868*44704f69SBart Van Assche                 else {
869*44704f69SBart Van Assche                     sg_get_category_sense_str(res, sizeof(b), b, op->vb);
870*44704f69SBart Van Assche                     pr2serr("%s: %s%u, %s command: %s\n", __func__,
871*44704f69SBart Van Assche                             zn_dnum_s, zn_dnum, cmd_name, b);
872*44704f69SBart Van Assche                 }
873*44704f69SBart Van Assche                 break;
874*44704f69SBart Van Assche             }
875*44704f69SBart Van Assche         } else
876*44704f69SBart Van Assche             res = 0;
877*44704f69SBart Van Assche         rlen = op->maxlen - resid;
878*44704f69SBart Van Assche         if (rlen <= 64) {
879*44704f69SBart Van Assche             break;
880*44704f69SBart Van Assche         }
881*44704f69SBart Van Assche         mx_lba = sg_get_unaligned_be64(rzBuff + 8);
882*44704f69SBart Van Assche         num_zd = (rlen - 64) / REPORT_ZONES_DESC_LEN;
883*44704f69SBart Van Assche         if (num_zd > num_rem)
884*44704f69SBart Van Assche             num_zd = num_rem;
885*44704f69SBart Van Assche         for (k = 0, bp = rzBuff + 64; k < num_zd;
886*44704f69SBart Van Assche              ++k, bp += REPORT_ZONES_DESC_LEN, ++zn_dnum) {
887*44704f69SBart Van Assche             z_blks = sg_get_unaligned_be64(bp + 8);
888*44704f69SBart Van Assche             zs_lba = sg_get_unaligned_be64(bp + 16);
889*44704f69SBart Van Assche             zwp = sg_get_unaligned_be64(bp + 24);
890*44704f69SBart Van Assche             zt = 0xf & bp[0];
891*44704f69SBart Van Assche             switch (zt) {
892*44704f69SBart Van Assche             case 1:     /* conventional */
893*44704f69SBart Van Assche                 ++st.zt_conv_num;
894*44704f69SBart Van Assche                 st.conv_blk_num += z_blks;
895*44704f69SBart Van Assche                 break;
896*44704f69SBart Van Assche             case 2:     /* sequential write required */
897*44704f69SBart Van Assche                 ++st.zt_swr_num;
898*44704f69SBart Van Assche                 if (0 == st.zt_swr_1st_lba1)
899*44704f69SBart Van Assche                     st.zt_swr_1st_lba1 = zs_lba + 1;
900*44704f69SBart Van Assche                 break;
901*44704f69SBart Van Assche             case 3:     /* sequential write preferred */
902*44704f69SBart Van Assche                 ++st.zt_swp_num;
903*44704f69SBart Van Assche                 if (0 == st.zt_swp_1st_lba1)
904*44704f69SBart Van Assche                     st.zt_swp_1st_lba1 = zs_lba + 1;
905*44704f69SBart Van Assche                 break;
906*44704f69SBart Van Assche             case 4:     /* sequential or before (write) */
907*44704f69SBart Van Assche                 ++st.zt_sob_num;
908*44704f69SBart Van Assche                 if (0 == st.zt_sob_1st_lba1)
909*44704f69SBart Van Assche                     st.zt_sob_1st_lba1 = zs_lba + 1;
910*44704f69SBart Van Assche                 break;
911*44704f69SBart Van Assche             case 5:     /* gap */
912*44704f69SBart Van Assche                 ++st.zt_gap_num;
913*44704f69SBart Van Assche                 if (0 == st.zt_gap_1st_lba1)
914*44704f69SBart Van Assche                     st.zt_gap_1st_lba1 = zs_lba + 1;
915*44704f69SBart Van Assche                 break;
916*44704f69SBart Van Assche             default:
917*44704f69SBart Van Assche                 ++st.zt_unk_num;
918*44704f69SBart Van Assche                 break;
919*44704f69SBart Van Assche             }
920*44704f69SBart Van Assche             zc = (bp[1] >> 4) & 0xf;
921*44704f69SBart Van Assche             switch (zc) {
922*44704f69SBart Van Assche             case 0:     /* not write pointer (zone) */
923*44704f69SBart Van Assche                 ++st.zc_nwp_num;
924*44704f69SBart Van Assche                 if (0 == st.zc_nwp_1st_lba1)
925*44704f69SBart Van Assche                     st.zc_nwp_1st_lba1 = zs_lba + 1;
926*44704f69SBart Van Assche                 break;
927*44704f69SBart Van Assche             case 1:     /* empty */
928*44704f69SBart Van Assche                 ++st.zc_mt_num;
929*44704f69SBart Van Assche                 if (0 == st.zc_mt_1st_lba1)
930*44704f69SBart Van Assche                     st.zc_mt_1st_lba1 = zs_lba + 1;
931*44704f69SBart Van Assche                 break;
932*44704f69SBart Van Assche             case 2:     /* implicitly opened */
933*44704f69SBart Van Assche                 ++st.zc_iop_num;
934*44704f69SBart Van Assche                 if (0 == st.zc_iop_1st_lba1)
935*44704f69SBart Van Assche                     st.zc_iop_1st_lba1 = zs_lba + 1;
936*44704f69SBart Van Assche                 if (zwp > zs_lba) {
937*44704f69SBart Van Assche                     st.wp_max_lba1 = zwp + 1;
938*44704f69SBart Van Assche                     st.wp_blk_num += zwp - zs_lba;
939*44704f69SBart Van Assche                 }
940*44704f69SBart Van Assche                 break;
941*44704f69SBart Van Assche             case 3:     /* explicitly opened */
942*44704f69SBart Van Assche                 ++st.zc_eop_num;
943*44704f69SBart Van Assche                 if (0 == st.zc_eop_1st_lba1)
944*44704f69SBart Van Assche                     st.zc_eop_1st_lba1 = zs_lba + 1;
945*44704f69SBart Van Assche                 if (zwp > zs_lba) {
946*44704f69SBart Van Assche                     st.wp_max_lba1 = zwp + 1;
947*44704f69SBart Van Assche                     st.wp_blk_num += zwp - zs_lba;
948*44704f69SBart Van Assche                 }
949*44704f69SBart Van Assche                 break;
950*44704f69SBart Van Assche             case 4:     /* closed */
951*44704f69SBart Van Assche                 ++st.zc_cl_num;
952*44704f69SBart Van Assche                 if (0 == st.zc_cl_1st_lba1)
953*44704f69SBart Van Assche                     st.zc_cl_1st_lba1 = zs_lba + 1;
954*44704f69SBart Van Assche                 if (zwp > zs_lba) {
955*44704f69SBart Van Assche                     st.wp_max_lba1 = zwp + 1;
956*44704f69SBart Van Assche                     st.wp_blk_num += zwp - zs_lba;
957*44704f69SBart Van Assche                 }
958*44704f69SBart Van Assche                 break;
959*44704f69SBart Van Assche             case 5:     /* inactive */
960*44704f69SBart Van Assche                 ++st.zc_ina_num;
961*44704f69SBart Van Assche                 if (0 == st.zc_ina_1st_lba1)
962*44704f69SBart Van Assche                     st.zc_ina_1st_lba1 = zs_lba + 1;
963*44704f69SBart Van Assche                 break;
964*44704f69SBart Van Assche             case 0xd:   /* read-only */
965*44704f69SBart Van Assche                 ++st.zc_ro_num;
966*44704f69SBart Van Assche                 if (0 == st.zc_ro_1st_lba1)
967*44704f69SBart Van Assche                     st.zc_ro_1st_lba1 = zs_lba + 1;
968*44704f69SBart Van Assche                 break;
969*44704f69SBart Van Assche             case 0xe:   /* full */
970*44704f69SBart Van Assche                 ++st.zc_full_num;
971*44704f69SBart Van Assche                 if (0 == st.zc_full_1st_lba1)
972*44704f69SBart Van Assche                     st.zc_full_1st_lba1 = zs_lba + 1;
973*44704f69SBart Van Assche                 st.wp_blk_num += z_blks;
974*44704f69SBart Van Assche                 break;
975*44704f69SBart Van Assche             case 0xf:   /* offline */
976*44704f69SBart Van Assche                 ++st.zc_off_num;
977*44704f69SBart Van Assche                 if (0 == st.zc_off_1st_lba1)
978*44704f69SBart Van Assche                     st.zc_off_1st_lba1 = zs_lba + 1;
979*44704f69SBart Van Assche                 break;
980*44704f69SBart Van Assche             default:
981*44704f69SBart Van Assche                 ++st.zc_unk_num;
982*44704f69SBart Van Assche                 break;
983*44704f69SBart Van Assche             }
984*44704f69SBart Van Assche             slba = zs_lba + z_blks;
985*44704f69SBart Van Assche         }       /* end of inner for loop */
986*44704f69SBart Van Assche         if ((slba > mx_lba) || (sg_fd < 0))
987*44704f69SBart Van Assche             break;
988*44704f69SBart Van Assche     }           /* end of outer for loop */
989*44704f69SBart Van Assche     printf("Number of conventional type zones: %u\n", st.zt_conv_num);
990*44704f69SBart Van Assche     if (st.zt_swr_num > 0)
991*44704f69SBart Van Assche         printf("Number of sequential write required type zones: %u\n",
992*44704f69SBart Van Assche                st.zt_swr_num);
993*44704f69SBart Van Assche     if (st.zt_swr_1st_lba1 > 0)
994*44704f69SBart Van Assche         printf("    Lowest starting LBA: 0x%" PRIx64 "\n",
995*44704f69SBart Van Assche               st.zt_swr_1st_lba1 - 1);
996*44704f69SBart Van Assche     if (st.zt_swp_num > 0)
997*44704f69SBart Van Assche         printf("Number of sequential write preferred type zones: %u\n",
998*44704f69SBart Van Assche                st.zt_swp_num);
999*44704f69SBart Van Assche     if (st.zt_swp_1st_lba1 > 0)
1000*44704f69SBart Van Assche         printf("    Lowest starting LBA: 0x%" PRIx64 "\n",
1001*44704f69SBart Van Assche               st.zt_swp_1st_lba1 - 1);
1002*44704f69SBart Van Assche     if (st.zt_sob_num > 0)
1003*44704f69SBart Van Assche         printf("Number of sequential or before type zones: %u\n",
1004*44704f69SBart Van Assche                st.zt_sob_num);
1005*44704f69SBart Van Assche     if (st.zt_sob_1st_lba1 > 0)
1006*44704f69SBart Van Assche         printf("    Lowest starting LBA: 0x%" PRIx64 "\n",
1007*44704f69SBart Van Assche               st.zt_sob_1st_lba1 - 1);
1008*44704f69SBart Van Assche     if (st.zt_gap_num > 0)
1009*44704f69SBart Van Assche         printf("Number of gap type zones: %u\n", st.zt_gap_num);
1010*44704f69SBart Van Assche     if (st.zt_gap_1st_lba1 > 0)
1011*44704f69SBart Van Assche         printf("    Lowest starting LBA: 0x%" PRIx64 "\n",
1012*44704f69SBart Van Assche               st.zt_gap_1st_lba1 - 1);
1013*44704f69SBart Van Assche     if (st.zt_unk_num > 0)
1014*44704f69SBart Van Assche         printf("Number of unknown type zones: %u\n", st.zt_unk_num);
1015*44704f69SBart Van Assche 
1016*44704f69SBart Van Assche     printf("Number of 'not write pointer' condition zones: %u\n",
1017*44704f69SBart Van Assche            st.zc_nwp_num);
1018*44704f69SBart Van Assche     if (st.zc_nwp_1st_lba1 > 0)
1019*44704f69SBart Van Assche         printf("    Lowest starting LBA: 0x%" PRIx64 "\n",
1020*44704f69SBart Van Assche               st.zc_nwp_1st_lba1 - 1);
1021*44704f69SBart Van Assche     printf("Number of empty condition zones: %u\n", st.zc_mt_num);
1022*44704f69SBart Van Assche     if (st.zc_mt_1st_lba1 > 0)
1023*44704f69SBart Van Assche         printf("    Lowest starting LBA: 0x%" PRIx64 "\n",
1024*44704f69SBart Van Assche               st.zc_mt_1st_lba1 - 1);
1025*44704f69SBart Van Assche     if (st.zc_iop_num > 0)
1026*44704f69SBart Van Assche         printf("Number of implicitly open condition zones: %u\n",
1027*44704f69SBart Van Assche                st.zc_iop_num);
1028*44704f69SBart Van Assche     if (st.zc_iop_1st_lba1 > 0)
1029*44704f69SBart Van Assche         printf("    Lowest starting LBA: 0x%" PRIx64 "\n",
1030*44704f69SBart Van Assche               st.zc_iop_1st_lba1 - 1);
1031*44704f69SBart Van Assche     if (st.zc_eop_num)
1032*44704f69SBart Van Assche         printf("Number of explicitly open condition zones: %u\n",
1033*44704f69SBart Van Assche                st.zc_eop_num);
1034*44704f69SBart Van Assche     if (st.zc_eop_1st_lba1 > 0)
1035*44704f69SBart Van Assche         printf("    Lowest starting LBA: 0x%" PRIx64 "\n",
1036*44704f69SBart Van Assche               st.zc_eop_1st_lba1 - 1);
1037*44704f69SBart Van Assche     if (st.zc_cl_num)
1038*44704f69SBart Van Assche         printf("Number of closed condition zones: %u\n", st.zc_cl_num);
1039*44704f69SBart Van Assche     if (st.zc_cl_1st_lba1 > 0)
1040*44704f69SBart Van Assche         printf("    Lowest starting LBA: 0x%" PRIx64 "\n",
1041*44704f69SBart Van Assche               st.zc_cl_1st_lba1 - 1);
1042*44704f69SBart Van Assche     if (st.zc_ina_num)
1043*44704f69SBart Van Assche         printf("Number of inactive condition zones: %u\n", st.zc_ina_num);
1044*44704f69SBart Van Assche     if (st.zc_ina_1st_lba1 > 0)
1045*44704f69SBart Van Assche         printf("    Lowest starting LBA: 0x%" PRIx64 "\n",
1046*44704f69SBart Van Assche               st.zc_ina_1st_lba1 - 1);
1047*44704f69SBart Van Assche     if (st.zc_ro_num)
1048*44704f69SBart Van Assche         printf("Number of inactive condition zones: %u\n", st.zc_ro_num);
1049*44704f69SBart Van Assche     if (st.zc_ro_1st_lba1 > 0)
1050*44704f69SBart Van Assche         printf("    Lowest starting LBA: 0x%" PRIx64 "\n",
1051*44704f69SBart Van Assche               st.zc_ro_1st_lba1 - 1);
1052*44704f69SBart Van Assche     if (st.zc_full_num)
1053*44704f69SBart Van Assche         printf("Number of full condition zones: %u\n", st.zc_full_num);
1054*44704f69SBart Van Assche     if (st.zc_full_1st_lba1 > 0)
1055*44704f69SBart Van Assche         printf("    Lowest starting LBA: 0x%" PRIx64 "\n",
1056*44704f69SBart Van Assche               st.zc_full_1st_lba1 - 1);
1057*44704f69SBart Van Assche     if (st.zc_off_num)
1058*44704f69SBart Van Assche         printf("Number of offline condition zones: %u\n", st.zc_off_num);
1059*44704f69SBart Van Assche     if (st.zc_off_1st_lba1 > 0)
1060*44704f69SBart Van Assche         printf("    Lowest starting LBA: 0x%" PRIx64 "\n",
1061*44704f69SBart Van Assche               st.zc_off_1st_lba1 - 1);
1062*44704f69SBart Van Assche     if (st.zc_unk_num > 0)
1063*44704f69SBart Van Assche         printf("Number of unknown condition zones: %u\n", st.zc_unk_num);
1064*44704f69SBart Van Assche 
1065*44704f69SBart Van Assche     if (st.wp_max_lba1 > 0)
1066*44704f69SBart Van Assche         printf("Highest active write pointer LBA: 0x%" PRIx64 "\n",
1067*44704f69SBart Van Assche               st.wp_max_lba1 - 1);
1068*44704f69SBart Van Assche     printf("Number of used blocks in write pointer zones: 0x%" PRIx64 "\n",
1069*44704f69SBart Van Assche            st.wp_blk_num);
1070*44704f69SBart Van Assche 
1071*44704f69SBart Van Assche     if ((sg_fd >= 0) && (op->maxlen >= RCAP16_REPLY_LEN) &&
1072*44704f69SBart Van Assche         ((st.wp_blk_num > 0) || (st.conv_blk_num > 0))) {
1073*44704f69SBart Van Assche         uint32_t block_size = 0;
1074*44704f69SBart Van Assche         uint64_t total_sz;
1075*44704f69SBart Van Assche         double sz_mb, sz_gb;
1076*44704f69SBart Van Assche 
1077*44704f69SBart Van Assche         res = sg_ll_readcap_16(sg_fd, false, 0, rzBuff,
1078*44704f69SBart Van Assche                                RCAP16_REPLY_LEN, true, op->vb);
1079*44704f69SBart Van Assche         if (SG_LIB_CAT_INVALID_OP == res) {
1080*44704f69SBart Van Assche             pr2serr("READ CAPACITY (16) cdb not supported\n");
1081*44704f69SBart Van Assche         } else if (SG_LIB_CAT_ILLEGAL_REQ == res)
1082*44704f69SBart Van Assche             pr2serr("bad field in READ CAPACITY (16) cdb including "
1083*44704f69SBart Van Assche                     "unsupported service action\n");
1084*44704f69SBart Van Assche         else if (res) {
1085*44704f69SBart Van Assche             sg_get_category_sense_str(res, sizeof(b), b, op->vb);
1086*44704f69SBart Van Assche             pr2serr("READ CAPACITY (16) failed: %s\n", b);
1087*44704f69SBart Van Assche         } else
1088*44704f69SBart Van Assche             block_size = sg_get_unaligned_be32(rzBuff + 8);
1089*44704f69SBart Van Assche 
1090*44704f69SBart Van Assche         if (st.wp_blk_num) {
1091*44704f69SBart Van Assche             total_sz = st.wp_blk_num * block_size;
1092*44704f69SBart Van Assche             sz_mb = (double)(total_sz) / (double)(1048576);
1093*44704f69SBart Van Assche             sz_gb = (double)(total_sz) / (double)(1000000000L);
1094*44704f69SBart Van Assche #ifdef SG_LIB_MINGW
1095*44704f69SBart Van Assche             printf("   associated size: %" PRIu64 " bytes, %g MiB, %g GB",
1096*44704f69SBart Van Assche                    total_sz, sz_mb, sz_gb);
1097*44704f69SBart Van Assche #else
1098*44704f69SBart Van Assche             printf("   associated size: %" PRIu64 " bytes, %.1f MiB, %.2f "
1099*44704f69SBart Van Assche                    "GB", total_sz, sz_mb, sz_gb);
1100*44704f69SBart Van Assche #endif
1101*44704f69SBart Van Assche             if (sz_gb > 2000) {
1102*44704f69SBart Van Assche #ifdef SG_LIB_MINGW
1103*44704f69SBart Van Assche                 printf(", %g TB", sz_gb / 1000);
1104*44704f69SBart Van Assche #else
1105*44704f69SBart Van Assche                 printf(", %.2f TB", sz_gb / 1000);
1106*44704f69SBart Van Assche #endif
1107*44704f69SBart Van Assche             }
1108*44704f69SBart Van Assche             printf("\n");
1109*44704f69SBart Van Assche         }
1110*44704f69SBart Van Assche         if (st.conv_blk_num) {
1111*44704f69SBart Van Assche             total_sz = st.conv_blk_num * block_size;
1112*44704f69SBart Van Assche             sz_mb = (double)(total_sz) / (double)(1048576);
1113*44704f69SBart Van Assche             sz_gb = (double)(total_sz) / (double)(1000000000L);
1114*44704f69SBart Van Assche             printf("Size of all conventional zones: ");
1115*44704f69SBart Van Assche #ifdef SG_LIB_MINGW
1116*44704f69SBart Van Assche             printf("%" PRIu64 " bytes, %g MiB, %g GB", total_sz, sz_mb,
1117*44704f69SBart Van Assche                    sz_gb);
1118*44704f69SBart Van Assche #else
1119*44704f69SBart Van Assche             printf("%" PRIu64 " bytes, %.1f MiB, %.2f GB", total_sz,
1120*44704f69SBart Van Assche                    sz_mb, sz_gb);
1121*44704f69SBart Van Assche #endif
1122*44704f69SBart Van Assche             if (sz_gb > 2000) {
1123*44704f69SBart Van Assche #ifdef SG_LIB_MINGW
1124*44704f69SBart Van Assche                 printf(", %g TB", sz_gb / 1000);
1125*44704f69SBart Van Assche #else
1126*44704f69SBart Van Assche                 printf(", %.2f TB", sz_gb / 1000);
1127*44704f69SBart Van Assche #endif
1128*44704f69SBart Van Assche             }
1129*44704f69SBart Van Assche             printf("\n");
1130*44704f69SBart Van Assche         }
1131*44704f69SBart Van Assche     }
1132*44704f69SBart Van Assche     return res;
1133*44704f69SBart Van Assche }
1134*44704f69SBart Van Assche 
1135*44704f69SBart Van Assche 
1136*44704f69SBart Van Assche int
main(int argc,char * argv[])1137*44704f69SBart Van Assche main(int argc, char * argv[])
1138*44704f69SBart Van Assche {
1139*44704f69SBart Van Assche     bool no_final_msg = false;
1140*44704f69SBart Van Assche     bool as_json;
1141*44704f69SBart Van Assche     int res, c, act_len, rlen, in_len, off;
1142*44704f69SBart Van Assche     int sg_fd = -1;
1143*44704f69SBart Van Assche     int resid = 0;
1144*44704f69SBart Van Assche     int ret = 0;
1145*44704f69SBart Van Assche     uint32_t decod_len;
1146*44704f69SBart Van Assche     int64_t ll;
1147*44704f69SBart Van Assche     const char * device_name = NULL;
1148*44704f69SBart Van Assche     uint8_t * rzBuff = NULL;
1149*44704f69SBart Van Assche     uint8_t * free_rzbp = NULL;
1150*44704f69SBart Van Assche     const char * cmd_name = "Report zones";
1151*44704f69SBart Van Assche     sgj_state * jsp;
1152*44704f69SBart Van Assche     sgj_opaque_p jop = NULL;
1153*44704f69SBart Van Assche     char b[80];
1154*44704f69SBart Van Assche     struct opts_t opts SG_C_CPP_ZERO_INIT;
1155*44704f69SBart Van Assche     struct opts_t * op = &opts;
1156*44704f69SBart Van Assche 
1157*44704f69SBart Van Assche     op->serv_act = REPORT_ZONES_SA;
1158*44704f69SBart Van Assche     while (1) {
1159*44704f69SBart Van Assche         int option_index = 0;
1160*44704f69SBart Van Assche 
1161*44704f69SBart Van Assche         c = getopt_long(argc, argv, "bdefF:hHi:j::l:m:n:o:prRs:SvVw",
1162*44704f69SBart Van Assche                         long_options, &option_index);
1163*44704f69SBart Van Assche         if (c == -1)
1164*44704f69SBart Van Assche             break;
1165*44704f69SBart Van Assche 
1166*44704f69SBart Van Assche         switch (c) {
1167*44704f69SBart Van Assche         case 'b':
1168*44704f69SBart Van Assche             op->do_brief = true;
1169*44704f69SBart Van Assche             break;
1170*44704f69SBart Van Assche         case 'd':
1171*44704f69SBart Van Assche             op->do_zdomains = true;
1172*44704f69SBart Van Assche             op->serv_act = REPORT_ZONE_DOMAINS_SA;
1173*44704f69SBart Van Assche             break;
1174*44704f69SBart Van Assche         case 'e':
1175*44704f69SBart Van Assche             op->do_realms = true;
1176*44704f69SBart Van Assche             op->serv_act = REPORT_REALMS_SA;
1177*44704f69SBart Van Assche             break;
1178*44704f69SBart Van Assche         case 'f':
1179*44704f69SBart Van Assche             op->do_force = true;
1180*44704f69SBart Van Assche             break;
1181*44704f69SBart Van Assche         case 'F':
1182*44704f69SBart Van Assche             off = (('-' == *optarg) || ('!' == *optarg)) ? 1 : 0;
1183*44704f69SBart Van Assche             if (isdigit(*(optarg + off))) {
1184*44704f69SBart Van Assche                 op->find_zt = sg_get_num_nomult(optarg + off);
1185*44704f69SBart Van Assche                 if (op->find_zt < 0) {
1186*44704f69SBart Van Assche                     pr2serr("bad numeric argument to '--find='\n");
1187*44704f69SBart Van Assche                     return SG_LIB_SYNTAX_ERROR;
1188*44704f69SBart Van Assche                 }
1189*44704f69SBart Van Assche                 if (off)
1190*44704f69SBart Van Assche                     op->find_zt = -op->find_zt; /* find first not equal */
1191*44704f69SBart Van Assche             } else {    /* check for abbreviation */
1192*44704f69SBart Van Assche                 struct zt_num2abbrev_t * zn2ap = zt_num2abbrev;
1193*44704f69SBart Van Assche 
1194*44704f69SBart Van Assche                 for ( ; zn2ap->abbrev; ++zn2ap) {
1195*44704f69SBart Van Assche                     if (0 == strcmp(optarg + off, zn2ap->abbrev))
1196*44704f69SBart Van Assche                         break;
1197*44704f69SBart Van Assche                 }
1198*44704f69SBart Van Assche                 if (NULL == zn2ap->abbrev) {
1199*44704f69SBart Van Assche                     pr2serr("bad abbreviation argument to '--find='\n\n");
1200*44704f69SBart Van Assche                     prn_zone_type_abbrevs();
1201*44704f69SBart Van Assche                     return SG_LIB_SYNTAX_ERROR;
1202*44704f69SBart Van Assche                 }
1203*44704f69SBart Van Assche                 op->find_zt = off ? -zn2ap->ztn : zn2ap->ztn;
1204*44704f69SBart Van Assche             }
1205*44704f69SBart Van Assche             break;
1206*44704f69SBart Van Assche         case 'h':
1207*44704f69SBart Van Assche         case '?':
1208*44704f69SBart Van Assche             ++op->do_help;
1209*44704f69SBart Van Assche             break;
1210*44704f69SBart Van Assche         case 'H':
1211*44704f69SBart Van Assche             ++op->do_hex;
1212*44704f69SBart Van Assche             break;
1213*44704f69SBart Van Assche        case 'i':
1214*44704f69SBart Van Assche             op->in_fn = optarg;
1215*44704f69SBart Van Assche             break;
1216*44704f69SBart Van Assche        case 'j':
1217*44704f69SBart Van Assche             if (! sgj_init_state(&op->json_st, optarg)) {
1218*44704f69SBart Van Assche                 int bad_char = op->json_st.first_bad_char;
1219*44704f69SBart Van Assche                 char e[1500];
1220*44704f69SBart Van Assche 
1221*44704f69SBart Van Assche                 if (bad_char) {
1222*44704f69SBart Van Assche                     pr2serr("bad argument to --json= option, unrecognized "
1223*44704f69SBart Van Assche                             "character '%c'\n\n", bad_char);
1224*44704f69SBart Van Assche                 }
1225*44704f69SBart Van Assche                 sg_json_usage(0, e, sizeof(e));
1226*44704f69SBart Van Assche                 pr2serr("%s", e);
1227*44704f69SBart Van Assche                 return SG_LIB_SYNTAX_ERROR;
1228*44704f69SBart Van Assche             }
1229*44704f69SBart Van Assche             break;
1230*44704f69SBart Van Assche         /* case 'l': is under case 's': */
1231*44704f69SBart Van Assche         case 'm':
1232*44704f69SBart Van Assche             op->maxlen = sg_get_num(optarg);
1233*44704f69SBart Van Assche             if ((op->maxlen < 0) || (op->maxlen > MAX_RZONES_BUFF_LEN)) {
1234*44704f69SBart Van Assche                 pr2serr("argument to '--maxlen' should be %d or "
1235*44704f69SBart Van Assche                         "less\n", MAX_RZONES_BUFF_LEN);
1236*44704f69SBart Van Assche                 return SG_LIB_SYNTAX_ERROR;
1237*44704f69SBart Van Assche             }
1238*44704f69SBart Van Assche             op->maxlen_given = true;
1239*44704f69SBart Van Assche             break;
1240*44704f69SBart Van Assche         case 'n':
1241*44704f69SBart Van Assche             op->do_num = sg_get_num(optarg);
1242*44704f69SBart Van Assche             if (op->do_num < 0) {
1243*44704f69SBart Van Assche                 pr2serr("argument to '--num' should be zero or more\n");
1244*44704f69SBart Van Assche                 return SG_LIB_SYNTAX_ERROR;
1245*44704f69SBart Van Assche             }
1246*44704f69SBart Van Assche             break;
1247*44704f69SBart Van Assche         case 'o':
1248*44704f69SBart Van Assche            op->reporting_opt = sg_get_num_nomult(optarg);
1249*44704f69SBart Van Assche            if ((op->reporting_opt < 0) || (op->reporting_opt > 63)) {
1250*44704f69SBart Van Assche                 pr2serr("bad argument to '--report=OPT', expect 0 to "
1251*44704f69SBart Van Assche                         "63\n");
1252*44704f69SBart Van Assche                 return SG_LIB_SYNTAX_ERROR;
1253*44704f69SBart Van Assche             }
1254*44704f69SBart Van Assche             break;
1255*44704f69SBart Van Assche         case 'p':
1256*44704f69SBart Van Assche             op->do_partial = true;
1257*44704f69SBart Van Assche             break;
1258*44704f69SBart Van Assche         case 'r':
1259*44704f69SBart Van Assche             op->do_raw = true;
1260*44704f69SBart Van Assche             break;
1261*44704f69SBart Van Assche         case 'R':
1262*44704f69SBart Van Assche             op->o_readonly = true;
1263*44704f69SBart Van Assche             break;
1264*44704f69SBart Van Assche         case 's':
1265*44704f69SBart Van Assche         case 'l':       /* --locator= and --start= are interchangeable */
1266*44704f69SBart Van Assche         if ((2 == strlen(optarg)) && (0 == memcmp("-1", optarg, 2))) {
1267*44704f69SBart Van Assche                 op->st_lba = UINT64_MAX;
1268*44704f69SBart Van Assche                 break;
1269*44704f69SBart Van Assche             }
1270*44704f69SBart Van Assche             ll = sg_get_llnum(optarg);
1271*44704f69SBart Van Assche             if (-1 == ll) {
1272*44704f69SBart Van Assche                 pr2serr("bad argument to '--start=LBA' or '--locator=LBA\n");
1273*44704f69SBart Van Assche                 return SG_LIB_SYNTAX_ERROR;
1274*44704f69SBart Van Assche             }
1275*44704f69SBart Van Assche             op->st_lba = (uint64_t)ll;
1276*44704f69SBart Van Assche             break;
1277*44704f69SBart Van Assche         case 'S':
1278*44704f69SBart Van Assche             op->statistics = true;
1279*44704f69SBart Van Assche             break;
1280*44704f69SBart Van Assche         case 'v':
1281*44704f69SBart Van Assche             op->verbose_given = true;
1282*44704f69SBart Van Assche             ++op->vb;
1283*44704f69SBart Van Assche             break;
1284*44704f69SBart Van Assche         case 'V':
1285*44704f69SBart Van Assche             op->version_given = true;
1286*44704f69SBart Van Assche             break;
1287*44704f69SBart Van Assche         case 'w':
1288*44704f69SBart Van Assche             op->wp_only = true;
1289*44704f69SBart Van Assche             break;
1290*44704f69SBart Van Assche         default:
1291*44704f69SBart Van Assche             pr2serr("unrecognised option code 0x%x ??\n", c);
1292*44704f69SBart Van Assche             usage(1);
1293*44704f69SBart Van Assche             return SG_LIB_SYNTAX_ERROR;
1294*44704f69SBart Van Assche         }
1295*44704f69SBart Van Assche     }
1296*44704f69SBart Van Assche     if (optind < argc) {
1297*44704f69SBart Van Assche         if (NULL == device_name) {
1298*44704f69SBart Van Assche             device_name = argv[optind];
1299*44704f69SBart Van Assche             ++optind;
1300*44704f69SBart Van Assche         }
1301*44704f69SBart Van Assche         if (optind < argc) {
1302*44704f69SBart Van Assche             for (; optind < argc; ++optind)
1303*44704f69SBart Van Assche                 pr2serr("Unexpected extra argument: %s\n", argv[optind]);
1304*44704f69SBart Van Assche             usage(1);
1305*44704f69SBart Van Assche             return SG_LIB_SYNTAX_ERROR;
1306*44704f69SBart Van Assche         }
1307*44704f69SBart Van Assche     }
1308*44704f69SBart Van Assche #ifdef DEBUG
1309*44704f69SBart Van Assche     pr2serr("In DEBUG mode, ");
1310*44704f69SBart Van Assche     if (op->verbose_given && op->version_given) {
1311*44704f69SBart Van Assche         pr2serr("but override: '-vV' given, zero verbose and continue\n");
1312*44704f69SBart Van Assche         op->verbose_given = false;
1313*44704f69SBart Van Assche         op->version_given = false;
1314*44704f69SBart Van Assche         op->vb = 0;
1315*44704f69SBart Van Assche     } else if (! op->verbose_given) {
1316*44704f69SBart Van Assche         pr2serr("set '-vv'\n");
1317*44704f69SBart Van Assche         op->vb = 2;
1318*44704f69SBart Van Assche     } else
1319*44704f69SBart Van Assche         pr2serr("keep verbose=%d\n", op->vb);
1320*44704f69SBart Van Assche #else
1321*44704f69SBart Van Assche     if (op->verbose_given && op->version_given)
1322*44704f69SBart Van Assche         pr2serr("Not in DEBUG mode, so '-vV' has no special action\n");
1323*44704f69SBart Van Assche #endif
1324*44704f69SBart Van Assche     if (op->version_given) {
1325*44704f69SBart Van Assche         pr2serr("version: %s\n", version_str);
1326*44704f69SBart Van Assche         return 0;
1327*44704f69SBart Van Assche     }
1328*44704f69SBart Van Assche 
1329*44704f69SBart Van Assche     if (op->do_help) {
1330*44704f69SBart Van Assche         usage(op->do_help);
1331*44704f69SBart Van Assche         return 0;
1332*44704f69SBart Van Assche     }
1333*44704f69SBart Van Assche     as_json = op->json_st.pr_as_json;
1334*44704f69SBart Van Assche     jsp = &op->json_st;
1335*44704f69SBart Van Assche     if (as_json)
1336*44704f69SBart Van Assche         jop = sgj_start_r(MY_NAME, version_str, argc, argv, jsp);
1337*44704f69SBart Van Assche 
1338*44704f69SBart Van Assche     if (op->do_zdomains && op->do_realms) {
1339*44704f69SBart Van Assche         pr2serr("Can't have both --domain and --realm\n");
1340*44704f69SBart Van Assche         return SG_LIB_SYNTAX_ERROR;
1341*44704f69SBart Van Assche     } else if (op->do_zdomains)
1342*44704f69SBart Van Assche         cmd_name = "Report zone domains";
1343*44704f69SBart Van Assche     else if (op->do_realms)
1344*44704f69SBart Van Assche         cmd_name = "Report realms";
1345*44704f69SBart Van Assche     if (as_json)
1346*44704f69SBart Van Assche         sgj_js_nv_s(jsp, jop, "scsi_command_name", cmd_name);
1347*44704f69SBart Van Assche     if ((op->serv_act != REPORT_ZONES_SA) && op->do_partial) {
1348*44704f69SBart Van Assche         pr2serr("Can only use --partial with REPORT ZONES\n");
1349*44704f69SBart Van Assche         return SG_LIB_SYNTAX_ERROR;
1350*44704f69SBart Van Assche     }
1351*44704f69SBart Van Assche     if (device_name && op->in_fn) {
1352*44704f69SBart Van Assche         pr2serr("ignoring DEVICE, best to give DEVICE or --inhex=FN, but "
1353*44704f69SBart Van Assche                 "not both\n");
1354*44704f69SBart Van Assche         device_name = NULL;
1355*44704f69SBart Van Assche     }
1356*44704f69SBart Van Assche     if (0 == op->maxlen)
1357*44704f69SBart Van Assche         op->maxlen = DEF_RZONES_BUFF_LEN;
1358*44704f69SBart Van Assche     rzBuff = (uint8_t *)sg_memalign(op->maxlen, 0, &free_rzbp, op->vb > 3);
1359*44704f69SBart Van Assche     if (NULL == rzBuff) {
1360*44704f69SBart Van Assche         pr2serr("unable to sg_memalign %d bytes\n", op->maxlen);
1361*44704f69SBart Van Assche         return sg_convert_errno(ENOMEM);
1362*44704f69SBart Van Assche     }
1363*44704f69SBart Van Assche 
1364*44704f69SBart Van Assche     if (NULL == device_name) {
1365*44704f69SBart Van Assche         if (op->in_fn) {
1366*44704f69SBart Van Assche             if ((ret = sg_f2hex_arr(op->in_fn, op->do_raw, false, rzBuff,
1367*44704f69SBart Van Assche                                     &in_len, op->maxlen))) {
1368*44704f69SBart Van Assche                 if (SG_LIB_LBA_OUT_OF_RANGE == ret) {
1369*44704f69SBart Van Assche                     no_final_msg = true;
1370*44704f69SBart Van Assche                     pr2serr("... decode what we have, --maxlen=%d needs to "
1371*44704f69SBart Van Assche                             "be increased\n", op->maxlen);
1372*44704f69SBart Van Assche                 } else
1373*44704f69SBart Van Assche                     goto the_end;
1374*44704f69SBart Van Assche             }
1375*44704f69SBart Van Assche             if (op->vb > 2)
1376*44704f69SBart Van Assche                 pr2serr("Read %d [0x%x] bytes of user supplied data\n",
1377*44704f69SBart Van Assche                         in_len, in_len);
1378*44704f69SBart Van Assche             if (op->do_raw)
1379*44704f69SBart Van Assche                 op->do_raw = false;    /* can interfere on decode */
1380*44704f69SBart Van Assche             if (in_len < 4) {
1381*44704f69SBart Van Assche                 pr2serr("--inhex=%s only decoded %d bytes (needs 4 at "
1382*44704f69SBart Van Assche                         "least)\n", op->in_fn, in_len);
1383*44704f69SBart Van Assche                 ret = SG_LIB_SYNTAX_ERROR;
1384*44704f69SBart Van Assche                 goto the_end;
1385*44704f69SBart Van Assche             }
1386*44704f69SBart Van Assche             res = 0;
1387*44704f69SBart Van Assche             if (op->find_zt) {  /* so '-F none' will drop through */
1388*44704f69SBart Van Assche                 op->maxlen = in_len;
1389*44704f69SBart Van Assche                 ret = find_report_zones(sg_fd, rzBuff, cmd_name, op, jsp);
1390*44704f69SBart Van Assche                 goto the_end;
1391*44704f69SBart Van Assche             } else if (op->statistics) {
1392*44704f69SBart Van Assche                 op->maxlen = in_len;
1393*44704f69SBart Van Assche                 ret = gather_statistics(sg_fd, rzBuff, cmd_name, op);
1394*44704f69SBart Van Assche                 goto the_end;
1395*44704f69SBart Van Assche             }
1396*44704f69SBart Van Assche             goto start_response;
1397*44704f69SBart Van Assche         } else {
1398*44704f69SBart Van Assche             pr2serr("missing device name!\n\n");
1399*44704f69SBart Van Assche             usage(1);
1400*44704f69SBart Van Assche             ret = SG_LIB_FILE_ERROR;
1401*44704f69SBart Van Assche             no_final_msg = true;
1402*44704f69SBart Van Assche             goto the_end;
1403*44704f69SBart Van Assche         }
1404*44704f69SBart Van Assche     }
1405*44704f69SBart Van Assche 
1406*44704f69SBart Van Assche     if (op->do_raw) {
1407*44704f69SBart Van Assche         if (sg_set_binary_mode(STDOUT_FILENO) < 0) {
1408*44704f69SBart Van Assche             perror("sg_set_binary_mode");
1409*44704f69SBart Van Assche             ret = SG_LIB_FILE_ERROR;
1410*44704f69SBart Van Assche             goto the_end;
1411*44704f69SBart Van Assche         }
1412*44704f69SBart Van Assche     }
1413*44704f69SBart Van Assche 
1414*44704f69SBart Van Assche     sg_fd = sg_cmds_open_device(device_name, op->o_readonly, op->vb);
1415*44704f69SBart Van Assche     if (sg_fd < 0) {
1416*44704f69SBart Van Assche         if (op->vb)
1417*44704f69SBart Van Assche             pr2serr("open error: %s: %s\n", device_name,
1418*44704f69SBart Van Assche                     safe_strerror(-sg_fd));
1419*44704f69SBart Van Assche         ret = sg_convert_errno(-sg_fd);
1420*44704f69SBart Van Assche         goto the_end;
1421*44704f69SBart Van Assche     }
1422*44704f69SBart Van Assche 
1423*44704f69SBart Van Assche     if (op->find_zt) {  /* so '-F none' will drop through */
1424*44704f69SBart Van Assche         ret = find_report_zones(sg_fd, rzBuff, cmd_name, op, jsp);
1425*44704f69SBart Van Assche         goto the_end;
1426*44704f69SBart Van Assche     } else if (op->statistics) {
1427*44704f69SBart Van Assche         ret = gather_statistics(sg_fd, rzBuff, cmd_name, op);
1428*44704f69SBart Van Assche         goto the_end;
1429*44704f69SBart Van Assche     }
1430*44704f69SBart Van Assche     res = sg_ll_report_zzz(sg_fd, op->serv_act, op->st_lba, op->do_partial,
1431*44704f69SBart Van Assche                            op->reporting_opt, rzBuff, op->maxlen, &resid,
1432*44704f69SBart Van Assche                            true, op->vb);
1433*44704f69SBart Van Assche     ret = res;
1434*44704f69SBart Van Assche start_response:
1435*44704f69SBart Van Assche     if (0 == res) {
1436*44704f69SBart Van Assche         rlen = op->in_fn ? in_len : (op->maxlen - resid);
1437*44704f69SBart Van Assche         if (rlen < 4) {
1438*44704f69SBart Van Assche             pr2serr("Decoded response length (%d) too short\n", rlen);
1439*44704f69SBart Van Assche             ret = SG_LIB_CAT_MALFORMED;
1440*44704f69SBart Van Assche             goto the_end;
1441*44704f69SBart Van Assche         }
1442*44704f69SBart Van Assche         decod_len = sg_get_unaligned_be32(rzBuff + 0) + 64;
1443*44704f69SBart Van Assche         if (decod_len > WILD_RZONES_BUFF_LEN) {
1444*44704f69SBart Van Assche             if (! op->do_force) {
1445*44704f69SBart Van Assche                 pr2serr("decode length [%u bytes] seems wild, use --force "
1446*44704f69SBart Van Assche                         "override\n", decod_len);
1447*44704f69SBart Van Assche                 ret = SG_LIB_CAT_MALFORMED;
1448*44704f69SBart Van Assche                 goto the_end;
1449*44704f69SBart Van Assche             }
1450*44704f69SBart Van Assche         }
1451*44704f69SBart Van Assche         if (decod_len > (uint32_t)rlen) {
1452*44704f69SBart Van Assche             if ((REPORT_ZONES_SA == op->serv_act) && (! op->do_partial)) {
1453*44704f69SBart Van Assche                 pr2serr("%u zones starting from LBA 0x%" PRIx64 " available "
1454*44704f69SBart Van Assche                         "but only %d zones returned\n",
1455*44704f69SBart Van Assche                         (decod_len - 64) / REPORT_ZONES_DESC_LEN, op->st_lba,
1456*44704f69SBart Van Assche                         (rlen - 64) / REPORT_ZONES_DESC_LEN);
1457*44704f69SBart Van Assche                 decod_len = rlen;
1458*44704f69SBart Van Assche                 act_len = rlen;
1459*44704f69SBart Van Assche             } else {
1460*44704f69SBart Van Assche                 pr2serr("decoded response length is %u bytes, but system "
1461*44704f69SBart Van Assche                         "reports %d bytes received??\n", decod_len, rlen);
1462*44704f69SBart Van Assche                 if (op->do_force)
1463*44704f69SBart Van Assche                     act_len = rlen;
1464*44704f69SBart Van Assche                 else {
1465*44704f69SBart Van Assche                     pr2serr("Exiting, use --force to override\n");
1466*44704f69SBart Van Assche                     ret = SG_LIB_CAT_MALFORMED;
1467*44704f69SBart Van Assche                     goto the_end;
1468*44704f69SBart Van Assche                 }
1469*44704f69SBart Van Assche             }
1470*44704f69SBart Van Assche         } else
1471*44704f69SBart Van Assche             act_len = decod_len;
1472*44704f69SBart Van Assche         if (op->do_raw) {
1473*44704f69SBart Van Assche             dStrRaw(rzBuff, act_len);
1474*44704f69SBart Van Assche             goto the_end;
1475*44704f69SBart Van Assche         }
1476*44704f69SBart Van Assche         if (op->do_hex && (2 != op->do_hex)) {
1477*44704f69SBart Van Assche             hex2stdout(rzBuff, act_len, ((1 == op->do_hex) ? 1 : -1));
1478*44704f69SBart Van Assche             goto the_end;
1479*44704f69SBart Van Assche         }
1480*44704f69SBart Van Assche         if (! op->wp_only && (! op->do_hex))
1481*44704f69SBart Van Assche             sgj_pr_hr(jsp, "%s response:\n", cmd_name);
1482*44704f69SBart Van Assche 
1483*44704f69SBart Van Assche         if (act_len < 64) {
1484*44704f69SBart Van Assche             pr2serr("Zone length [%d] too short (perhaps after truncation\n)",
1485*44704f69SBart Van Assche                     act_len);
1486*44704f69SBart Van Assche             ret = SG_LIB_CAT_MALFORMED;
1487*44704f69SBart Van Assche             goto the_end;
1488*44704f69SBart Van Assche         }
1489*44704f69SBart Van Assche         if (REPORT_ZONES_SA == op->serv_act)
1490*44704f69SBart Van Assche             ret = decode_rep_zones(rzBuff, act_len, decod_len, op, jsp);
1491*44704f69SBart Van Assche         else if (op->do_realms)
1492*44704f69SBart Van Assche             ret = decode_rep_realms(rzBuff, act_len, op, jsp);
1493*44704f69SBart Van Assche         else if (op->do_zdomains)
1494*44704f69SBart Van Assche             ret = decode_rep_zdomains(rzBuff, act_len, op, jsp);
1495*44704f69SBart Van Assche     } else if (SG_LIB_CAT_INVALID_OP == res)
1496*44704f69SBart Van Assche         pr2serr("%s command not supported\n", cmd_name);
1497*44704f69SBart Van Assche     else {
1498*44704f69SBart Van Assche         sg_get_category_sense_str(res, sizeof(b), b, op->vb);
1499*44704f69SBart Van Assche         pr2serr("%s command: %s\n", cmd_name, b);
1500*44704f69SBart Van Assche     }
1501*44704f69SBart Van Assche 
1502*44704f69SBart Van Assche the_end:
1503*44704f69SBart Van Assche     if (free_rzbp)
1504*44704f69SBart Van Assche         free(free_rzbp);
1505*44704f69SBart Van Assche     if (sg_fd >= 0) {
1506*44704f69SBart Van Assche         res = sg_cmds_close_device(sg_fd);
1507*44704f69SBart Van Assche         if (res < 0) {
1508*44704f69SBart Van Assche             pr2serr("close error: %s\n", safe_strerror(-res));
1509*44704f69SBart Van Assche             if (0 == ret)
1510*44704f69SBart Van Assche                 ret = sg_convert_errno(-res);
1511*44704f69SBart Van Assche         }
1512*44704f69SBart Van Assche     }
1513*44704f69SBart Van Assche     if ((0 == op->vb && (! no_final_msg))) {
1514*44704f69SBart Van Assche         if (! sg_if_can2stderr("sg_rep_zones failed: ", ret))
1515*44704f69SBart Van Assche             pr2serr("Some error occurred, try again with '-v' "
1516*44704f69SBart Van Assche                     "or '-vv' for more information\n");
1517*44704f69SBart Van Assche     }
1518*44704f69SBart Van Assche     ret = (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
1519*44704f69SBart Van Assche     if (as_json) {
1520*44704f69SBart Van Assche         if (0 == op->do_hex)
1521*44704f69SBart Van Assche             sgj_js2file(jsp, NULL, ret, stdout);
1522*44704f69SBart Van Assche         sgj_finish(jsp);
1523*44704f69SBart Van Assche     }
1524*44704f69SBart Van Assche     return ret;
1525*44704f69SBart Van Assche }
1526