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