1 /*
2  * Copyright (c) 2009-2015 Douglas Gilbert.
3  * All rights reserved.
4  * Use of this source code is governed by a BSD-style
5  * license that can be found in the BSD_LICENSE file.
6  */
7 
8 #include <unistd.h>
9 #include <fcntl.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <getopt.h>
14 #define __STDC_FORMAT_MACROS 1
15 #include <inttypes.h>
16 
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
20 #include "sg_lib.h"
21 #include "sg_cmds_basic.h"
22 #include "sg_cmds_extra.h"
23 #include "sg_unaligned.h"
24 #include "sg_pr2serr.h"
25 
26 /* A utility program originally written for the Linux OS SCSI subsystem.
27  *
28  *
29  * This program issues the SCSI READ BLOCK LIMITS command (SSC) to the given
30  * SCSI device.
31  */
32 
33 static const char * version_str = "1.04 20151219";
34 
35 #define MAX_READ_BLOCK_LIMITS_LEN 6
36 
37 static unsigned char readBlkLmtBuff[MAX_READ_BLOCK_LIMITS_LEN];
38 
39 
40 static struct option long_options[] = {
41         {"help", no_argument, 0, 'h'},
42         {"hex", no_argument, 0, 'H'},
43         {"raw", no_argument, 0, 'r'},
44         {"verbose", no_argument, 0, 'v'},
45         {"version", no_argument, 0, 'V'},
46         {0, 0, 0, 0},
47 };
48 
49 
50 static void
usage()51 usage()
52 {
53     pr2serr("Usage: sg_read_block_limits  [--help] [--hex] [--raw] "
54             "[--verbose] [--version]\n"
55             "                             DEVICE\n"
56             "  where:\n"
57             "    --help|-h          print out usage message\n"
58             "    --hex|-H           output response in hexadecimal\n"
59             "    --raw|-r           output response in binary to stdout\n"
60             "    --verbose|-v       increase verbosity\n"
61             "    --version|-V       print version string and exit\n\n"
62             "Performs a SCSI READ BLOCK LIMITS command and decode the "
63             "response\n"
64             );
65 }
66 
67 static void
dStrRaw(const char * str,int len)68 dStrRaw(const char* str, int len)
69 {
70     int k;
71 
72     for (k = 0 ; k < len; ++k)
73         printf("%c", str[k]);
74 }
75 
76 int
main(int argc,char * argv[])77 main(int argc, char * argv[])
78 {
79     int sg_fd, k, m, res, c;
80     int do_hex = 0;
81     int do_raw = 0;
82     int verbose = 0;
83     const char * device_name = NULL;
84     int ret = 0;
85     uint32_t max_block_size;
86     uint16_t min_block_size;
87 
88     while (1) {
89         int option_index = 0;
90 
91         c = getopt_long(argc, argv, "hHrvV", long_options,
92                         &option_index);
93         if (c == -1)
94             break;
95 
96         switch (c) {
97         case 'h':
98         case '?':
99             usage();
100             return 0;
101         case 'H':
102             ++do_hex;
103             break;
104         case 'r':
105             ++do_raw;
106             break;
107         case 'v':
108             ++verbose;
109             break;
110         case 'V':
111             pr2serr("version: %s\n", version_str);
112             return 0;
113         default:
114             pr2serr("invalid option -%c ??\n", c);
115             usage();
116             return SG_LIB_SYNTAX_ERROR;
117         }
118     }
119     if (optind < argc) {
120         if (NULL == device_name) {
121             device_name = argv[optind];
122             ++optind;
123         }
124         if (optind < argc) {
125             for (; optind < argc; ++optind)
126                 pr2serr("Unexpected extra argument: %s\n", argv[optind]);
127             usage();
128             return SG_LIB_SYNTAX_ERROR;
129         }
130     }
131 
132     if (NULL == device_name) {
133         pr2serr("missing device name!\n");
134         usage();
135         return SG_LIB_SYNTAX_ERROR;
136     }
137 
138     sg_fd = sg_cmds_open_device(device_name, 0 /* rw */, verbose);
139     if (sg_fd < 0) {
140         pr2serr("open error: %s: %s\n", device_name, safe_strerror(-sg_fd));
141         return SG_LIB_FILE_ERROR;
142     }
143 
144     memset(readBlkLmtBuff, 0x0, 6);
145     res = sg_ll_read_block_limits(sg_fd, readBlkLmtBuff, 6, 1,
146                             verbose);
147     ret = res;
148     if (0 == res) {
149       if (do_hex) {
150         dStrHex((const char *)readBlkLmtBuff, sizeof(readBlkLmtBuff), 1);
151         goto the_end;
152       } else if (do_raw) {
153         dStrRaw((const char *)readBlkLmtBuff, sizeof(readBlkLmtBuff));
154         goto the_end;
155       }
156 
157       max_block_size = sg_get_unaligned_be32(readBlkLmtBuff + 0);
158       min_block_size = sg_get_unaligned_be16(readBlkLmtBuff + 4);
159       k = min_block_size / 1024;
160       pr2serr("Read Block Limits results:\n");
161       pr2serr("\tMinimum block size: %u byte(s)",
162               (unsigned int)min_block_size);
163       if (k != 0)
164         pr2serr(", %d KB", k);
165       pr2serr("\n");
166       k = max_block_size / 1024;
167       m = max_block_size / 1048576;
168       pr2serr("\tMaximum block size: %u byte(s)",
169               (unsigned int)max_block_size);
170       if (k != 0)
171         pr2serr(", %d KB", k);
172       if (m != 0)
173         pr2serr(", %d MB", m);
174       pr2serr("\n");
175     } else {
176         char b[80];
177 
178         sg_get_category_sense_str(res, sizeof(b), b, verbose);
179         pr2serr("Read block limits: %s\n", b);
180         if (0 == verbose)
181             pr2serr("    try '-v' option for more information\n");
182     }
183 
184 the_end:
185     res = sg_cmds_close_device(sg_fd);
186     if (res < 0) {
187         pr2serr("close error: %s\n", safe_strerror(-res));
188         if (0 == ret)
189             return SG_LIB_FILE_ERROR;
190     }
191     return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
192 }
193