1*44704f69SBart Van Assche /*
2*44704f69SBart Van Assche * Copyright (c) 2011-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 <string.h>
17*44704f69SBart Van Assche #include <errno.h>
18*44704f69SBart Van Assche #include <limits.h>
19*44704f69SBart Van Assche #include <sys/types.h>
20*44704f69SBart Van Assche #include <sys/stat.h>
21*44704f69SBart Van Assche #include <getopt.h>
22*44704f69SBart Van Assche #define __STDC_FORMAT_MACROS 1
23*44704f69SBart Van Assche #include <inttypes.h>
24*44704f69SBart Van Assche
25*44704f69SBart Van Assche #ifdef HAVE_CONFIG_H
26*44704f69SBart Van Assche #include "config.h"
27*44704f69SBart Van Assche #endif
28*44704f69SBart Van Assche
29*44704f69SBart Van Assche #include "sg_lib.h"
30*44704f69SBart Van Assche #include "sg_pt.h"
31*44704f69SBart Van Assche #include "sg_cmds_basic.h"
32*44704f69SBart Van Assche #include "sg_cmds_extra.h"
33*44704f69SBart Van Assche #include "sg_unaligned.h"
34*44704f69SBart Van Assche #include "sg_pr2serr.h"
35*44704f69SBart Van Assche
36*44704f69SBart Van Assche static const char * version_str = "1.19 20220608";
37*44704f69SBart Van Assche
38*44704f69SBart Van Assche #define ME "sg_sanitize: "
39*44704f69SBart Van Assche
40*44704f69SBart Van Assche #define SANITIZE_OP 0x48
41*44704f69SBart Van Assche #define SANITIZE_OP_LEN 10
42*44704f69SBart Van Assche #define SANITIZE_SA_OVERWRITE 0x1
43*44704f69SBart Van Assche #define SANITIZE_SA_BLOCK_ERASE 0x2
44*44704f69SBart Van Assche #define SANITIZE_SA_CRYPTO_ERASE 0x3
45*44704f69SBart Van Assche #define SANITIZE_SA_EXIT_FAIL_MODE 0x1f
46*44704f69SBart Van Assche #define DEF_REQS_RESP_LEN 252
47*44704f69SBart Van Assche #define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */
48*44704f69SBart Van Assche #define MAX_XFER_LEN 65535
49*44704f69SBart Van Assche #define EBUFF_SZ 256
50*44704f69SBart Van Assche
51*44704f69SBart Van Assche #define SHORT_TIMEOUT 20 /* 20 seconds unless immed=0 ... */
52*44704f69SBart Van Assche #define LONG_TIMEOUT (15 * 3600) /* 15 hours ! */
53*44704f69SBart Van Assche /* Seagate ST32000444SS 2TB disk takes 9.5 hours to format */
54*44704f69SBart Van Assche #define POLL_DURATION_SECS 60
55*44704f69SBart Van Assche
56*44704f69SBart Van Assche
57*44704f69SBart Van Assche static struct option long_options[] = {
58*44704f69SBart Van Assche {"ause", no_argument, 0, 'A'},
59*44704f69SBart Van Assche {"block", no_argument, 0, 'B'},
60*44704f69SBart Van Assche {"count", required_argument, 0, 'c'},
61*44704f69SBart Van Assche {"crypto", no_argument, 0, 'C'},
62*44704f69SBart Van Assche {"desc", no_argument, 0, 'd'},
63*44704f69SBart Van Assche {"dry-run", no_argument, 0, 'D'},
64*44704f69SBart Van Assche {"dry_run", no_argument, 0, 'D'},
65*44704f69SBart Van Assche {"early", no_argument, 0, 'e'},
66*44704f69SBart Van Assche {"fail", no_argument, 0, 'F'},
67*44704f69SBart Van Assche {"help", no_argument, 0, 'h'},
68*44704f69SBart Van Assche {"invert", no_argument, 0, 'I'},
69*44704f69SBart Van Assche {"ipl", required_argument, 0, 'i'},
70*44704f69SBart Van Assche {"overwrite", no_argument, 0, 'O'},
71*44704f69SBart Van Assche {"pattern", required_argument, 0, 'p'},
72*44704f69SBart Van Assche {"quick", no_argument, 0, 'Q'},
73*44704f69SBart Van Assche {"test", required_argument, 0, 'T'},
74*44704f69SBart Van Assche {"timeout", required_argument, 0, 't'},
75*44704f69SBart Van Assche {"verbose", no_argument, 0, 'v'},
76*44704f69SBart Van Assche {"version", no_argument, 0, 'V'},
77*44704f69SBart Van Assche {"wait", no_argument, 0, 'w'},
78*44704f69SBart Van Assche {"zero", no_argument, 0, 'z'},
79*44704f69SBart Van Assche {0, 0, 0, 0},
80*44704f69SBart Van Assche };
81*44704f69SBart Van Assche
82*44704f69SBart Van Assche struct opts_t {
83*44704f69SBart Van Assche bool ause;
84*44704f69SBart Van Assche bool block;
85*44704f69SBart Van Assche bool crypto;
86*44704f69SBart Van Assche bool desc;
87*44704f69SBart Van Assche bool dry_run;
88*44704f69SBart Van Assche bool early;
89*44704f69SBart Van Assche bool fail;
90*44704f69SBart Van Assche bool invert;
91*44704f69SBart Van Assche bool overwrite;
92*44704f69SBart Van Assche bool quick;
93*44704f69SBart Van Assche bool verbose_given;
94*44704f69SBart Van Assche bool version_given;
95*44704f69SBart Van Assche bool wait;
96*44704f69SBart Van Assche bool znr;
97*44704f69SBart Van Assche int count;
98*44704f69SBart Van Assche int ipl; /* initialization pattern length */
99*44704f69SBart Van Assche int test;
100*44704f69SBart Van Assche int timeout; /* in seconds */
101*44704f69SBart Van Assche int verbose;
102*44704f69SBart Van Assche int zero;
103*44704f69SBart Van Assche const char * pattern_fn;
104*44704f69SBart Van Assche };
105*44704f69SBart Van Assche
106*44704f69SBart Van Assche
107*44704f69SBart Van Assche static void
usage()108*44704f69SBart Van Assche usage()
109*44704f69SBart Van Assche {
110*44704f69SBart Van Assche pr2serr("Usage: sg_sanitize [--ause] [--block] [--count=OC] [--crypto] "
111*44704f69SBart Van Assche "[--dry-run]\n"
112*44704f69SBart Van Assche " [--early] [--fail] [--help] [--invert] "
113*44704f69SBart Van Assche "[--ipl=LEN]\n"
114*44704f69SBart Van Assche " [--overwrite] [--pattern=PF] [--quick] "
115*44704f69SBart Van Assche "[--test=TE]\n"
116*44704f69SBart Van Assche " [--timeout=SECS] [--verbose] [--version] "
117*44704f69SBart Van Assche "[--wait]\n"
118*44704f69SBart Van Assche " [--zero] [--znr] DEVICE\n"
119*44704f69SBart Van Assche " where:\n"
120*44704f69SBart Van Assche " --ause|-A set AUSE bit in cdb\n"
121*44704f69SBart Van Assche " --block|-B do BLOCK ERASE sanitize\n"
122*44704f69SBart Van Assche " --count=OC|-c OC OC is overwrite count field (from 1 "
123*44704f69SBart Van Assche "(def) to 31)\n"
124*44704f69SBart Van Assche " --crypto|-C do CRYPTOGRAPHIC ERASE sanitize\n"
125*44704f69SBart Van Assche " --desc|-d polling request sense sets 'desc' "
126*44704f69SBart Van Assche "field\n"
127*44704f69SBart Van Assche " (def: clear 'desc' field)\n"
128*44704f69SBart Van Assche " --dry-run|-D to preparation but bypass SANITIZE "
129*44704f69SBart Van Assche "command\n"
130*44704f69SBart Van Assche " --early|-e exit once sanitize started (IMMED set "
131*44704f69SBart Van Assche "in cdb)\n"
132*44704f69SBart Van Assche " user can monitor progress with REQUEST "
133*44704f69SBart Van Assche "SENSE\n"
134*44704f69SBart Van Assche " --fail|-F do EXIT FAILURE MODE sanitize\n"
135*44704f69SBart Van Assche " --help|-h print out usage message\n"
136*44704f69SBart Van Assche " --invert|-I set INVERT bit in OVERWRITE parameter "
137*44704f69SBart Van Assche "list\n"
138*44704f69SBart Van Assche " --ipl=LEN|-i LEN initialization pattern length (in "
139*44704f69SBart Van Assche "bytes)\n"
140*44704f69SBart Van Assche " --overwrite|-O do OVERWRITE sanitize\n"
141*44704f69SBart Van Assche " --pattern=PF|-p PF PF is file containing initialization "
142*44704f69SBart Van Assche "pattern\n"
143*44704f69SBart Van Assche " for OVERWRITE\n"
144*44704f69SBart Van Assche " --quick|-Q start sanitize without pause for user\n"
145*44704f69SBart Van Assche " intervention (i.e. no time to "
146*44704f69SBart Van Assche "reconsider)\n"
147*44704f69SBart Van Assche " --test=TE|-T TE TE is placed in TEST field of "
148*44704f69SBart Van Assche "OVERWRITE\n"
149*44704f69SBart Van Assche " parameter list (def: 0)\n"
150*44704f69SBart Van Assche " --timeout=SECS|-t SECS SANITIZE command timeout in "
151*44704f69SBart Van Assche "seconds\n"
152*44704f69SBart Van Assche " --verbose|-v increase verbosity\n"
153*44704f69SBart Van Assche " --version|-V print version string then exit\n"
154*44704f69SBart Van Assche " --wait|-w wait for command to finish (could "
155*44704f69SBart Van Assche "take hours)\n"
156*44704f69SBart Van Assche " --zero|-z use pattern of zeros for "
157*44704f69SBart Van Assche "OVERWRITE\n"
158*44704f69SBart Van Assche " --znr|-Z set ZNR (zone no reset) bit in cdb\n\n"
159*44704f69SBart Van Assche "Performs a SCSI SANITIZE command.\n <<<WARNING>>>: all data "
160*44704f69SBart Van Assche "on DEVICE will be lost.\nDefault action is to give user time to "
161*44704f69SBart Van Assche "reconsider; then execute SANITIZE\ncommand with IMMED bit set; "
162*44704f69SBart Van Assche "then use REQUEST SENSE command every 60\nseconds to poll for a "
163*44704f69SBart Van Assche "progress indication; then exit when there is no\nmore progress "
164*44704f69SBart Van Assche "indication.\n"
165*44704f69SBart Van Assche );
166*44704f69SBart Van Assche }
167*44704f69SBart Van Assche
168*44704f69SBart Van Assche /* Invoke SCSI SANITIZE command. Returns 0 if successful, otherwise error */
169*44704f69SBart Van Assche static int
do_sanitize(int sg_fd,const struct opts_t * op,const void * param_lstp,int param_lst_len)170*44704f69SBart Van Assche do_sanitize(int sg_fd, const struct opts_t * op, const void * param_lstp,
171*44704f69SBart Van Assche int param_lst_len)
172*44704f69SBart Van Assche {
173*44704f69SBart Van Assche bool immed;
174*44704f69SBart Van Assche int ret, res, sense_cat, timeout;
175*44704f69SBart Van Assche uint8_t san_cdb[SANITIZE_OP_LEN];
176*44704f69SBart Van Assche uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT;
177*44704f69SBart Van Assche struct sg_pt_base * ptvp;
178*44704f69SBart Van Assche
179*44704f69SBart Van Assche if (op->early || op->wait)
180*44704f69SBart Van Assche immed = op->early;
181*44704f69SBart Van Assche else
182*44704f69SBart Van Assche immed = true;
183*44704f69SBart Van Assche timeout = (immed ? SHORT_TIMEOUT : LONG_TIMEOUT);
184*44704f69SBart Van Assche /* only use command line timeout if it exceeds previous defaults */
185*44704f69SBart Van Assche if (op->timeout > timeout)
186*44704f69SBart Van Assche timeout = op->timeout;
187*44704f69SBart Van Assche memset(san_cdb, 0, sizeof(san_cdb));
188*44704f69SBart Van Assche san_cdb[0] = SANITIZE_OP;
189*44704f69SBart Van Assche if (op->overwrite)
190*44704f69SBart Van Assche san_cdb[1] = SANITIZE_SA_OVERWRITE;
191*44704f69SBart Van Assche else if (op->block)
192*44704f69SBart Van Assche san_cdb[1] = SANITIZE_SA_BLOCK_ERASE;
193*44704f69SBart Van Assche else if (op->crypto)
194*44704f69SBart Van Assche san_cdb[1] = SANITIZE_SA_CRYPTO_ERASE;
195*44704f69SBart Van Assche else if (op->fail)
196*44704f69SBart Van Assche san_cdb[1] = SANITIZE_SA_EXIT_FAIL_MODE;
197*44704f69SBart Van Assche else
198*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
199*44704f69SBart Van Assche if (immed)
200*44704f69SBart Van Assche san_cdb[1] |= 0x80;
201*44704f69SBart Van Assche if (op->znr) /* added sbc4r07 */
202*44704f69SBart Van Assche san_cdb[1] |= 0x40;
203*44704f69SBart Van Assche if (op->ause)
204*44704f69SBart Van Assche san_cdb[1] |= 0x20;
205*44704f69SBart Van Assche sg_put_unaligned_be16((uint16_t)param_lst_len, san_cdb + 7);
206*44704f69SBart Van Assche
207*44704f69SBart Van Assche if (op->verbose > 1) {
208*44704f69SBart Van Assche char b[128];
209*44704f69SBart Van Assche
210*44704f69SBart Van Assche pr2serr(" Sanitize cdb: %s\n",
211*44704f69SBart Van Assche sg_get_command_str(san_cdb, SANITIZE_OP_LEN, false,
212*44704f69SBart Van Assche sizeof(b), b));
213*44704f69SBart Van Assche if (op->verbose > 2) {
214*44704f69SBart Van Assche if (param_lst_len > 0) {
215*44704f69SBart Van Assche pr2serr(" Parameter list contents:\n");
216*44704f69SBart Van Assche hex2stderr((const uint8_t *)param_lstp, param_lst_len, -1);
217*44704f69SBart Van Assche }
218*44704f69SBart Van Assche pr2serr(" Sanitize command timeout: %d seconds\n", timeout);
219*44704f69SBart Van Assche }
220*44704f69SBart Van Assche }
221*44704f69SBart Van Assche if (op->dry_run) {
222*44704f69SBart Van Assche pr2serr("Due to --dry-run option, bypassing SANITIZE command\n");
223*44704f69SBart Van Assche return 0;
224*44704f69SBart Van Assche }
225*44704f69SBart Van Assche ptvp = construct_scsi_pt_obj();
226*44704f69SBart Van Assche if (NULL == ptvp) {
227*44704f69SBart Van Assche pr2serr("Sanitize: out of memory\n");
228*44704f69SBart Van Assche return -1;
229*44704f69SBart Van Assche }
230*44704f69SBart Van Assche set_scsi_pt_cdb(ptvp, san_cdb, sizeof(san_cdb));
231*44704f69SBart Van Assche set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
232*44704f69SBart Van Assche set_scsi_pt_data_out(ptvp, (uint8_t *)param_lstp, param_lst_len);
233*44704f69SBart Van Assche res = do_scsi_pt(ptvp, sg_fd, timeout, op->verbose);
234*44704f69SBart Van Assche ret = sg_cmds_process_resp(ptvp, "Sanitize", res, true /*noisy */,
235*44704f69SBart Van Assche op->verbose, &sense_cat);
236*44704f69SBart Van Assche if (-1 == ret) {
237*44704f69SBart Van Assche if (get_scsi_pt_transport_err(ptvp))
238*44704f69SBart Van Assche ret = SG_LIB_TRANSPORT_ERROR;
239*44704f69SBart Van Assche else
240*44704f69SBart Van Assche ret = sg_convert_errno(get_scsi_pt_os_err(ptvp));
241*44704f69SBart Van Assche } else if (-2 == ret) {
242*44704f69SBart Van Assche switch (sense_cat) {
243*44704f69SBart Van Assche case SG_LIB_CAT_RECOVERED:
244*44704f69SBart Van Assche case SG_LIB_CAT_NO_SENSE:
245*44704f69SBart Van Assche ret = 0;
246*44704f69SBart Van Assche break;
247*44704f69SBart Van Assche case SG_LIB_CAT_MEDIUM_HARD:
248*44704f69SBart Van Assche {
249*44704f69SBart Van Assche bool valid;
250*44704f69SBart Van Assche int slen;
251*44704f69SBart Van Assche uint64_t ull = 0;
252*44704f69SBart Van Assche
253*44704f69SBart Van Assche slen = get_scsi_pt_sense_len(ptvp);
254*44704f69SBart Van Assche valid = sg_get_sense_info_fld(sense_b, slen, &ull);
255*44704f69SBart Van Assche if (valid)
256*44704f69SBart Van Assche pr2serr("Medium or hardware error starting at "
257*44704f69SBart Van Assche "lba=%" PRIu64 " [0x%" PRIx64 "]\n", ull, ull);
258*44704f69SBart Van Assche }
259*44704f69SBart Van Assche ret = sense_cat;
260*44704f69SBart Van Assche break;
261*44704f69SBart Van Assche default:
262*44704f69SBart Van Assche ret = sense_cat;
263*44704f69SBart Van Assche break;
264*44704f69SBart Van Assche }
265*44704f69SBart Van Assche } else {
266*44704f69SBart Van Assche ret = 0;
267*44704f69SBart Van Assche if (op->verbose)
268*44704f69SBart Van Assche pr2serr("Sanitize command %s without error\n",
269*44704f69SBart Van Assche (immed ? "launched" : "completed"));
270*44704f69SBart Van Assche }
271*44704f69SBart Van Assche
272*44704f69SBart Van Assche destruct_scsi_pt_obj(ptvp);
273*44704f69SBart Van Assche return ret;
274*44704f69SBart Van Assche }
275*44704f69SBart Van Assche
276*44704f69SBart Van Assche #define VPD_DEVICE_ID 0x83
277*44704f69SBart Van Assche #define VPD_ASSOC_LU 0
278*44704f69SBart Van Assche #define VPD_ASSOC_TPORT 1
279*44704f69SBart Van Assche #define TPROTO_ISCSI 5
280*44704f69SBart Van Assche
281*44704f69SBart Van Assche static char *
get_lu_name(const uint8_t * bp,int u_len,char * b,int b_len)282*44704f69SBart Van Assche get_lu_name(const uint8_t * bp, int u_len, char * b, int b_len)
283*44704f69SBart Van Assche {
284*44704f69SBart Van Assche int len, off, sns_dlen, dlen, k;
285*44704f69SBart Van Assche uint8_t u_sns[512];
286*44704f69SBart Van Assche char * cp;
287*44704f69SBart Van Assche
288*44704f69SBart Van Assche len = u_len - 4;
289*44704f69SBart Van Assche bp += 4;
290*44704f69SBart Van Assche off = -1;
291*44704f69SBart Van Assche if (0 == sg_vpd_dev_id_iter(bp, len, &off, VPD_ASSOC_LU,
292*44704f69SBart Van Assche 8 /* SCSI name string (sns) */,
293*44704f69SBart Van Assche 3 /* UTF-8 */)) {
294*44704f69SBart Van Assche sns_dlen = bp[off + 3];
295*44704f69SBart Van Assche memcpy(u_sns, bp + off + 4, sns_dlen);
296*44704f69SBart Van Assche /* now want to check if this is iSCSI */
297*44704f69SBart Van Assche off = -1;
298*44704f69SBart Van Assche if (0 == sg_vpd_dev_id_iter(bp, len, &off, VPD_ASSOC_TPORT,
299*44704f69SBart Van Assche 8 /* SCSI name string (sns) */,
300*44704f69SBart Van Assche 3 /* UTF-8 */)) {
301*44704f69SBart Van Assche if ((0x80 & bp[1]) && (TPROTO_ISCSI == (bp[0] >> 4))) {
302*44704f69SBart Van Assche snprintf(b, b_len, "%.*s", sns_dlen, u_sns);
303*44704f69SBart Van Assche return b;
304*44704f69SBart Van Assche }
305*44704f69SBart Van Assche }
306*44704f69SBart Van Assche } else
307*44704f69SBart Van Assche sns_dlen = 0;
308*44704f69SBart Van Assche if (0 == sg_vpd_dev_id_iter(bp, len, &off, VPD_ASSOC_LU,
309*44704f69SBart Van Assche 3 /* NAA */, 1 /* binary */)) {
310*44704f69SBart Van Assche dlen = bp[off + 3];
311*44704f69SBart Van Assche if (! ((8 == dlen) || (16 ==dlen)))
312*44704f69SBart Van Assche return b;
313*44704f69SBart Van Assche cp = b;
314*44704f69SBart Van Assche for (k = 0; ((k < dlen) && (b_len > 1)); ++k) {
315*44704f69SBart Van Assche snprintf(cp, b_len, "%02x", bp[off + 4 + k]);
316*44704f69SBart Van Assche cp += 2;
317*44704f69SBart Van Assche b_len -= 2;
318*44704f69SBart Van Assche }
319*44704f69SBart Van Assche } else if (0 == sg_vpd_dev_id_iter(bp, len, &off, VPD_ASSOC_LU,
320*44704f69SBart Van Assche 2 /* EUI */, 1 /* binary */)) {
321*44704f69SBart Van Assche dlen = bp[off + 3];
322*44704f69SBart Van Assche if (! ((8 == dlen) || (12 == dlen) || (16 ==dlen)))
323*44704f69SBart Van Assche return b;
324*44704f69SBart Van Assche cp = b;
325*44704f69SBart Van Assche for (k = 0; ((k < dlen) && (b_len > 1)); ++k) {
326*44704f69SBart Van Assche snprintf(cp, b_len, "%02x", bp[off + 4 + k]);
327*44704f69SBart Van Assche cp += 2;
328*44704f69SBart Van Assche b_len -= 2;
329*44704f69SBart Van Assche }
330*44704f69SBart Van Assche } else if (sns_dlen > 0)
331*44704f69SBart Van Assche snprintf(b, b_len, "%.*s", sns_dlen, u_sns);
332*44704f69SBart Van Assche return b;
333*44704f69SBart Van Assche }
334*44704f69SBart Van Assche
335*44704f69SBart Van Assche #define SAFE_STD_INQ_RESP_LEN 36
336*44704f69SBart Van Assche #define VPD_SUPPORTED_VPDS 0x0
337*44704f69SBart Van Assche #define VPD_UNIT_SERIAL_NUM 0x80
338*44704f69SBart Van Assche #define VPD_DEVICE_ID 0x83
339*44704f69SBart Van Assche
340*44704f69SBart Van Assche static int
print_dev_id(int fd,uint8_t * sinq_resp,int max_rlen,int verbose)341*44704f69SBart Van Assche print_dev_id(int fd, uint8_t * sinq_resp, int max_rlen, int verbose)
342*44704f69SBart Van Assche {
343*44704f69SBart Van Assche int res, k, n, verb, pdt, has_sn, has_di;
344*44704f69SBart Van Assche uint8_t b[256];
345*44704f69SBart Van Assche char a[256];
346*44704f69SBart Van Assche char pdt_name[64];
347*44704f69SBart Van Assche
348*44704f69SBart Van Assche verb = (verbose > 1) ? verbose - 1 : 0;
349*44704f69SBart Van Assche memset(sinq_resp, 0, max_rlen);
350*44704f69SBart Van Assche res = sg_ll_inquiry(fd, false, false /* evpd */, 0 /* pg_op */, b,
351*44704f69SBart Van Assche SAFE_STD_INQ_RESP_LEN, 1, verb);
352*44704f69SBart Van Assche if (res)
353*44704f69SBart Van Assche return res;
354*44704f69SBart Van Assche n = b[4] + 5;
355*44704f69SBart Van Assche if (n > SAFE_STD_INQ_RESP_LEN)
356*44704f69SBart Van Assche n = SAFE_STD_INQ_RESP_LEN;
357*44704f69SBart Van Assche memcpy(sinq_resp, b, (n < max_rlen) ? n : max_rlen);
358*44704f69SBart Van Assche if (n == SAFE_STD_INQ_RESP_LEN) {
359*44704f69SBart Van Assche pdt = b[0] & PDT_MASK;
360*44704f69SBart Van Assche printf(" %.8s %.16s %.4s peripheral_type: %s [0x%x]\n",
361*44704f69SBart Van Assche (const char *)(b + 8), (const char *)(b + 16),
362*44704f69SBart Van Assche (const char *)(b + 32),
363*44704f69SBart Van Assche sg_get_pdt_str(pdt, sizeof(pdt_name), pdt_name), pdt);
364*44704f69SBart Van Assche if (verbose)
365*44704f69SBart Van Assche printf(" PROTECT=%d\n", !!(b[5] & 1));
366*44704f69SBart Van Assche if (b[5] & 1)
367*44704f69SBart Van Assche printf(" << supports protection information>>\n");
368*44704f69SBart Van Assche } else {
369*44704f69SBart Van Assche pr2serr("Short INQUIRY response: %d bytes, expect at least 36\n", n);
370*44704f69SBart Van Assche return SG_LIB_CAT_OTHER;
371*44704f69SBart Van Assche }
372*44704f69SBart Van Assche res = sg_ll_inquiry(fd, false, true /* evpd */, VPD_SUPPORTED_VPDS, b,
373*44704f69SBart Van Assche SAFE_STD_INQ_RESP_LEN, 1, verb);
374*44704f69SBart Van Assche if (res) {
375*44704f69SBart Van Assche if (verbose)
376*44704f69SBart Van Assche pr2serr("VPD_SUPPORTED_VPDS gave res=%d\n", res);
377*44704f69SBart Van Assche return 0;
378*44704f69SBart Van Assche }
379*44704f69SBart Van Assche if (VPD_SUPPORTED_VPDS != b[1]) {
380*44704f69SBart Van Assche if (verbose)
381*44704f69SBart Van Assche pr2serr("VPD_SUPPORTED_VPDS corrupted\n");
382*44704f69SBart Van Assche return 0;
383*44704f69SBart Van Assche }
384*44704f69SBart Van Assche n = sg_get_unaligned_be16(b + 2);
385*44704f69SBart Van Assche if (n > (SAFE_STD_INQ_RESP_LEN - 4))
386*44704f69SBart Van Assche n = (SAFE_STD_INQ_RESP_LEN - 4);
387*44704f69SBart Van Assche for (k = 0, has_sn = 0, has_di = 0; k < n; ++k) {
388*44704f69SBart Van Assche if (VPD_UNIT_SERIAL_NUM == b[4 + k])
389*44704f69SBart Van Assche ++has_sn;
390*44704f69SBart Van Assche else if (VPD_DEVICE_ID == b[4 + k]) {
391*44704f69SBart Van Assche ++has_di;
392*44704f69SBart Van Assche break;
393*44704f69SBart Van Assche }
394*44704f69SBart Van Assche }
395*44704f69SBart Van Assche if (has_sn) {
396*44704f69SBart Van Assche res = sg_ll_inquiry(fd, false, true /* evpd */, VPD_UNIT_SERIAL_NUM,
397*44704f69SBart Van Assche b, sizeof(b), 1, verb);
398*44704f69SBart Van Assche if (res) {
399*44704f69SBart Van Assche if (verbose)
400*44704f69SBart Van Assche pr2serr("VPD_UNIT_SERIAL_NUM gave res=%d\n", res);
401*44704f69SBart Van Assche return 0;
402*44704f69SBart Van Assche }
403*44704f69SBart Van Assche if (VPD_UNIT_SERIAL_NUM != b[1]) {
404*44704f69SBart Van Assche if (verbose)
405*44704f69SBart Van Assche pr2serr("VPD_UNIT_SERIAL_NUM corrupted\n");
406*44704f69SBart Van Assche return 0;
407*44704f69SBart Van Assche }
408*44704f69SBart Van Assche n = sg_get_unaligned_be16(b + 2);
409*44704f69SBart Van Assche if (n > (int)(sizeof(b) - 4))
410*44704f69SBart Van Assche n = (sizeof(b) - 4);
411*44704f69SBart Van Assche printf(" Unit serial number: %.*s\n", n, (const char *)(b + 4));
412*44704f69SBart Van Assche }
413*44704f69SBart Van Assche if (has_di) {
414*44704f69SBart Van Assche res = sg_ll_inquiry(fd, false, true /* evpd */, VPD_DEVICE_ID, b,
415*44704f69SBart Van Assche sizeof(b), 1, verb);
416*44704f69SBart Van Assche if (res) {
417*44704f69SBart Van Assche if (verbose)
418*44704f69SBart Van Assche pr2serr("VPD_DEVICE_ID gave res=%d\n", res);
419*44704f69SBart Van Assche return 0;
420*44704f69SBart Van Assche }
421*44704f69SBart Van Assche if (VPD_DEVICE_ID != b[1]) {
422*44704f69SBart Van Assche if (verbose)
423*44704f69SBart Van Assche pr2serr("VPD_DEVICE_ID corrupted\n");
424*44704f69SBart Van Assche return 0;
425*44704f69SBart Van Assche }
426*44704f69SBart Van Assche n = sg_get_unaligned_be16(b + 2);
427*44704f69SBart Van Assche if (n > (int)(sizeof(b) - 4))
428*44704f69SBart Van Assche n = (sizeof(b) - 4);
429*44704f69SBart Van Assche n = strlen(get_lu_name(b, n + 4, a, sizeof(a)));
430*44704f69SBart Van Assche if (n > 0)
431*44704f69SBart Van Assche printf(" LU name: %.*s\n", n, a);
432*44704f69SBart Van Assche }
433*44704f69SBart Van Assche return 0;
434*44704f69SBart Van Assche }
435*44704f69SBart Van Assche
436*44704f69SBart Van Assche
437*44704f69SBart Van Assche int
main(int argc,char * argv[])438*44704f69SBart Van Assche main(int argc, char * argv[])
439*44704f69SBart Van Assche {
440*44704f69SBart Van Assche bool got_stdin = false;
441*44704f69SBart Van Assche int k, res, c, infd, progress, vb, n, resp_len, err;
442*44704f69SBart Van Assche int sg_fd = -1;
443*44704f69SBart Van Assche int param_lst_len = 0;
444*44704f69SBart Van Assche int ret = -1;
445*44704f69SBart Van Assche const char * device_name = NULL;
446*44704f69SBart Van Assche char ebuff[EBUFF_SZ];
447*44704f69SBart Van Assche char b[80];
448*44704f69SBart Van Assche uint8_t rsBuff[DEF_REQS_RESP_LEN];
449*44704f69SBart Van Assche uint8_t * wBuff = NULL;
450*44704f69SBart Van Assche uint8_t * free_wBuff = NULL;
451*44704f69SBart Van Assche struct opts_t opts;
452*44704f69SBart Van Assche struct opts_t * op;
453*44704f69SBart Van Assche struct stat a_stat;
454*44704f69SBart Van Assche uint8_t inq_resp[SAFE_STD_INQ_RESP_LEN];
455*44704f69SBart Van Assche
456*44704f69SBart Van Assche op = &opts;
457*44704f69SBart Van Assche memset(op, 0, sizeof(opts));
458*44704f69SBart Van Assche op->count = 1;
459*44704f69SBart Van Assche while (1) {
460*44704f69SBart Van Assche int option_index = 0;
461*44704f69SBart Van Assche
462*44704f69SBart Van Assche c = getopt_long(argc, argv, "ABc:CdDeFhi:IOp:Qt:T:vVwzZ",
463*44704f69SBart Van Assche long_options, &option_index);
464*44704f69SBart Van Assche if (c == -1)
465*44704f69SBart Van Assche break;
466*44704f69SBart Van Assche
467*44704f69SBart Van Assche switch (c) {
468*44704f69SBart Van Assche case 'A':
469*44704f69SBart Van Assche op->ause = true;
470*44704f69SBart Van Assche break;
471*44704f69SBart Van Assche case 'B':
472*44704f69SBart Van Assche op->block = true;
473*44704f69SBart Van Assche break;
474*44704f69SBart Van Assche case 'c':
475*44704f69SBart Van Assche op->count = sg_get_num(optarg);
476*44704f69SBart Van Assche if ((op->count < 1) || (op->count > 31)) {
477*44704f69SBart Van Assche pr2serr("bad argument to '--count', expect 1 to 31\n");
478*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
479*44704f69SBart Van Assche }
480*44704f69SBart Van Assche break;
481*44704f69SBart Van Assche case 'C':
482*44704f69SBart Van Assche op->crypto = true;
483*44704f69SBart Van Assche break;
484*44704f69SBart Van Assche case 'd':
485*44704f69SBart Van Assche op->desc = true;
486*44704f69SBart Van Assche break;
487*44704f69SBart Van Assche case 'D':
488*44704f69SBart Van Assche op->dry_run = true;
489*44704f69SBart Van Assche break;
490*44704f69SBart Van Assche case 'e':
491*44704f69SBart Van Assche op->early = true;
492*44704f69SBart Van Assche break;
493*44704f69SBart Van Assche case 'F':
494*44704f69SBart Van Assche op->fail = true;
495*44704f69SBart Van Assche break;
496*44704f69SBart Van Assche case 'h':
497*44704f69SBart Van Assche case '?':
498*44704f69SBart Van Assche usage();
499*44704f69SBart Van Assche return 0;
500*44704f69SBart Van Assche case 'i':
501*44704f69SBart Van Assche op->ipl = sg_get_num(optarg);
502*44704f69SBart Van Assche if ((op->ipl < 1) || (op->ipl > 65535)) {
503*44704f69SBart Van Assche pr2serr("bad argument to '--ipl', expect 1 to 65535\n");
504*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
505*44704f69SBart Van Assche }
506*44704f69SBart Van Assche break;
507*44704f69SBart Van Assche case 'I':
508*44704f69SBart Van Assche op->invert = true;
509*44704f69SBart Van Assche break;
510*44704f69SBart Van Assche case 'O':
511*44704f69SBart Van Assche op->overwrite = true;
512*44704f69SBart Van Assche break;
513*44704f69SBart Van Assche case 'p':
514*44704f69SBart Van Assche op->pattern_fn = optarg;
515*44704f69SBart Van Assche break;
516*44704f69SBart Van Assche case 'Q':
517*44704f69SBart Van Assche op->quick = true;
518*44704f69SBart Van Assche break;
519*44704f69SBart Van Assche case 't':
520*44704f69SBart Van Assche op->timeout = sg_get_num(optarg);
521*44704f69SBart Van Assche if (op->timeout < 0) {
522*44704f69SBart Van Assche pr2serr("bad argument to '--timeout=SECS', want 0 or more\n");
523*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
524*44704f69SBart Van Assche }
525*44704f69SBart Van Assche break;
526*44704f69SBart Van Assche case 'T':
527*44704f69SBart Van Assche op->test = sg_get_num(optarg);
528*44704f69SBart Van Assche if ((op->test < 0) || (op->test > 3)) {
529*44704f69SBart Van Assche pr2serr("bad argument to '--test', expect 0 to 3\n");
530*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
531*44704f69SBart Van Assche }
532*44704f69SBart Van Assche break;
533*44704f69SBart Van Assche case 'v':
534*44704f69SBart Van Assche op->verbose_given = true;
535*44704f69SBart Van Assche ++op->verbose;
536*44704f69SBart Van Assche break;
537*44704f69SBart Van Assche case 'V':
538*44704f69SBart Van Assche op->version_given = true;
539*44704f69SBart Van Assche break;
540*44704f69SBart Van Assche case 'w':
541*44704f69SBart Van Assche op->wait = true;
542*44704f69SBart Van Assche break;
543*44704f69SBart Van Assche case 'z':
544*44704f69SBart Van Assche ++op->zero;
545*44704f69SBart Van Assche break;
546*44704f69SBart Van Assche case 'Z':
547*44704f69SBart Van Assche op->znr = true;
548*44704f69SBart Van Assche break;
549*44704f69SBart Van Assche default:
550*44704f69SBart Van Assche pr2serr("unrecognised option code 0x%x ??\n", c);
551*44704f69SBart Van Assche usage();
552*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
553*44704f69SBart Van Assche }
554*44704f69SBart Van Assche }
555*44704f69SBart Van Assche if (optind < argc) {
556*44704f69SBart Van Assche if (NULL == device_name) {
557*44704f69SBart Van Assche device_name = argv[optind];
558*44704f69SBart Van Assche ++optind;
559*44704f69SBart Van Assche }
560*44704f69SBart Van Assche if (optind < argc) {
561*44704f69SBart Van Assche for (; optind < argc; ++optind)
562*44704f69SBart Van Assche pr2serr("Unexpected extra argument: %s\n", argv[optind]);
563*44704f69SBart Van Assche usage();
564*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
565*44704f69SBart Van Assche }
566*44704f69SBart Van Assche }
567*44704f69SBart Van Assche #ifdef DEBUG
568*44704f69SBart Van Assche pr2serr("In DEBUG mode, ");
569*44704f69SBart Van Assche if (op->verbose_given && op->version_given) {
570*44704f69SBart Van Assche pr2serr("but override: '-vV' given, zero verbose and continue\n");
571*44704f69SBart Van Assche op->verbose_given = false;
572*44704f69SBart Van Assche op->version_given = false;
573*44704f69SBart Van Assche op->verbose = 0;
574*44704f69SBart Van Assche } else if (! op->verbose_given) {
575*44704f69SBart Van Assche pr2serr("set '-vv'\n");
576*44704f69SBart Van Assche op->verbose = 2;
577*44704f69SBart Van Assche } else
578*44704f69SBart Van Assche pr2serr("keep verbose=%d\n", op->verbose);
579*44704f69SBart Van Assche #else
580*44704f69SBart Van Assche if (op->verbose_given && op->version_given)
581*44704f69SBart Van Assche pr2serr("Not in DEBUG mode, so '-vV' has no special action\n");
582*44704f69SBart Van Assche #endif
583*44704f69SBart Van Assche if (op->version_given) {
584*44704f69SBart Van Assche pr2serr(ME "version: %s\n", version_str);
585*44704f69SBart Van Assche return 0;
586*44704f69SBart Van Assche }
587*44704f69SBart Van Assche
588*44704f69SBart Van Assche if (NULL == device_name) {
589*44704f69SBart Van Assche pr2serr("Missing device name!\n\n");
590*44704f69SBart Van Assche usage();
591*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
592*44704f69SBart Van Assche }
593*44704f69SBart Van Assche vb = op->verbose;
594*44704f69SBart Van Assche n = (int)op->block + (int)op->crypto + (int)op->fail + (int)op->overwrite;
595*44704f69SBart Van Assche if (1 != n) {
596*44704f69SBart Van Assche pr2serr("one and only one of '--block', '--crypto', '--fail' or "
597*44704f69SBart Van Assche "'--overwrite' please\n");
598*44704f69SBart Van Assche return SG_LIB_CONTRADICT;
599*44704f69SBart Van Assche }
600*44704f69SBart Van Assche if (op->overwrite) {
601*44704f69SBart Van Assche if (op->zero) {
602*44704f69SBart Van Assche if (op->pattern_fn) {
603*44704f69SBart Van Assche pr2serr("confused: both '--pattern=PF' and '--zero' "
604*44704f69SBart Van Assche "options\n");
605*44704f69SBart Van Assche return SG_LIB_CONTRADICT;
606*44704f69SBart Van Assche }
607*44704f69SBart Van Assche op->ipl = 4;
608*44704f69SBart Van Assche } else {
609*44704f69SBart Van Assche if (NULL == op->pattern_fn) {
610*44704f69SBart Van Assche pr2serr("'--overwrite' requires '--pattern=PF' or '--zero' "
611*44704f69SBart Van Assche "option\n");
612*44704f69SBart Van Assche return SG_LIB_CONTRADICT;
613*44704f69SBart Van Assche }
614*44704f69SBart Van Assche got_stdin = (0 == strcmp(op->pattern_fn, "-"));
615*44704f69SBart Van Assche if (! got_stdin) {
616*44704f69SBart Van Assche memset(&a_stat, 0, sizeof(a_stat));
617*44704f69SBart Van Assche if (stat(op->pattern_fn, &a_stat) < 0) {
618*44704f69SBart Van Assche err = errno;
619*44704f69SBart Van Assche pr2serr("pattern file: unable to stat(%s): %s\n",
620*44704f69SBart Van Assche op->pattern_fn, safe_strerror(err));
621*44704f69SBart Van Assche ret = sg_convert_errno(err);
622*44704f69SBart Van Assche goto err_out;
623*44704f69SBart Van Assche }
624*44704f69SBart Van Assche if (op->ipl <= 0) {
625*44704f69SBart Van Assche op->ipl = (int)a_stat.st_size;
626*44704f69SBart Van Assche if (op->ipl > MAX_XFER_LEN) {
627*44704f69SBart Van Assche pr2serr("pattern file length exceeds 65535 bytes, "
628*44704f69SBart Van Assche "need '--ipl=LEN' option\n");
629*44704f69SBart Van Assche return SG_LIB_FILE_ERROR;
630*44704f69SBart Van Assche }
631*44704f69SBart Van Assche }
632*44704f69SBart Van Assche }
633*44704f69SBart Van Assche if (op->ipl < 1) {
634*44704f69SBart Van Assche pr2serr("'--overwrite' requires '--ipl=LEN' option if can't "
635*44704f69SBart Van Assche "get PF length\n");
636*44704f69SBart Van Assche return SG_LIB_CONTRADICT;
637*44704f69SBart Van Assche }
638*44704f69SBart Van Assche }
639*44704f69SBart Van Assche }
640*44704f69SBart Van Assche
641*44704f69SBart Van Assche sg_fd = sg_cmds_open_device(device_name, false /* rw */, vb);
642*44704f69SBart Van Assche if (sg_fd < 0) {
643*44704f69SBart Van Assche if (op->verbose)
644*44704f69SBart Van Assche pr2serr(ME "open error: %s: %s\n", device_name,
645*44704f69SBart Van Assche safe_strerror(-sg_fd));
646*44704f69SBart Van Assche ret = sg_convert_errno(-sg_fd);
647*44704f69SBart Van Assche goto err_out;
648*44704f69SBart Van Assche }
649*44704f69SBart Van Assche
650*44704f69SBart Van Assche ret = print_dev_id(sg_fd, inq_resp, sizeof(inq_resp), op->verbose);
651*44704f69SBart Van Assche if (ret)
652*44704f69SBart Van Assche goto err_out;
653*44704f69SBart Van Assche
654*44704f69SBart Van Assche if (op->overwrite) {
655*44704f69SBart Van Assche param_lst_len = op->ipl + 4;
656*44704f69SBart Van Assche wBuff = (uint8_t*)sg_memalign(op->ipl + 4, 0, &free_wBuff, false);
657*44704f69SBart Van Assche if (NULL == wBuff) {
658*44704f69SBart Van Assche pr2serr("unable to allocate %d bytes of memory with calloc()\n",
659*44704f69SBart Van Assche op->ipl + 4);
660*44704f69SBart Van Assche ret = sg_convert_errno(ENOMEM);
661*44704f69SBart Van Assche goto err_out;
662*44704f69SBart Van Assche }
663*44704f69SBart Van Assche if (op->zero) {
664*44704f69SBart Van Assche if (2 == op->zero) /* treat -zz as fill with 0xff bytes */
665*44704f69SBart Van Assche memset(wBuff + 4, 0xff, op->ipl);
666*44704f69SBart Van Assche else
667*44704f69SBart Van Assche memset(wBuff + 4, 0, op->ipl);
668*44704f69SBart Van Assche } else {
669*44704f69SBart Van Assche if (got_stdin) {
670*44704f69SBart Van Assche infd = STDIN_FILENO;
671*44704f69SBart Van Assche if (sg_set_binary_mode(STDIN_FILENO) < 0)
672*44704f69SBart Van Assche perror("sg_set_binary_mode");
673*44704f69SBart Van Assche } else {
674*44704f69SBart Van Assche if ((infd = open(op->pattern_fn, O_RDONLY)) < 0) {
675*44704f69SBart Van Assche err = errno;
676*44704f69SBart Van Assche snprintf(ebuff, EBUFF_SZ, ME "could not open %s for "
677*44704f69SBart Van Assche "reading", op->pattern_fn);
678*44704f69SBart Van Assche perror(ebuff);
679*44704f69SBart Van Assche ret = sg_convert_errno(err);
680*44704f69SBart Van Assche goto err_out;
681*44704f69SBart Van Assche } else if (sg_set_binary_mode(infd) < 0)
682*44704f69SBart Van Assche perror("sg_set_binary_mode");
683*44704f69SBart Van Assche }
684*44704f69SBart Van Assche res = read(infd, wBuff + 4, op->ipl);
685*44704f69SBart Van Assche if (res < 0) {
686*44704f69SBart Van Assche err = errno;
687*44704f69SBart Van Assche snprintf(ebuff, EBUFF_SZ, ME "couldn't read from %s",
688*44704f69SBart Van Assche op->pattern_fn);
689*44704f69SBart Van Assche perror(ebuff);
690*44704f69SBart Van Assche if (! got_stdin)
691*44704f69SBart Van Assche close(infd);
692*44704f69SBart Van Assche ret = sg_convert_errno(err);
693*44704f69SBart Van Assche goto err_out;
694*44704f69SBart Van Assche }
695*44704f69SBart Van Assche if (res < op->ipl) {
696*44704f69SBart Van Assche pr2serr("tried to read %d bytes from %s, got %d bytes\n",
697*44704f69SBart Van Assche op->ipl, op->pattern_fn, res);
698*44704f69SBart Van Assche pr2serr(" so pad with 0x0 bytes and continue\n");
699*44704f69SBart Van Assche }
700*44704f69SBart Van Assche if (! got_stdin)
701*44704f69SBart Van Assche close(infd);
702*44704f69SBart Van Assche }
703*44704f69SBart Van Assche wBuff[0] = op->count & 0x1f;
704*44704f69SBart Van Assche if (op->test)
705*44704f69SBart Van Assche wBuff[0] |= ((op->test & 0x3) << 5);
706*44704f69SBart Van Assche if (op->invert)
707*44704f69SBart Van Assche wBuff[0] |= 0x80;
708*44704f69SBart Van Assche sg_put_unaligned_be16((uint16_t)op->ipl, wBuff + 2);
709*44704f69SBart Van Assche }
710*44704f69SBart Van Assche
711*44704f69SBart Van Assche if ((! op->quick) && (! op->fail))
712*44704f69SBart Van Assche sg_warn_and_wait("SANITIZE", device_name, true);
713*44704f69SBart Van Assche
714*44704f69SBart Van Assche ret = do_sanitize(sg_fd, op, wBuff, param_lst_len);
715*44704f69SBart Van Assche if (ret) {
716*44704f69SBart Van Assche sg_get_category_sense_str(ret, sizeof(b), b, vb);
717*44704f69SBart Van Assche pr2serr("Sanitize failed: %s\n", b);
718*44704f69SBart Van Assche }
719*44704f69SBart Van Assche
720*44704f69SBart Van Assche if ((0 == ret) && (! op->early) && (! op->wait)) {
721*44704f69SBart Van Assche for (k = 0; ;++k) { /* unbounded, exits via break */
722*44704f69SBart Van Assche if (op->dry_run && (k > 0)) {
723*44704f69SBart Van Assche pr2serr("Due to --dry-run option, leave poll loop\n");
724*44704f69SBart Van Assche break;
725*44704f69SBart Van Assche }
726*44704f69SBart Van Assche sg_sleep_secs(POLL_DURATION_SECS);
727*44704f69SBart Van Assche memset(rsBuff, 0x0, sizeof(rsBuff));
728*44704f69SBart Van Assche res = sg_ll_request_sense(sg_fd, op->desc, rsBuff, sizeof(rsBuff),
729*44704f69SBart Van Assche 1, vb);
730*44704f69SBart Van Assche if (res) {
731*44704f69SBart Van Assche ret = res;
732*44704f69SBart Van Assche if (SG_LIB_CAT_INVALID_OP == res)
733*44704f69SBart Van Assche pr2serr("Request Sense command not supported\n");
734*44704f69SBart Van Assche else if (SG_LIB_CAT_ILLEGAL_REQ == res) {
735*44704f69SBart Van Assche pr2serr("bad field in Request Sense cdb\n");
736*44704f69SBart Van Assche if (op->desc) {
737*44704f69SBart Van Assche pr2serr("Descriptor type sense may not be supported, "
738*44704f69SBart Van Assche "try again with fixed type\n");
739*44704f69SBart Van Assche op->desc = false;
740*44704f69SBart Van Assche continue;
741*44704f69SBart Van Assche }
742*44704f69SBart Van Assche } else {
743*44704f69SBart Van Assche sg_get_category_sense_str(res, sizeof(b), b, vb);
744*44704f69SBart Van Assche pr2serr("Request Sense: %s\n", b);
745*44704f69SBart Van Assche if (0 == vb)
746*44704f69SBart Van Assche pr2serr(" try the '-v' option for more "
747*44704f69SBart Van Assche "information\n");
748*44704f69SBart Van Assche }
749*44704f69SBart Van Assche break;
750*44704f69SBart Van Assche }
751*44704f69SBart Van Assche /* "Additional sense length" same in descriptor and fixed */
752*44704f69SBart Van Assche resp_len = rsBuff[7] + 8;
753*44704f69SBart Van Assche if (vb > 2) {
754*44704f69SBart Van Assche pr2serr("Parameter data in hex\n");
755*44704f69SBart Van Assche hex2stderr(rsBuff, resp_len, -1);
756*44704f69SBart Van Assche }
757*44704f69SBart Van Assche progress = -1;
758*44704f69SBart Van Assche sg_get_sense_progress_fld(rsBuff, resp_len, &progress);
759*44704f69SBart Van Assche if (progress < 0) {
760*44704f69SBart Van Assche ret = res;
761*44704f69SBart Van Assche if (vb > 1)
762*44704f69SBart Van Assche pr2serr("No progress indication found, iteration %d\n",
763*44704f69SBart Van Assche k + 1);
764*44704f69SBart Van Assche if ((0 == k) && vb)
765*44704f69SBart Van Assche pr2serr("Sanitize seems to be successful and finished "
766*44704f69SBart Van Assche "quickly\n");
767*44704f69SBart Van Assche /* N.B. exits first time there isn't a progress indication */
768*44704f69SBart Van Assche break;
769*44704f69SBart Van Assche } else
770*44704f69SBart Van Assche printf("Progress indication: %d%% done\n",
771*44704f69SBart Van Assche (progress * 100) / 65536);
772*44704f69SBart Van Assche }
773*44704f69SBart Van Assche }
774*44704f69SBart Van Assche
775*44704f69SBart Van Assche err_out:
776*44704f69SBart Van Assche if (free_wBuff)
777*44704f69SBart Van Assche free(free_wBuff);
778*44704f69SBart Van Assche if (sg_fd >= 0) {
779*44704f69SBart Van Assche res = sg_cmds_close_device(sg_fd);
780*44704f69SBart Van Assche if (res < 0) {
781*44704f69SBart Van Assche pr2serr("close error: %s\n", safe_strerror(-res));
782*44704f69SBart Van Assche if (0 == ret)
783*44704f69SBart Van Assche ret = sg_convert_errno(-res);
784*44704f69SBart Van Assche }
785*44704f69SBart Van Assche }
786*44704f69SBart Van Assche if (0 == op->verbose) {
787*44704f69SBart Van Assche if (! sg_if_can2stderr("sg_sanitize failed: ", ret))
788*44704f69SBart Van Assche pr2serr("Some error occurred, try again with '-v' "
789*44704f69SBart Van Assche "or '-vv' for more information\n");
790*44704f69SBart Van Assche }
791*44704f69SBart Van Assche return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
792*44704f69SBart Van Assche }
793