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