xref: /aosp_15_r20/external/sg3_utils/src/sg_readcap.c (revision 44704f698541f6367e81f991ef8bb54ccbf3fc18)
1*44704f69SBart Van Assche /* This code is does a SCSI READ CAPACITY command on the given device
2*44704f69SBart Van Assche  * and outputs the result.
3*44704f69SBart Van Assche  *
4*44704f69SBart Van Assche  * Copyright (C) 1999 - 2020 D. Gilbert
5*44704f69SBart Van Assche  * This program is free software; you can redistribute it and/or modify
6*44704f69SBart Van Assche  * it under the terms of the GNU General Public License as published by
7*44704f69SBart Van Assche  * the Free Software Foundation; either version 2, or (at your option)
8*44704f69SBart Van Assche  * any later version.
9*44704f69SBart Van Assche  *
10*44704f69SBart Van Assche  * SPDX-License-Identifier: GPL-2.0-or-later
11*44704f69SBart Van Assche  *
12*44704f69SBart Van Assche  * This program was originally written with Linux 2.4 kernel series.
13*44704f69SBart Van Assche  * It now builds for the Linux 2.6, 3 and 4 kernel series and various other
14*44704f69SBart Van Assche  * operating systems.
15*44704f69SBart Van Assche  */
16*44704f69SBart Van Assche 
17*44704f69SBart Van Assche #include <stdio.h>
18*44704f69SBart Van Assche #include <stdlib.h>
19*44704f69SBart Van Assche #include <stdarg.h>
20*44704f69SBart Van Assche #include <stdbool.h>
21*44704f69SBart Van Assche #include <unistd.h>
22*44704f69SBart Van Assche #include <string.h>
23*44704f69SBart Van Assche #include <fcntl.h>
24*44704f69SBart Van Assche #include <errno.h>
25*44704f69SBart Van Assche #include <getopt.h>
26*44704f69SBart Van Assche #define __STDC_FORMAT_MACROS 1
27*44704f69SBart Van Assche #include <inttypes.h>
28*44704f69SBart Van Assche 
29*44704f69SBart Van Assche #ifdef HAVE_CONFIG_H
30*44704f69SBart Van Assche #include "config.h"
31*44704f69SBart Van Assche #endif
32*44704f69SBart Van Assche 
33*44704f69SBart Van Assche #include "sg_lib.h"
34*44704f69SBart Van Assche #include "sg_cmds_basic.h"
35*44704f69SBart Van Assche #include "sg_unaligned.h"
36*44704f69SBart Van Assche #include "sg_pr2serr.h"
37*44704f69SBart Van Assche 
38*44704f69SBart Van Assche 
39*44704f69SBart Van Assche static const char * version_str = "4.05 20200122";
40*44704f69SBart Van Assche 
41*44704f69SBart Van Assche #define ME "sg_readcap: "
42*44704f69SBart Van Assche 
43*44704f69SBart Van Assche #define RCAP_REPLY_LEN 8
44*44704f69SBart Van Assche #define RCAP16_REPLY_LEN 32
45*44704f69SBart Van Assche 
46*44704f69SBart Van Assche static struct option long_options[] = {
47*44704f69SBart Van Assche     {"brief", no_argument, 0, 'b'},
48*44704f69SBart Van Assche     {"help", no_argument, 0, 'h'},
49*44704f69SBart Van Assche     {"hex", no_argument, 0, 'H'},
50*44704f69SBart Van Assche     {"lba", required_argument, 0, 'L'},
51*44704f69SBart Van Assche     {"long", no_argument, 0, 'l'},
52*44704f69SBart Van Assche     {"16", no_argument, 0, 'l'},
53*44704f69SBart Van Assche     {"new", no_argument, 0, 'N'},
54*44704f69SBart Van Assche     {"old", no_argument, 0, 'O'},
55*44704f69SBart Van Assche     {"pmi", no_argument, 0, 'p'},
56*44704f69SBart Van Assche     {"raw", no_argument, 0, 'r'},
57*44704f69SBart Van Assche     {"readonly", no_argument, 0, 'R'},
58*44704f69SBart Van Assche     {"verbose", no_argument, 0, 'v'},
59*44704f69SBart Van Assche     {"version", no_argument, 0, 'V'},
60*44704f69SBart Van Assche     {"zbc", no_argument, 0, 'z'},
61*44704f69SBart Van Assche     {0, 0, 0, 0},
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_long;
67*44704f69SBart Van Assche     bool do_pmi;
68*44704f69SBart Van Assche     bool do_raw;
69*44704f69SBart Van Assche     bool o_readonly;
70*44704f69SBart Van Assche     bool do_zbc;
71*44704f69SBart Van Assche     bool opt_new;
72*44704f69SBart Van Assche     bool verbose_given;
73*44704f69SBart Van Assche     bool version_given;
74*44704f69SBart Van Assche     int do_help;
75*44704f69SBart Van Assche     int do_hex;
76*44704f69SBart Van Assche     int do_lba;
77*44704f69SBart Van Assche     int verbose;
78*44704f69SBart Van Assche     uint64_t llba;
79*44704f69SBart Van Assche     const char * device_name;
80*44704f69SBart Van Assche };
81*44704f69SBart Van Assche 
82*44704f69SBart Van Assche 
83*44704f69SBart Van Assche static void
usage()84*44704f69SBart Van Assche usage()
85*44704f69SBart Van Assche {
86*44704f69SBart Van Assche     pr2serr("Usage: sg_readcap [--16] [--brief] [--help] [--hex] "
87*44704f69SBart Van Assche             "[--lba=LBA] [--long]\n"
88*44704f69SBart Van Assche             "                  [--pmi] [--raw] [--readonly] [--verbose] "
89*44704f69SBart Van Assche             "[--version]\n"
90*44704f69SBart Van Assche             "                  [--zbc] DEVICE\n"
91*44704f69SBart Van Assche             "  where:\n"
92*44704f69SBart Van Assche             "    --16            use READ CAPACITY (16) cdb (same as "
93*44704f69SBart Van Assche             "--long)\n"
94*44704f69SBart Van Assche             "    --brief|-b      brief, two hex numbers: number of blocks "
95*44704f69SBart Van Assche             "and block size\n"
96*44704f69SBart Van Assche             "    --help|-h       print this usage message and exit\n"
97*44704f69SBart Van Assche             "    --hex|-H        output response in hexadecimal to stdout\n"
98*44704f69SBart Van Assche             "    --lba=LBA|-L LBA    yields the last block prior to (head "
99*44704f69SBart Van Assche             "movement) delay\n"
100*44704f69SBart Van Assche             "                        after LBA [in decimal (def: 0) "
101*44704f69SBart Van Assche             "valid with '--pmi']\n"
102*44704f69SBart Van Assche             "    --long|-l       use READ CAPACITY (16) cdb (def: use "
103*44704f69SBart Van Assche             "10 byte cdb)\n"
104*44704f69SBart Van Assche             "    --pmi|-p        partial medium indicator (without this "
105*44704f69SBart Van Assche             "option shows\n"
106*44704f69SBart Van Assche             "                    total disk capacity) [made obsolete in "
107*44704f69SBart Van Assche             "sbc3r26]\n"
108*44704f69SBart Van Assche             "    --raw|-r        output response in binary to stdout\n"
109*44704f69SBart Van Assche             "    --readonly|-R    open DEVICE read-only (def: RCAP(16) "
110*44704f69SBart Van Assche             "read-write)\n"
111*44704f69SBart Van Assche             "    --verbose|-v    increase verbosity\n"
112*44704f69SBart Van Assche             "    --version|-V    print version string and exit\n"
113*44704f69SBart Van Assche             "    --old|-O        use old interface (use as first option)\n"
114*44704f69SBart Van Assche             "    --zbc|-z        show rc_basis ZBC field (implies --16)\n\n"
115*44704f69SBart Van Assche             "Perform a SCSI READ CAPACITY (10 or 16) command\n");
116*44704f69SBart Van Assche }
117*44704f69SBart Van Assche 
118*44704f69SBart Van Assche static void
usage_old()119*44704f69SBart Van Assche usage_old()
120*44704f69SBart Van Assche {
121*44704f69SBart Van Assche     pr2serr("Usage:  sg_readcap [-16] [-b] [-h] [-H] [-lba=LBA] "
122*44704f69SBart Van Assche             "[-pmi] [-r] [-R]\n"
123*44704f69SBart Van Assche             "                   [-v] [-V] [-z] DEVICE\n"
124*44704f69SBart Van Assche             "  where:\n"
125*44704f69SBart Van Assche             "    -16    use READ CAPACITY (16) cdb (def: use "
126*44704f69SBart Van Assche             "10 byte cdb)\n"
127*44704f69SBart Van Assche             "    -b     brief, two hex numbers: number of blocks "
128*44704f69SBart Van Assche             "and block size\n"
129*44704f69SBart Van Assche             "    -h     print this usage message and exit\n"
130*44704f69SBart Van Assche             "    -H     output response in hexadecimal to stdout\n"
131*44704f69SBart Van Assche             "    -lba=LBA    yields the last block prior to (head "
132*44704f69SBart Van Assche             "movement) delay\n"
133*44704f69SBart Van Assche             "                after LBA [in hex (def: 0) "
134*44704f69SBart Van Assche             "valid with -pmi]\n"
135*44704f69SBart Van Assche             "    -pmi   partial medium indicator (without this option "
136*44704f69SBart Van Assche             "shows total\n"
137*44704f69SBart Van Assche             "           disk capacity)\n"
138*44704f69SBart Van Assche             "    -r     output response in binary to stdout\n"
139*44704f69SBart Van Assche             "    -R     open DEVICE read-only (def: RCAP(16) read-write)\n"
140*44704f69SBart Van Assche             "    -v     increase verbosity\n"
141*44704f69SBart Van Assche             "    -V     print version string and exit\n"
142*44704f69SBart Van Assche             "    -N|--new   use new interface\n"
143*44704f69SBart Van Assche             "    -z     show rc_basis ZBC field (implies -16)\n\n"
144*44704f69SBart Van Assche             "Perform a SCSI READ CAPACITY (10 or 16) command\n");
145*44704f69SBart Van Assche }
146*44704f69SBart Van Assche 
147*44704f69SBart Van Assche static void
usage_for(const struct opts_t * op)148*44704f69SBart Van Assche usage_for(const struct opts_t * op)
149*44704f69SBart Van Assche {
150*44704f69SBart Van Assche     if (op->opt_new)
151*44704f69SBart Van Assche         usage();
152*44704f69SBart Van Assche     else
153*44704f69SBart Van Assche         usage_old();
154*44704f69SBart Van Assche }
155*44704f69SBart Van Assche 
156*44704f69SBart Van Assche static int
new_parse_cmd_line(struct opts_t * op,int argc,char * argv[])157*44704f69SBart Van Assche new_parse_cmd_line(struct opts_t * op, int argc, char * argv[])
158*44704f69SBart Van Assche {
159*44704f69SBart Van Assche     int c;
160*44704f69SBart Van Assche     int a_one = 0;
161*44704f69SBart Van Assche     int64_t nn;
162*44704f69SBart Van Assche 
163*44704f69SBart Van Assche     while (1) {
164*44704f69SBart Van Assche         int option_index = 0;
165*44704f69SBart Van Assche 
166*44704f69SBart Van Assche         c = getopt_long(argc, argv, "16bhHlL:NOprRvVz", long_options,
167*44704f69SBart Van Assche                         &option_index);
168*44704f69SBart Van Assche         if (c == -1)
169*44704f69SBart Van Assche             break;
170*44704f69SBart Van Assche 
171*44704f69SBart Van Assche         switch (c) {
172*44704f69SBart Van Assche         case '1':
173*44704f69SBart Van Assche             ++a_one;
174*44704f69SBart Van Assche             break;
175*44704f69SBart Van Assche         case '6':
176*44704f69SBart Van Assche             if (a_one)
177*44704f69SBart Van Assche                 op->do_long = true;
178*44704f69SBart Van Assche             break;
179*44704f69SBart Van Assche         case 'b':
180*44704f69SBart Van Assche             op->do_brief = true;
181*44704f69SBart Van Assche             break;
182*44704f69SBart Van Assche         case 'h':
183*44704f69SBart Van Assche         case '?':
184*44704f69SBart Van Assche             ++op->do_help;
185*44704f69SBart Van Assche             break;
186*44704f69SBart Van Assche         case 'H':
187*44704f69SBart Van Assche             ++op->do_hex;
188*44704f69SBart Van Assche             break;
189*44704f69SBart Van Assche         case 'l':
190*44704f69SBart Van Assche             op->do_long = true;
191*44704f69SBart Van Assche             break;
192*44704f69SBart Van Assche         case 'L':
193*44704f69SBart Van Assche             nn = sg_get_llnum(optarg);
194*44704f69SBart Van Assche             if (-1 == nn) {
195*44704f69SBart Van Assche                 pr2serr("bad argument to '--lba='\n");
196*44704f69SBart Van Assche                 usage();
197*44704f69SBart Van Assche                 return SG_LIB_SYNTAX_ERROR;
198*44704f69SBart Van Assche             }
199*44704f69SBart Van Assche             op->llba = nn;
200*44704f69SBart Van Assche             /* force READ_CAPACITY16 for large lbas */
201*44704f69SBart Van Assche             if (op->llba > 0xfffffffeULL)
202*44704f69SBart Van Assche                 op->do_long = true;
203*44704f69SBart Van Assche             ++op->do_lba;
204*44704f69SBart Van Assche             break;
205*44704f69SBart Van Assche         case 'N':
206*44704f69SBart Van Assche             break;      /* ignore */
207*44704f69SBart Van Assche         case 'O':
208*44704f69SBart Van Assche             op->opt_new = false;
209*44704f69SBart Van Assche             return 0;
210*44704f69SBart Van Assche         case 'p':
211*44704f69SBart Van Assche             op->do_pmi = true;
212*44704f69SBart Van Assche             break;
213*44704f69SBart Van Assche         case 'r':
214*44704f69SBart Van Assche             op->do_raw = true;
215*44704f69SBart Van Assche             break;
216*44704f69SBart Van Assche         case 'R':
217*44704f69SBart Van Assche             op->o_readonly = true;
218*44704f69SBart Van Assche             break;
219*44704f69SBart Van Assche         case 'v':
220*44704f69SBart Van Assche             op->verbose_given = true;
221*44704f69SBart Van Assche             ++op->verbose;
222*44704f69SBart Van Assche             break;
223*44704f69SBart Van Assche         case 'V':
224*44704f69SBart Van Assche             op->version_given = true;
225*44704f69SBart Van Assche             break;
226*44704f69SBart Van Assche         case 'z':
227*44704f69SBart Van Assche             op->do_zbc = true;
228*44704f69SBart Van Assche             break;
229*44704f69SBart Van Assche         default:
230*44704f69SBart Van Assche             pr2serr("unrecognised option code %c [0x%x]\n", c, c);
231*44704f69SBart Van Assche             if (op->do_help)
232*44704f69SBart Van Assche                 break;
233*44704f69SBart Van Assche             usage();
234*44704f69SBart Van Assche             return SG_LIB_SYNTAX_ERROR;
235*44704f69SBart Van Assche         }
236*44704f69SBart Van Assche     }
237*44704f69SBart Van Assche     if (optind < argc) {
238*44704f69SBart Van Assche         if (NULL == op->device_name) {
239*44704f69SBart Van Assche             op->device_name = argv[optind];
240*44704f69SBart Van Assche             ++optind;
241*44704f69SBart Van Assche         }
242*44704f69SBart Van Assche         if (optind < argc) {
243*44704f69SBart Van Assche             for (; optind < argc; ++optind)
244*44704f69SBart Van Assche                 pr2serr("Unexpected extra argument: %s\n", argv[optind]);
245*44704f69SBart Van Assche             usage();
246*44704f69SBart Van Assche             return SG_LIB_SYNTAX_ERROR;
247*44704f69SBart Van Assche         }
248*44704f69SBart Van Assche     }
249*44704f69SBart Van Assche     return 0;
250*44704f69SBart Van Assche }
251*44704f69SBart Van Assche 
252*44704f69SBart Van Assche static int
old_parse_cmd_line(struct opts_t * op,int argc,char * argv[])253*44704f69SBart Van Assche old_parse_cmd_line(struct opts_t * op, int argc, char * argv[])
254*44704f69SBart Van Assche {
255*44704f69SBart Van Assche     bool jmp_out;
256*44704f69SBart Van Assche     int k, plen, num;
257*44704f69SBart Van Assche     const char * cp;
258*44704f69SBart Van Assche     uint64_t uu;
259*44704f69SBart Van Assche 
260*44704f69SBart Van Assche     for (k = 1; k < argc; ++k) {
261*44704f69SBart Van Assche         cp = argv[k];
262*44704f69SBart Van Assche         plen = strlen(cp);
263*44704f69SBart Van Assche         if (plen <= 0)
264*44704f69SBart Van Assche             continue;
265*44704f69SBart Van Assche         if ('-' == *cp) {
266*44704f69SBart Van Assche             for (--plen, ++cp, jmp_out = false; plen > 0; --plen, ++cp) {
267*44704f69SBart Van Assche                 switch (*cp) {
268*44704f69SBart Van Assche                 case '1':
269*44704f69SBart Van Assche                     if ('6' == *(cp + 1)) {
270*44704f69SBart Van Assche                         op->do_long = true;
271*44704f69SBart Van Assche                         ++cp;
272*44704f69SBart Van Assche                         --plen;
273*44704f69SBart Van Assche                     } else
274*44704f69SBart Van Assche                         jmp_out = true;
275*44704f69SBart Van Assche                     break;
276*44704f69SBart Van Assche                 case 'b':
277*44704f69SBart Van Assche                     op->do_brief = true;
278*44704f69SBart Van Assche                     break;
279*44704f69SBart Van Assche                 case 'h':
280*44704f69SBart Van Assche                 case '?':
281*44704f69SBart Van Assche                     ++op->do_help;
282*44704f69SBart Van Assche                     break;
283*44704f69SBart Van Assche                 case 'H':
284*44704f69SBart Van Assche                     ++op->do_hex;
285*44704f69SBart Van Assche                     break;
286*44704f69SBart Van Assche                 case 'N':
287*44704f69SBart Van Assche                     op->opt_new = true;
288*44704f69SBart Van Assche                     return 0;
289*44704f69SBart Van Assche                 case 'O':
290*44704f69SBart Van Assche                     break;
291*44704f69SBart Van Assche                 case 'p':
292*44704f69SBart Van Assche                     if (0 == strncmp("pmi", cp, 3)) {
293*44704f69SBart Van Assche                         op->do_pmi = true;
294*44704f69SBart Van Assche                         cp += 2;
295*44704f69SBart Van Assche                         plen -= 2;
296*44704f69SBart Van Assche                     } else
297*44704f69SBart Van Assche                         jmp_out = true;
298*44704f69SBart Van Assche                     break;
299*44704f69SBart Van Assche                 case 'r':
300*44704f69SBart Van Assche                     op->do_raw = true;
301*44704f69SBart Van Assche                     break;
302*44704f69SBart Van Assche                 case 'R':
303*44704f69SBart Van Assche                     op->o_readonly = true;
304*44704f69SBart Van Assche                     break;
305*44704f69SBart Van Assche                 case 'v':
306*44704f69SBart Van Assche                     op->verbose_given = true;
307*44704f69SBart Van Assche                     ++op->verbose;
308*44704f69SBart Van Assche                     break;
309*44704f69SBart Van Assche                 case 'V':
310*44704f69SBart Van Assche                     op->version_given = true;
311*44704f69SBart Van Assche                     break;
312*44704f69SBart Van Assche                 case 'z':
313*44704f69SBart Van Assche                     op->do_zbc = true;
314*44704f69SBart Van Assche                     break;
315*44704f69SBart Van Assche                 default:
316*44704f69SBart Van Assche                     jmp_out = true;
317*44704f69SBart Van Assche                     break;
318*44704f69SBart Van Assche                 }
319*44704f69SBart Van Assche                 if (jmp_out)
320*44704f69SBart Van Assche                     break;
321*44704f69SBart Van Assche             }
322*44704f69SBart Van Assche             if (plen <= 0)
323*44704f69SBart Van Assche                 continue;
324*44704f69SBart Van Assche             if (0 == strncmp("lba=", cp, 4)) {
325*44704f69SBart Van Assche                 num = sscanf(cp + 4, "%" SCNx64 "", &uu);
326*44704f69SBart Van Assche                 if (1 != num) {
327*44704f69SBart Van Assche                     printf("Bad value after 'lba=' option\n");
328*44704f69SBart Van Assche                     usage();
329*44704f69SBart Van Assche                     return SG_LIB_SYNTAX_ERROR;
330*44704f69SBart Van Assche                 }
331*44704f69SBart Van Assche                 /* force READ_CAPACITY16 for large lbas */
332*44704f69SBart Van Assche                 if (uu > 0xfffffffeULL)
333*44704f69SBart Van Assche                     op->do_long = true;
334*44704f69SBart Van Assche                 op->llba = uu;
335*44704f69SBart Van Assche                 ++op->do_lba;
336*44704f69SBart Van Assche             } else if (0 == strncmp("-old", cp, 4))
337*44704f69SBart Van Assche                 ;
338*44704f69SBart Van Assche             else if (jmp_out) {
339*44704f69SBart Van Assche                 pr2serr("Unrecognized option: %s\n", cp);
340*44704f69SBart Van Assche                 usage();
341*44704f69SBart Van Assche                 return SG_LIB_SYNTAX_ERROR;
342*44704f69SBart Van Assche             }
343*44704f69SBart Van Assche         } else if (0 == op->device_name)
344*44704f69SBart Van Assche             op->device_name = cp;
345*44704f69SBart Van Assche         else {
346*44704f69SBart Van Assche             pr2serr("too many arguments, got: %s, not expecting: %s\n",
347*44704f69SBart Van Assche                     op->device_name, cp);
348*44704f69SBart Van Assche             usage();
349*44704f69SBart Van Assche             return SG_LIB_SYNTAX_ERROR;
350*44704f69SBart Van Assche         }
351*44704f69SBart Van Assche     }
352*44704f69SBart Van Assche     return 0;
353*44704f69SBart Van Assche }
354*44704f69SBart Van Assche 
355*44704f69SBart Van Assche static int
parse_cmd_line(struct opts_t * op,int argc,char * argv[])356*44704f69SBart Van Assche parse_cmd_line(struct opts_t * op, int argc, char * argv[])
357*44704f69SBart Van Assche {
358*44704f69SBart Van Assche     int res;
359*44704f69SBart Van Assche     char * cp;
360*44704f69SBart Van Assche 
361*44704f69SBart Van Assche     cp = getenv("SG3_UTILS_OLD_OPTS");
362*44704f69SBart Van Assche     if (cp) {
363*44704f69SBart Van Assche         op->opt_new = false;
364*44704f69SBart Van Assche         res = old_parse_cmd_line(op, argc, argv);
365*44704f69SBart Van Assche         if ((0 == res) && op->opt_new)
366*44704f69SBart Van Assche             res = new_parse_cmd_line(op, argc, argv);
367*44704f69SBart Van Assche     } else {
368*44704f69SBart Van Assche         op->opt_new = true;
369*44704f69SBart Van Assche         res = new_parse_cmd_line(op, argc, argv);
370*44704f69SBart Van Assche         if ((0 == res) && (! op->opt_new))
371*44704f69SBart Van Assche             res = old_parse_cmd_line(op, argc, argv);
372*44704f69SBart Van Assche     }
373*44704f69SBart Van Assche     return res;
374*44704f69SBart Van Assche }
375*44704f69SBart Van Assche 
376*44704f69SBart Van Assche static void
dStrRaw(const uint8_t * str,int len)377*44704f69SBart Van Assche dStrRaw(const uint8_t * str, int len)
378*44704f69SBart Van Assche {
379*44704f69SBart Van Assche     int k;
380*44704f69SBart Van Assche 
381*44704f69SBart Van Assche     for (k = 0; k < len; ++k)
382*44704f69SBart Van Assche         printf("%c", str[k]);
383*44704f69SBart Van Assche }
384*44704f69SBart Van Assche 
385*44704f69SBart Van Assche static const char *
rc_basis_str(int rc_basis,char * b,int blen)386*44704f69SBart Van Assche rc_basis_str(int rc_basis, char * b, int blen)
387*44704f69SBart Van Assche {
388*44704f69SBart Van Assche     switch (rc_basis) {
389*44704f69SBart Van Assche     case 0:
390*44704f69SBart Van Assche         snprintf(b, blen, "last contiguous that's not seq write required");
391*44704f69SBart Van Assche         break;
392*44704f69SBart Van Assche     case 1:
393*44704f69SBart Van Assche         snprintf(b, blen, "last LBA on logical unit");
394*44704f69SBart Van Assche         break;
395*44704f69SBart Van Assche     default:
396*44704f69SBart Van Assche         snprintf(b, blen, "reserved (0x%x)", rc_basis);
397*44704f69SBart Van Assche         break;
398*44704f69SBart Van Assche     }
399*44704f69SBart Van Assche     return b;
400*44704f69SBart Van Assche }
401*44704f69SBart Van Assche 
402*44704f69SBart Van Assche 
403*44704f69SBart Van Assche int
main(int argc,char * argv[])404*44704f69SBart Van Assche main(int argc, char * argv[])
405*44704f69SBart Van Assche {
406*44704f69SBart Van Assche     bool rw_0_flag;
407*44704f69SBart Van Assche     int res, prot_en, p_type, lbppbe;
408*44704f69SBart Van Assche     int sg_fd = -1;
409*44704f69SBart Van Assche     int ret = 0;
410*44704f69SBart Van Assche     uint32_t last_blk_addr, block_size;
411*44704f69SBart Van Assche     uint64_t llast_blk_addr;
412*44704f69SBart Van Assche     uint8_t * resp_buff;
413*44704f69SBart Van Assche     uint8_t * free_resp_buff;
414*44704f69SBart Van Assche     const int resp_buff_sz = RCAP16_REPLY_LEN;
415*44704f69SBart Van Assche     char b[80];
416*44704f69SBart Van Assche     struct opts_t opts;
417*44704f69SBart Van Assche     struct opts_t * op;
418*44704f69SBart Van Assche 
419*44704f69SBart Van Assche     op = &opts;
420*44704f69SBart Van Assche     memset(op, 0, sizeof(opts));
421*44704f69SBart Van Assche     res = parse_cmd_line(op, argc, argv);
422*44704f69SBart Van Assche     if (res)
423*44704f69SBart Van Assche         return res;
424*44704f69SBart Van Assche     if (op->do_help) {
425*44704f69SBart Van Assche         usage_for(op);
426*44704f69SBart Van Assche         return 0;
427*44704f69SBart Van Assche     }
428*44704f69SBart Van Assche #ifdef DEBUG
429*44704f69SBart Van Assche     pr2serr("In DEBUG mode, ");
430*44704f69SBart Van Assche     if (op->verbose_given && op->version_given) {
431*44704f69SBart Van Assche         pr2serr("but override: '-vV' given, zero verbose and continue\n");
432*44704f69SBart Van Assche         op->verbose_given = false;
433*44704f69SBart Van Assche         op->version_given = false;
434*44704f69SBart Van Assche         op->verbose = 0;
435*44704f69SBart Van Assche     } else if (! op->verbose_given) {
436*44704f69SBart Van Assche         pr2serr("set '-vv'\n");
437*44704f69SBart Van Assche         op->verbose = 2;
438*44704f69SBart Van Assche     } else
439*44704f69SBart Van Assche         pr2serr("keep verbose=%d\n", op->verbose);
440*44704f69SBart Van Assche #else
441*44704f69SBart Van Assche     if (op->verbose_given && op->version_given)
442*44704f69SBart Van Assche         pr2serr("Not in DEBUG mode, so '-vV' has no special action\n");
443*44704f69SBart Van Assche #endif
444*44704f69SBart Van Assche     if (op->version_given) {
445*44704f69SBart Van Assche         pr2serr("Version string: %s\n", version_str);
446*44704f69SBart Van Assche         return 0;
447*44704f69SBart Van Assche     }
448*44704f69SBart Van Assche 
449*44704f69SBart Van Assche     if (NULL == op->device_name) {
450*44704f69SBart Van Assche         pr2serr("No DEVICE argument given\n\n");
451*44704f69SBart Van Assche         usage_for(op);
452*44704f69SBart Van Assche         return SG_LIB_SYNTAX_ERROR;
453*44704f69SBart Van Assche     }
454*44704f69SBart Van Assche     if (op->do_raw) {
455*44704f69SBart Van Assche         if (sg_set_binary_mode(STDOUT_FILENO) < 0) {
456*44704f69SBart Van Assche             perror("sg_set_binary_mode");
457*44704f69SBart Van Assche             return SG_LIB_FILE_ERROR;
458*44704f69SBart Van Assche         }
459*44704f69SBart Van Assche     }
460*44704f69SBart Van Assche     if (op->do_zbc) {
461*44704f69SBart Van Assche         if (! op->do_long)
462*44704f69SBart Van Assche             op->do_long = true;
463*44704f69SBart Van Assche     }
464*44704f69SBart Van Assche 
465*44704f69SBart Van Assche     resp_buff = sg_memalign(resp_buff_sz, 0, &free_resp_buff, false);
466*44704f69SBart Van Assche     if (NULL == resp_buff) {
467*44704f69SBart Van Assche         pr2serr("Unable to allocate %d bytes on heap\n", resp_buff_sz);
468*44704f69SBart Van Assche         return sg_convert_errno(ENOMEM);
469*44704f69SBart Van Assche     }
470*44704f69SBart Van Assche     if ((! op->do_pmi) && (op->llba > 0)) {
471*44704f69SBart Van Assche         pr2serr(ME "lba can only be non-zero when '--pmi' is set\n");
472*44704f69SBart Van Assche         usage_for(op);
473*44704f69SBart Van Assche         ret = SG_LIB_CONTRADICT;
474*44704f69SBart Van Assche         goto fini;
475*44704f69SBart Van Assche     }
476*44704f69SBart Van Assche     if (op->do_long)
477*44704f69SBart Van Assche         rw_0_flag = op->o_readonly;
478*44704f69SBart Van Assche     else
479*44704f69SBart Van Assche         rw_0_flag = true;  /* RCAP(10) has opened RO in past, so leave */
480*44704f69SBart Van Assche     if ((sg_fd = sg_cmds_open_device(op->device_name, rw_0_flag,
481*44704f69SBart Van Assche                                      op->verbose)) < 0) {
482*44704f69SBart Van Assche         pr2serr(ME "error opening file: %s: %s\n", op->device_name,
483*44704f69SBart Van Assche                 safe_strerror(-sg_fd));
484*44704f69SBart Van Assche         ret = sg_convert_errno(-sg_fd);
485*44704f69SBart Van Assche         goto fini;
486*44704f69SBart Van Assche     }
487*44704f69SBart Van Assche 
488*44704f69SBart Van Assche     if (! op->do_long) {
489*44704f69SBart Van Assche         res = sg_ll_readcap_10(sg_fd, op->do_pmi, (unsigned int)op->llba,
490*44704f69SBart Van Assche                                resp_buff, RCAP_REPLY_LEN, true,
491*44704f69SBart Van Assche                                op->verbose);
492*44704f69SBart Van Assche         ret = res;
493*44704f69SBart Van Assche         if (0 == res) {
494*44704f69SBart Van Assche             if (op->do_hex || op->do_raw) {
495*44704f69SBart Van Assche                 if (op->do_raw)
496*44704f69SBart Van Assche                     dStrRaw(resp_buff, RCAP_REPLY_LEN);
497*44704f69SBart Van Assche                 else if (op->do_hex > 2)
498*44704f69SBart Van Assche                     hex2stdout(resp_buff, RCAP_REPLY_LEN, -1);
499*44704f69SBart Van Assche                 else
500*44704f69SBart Van Assche                     hex2stdout(resp_buff, RCAP_REPLY_LEN, 1);
501*44704f69SBart Van Assche                 goto fini;
502*44704f69SBart Van Assche             }
503*44704f69SBart Van Assche             last_blk_addr = sg_get_unaligned_be32(resp_buff + 0);
504*44704f69SBart Van Assche             if (0xffffffff != last_blk_addr) {
505*44704f69SBart Van Assche                 block_size = sg_get_unaligned_be32(resp_buff + 4);
506*44704f69SBart Van Assche                 if (op->do_brief) {
507*44704f69SBart Van Assche                     printf("0x%" PRIx32 " 0x%" PRIx32 "\n",
508*44704f69SBart Van Assche                            last_blk_addr + 1, block_size);
509*44704f69SBart Van Assche                     goto fini;
510*44704f69SBart Van Assche                 }
511*44704f69SBart Van Assche                 printf("Read Capacity results:\n");
512*44704f69SBart Van Assche                 if (op->do_pmi)
513*44704f69SBart Van Assche                     printf("   PMI mode: given lba=0x%" PRIx64 ", last lba "
514*44704f69SBart Van Assche                            "before delay=0x%" PRIx32 "\n", op->llba,
515*44704f69SBart Van Assche                            last_blk_addr);
516*44704f69SBart Van Assche                 else
517*44704f69SBart Van Assche                     printf("   Last LBA=%" PRIu32 " (0x%" PRIx32 "), Number "
518*44704f69SBart Van Assche                            "of logical blocks=%" PRIu32 "\n", last_blk_addr,
519*44704f69SBart Van Assche                             last_blk_addr, last_blk_addr + 1);
520*44704f69SBart Van Assche                 printf("   Logical block length=%u bytes\n", block_size);
521*44704f69SBart Van Assche                 if (! op->do_pmi) {
522*44704f69SBart Van Assche                     uint64_t total_sz = last_blk_addr + 1;
523*44704f69SBart Van Assche                     double sz_mb, sz_gb;
524*44704f69SBart Van Assche 
525*44704f69SBart Van Assche                     total_sz *= block_size;
526*44704f69SBart Van Assche                     sz_mb = ((double)(last_blk_addr + 1) * block_size) /
527*44704f69SBart Van Assche                             (double)(1048576);
528*44704f69SBart Van Assche                     sz_gb = ((double)(last_blk_addr + 1) * block_size) /
529*44704f69SBart Van Assche                             (double)(1000000000L);
530*44704f69SBart Van Assche                     printf("Hence:\n");
531*44704f69SBart Van Assche #ifdef SG_LIB_MINGW
532*44704f69SBart Van Assche                     printf("   Device size: %" PRIu64 " bytes, %g MiB, %g "
533*44704f69SBart Van Assche                            "GB", total_sz, sz_mb, sz_gb);
534*44704f69SBart Van Assche #else
535*44704f69SBart Van Assche                     printf("   Device size: %" PRIu64 " bytes, %.1f MiB, "
536*44704f69SBart Van Assche                            "%.2f GB", total_sz, sz_mb, sz_gb);
537*44704f69SBart Van Assche #endif
538*44704f69SBart Van Assche                     if (sz_gb > 2000) {
539*44704f69SBart Van Assche #ifdef SG_LIB_MINGW
540*44704f69SBart Van Assche                         printf(", %g TB", sz_gb / 1000);
541*44704f69SBart Van Assche #else
542*44704f69SBart Van Assche                         printf(", %.2f TB", sz_gb / 1000);
543*44704f69SBart Van Assche #endif
544*44704f69SBart Van Assche                     }
545*44704f69SBart Van Assche                     printf("\n");
546*44704f69SBart Van Assche                 }
547*44704f69SBart Van Assche                 goto fini;
548*44704f69SBart Van Assche             } else {
549*44704f69SBart Van Assche                 printf("READ CAPACITY (10) indicates device capacity too "
550*44704f69SBart Van Assche                        "large\n  now trying 16 byte cdb variant\n");
551*44704f69SBart Van Assche                 op->do_long = true;
552*44704f69SBart Van Assche             }
553*44704f69SBart Van Assche         } else if (SG_LIB_CAT_INVALID_OP == res) {
554*44704f69SBart Van Assche             op->do_long = true;
555*44704f69SBart Van Assche             sg_cmds_close_device(sg_fd);
556*44704f69SBart Van Assche             if ((sg_fd = sg_cmds_open_device(op->device_name, op->o_readonly,
557*44704f69SBart Van Assche                                              op->verbose)) < 0) {
558*44704f69SBart Van Assche                 pr2serr(ME "error re-opening file: %s (rw): %s\n",
559*44704f69SBart Van Assche                         op->device_name, safe_strerror(-sg_fd));
560*44704f69SBart Van Assche                 ret = sg_convert_errno(-sg_fd);
561*44704f69SBart Van Assche                 goto fini;
562*44704f69SBart Van Assche             }
563*44704f69SBart Van Assche             if (op->verbose)
564*44704f69SBart Van Assche                 pr2serr("READ CAPACITY (10) not supported, trying READ "
565*44704f69SBart Van Assche                         "CAPACITY (16)\n");
566*44704f69SBart Van Assche         } else if (res) {
567*44704f69SBart Van Assche             sg_get_category_sense_str(res, sizeof(b), b, op->verbose);
568*44704f69SBart Van Assche             pr2serr("READ CAPACITY (10) failed: %s\n", b);
569*44704f69SBart Van Assche         }
570*44704f69SBart Van Assche     }
571*44704f69SBart Van Assche     if (op->do_long) {
572*44704f69SBart Van Assche         res = sg_ll_readcap_16(sg_fd, op->do_pmi, op->llba, resp_buff,
573*44704f69SBart Van Assche                                RCAP16_REPLY_LEN, true, op->verbose);
574*44704f69SBart Van Assche         ret = res;
575*44704f69SBart Van Assche         if (0 == res) {
576*44704f69SBart Van Assche             if (op->do_hex || op->do_raw) {
577*44704f69SBart Van Assche                 if (op->do_raw)
578*44704f69SBart Van Assche                     dStrRaw(resp_buff, RCAP16_REPLY_LEN);
579*44704f69SBart Van Assche                 else if (op->do_hex > 2)
580*44704f69SBart Van Assche                     hex2stdout(resp_buff, RCAP16_REPLY_LEN, -1);
581*44704f69SBart Van Assche                 else
582*44704f69SBart Van Assche                     hex2stdout(resp_buff, RCAP16_REPLY_LEN, 1);
583*44704f69SBart Van Assche                 goto fini;
584*44704f69SBart Van Assche             }
585*44704f69SBart Van Assche             llast_blk_addr = sg_get_unaligned_be64(resp_buff + 0);
586*44704f69SBart Van Assche             block_size = sg_get_unaligned_be32(resp_buff + 8);
587*44704f69SBart Van Assche             if (op->do_brief) {
588*44704f69SBart Van Assche                 printf("0x%" PRIx64 " 0x%" PRIx32 "\n", llast_blk_addr + 1,
589*44704f69SBart Van Assche                        block_size);
590*44704f69SBart Van Assche                 goto fini;
591*44704f69SBart Van Assche             }
592*44704f69SBart Van Assche             prot_en = !!(resp_buff[12] & 0x1);
593*44704f69SBart Van Assche             p_type = ((resp_buff[12] >> 1) & 0x7);
594*44704f69SBart Van Assche             printf("Read Capacity results:\n");
595*44704f69SBart Van Assche             printf("   Protection: prot_en=%d, p_type=%d, p_i_exponent=%d",
596*44704f69SBart Van Assche                    prot_en, p_type, ((resp_buff[13] >> 4) & 0xf));
597*44704f69SBart Van Assche             if (prot_en)
598*44704f69SBart Van Assche                 printf(" [type %d protection]\n", p_type + 1);
599*44704f69SBart Van Assche             else
600*44704f69SBart Van Assche                 printf("\n");
601*44704f69SBart Van Assche             if (op->do_zbc) {
602*44704f69SBart Van Assche                 int rc_basis = (resp_buff[12] >> 4) & 0x3;
603*44704f69SBart Van Assche 
604*44704f69SBart Van Assche                 printf("   ZBC's rc_basis=%d [%s]\n", rc_basis,
605*44704f69SBart Van Assche                        rc_basis_str(rc_basis, b, sizeof(b)));
606*44704f69SBart Van Assche             }
607*44704f69SBart Van Assche             printf("   Logical block provisioning: lbpme=%d, lbprz=%d\n",
608*44704f69SBart Van Assche                    !!(resp_buff[14] & 0x80), !!(resp_buff[14] & 0x40));
609*44704f69SBart Van Assche             if (op->do_pmi)
610*44704f69SBart Van Assche                 printf("   PMI mode: given lba=0x%" PRIx64 ", last lba "
611*44704f69SBart Van Assche                        "before delay=0x%" PRIx64 "\n", op->llba,
612*44704f69SBart Van Assche                        llast_blk_addr);
613*44704f69SBart Van Assche             else
614*44704f69SBart Van Assche                 printf("   Last LBA=%" PRIu64 " (0x%" PRIx64 "), Number of "
615*44704f69SBart Van Assche                        "logical blocks=%" PRIu64 "\n", llast_blk_addr,
616*44704f69SBart Van Assche                        llast_blk_addr, llast_blk_addr + 1);
617*44704f69SBart Van Assche             printf("   Logical block length=%" PRIu32 " bytes\n", block_size);
618*44704f69SBart Van Assche             lbppbe = resp_buff[13] & 0xf;
619*44704f69SBart Van Assche             printf("   Logical blocks per physical block exponent=%d",
620*44704f69SBart Van Assche                    lbppbe);
621*44704f69SBart Van Assche             if (lbppbe > 0)
622*44704f69SBart Van Assche                 printf(" [so physical block length=%u bytes]\n",
623*44704f69SBart Van Assche                        block_size * (1 << lbppbe));
624*44704f69SBart Van Assche             else
625*44704f69SBart Van Assche                 printf("\n");
626*44704f69SBart Van Assche             printf("   Lowest aligned LBA=%d\n",
627*44704f69SBart Van Assche                    ((resp_buff[14] & 0x3f) << 8) + resp_buff[15]);
628*44704f69SBart Van Assche             if (! op->do_pmi) {
629*44704f69SBart Van Assche                 uint64_t total_sz = llast_blk_addr + 1;
630*44704f69SBart Van Assche                 double sz_mb, sz_gb;
631*44704f69SBart Van Assche 
632*44704f69SBart Van Assche                 total_sz *= block_size;
633*44704f69SBart Van Assche                 sz_mb = ((double)(llast_blk_addr + 1) * block_size) /
634*44704f69SBart Van Assche                         (double)(1048576);
635*44704f69SBart Van Assche                 sz_gb = ((double)(llast_blk_addr + 1) * block_size) /
636*44704f69SBart Van Assche                         (double)(1000000000L);
637*44704f69SBart Van Assche                 printf("Hence:\n");
638*44704f69SBart Van Assche #ifdef SG_LIB_MINGW
639*44704f69SBart Van Assche                 printf("   Device size: %" PRIu64 " bytes, %g MiB, %g GB",
640*44704f69SBart Van Assche                        total_sz, sz_mb, sz_gb);
641*44704f69SBart Van Assche #else
642*44704f69SBart Van Assche                 printf("   Device size: %" PRIu64 " bytes, %.1f MiB, %.2f "
643*44704f69SBart Van Assche                        "GB", total_sz, sz_mb, sz_gb);
644*44704f69SBart Van Assche #endif
645*44704f69SBart Van Assche                 if (sz_gb > 2000) {
646*44704f69SBart Van Assche #ifdef SG_LIB_MINGW
647*44704f69SBart Van Assche                     printf(", %g TB", sz_gb / 1000);
648*44704f69SBart Van Assche #else
649*44704f69SBart Van Assche                     printf(", %.2f TB", sz_gb / 1000);
650*44704f69SBart Van Assche #endif
651*44704f69SBart Van Assche                 }
652*44704f69SBart Van Assche                 printf("\n");
653*44704f69SBart Van Assche             }
654*44704f69SBart Van Assche             goto fini;
655*44704f69SBart Van Assche         } else if (SG_LIB_CAT_ILLEGAL_REQ == res)
656*44704f69SBart Van Assche             pr2serr("bad field in READ CAPACITY (16) cdb including "
657*44704f69SBart Van Assche                     "unsupported service action\n");
658*44704f69SBart Van Assche         else if (res) {
659*44704f69SBart Van Assche             sg_get_category_sense_str(res, sizeof(b), b, op->verbose);
660*44704f69SBart Van Assche             pr2serr("READ CAPACITY (16) failed: %s\n", b);
661*44704f69SBart Van Assche         }
662*44704f69SBart Van Assche     }
663*44704f69SBart Van Assche     if (op->do_brief)
664*44704f69SBart Van Assche         printf("0x0 0x0\n");
665*44704f69SBart Van Assche fini:
666*44704f69SBart Van Assche     if (free_resp_buff)
667*44704f69SBart Van Assche         free(free_resp_buff);
668*44704f69SBart Van Assche     if (sg_fd >= 0) {
669*44704f69SBart Van Assche         res = sg_cmds_close_device(sg_fd);
670*44704f69SBart Van Assche         if (res < 0) {
671*44704f69SBart Van Assche             pr2serr("close error: %s\n", safe_strerror(-res));
672*44704f69SBart Van Assche             if (0 == ret)
673*44704f69SBart Van Assche                 ret = sg_convert_errno(-res);
674*44704f69SBart Van Assche         }
675*44704f69SBart Van Assche     }
676*44704f69SBart Van Assche     if (0 == op->verbose) {
677*44704f69SBart Van Assche         if (! sg_if_can2stderr("sg_readcap failed: ", ret))
678*44704f69SBart Van Assche             pr2serr("Some error occurred, try again with '-v' "
679*44704f69SBart Van Assche                     "or '-vv' for more information\n");
680*44704f69SBart Van Assche     }
681*44704f69SBart Van Assche     return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
682*44704f69SBart Van Assche }
683