xref: /aosp_15_r20/external/sg3_utils/src/sg_requests.c (revision 44704f698541f6367e81f991ef8bb54ccbf3fc18)
1*44704f69SBart Van Assche /*
2*44704f69SBart Van Assche  * Copyright (c) 2004-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 <stdint.h>
17*44704f69SBart Van Assche #include <string.h>
18*44704f69SBart Van Assche #include <errno.h>
19*44704f69SBart Van Assche #include <getopt.h>
20*44704f69SBart Van Assche #include <sys/time.h>
21*44704f69SBart Van Assche 
22*44704f69SBart Van Assche #ifdef HAVE_CONFIG_H
23*44704f69SBart Van Assche #include "config.h"
24*44704f69SBart Van Assche #endif
25*44704f69SBart Van Assche 
26*44704f69SBart Van Assche #include "sg_lib.h"
27*44704f69SBart Van Assche #include "sg_cmds_basic.h"
28*44704f69SBart Van Assche #include "sg_pr2serr.h"
29*44704f69SBart Van Assche #include "sg_pt.h"
30*44704f69SBart Van Assche 
31*44704f69SBart Van Assche /* A utility program for the Linux OS SCSI subsystem.
32*44704f69SBart Van Assche  *
33*44704f69SBart Van Assche  *
34*44704f69SBart Van Assche  * This program issues the SCSI command REQUEST SENSE to the given SCSI device.
35*44704f69SBart Van Assche  */
36*44704f69SBart Van Assche 
37*44704f69SBart Van Assche static const char * version_str = "1.40 20220607";
38*44704f69SBart Van Assche 
39*44704f69SBart Van Assche #define MAX_REQS_RESP_LEN 255
40*44704f69SBart Van Assche #define DEF_REQS_RESP_LEN 252
41*44704f69SBart Van Assche 
42*44704f69SBart Van Assche #define SENSE_BUFF_LEN 96       /* Arbitrary, could be larger */
43*44704f69SBart Van Assche #define DEF_PT_TIMEOUT 60       /* 60 seconds */
44*44704f69SBart Van Assche 
45*44704f69SBart Van Assche #define REQUEST_SENSE_CMD 0x3
46*44704f69SBart Van Assche #define REQUEST_SENSE_CMDLEN 6
47*44704f69SBart Van Assche 
48*44704f69SBart Van Assche #define ME "sg_requests: "
49*44704f69SBart Van Assche 
50*44704f69SBart Van Assche 
51*44704f69SBart Van Assche static struct option long_options[] = {
52*44704f69SBart Van Assche         {"desc", no_argument, 0, 'd'},
53*44704f69SBart Van Assche         {"error", no_argument, 0, 'e'},
54*44704f69SBart Van Assche         {"help", no_argument, 0, 'h'},
55*44704f69SBart Van Assche         {"hex", no_argument, 0, 'H'},
56*44704f69SBart Van Assche         {"maxlen", required_argument, 0, 'm'},
57*44704f69SBart Van Assche         {"num", required_argument, 0, 'n'},
58*44704f69SBart Van Assche         {"number", required_argument, 0, 'n'},
59*44704f69SBart Van Assche         {"progress", no_argument, 0, 'p'},
60*44704f69SBart Van Assche         {"raw", no_argument, 0, 'r'},
61*44704f69SBart Van Assche         {"status", no_argument, 0, 's'},
62*44704f69SBart Van Assche         {"time", no_argument, 0, 't'},
63*44704f69SBart Van Assche         {"verbose", no_argument, 0, 'v'},
64*44704f69SBart Van Assche         {"version", no_argument, 0, 'V'},
65*44704f69SBart Van Assche         {0, 0, 0, 0},
66*44704f69SBart Van Assche };
67*44704f69SBart Van Assche 
68*44704f69SBart Van Assche static void
usage()69*44704f69SBart Van Assche usage()
70*44704f69SBart Van Assche {
71*44704f69SBart Van Assche     pr2serr("Usage: sg_requests [--desc] [--error] [--help] [--hex] "
72*44704f69SBart Van Assche             "[--maxlen=LEN]\n"
73*44704f69SBart Van Assche             "                   [--num=NUM] [--number=NUM] [--progress] "
74*44704f69SBart Van Assche             "[--raw]\n"
75*44704f69SBart Van Assche             "                   [--status] [--time] [--verbose] "
76*44704f69SBart Van Assche             "[--version] DEVICE\n"
77*44704f69SBart Van Assche             "  where:\n"
78*44704f69SBart Van Assche             "    --desc|-d         set flag for descriptor sense "
79*44704f69SBart Van Assche             "format\n"
80*44704f69SBart Van Assche             "    --error|-e        change opcode to 0xff; to measure "
81*44704f69SBart Van Assche             "overhead\n"
82*44704f69SBart Van Assche             "                      twice: skip ioctl call\n"
83*44704f69SBart Van Assche             "    --help|-h         print out usage message\n"
84*44704f69SBart Van Assche             "    --hex|-H          output in hexadecimal\n"
85*44704f69SBart Van Assche             "    --maxlen=LEN|-m LEN    max response length (allocation "
86*44704f69SBart Van Assche             "length in cdb)\n"
87*44704f69SBart Van Assche             "                           (def: 0 -> 252 bytes)\n"
88*44704f69SBart Van Assche             "    --num=NUM|-n NUM  number of REQUEST SENSE commands "
89*44704f69SBart Van Assche             "to send (def: 1)\n"
90*44704f69SBart Van Assche             "    --number=NUM      same action as '--num=NUM'\n"
91*44704f69SBart Van Assche             "    --progress|-p     output a progress indication (percentage) "
92*44704f69SBart Van Assche             "if available\n"
93*44704f69SBart Van Assche             "    --raw|-r          output in binary (to stdout)\n"
94*44704f69SBart Van Assche             "    --status|-s       set exit status from parameter data "
95*44704f69SBart Van Assche             "(def: only set\n"
96*44704f69SBart Van Assche             "                       exit status from autosense)\n"
97*44704f69SBart Van Assche             "    --time|-t         time the transfer, calculate commands "
98*44704f69SBart Van Assche             "per second\n"
99*44704f69SBart Van Assche             "    --verbose|-v      increase verbosity\n"
100*44704f69SBart Van Assche             "    --version|-V      print version string and exit\n\n"
101*44704f69SBart Van Assche             "Performs a SCSI REQUEST SENSE command\n"
102*44704f69SBart Van Assche             );
103*44704f69SBart Van Assche 
104*44704f69SBart Van Assche }
105*44704f69SBart Van Assche 
106*44704f69SBart Van Assche static void
dStrRaw(const uint8_t * str,int len)107*44704f69SBart Van Assche dStrRaw(const uint8_t * str, int len)
108*44704f69SBart Van Assche {
109*44704f69SBart Van Assche     int k;
110*44704f69SBart Van Assche 
111*44704f69SBart Van Assche     for (k = 0; k < len; ++k)
112*44704f69SBart Van Assche         printf("%c", str[k]);
113*44704f69SBart Van Assche }
114*44704f69SBart Van Assche 
115*44704f69SBart Van Assche int
main(int argc,char * argv[])116*44704f69SBart Van Assche main(int argc, char * argv[])
117*44704f69SBart Van Assche {
118*44704f69SBart Van Assche     int c, n, k, progress, rs, sense_cat, act_din_len;
119*44704f69SBart Van Assche     int do_error = 0;
120*44704f69SBart Van Assche     int err = 0;
121*44704f69SBart Van Assche     int num_errs = 0;
122*44704f69SBart Van Assche     int num_din_errs = 0;
123*44704f69SBart Van Assche     int most_recent_skey = 0;
124*44704f69SBart Van Assche     int sg_fd = -1;
125*44704f69SBart Van Assche     int res = 0;
126*44704f69SBart Van Assche     uint8_t rsBuff[MAX_REQS_RESP_LEN + 1];
127*44704f69SBart Van Assche     bool desc = false;
128*44704f69SBart Van Assche     bool do_progress = false;
129*44704f69SBart Van Assche     bool do_raw = false;
130*44704f69SBart Van Assche     bool do_status = false;
131*44704f69SBart Van Assche     bool verbose_given = false;
132*44704f69SBart Van Assche     bool version_given = false;
133*44704f69SBart Van Assche     bool not_raw_hex;
134*44704f69SBart Van Assche     int num_rs = 1;
135*44704f69SBart Van Assche     int do_hex = 0;
136*44704f69SBart Van Assche     int maxlen = 0;
137*44704f69SBart Van Assche     int verbose = 0;
138*44704f69SBart Van Assche     const char * device_name = NULL;
139*44704f69SBart Van Assche     int ret = 0;
140*44704f69SBart Van Assche     struct sg_pt_base * ptvp = NULL;
141*44704f69SBart Van Assche     char b[256];
142*44704f69SBart Van Assche     uint8_t rs_cdb[REQUEST_SENSE_CMDLEN] =
143*44704f69SBart Van Assche         {REQUEST_SENSE_CMD, 0, 0, 0, 0, 0};
144*44704f69SBart Van Assche     uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT;
145*44704f69SBart Van Assche #ifndef SG_LIB_MINGW
146*44704f69SBart Van Assche     bool do_time = false;
147*44704f69SBart Van Assche     struct timeval start_tm, end_tm;
148*44704f69SBart Van Assche #endif
149*44704f69SBart Van Assche 
150*44704f69SBart Van Assche     while (1) {
151*44704f69SBart Van Assche         int option_index = 0;
152*44704f69SBart Van Assche 
153*44704f69SBart Van Assche         c = getopt_long(argc, argv, "dehHm:n:prstvV", long_options,
154*44704f69SBart Van Assche                         &option_index);
155*44704f69SBart Van Assche         if (c == -1)
156*44704f69SBart Van Assche             break;
157*44704f69SBart Van Assche 
158*44704f69SBart Van Assche         switch (c) {
159*44704f69SBart Van Assche         case 'd':
160*44704f69SBart Van Assche             desc = true;
161*44704f69SBart Van Assche             break;
162*44704f69SBart Van Assche         case 'e':
163*44704f69SBart Van Assche             ++do_error;
164*44704f69SBart Van Assche             break;
165*44704f69SBart Van Assche         case 'h':
166*44704f69SBart Van Assche         case '?':
167*44704f69SBart Van Assche             usage();
168*44704f69SBart Van Assche             return 0;
169*44704f69SBart Van Assche         case 'H':
170*44704f69SBart Van Assche             ++do_hex;
171*44704f69SBart Van Assche             break;
172*44704f69SBart Van Assche         case 'm':
173*44704f69SBart Van Assche             maxlen = sg_get_num(optarg);
174*44704f69SBart Van Assche             if ((maxlen < 0) || (maxlen > MAX_REQS_RESP_LEN)) {
175*44704f69SBart Van Assche                 pr2serr("argument to '--maxlen' should be %d or less\n",
176*44704f69SBart Van Assche                         MAX_REQS_RESP_LEN);
177*44704f69SBart Van Assche                 return SG_LIB_SYNTAX_ERROR;
178*44704f69SBart Van Assche             }
179*44704f69SBart Van Assche             break;
180*44704f69SBart Van Assche         case 'n':
181*44704f69SBart Van Assche            num_rs = sg_get_num(optarg);
182*44704f69SBart Van Assche            if (num_rs < 1) {
183*44704f69SBart Van Assche                 pr2serr("bad argument to '--num'\n");
184*44704f69SBart Van Assche                 return SG_LIB_SYNTAX_ERROR;
185*44704f69SBart Van Assche             }
186*44704f69SBart Van Assche             break;
187*44704f69SBart Van Assche         case 'p':
188*44704f69SBart Van Assche             do_progress = true;
189*44704f69SBart Van Assche             break;
190*44704f69SBart Van Assche         case 'r':
191*44704f69SBart Van Assche             do_raw = true;
192*44704f69SBart Van Assche             break;
193*44704f69SBart Van Assche         case 's':
194*44704f69SBart Van Assche             do_status = true;
195*44704f69SBart Van Assche             break;
196*44704f69SBart Van Assche         case 't':
197*44704f69SBart Van Assche #ifndef SG_LIB_MINGW
198*44704f69SBart Van Assche             do_time = true;
199*44704f69SBart Van Assche #endif
200*44704f69SBart Van Assche             break;
201*44704f69SBart Van Assche         case 'v':
202*44704f69SBart Van Assche             verbose_given = true;
203*44704f69SBart Van Assche             ++verbose;
204*44704f69SBart Van Assche             break;
205*44704f69SBart Van Assche         case 'V':
206*44704f69SBart Van Assche             version_given = true;
207*44704f69SBart Van Assche             break;
208*44704f69SBart Van Assche         default:
209*44704f69SBart Van Assche             pr2serr("unrecognised option code 0x%x ??\n", c);
210*44704f69SBart Van Assche             usage();
211*44704f69SBart Van Assche             return SG_LIB_SYNTAX_ERROR;
212*44704f69SBart Van Assche         }
213*44704f69SBart Van Assche     }
214*44704f69SBart Van Assche     if (optind < argc) {
215*44704f69SBart Van Assche         if (NULL == device_name) {
216*44704f69SBart Van Assche             device_name = argv[optind];
217*44704f69SBart Van Assche             ++optind;
218*44704f69SBart Van Assche         }
219*44704f69SBart Van Assche         if (optind < argc) {
220*44704f69SBart Van Assche             for (; optind < argc; ++optind)
221*44704f69SBart Van Assche                 pr2serr("Unexpected extra argument: %s\n", argv[optind]);
222*44704f69SBart Van Assche             usage();
223*44704f69SBart Van Assche             return SG_LIB_SYNTAX_ERROR;
224*44704f69SBart Van Assche         }
225*44704f69SBart Van Assche     }
226*44704f69SBart Van Assche #ifdef DEBUG
227*44704f69SBart Van Assche     pr2serr("In DEBUG mode, ");
228*44704f69SBart Van Assche     if (verbose_given && version_given) {
229*44704f69SBart Van Assche         pr2serr("but override: '-vV' given, zero verbose and continue\n");
230*44704f69SBart Van Assche         verbose_given = false;
231*44704f69SBart Van Assche         version_given = false;
232*44704f69SBart Van Assche         verbose = 0;
233*44704f69SBart Van Assche     } else if (! verbose_given) {
234*44704f69SBart Van Assche         pr2serr("set '-vv'\n");
235*44704f69SBart Van Assche         verbose = 2;
236*44704f69SBart Van Assche     } else
237*44704f69SBart Van Assche         pr2serr("keep verbose=%d\n", verbose);
238*44704f69SBart Van Assche #else
239*44704f69SBart Van Assche     if (verbose_given && version_given)
240*44704f69SBart Van Assche         pr2serr("Not in DEBUG mode, so '-vV' has no special action\n");
241*44704f69SBart Van Assche #endif
242*44704f69SBart Van Assche     if (version_given) {
243*44704f69SBart Van Assche         pr2serr(ME "version: %s\n", version_str);
244*44704f69SBart Van Assche         return 0;
245*44704f69SBart Van Assche     }
246*44704f69SBart Van Assche 
247*44704f69SBart Van Assche     if (0 == maxlen)
248*44704f69SBart Van Assche         maxlen = DEF_REQS_RESP_LEN;
249*44704f69SBart Van Assche     if (NULL == device_name) {
250*44704f69SBart Van Assche         pr2serr("Missing device name!\n\n");
251*44704f69SBart Van Assche         usage();
252*44704f69SBart Van Assche         return SG_LIB_SYNTAX_ERROR;
253*44704f69SBart Van Assche     }
254*44704f69SBart Van Assche     if (do_raw) {
255*44704f69SBart Van Assche         if (sg_set_binary_mode(STDOUT_FILENO) < 0) {
256*44704f69SBart Van Assche             perror("sg_set_binary_mode");
257*44704f69SBart Van Assche             return SG_LIB_FILE_ERROR;
258*44704f69SBart Van Assche         }
259*44704f69SBart Van Assche     }
260*44704f69SBart Van Assche     if (do_raw || do_hex) {
261*44704f69SBart Van Assche         not_raw_hex = false;
262*44704f69SBart Van Assche #ifdef SG_LIB_MINGW
263*44704f69SBart Van Assche         bool prog_time = do_progress;
264*44704f69SBart Van Assche #else
265*44704f69SBart Van Assche         bool prog_time = do_progress || do_time;
266*44704f69SBart Van Assche #endif
267*44704f69SBart Van Assche 
268*44704f69SBart Van Assche         if (prog_time) {
269*44704f69SBart Van Assche             pr2serr("With either --raw or --hex, --progress and --time "
270*44704f69SBart Van Assche                     "contradict\n");
271*44704f69SBart Van Assche             ret = SG_LIB_CONTRADICT;
272*44704f69SBart Van Assche             goto finish;
273*44704f69SBart Van Assche         }
274*44704f69SBart Van Assche     } else
275*44704f69SBart Van Assche         not_raw_hex = true;
276*44704f69SBart Van Assche 
277*44704f69SBart Van Assche     sg_fd = sg_cmds_open_device(device_name, true /* ro */, verbose);
278*44704f69SBart Van Assche     if (sg_fd < 0) {
279*44704f69SBart Van Assche         if (not_raw_hex && verbose)
280*44704f69SBart Van Assche             pr2serr(ME "open error: %s: %s\n", device_name,
281*44704f69SBart Van Assche                     safe_strerror(-sg_fd));
282*44704f69SBart Van Assche         ret = sg_convert_errno(-sg_fd);
283*44704f69SBart Van Assche         goto finish;
284*44704f69SBart Van Assche     }
285*44704f69SBart Van Assche     ptvp = construct_scsi_pt_obj_with_fd(sg_fd, verbose);
286*44704f69SBart Van Assche     if ((NULL == ptvp) || ((err = get_scsi_pt_os_err(ptvp)))) {
287*44704f69SBart Van Assche         if (not_raw_hex)
288*44704f69SBart Van Assche             pr2serr("%s: unable to construct pt object\n", __func__);
289*44704f69SBart Van Assche         ret = sg_convert_errno(err ? err : ENOMEM);
290*44704f69SBart Van Assche         goto finish;
291*44704f69SBart Van Assche     }
292*44704f69SBart Van Assche     if (do_error)
293*44704f69SBart Van Assche         rs_cdb[0] = 0xff;
294*44704f69SBart Van Assche     if (desc)
295*44704f69SBart Van Assche         rs_cdb[1] |= 0x1;
296*44704f69SBart Van Assche     rs_cdb[4] = maxlen;
297*44704f69SBart Van Assche     if (do_progress) {
298*44704f69SBart Van Assche         for (k = 0; k < num_rs; ++k) {
299*44704f69SBart Van Assche             act_din_len = 0;
300*44704f69SBart Van Assche             if (k > 0)
301*44704f69SBart Van Assche                 sg_sleep_secs(30);
302*44704f69SBart Van Assche             set_scsi_pt_cdb(ptvp, rs_cdb, sizeof(rs_cdb));
303*44704f69SBart Van Assche             set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
304*44704f69SBart Van Assche             memset(rsBuff, 0x0, sizeof(rsBuff));
305*44704f69SBart Van Assche             set_scsi_pt_data_in(ptvp, rsBuff, sizeof(rsBuff));
306*44704f69SBart Van Assche             set_scsi_pt_packet_id(ptvp, k + 1);
307*44704f69SBart Van Assche             if (do_error > 1) {
308*44704f69SBart Van Assche                 ++num_errs;
309*44704f69SBart Van Assche                 n = 0;
310*44704f69SBart Van Assche             } else {
311*44704f69SBart Van Assche                 if (verbose && (0 == k)) {
312*44704f69SBart Van Assche                     char bb[128];
313*44704f69SBart Van Assche 
314*44704f69SBart Van Assche                     pr2serr("    cdb: %s\n",
315*44704f69SBart Van Assche                             sg_get_command_str(rs_cdb, REQUEST_SENSE_CMDLEN,
316*44704f69SBart Van Assche                                                true, sizeof(bb), bb));
317*44704f69SBart Van Assche                 }
318*44704f69SBart Van Assche                 rs = do_scsi_pt(ptvp, -1, DEF_PT_TIMEOUT, verbose);
319*44704f69SBart Van Assche                 n = sg_cmds_process_resp(ptvp, "Request sense", rs, (0 == k),
320*44704f69SBart Van Assche                                          verbose, &sense_cat);
321*44704f69SBart Van Assche             }
322*44704f69SBart Van Assche             if (-1 == n) {
323*44704f69SBart Van Assche                 if (get_scsi_pt_transport_err(ptvp))
324*44704f69SBart Van Assche                     ret = SG_LIB_TRANSPORT_ERROR;
325*44704f69SBart Van Assche                 else
326*44704f69SBart Van Assche                     ret = sg_convert_errno(get_scsi_pt_os_err(ptvp));
327*44704f69SBart Van Assche                 goto finish;
328*44704f69SBart Van Assche             } else if (-2 == n) {
329*44704f69SBart Van Assche                 switch (sense_cat) {
330*44704f69SBart Van Assche                 case SG_LIB_CAT_RECOVERED:
331*44704f69SBart Van Assche                 case SG_LIB_CAT_NO_SENSE:
332*44704f69SBart Van Assche                     break;
333*44704f69SBart Van Assche                 case SG_LIB_CAT_NOT_READY:
334*44704f69SBart Van Assche                     ++num_errs;
335*44704f69SBart Van Assche                     if (1 ==  num_rs) {
336*44704f69SBart Van Assche                         ret = sense_cat;
337*44704f69SBart Van Assche                         printf("device not ready\n");
338*44704f69SBart Van Assche                     }
339*44704f69SBart Van Assche                     break;
340*44704f69SBart Van Assche                 case SG_LIB_CAT_UNIT_ATTENTION:
341*44704f69SBart Van Assche                     ++num_errs;
342*44704f69SBart Van Assche                     if (verbose) {
343*44704f69SBart Van Assche                         pr2serr("Ignoring Unit attention (sense key)\n");
344*44704f69SBart Van Assche                     }
345*44704f69SBart Van Assche                     break;
346*44704f69SBart Van Assche                 default:
347*44704f69SBart Van Assche                     ++num_errs;
348*44704f69SBart Van Assche                     if (1 == num_rs) {
349*44704f69SBart Van Assche                         ret = sense_cat;
350*44704f69SBart Van Assche                         sg_get_category_sense_str(sense_cat, sizeof(b), b,
351*44704f69SBart Van Assche                                                   verbose);
352*44704f69SBart Van Assche                         printf("%s\n", b);
353*44704f69SBart Van Assche                         break; // return k;
354*44704f69SBart Van Assche                     }
355*44704f69SBart Van Assche                     break;
356*44704f69SBart Van Assche                 }
357*44704f69SBart Van Assche             }
358*44704f69SBart Van Assche             if (n >= 0)
359*44704f69SBart Van Assche                 act_din_len = n;
360*44704f69SBart Van Assche             if (ret)
361*44704f69SBart Van Assche                 goto finish;
362*44704f69SBart Van Assche 
363*44704f69SBart Van Assche             if (verbose > 1) {
364*44704f69SBart Van Assche                 pr2serr("Parameter data in hex\n");
365*44704f69SBart Van Assche                 hex2stderr(rsBuff, act_din_len, 1);
366*44704f69SBart Van Assche             }
367*44704f69SBart Van Assche             progress = -1;
368*44704f69SBart Van Assche             sg_get_sense_progress_fld(rsBuff, act_din_len, &progress);
369*44704f69SBart Van Assche             if (progress < 0) {
370*44704f69SBart Van Assche                 ret = res;
371*44704f69SBart Van Assche                 if (verbose > 1)
372*44704f69SBart Van Assche                      pr2serr("No progress indication found, iteration %d\n",
373*44704f69SBart Van Assche                              k + 1);
374*44704f69SBart Van Assche                 /* N.B. exits first time there isn't a progress indication */
375*44704f69SBart Van Assche                 break;
376*44704f69SBart Van Assche             } else
377*44704f69SBart Van Assche                 printf("Progress indication: %d.%02d%% done\n",
378*44704f69SBart Van Assche                        (progress * 100) / 65536,
379*44704f69SBart Van Assche                        ((progress * 100) % 65536) / 656);
380*44704f69SBart Van Assche             partial_clear_scsi_pt_obj(ptvp);
381*44704f69SBart Van Assche         }                               /* >>>>> end of for(num_rs) loop */
382*44704f69SBart Van Assche         goto finish;
383*44704f69SBart Van Assche     }
384*44704f69SBart Van Assche 
385*44704f69SBart Van Assche #ifndef SG_LIB_MINGW
386*44704f69SBart Van Assche     if (not_raw_hex && do_time) {
387*44704f69SBart Van Assche         start_tm.tv_sec = 0;
388*44704f69SBart Van Assche         start_tm.tv_usec = 0;
389*44704f69SBart Van Assche         gettimeofday(&start_tm, NULL);
390*44704f69SBart Van Assche     }
391*44704f69SBart Van Assche #endif
392*44704f69SBart Van Assche 
393*44704f69SBart Van Assche     rsBuff[0] = '\0';
394*44704f69SBart Van Assche     rsBuff[7] = '\0';
395*44704f69SBart Van Assche     for (k = 0; k < num_rs; ++k) {
396*44704f69SBart Van Assche         act_din_len = 0;
397*44704f69SBart Van Assche         ret = 0;
398*44704f69SBart Van Assche         set_scsi_pt_cdb(ptvp, rs_cdb, sizeof(rs_cdb));
399*44704f69SBart Van Assche         set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
400*44704f69SBart Van Assche         memset(rsBuff, 0x0, sizeof(rsBuff));
401*44704f69SBart Van Assche         set_scsi_pt_data_in(ptvp, rsBuff, sizeof(rsBuff));
402*44704f69SBart Van Assche         set_scsi_pt_packet_id(ptvp, k + 1);
403*44704f69SBart Van Assche         if (do_error > 1) {
404*44704f69SBart Van Assche             ++num_errs;
405*44704f69SBart Van Assche             n = 0;
406*44704f69SBart Van Assche         } else {
407*44704f69SBart Van Assche             if (verbose && (0 == k)) {
408*44704f69SBart Van Assche                 char bb[128];
409*44704f69SBart Van Assche 
410*44704f69SBart Van Assche                 pr2serr("    cdb: %s\n",
411*44704f69SBart Van Assche                         sg_get_command_str(rs_cdb, REQUEST_SENSE_CMDLEN,
412*44704f69SBart Van Assche                                            true, sizeof(bb), bb));
413*44704f69SBart Van Assche             }
414*44704f69SBart Van Assche             rs = do_scsi_pt(ptvp, -1, DEF_PT_TIMEOUT, verbose);
415*44704f69SBart Van Assche             n = sg_cmds_process_resp(ptvp, "Request sense", rs, (0 == k),
416*44704f69SBart Van Assche                                      verbose, &sense_cat);
417*44704f69SBart Van Assche         }
418*44704f69SBart Van Assche         if (-1 == n) {
419*44704f69SBart Van Assche             if (get_scsi_pt_transport_err(ptvp))
420*44704f69SBart Van Assche                 ret = SG_LIB_TRANSPORT_ERROR;
421*44704f69SBart Van Assche             else
422*44704f69SBart Van Assche                 ret = sg_convert_errno(get_scsi_pt_os_err(ptvp));
423*44704f69SBart Van Assche             goto finish;
424*44704f69SBart Van Assche         } else if (-2 == n) {
425*44704f69SBart Van Assche             switch (sense_cat) {
426*44704f69SBart Van Assche             case SG_LIB_CAT_RECOVERED:
427*44704f69SBart Van Assche             case SG_LIB_CAT_NO_SENSE:
428*44704f69SBart Van Assche                 break;
429*44704f69SBart Van Assche             case SG_LIB_CAT_NOT_READY:
430*44704f69SBart Van Assche                 ++num_errs;
431*44704f69SBart Van Assche                 if (1 ==  num_rs) {
432*44704f69SBart Van Assche                     ret = sense_cat;
433*44704f69SBart Van Assche                     printf("device not ready\n");
434*44704f69SBart Van Assche                 }
435*44704f69SBart Van Assche                 break;
436*44704f69SBart Van Assche             case SG_LIB_CAT_UNIT_ATTENTION:
437*44704f69SBart Van Assche                 ++num_errs;
438*44704f69SBart Van Assche                 if (verbose) {
439*44704f69SBart Van Assche                     pr2serr("Ignoring Unit attention (sense key)\n");
440*44704f69SBart Van Assche                 }
441*44704f69SBart Van Assche                 break;
442*44704f69SBart Van Assche             default:
443*44704f69SBart Van Assche                 ++num_errs;
444*44704f69SBart Van Assche                 if (1 == num_rs) {
445*44704f69SBart Van Assche                     ret = sense_cat;
446*44704f69SBart Van Assche                     sg_get_category_sense_str(sense_cat, sizeof(b), b,
447*44704f69SBart Van Assche                                               verbose);
448*44704f69SBart Van Assche                     printf("%s\n", b);
449*44704f69SBart Van Assche                     break; // return k;
450*44704f69SBart Van Assche                 }
451*44704f69SBart Van Assche                 break;
452*44704f69SBart Van Assche             }
453*44704f69SBart Van Assche         }
454*44704f69SBart Van Assche         if (n >= 0)
455*44704f69SBart Van Assche             act_din_len = n;
456*44704f69SBart Van Assche 
457*44704f69SBart Van Assche         if (act_din_len > 7) {
458*44704f69SBart Van Assche             struct sg_scsi_sense_hdr ssh;
459*44704f69SBart Van Assche 
460*44704f69SBart Van Assche             if (sg_scsi_normalize_sense(rsBuff, act_din_len, &ssh)) {
461*44704f69SBart Van Assche                 if (ssh.sense_key > 0) {
462*44704f69SBart Van Assche                     ++num_din_errs;
463*44704f69SBart Van Assche                     most_recent_skey = ssh.sense_key;
464*44704f69SBart Van Assche                 }
465*44704f69SBart Van Assche                 if (not_raw_hex && ((1 == num_rs) || verbose)) {
466*44704f69SBart Van Assche                     char bb[144];
467*44704f69SBart Van Assche 
468*44704f69SBart Van Assche                     sg_get_sense_str(NULL, rsBuff, act_din_len,
469*44704f69SBart Van Assche                                      false, sizeof(bb), bb);
470*44704f69SBart Van Assche                     pr2serr("data-in decoded as sense:\n%s\n", bb);
471*44704f69SBart Van Assche                 }
472*44704f69SBart Van Assche             }
473*44704f69SBart Van Assche         }
474*44704f69SBart Van Assche         partial_clear_scsi_pt_obj(ptvp);
475*44704f69SBart Van Assche         if (ret)
476*44704f69SBart Van Assche             goto finish;
477*44704f69SBart Van Assche 
478*44704f69SBart Van Assche         if (act_din_len > 0) {
479*44704f69SBart Van Assche             if (do_raw)
480*44704f69SBart Van Assche                 dStrRaw(rsBuff, act_din_len);
481*44704f69SBart Van Assche             else if (do_hex)
482*44704f69SBart Van Assche                 hex2stdout(rsBuff, act_din_len, 1);
483*44704f69SBart Van Assche         }
484*44704f69SBart Van Assche     }                                   /* <<<<< end of for(num_rs) loop */
485*44704f69SBart Van Assche     if ((0 == ret) && do_status) {
486*44704f69SBart Van Assche         ret = sg_err_category_sense(rsBuff, act_din_len);
487*44704f69SBart Van Assche         if (SG_LIB_CAT_NO_SENSE == ret) {
488*44704f69SBart Van Assche             struct sg_scsi_sense_hdr ssh;
489*44704f69SBart Van Assche 
490*44704f69SBart Van Assche             if (sg_scsi_normalize_sense(rsBuff, act_din_len, &ssh)) {
491*44704f69SBart Van Assche                 if ((0 == ssh.asc) && (0 == ssh.ascq))
492*44704f69SBart Van Assche                     ret = 0;
493*44704f69SBart Van Assche             }
494*44704f69SBart Van Assche         }
495*44704f69SBart Van Assche     }
496*44704f69SBart Van Assche #ifndef SG_LIB_MINGW
497*44704f69SBart Van Assche     if (not_raw_hex && do_time && (start_tm.tv_sec || start_tm.tv_usec)) {
498*44704f69SBart Van Assche         struct timeval res_tm;
499*44704f69SBart Van Assche         double den, num;
500*44704f69SBart Van Assche 
501*44704f69SBart Van Assche         gettimeofday(&end_tm, NULL);
502*44704f69SBart Van Assche         res_tm.tv_sec = end_tm.tv_sec - start_tm.tv_sec;
503*44704f69SBart Van Assche         res_tm.tv_usec = end_tm.tv_usec - start_tm.tv_usec;
504*44704f69SBart Van Assche         if (res_tm.tv_usec < 0) {
505*44704f69SBart Van Assche             --res_tm.tv_sec;
506*44704f69SBart Van Assche             res_tm.tv_usec += 1000000;
507*44704f69SBart Van Assche         }
508*44704f69SBart Van Assche         den = res_tm.tv_sec;
509*44704f69SBart Van Assche         den += (0.000001 * res_tm.tv_usec);
510*44704f69SBart Van Assche         num = (double)num_rs;
511*44704f69SBart Van Assche         printf("time to perform commands was %d.%06d secs",
512*44704f69SBart Van Assche                (int)res_tm.tv_sec, (int)res_tm.tv_usec);
513*44704f69SBart Van Assche         if (den > 0.00001)
514*44704f69SBart Van Assche             printf("; %.2f operations/sec\n", num / den);
515*44704f69SBart Van Assche         else
516*44704f69SBart Van Assche             printf("\n");
517*44704f69SBart Van Assche     }
518*44704f69SBart Van Assche #endif
519*44704f69SBart Van Assche 
520*44704f69SBart Van Assche finish:
521*44704f69SBart Van Assche     if (not_raw_hex) {
522*44704f69SBart Van Assche         if (num_errs > 0)
523*44704f69SBart Van Assche             printf("Number of command errors detected: %d\n", num_errs);
524*44704f69SBart Van Assche         if (num_din_errs > 0)
525*44704f69SBart Van Assche             printf("Number of data-in errors detected: %d, most recent "
526*44704f69SBart Van Assche                    "sense_key=%d\n", num_din_errs, most_recent_skey);
527*44704f69SBart Van Assche     }
528*44704f69SBart Van Assche     if (sg_fd >= 0) {
529*44704f69SBart Van Assche         res = sg_cmds_close_device(sg_fd);
530*44704f69SBart Van Assche         if (res < 0) {
531*44704f69SBart Van Assche             if (not_raw_hex)
532*44704f69SBart Van Assche                 pr2serr("close error: %s\n", safe_strerror(-res));
533*44704f69SBart Van Assche             if (0 == ret)
534*44704f69SBart Van Assche                 ret = sg_convert_errno(-res);
535*44704f69SBart Van Assche         }
536*44704f69SBart Van Assche     }
537*44704f69SBart Van Assche     if (not_raw_hex && (0 == verbose)) {
538*44704f69SBart Van Assche         if (! sg_if_can2stderr("sg_requests failed: ", ret))
539*44704f69SBart Van Assche             pr2serr("Some error occurred, try again with '-v' "
540*44704f69SBart Van Assche                     "or '-vv' for more information\n");
541*44704f69SBart Van Assche     }
542*44704f69SBart Van Assche     return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
543*44704f69SBart Van Assche }
544