xref: /aosp_15_r20/external/sg3_utils/src/sg_senddiag.c (revision 44704f698541f6367e81f991ef8bb54ccbf3fc18)
1*44704f69SBart Van Assche /*
2*44704f69SBart Van Assche  * A utility program originally written for the Linux OS SCSI subsystem
3*44704f69SBart Van Assche  *    Copyright (C) 2003-2022 D. Gilbert
4*44704f69SBart Van Assche  * This program is free software; you can redistribute it and/or modify
5*44704f69SBart Van Assche  * it under the terms of the GNU General Public License as published by
6*44704f69SBart Van Assche  * the Free Software Foundation; either version 2, or (at your option)
7*44704f69SBart Van Assche  * any later version.
8*44704f69SBart Van Assche  *
9*44704f69SBart Van Assche  * SPDX-License-Identifier: GPL-2.0-or-later
10*44704f69SBart Van Assche 
11*44704f69SBart Van Assche    This program issues the SCSI SEND DIAGNOSTIC command and in one case
12*44704f69SBart Van Assche    the SCSI RECEIVE DIAGNOSTIC command to list supported diagnostic pages.
13*44704f69SBart Van Assche */
14*44704f69SBart Van Assche 
15*44704f69SBart Van Assche #include <unistd.h>
16*44704f69SBart Van Assche #include <fcntl.h>
17*44704f69SBart Van Assche #include <stdio.h>
18*44704f69SBart Van Assche #include <stdlib.h>
19*44704f69SBart Van Assche #include <string.h>
20*44704f69SBart Van Assche #include <ctype.h>
21*44704f69SBart Van Assche #include <getopt.h>
22*44704f69SBart Van Assche 
23*44704f69SBart Van Assche #ifdef HAVE_CONFIG_H
24*44704f69SBart Van Assche #include "config.h"
25*44704f69SBart Van Assche #endif
26*44704f69SBart Van Assche 
27*44704f69SBart Van Assche #include "sg_lib.h"
28*44704f69SBart Van Assche #include "sg_cmds_basic.h"
29*44704f69SBart Van Assche #include "sg_cmds_extra.h"
30*44704f69SBart Van Assche #if SG_LIB_WIN32
31*44704f69SBart Van Assche #include "sg_pt.h"      /* needed for scsi_pt_win32_direct() */
32*44704f69SBart Van Assche #endif
33*44704f69SBart Van Assche #include "sg_unaligned.h"
34*44704f69SBart Van Assche #include "sg_pr2serr.h"
35*44704f69SBart Van Assche 
36*44704f69SBart Van Assche 
37*44704f69SBart Van Assche static const char * version_str = "0.65 20220128";
38*44704f69SBart Van Assche 
39*44704f69SBart Van Assche #define ME "sg_senddiag: "
40*44704f69SBart Van Assche 
41*44704f69SBart Van Assche #define DEF_ALLOC_LEN (1024 * 4)
42*44704f69SBart Van Assche 
43*44704f69SBart Van Assche static struct option long_options[] = {
44*44704f69SBart Van Assche         {"doff", no_argument, 0, 'd'},
45*44704f69SBart Van Assche         {"extdur", no_argument, 0, 'e'},
46*44704f69SBart Van Assche         {"help", no_argument, 0, 'h'},
47*44704f69SBart Van Assche         {"hex", no_argument, 0, 'H'},
48*44704f69SBart Van Assche         {"list", no_argument, 0, 'l'},
49*44704f69SBart Van Assche         {"maxlen", required_argument, 0, 'm'},
50*44704f69SBart Van Assche         {"new", no_argument, 0, 'N'},
51*44704f69SBart Van Assche         {"old", no_argument, 0, 'O'},
52*44704f69SBart Van Assche         {"page", required_argument, 0, 'P'},
53*44704f69SBart Van Assche         {"pf", no_argument, 0, 'p'},
54*44704f69SBart Van Assche         {"raw", required_argument, 0, 'r'},
55*44704f69SBart Van Assche         {"selftest", required_argument, 0, 's'},
56*44704f69SBart Van Assche         {"test", no_argument, 0, 't'},
57*44704f69SBart Van Assche         {"timeout", required_argument, 0, 'T'},
58*44704f69SBart Van Assche         {"uoff", no_argument, 0, 'u'},
59*44704f69SBart Van Assche         {"verbose", no_argument, 0, 'v'},
60*44704f69SBart Van Assche         {"version", no_argument, 0, 'V'},
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_deftest;
66*44704f69SBart Van Assche     bool do_doff;
67*44704f69SBart Van Assche     bool do_extdur;
68*44704f69SBart Van Assche     bool do_list;
69*44704f69SBart Van Assche     bool do_pf;
70*44704f69SBart Van Assche     bool do_raw;
71*44704f69SBart Van Assche     bool do_uoff;
72*44704f69SBart Van Assche     bool opt_new;
73*44704f69SBart Van Assche     bool verbose_given;
74*44704f69SBart Van Assche     bool version_given;
75*44704f69SBart Van Assche     int do_help;
76*44704f69SBart Van Assche     int do_hex;
77*44704f69SBart Van Assche     int maxlen;
78*44704f69SBart Van Assche     int page_code;
79*44704f69SBart Van Assche     int do_selftest;
80*44704f69SBart Van Assche     int timeout;
81*44704f69SBart Van Assche     int verbose;
82*44704f69SBart Van Assche     const char * device_name;
83*44704f69SBart Van Assche     const char * raw_arg;
84*44704f69SBart Van Assche };
85*44704f69SBart Van Assche 
86*44704f69SBart Van Assche 
87*44704f69SBart Van Assche static void
usage()88*44704f69SBart Van Assche usage()
89*44704f69SBart Van Assche {
90*44704f69SBart Van Assche     printf("Usage: sg_senddiag [--doff] [--extdur] [--help] [--hex] "
91*44704f69SBart Van Assche            "[--list]\n"
92*44704f69SBart Van Assche            "                   [--maxlen=LEN] [--page=PG] [--pf] "
93*44704f69SBart Van Assche            "[--raw=H,H...]\n"
94*44704f69SBart Van Assche            "                   [--selftest=ST] [--test] [--timeout=SECS] "
95*44704f69SBart Van Assche            "[--uoff]\n"
96*44704f69SBart Van Assche            "                   [--verbose] [--version] [DEVICE]\n"
97*44704f69SBart Van Assche            "  where:\n"
98*44704f69SBart Van Assche            "    --doff|-d       device online (def: 0, only with '--test')\n"
99*44704f69SBart Van Assche            "    --extdur|-e     duration of an extended self-test (from mode "
100*44704f69SBart Van Assche            "page 0xa)\n"
101*44704f69SBart Van Assche            "    --help|-h       print usage message then exit\n"
102*44704f69SBart Van Assche            "    --hex|-H        output RDR in hex; twice: plus ASCII; thrice: "
103*44704f69SBart Van Assche            "suitable\n"
104*44704f69SBart Van Assche            "                    for '--raw=-' with later invocation\n"
105*44704f69SBart Van Assche            "    --list|-l       list supported page codes (with or without "
106*44704f69SBart Van Assche            "DEVICE)\n"
107*44704f69SBart Van Assche            "    --maxlen=LEN|-m LEN    parameter list length or maximum "
108*44704f69SBart Van Assche            "allocation\n"
109*44704f69SBart Van Assche            "                           length (default: 4096 bytes)\n"
110*44704f69SBart Van Assche            "    --page=PG|-P PG    do RECEIVE DIAGNOSTIC RESULTS only, set "
111*44704f69SBart Van Assche            "PCV\n"
112*44704f69SBart Van Assche            "    --pf|-p         set PF bit (def: 0)\n"
113*44704f69SBart Van Assche            "    --raw=H,H...|-r H,H...    sequence of hex bytes to form "
114*44704f69SBart Van Assche            "diag page to send\n"
115*44704f69SBart Van Assche            "    --raw=-|-r -    read stdin for sequence of bytes to send\n"
116*44704f69SBart Van Assche            "    --selftest=ST|-s ST    self-test code, default: 0 "
117*44704f69SBart Van Assche            "(inactive)\n"
118*44704f69SBart Van Assche            "                           1->background short, 2->background "
119*44704f69SBart Van Assche            "extended\n"
120*44704f69SBart Van Assche            "                           4->abort test\n"
121*44704f69SBart Van Assche            "                           5->foreground short, 6->foreground "
122*44704f69SBart Van Assche            "extended\n"
123*44704f69SBart Van Assche            "    --test|-t       default self-test\n"
124*44704f69SBart Van Assche            "    --timeout=SECS|-T SECS    timeout for foreground self tests\n"
125*44704f69SBart Van Assche            "                            unit: second (def: 7200 seconds)\n"
126*44704f69SBart Van Assche            "    --uoff|-u       unit offline (def: 0, only with '--test')\n"
127*44704f69SBart Van Assche            "    --verbose|-v    increase verbosity\n"
128*44704f69SBart Van Assche            "    --old|-O        use old interface (use as first option)\n"
129*44704f69SBart Van Assche            "    --version|-V    output version string then exit\n\n"
130*44704f69SBart Van Assche            "Performs a SCSI SEND DIAGNOSTIC (and/or a RECEIVE DIAGNOSTIC "
131*44704f69SBart Van Assche            "RESULTS) command\n"
132*44704f69SBart Van Assche         );
133*44704f69SBart Van Assche }
134*44704f69SBart Van Assche 
135*44704f69SBart Van Assche static void
usage_old()136*44704f69SBart Van Assche usage_old()
137*44704f69SBart Van Assche {
138*44704f69SBart Van Assche     printf("Usage: sg_senddiag [-doff] [-e] [-h] [-H] [-l] [-pf]"
139*44704f69SBart Van Assche            " [-raw=H,H...]\n"
140*44704f69SBart Van Assche            "                   [-s=SF] [-t] [-T=SECS] [-uoff] [-v] [-V] "
141*44704f69SBart Van Assche            "[DEVICE]\n"
142*44704f69SBart Van Assche            "  where:\n"
143*44704f69SBart Van Assche            "    -doff   device online (def: 0, only with '-t')\n"
144*44704f69SBart Van Assche            "    -e      duration of an extended self-test (from mode page "
145*44704f69SBart Van Assche            "0xa)\n"
146*44704f69SBart Van Assche            "    -h      output in hex\n"
147*44704f69SBart Van Assche            "    -H      output in hex (same as '-h')\n"
148*44704f69SBart Van Assche            "    -l      list supported page codes\n"
149*44704f69SBart Van Assche            "    -pf     set PF bit (def: 0)\n"
150*44704f69SBart Van Assche            "    -raw=H,H...    sequence of bytes to form diag page to "
151*44704f69SBart Van Assche            "send\n"
152*44704f69SBart Van Assche            "    -raw=-  read stdin for sequence of bytes to send\n"
153*44704f69SBart Van Assche            "    -s=SF   self-test code (def: 0)\n"
154*44704f69SBart Van Assche            "            1->background short, 2->background extended,"
155*44704f69SBart Van Assche            " 4->abort test\n"
156*44704f69SBart Van Assche            "            5->foreground short, 6->foreground extended\n"
157*44704f69SBart Van Assche            "    -t      default self-test\n"
158*44704f69SBart Van Assche            "    -T SECS    timeout for foreground self tests\n"
159*44704f69SBart Van Assche            "    -uoff   unit offline (def: 0, only with '-t')\n"
160*44704f69SBart Van Assche            "    -v      increase verbosity (print issued SCSI cmds)\n"
161*44704f69SBart Van Assche            "    -V      output version string\n"
162*44704f69SBart Van Assche            "    -N|--new   use new interface\n"
163*44704f69SBart Van Assche            "    -?      output this usage message\n\n"
164*44704f69SBart Van Assche            "Performs a SCSI SEND DIAGNOSTIC (and/or a RECEIVE DIAGNOSTIC "
165*44704f69SBart Van Assche            "RESULTS) command\n"
166*44704f69SBart Van Assche         );
167*44704f69SBart Van Assche }
168*44704f69SBart Van Assche 
169*44704f69SBart Van Assche static int
new_parse_cmd_line(struct opts_t * op,int argc,char * argv[])170*44704f69SBart Van Assche new_parse_cmd_line(struct opts_t * op, int argc, char * argv[])
171*44704f69SBart Van Assche {
172*44704f69SBart Van Assche     int c, n;
173*44704f69SBart Van Assche 
174*44704f69SBart Van Assche     while (1) {
175*44704f69SBart Van Assche         int option_index = 0;
176*44704f69SBart Van Assche 
177*44704f69SBart Van Assche         c = getopt_long(argc, argv, "dehHlm:NOpP:r:s:tT:uvV", long_options,
178*44704f69SBart Van Assche                         &option_index);
179*44704f69SBart Van Assche         if (c == -1)
180*44704f69SBart Van Assche             break;
181*44704f69SBart Van Assche 
182*44704f69SBart Van Assche         switch (c) {
183*44704f69SBart Van Assche         case 'd':
184*44704f69SBart Van Assche             op->do_doff = true;
185*44704f69SBart Van Assche             break;
186*44704f69SBart Van Assche         case 'e':
187*44704f69SBart Van Assche             op->do_extdur = true;
188*44704f69SBart Van Assche             break;
189*44704f69SBart Van Assche         case 'h':
190*44704f69SBart Van Assche         case '?':
191*44704f69SBart Van Assche             ++op->do_help;
192*44704f69SBart Van Assche             break;
193*44704f69SBart Van Assche         case 'H':
194*44704f69SBart Van Assche             ++op->do_hex;
195*44704f69SBart Van Assche             break;
196*44704f69SBart Van Assche         case 'l':
197*44704f69SBart Van Assche             op->do_list = true;
198*44704f69SBart Van Assche             break;
199*44704f69SBart Van Assche         case 'm':
200*44704f69SBart Van Assche             n = sg_get_num(optarg);
201*44704f69SBart Van Assche             if ((n < 0) || (n > 0xffff)) {
202*44704f69SBart Van Assche                 pr2serr("bad argument to '--maxlen=' or greater than 65535 "
203*44704f69SBart Van Assche                         "[0xffff]\n");
204*44704f69SBart Van Assche                 return SG_LIB_SYNTAX_ERROR;
205*44704f69SBart Van Assche             }
206*44704f69SBart Van Assche             op->maxlen = n;
207*44704f69SBart Van Assche             break;
208*44704f69SBart Van Assche         case 'N':
209*44704f69SBart Van Assche             break;      /* ignore */
210*44704f69SBart Van Assche         case 'O':
211*44704f69SBart Van Assche             op->opt_new = false;
212*44704f69SBart Van Assche             return 0;
213*44704f69SBart Van Assche         case 'p':
214*44704f69SBart Van Assche             op->do_pf = true;
215*44704f69SBart Van Assche             break;
216*44704f69SBart Van Assche         case 'P':
217*44704f69SBart Van Assche             n = sg_get_num(optarg);
218*44704f69SBart Van Assche             if ((n < 0) || (n > 0xff)) {
219*44704f69SBart Van Assche                 pr2serr("bad argument to '--page=' or greater than 255 "
220*44704f69SBart Van Assche                         "[0xff]\n");
221*44704f69SBart Van Assche                 return SG_LIB_SYNTAX_ERROR;
222*44704f69SBart Van Assche             }
223*44704f69SBart Van Assche             op->page_code = n;
224*44704f69SBart Van Assche             break;
225*44704f69SBart Van Assche         case 'r':
226*44704f69SBart Van Assche             op->raw_arg = optarg;
227*44704f69SBart Van Assche             op->do_raw = true;
228*44704f69SBart Van Assche             break;
229*44704f69SBart Van Assche         case 's':
230*44704f69SBart Van Assche             n = sg_get_num(optarg);
231*44704f69SBart Van Assche             if ((n < 0) || (n > 7)) {
232*44704f69SBart Van Assche                 pr2serr("bad argument to '--selftest='\n");
233*44704f69SBart Van Assche                 usage();
234*44704f69SBart Van Assche                 return SG_LIB_SYNTAX_ERROR;
235*44704f69SBart Van Assche             }
236*44704f69SBart Van Assche             op->do_selftest = n;
237*44704f69SBart Van Assche             break;
238*44704f69SBart Van Assche         case 't':
239*44704f69SBart Van Assche             op->do_deftest = true;
240*44704f69SBart Van Assche             break;
241*44704f69SBart Van Assche         case 'T':
242*44704f69SBart Van Assche             n = sg_get_num(optarg);
243*44704f69SBart Van Assche             if (n < 0) {
244*44704f69SBart Van Assche                 pr2serr("bad argument to '--timeout=SECS'\n");
245*44704f69SBart Van Assche                 return SG_LIB_SYNTAX_ERROR;
246*44704f69SBart Van Assche             }
247*44704f69SBart Van Assche             op->timeout = n;
248*44704f69SBart Van Assche             break;
249*44704f69SBart Van Assche         case 'u':
250*44704f69SBart Van Assche             op->do_uoff = true;
251*44704f69SBart Van Assche             break;
252*44704f69SBart Van Assche         case 'v':
253*44704f69SBart Van Assche             op->verbose_given = true;
254*44704f69SBart Van Assche             ++op->verbose;
255*44704f69SBart Van Assche             break;
256*44704f69SBart Van Assche         case 'V':
257*44704f69SBart Van Assche             op->version_given = true;
258*44704f69SBart Van Assche             break;
259*44704f69SBart Van Assche         default:
260*44704f69SBart Van Assche             pr2serr("unrecognised option code %c [0x%x]\n", c, c);
261*44704f69SBart Van Assche             if (op->do_help)
262*44704f69SBart Van Assche                 break;
263*44704f69SBart Van Assche             usage();
264*44704f69SBart Van Assche             return SG_LIB_SYNTAX_ERROR;
265*44704f69SBart Van Assche         }
266*44704f69SBart Van Assche     }
267*44704f69SBart Van Assche     if (optind < argc) {
268*44704f69SBart Van Assche         if (NULL == op->device_name) {
269*44704f69SBart Van Assche             op->device_name = argv[optind];
270*44704f69SBart Van Assche             ++optind;
271*44704f69SBart Van Assche         }
272*44704f69SBart Van Assche         if (optind < argc) {
273*44704f69SBart Van Assche             for (; optind < argc; ++optind)
274*44704f69SBart Van Assche                 pr2serr("Unexpected extra argument: %s\n", argv[optind]);
275*44704f69SBart Van Assche             usage();
276*44704f69SBart Van Assche             return SG_LIB_SYNTAX_ERROR;
277*44704f69SBart Van Assche         }
278*44704f69SBart Van Assche     }
279*44704f69SBart Van Assche     return 0;
280*44704f69SBart Van Assche }
281*44704f69SBart Van Assche 
282*44704f69SBart Van Assche static int
old_parse_cmd_line(struct opts_t * op,int argc,char * argv[])283*44704f69SBart Van Assche old_parse_cmd_line(struct opts_t * op, int argc, char * argv[])
284*44704f69SBart Van Assche {
285*44704f69SBart Van Assche     bool jmp_out;
286*44704f69SBart Van Assche     int k, plen, num, n;
287*44704f69SBart Van Assche     unsigned int u;
288*44704f69SBart Van Assche     const char * cp;
289*44704f69SBart Van Assche 
290*44704f69SBart Van Assche     for (k = 1; k < argc; ++k) {
291*44704f69SBart Van Assche         cp = argv[k];
292*44704f69SBart Van Assche         plen = strlen(cp);
293*44704f69SBart Van Assche         if (plen <= 0)
294*44704f69SBart Van Assche             continue;
295*44704f69SBart Van Assche         if ('-' == *cp) {
296*44704f69SBart Van Assche             for (--plen, ++cp, jmp_out = false; plen > 0; --plen, ++cp) {
297*44704f69SBart Van Assche                 switch (*cp) {
298*44704f69SBart Van Assche                 case 'd':
299*44704f69SBart Van Assche                     if (0 == strncmp("doff", cp, 4)) {
300*44704f69SBart Van Assche                         op->do_doff = true;
301*44704f69SBart Van Assche                         cp += 3;
302*44704f69SBart Van Assche                         plen -= 3;
303*44704f69SBart Van Assche                     } else
304*44704f69SBart Van Assche                         jmp_out = true;
305*44704f69SBart Van Assche                     break;
306*44704f69SBart Van Assche                 case 'e':
307*44704f69SBart Van Assche                     op->do_extdur = true;
308*44704f69SBart Van Assche                     break;
309*44704f69SBart Van Assche                 case 'h':
310*44704f69SBart Van Assche                 case 'H':
311*44704f69SBart Van Assche                     ++op->do_hex;
312*44704f69SBart Van Assche                     break;
313*44704f69SBart Van Assche                 case 'l':
314*44704f69SBart Van Assche                     op->do_list = true;
315*44704f69SBart Van Assche                     break;
316*44704f69SBart Van Assche                 case 'N':
317*44704f69SBart Van Assche                     op->opt_new = true;
318*44704f69SBart Van Assche                     return 0;
319*44704f69SBart Van Assche                 case 'O':
320*44704f69SBart Van Assche                     break;
321*44704f69SBart Van Assche                 case 'p':
322*44704f69SBart Van Assche                     if (0 == strncmp("pf", cp, 2)) {
323*44704f69SBart Van Assche                         op->do_pf = true;
324*44704f69SBart Van Assche                         ++cp;
325*44704f69SBart Van Assche                         --plen;
326*44704f69SBart Van Assche                     } else
327*44704f69SBart Van Assche                         jmp_out = true;
328*44704f69SBart Van Assche                     break;
329*44704f69SBart Van Assche                 case 't':
330*44704f69SBart Van Assche                     op->do_deftest = true;
331*44704f69SBart Van Assche                     break;
332*44704f69SBart Van Assche                 case 'u':
333*44704f69SBart Van Assche                     if (0 == strncmp("uoff", cp, 4)) {
334*44704f69SBart Van Assche                         op->do_uoff = true;
335*44704f69SBart Van Assche                         cp += 3;
336*44704f69SBart Van Assche                         plen -= 3;
337*44704f69SBart Van Assche                     } else
338*44704f69SBart Van Assche                         jmp_out = true;
339*44704f69SBart Van Assche                     break;
340*44704f69SBart Van Assche                 case 'v':
341*44704f69SBart Van Assche                     op->verbose_given = true;
342*44704f69SBart Van Assche                     ++op->verbose;
343*44704f69SBart Van Assche                     break;
344*44704f69SBart Van Assche                 case 'V':
345*44704f69SBart Van Assche                     op->version_given = true;
346*44704f69SBart Van Assche                     break;
347*44704f69SBart Van Assche                 case '?':
348*44704f69SBart Van Assche                     ++op->do_help;
349*44704f69SBart Van Assche                     break;
350*44704f69SBart Van Assche                 default:
351*44704f69SBart Van Assche                     jmp_out = true;
352*44704f69SBart Van Assche                     break;
353*44704f69SBart Van Assche                 }
354*44704f69SBart Van Assche                 if (jmp_out)
355*44704f69SBart Van Assche                     break;
356*44704f69SBart Van Assche             }
357*44704f69SBart Van Assche             if (plen <= 0)
358*44704f69SBart Van Assche                 continue;
359*44704f69SBart Van Assche             if (0 == strncmp("raw=", cp, 4)) {
360*44704f69SBart Van Assche                 op->raw_arg = cp + 4;
361*44704f69SBart Van Assche                 op->do_raw = true;
362*44704f69SBart Van Assche             } else if (0 == strncmp("s=", cp, 2)) {
363*44704f69SBart Van Assche                 num = sscanf(cp + 2, "%x", &u);
364*44704f69SBart Van Assche                 if ((1 != num) || (u > 7)) {
365*44704f69SBart Van Assche                     printf("Bad page code after '-s=' option\n");
366*44704f69SBart Van Assche                     usage_old();
367*44704f69SBart Van Assche                     return SG_LIB_SYNTAX_ERROR;
368*44704f69SBart Van Assche                 }
369*44704f69SBart Van Assche                 op->do_selftest = u;
370*44704f69SBart Van Assche             } else if (0 == strncmp("T=", cp, 2)) {
371*44704f69SBart Van Assche                 num = sscanf(cp + 2, "%d", &n);
372*44704f69SBart Van Assche                 if ((1 != num) || (n < 0)) {
373*44704f69SBart Van Assche                     printf("Bad page code after '-T=SECS' option\n");
374*44704f69SBart Van Assche                     usage_old();
375*44704f69SBart Van Assche                     return SG_LIB_SYNTAX_ERROR;
376*44704f69SBart Van Assche                 }
377*44704f69SBart Van Assche                 op->timeout = n;
378*44704f69SBart Van Assche             } else if (0 == strncmp("-old", cp, 5))
379*44704f69SBart Van Assche                 ;
380*44704f69SBart Van Assche             else if (jmp_out) {
381*44704f69SBart Van Assche                 pr2serr("Unrecognized option: %s\n", cp);
382*44704f69SBart Van Assche                 usage_old();
383*44704f69SBart Van Assche                 return SG_LIB_SYNTAX_ERROR;
384*44704f69SBart Van Assche             }
385*44704f69SBart Van Assche         } else if (0 == op->device_name)
386*44704f69SBart Van Assche             op->device_name = cp;
387*44704f69SBart Van Assche         else {
388*44704f69SBart Van Assche             pr2serr("too many arguments, got: %s, not expecting: %s\n",
389*44704f69SBart Van Assche                     op->device_name, cp);
390*44704f69SBart Van Assche             usage_old();
391*44704f69SBart Van Assche             return SG_LIB_SYNTAX_ERROR;
392*44704f69SBart Van Assche         }
393*44704f69SBart Van Assche     }
394*44704f69SBart Van Assche     return 0;
395*44704f69SBart Van Assche }
396*44704f69SBart Van Assche 
397*44704f69SBart Van Assche static int
parse_cmd_line(struct opts_t * op,int argc,char * argv[])398*44704f69SBart Van Assche parse_cmd_line(struct opts_t * op, int argc, char * argv[])
399*44704f69SBart Van Assche {
400*44704f69SBart Van Assche     int res;
401*44704f69SBart Van Assche     char * cp;
402*44704f69SBart Van Assche 
403*44704f69SBart Van Assche     cp = getenv("SG3_UTILS_OLD_OPTS");
404*44704f69SBart Van Assche     if (cp) {
405*44704f69SBart Van Assche         op->opt_new = false;
406*44704f69SBart Van Assche         res = old_parse_cmd_line(op, argc, argv);
407*44704f69SBart Van Assche         if ((0 == res) && op->opt_new)
408*44704f69SBart Van Assche             res = new_parse_cmd_line(op, argc, argv);
409*44704f69SBart Van Assche     } else {
410*44704f69SBart Van Assche         op->opt_new = true;
411*44704f69SBart Van Assche         res = new_parse_cmd_line(op, argc, argv);
412*44704f69SBart Van Assche         if ((0 == res) && (! op->opt_new))
413*44704f69SBart Van Assche             res = old_parse_cmd_line(op, argc, argv);
414*44704f69SBart Van Assche     }
415*44704f69SBart Van Assche     return res;
416*44704f69SBart Van Assche }
417*44704f69SBart Van Assche 
418*44704f69SBart Van Assche /* Return of 0 -> success, otherwise see sg_ll_send_diag() */
419*44704f69SBart Van Assche static int
do_senddiag(int sg_fd,int sf_code,bool pf_bit,bool sf_bit,bool devofl_bit,bool unitofl_bit,void * outgoing_pg,int outgoing_len,int tmout,bool noisy,int verbose)420*44704f69SBart Van Assche do_senddiag(int sg_fd, int sf_code, bool pf_bit, bool sf_bit,
421*44704f69SBart Van Assche             bool devofl_bit, bool unitofl_bit, void * outgoing_pg,
422*44704f69SBart Van Assche             int outgoing_len, int tmout, bool noisy, int verbose)
423*44704f69SBart Van Assche {
424*44704f69SBart Van Assche     int long_duration = 0;
425*44704f69SBart Van Assche 
426*44704f69SBart Van Assche     if ((0 == sf_bit) && ((5 == sf_code) || (6 == sf_code))) {
427*44704f69SBart Van Assche         /* foreground self-tests */
428*44704f69SBart Van Assche         if (tmout <= 0)
429*44704f69SBart Van Assche             long_duration = 1;
430*44704f69SBart Van Assche         else
431*44704f69SBart Van Assche             long_duration = tmout;
432*44704f69SBart Van Assche     }
433*44704f69SBart Van Assche     return sg_ll_send_diag(sg_fd, sf_code, pf_bit, sf_bit, devofl_bit,
434*44704f69SBart Van Assche                            unitofl_bit, long_duration, outgoing_pg,
435*44704f69SBart Van Assche                            outgoing_len, noisy, verbose);
436*44704f69SBart Van Assche }
437*44704f69SBart Van Assche 
438*44704f69SBart Van Assche /* Get expected extended self-test time from mode page 0xa (for '-e') */
439*44704f69SBart Van Assche static int
do_modes_0a(int sg_fd,void * resp,int mx_resp_len,bool mode6,bool noisy,int verbose)440*44704f69SBart Van Assche do_modes_0a(int sg_fd, void * resp, int mx_resp_len, bool mode6, bool noisy,
441*44704f69SBart Van Assche             int verbose)
442*44704f69SBart Van Assche {
443*44704f69SBart Van Assche     int res;
444*44704f69SBart Van Assche     int resid = 0;
445*44704f69SBart Van Assche 
446*44704f69SBart Van Assche     if (mode6)
447*44704f69SBart Van Assche         res = sg_ll_mode_sense6(sg_fd, true /* dbd */, false /* pc */,
448*44704f69SBart Van Assche                                 0xa /* page */, false, resp, mx_resp_len,
449*44704f69SBart Van Assche                                 noisy, verbose);
450*44704f69SBart Van Assche     else
451*44704f69SBart Van Assche         res = sg_ll_mode_sense10_v2(sg_fd, false /* llbaa */, true /* dbd */,
452*44704f69SBart Van Assche                                     false, 0xa, false, resp, mx_resp_len,
453*44704f69SBart Van Assche                                     0, &resid, noisy, verbose);
454*44704f69SBart Van Assche     if (res) {
455*44704f69SBart Van Assche         char b[80];
456*44704f69SBart Van Assche 
457*44704f69SBart Van Assche         sg_get_category_sense_str(res, sizeof(b), b, verbose);
458*44704f69SBart Van Assche         pr2serr("Mode sense (%s): %s\n", (mode6 ? "6" : "10"), b);
459*44704f69SBart Van Assche     } else {
460*44704f69SBart Van Assche         mx_resp_len -= resid;
461*44704f69SBart Van Assche         if (mx_resp_len < 4) {
462*44704f69SBart Van Assche             pr2serr("%s: response length (%d) too small (resid=%d)\n",
463*44704f69SBart Van Assche                     __func__, mx_resp_len, resid);
464*44704f69SBart Van Assche             res = SG_LIB_WILD_RESID;
465*44704f69SBart Van Assche         }
466*44704f69SBart Van Assche     }
467*44704f69SBart Van Assche     return res;
468*44704f69SBart Van Assche }
469*44704f69SBart Van Assche 
470*44704f69SBart Van Assche /* Read hex numbers from command line (comma separated list) or from */
471*44704f69SBart Van Assche /* stdin (one per line, comma separated list or space separated list). */
472*44704f69SBart Van Assche /* Returns 0 if ok, or 1 if error. */
473*44704f69SBart Van Assche static int
build_diag_page(const char * inp,uint8_t * mp_arr,int * mp_arr_len,int max_arr_len)474*44704f69SBart Van Assche build_diag_page(const char * inp, uint8_t * mp_arr, int * mp_arr_len,
475*44704f69SBart Van Assche                 int max_arr_len)
476*44704f69SBart Van Assche {
477*44704f69SBart Van Assche     int in_len, k, j, m;
478*44704f69SBart Van Assche     unsigned int h;
479*44704f69SBart Van Assche     const char * lcp;
480*44704f69SBart Van Assche     char * cp;
481*44704f69SBart Van Assche     char * c2p;
482*44704f69SBart Van Assche 
483*44704f69SBart Van Assche     if ((NULL == inp) || (NULL == mp_arr) ||
484*44704f69SBart Van Assche         (NULL == mp_arr_len))
485*44704f69SBart Van Assche         return 1;
486*44704f69SBart Van Assche     lcp = inp;
487*44704f69SBart Van Assche     in_len = strlen(inp);
488*44704f69SBart Van Assche     if (0 == in_len)
489*44704f69SBart Van Assche         *mp_arr_len = 0;
490*44704f69SBart Van Assche     if ('-' == inp[0]) {        /* read from stdin */
491*44704f69SBart Van Assche         bool split_line;
492*44704f69SBart Van Assche         int off = 0;
493*44704f69SBart Van Assche         char line[512];
494*44704f69SBart Van Assche         char carry_over[4];
495*44704f69SBart Van Assche 
496*44704f69SBart Van Assche         carry_over[0] = 0;
497*44704f69SBart Van Assche         for (j = 0; j < 512; ++j) {
498*44704f69SBart Van Assche             if (NULL == fgets(line, sizeof(line), stdin))
499*44704f69SBart Van Assche                 break;
500*44704f69SBart Van Assche             in_len = strlen(line);
501*44704f69SBart Van Assche             if (in_len > 0) {
502*44704f69SBart Van Assche                 if ('\n' == line[in_len - 1]) {
503*44704f69SBart Van Assche                     --in_len;
504*44704f69SBart Van Assche                     line[in_len] = '\0';
505*44704f69SBart Van Assche                     split_line = false;
506*44704f69SBart Van Assche                 } else
507*44704f69SBart Van Assche                     split_line = true;
508*44704f69SBart Van Assche             }
509*44704f69SBart Van Assche             if (in_len < 1) {
510*44704f69SBart Van Assche                 carry_over[0] = 0;
511*44704f69SBart Van Assche                 continue;
512*44704f69SBart Van Assche             }
513*44704f69SBart Van Assche             if (carry_over[0]) {
514*44704f69SBart Van Assche                 if (isxdigit((uint8_t)line[0])) {
515*44704f69SBart Van Assche                     carry_over[1] = line[0];
516*44704f69SBart Van Assche                     carry_over[2] = '\0';
517*44704f69SBart Van Assche                     if (1 == sscanf(carry_over, "%x", &h))
518*44704f69SBart Van Assche                         mp_arr[off - 1] = h;       /* back up and overwrite */
519*44704f69SBart Van Assche                     else {
520*44704f69SBart Van Assche                         pr2serr("build_diag_page: carry_over error ['%s'] "
521*44704f69SBart Van Assche                                 "around line %d\n", carry_over, j + 1);
522*44704f69SBart Van Assche                         return 1;
523*44704f69SBart Van Assche                     }
524*44704f69SBart Van Assche                     lcp = line + 1;
525*44704f69SBart Van Assche                     --in_len;
526*44704f69SBart Van Assche                 } else
527*44704f69SBart Van Assche                     lcp = line;
528*44704f69SBart Van Assche                 carry_over[0] = 0;
529*44704f69SBart Van Assche             } else
530*44704f69SBart Van Assche                 lcp = line;
531*44704f69SBart Van Assche             m = strspn(lcp, " \t");
532*44704f69SBart Van Assche             if (m == in_len)
533*44704f69SBart Van Assche                 continue;
534*44704f69SBart Van Assche             lcp += m;
535*44704f69SBart Van Assche             in_len -= m;
536*44704f69SBart Van Assche             if ('#' == *lcp)
537*44704f69SBart Van Assche                 continue;
538*44704f69SBart Van Assche             k = strspn(lcp, "0123456789aAbBcCdDeEfF ,\t");
539*44704f69SBart Van Assche             if ((k < in_len) && ('#' != lcp[k])) {
540*44704f69SBart Van Assche                 pr2serr("build_diag_page: syntax error at line %d, pos %d\n",
541*44704f69SBart Van Assche                         j + 1, m + k + 1);
542*44704f69SBart Van Assche                 return 1;
543*44704f69SBart Van Assche             }
544*44704f69SBart Van Assche             for (k = 0; k < 1024; ++k) {
545*44704f69SBart Van Assche                 if (1 == sscanf(lcp, "%x", &h)) {
546*44704f69SBart Van Assche                     if (h > 0xff) {
547*44704f69SBart Van Assche                         pr2serr("build_diag_page: hex number larger than "
548*44704f69SBart Van Assche                                 "0xff in line %d, pos %d\n", j + 1,
549*44704f69SBart Van Assche                                 (int)(lcp - line + 1));
550*44704f69SBart Van Assche                         return 1;
551*44704f69SBart Van Assche                     }
552*44704f69SBart Van Assche                     if (split_line && (1 == strlen(lcp))) {
553*44704f69SBart Van Assche                         /* single trailing hex digit might be a split pair */
554*44704f69SBart Van Assche                         carry_over[0] = *lcp;
555*44704f69SBart Van Assche                     }
556*44704f69SBart Van Assche                     if ((off + k) >= max_arr_len) {
557*44704f69SBart Van Assche                         pr2serr("build_diag_page: array length exceeded\n");
558*44704f69SBart Van Assche                         return 1;
559*44704f69SBart Van Assche                     }
560*44704f69SBart Van Assche                     mp_arr[off + k] = h;
561*44704f69SBart Van Assche                     lcp = strpbrk(lcp, " ,\t");
562*44704f69SBart Van Assche                     if (NULL == lcp)
563*44704f69SBart Van Assche                         break;
564*44704f69SBart Van Assche                     lcp += strspn(lcp, " ,\t");
565*44704f69SBart Van Assche                     if ('\0' == *lcp)
566*44704f69SBart Van Assche                         break;
567*44704f69SBart Van Assche                 } else {
568*44704f69SBart Van Assche                     if ('#' == *lcp) {
569*44704f69SBart Van Assche                         --k;
570*44704f69SBart Van Assche                         break;
571*44704f69SBart Van Assche                     }
572*44704f69SBart Van Assche                     pr2serr("build_diag_page: error in line %d, at pos %d\n",
573*44704f69SBart Van Assche                             j + 1, (int)(lcp - line + 1));
574*44704f69SBart Van Assche                     return 1;
575*44704f69SBart Van Assche                 }
576*44704f69SBart Van Assche             }
577*44704f69SBart Van Assche             off += (k + 1);
578*44704f69SBart Van Assche         }
579*44704f69SBart Van Assche         *mp_arr_len = off;
580*44704f69SBart Van Assche     } else {        /* hex string on command line */
581*44704f69SBart Van Assche         k = strspn(inp, "0123456789aAbBcCdDeEfF, ");
582*44704f69SBart Van Assche         if (in_len != k) {
583*44704f69SBart Van Assche             pr2serr("build_diag_page: error at pos %d\n", k + 1);
584*44704f69SBart Van Assche             return 1;
585*44704f69SBart Van Assche         }
586*44704f69SBart Van Assche         for (k = 0; k < max_arr_len; ++k) {
587*44704f69SBart Van Assche             if (1 == sscanf(lcp, "%x", &h)) {
588*44704f69SBart Van Assche                 if (h > 0xff) {
589*44704f69SBart Van Assche                     pr2serr("build_diag_page: hex number larger than 0xff at "
590*44704f69SBart Van Assche                             "pos %d\n", (int)(lcp - inp + 1));
591*44704f69SBart Van Assche                     return 1;
592*44704f69SBart Van Assche                 }
593*44704f69SBart Van Assche                 mp_arr[k] = h;
594*44704f69SBart Van Assche                 cp = (char *)strchr(lcp, ',');
595*44704f69SBart Van Assche                 c2p = (char *)strchr(lcp, ' ');
596*44704f69SBart Van Assche                 if (NULL == cp)
597*44704f69SBart Van Assche                     cp = c2p;
598*44704f69SBart Van Assche                 if (NULL == cp)
599*44704f69SBart Van Assche                     break;
600*44704f69SBart Van Assche                 if (c2p && (c2p < cp))
601*44704f69SBart Van Assche                     cp = c2p;
602*44704f69SBart Van Assche                 lcp = cp + 1;
603*44704f69SBart Van Assche             } else {
604*44704f69SBart Van Assche                 pr2serr("build_diag_page: error at pos %d\n",
605*44704f69SBart Van Assche                         (int)(lcp - inp + 1));
606*44704f69SBart Van Assche                 return 1;
607*44704f69SBart Van Assche             }
608*44704f69SBart Van Assche         }
609*44704f69SBart Van Assche         *mp_arr_len = k + 1;
610*44704f69SBart Van Assche         if (k == max_arr_len) {
611*44704f69SBart Van Assche             pr2serr("build_diag_page: array length exceeded\n");
612*44704f69SBart Van Assche             return 1;
613*44704f69SBart Van Assche         }
614*44704f69SBart Van Assche     }
615*44704f69SBart Van Assche     return 0;
616*44704f69SBart Van Assche }
617*44704f69SBart Van Assche 
618*44704f69SBart Van Assche 
619*44704f69SBart Van Assche struct page_code_desc {
620*44704f69SBart Van Assche         int page_code;
621*44704f69SBart Van Assche         const char * desc;
622*44704f69SBart Van Assche };
623*44704f69SBart Van Assche static struct page_code_desc pc_desc_arr[] = {
624*44704f69SBart Van Assche         {0x0, "Supported diagnostic pages"},
625*44704f69SBart Van Assche         {0x1, "Configuration (SES)"},
626*44704f69SBart Van Assche         {0x2, "Enclosure status/control (SES)"},
627*44704f69SBart Van Assche         {0x3, "Help text (SES)"},
628*44704f69SBart Van Assche         {0x4, "String In/Out (SES)"},
629*44704f69SBart Van Assche         {0x5, "Threshold In/Out (SES)"},
630*44704f69SBart Van Assche         {0x6, "Array Status/Control (SES, obsolete)"},
631*44704f69SBart Van Assche         {0x7, "Element descriptor (SES)"},
632*44704f69SBart Van Assche         {0x8, "Short enclosure status (SES)"},
633*44704f69SBart Van Assche         {0x9, "Enclosure busy (SES-2)"},
634*44704f69SBart Van Assche         {0xa, "Additional (device) element status (SES-2)"},
635*44704f69SBart Van Assche         {0xb, "Subenclosure help text (SES-2)"},
636*44704f69SBart Van Assche         {0xc, "Subenclosure string In/Out (SES-2)"},
637*44704f69SBart Van Assche         {0xd, "Supported SES diagnostic pages (SES-2)"},
638*44704f69SBart Van Assche         {0xe, "Download microcode diagnostic pages (SES-2)"},
639*44704f69SBart Van Assche         {0xf, "Subenclosure nickname diagnostic pages (SES-2)"},
640*44704f69SBart Van Assche         {0x3f, "Protocol specific (SAS transport)"},
641*44704f69SBart Van Assche         {0x40, "Translate address (direct access)"},
642*44704f69SBart Van Assche         {0x41, "Device status (direct access)"},
643*44704f69SBart Van Assche         {0x42, "Rebuild assist (direct access)"}, /* sbc3r31 */
644*44704f69SBart Van Assche };
645*44704f69SBart Van Assche 
646*44704f69SBart Van Assche static const char *
find_page_code_desc(int page_num)647*44704f69SBart Van Assche find_page_code_desc(int page_num)
648*44704f69SBart Van Assche {
649*44704f69SBart Van Assche     int k;
650*44704f69SBart Van Assche     int num = SG_ARRAY_SIZE(pc_desc_arr);
651*44704f69SBart Van Assche     const struct page_code_desc * pcdp = &pc_desc_arr[0];
652*44704f69SBart Van Assche 
653*44704f69SBart Van Assche     for (k = 0; k < num; ++k, ++pcdp) {
654*44704f69SBart Van Assche         if (page_num == pcdp->page_code)
655*44704f69SBart Van Assche             return pcdp->desc;
656*44704f69SBart Van Assche         else if (page_num < pcdp->page_code)
657*44704f69SBart Van Assche             return NULL;
658*44704f69SBart Van Assche     }
659*44704f69SBart Van Assche     return NULL;
660*44704f69SBart Van Assche }
661*44704f69SBart Van Assche 
662*44704f69SBart Van Assche static void
list_page_codes()663*44704f69SBart Van Assche list_page_codes()
664*44704f69SBart Van Assche {
665*44704f69SBart Van Assche     int k;
666*44704f69SBart Van Assche     int num = SG_ARRAY_SIZE(pc_desc_arr);
667*44704f69SBart Van Assche     const struct page_code_desc * pcdp = &pc_desc_arr[0];
668*44704f69SBart Van Assche 
669*44704f69SBart Van Assche     printf("Page_Code  Description\n");
670*44704f69SBart Van Assche     for (k = 0; k < num; ++k, ++pcdp)
671*44704f69SBart Van Assche         printf(" 0x%02x      %s\n", pcdp->page_code,
672*44704f69SBart Van Assche                (pcdp->desc ? pcdp->desc : "<unknown>"));
673*44704f69SBart Van Assche }
674*44704f69SBart Van Assche 
675*44704f69SBart Van Assche 
676*44704f69SBart Van Assche int
main(int argc,char * argv[])677*44704f69SBart Van Assche main(int argc, char * argv[])
678*44704f69SBart Van Assche {
679*44704f69SBart Van Assche     int k, num, rsp_len, res, rsp_buff_size, pg, bd_len, resid, vb;
680*44704f69SBart Van Assche     int sg_fd = -1;
681*44704f69SBart Van Assche     int read_in_len = 0;
682*44704f69SBart Van Assche     int ret = 0;
683*44704f69SBart Van Assche     struct opts_t opts;
684*44704f69SBart Van Assche     struct opts_t * op;
685*44704f69SBart Van Assche     uint8_t * rsp_buff = NULL;
686*44704f69SBart Van Assche     uint8_t * free_rsp_buff = NULL;
687*44704f69SBart Van Assche     const char * cp;
688*44704f69SBart Van Assche     uint8_t * read_in = NULL;
689*44704f69SBart Van Assche     uint8_t * free_read_in = NULL;
690*44704f69SBart Van Assche 
691*44704f69SBart Van Assche     op = &opts;
692*44704f69SBart Van Assche     memset(op, 0, sizeof(opts));
693*44704f69SBart Van Assche     op->maxlen = DEF_ALLOC_LEN;
694*44704f69SBart Van Assche     op->page_code = -1;
695*44704f69SBart Van Assche     res = parse_cmd_line(op, argc, argv);
696*44704f69SBart Van Assche     if (res)
697*44704f69SBart Van Assche         return SG_LIB_SYNTAX_ERROR;
698*44704f69SBart Van Assche     if (op->do_help) {
699*44704f69SBart Van Assche         if (op->opt_new)
700*44704f69SBart Van Assche             usage();
701*44704f69SBart Van Assche         else
702*44704f69SBart Van Assche             usage_old();
703*44704f69SBart Van Assche         return 0;
704*44704f69SBart Van Assche     }
705*44704f69SBart Van Assche #ifdef DEBUG
706*44704f69SBart Van Assche     pr2serr("In DEBUG mode, ");
707*44704f69SBart Van Assche     if (op->verbose_given && op->version_given) {
708*44704f69SBart Van Assche         pr2serr("but override: '-vV' given, zero verbose and continue\n");
709*44704f69SBart Van Assche         op->verbose_given = false;
710*44704f69SBart Van Assche         op->version_given = false;
711*44704f69SBart Van Assche         op->verbose = 0;
712*44704f69SBart Van Assche     } else if (! op->verbose_given) {
713*44704f69SBart Van Assche         pr2serr("set '-vv'\n");
714*44704f69SBart Van Assche         op->verbose = 2;
715*44704f69SBart Van Assche     } else
716*44704f69SBart Van Assche         pr2serr("keep verbose=%d\n", op->verbose);
717*44704f69SBart Van Assche #else
718*44704f69SBart Van Assche     if (op->verbose_given && op->version_given)
719*44704f69SBart Van Assche         pr2serr("Not in DEBUG mode, so '-vV' has no special action\n");
720*44704f69SBart Van Assche #endif
721*44704f69SBart Van Assche     if (op->version_given) {
722*44704f69SBart Van Assche         pr2serr("Version string: %s\n", version_str);
723*44704f69SBart Van Assche         return 0;
724*44704f69SBart Van Assche     }
725*44704f69SBart Van Assche 
726*44704f69SBart Van Assche     rsp_buff_size = op->maxlen;
727*44704f69SBart Van Assche 
728*44704f69SBart Van Assche     if (NULL == op->device_name) {
729*44704f69SBart Van Assche         if (op->do_list) {
730*44704f69SBart Van Assche             list_page_codes();
731*44704f69SBart Van Assche             return 0;
732*44704f69SBart Van Assche         }
733*44704f69SBart Van Assche         pr2serr("No DEVICE argument given\n\n");
734*44704f69SBart Van Assche         if (op->opt_new)
735*44704f69SBart Van Assche             usage();
736*44704f69SBart Van Assche         else
737*44704f69SBart Van Assche             usage_old();
738*44704f69SBart Van Assche         return SG_LIB_SYNTAX_ERROR;
739*44704f69SBart Van Assche     }
740*44704f69SBart Van Assche     vb = op->verbose;
741*44704f69SBart Van Assche     if (op->do_raw) {
742*44704f69SBart Van Assche         read_in = sg_memalign(op->maxlen, 0, &free_read_in, vb > 3);
743*44704f69SBart Van Assche         if (NULL == read_in) {
744*44704f69SBart Van Assche             pr2serr("unable to allocate %d bytes\n", op->maxlen);
745*44704f69SBart Van Assche             return SG_LIB_CAT_OTHER;
746*44704f69SBart Van Assche         }
747*44704f69SBart Van Assche         if (build_diag_page(op->raw_arg, read_in, &read_in_len, op->maxlen)) {
748*44704f69SBart Van Assche             if (op->opt_new) {
749*44704f69SBart Van Assche                 printf("Bad sequence after '--raw=' option\n");
750*44704f69SBart Van Assche                 usage();
751*44704f69SBart Van Assche             } else {
752*44704f69SBart Van Assche                 printf("Bad sequence after '-raw=' option\n");
753*44704f69SBart Van Assche                 usage_old();
754*44704f69SBart Van Assche             }
755*44704f69SBart Van Assche             ret = SG_LIB_SYNTAX_ERROR;
756*44704f69SBart Van Assche             goto fini;
757*44704f69SBart Van Assche         }
758*44704f69SBart Van Assche     }
759*44704f69SBart Van Assche 
760*44704f69SBart Van Assche     if ((op->do_doff || op->do_uoff) && (! op->do_deftest)) {
761*44704f69SBart Van Assche         if (op->opt_new) {
762*44704f69SBart Van Assche             printf("setting --doff or --uoff only useful when -t is set\n");
763*44704f69SBart Van Assche             usage();
764*44704f69SBart Van Assche         } else {
765*44704f69SBart Van Assche             printf("setting -doff or -uoff only useful when -t is set\n");
766*44704f69SBart Van Assche             usage_old();
767*44704f69SBart Van Assche         }
768*44704f69SBart Van Assche         ret = SG_LIB_CONTRADICT;
769*44704f69SBart Van Assche         goto fini;
770*44704f69SBart Van Assche     }
771*44704f69SBart Van Assche     if ((op->do_selftest > 0) && op->do_deftest) {
772*44704f69SBart Van Assche         if (op->opt_new) {
773*44704f69SBart Van Assche             printf("either set --selftest=SF or --test (not both)\n");
774*44704f69SBart Van Assche             usage();
775*44704f69SBart Van Assche         } else {
776*44704f69SBart Van Assche             printf("either set -s=SF or -t (not both)\n");
777*44704f69SBart Van Assche             usage_old();
778*44704f69SBart Van Assche         }
779*44704f69SBart Van Assche         ret = SG_LIB_CONTRADICT;
780*44704f69SBart Van Assche         goto fini;
781*44704f69SBart Van Assche     }
782*44704f69SBart Van Assche     if (op->do_raw) {
783*44704f69SBart Van Assche         if ((op->do_selftest > 0) || op->do_deftest || op->do_extdur ||
784*44704f69SBart Van Assche             op->do_list) {
785*44704f69SBart Van Assche             if (op->opt_new) {
786*44704f69SBart Van Assche                 printf("'--raw=' cannot be used with self-tests, '-e' or "
787*44704f69SBart Van Assche                        "'-l'\n");
788*44704f69SBart Van Assche                 usage();
789*44704f69SBart Van Assche             } else {
790*44704f69SBart Van Assche                 printf("'-raw=' cannot be used with self-tests, '-e' or "
791*44704f69SBart Van Assche                        "'-l'\n");
792*44704f69SBart Van Assche                 usage_old();
793*44704f69SBart Van Assche             }
794*44704f69SBart Van Assche             ret = SG_LIB_CONTRADICT;
795*44704f69SBart Van Assche             goto fini;
796*44704f69SBart Van Assche         }
797*44704f69SBart Van Assche         if (! op->do_pf) {
798*44704f69SBart Van Assche             if (op->opt_new)
799*44704f69SBart Van Assche                 printf(">>> warning, '--pf' probably should be used with "
800*44704f69SBart Van Assche                        "'--raw='\n");
801*44704f69SBart Van Assche             else
802*44704f69SBart Van Assche                 printf(">>> warning, '-pf' probably should be used with "
803*44704f69SBart Van Assche                        "'-raw='\n");
804*44704f69SBart Van Assche         }
805*44704f69SBart Van Assche     }
806*44704f69SBart Van Assche #ifdef SG_LIB_WIN32
807*44704f69SBart Van Assche #ifdef SG_LIB_WIN32_DIRECT
808*44704f69SBart Van Assche     if (vb > 4)
809*44704f69SBart Van Assche         pr2serr("Initial win32 SPT interface state: %s\n",
810*44704f69SBart Van Assche                 scsi_pt_win32_spt_state() ? "direct" : "indirect");
811*44704f69SBart Van Assche     if (op->maxlen >= 16384)
812*44704f69SBart Van Assche         scsi_pt_win32_direct(SG_LIB_WIN32_DIRECT /* SPT pt interface */);
813*44704f69SBart Van Assche #endif
814*44704f69SBart Van Assche #endif
815*44704f69SBart Van Assche 
816*44704f69SBart Van Assche     if ((sg_fd = sg_cmds_open_device(op->device_name, false /* rw */, vb)) <
817*44704f69SBart Van Assche          0) {
818*44704f69SBart Van Assche         if (vb)
819*44704f69SBart Van Assche             pr2serr(ME "error opening file: %s: %s\n", op->device_name,
820*44704f69SBart Van Assche                     safe_strerror(-sg_fd));
821*44704f69SBart Van Assche         ret = sg_convert_errno(-sg_fd);
822*44704f69SBart Van Assche         goto fini;
823*44704f69SBart Van Assche     }
824*44704f69SBart Van Assche     rsp_buff = sg_memalign(op->maxlen, 0, &free_rsp_buff, vb > 3);
825*44704f69SBart Van Assche     if (NULL == rsp_buff) {
826*44704f69SBart Van Assche         pr2serr("unable to allocate %d bytes (2)\n", op->maxlen);
827*44704f69SBart Van Assche         ret = SG_LIB_CAT_OTHER;
828*44704f69SBart Van Assche         goto close_fini;
829*44704f69SBart Van Assche     }
830*44704f69SBart Van Assche     if (op->do_extdur) {  /* fetch Extended self-test time from Control
831*44704f69SBart Van Assche                            * mode page with Mode Sense(10) command*/
832*44704f69SBart Van Assche         res = do_modes_0a(sg_fd, rsp_buff, 32, false /* mode6 */,
833*44704f69SBart Van Assche                           true /* noisy */, vb);
834*44704f69SBart Van Assche         if (0 == res) {
835*44704f69SBart Van Assche             /* Mode sense(10) response, step over any block descriptors */
836*44704f69SBart Van Assche             num = sg_msense_calc_length(rsp_buff, 32, false, &bd_len);
837*44704f69SBart Van Assche             num -= (8 /* MS(10) header length */ + bd_len);
838*44704f69SBart Van Assche             if (num >= 0xc) {
839*44704f69SBart Van Assche                 int secs = sg_get_unaligned_be16(rsp_buff + 8 + bd_len + 10);
840*44704f69SBart Van Assche 
841*44704f69SBart Van Assche 		if (0xffff == secs) {
842*44704f69SBart Van Assche 		    if (op->verbose > 1)
843*44704f69SBart Van Assche 			printf("Expected extended self-test duration's value "
844*44704f69SBart Van Assche 			       "[65535] indicates the\nsimilarly named field "
845*44704f69SBart Van Assche 			       "in the Extended Inquiry VPD page should be "
846*44704f69SBart Van Assche 			       "used\n");
847*44704f69SBart Van Assche 		} else {
848*44704f69SBart Van Assche #ifdef SG_LIB_MINGW
849*44704f69SBart Van Assche                     printf("Expected extended self-test duration=%d seconds "
850*44704f69SBart Van Assche                            "(%g minutes)\n", secs, secs / 60.0);
851*44704f69SBart Van Assche #else
852*44704f69SBart Van Assche                     printf("Expected extended self-test duration=%d seconds "
853*44704f69SBart Van Assche                            "(%.2f minutes)\n", secs, secs / 60.0);
854*44704f69SBart Van Assche #endif
855*44704f69SBart Van Assche 		}
856*44704f69SBart Van Assche             } else
857*44704f69SBart Van Assche                 printf("Extended self-test duration not available\n");
858*44704f69SBart Van Assche         } else {
859*44704f69SBart Van Assche             ret = res;
860*44704f69SBart Van Assche             printf("Extended self-test duration (mode page 0xa) failed\n");
861*44704f69SBart Van Assche             goto err_out9;
862*44704f69SBart Van Assche         }
863*44704f69SBart Van Assche     } else if (op->do_list || (op->page_code >= 0x0)) {
864*44704f69SBart Van Assche         pg = op->page_code;
865*44704f69SBart Van Assche         if (pg < 0)
866*44704f69SBart Van Assche             res = do_senddiag(sg_fd, 0, true /* pf */, false, false, false,
867*44704f69SBart Van Assche                               rsp_buff, 4, op->timeout, 1, vb);
868*44704f69SBart Van Assche         else
869*44704f69SBart Van Assche             res = 0;
870*44704f69SBart Van Assche         if (0 == res) {
871*44704f69SBart Van Assche             resid = 0;
872*44704f69SBart Van Assche             if (0 == sg_ll_receive_diag_v2(sg_fd, (pg >= 0x0),
873*44704f69SBart Van Assche                                            ((pg >= 0x0) ? pg : 0), rsp_buff,
874*44704f69SBart Van Assche                                            rsp_buff_size, 0, &resid,
875*44704f69SBart Van Assche                                            true, vb)) {
876*44704f69SBart Van Assche                 rsp_buff_size -= resid;
877*44704f69SBart Van Assche                 if (rsp_buff_size < 4) {
878*44704f69SBart Van Assche                     pr2serr("RD resid (%d) indicates response too small "
879*44704f69SBart Van Assche                             "(lem=%d)\n", resid, rsp_buff_size);
880*44704f69SBart Van Assche                     goto err_out;
881*44704f69SBart Van Assche                 }
882*44704f69SBart Van Assche                 rsp_len = sg_get_unaligned_be16(rsp_buff + 2) + 4;
883*44704f69SBart Van Assche                 rsp_len= (rsp_len < rsp_buff_size) ? rsp_len : rsp_buff_size;
884*44704f69SBart Van Assche                 if (op->do_hex > 1)
885*44704f69SBart Van Assche                     hex2stdout(rsp_buff, rsp_len,
886*44704f69SBart Van Assche                             (2 == op->do_hex) ? 0 : -1);
887*44704f69SBart Van Assche                 else if (pg < 0x1) {
888*44704f69SBart Van Assche                     printf("Supported diagnostic pages response:\n");
889*44704f69SBart Van Assche                     if (op->do_hex)
890*44704f69SBart Van Assche                         hex2stdout(rsp_buff, rsp_len, 1);
891*44704f69SBart Van Assche                     else {
892*44704f69SBart Van Assche                         for (k = 0; k < (rsp_len - 4); ++k) {
893*44704f69SBart Van Assche                             pg = rsp_buff[k + 4];
894*44704f69SBart Van Assche                             cp = find_page_code_desc(pg);
895*44704f69SBart Van Assche                             if (NULL == cp)
896*44704f69SBart Van Assche                                 cp = (pg < 0x80) ? "<unknown>" :
897*44704f69SBart Van Assche                                                    "<vendor specific>";
898*44704f69SBart Van Assche                             printf("  0x%02x  %s\n", pg, cp);
899*44704f69SBart Van Assche                         }
900*44704f69SBart Van Assche                     }
901*44704f69SBart Van Assche                 } else {
902*44704f69SBart Van Assche                     cp = find_page_code_desc(pg);
903*44704f69SBart Van Assche                     if (cp)
904*44704f69SBart Van Assche                         printf("%s diagnostic page [0x%x] response in "
905*44704f69SBart Van Assche                                "hex:\n", cp, pg);
906*44704f69SBart Van Assche                     else
907*44704f69SBart Van Assche                         printf("diagnostic page 0x%x response in hex:\n", pg);
908*44704f69SBart Van Assche                     hex2stdout(rsp_buff, rsp_len, 1);
909*44704f69SBart Van Assche                 }
910*44704f69SBart Van Assche             } else {
911*44704f69SBart Van Assche                 ret = res;
912*44704f69SBart Van Assche                 pr2serr("RECEIVE DIAGNOSTIC RESULTS command failed\n");
913*44704f69SBart Van Assche                 goto err_out9;
914*44704f69SBart Van Assche             }
915*44704f69SBart Van Assche         } else {
916*44704f69SBart Van Assche             ret = res;
917*44704f69SBart Van Assche             goto err_out;
918*44704f69SBart Van Assche         }
919*44704f69SBart Van Assche     } else if (op->do_raw) {
920*44704f69SBart Van Assche         res = do_senddiag(sg_fd, 0, op->do_pf, false, false, false, read_in,
921*44704f69SBart Van Assche                           read_in_len, op->timeout, 1, vb);
922*44704f69SBart Van Assche         if (res) {
923*44704f69SBart Van Assche             ret = res;
924*44704f69SBart Van Assche             goto err_out;
925*44704f69SBart Van Assche         }
926*44704f69SBart Van Assche     } else {
927*44704f69SBart Van Assche         res = do_senddiag(sg_fd, op->do_selftest, op->do_pf, op->do_deftest,
928*44704f69SBart Van Assche                           op->do_doff, op->do_uoff, NULL, 0, op->timeout, 1,
929*44704f69SBart Van Assche                           vb);
930*44704f69SBart Van Assche         if (0 == res) {
931*44704f69SBart Van Assche             if ((5 == op->do_selftest) || (6 == op->do_selftest))
932*44704f69SBart Van Assche                 printf("Foreground self-test returned GOOD status\n");
933*44704f69SBart Van Assche             else if (op->do_deftest && (! op->do_doff) && (! op->do_uoff))
934*44704f69SBart Van Assche                 printf("Default self-test returned GOOD status\n");
935*44704f69SBart Van Assche         } else {
936*44704f69SBart Van Assche             ret = res;
937*44704f69SBart Van Assche             goto err_out;
938*44704f69SBart Van Assche         }
939*44704f69SBart Van Assche     }
940*44704f69SBart Van Assche     goto close_fini;
941*44704f69SBart Van Assche 
942*44704f69SBart Van Assche err_out:
943*44704f69SBart Van Assche     if (SG_LIB_CAT_UNIT_ATTENTION == res)
944*44704f69SBart Van Assche         pr2serr("SEND DIAGNOSTIC, unit attention\n");
945*44704f69SBart Van Assche     else if (SG_LIB_CAT_ABORTED_COMMAND == res)
946*44704f69SBart Van Assche         pr2serr("SEND DIAGNOSTIC, aborted command\n");
947*44704f69SBart Van Assche     else if (SG_LIB_CAT_NOT_READY == res)
948*44704f69SBart Van Assche         pr2serr("SEND DIAGNOSTIC, device not ready\n");
949*44704f69SBart Van Assche     else
950*44704f69SBart Van Assche         pr2serr("SEND DIAGNOSTIC command, failed\n");
951*44704f69SBart Van Assche err_out9:
952*44704f69SBart Van Assche     if (vb < 2)
953*44704f69SBart Van Assche         pr2serr("  try again with '-vv' for more information\n");
954*44704f69SBart Van Assche close_fini:
955*44704f69SBart Van Assche     if (sg_fd >= 0) {
956*44704f69SBart Van Assche         res = sg_cmds_close_device(sg_fd);
957*44704f69SBart Van Assche         if (0 == ret)
958*44704f69SBart Van Assche             ret = sg_convert_errno(-res);
959*44704f69SBart Van Assche     }
960*44704f69SBart Van Assche fini:
961*44704f69SBart Van Assche     if (free_read_in)
962*44704f69SBart Van Assche         free(free_read_in);
963*44704f69SBart Van Assche     if (free_rsp_buff)
964*44704f69SBart Van Assche         free(free_rsp_buff);
965*44704f69SBart Van Assche     if (0 == vb) {
966*44704f69SBart Van Assche         if (! sg_if_can2stderr("sg_senddiag failed: ", ret))
967*44704f69SBart Van Assche             pr2serr("Some error occurred, try again with '-v' "
968*44704f69SBart Van Assche                     "or '-vv' for more information\n");
969*44704f69SBart Van Assche     }
970*44704f69SBart Van Assche     return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
971*44704f69SBart Van Assche }
972