1*44704f69SBart Van Assche /*
2*44704f69SBart Van Assche * sg_format : format a SCSI disk
3*44704f69SBart Van Assche * potentially with a different number of blocks and block size
4*44704f69SBart Van Assche *
5*44704f69SBart Van Assche * formerly called blk512-linux.c (v0.4)
6*44704f69SBart Van Assche *
7*44704f69SBart Van Assche * Copyright (C) 2003 Grant Grundler grundler at parisc-linux dot org
8*44704f69SBart Van Assche * Copyright (C) 2003 James Bottomley jejb at parisc-linux dot org
9*44704f69SBart Van Assche * Copyright (C) 2005-2022 Douglas Gilbert dgilbert at interlog dot com
10*44704f69SBart Van Assche *
11*44704f69SBart Van Assche * This program is free software; you can redistribute it and/or modify
12*44704f69SBart Van Assche * it under the terms of the GNU General Public License as published by
13*44704f69SBart Van Assche * the Free Software Foundation; either version 2, or (at your option)
14*44704f69SBart Van Assche * any later version.
15*44704f69SBart Van Assche *
16*44704f69SBart Van Assche * SPDX-License-Identifier: GPL-2.0-or-later
17*44704f69SBart Van Assche *
18*44704f69SBart Van Assche * See https://www.t10.org for relevant standards and drafts. The most recent
19*44704f69SBart Van Assche * draft is SBC-4 revision 2.
20*44704f69SBart Van Assche */
21*44704f69SBart Van Assche
22*44704f69SBart Van Assche #include <stdio.h>
23*44704f69SBart Van Assche #include <stdlib.h>
24*44704f69SBart Van Assche #include <stdarg.h>
25*44704f69SBart Van Assche #include <stdbool.h>
26*44704f69SBart Van Assche #include <string.h>
27*44704f69SBart Van Assche #include <errno.h>
28*44704f69SBart Van Assche #include <getopt.h>
29*44704f69SBart Van Assche #include <unistd.h>
30*44704f69SBart Van Assche #define __STDC_FORMAT_MACROS 1
31*44704f69SBart Van Assche #include <inttypes.h>
32*44704f69SBart Van Assche
33*44704f69SBart Van Assche #ifdef HAVE_CONFIG_H
34*44704f69SBart Van Assche #include "config.h"
35*44704f69SBart Van Assche #endif
36*44704f69SBart Van Assche #include "sg_lib.h"
37*44704f69SBart Van Assche #include "sg_cmds_basic.h"
38*44704f69SBart Van Assche #include "sg_cmds_extra.h"
39*44704f69SBart Van Assche #include "sg_unaligned.h"
40*44704f69SBart Van Assche #include "sg_pr2serr.h"
41*44704f69SBart Van Assche #include "sg_pt.h"
42*44704f69SBart Van Assche
43*44704f69SBart Van Assche static const char * version_str = "1.68 20220609";
44*44704f69SBart Van Assche
45*44704f69SBart Van Assche
46*44704f69SBart Van Assche #define RW_ERROR_RECOVERY_PAGE 1 /* can give alternate with --mode=MP */
47*44704f69SBart Van Assche
48*44704f69SBart Van Assche #define SHORT_TIMEOUT 20 /* 20 seconds unless --wait given */
49*44704f69SBart Van Assche #define FORMAT_TIMEOUT (20 * 3600) /* 20 hours ! */
50*44704f69SBart Van Assche #define FOUR_TBYTE (4LL * 1000 * 1000 * 1000 * 1000)
51*44704f69SBart Van Assche #define LONG_FORMAT_TIMEOUT (40 * 3600) /* 40 hours */
52*44704f69SBart Van Assche #define EIGHT_TBYTE (FOUR_TBYTE * 2)
53*44704f69SBart Van Assche #define VLONG_FORMAT_TIMEOUT (80 * 3600) /* 3 days, 8 hours */
54*44704f69SBart Van Assche
55*44704f69SBart Van Assche #define POLL_DURATION_SECS 60
56*44704f69SBart Van Assche #define POLL_DURATION_FFMT_SECS 10
57*44704f69SBart Van Assche #define DEF_POLL_TYPE_RS false /* false -> test unit ready;
58*44704f69SBart Van Assche true -> request sense */
59*44704f69SBart Van Assche #define MAX_BUFF_SZ 252
60*44704f69SBart Van Assche
61*44704f69SBart Van Assche /* FORMAT UNIT (SBC) and FORMAT MEDIUM (SSC) share the same opcode */
62*44704f69SBart Van Assche #define SG_FORMAT_MEDIUM_CMD 0x4
63*44704f69SBart Van Assche #define SG_FORMAT_MEDIUM_CMDLEN 6
64*44704f69SBart Van Assche
65*44704f69SBart Van Assche /* FORMAT WITH PRESET (new in sbc4r18) */
66*44704f69SBart Van Assche #define SG_FORMAT_WITH_PRESET_CMD 0x38
67*44704f69SBart Van Assche #define SG_FORMAT_WITH_PRESET_CMDLEN 10
68*44704f69SBart Van Assche
69*44704f69SBart Van Assche #define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */
70*44704f69SBart Van Assche
71*44704f69SBart Van Assche struct opts_t {
72*44704f69SBart Van Assche bool cmplst; /* -C value */
73*44704f69SBart Van Assche bool cmplst_given;
74*44704f69SBart Van Assche bool dry_run; /* -d */
75*44704f69SBart Van Assche bool early; /* -e */
76*44704f69SBart Van Assche bool fmtmaxlba; /* -b (only with F_WITH_PRESET) */
77*44704f69SBart Van Assche bool fwait; /* -w (negated form IMMED) */
78*44704f69SBart Van Assche bool ip_def; /* -I */
79*44704f69SBart Van Assche bool long_lba; /* -l */
80*44704f69SBart Van Assche bool mode6; /* -6 */
81*44704f69SBart Van Assche bool pinfo; /* -p, deprecated, prefer fmtpinfo */
82*44704f69SBart Van Assche bool poll_type; /* -x 0|1 */
83*44704f69SBart Van Assche bool poll_type_given;
84*44704f69SBart Van Assche bool preset; /* -E */
85*44704f69SBart Van Assche bool quick; /* -Q */
86*44704f69SBart Van Assche bool do_rcap16; /* -l */
87*44704f69SBart Van Assche bool resize; /* -r */
88*44704f69SBart Van Assche bool rto_req; /* -R, deprecated, prefer fmtpinfo */
89*44704f69SBart Van Assche bool verbose_given;
90*44704f69SBart Van Assche bool verify; /* -y */
91*44704f69SBart Van Assche bool version_given;
92*44704f69SBart Van Assche int dcrt; /* -D (can be given once or twice) */
93*44704f69SBart Van Assche int lblk_sz; /* -s value */
94*44704f69SBart Van Assche int ffmt; /* -t value; fast_format if > 0 */
95*44704f69SBart Van Assche int fmtpinfo;
96*44704f69SBart Van Assche int format; /* -F */
97*44704f69SBart Van Assche uint32_t p_id; /* set by argument of --preset=id */
98*44704f69SBart Van Assche int mode_page; /* -M value */
99*44704f69SBart Van Assche int pfu; /* -P value */
100*44704f69SBart Van Assche int pie; /* -q value */
101*44704f69SBart Van Assche int sec_init; /* -S */
102*44704f69SBart Van Assche int tape; /* -T <format>, def: -1 */
103*44704f69SBart Van Assche int timeout; /* -m SECS, def: depends on IMMED bit */
104*44704f69SBart Van Assche int verbose; /* -v */
105*44704f69SBart Van Assche int64_t blk_count; /* -c value */
106*44704f69SBart Van Assche int64_t total_byte_count; /* from READ CAPACITY command */
107*44704f69SBart Van Assche const char * device_name;
108*44704f69SBart Van Assche };
109*44704f69SBart Van Assche
110*44704f69SBart Van Assche
111*44704f69SBart Van Assche
112*44704f69SBart Van Assche static struct option long_options[] = {
113*44704f69SBart Van Assche {"count", required_argument, 0, 'c'},
114*44704f69SBart Van Assche {"cmplst", required_argument, 0, 'C'},
115*44704f69SBart Van Assche {"dcrt", no_argument, 0, 'D'},
116*44704f69SBart Van Assche {"dry-run", no_argument, 0, 'd'},
117*44704f69SBart Van Assche {"dry_run", no_argument, 0, 'd'},
118*44704f69SBart Van Assche {"early", no_argument, 0, 'e'},
119*44704f69SBart Van Assche {"ffmt", required_argument, 0, 't'},
120*44704f69SBart Van Assche {"fmtmaxlba", no_argument, 0, 'b'},
121*44704f69SBart Van Assche {"fmtpinfo", required_argument, 0, 'f'},
122*44704f69SBart Van Assche {"format", no_argument, 0, 'F'},
123*44704f69SBart Van Assche {"help", no_argument, 0, 'h'},
124*44704f69SBart Van Assche {"ip-def", no_argument, 0, 'I'},
125*44704f69SBart Van Assche {"ip_def", no_argument, 0, 'I'},
126*44704f69SBart Van Assche {"long", no_argument, 0, 'l'},
127*44704f69SBart Van Assche {"mode", required_argument, 0, 'M'},
128*44704f69SBart Van Assche {"pinfo", no_argument, 0, 'p'},
129*44704f69SBart Van Assche {"pfu", required_argument, 0, 'P'},
130*44704f69SBart Van Assche {"pie", required_argument, 0, 'q'},
131*44704f69SBart Van Assche {"poll", required_argument, 0, 'x'},
132*44704f69SBart Van Assche {"preset", required_argument, 0, 'E'},
133*44704f69SBart Van Assche {"quick", no_argument, 0, 'Q'},
134*44704f69SBart Van Assche {"resize", no_argument, 0, 'r'},
135*44704f69SBart Van Assche {"rto_req", no_argument, 0, 'R'},
136*44704f69SBart Van Assche {"security", no_argument, 0, 'S'},
137*44704f69SBart Van Assche {"six", no_argument, 0, '6'},
138*44704f69SBart Van Assche {"size", required_argument, 0, 's'},
139*44704f69SBart Van Assche {"tape", required_argument, 0, 'T'},
140*44704f69SBart Van Assche {"timeout", required_argument, 0, 'm'},
141*44704f69SBart Van Assche {"verbose", no_argument, 0, 'v'},
142*44704f69SBart Van Assche {"verify", no_argument, 0, 'y'},
143*44704f69SBart Van Assche {"version", no_argument, 0, 'V'},
144*44704f69SBart Van Assche {"wait", no_argument, 0, 'w'},
145*44704f69SBart Van Assche {0, 0, 0, 0},
146*44704f69SBart Van Assche };
147*44704f69SBart Van Assche
148*44704f69SBart Van Assche static const char * fu_s = "Format unit";
149*44704f69SBart Van Assche static const char * fm_s = "Format medium";
150*44704f69SBart Van Assche static const char * fwp_s = "Format with preset";
151*44704f69SBart Van Assche
152*44704f69SBart Van Assche
153*44704f69SBart Van Assche static void
usage()154*44704f69SBart Van Assche usage()
155*44704f69SBart Van Assche {
156*44704f69SBart Van Assche printf("Usage:\n"
157*44704f69SBart Van Assche " sg_format [--cmplst=0|1] [--count=COUNT] [--dcrt] "
158*44704f69SBart Van Assche "[--dry-run] [--early]\n"
159*44704f69SBart Van Assche " [--ffmt=FFMT] [--fmtmaxlba] [--fmtpinfo=FPI] "
160*44704f69SBart Van Assche "[--format] [--help]\n"
161*44704f69SBart Van Assche " [--ip-def] [--long] [--mode=MP] [--pfu=PFU] "
162*44704f69SBart Van Assche "[--pie=PIE]\n"
163*44704f69SBart Van Assche " [--pinfo] [--poll=PT] [--preset=ID] [--quick] "
164*44704f69SBart Van Assche "[--resize]\n"
165*44704f69SBart Van Assche " [--rto_req] [--security] [--six] [--size=LB_SZ] "
166*44704f69SBart Van Assche "[--tape=FM]\n"
167*44704f69SBart Van Assche " [--timeout=SECS] [--verbose] [--verify] "
168*44704f69SBart Van Assche "[--version] [--wait]\n"
169*44704f69SBart Van Assche " DEVICE\n"
170*44704f69SBart Van Assche " where:\n"
171*44704f69SBart Van Assche " --cmplst=0|1\n"
172*44704f69SBart Van Assche " -C 0|1 sets CMPLST bit in format cdb "
173*44704f69SBart Van Assche "(def: 1; if FFMT: 0)\n"
174*44704f69SBart Van Assche " --count=COUNT|-c COUNT number of blocks to report "
175*44704f69SBart Van Assche "after format or\n"
176*44704f69SBart Van Assche " resize. Format default is "
177*44704f69SBart Van Assche "same as current\n"
178*44704f69SBart Van Assche " --dcrt|-D disable certification (doesn't "
179*44704f69SBart Van Assche "verify media)\n"
180*44704f69SBart Van Assche " use twice to enable certification and "
181*44704f69SBart Van Assche "set FOV bit\n"
182*44704f69SBart Van Assche " --dry-run|-d bypass device modifying commands (i.e. "
183*44704f69SBart Van Assche "don't format)\n"
184*44704f69SBart Van Assche " --early|-e exit once format started (user can "
185*44704f69SBart Van Assche "monitor progress)\n"
186*44704f69SBart Van Assche " --ffmt=FFMT|-t FFMT fast format (def: 0 -> slow, "
187*44704f69SBart Van Assche "may visit every\n"
188*44704f69SBart Van Assche " block). 1 and 2 are fast formats; "
189*44704f69SBart Van Assche "1: after\n"
190*44704f69SBart Van Assche " format, unwritten data read "
191*44704f69SBart Van Assche "without error\n"
192*44704f69SBart Van Assche " --fmtpinfo=FPI|-f FPI FMTPINFO field value "
193*44704f69SBart Van Assche "(default: 0)\n"
194*44704f69SBart Van Assche " --format|-F do FORMAT UNIT (default: report current "
195*44704f69SBart Van Assche "count and size)\n"
196*44704f69SBart Van Assche " use thrice for FORMAT UNIT command "
197*44704f69SBart Van Assche "only\n"
198*44704f69SBart Van Assche " --fmtmaxlba|-b sets FMTMAXLBA field in FORMAT WITH "
199*44704f69SBart Van Assche "PRESET\n"
200*44704f69SBart Van Assche " --help|-h prints out this usage message\n"
201*44704f69SBart Van Assche " --ip-def|-I use default initialization pattern\n"
202*44704f69SBart Van Assche " --long|-l allow for 64 bit lbas (default: assume "
203*44704f69SBart Van Assche "32 bit lbas)\n"
204*44704f69SBart Van Assche " --mode=MP|-M MP mode page (def: 1 -> RW error "
205*44704f69SBart Van Assche "recovery mpage)\n"
206*44704f69SBart Van Assche " --pie=PIE|-q PIE Protection Information Exponent "
207*44704f69SBart Van Assche "(default: 0)\n"
208*44704f69SBart Van Assche " --pinfo|-p set upper bit of FMTPINFO field\n"
209*44704f69SBart Van Assche " (deprecated, use '--fmtpinfo=FPI' "
210*44704f69SBart Van Assche "instead)\n"
211*44704f69SBart Van Assche " --poll=PT|-x PT PT is poll type, 0 for test unit "
212*44704f69SBart Van Assche "ready\n"
213*44704f69SBart Van Assche " 1 for request sense (def: 0 (1 "
214*44704f69SBart Van Assche "for tape and\n"
215*44704f69SBart Van Assche " format with preset))\n");
216*44704f69SBart Van Assche printf(" --preset=ID|-E ID do FORMAT WITH PRESET command "
217*44704f69SBart Van Assche "with PRESET\n"
218*44704f69SBart Van Assche " IDENTIFIER field set to ID\n"
219*44704f69SBart Van Assche " --quick|-Q start format without pause for user "
220*44704f69SBart Van Assche "intervention\n"
221*44704f69SBart Van Assche " (i.e. no time to reconsider)\n"
222*44704f69SBart Van Assche " --resize|-r resize (rather than format) to COUNT "
223*44704f69SBart Van Assche "value\n"
224*44704f69SBart Van Assche " --rto_req|-R set lower bit of FMTPINFO field\n"
225*44704f69SBart Van Assche " (deprecated use '--fmtpinfo=FPI' "
226*44704f69SBart Van Assche "instead)\n"
227*44704f69SBart Van Assche " --security|-S set security initialization (SI) bit\n"
228*44704f69SBart Van Assche " --six|-6 use 6 byte MODE SENSE/SELECT to probe "
229*44704f69SBart Van Assche "disk\n"
230*44704f69SBart Van Assche " (def: use 10 byte MODE SENSE/SELECT)\n"
231*44704f69SBart Van Assche " --size=LB_SZ|-s LB_SZ bytes per logical block, "
232*44704f69SBart Van Assche "defaults to DEVICE's\n"
233*44704f69SBart Van Assche " current logical block size. Only "
234*44704f69SBart Van Assche "needed to\n"
235*44704f69SBart Van Assche " change current logical block "
236*44704f69SBart Van Assche "size\n"
237*44704f69SBart Van Assche " --tape=FM|-T FM request FORMAT MEDIUM with FORMAT "
238*44704f69SBart Van Assche "field set\n"
239*44704f69SBart Van Assche " to FM (def: 0 --> default format)\n"
240*44704f69SBart Van Assche " --timeout=SECS|-m SECS FORMAT UNIT/MEDIUM command "
241*44704f69SBart Van Assche "timeout in seconds\n"
242*44704f69SBart Van Assche " --verbose|-v increase verbosity\n"
243*44704f69SBart Van Assche " --verify|-y sets VERIFY bit in FORMAT MEDIUM (tape)\n"
244*44704f69SBart Van Assche " --version|-V print version details and exit\n"
245*44704f69SBart Van Assche " --wait|-w format commands wait until format "
246*44704f69SBart Van Assche "operations complete\n"
247*44704f69SBart Van Assche " (default: set IMMED=1 and poll with "
248*44704f69SBart Van Assche "Test Unit Ready)\n\n"
249*44704f69SBart Van Assche "\tExample: sg_format --format /dev/sdc\n\n"
250*44704f69SBart Van Assche "This utility formats a SCSI disk [FORMAT UNIT] or resizes "
251*44704f69SBart Van Assche "it. Alternatively\nif '--tape=FM' is given formats a tape "
252*44704f69SBart Van Assche "[FORMAT MEDIUM]. Another alternative\nis doing the FORMAT "
253*44704f69SBart Van Assche "WITH PRESET command when '--preset=ID' is given.\n\n");
254*44704f69SBart Van Assche printf("WARNING: This utility will destroy all the data on the "
255*44704f69SBart Van Assche "DEVICE when\n\t '--format', '--tape=FM' or '--preset=ID' "
256*44704f69SBart Van Assche "is given. Double check\n\t that you have specified the "
257*44704f69SBart Van Assche "correct DEVICE.\n");
258*44704f69SBart Van Assche }
259*44704f69SBart Van Assche
260*44704f69SBart Van Assche /* Invokes a SCSI FORMAT MEDIUM command (SSC). Return of 0 -> success,
261*44704f69SBart Van Assche * various SG_LIB_CAT_* positive values or -1 -> other errors */
262*44704f69SBart Van Assche static int
sg_ll_format_medium(int sg_fd,bool verify,bool immed,int format,void * paramp,int transfer_len,int timeout,bool noisy,int verbose)263*44704f69SBart Van Assche sg_ll_format_medium(int sg_fd, bool verify, bool immed, int format,
264*44704f69SBart Van Assche void * paramp, int transfer_len, int timeout, bool noisy,
265*44704f69SBart Van Assche int verbose)
266*44704f69SBart Van Assche {
267*44704f69SBart Van Assche int ret, res, sense_cat;
268*44704f69SBart Van Assche uint8_t fm_cdb[SG_FORMAT_MEDIUM_CMDLEN] =
269*44704f69SBart Van Assche {SG_FORMAT_MEDIUM_CMD, 0, 0, 0, 0, 0};
270*44704f69SBart Van Assche uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT;
271*44704f69SBart Van Assche struct sg_pt_base * ptvp;
272*44704f69SBart Van Assche
273*44704f69SBart Van Assche if (verify)
274*44704f69SBart Van Assche fm_cdb[1] |= 0x2;
275*44704f69SBart Van Assche if (immed)
276*44704f69SBart Van Assche fm_cdb[1] |= 0x1;
277*44704f69SBart Van Assche if (format)
278*44704f69SBart Van Assche fm_cdb[2] |= (0xf & format);
279*44704f69SBart Van Assche if (transfer_len > 0)
280*44704f69SBart Van Assche sg_put_unaligned_be16(transfer_len, fm_cdb + 3);
281*44704f69SBart Van Assche if (verbose) {
282*44704f69SBart Van Assche char b[128];
283*44704f69SBart Van Assche
284*44704f69SBart Van Assche pr2serr(" %s cdb: %s\n", fm_s,
285*44704f69SBart Van Assche sg_get_command_str(fm_cdb, SG_FORMAT_MEDIUM_CMDLEN,
286*44704f69SBart Van Assche false, sizeof(b), b));
287*44704f69SBart Van Assche }
288*44704f69SBart Van Assche
289*44704f69SBart Van Assche ptvp = construct_scsi_pt_obj();
290*44704f69SBart Van Assche if (NULL == ptvp) {
291*44704f69SBart Van Assche pr2serr("%s: out of memory\n", __func__);
292*44704f69SBart Van Assche return sg_convert_errno(ENOMEM);
293*44704f69SBart Van Assche }
294*44704f69SBart Van Assche set_scsi_pt_cdb(ptvp, fm_cdb, sizeof(fm_cdb));
295*44704f69SBart Van Assche set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
296*44704f69SBart Van Assche set_scsi_pt_data_out(ptvp, (uint8_t *)paramp, transfer_len);
297*44704f69SBart Van Assche res = do_scsi_pt(ptvp, sg_fd, timeout, verbose);
298*44704f69SBart Van Assche ret = sg_cmds_process_resp(ptvp, fm_s, res, noisy, verbose,
299*44704f69SBart Van Assche &sense_cat);
300*44704f69SBart Van Assche if (-1 == ret) {
301*44704f69SBart Van Assche if (get_scsi_pt_transport_err(ptvp))
302*44704f69SBart Van Assche ret = SG_LIB_TRANSPORT_ERROR;
303*44704f69SBart Van Assche else
304*44704f69SBart Van Assche ret = sg_convert_errno(get_scsi_pt_os_err(ptvp));
305*44704f69SBart Van Assche } else if (-2 == ret) {
306*44704f69SBart Van Assche switch (sense_cat) {
307*44704f69SBart Van Assche case SG_LIB_CAT_RECOVERED:
308*44704f69SBart Van Assche case SG_LIB_CAT_NO_SENSE:
309*44704f69SBart Van Assche ret = 0;
310*44704f69SBart Van Assche break;
311*44704f69SBart Van Assche default:
312*44704f69SBart Van Assche ret = sense_cat;
313*44704f69SBart Van Assche break;
314*44704f69SBart Van Assche }
315*44704f69SBart Van Assche } else {
316*44704f69SBart Van Assche ret = 0;
317*44704f69SBart Van Assche if (verbose)
318*44704f69SBart Van Assche pr2serr("%s command %s without error\n", fm_s,
319*44704f69SBart Van Assche (immed ? "launched" : "completed"));
320*44704f69SBart Van Assche }
321*44704f69SBart Van Assche destruct_scsi_pt_obj(ptvp);
322*44704f69SBart Van Assche return ret;
323*44704f69SBart Van Assche }
324*44704f69SBart Van Assche
325*44704f69SBart Van Assche /* Invokes a SCSI FORMAT WITH PRESET command (SBC). Return of 0 -> success,
326*44704f69SBart Van Assche * various SG_LIB_CAT_* positive values or -1 -> other errors */
327*44704f69SBart Van Assche static int
sg_ll_format_with_preset(int sg_fd,bool immed,bool fmtmaxlba,uint32_t preset_id,int timeout,bool noisy,int verbose)328*44704f69SBart Van Assche sg_ll_format_with_preset(int sg_fd, bool immed, bool fmtmaxlba,
329*44704f69SBart Van Assche uint32_t preset_id, int timeout, bool noisy,
330*44704f69SBart Van Assche int verbose)
331*44704f69SBart Van Assche {
332*44704f69SBart Van Assche int ret, res, sense_cat;
333*44704f69SBart Van Assche uint8_t fwp_cdb[SG_FORMAT_WITH_PRESET_CMDLEN] =
334*44704f69SBart Van Assche {SG_FORMAT_WITH_PRESET_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
335*44704f69SBart Van Assche uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT;
336*44704f69SBart Van Assche struct sg_pt_base * ptvp;
337*44704f69SBart Van Assche
338*44704f69SBart Van Assche if (immed)
339*44704f69SBart Van Assche fwp_cdb[1] |= 0x80;
340*44704f69SBart Van Assche if (fmtmaxlba)
341*44704f69SBart Van Assche fwp_cdb[1] |= 0x40;
342*44704f69SBart Van Assche if (preset_id > 0)
343*44704f69SBart Van Assche sg_put_unaligned_be32(preset_id, fwp_cdb + 2);
344*44704f69SBart Van Assche if (verbose) {
345*44704f69SBart Van Assche char b[128];
346*44704f69SBart Van Assche
347*44704f69SBart Van Assche pr2serr(" %s cdb: %s\n", fwp_s,
348*44704f69SBart Van Assche sg_get_command_str(fwp_cdb,
349*44704f69SBart Van Assche SG_FORMAT_WITH_PRESET_CMDLEN,
350*44704f69SBart Van Assche false, sizeof(b), b));
351*44704f69SBart Van Assche }
352*44704f69SBart Van Assche ptvp = construct_scsi_pt_obj();
353*44704f69SBart Van Assche if (NULL == ptvp) {
354*44704f69SBart Van Assche pr2serr("%s: out of memory\n", __func__);
355*44704f69SBart Van Assche return sg_convert_errno(ENOMEM);
356*44704f69SBart Van Assche }
357*44704f69SBart Van Assche set_scsi_pt_cdb(ptvp, fwp_cdb, sizeof(fwp_cdb));
358*44704f69SBart Van Assche set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
359*44704f69SBart Van Assche res = do_scsi_pt(ptvp, sg_fd, timeout, verbose);
360*44704f69SBart Van Assche ret = sg_cmds_process_resp(ptvp, fwp_s, res, noisy, verbose,
361*44704f69SBart Van Assche &sense_cat);
362*44704f69SBart Van Assche if (-1 == ret) {
363*44704f69SBart Van Assche if (get_scsi_pt_transport_err(ptvp))
364*44704f69SBart Van Assche ret = SG_LIB_TRANSPORT_ERROR;
365*44704f69SBart Van Assche else
366*44704f69SBart Van Assche ret = sg_convert_errno(get_scsi_pt_os_err(ptvp));
367*44704f69SBart Van Assche } else if (-2 == ret) {
368*44704f69SBart Van Assche switch (sense_cat) {
369*44704f69SBart Van Assche case SG_LIB_CAT_RECOVERED:
370*44704f69SBart Van Assche case SG_LIB_CAT_NO_SENSE:
371*44704f69SBart Van Assche ret = 0;
372*44704f69SBart Van Assche break;
373*44704f69SBart Van Assche default:
374*44704f69SBart Van Assche ret = sense_cat;
375*44704f69SBart Van Assche break;
376*44704f69SBart Van Assche }
377*44704f69SBart Van Assche } else {
378*44704f69SBart Van Assche ret = 0;
379*44704f69SBart Van Assche if (verbose)
380*44704f69SBart Van Assche pr2serr("%s command %s without error\n", fwp_s,
381*44704f69SBart Van Assche (immed ? "launched" : "completed"));
382*44704f69SBart Van Assche }
383*44704f69SBart Van Assche destruct_scsi_pt_obj(ptvp);
384*44704f69SBart Van Assche return ret;
385*44704f69SBart Van Assche }
386*44704f69SBart Van Assche
387*44704f69SBart Van Assche /* Return 0 on success, else see sg_ll_format_unit_v2() */
388*44704f69SBart Van Assche static int
scsi_format_unit(int fd,const struct opts_t * op)389*44704f69SBart Van Assche scsi_format_unit(int fd, const struct opts_t * op)
390*44704f69SBart Van Assche {
391*44704f69SBart Van Assche bool need_param_lst, longlist, ip_desc, first;
392*44704f69SBart Van Assche bool immed = ! op->fwait;
393*44704f69SBart Van Assche int res, progress, pr, rem, param_sz, off, resp_len, tmout;
394*44704f69SBart Van Assche int poll_wait_secs;
395*44704f69SBart Van Assche int vb = op->verbose;
396*44704f69SBart Van Assche const int SH_FORMAT_HEADER_SZ = 4;
397*44704f69SBart Van Assche const int LONG_FORMAT_HEADER_SZ = 8;
398*44704f69SBart Van Assche const int INIT_PATTERN_DESC_SZ = 4;
399*44704f69SBart Van Assche const int max_param_sz = LONG_FORMAT_HEADER_SZ + INIT_PATTERN_DESC_SZ;
400*44704f69SBart Van Assche uint8_t * param;
401*44704f69SBart Van Assche uint8_t * free_param = NULL;
402*44704f69SBart Van Assche char b[80];
403*44704f69SBart Van Assche
404*44704f69SBart Van Assche param = sg_memalign(max_param_sz, 0, &free_param, false);
405*44704f69SBart Van Assche if (NULL == param) {
406*44704f69SBart Van Assche pr2serr("%s: unable to obtain heap for parameter list\n",
407*44704f69SBart Van Assche __func__);
408*44704f69SBart Van Assche return sg_convert_errno(ENOMEM);
409*44704f69SBart Van Assche }
410*44704f69SBart Van Assche if (immed)
411*44704f69SBart Van Assche tmout = SHORT_TIMEOUT;
412*44704f69SBart Van Assche else {
413*44704f69SBart Van Assche if (op->total_byte_count > EIGHT_TBYTE)
414*44704f69SBart Van Assche tmout = VLONG_FORMAT_TIMEOUT;
415*44704f69SBart Van Assche else if (op->total_byte_count > FOUR_TBYTE)
416*44704f69SBart Van Assche tmout = LONG_FORMAT_TIMEOUT;
417*44704f69SBart Van Assche else
418*44704f69SBart Van Assche tmout = FORMAT_TIMEOUT;
419*44704f69SBart Van Assche }
420*44704f69SBart Van Assche if (op->timeout > tmout)
421*44704f69SBart Van Assche tmout = op->timeout;
422*44704f69SBart Van Assche longlist = (op->pie > 0); /* only set LONGLIST if PI_EXPONENT>0 */
423*44704f69SBart Van Assche ip_desc = (op->ip_def || op->sec_init);
424*44704f69SBart Van Assche off = longlist ? LONG_FORMAT_HEADER_SZ : SH_FORMAT_HEADER_SZ;
425*44704f69SBart Van Assche param[0] = op->pfu & 0x7; /* PROTECTION_FIELD_USAGE (bits 2-0) */
426*44704f69SBart Van Assche param[1] = (immed ? 0x2 : 0); /* FOV=0, [DPRY,DCRT,STPF,IP=0] */
427*44704f69SBart Van Assche if (1 == op->dcrt)
428*44704f69SBart Van Assche param[1] |= 0xa0; /* FOV=1, DCRT=1 */
429*44704f69SBart Van Assche else if (op->dcrt > 1)
430*44704f69SBart Van Assche param[1] |= 0x80; /* FOV=1, DCRT=0 */
431*44704f69SBart Van Assche if (ip_desc) {
432*44704f69SBart Van Assche param[1] |= 0x88; /* FOV=1, IP=1 */
433*44704f69SBart Van Assche if (op->sec_init)
434*44704f69SBart Van Assche param[off + 0] = 0x20; /* SI=1 in IP desc */
435*44704f69SBart Van Assche }
436*44704f69SBart Van Assche if (longlist)
437*44704f69SBart Van Assche param[3] = (op->pie & 0xf);/* PROTECTION_INTERVAL_EXPONENT */
438*44704f69SBart Van Assche /* with the long parameter list header, P_I_INFORMATION is always 0 */
439*44704f69SBart Van Assche
440*44704f69SBart Van Assche need_param_lst = (immed || op->cmplst || (op->dcrt > 0) || ip_desc ||
441*44704f69SBart Van Assche (op->pfu > 0) || (op->pie > 0));
442*44704f69SBart Van Assche param_sz = need_param_lst ?
443*44704f69SBart Van Assche (off + (ip_desc ? INIT_PATTERN_DESC_SZ : 0)) : 0;
444*44704f69SBart Van Assche
445*44704f69SBart Van Assche if (op->dry_run) {
446*44704f69SBart Van Assche res = 0;
447*44704f69SBart Van Assche pr2serr("Due to --dry-run option bypassing FORMAT UNIT "
448*44704f69SBart Van Assche "command\n");
449*44704f69SBart Van Assche if (vb) {
450*44704f69SBart Van Assche if (need_param_lst) {
451*44704f69SBart Van Assche pr2serr(" %s would have received parameter "
452*44704f69SBart Van Assche "list: ", fu_s);
453*44704f69SBart Van Assche hex2stderr(param, max_param_sz, -1);
454*44704f69SBart Van Assche } else
455*44704f69SBart Van Assche pr2serr(" %s would not have received a "
456*44704f69SBart Van Assche "parameter list\n", fu_s);
457*44704f69SBart Van Assche pr2serr(" %s cdb fields: fmtpinfo=0x%x, "
458*44704f69SBart Van Assche "longlist=%d, fmtdata=%d, cmplst=%d, "
459*44704f69SBart Van Assche "ffmt=%d [timeout=%d secs]\n", fu_s,
460*44704f69SBart Van Assche op->fmtpinfo, longlist, need_param_lst,
461*44704f69SBart Van Assche op->cmplst, op->ffmt, tmout);
462*44704f69SBart Van Assche }
463*44704f69SBart Van Assche } else
464*44704f69SBart Van Assche res = sg_ll_format_unit_v2(fd, op->fmtpinfo, longlist,
465*44704f69SBart Van Assche need_param_lst, op->cmplst, 0,
466*44704f69SBart Van Assche op->ffmt, tmout, param, param_sz,
467*44704f69SBart Van Assche true, vb);
468*44704f69SBart Van Assche if (free_param)
469*44704f69SBart Van Assche free(free_param);
470*44704f69SBart Van Assche
471*44704f69SBart Van Assche if (res) {
472*44704f69SBart Van Assche sg_get_category_sense_str(res, sizeof(b), b, vb);
473*44704f69SBart Van Assche pr2serr("%s command: %s\n", fu_s, b);
474*44704f69SBart Van Assche return res;
475*44704f69SBart Van Assche } else if (op->verbose)
476*44704f69SBart Van Assche pr2serr("%s command %s without error\n", fu_s,
477*44704f69SBart Van Assche (immed ? "launched" : "completed"));
478*44704f69SBart Van Assche if (! immed)
479*44704f69SBart Van Assche return 0;
480*44704f69SBart Van Assche
481*44704f69SBart Van Assche if (! op->dry_run)
482*44704f69SBart Van Assche printf("\n%s has started\n", fu_s);
483*44704f69SBart Van Assche
484*44704f69SBart Van Assche if (op->early) {
485*44704f69SBart Van Assche if (immed)
486*44704f69SBart Van Assche printf("%s continuing,\n request sense or "
487*44704f69SBart Van Assche "test unit ready can be used to monitor "
488*44704f69SBart Van Assche "progress\n", fu_s);
489*44704f69SBart Van Assche return 0;
490*44704f69SBart Van Assche }
491*44704f69SBart Van Assche
492*44704f69SBart Van Assche if (op->dry_run) {
493*44704f69SBart Van Assche printf("No point in polling for progress, so exit\n");
494*44704f69SBart Van Assche return 0;
495*44704f69SBart Van Assche }
496*44704f69SBart Van Assche poll_wait_secs = op->ffmt ? POLL_DURATION_FFMT_SECS :
497*44704f69SBart Van Assche POLL_DURATION_SECS;
498*44704f69SBart Van Assche if (! op->poll_type) {
499*44704f69SBart Van Assche for(first = true; ; first = false) {
500*44704f69SBart Van Assche sg_sleep_secs(poll_wait_secs);
501*44704f69SBart Van Assche progress = -1;
502*44704f69SBart Van Assche res = sg_ll_test_unit_ready_progress(fd, 0, &progress,
503*44704f69SBart Van Assche true, (vb > 1) ? (vb - 1) : 0);
504*44704f69SBart Van Assche if (progress >= 0) {
505*44704f69SBart Van Assche pr = (progress * 100) / 65536;
506*44704f69SBart Van Assche rem = ((progress * 100) % 65536) / 656;
507*44704f69SBart Van Assche printf("%s in progress, %d.%02d%% done\n",
508*44704f69SBart Van Assche fu_s, pr, rem);
509*44704f69SBart Van Assche } else {
510*44704f69SBart Van Assche if (first && op->verbose)
511*44704f69SBart Van Assche pr2serr("%s seems to be successful "
512*44704f69SBart Van Assche "and finished quickly\n",
513*44704f69SBart Van Assche fu_s);
514*44704f69SBart Van Assche break;
515*44704f69SBart Van Assche }
516*44704f69SBart Van Assche }
517*44704f69SBart Van Assche }
518*44704f69SBart Van Assche if (op->poll_type || (SG_LIB_CAT_NOT_READY == res)) {
519*44704f69SBart Van Assche uint8_t * reqSense;
520*44704f69SBart Van Assche uint8_t * free_reqSense = NULL;
521*44704f69SBart Van Assche
522*44704f69SBart Van Assche reqSense = sg_memalign(MAX_BUFF_SZ, 0, &free_reqSense, false);
523*44704f69SBart Van Assche if (NULL == reqSense) {
524*44704f69SBart Van Assche pr2serr("%s: unable to obtain heap for Request "
525*44704f69SBart Van Assche "Sense\n", __func__);
526*44704f69SBart Van Assche return sg_convert_errno(ENOMEM);
527*44704f69SBart Van Assche }
528*44704f69SBart Van Assche for(first = true; ; first = false) {
529*44704f69SBart Van Assche sg_sleep_secs(poll_wait_secs);
530*44704f69SBart Van Assche memset(reqSense, 0x0, MAX_BUFF_SZ);
531*44704f69SBart Van Assche res = sg_ll_request_sense(fd, false, reqSense,
532*44704f69SBart Van Assche MAX_BUFF_SZ, false,
533*44704f69SBart Van Assche (vb > 1) ? (vb - 1) : 0);
534*44704f69SBart Van Assche if (res) {
535*44704f69SBart Van Assche pr2serr("polling with Request Sense command "
536*44704f69SBart Van Assche "failed [res=%d]\n", res);
537*44704f69SBart Van Assche break;
538*44704f69SBart Van Assche }
539*44704f69SBart Van Assche resp_len = reqSense[7] + 8;
540*44704f69SBart Van Assche if (vb > 1) {
541*44704f69SBart Van Assche pr2serr("Parameter data in hex:\n");
542*44704f69SBart Van Assche hex2stderr(reqSense, resp_len, 1);
543*44704f69SBart Van Assche }
544*44704f69SBart Van Assche progress = -1;
545*44704f69SBart Van Assche sg_get_sense_progress_fld(reqSense, resp_len,
546*44704f69SBart Van Assche &progress);
547*44704f69SBart Van Assche if (progress >= 0) {
548*44704f69SBart Van Assche pr = (progress * 100) / 65536;
549*44704f69SBart Van Assche rem = ((progress * 100) % 65536) / 656;
550*44704f69SBart Van Assche printf("%s in progress, %d.%02d%% done\n",
551*44704f69SBart Van Assche fu_s, pr, rem);
552*44704f69SBart Van Assche } else {
553*44704f69SBart Van Assche if (first && op->verbose)
554*44704f69SBart Van Assche pr2serr("%s seems to be successful "
555*44704f69SBart Van Assche "and finished quickly\n",
556*44704f69SBart Van Assche fu_s);
557*44704f69SBart Van Assche break;
558*44704f69SBart Van Assche }
559*44704f69SBart Van Assche }
560*44704f69SBart Van Assche if (free_reqSense)
561*44704f69SBart Van Assche free(free_reqSense);
562*44704f69SBart Van Assche }
563*44704f69SBart Van Assche printf("FORMAT UNIT Complete\n");
564*44704f69SBart Van Assche return 0;
565*44704f69SBart Van Assche }
566*44704f69SBart Van Assche
567*44704f69SBart Van Assche /* Return 0 on success, else see sg_ll_format_medium() above */
568*44704f69SBart Van Assche static int
scsi_format_medium(int fd,const struct opts_t * op)569*44704f69SBart Van Assche scsi_format_medium(int fd, const struct opts_t * op)
570*44704f69SBart Van Assche {
571*44704f69SBart Van Assche bool first;
572*44704f69SBart Van Assche bool immed = ! op->fwait;
573*44704f69SBart Van Assche int res, progress, pr, rem, resp_len, tmout;
574*44704f69SBart Van Assche int vb = op->verbose;
575*44704f69SBart Van Assche char b[80];
576*44704f69SBart Van Assche
577*44704f69SBart Van Assche if (immed)
578*44704f69SBart Van Assche tmout = SHORT_TIMEOUT;
579*44704f69SBart Van Assche else {
580*44704f69SBart Van Assche if (op->total_byte_count > EIGHT_TBYTE)
581*44704f69SBart Van Assche tmout = VLONG_FORMAT_TIMEOUT;
582*44704f69SBart Van Assche else if (op->total_byte_count > FOUR_TBYTE)
583*44704f69SBart Van Assche tmout = LONG_FORMAT_TIMEOUT;
584*44704f69SBart Van Assche else
585*44704f69SBart Van Assche tmout = FORMAT_TIMEOUT;
586*44704f69SBart Van Assche }
587*44704f69SBart Van Assche if (op->timeout > tmout)
588*44704f69SBart Van Assche tmout = op->timeout;
589*44704f69SBart Van Assche if (op->dry_run) {
590*44704f69SBart Van Assche res = 0;
591*44704f69SBart Van Assche pr2serr("Due to --dry-run option bypassing %s command\n",
592*44704f69SBart Van Assche fm_s);
593*44704f69SBart Van Assche } else
594*44704f69SBart Van Assche res = sg_ll_format_medium(fd, op->verify, immed,
595*44704f69SBart Van Assche 0xf & op->tape, NULL, 0, tmout,
596*44704f69SBart Van Assche true, vb);
597*44704f69SBart Van Assche if (res) {
598*44704f69SBart Van Assche sg_get_category_sense_str(res, sizeof(b), b, vb);
599*44704f69SBart Van Assche pr2serr("%s command: %s\n", fm_s, b);
600*44704f69SBart Van Assche return res;
601*44704f69SBart Van Assche }
602*44704f69SBart Van Assche if (! immed)
603*44704f69SBart Van Assche return 0;
604*44704f69SBart Van Assche
605*44704f69SBart Van Assche if (! op->dry_run)
606*44704f69SBart Van Assche printf("\n%s has started\n", fm_s);
607*44704f69SBart Van Assche if (op->early) {
608*44704f69SBart Van Assche if (immed)
609*44704f69SBart Van Assche printf("%s continuing,\n request sense or "
610*44704f69SBart Van Assche "test unit ready can be used to monitor "
611*44704f69SBart Van Assche "progress\n", fm_s);
612*44704f69SBart Van Assche return 0;
613*44704f69SBart Van Assche }
614*44704f69SBart Van Assche
615*44704f69SBart Van Assche if (op->dry_run) {
616*44704f69SBart Van Assche printf("No point in polling for progress, so exit\n");
617*44704f69SBart Van Assche return 0;
618*44704f69SBart Van Assche }
619*44704f69SBart Van Assche if (! op->poll_type) {
620*44704f69SBart Van Assche for(first = true; ; first = false) {
621*44704f69SBart Van Assche sg_sleep_secs(POLL_DURATION_SECS);
622*44704f69SBart Van Assche progress = -1;
623*44704f69SBart Van Assche res = sg_ll_test_unit_ready_progress(fd, 0, &progress,
624*44704f69SBart Van Assche true, (vb > 1) ? (vb - 1) : 0);
625*44704f69SBart Van Assche if (progress >= 0) {
626*44704f69SBart Van Assche pr = (progress * 100) / 65536;
627*44704f69SBart Van Assche rem = ((progress * 100) % 65536) / 656;
628*44704f69SBart Van Assche printf("%s in progress, %d.%02d%% done\n",
629*44704f69SBart Van Assche fm_s, pr, rem);
630*44704f69SBart Van Assche } else {
631*44704f69SBart Van Assche if (first && op->verbose)
632*44704f69SBart Van Assche pr2serr("%s seems to be successful "
633*44704f69SBart Van Assche "and finished quickly\n",
634*44704f69SBart Van Assche fm_s);
635*44704f69SBart Van Assche break;
636*44704f69SBart Van Assche }
637*44704f69SBart Van Assche }
638*44704f69SBart Van Assche }
639*44704f69SBart Van Assche if (op->poll_type || (SG_LIB_CAT_NOT_READY == res)) {
640*44704f69SBart Van Assche uint8_t * reqSense;
641*44704f69SBart Van Assche uint8_t * free_reqSense = NULL;
642*44704f69SBart Van Assche
643*44704f69SBart Van Assche reqSense = sg_memalign(MAX_BUFF_SZ, 0, &free_reqSense, false);
644*44704f69SBart Van Assche if (NULL == reqSense) {
645*44704f69SBart Van Assche pr2serr("%s: unable to obtain heap for Request "
646*44704f69SBart Van Assche "Sense\n", __func__);
647*44704f69SBart Van Assche return sg_convert_errno(ENOMEM);
648*44704f69SBart Van Assche }
649*44704f69SBart Van Assche for(first = true; ; first = false) {
650*44704f69SBart Van Assche sg_sleep_secs(POLL_DURATION_SECS);
651*44704f69SBart Van Assche memset(reqSense, 0x0, MAX_BUFF_SZ);
652*44704f69SBart Van Assche res = sg_ll_request_sense(fd, false, reqSense,
653*44704f69SBart Van Assche MAX_BUFF_SZ, false,
654*44704f69SBart Van Assche (vb > 1) ? (vb - 1) : 0);
655*44704f69SBart Van Assche if (res) {
656*44704f69SBart Van Assche pr2serr("polling with Request Sense command "
657*44704f69SBart Van Assche "failed [res=%d]\n", res);
658*44704f69SBart Van Assche break;
659*44704f69SBart Van Assche }
660*44704f69SBart Van Assche resp_len = reqSense[7] + 8;
661*44704f69SBart Van Assche if (vb > 1) {
662*44704f69SBart Van Assche pr2serr("Parameter data in hex:\n");
663*44704f69SBart Van Assche hex2stderr(reqSense, resp_len, 1);
664*44704f69SBart Van Assche }
665*44704f69SBart Van Assche progress = -1;
666*44704f69SBart Van Assche sg_get_sense_progress_fld(reqSense, resp_len,
667*44704f69SBart Van Assche &progress);
668*44704f69SBart Van Assche if (progress >= 0) {
669*44704f69SBart Van Assche pr = (progress * 100) / 65536;
670*44704f69SBart Van Assche rem = ((progress * 100) % 65536) / 656;
671*44704f69SBart Van Assche printf("%s in progress, %d.%02d%% done\n",
672*44704f69SBart Van Assche fm_s, pr, rem);
673*44704f69SBart Van Assche } else {
674*44704f69SBart Van Assche if (first && op->verbose)
675*44704f69SBart Van Assche pr2serr("%s seems to be successful "
676*44704f69SBart Van Assche "and finished quickly\n",
677*44704f69SBart Van Assche fm_s);
678*44704f69SBart Van Assche break;
679*44704f69SBart Van Assche }
680*44704f69SBart Van Assche }
681*44704f69SBart Van Assche if (free_reqSense)
682*44704f69SBart Van Assche free(free_reqSense);
683*44704f69SBart Van Assche }
684*44704f69SBart Van Assche printf("FORMAT MEDIUM Complete\n");
685*44704f69SBart Van Assche return 0;
686*44704f69SBart Van Assche }
687*44704f69SBart Van Assche
688*44704f69SBart Van Assche /* Return 0 on success, else see sg_ll_format_medium() above */
689*44704f69SBart Van Assche static int
scsi_format_with_preset(int fd,const struct opts_t * op)690*44704f69SBart Van Assche scsi_format_with_preset(int fd, const struct opts_t * op)
691*44704f69SBart Van Assche {
692*44704f69SBart Van Assche bool first;
693*44704f69SBart Van Assche bool immed = ! op->fwait;
694*44704f69SBart Van Assche int res, progress, pr, rem, resp_len, tmout;
695*44704f69SBart Van Assche int vb = op->verbose;
696*44704f69SBart Van Assche char b[80];
697*44704f69SBart Van Assche
698*44704f69SBart Van Assche if (immed)
699*44704f69SBart Van Assche tmout = SHORT_TIMEOUT;
700*44704f69SBart Van Assche else {
701*44704f69SBart Van Assche if (op->total_byte_count > EIGHT_TBYTE)
702*44704f69SBart Van Assche tmout = VLONG_FORMAT_TIMEOUT;
703*44704f69SBart Van Assche else if (op->total_byte_count > FOUR_TBYTE)
704*44704f69SBart Van Assche tmout = LONG_FORMAT_TIMEOUT;
705*44704f69SBart Van Assche else
706*44704f69SBart Van Assche tmout = FORMAT_TIMEOUT;
707*44704f69SBart Van Assche }
708*44704f69SBart Van Assche if (op->timeout > tmout)
709*44704f69SBart Van Assche tmout = op->timeout;
710*44704f69SBart Van Assche if (op->dry_run) {
711*44704f69SBart Van Assche res = 0;
712*44704f69SBart Van Assche pr2serr("Due to --dry-run option bypassing FORMAT WITH "
713*44704f69SBart Van Assche "PRESET command\n");
714*44704f69SBart Van Assche } else
715*44704f69SBart Van Assche res = sg_ll_format_with_preset(fd, immed, op->fmtmaxlba,
716*44704f69SBart Van Assche op->p_id, tmout, true, vb);
717*44704f69SBart Van Assche if (res) {
718*44704f69SBart Van Assche sg_get_category_sense_str(res, sizeof(b), b, vb);
719*44704f69SBart Van Assche pr2serr("%s command: %s\n", fwp_s, b);
720*44704f69SBart Van Assche return res;
721*44704f69SBart Van Assche }
722*44704f69SBart Van Assche if (! immed)
723*44704f69SBart Van Assche return 0;
724*44704f69SBart Van Assche
725*44704f69SBart Van Assche if (! op->dry_run)
726*44704f69SBart Van Assche printf("\n%s has started\n", fwp_s);
727*44704f69SBart Van Assche if (op->early) {
728*44704f69SBart Van Assche if (immed)
729*44704f69SBart Van Assche printf("%s continuing,\n Request sense can "
730*44704f69SBart Van Assche "be used to monitor progress\n", fwp_s);
731*44704f69SBart Van Assche return 0;
732*44704f69SBart Van Assche }
733*44704f69SBart Van Assche
734*44704f69SBart Van Assche if (op->dry_run) {
735*44704f69SBart Van Assche printf("No point in polling for progress, so exit\n");
736*44704f69SBart Van Assche return 0;
737*44704f69SBart Van Assche }
738*44704f69SBart Van Assche if (! op->poll_type) {
739*44704f69SBart Van Assche for(first = true; ; first = false) {
740*44704f69SBart Van Assche sg_sleep_secs(POLL_DURATION_SECS);
741*44704f69SBart Van Assche progress = -1;
742*44704f69SBart Van Assche res = sg_ll_test_unit_ready_progress(fd, 0, &progress,
743*44704f69SBart Van Assche true, (vb > 1) ? (vb - 1) : 0);
744*44704f69SBart Van Assche if (progress >= 0) {
745*44704f69SBart Van Assche pr = (progress * 100) / 65536;
746*44704f69SBart Van Assche rem = ((progress * 100) % 65536) / 656;
747*44704f69SBart Van Assche printf("%s in progress, %d.%02d%% done\n",
748*44704f69SBart Van Assche fwp_s, pr, rem);
749*44704f69SBart Van Assche } else {
750*44704f69SBart Van Assche if (first && op->verbose)
751*44704f69SBart Van Assche pr2serr("%s seems to be successful "
752*44704f69SBart Van Assche "and finished quickly\n",
753*44704f69SBart Van Assche fwp_s);
754*44704f69SBart Van Assche break;
755*44704f69SBart Van Assche }
756*44704f69SBart Van Assche }
757*44704f69SBart Van Assche }
758*44704f69SBart Van Assche if (op->poll_type || (SG_LIB_CAT_NOT_READY == res)) {
759*44704f69SBart Van Assche uint8_t * reqSense;
760*44704f69SBart Van Assche uint8_t * free_reqSense = NULL;
761*44704f69SBart Van Assche
762*44704f69SBart Van Assche reqSense = sg_memalign(MAX_BUFF_SZ, 0, &free_reqSense, false);
763*44704f69SBart Van Assche if (NULL == reqSense) {
764*44704f69SBart Van Assche pr2serr("%s: unable to obtain heap for Request "
765*44704f69SBart Van Assche "Sense\n", __func__);
766*44704f69SBart Van Assche return sg_convert_errno(ENOMEM);
767*44704f69SBart Van Assche }
768*44704f69SBart Van Assche for(first = true; ; first = false) {
769*44704f69SBart Van Assche sg_sleep_secs(POLL_DURATION_SECS);
770*44704f69SBart Van Assche memset(reqSense, 0x0, MAX_BUFF_SZ);
771*44704f69SBart Van Assche res = sg_ll_request_sense(fd, false, reqSense,
772*44704f69SBart Van Assche MAX_BUFF_SZ, false,
773*44704f69SBart Van Assche (vb > 1) ? (vb - 1) : 0);
774*44704f69SBart Van Assche if (res) {
775*44704f69SBart Van Assche pr2serr("polling with Request Sense command "
776*44704f69SBart Van Assche "failed [res=%d]\n", res);
777*44704f69SBart Van Assche break;
778*44704f69SBart Van Assche }
779*44704f69SBart Van Assche resp_len = reqSense[7] + 8;
780*44704f69SBart Van Assche if (vb > 1) {
781*44704f69SBart Van Assche pr2serr("Parameter data in hex:\n");
782*44704f69SBart Van Assche hex2stderr(reqSense, resp_len, 1);
783*44704f69SBart Van Assche }
784*44704f69SBart Van Assche progress = -1;
785*44704f69SBart Van Assche sg_get_sense_progress_fld(reqSense, resp_len,
786*44704f69SBart Van Assche &progress);
787*44704f69SBart Van Assche if (progress >= 0) {
788*44704f69SBart Van Assche pr = (progress * 100) / 65536;
789*44704f69SBart Van Assche rem = ((progress * 100) % 65536) / 656;
790*44704f69SBart Van Assche printf("%s in progress, %d.%02d%% done\n",
791*44704f69SBart Van Assche fwp_s, pr, rem);
792*44704f69SBart Van Assche } else {
793*44704f69SBart Van Assche if (first && op->verbose)
794*44704f69SBart Van Assche pr2serr("%s seems to be successful "
795*44704f69SBart Van Assche "and finished quickly\n",
796*44704f69SBart Van Assche fwp_s);
797*44704f69SBart Van Assche break;
798*44704f69SBart Van Assche }
799*44704f69SBart Van Assche }
800*44704f69SBart Van Assche if (free_reqSense)
801*44704f69SBart Van Assche free(free_reqSense);
802*44704f69SBart Van Assche }
803*44704f69SBart Van Assche printf("FORMAT WITH PRESET Complete\n");
804*44704f69SBart Van Assche return 0;
805*44704f69SBart Van Assche }
806*44704f69SBart Van Assche
807*44704f69SBart Van Assche #define VPD_DEVICE_ID 0x83
808*44704f69SBart Van Assche #define VPD_ASSOC_LU 0
809*44704f69SBart Van Assche #define VPD_ASSOC_TPORT 1
810*44704f69SBart Van Assche #define TPROTO_ISCSI 5
811*44704f69SBart Van Assche
812*44704f69SBart Van Assche static char *
get_lu_name(const uint8_t * bp,int u_len,char * b,int b_len)813*44704f69SBart Van Assche get_lu_name(const uint8_t * bp, int u_len, char * b, int b_len)
814*44704f69SBart Van Assche {
815*44704f69SBart Van Assche int len, off, sns_dlen, dlen, k;
816*44704f69SBart Van Assche uint8_t u_sns[512];
817*44704f69SBart Van Assche char * cp;
818*44704f69SBart Van Assche
819*44704f69SBart Van Assche len = u_len - 4;
820*44704f69SBart Van Assche bp += 4;
821*44704f69SBart Van Assche off = -1;
822*44704f69SBart Van Assche if (0 == sg_vpd_dev_id_iter(bp, len, &off, VPD_ASSOC_LU,
823*44704f69SBart Van Assche 8 /* SCSI name string (sns) */,
824*44704f69SBart Van Assche 3 /* UTF-8 */)) {
825*44704f69SBart Van Assche sns_dlen = bp[off + 3];
826*44704f69SBart Van Assche memcpy(u_sns, bp + off + 4, sns_dlen);
827*44704f69SBart Van Assche /* now want to check if this is iSCSI */
828*44704f69SBart Van Assche off = -1;
829*44704f69SBart Van Assche if (0 == sg_vpd_dev_id_iter(bp, len, &off, VPD_ASSOC_TPORT,
830*44704f69SBart Van Assche 8 /* SCSI name string (sns) */,
831*44704f69SBart Van Assche 3 /* UTF-8 */)) {
832*44704f69SBart Van Assche if ((0x80 & bp[1]) &&
833*44704f69SBart Van Assche (TPROTO_ISCSI == (bp[0] >> 4))) {
834*44704f69SBart Van Assche snprintf(b, b_len, "%.*s", sns_dlen, u_sns);
835*44704f69SBart Van Assche return b;
836*44704f69SBart Van Assche }
837*44704f69SBart Van Assche }
838*44704f69SBart Van Assche } else
839*44704f69SBart Van Assche sns_dlen = 0;
840*44704f69SBart Van Assche if (0 == sg_vpd_dev_id_iter(bp, len, &off, VPD_ASSOC_LU,
841*44704f69SBart Van Assche 3 /* NAA */, 1 /* binary */)) {
842*44704f69SBart Van Assche dlen = bp[off + 3];
843*44704f69SBart Van Assche if (! ((8 == dlen) || (16 ==dlen)))
844*44704f69SBart Van Assche return b;
845*44704f69SBart Van Assche cp = b;
846*44704f69SBart Van Assche for (k = 0; ((k < dlen) && (b_len > 1)); ++k) {
847*44704f69SBart Van Assche snprintf(cp, b_len, "%02x", bp[off + 4 + k]);
848*44704f69SBart Van Assche cp += 2;
849*44704f69SBart Van Assche b_len -= 2;
850*44704f69SBart Van Assche }
851*44704f69SBart Van Assche } else if (0 == sg_vpd_dev_id_iter(bp, len, &off, VPD_ASSOC_LU,
852*44704f69SBart Van Assche 2 /* EUI */, 1 /* binary */)) {
853*44704f69SBart Van Assche dlen = bp[off + 3];
854*44704f69SBart Van Assche if (! ((8 == dlen) || (12 == dlen) || (16 ==dlen)))
855*44704f69SBart Van Assche return b;
856*44704f69SBart Van Assche cp = b;
857*44704f69SBart Van Assche for (k = 0; ((k < dlen) && (b_len > 1)); ++k) {
858*44704f69SBart Van Assche snprintf(cp, b_len, "%02x", bp[off + 4 + k]);
859*44704f69SBart Van Assche cp += 2;
860*44704f69SBart Van Assche b_len -= 2;
861*44704f69SBart Van Assche }
862*44704f69SBart Van Assche } else if (sns_dlen > 0)
863*44704f69SBart Van Assche snprintf(b, b_len, "%.*s", sns_dlen, u_sns);
864*44704f69SBart Van Assche return b;
865*44704f69SBart Van Assche }
866*44704f69SBart Van Assche
867*44704f69SBart Van Assche #define SAFE_STD_INQ_RESP_LEN 36
868*44704f69SBart Van Assche #define VPD_SUPPORTED_VPDS 0x0
869*44704f69SBart Van Assche #define VPD_UNIT_SERIAL_NUM 0x80
870*44704f69SBart Van Assche #define VPD_DEVICE_ID 0x83
871*44704f69SBart Van Assche #define MAX_VPD_RESP_LEN 256
872*44704f69SBart Van Assche
873*44704f69SBart Van Assche static int
print_dev_id(int fd,uint8_t * sinq_resp,int max_rlen,const struct opts_t * op)874*44704f69SBart Van Assche print_dev_id(int fd, uint8_t * sinq_resp, int max_rlen,
875*44704f69SBart Van Assche const struct opts_t * op)
876*44704f69SBart Van Assche {
877*44704f69SBart Van Assche int k, n, verb, pdt, has_sn, has_di;
878*44704f69SBart Van Assche int res = 0;
879*44704f69SBart Van Assche uint8_t * b;
880*44704f69SBart Van Assche uint8_t * free_b = NULL;
881*44704f69SBart Van Assche char a[MAX_VPD_RESP_LEN];
882*44704f69SBart Van Assche char pdt_name[64];
883*44704f69SBart Van Assche
884*44704f69SBart Van Assche verb = (op->verbose > 1) ? op->verbose - 1 : 0;
885*44704f69SBart Van Assche memset(sinq_resp, 0, max_rlen);
886*44704f69SBart Van Assche b = sg_memalign(MAX_VPD_RESP_LEN, 0, &free_b, false);
887*44704f69SBart Van Assche if (NULL == b) {
888*44704f69SBart Van Assche res = sg_convert_errno(ENOMEM);
889*44704f69SBart Van Assche goto out;
890*44704f69SBart Van Assche }
891*44704f69SBart Van Assche /* Standard INQUIRY */
892*44704f69SBart Van Assche res = sg_ll_inquiry(fd, false, false, 0, b, SAFE_STD_INQ_RESP_LEN,
893*44704f69SBart Van Assche true, verb);
894*44704f69SBart Van Assche if (res)
895*44704f69SBart Van Assche goto out;
896*44704f69SBart Van Assche n = b[4] + 5;
897*44704f69SBart Van Assche if (n > SAFE_STD_INQ_RESP_LEN)
898*44704f69SBart Van Assche n = SAFE_STD_INQ_RESP_LEN;
899*44704f69SBart Van Assche memcpy(sinq_resp, b, (n < max_rlen) ? n : max_rlen);
900*44704f69SBart Van Assche if (n == SAFE_STD_INQ_RESP_LEN) {
901*44704f69SBart Van Assche pdt = b[0] & PDT_MASK;
902*44704f69SBart Van Assche printf(" %.8s %.16s %.4s peripheral_type: %s [0x%x]\n",
903*44704f69SBart Van Assche (const char *)(b + 8), (const char *)(b + 16),
904*44704f69SBart Van Assche (const char *)(b + 32),
905*44704f69SBart Van Assche sg_get_pdt_str(pdt, sizeof(pdt_name), pdt_name), pdt);
906*44704f69SBart Van Assche if (op->verbose)
907*44704f69SBart Van Assche printf(" PROTECT=%d\n", !!(b[5] & 1));
908*44704f69SBart Van Assche if (b[5] & 1)
909*44704f69SBart Van Assche printf(" << supports protection information>>"
910*44704f69SBart Van Assche "\n");
911*44704f69SBart Van Assche } else {
912*44704f69SBart Van Assche pr2serr("Short INQUIRY response: %d bytes, expect at least "
913*44704f69SBart Van Assche "36\n", n);
914*44704f69SBart Van Assche res = SG_LIB_CAT_OTHER;
915*44704f69SBart Van Assche goto out;
916*44704f69SBart Van Assche }
917*44704f69SBart Van Assche res = sg_ll_inquiry(fd, false, true, VPD_SUPPORTED_VPDS, b,
918*44704f69SBart Van Assche SAFE_STD_INQ_RESP_LEN, true, verb);
919*44704f69SBart Van Assche if (res) {
920*44704f69SBart Van Assche if (op->verbose)
921*44704f69SBart Van Assche pr2serr("VPD_SUPPORTED_VPDS gave res=%d\n", res);
922*44704f69SBart Van Assche res = 0;
923*44704f69SBart Van Assche goto out;
924*44704f69SBart Van Assche }
925*44704f69SBart Van Assche if (VPD_SUPPORTED_VPDS != b[1]) {
926*44704f69SBart Van Assche if (op->verbose)
927*44704f69SBart Van Assche pr2serr("VPD_SUPPORTED_VPDS corrupted\n");
928*44704f69SBart Van Assche goto out;
929*44704f69SBart Van Assche }
930*44704f69SBart Van Assche n = sg_get_unaligned_be16(b + 2);
931*44704f69SBart Van Assche if (n > (SAFE_STD_INQ_RESP_LEN - 4))
932*44704f69SBart Van Assche n = (SAFE_STD_INQ_RESP_LEN - 4);
933*44704f69SBart Van Assche for (k = 0, has_sn = 0, has_di = 0; k < n; ++k) {
934*44704f69SBart Van Assche if (VPD_UNIT_SERIAL_NUM == b[4 + k])
935*44704f69SBart Van Assche ++has_sn;
936*44704f69SBart Van Assche else if (VPD_DEVICE_ID == b[4 + k]) {
937*44704f69SBart Van Assche ++has_di;
938*44704f69SBart Van Assche break;
939*44704f69SBart Van Assche }
940*44704f69SBart Van Assche }
941*44704f69SBart Van Assche if (has_sn) {
942*44704f69SBart Van Assche res = sg_ll_inquiry(fd, false, true /* evpd */,
943*44704f69SBart Van Assche VPD_UNIT_SERIAL_NUM, b, MAX_VPD_RESP_LEN,
944*44704f69SBart Van Assche true, verb);
945*44704f69SBart Van Assche if (res) {
946*44704f69SBart Van Assche if (op->verbose)
947*44704f69SBart Van Assche pr2serr("VPD_UNIT_SERIAL_NUM gave res=%d\n",
948*44704f69SBart Van Assche res);
949*44704f69SBart Van Assche res = 0;
950*44704f69SBart Van Assche goto out;
951*44704f69SBart Van Assche }
952*44704f69SBart Van Assche if (VPD_UNIT_SERIAL_NUM != b[1]) {
953*44704f69SBart Van Assche if (op->verbose)
954*44704f69SBart Van Assche pr2serr("VPD_UNIT_SERIAL_NUM corrupted\n");
955*44704f69SBart Van Assche goto out;
956*44704f69SBart Van Assche }
957*44704f69SBart Van Assche n = sg_get_unaligned_be16(b + 2);
958*44704f69SBart Van Assche if (n > (int)(MAX_VPD_RESP_LEN - 4))
959*44704f69SBart Van Assche n = (MAX_VPD_RESP_LEN - 4);
960*44704f69SBart Van Assche printf(" Unit serial number: %.*s\n", n,
961*44704f69SBart Van Assche (const char *)(b + 4));
962*44704f69SBart Van Assche }
963*44704f69SBart Van Assche if (has_di) {
964*44704f69SBart Van Assche res = sg_ll_inquiry(fd, false, true /* evpd */, VPD_DEVICE_ID,
965*44704f69SBart Van Assche b, MAX_VPD_RESP_LEN, true, verb);
966*44704f69SBart Van Assche if (res) {
967*44704f69SBart Van Assche if (op->verbose)
968*44704f69SBart Van Assche pr2serr("VPD_DEVICE_ID gave res=%d\n", res);
969*44704f69SBart Van Assche res = 0;
970*44704f69SBart Van Assche goto out;
971*44704f69SBart Van Assche }
972*44704f69SBart Van Assche if (VPD_DEVICE_ID != b[1]) {
973*44704f69SBart Van Assche if (op->verbose)
974*44704f69SBart Van Assche pr2serr("VPD_DEVICE_ID corrupted\n");
975*44704f69SBart Van Assche goto out;
976*44704f69SBart Van Assche }
977*44704f69SBart Van Assche n = sg_get_unaligned_be16(b + 2);
978*44704f69SBart Van Assche if (n > (int)(MAX_VPD_RESP_LEN - 4))
979*44704f69SBart Van Assche n = (MAX_VPD_RESP_LEN - 4);
980*44704f69SBart Van Assche n = strlen(get_lu_name(b, n + 4, a, sizeof(a)));
981*44704f69SBart Van Assche if (n > 0)
982*44704f69SBart Van Assche printf(" LU name: %.*s\n", n, a);
983*44704f69SBart Van Assche }
984*44704f69SBart Van Assche out:
985*44704f69SBart Van Assche if (free_b)
986*44704f69SBart Van Assche free(free_b);
987*44704f69SBart Van Assche return res;
988*44704f69SBart Van Assche }
989*44704f69SBart Van Assche
990*44704f69SBart Van Assche #define RCAP_REPLY_LEN 32
991*44704f69SBart Van Assche
992*44704f69SBart Van Assche /* Returns block size or -2 if do_16==0 and the number of blocks is too
993*44704f69SBart Van Assche * big, or returns -1 for other error. */
994*44704f69SBart Van Assche static int
print_read_cap(int fd,struct opts_t * op)995*44704f69SBart Van Assche print_read_cap(int fd, struct opts_t * op)
996*44704f69SBart Van Assche {
997*44704f69SBart Van Assche int res = 0;
998*44704f69SBart Van Assche uint8_t * resp_buff;
999*44704f69SBart Van Assche uint8_t * free_resp_buff = NULL;
1000*44704f69SBart Van Assche unsigned int last_blk_addr, block_size;
1001*44704f69SBart Van Assche uint64_t llast_blk_addr;
1002*44704f69SBart Van Assche int64_t ll;
1003*44704f69SBart Van Assche char b[80];
1004*44704f69SBart Van Assche
1005*44704f69SBart Van Assche resp_buff = sg_memalign(RCAP_REPLY_LEN, 0, &free_resp_buff, false);
1006*44704f69SBart Van Assche if (NULL == resp_buff) {
1007*44704f69SBart Van Assche pr2serr("%s: unable to obtain heap\n", __func__);
1008*44704f69SBart Van Assche res = -1;
1009*44704f69SBart Van Assche goto out;
1010*44704f69SBart Van Assche }
1011*44704f69SBart Van Assche if (op->do_rcap16) {
1012*44704f69SBart Van Assche res = sg_ll_readcap_16(fd, false /* pmi */, 0 /* llba */,
1013*44704f69SBart Van Assche resp_buff, RCAP_REPLY_LEN, true,
1014*44704f69SBart Van Assche op->verbose);
1015*44704f69SBart Van Assche if (0 == res) {
1016*44704f69SBart Van Assche llast_blk_addr = sg_get_unaligned_be64(resp_buff + 0);
1017*44704f69SBart Van Assche block_size = sg_get_unaligned_be32(resp_buff + 8);
1018*44704f69SBart Van Assche printf("Read Capacity (16) results:\n");
1019*44704f69SBart Van Assche printf(" Protection: prot_en=%d, p_type=%d, "
1020*44704f69SBart Van Assche "p_i_exponent=%d\n",
1021*44704f69SBart Van Assche !!(resp_buff[12] & 0x1),
1022*44704f69SBart Van Assche ((resp_buff[12] >> 1) & 0x7),
1023*44704f69SBart Van Assche ((resp_buff[13] >> 4) & 0xf));
1024*44704f69SBart Van Assche printf(" Logical block provisioning: lbpme=%d, "
1025*44704f69SBart Van Assche "lbprz=%d\n", !!(resp_buff[14] & 0x80),
1026*44704f69SBart Van Assche !!(resp_buff[14] & 0x40));
1027*44704f69SBart Van Assche printf(" Logical blocks per physical block "
1028*44704f69SBart Van Assche "exponent=%d\n", resp_buff[13] & 0xf);
1029*44704f69SBart Van Assche printf(" Lowest aligned logical block address=%d\n",
1030*44704f69SBart Van Assche 0x3fff & sg_get_unaligned_be16(resp_buff +
1031*44704f69SBart Van Assche 14));
1032*44704f69SBart Van Assche printf(" Number of logical blocks=%" PRIu64 "\n",
1033*44704f69SBart Van Assche llast_blk_addr + 1);
1034*44704f69SBart Van Assche printf(" Logical block size=%u bytes\n",
1035*44704f69SBart Van Assche block_size);
1036*44704f69SBart Van Assche ll = (int64_t)(llast_blk_addr + 1) * block_size;
1037*44704f69SBart Van Assche if (ll > op->total_byte_count)
1038*44704f69SBart Van Assche op->total_byte_count = ll;
1039*44704f69SBart Van Assche res = (int)block_size;
1040*44704f69SBart Van Assche goto out;
1041*44704f69SBart Van Assche }
1042*44704f69SBart Van Assche } else {
1043*44704f69SBart Van Assche res = sg_ll_readcap_10(fd, false /* pmi */, 0 /* lba */,
1044*44704f69SBart Van Assche resp_buff, 8, true, op->verbose);
1045*44704f69SBart Van Assche if (0 == res) {
1046*44704f69SBart Van Assche last_blk_addr = sg_get_unaligned_be32(resp_buff + 0);
1047*44704f69SBart Van Assche block_size = sg_get_unaligned_be32(resp_buff + 4);
1048*44704f69SBart Van Assche if (0xffffffff == last_blk_addr) {
1049*44704f69SBart Van Assche if (op->verbose)
1050*44704f69SBart Van Assche printf("Read Capacity (10) response "
1051*44704f69SBart Van Assche "indicates that Read Capacity "
1052*44704f69SBart Van Assche "(16) is required\n");
1053*44704f69SBart Van Assche res = -2;
1054*44704f69SBart Van Assche goto out;
1055*44704f69SBart Van Assche }
1056*44704f69SBart Van Assche printf("Read Capacity (10) results:\n");
1057*44704f69SBart Van Assche printf(" Number of logical blocks=%u\n",
1058*44704f69SBart Van Assche last_blk_addr + 1);
1059*44704f69SBart Van Assche printf(" Logical block size=%u bytes\n",
1060*44704f69SBart Van Assche block_size);
1061*44704f69SBart Van Assche ll = (int64_t)(last_blk_addr + 1) * block_size;
1062*44704f69SBart Van Assche if (ll > op->total_byte_count)
1063*44704f69SBart Van Assche op->total_byte_count = ll;
1064*44704f69SBart Van Assche res = (int)block_size;
1065*44704f69SBart Van Assche goto out;
1066*44704f69SBart Van Assche }
1067*44704f69SBart Van Assche }
1068*44704f69SBart Van Assche sg_get_category_sense_str(res, sizeof(b), b, op->verbose);
1069*44704f69SBart Van Assche pr2serr("READ CAPACITY (%d): %s\n", (op->do_rcap16 ? 16 : 10), b);
1070*44704f69SBart Van Assche res = -1;
1071*44704f69SBart Van Assche out:
1072*44704f69SBart Van Assche if (free_resp_buff)
1073*44704f69SBart Van Assche free(free_resp_buff);
1074*44704f69SBart Van Assche return res;
1075*44704f69SBart Van Assche }
1076*44704f69SBart Van Assche
1077*44704f69SBart Van Assche /* Use MODE SENSE(6 or 10) to fetch blocks descriptor(s), if any. Analyze
1078*44704f69SBart Van Assche * the first block descriptor and if required, start preparing for a
1079*44704f69SBart Van Assche * MODE SELECT(6 or 10). Returns 0 on success. */
1080*44704f69SBart Van Assche static int
fetch_block_desc(int fd,uint8_t * dbuff,int * calc_lenp,int * bd_lb_szp,struct opts_t * op)1081*44704f69SBart Van Assche fetch_block_desc(int fd, uint8_t * dbuff, int * calc_lenp, int * bd_lb_szp,
1082*44704f69SBart Van Assche struct opts_t * op)
1083*44704f69SBart Van Assche {
1084*44704f69SBart Van Assche bool first = true;
1085*44704f69SBart Van Assche bool prob;
1086*44704f69SBart Van Assche int bd_lbsz, bd_len, dev_specific_param, offset, res, rq_lb_sz;
1087*44704f69SBart Van Assche int rsp_len;
1088*44704f69SBart Van Assche int resid = 0;
1089*44704f69SBart Van Assche int vb = op->verbose;
1090*44704f69SBart Van Assche uint64_t ull;
1091*44704f69SBart Van Assche int64_t ll;
1092*44704f69SBart Van Assche char b[80];
1093*44704f69SBart Van Assche
1094*44704f69SBart Van Assche again_with_long_lba:
1095*44704f69SBart Van Assche memset(dbuff, 0, MAX_BUFF_SZ);
1096*44704f69SBart Van Assche if (op->mode6)
1097*44704f69SBart Van Assche res = sg_ll_mode_sense6(fd, false /* DBD */, 0 /* current */,
1098*44704f69SBart Van Assche op->mode_page, 0 /* subpage */, dbuff,
1099*44704f69SBart Van Assche MAX_BUFF_SZ, true, vb);
1100*44704f69SBart Van Assche else
1101*44704f69SBart Van Assche res = sg_ll_mode_sense10_v2(fd, op->long_lba, false /* DBD */,
1102*44704f69SBart Van Assche 0 /* current */, op->mode_page,
1103*44704f69SBart Van Assche 0 /* subpage */, dbuff,
1104*44704f69SBart Van Assche MAX_BUFF_SZ, 0, &resid, true,
1105*44704f69SBart Van Assche vb);
1106*44704f69SBart Van Assche if (res) {
1107*44704f69SBart Van Assche if (SG_LIB_CAT_ILLEGAL_REQ == res) {
1108*44704f69SBart Van Assche if (op->long_lba && (! op->mode6))
1109*44704f69SBart Van Assche pr2serr("bad field in MODE SENSE (%d) "
1110*44704f69SBart Van Assche "[longlba flag not supported?]\n",
1111*44704f69SBart Van Assche (op->mode6 ? 6 : 10));
1112*44704f69SBart Van Assche else
1113*44704f69SBart Van Assche pr2serr("bad field in MODE SENSE (%d) "
1114*44704f69SBart Van Assche "[mode_page %d not supported?]\n",
1115*44704f69SBart Van Assche (op->mode6 ? 6 : 10), op->mode_page);
1116*44704f69SBart Van Assche } else {
1117*44704f69SBart Van Assche sg_get_category_sense_str(res, sizeof(b), b, vb);
1118*44704f69SBart Van Assche pr2serr("MODE SENSE (%d) command: %s\n",
1119*44704f69SBart Van Assche (op->mode6 ? 6 : 10), b);
1120*44704f69SBart Van Assche }
1121*44704f69SBart Van Assche if (0 == vb)
1122*44704f69SBart Van Assche pr2serr(" try '-v' for more information\n");
1123*44704f69SBart Van Assche return res;
1124*44704f69SBart Van Assche }
1125*44704f69SBart Van Assche rsp_len = (resid > 0) ? (MAX_BUFF_SZ - resid) : MAX_BUFF_SZ;
1126*44704f69SBart Van Assche if (rsp_len < 0) {
1127*44704f69SBart Van Assche pr2serr("%s: resid=%d implies negative response "
1128*44704f69SBart Van Assche "length of %d\n", __func__, resid, rsp_len);
1129*44704f69SBart Van Assche return SG_LIB_WILD_RESID;
1130*44704f69SBart Van Assche }
1131*44704f69SBart Van Assche *calc_lenp = sg_msense_calc_length(dbuff, rsp_len, op->mode6, &bd_len);
1132*44704f69SBart Van Assche if (op->mode6) {
1133*44704f69SBart Van Assche if (rsp_len < 4) {
1134*44704f69SBart Van Assche pr2serr("%s: MS(6) response length too short (%d)\n",
1135*44704f69SBart Van Assche __func__, rsp_len);
1136*44704f69SBart Van Assche return SG_LIB_CAT_MALFORMED;
1137*44704f69SBart Van Assche }
1138*44704f69SBart Van Assche dev_specific_param = dbuff[2];
1139*44704f69SBart Van Assche op->long_lba = false;
1140*44704f69SBart Van Assche offset = 4;
1141*44704f69SBart Van Assche /* prepare for mode select */
1142*44704f69SBart Van Assche dbuff[0] = 0;
1143*44704f69SBart Van Assche dbuff[1] = 0;
1144*44704f69SBart Van Assche dbuff[2] = 0;
1145*44704f69SBart Van Assche } else { /* MODE SENSE(10) */
1146*44704f69SBart Van Assche if (rsp_len < 8) {
1147*44704f69SBart Van Assche pr2serr("%s: MS(10) response length too short (%d)\n",
1148*44704f69SBart Van Assche __func__, rsp_len);
1149*44704f69SBart Van Assche return SG_LIB_CAT_MALFORMED;
1150*44704f69SBart Van Assche }
1151*44704f69SBart Van Assche dev_specific_param = dbuff[3];
1152*44704f69SBart Van Assche op->long_lba = !! (dbuff[4] & 1);
1153*44704f69SBart Van Assche offset = 8;
1154*44704f69SBart Van Assche /* prepare for mode select */
1155*44704f69SBart Van Assche dbuff[0] = 0;
1156*44704f69SBart Van Assche dbuff[1] = 0;
1157*44704f69SBart Van Assche dbuff[2] = 0;
1158*44704f69SBart Van Assche dbuff[3] = 0;
1159*44704f69SBart Van Assche }
1160*44704f69SBart Van Assche if (rsp_len < *calc_lenp) {
1161*44704f69SBart Van Assche pr2serr("%s: MS response length truncated (%d < %d)\n",
1162*44704f69SBart Van Assche __func__, rsp_len, *calc_lenp);
1163*44704f69SBart Van Assche return SG_LIB_CAT_MALFORMED;
1164*44704f69SBart Van Assche }
1165*44704f69SBart Van Assche if ((offset + bd_len) < *calc_lenp)
1166*44704f69SBart Van Assche dbuff[offset + bd_len] &= 0x7f; /* clear PS bit in mpage */
1167*44704f69SBart Van Assche prob = false;
1168*44704f69SBart Van Assche bd_lbsz = 0;
1169*44704f69SBart Van Assche *bd_lb_szp = bd_lbsz;
1170*44704f69SBart Van Assche rq_lb_sz = op->lblk_sz;
1171*44704f69SBart Van Assche if (first) {
1172*44704f69SBart Van Assche first = false;
1173*44704f69SBart Van Assche printf("Mode Sense (block descriptor) data, prior to "
1174*44704f69SBart Van Assche "changes:\n");
1175*44704f69SBart Van Assche }
1176*44704f69SBart Van Assche if (dev_specific_param & 0x40)
1177*44704f69SBart Van Assche printf(" <<< Write Protect (WP) bit set >>>\n");
1178*44704f69SBart Van Assche if (bd_len > 0) {
1179*44704f69SBart Van Assche ull = op->long_lba ? sg_get_unaligned_be64(dbuff + offset) :
1180*44704f69SBart Van Assche sg_get_unaligned_be32(dbuff + offset);
1181*44704f69SBart Van Assche bd_lbsz = op->long_lba ?
1182*44704f69SBart Van Assche sg_get_unaligned_be32(dbuff + offset + 12) :
1183*44704f69SBart Van Assche sg_get_unaligned_be24(dbuff + offset + 5);
1184*44704f69SBart Van Assche *bd_lb_szp = bd_lbsz;
1185*44704f69SBart Van Assche if (! op->long_lba) {
1186*44704f69SBart Van Assche if (0xffffffff == ull) {
1187*44704f69SBart Van Assche if (vb)
1188*44704f69SBart Van Assche pr2serr("block count maxed out, set "
1189*44704f69SBart Van Assche "<<longlba>>\n");
1190*44704f69SBart Van Assche op->long_lba = true;
1191*44704f69SBart Van Assche op->mode6 = false;
1192*44704f69SBart Van Assche op->do_rcap16 = true;
1193*44704f69SBart Van Assche goto again_with_long_lba;
1194*44704f69SBart Van Assche } else if ((rq_lb_sz > 0) && (rq_lb_sz < bd_lbsz) &&
1195*44704f69SBart Van Assche (((ull * bd_lbsz) / rq_lb_sz) >=
1196*44704f69SBart Van Assche 0xffffffff)) {
1197*44704f69SBart Van Assche if (vb)
1198*44704f69SBart Van Assche pr2serr("number of blocks will max "
1199*44704f69SBart Van Assche "out, set <<longlba>>\n");
1200*44704f69SBart Van Assche op->long_lba = true;
1201*44704f69SBart Van Assche op->mode6 = false;
1202*44704f69SBart Van Assche op->do_rcap16 = true;
1203*44704f69SBart Van Assche goto again_with_long_lba;
1204*44704f69SBart Van Assche }
1205*44704f69SBart Van Assche }
1206*44704f69SBart Van Assche if (op->long_lba) {
1207*44704f69SBart Van Assche printf(" <<< longlba flag set (64 bit lba) >>>\n");
1208*44704f69SBart Van Assche if (bd_len != 16)
1209*44704f69SBart Van Assche prob = true;
1210*44704f69SBart Van Assche } else if (bd_len != 8)
1211*44704f69SBart Van Assche prob = true;
1212*44704f69SBart Van Assche printf(" Number of blocks=%" PRIu64 " [0x%" PRIx64 "]\n",
1213*44704f69SBart Van Assche ull, ull);
1214*44704f69SBart Van Assche printf(" Block size=%d [0x%x]\n", bd_lbsz, bd_lbsz);
1215*44704f69SBart Van Assche ll = (int64_t)ull * bd_lbsz;
1216*44704f69SBart Van Assche if (ll > op->total_byte_count)
1217*44704f69SBart Van Assche op->total_byte_count = ll;
1218*44704f69SBart Van Assche } else {
1219*44704f69SBart Van Assche printf(" No block descriptors present\n");
1220*44704f69SBart Van Assche prob = true;
1221*44704f69SBart Van Assche }
1222*44704f69SBart Van Assche if (op->resize || (op->format && ((op->blk_count != 0) ||
1223*44704f69SBart Van Assche ((rq_lb_sz > 0) && (rq_lb_sz != bd_lbsz))))) {
1224*44704f69SBart Van Assche /* want to run MODE SELECT, prepare now */
1225*44704f69SBart Van Assche
1226*44704f69SBart Van Assche if (prob) {
1227*44704f69SBart Van Assche pr2serr("Need to perform MODE SELECT (to change "
1228*44704f69SBart Van Assche "number or blocks or block length)\n");
1229*44704f69SBart Van Assche pr2serr("but (single) block descriptor not found "
1230*44704f69SBart Van Assche "in earlier MODE SENSE\n");
1231*44704f69SBart Van Assche return SG_LIB_CAT_MALFORMED;
1232*44704f69SBart Van Assche }
1233*44704f69SBart Van Assche if (op->blk_count != 0) { /* user supplied blk count */
1234*44704f69SBart Van Assche if (op->long_lba)
1235*44704f69SBart Van Assche sg_put_unaligned_be64(op->blk_count,
1236*44704f69SBart Van Assche dbuff + offset);
1237*44704f69SBart Van Assche else
1238*44704f69SBart Van Assche sg_put_unaligned_be32(op->blk_count,
1239*44704f69SBart Van Assche dbuff + offset);
1240*44704f69SBart Van Assche } else if ((rq_lb_sz > 0) && (rq_lb_sz != bd_lbsz))
1241*44704f69SBart Van Assche /* 0 implies max capacity with new LB size */
1242*44704f69SBart Van Assche memset(dbuff + offset, 0, op->long_lba ? 8 : 4);
1243*44704f69SBart Van Assche
1244*44704f69SBart Van Assche if ((rq_lb_sz > 0) && (rq_lb_sz != bd_lbsz)) {
1245*44704f69SBart Van Assche if (op->long_lba)
1246*44704f69SBart Van Assche sg_put_unaligned_be32((uint32_t)rq_lb_sz,
1247*44704f69SBart Van Assche dbuff + offset + 12);
1248*44704f69SBart Van Assche else
1249*44704f69SBart Van Assche sg_put_unaligned_be24((uint32_t)rq_lb_sz,
1250*44704f69SBart Van Assche dbuff + offset + 5);
1251*44704f69SBart Van Assche }
1252*44704f69SBart Van Assche }
1253*44704f69SBart Van Assche return 0;
1254*44704f69SBart Van Assche }
1255*44704f69SBart Van Assche
1256*44704f69SBart Van Assche static int
parse_cmd_line(struct opts_t * op,int argc,char ** argv)1257*44704f69SBart Van Assche parse_cmd_line(struct opts_t * op, int argc, char **argv)
1258*44704f69SBart Van Assche {
1259*44704f69SBart Van Assche int j;
1260*44704f69SBart Van Assche int64_t ll;
1261*44704f69SBart Van Assche
1262*44704f69SBart Van Assche op->cmplst = true; /* will be set false if FFMT > 0 */
1263*44704f69SBart Van Assche op->mode_page = RW_ERROR_RECOVERY_PAGE;
1264*44704f69SBart Van Assche op->poll_type = DEF_POLL_TYPE_RS;
1265*44704f69SBart Van Assche op->tape = -1;
1266*44704f69SBart Van Assche while (1) {
1267*44704f69SBart Van Assche int option_index = 0;
1268*44704f69SBart Van Assche int c;
1269*44704f69SBart Van Assche
1270*44704f69SBart Van Assche c = getopt_long(argc, argv,
1271*44704f69SBart Van Assche "bc:C:dDeE:f:FhIlm:M:pP:q:QrRs:St:T:vVwx:y6",
1272*44704f69SBart Van Assche long_options, &option_index);
1273*44704f69SBart Van Assche if (c == -1)
1274*44704f69SBart Van Assche break;
1275*44704f69SBart Van Assche
1276*44704f69SBart Van Assche switch (c) {
1277*44704f69SBart Van Assche case 'b':
1278*44704f69SBart Van Assche op->fmtmaxlba = true;
1279*44704f69SBart Van Assche break;
1280*44704f69SBart Van Assche case 'c':
1281*44704f69SBart Van Assche if (0 == strcmp("-1", optarg))
1282*44704f69SBart Van Assche op->blk_count = -1;
1283*44704f69SBart Van Assche else {
1284*44704f69SBart Van Assche op->blk_count = sg_get_llnum(optarg);
1285*44704f69SBart Van Assche if (-1 == op->blk_count) {
1286*44704f69SBart Van Assche pr2serr("bad argument to '--count'\n");
1287*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
1288*44704f69SBart Van Assche }
1289*44704f69SBart Van Assche }
1290*44704f69SBart Van Assche break;
1291*44704f69SBart Van Assche case 'C':
1292*44704f69SBart Van Assche j = sg_get_num(optarg);
1293*44704f69SBart Van Assche if ((j < 0) || (j > 1)) {
1294*44704f69SBart Van Assche pr2serr("bad argument to '--cmplst', want 0 "
1295*44704f69SBart Van Assche "or 1\n");
1296*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
1297*44704f69SBart Van Assche }
1298*44704f69SBart Van Assche op->cmplst_given = true;
1299*44704f69SBart Van Assche op->cmplst = !! j;
1300*44704f69SBart Van Assche break;
1301*44704f69SBart Van Assche case 'd':
1302*44704f69SBart Van Assche op->dry_run = true;
1303*44704f69SBart Van Assche break;
1304*44704f69SBart Van Assche case 'D':
1305*44704f69SBart Van Assche ++op->dcrt;
1306*44704f69SBart Van Assche break;
1307*44704f69SBart Van Assche case 'e':
1308*44704f69SBart Van Assche op->early = true;
1309*44704f69SBart Van Assche break;
1310*44704f69SBart Van Assche case 'E':
1311*44704f69SBart Van Assche ll = sg_get_llnum(optarg);
1312*44704f69SBart Van Assche if ((ll < 0) || (ll > UINT32_MAX)) {
1313*44704f69SBart Van Assche pr2serr("bad argument to '--preset', need 32 "
1314*44704f69SBart Van Assche "bit integer\n");
1315*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
1316*44704f69SBart Van Assche }
1317*44704f69SBart Van Assche op->p_id = (uint32_t)ll;
1318*44704f69SBart Van Assche op->preset = true;
1319*44704f69SBart Van Assche op->poll_type = 1; /* poll with REQUEST SENSE */
1320*44704f69SBart Van Assche break;
1321*44704f69SBart Van Assche case 'f':
1322*44704f69SBart Van Assche op->fmtpinfo = sg_get_num(optarg);
1323*44704f69SBart Van Assche if ((op->fmtpinfo < 0) || ( op->fmtpinfo > 3)) {
1324*44704f69SBart Van Assche pr2serr("bad argument to '--fmtpinfo', "
1325*44704f69SBart Van Assche "accepts 0 to 3 inclusive\n");
1326*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
1327*44704f69SBart Van Assche }
1328*44704f69SBart Van Assche break;
1329*44704f69SBart Van Assche case 'F':
1330*44704f69SBart Van Assche ++op->format;
1331*44704f69SBart Van Assche break;
1332*44704f69SBart Van Assche case 'h':
1333*44704f69SBart Van Assche usage();
1334*44704f69SBart Van Assche return SG_LIB_OK_FALSE;
1335*44704f69SBart Van Assche case 'I':
1336*44704f69SBart Van Assche op->ip_def = true;
1337*44704f69SBart Van Assche break;
1338*44704f69SBart Van Assche case 'l':
1339*44704f69SBart Van Assche op->long_lba = true;
1340*44704f69SBart Van Assche op->do_rcap16 = true;
1341*44704f69SBart Van Assche break;
1342*44704f69SBart Van Assche case 'm':
1343*44704f69SBart Van Assche op->timeout = sg_get_num(optarg);
1344*44704f69SBart Van Assche if (op->timeout < 0) {
1345*44704f69SBart Van Assche pr2serr("bad argument to '--timeout=', "
1346*44704f69SBart Van Assche "accepts 0 or more\n");
1347*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
1348*44704f69SBart Van Assche }
1349*44704f69SBart Van Assche break;
1350*44704f69SBart Van Assche case 'M':
1351*44704f69SBart Van Assche op->mode_page = sg_get_num(optarg);
1352*44704f69SBart Van Assche if ((op->mode_page < 0) || ( op->mode_page > 62)) {
1353*44704f69SBart Van Assche pr2serr("bad argument to '--mode', accepts "
1354*44704f69SBart Van Assche "0 to 62 inclusive\n");
1355*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
1356*44704f69SBart Van Assche }
1357*44704f69SBart Van Assche break;
1358*44704f69SBart Van Assche case 'p':
1359*44704f69SBart Van Assche op->pinfo = true;
1360*44704f69SBart Van Assche break;
1361*44704f69SBart Van Assche case 'P':
1362*44704f69SBart Van Assche op->pfu = sg_get_num(optarg);
1363*44704f69SBart Van Assche if ((op->pfu < 0) || ( op->pfu > 7)) {
1364*44704f69SBart Van Assche pr2serr("bad argument to '--pfu', accepts 0 "
1365*44704f69SBart Van Assche "to 7 inclusive\n");
1366*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
1367*44704f69SBart Van Assche }
1368*44704f69SBart Van Assche break;
1369*44704f69SBart Van Assche case 'q':
1370*44704f69SBart Van Assche op->pie = sg_get_num(optarg);
1371*44704f69SBart Van Assche if ((op->pie < 0) || (op->pie > 15)) {
1372*44704f69SBart Van Assche pr2serr("bad argument to '--pie', accepts 0 "
1373*44704f69SBart Van Assche "to 15 inclusive\n");
1374*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
1375*44704f69SBart Van Assche }
1376*44704f69SBart Van Assche break;
1377*44704f69SBart Van Assche case 'Q':
1378*44704f69SBart Van Assche op->quick = true;
1379*44704f69SBart Van Assche break;
1380*44704f69SBart Van Assche case 'r':
1381*44704f69SBart Van Assche op->resize = true;
1382*44704f69SBart Van Assche break;
1383*44704f69SBart Van Assche case 'R':
1384*44704f69SBart Van Assche op->rto_req = true;
1385*44704f69SBart Van Assche break;
1386*44704f69SBart Van Assche case 's':
1387*44704f69SBart Van Assche op->lblk_sz = sg_get_num(optarg);
1388*44704f69SBart Van Assche if (op->lblk_sz <= 0) {
1389*44704f69SBart Van Assche pr2serr("bad argument to '--size', want arg "
1390*44704f69SBart Van Assche "> 0\n");
1391*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
1392*44704f69SBart Van Assche }
1393*44704f69SBart Van Assche break;
1394*44704f69SBart Van Assche case 'S':
1395*44704f69SBart Van Assche op->sec_init = true;
1396*44704f69SBart Van Assche break;
1397*44704f69SBart Van Assche case 't':
1398*44704f69SBart Van Assche op->ffmt = sg_get_num(optarg);
1399*44704f69SBart Van Assche if ((op->ffmt < 0) || ( op->ffmt > 3)) {
1400*44704f69SBart Van Assche pr2serr("bad argument to '--ffmt', "
1401*44704f69SBart Van Assche "accepts 0 to 3 inclusive\n");
1402*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
1403*44704f69SBart Van Assche }
1404*44704f69SBart Van Assche break;
1405*44704f69SBart Van Assche case 'T':
1406*44704f69SBart Van Assche if (('-' == optarg[0]) && ('1' == optarg[1]) &&
1407*44704f69SBart Van Assche ('\0' == optarg[2])) {
1408*44704f69SBart Van Assche op->tape = -1;
1409*44704f69SBart Van Assche break;
1410*44704f69SBart Van Assche }
1411*44704f69SBart Van Assche op->tape = sg_get_num(optarg);
1412*44704f69SBart Van Assche if ((op->tape < 0) || ( op->tape > 15)) {
1413*44704f69SBart Van Assche pr2serr("bad argument to '--tape', accepts "
1414*44704f69SBart Van Assche "0 to 15 inclusive\n");
1415*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
1416*44704f69SBart Van Assche }
1417*44704f69SBart Van Assche break;
1418*44704f69SBart Van Assche case 'v':
1419*44704f69SBart Van Assche op->verbose_given = true;
1420*44704f69SBart Van Assche op->verbose++;
1421*44704f69SBart Van Assche break;
1422*44704f69SBart Van Assche case 'V':
1423*44704f69SBart Van Assche op->version_given = true;
1424*44704f69SBart Van Assche break;
1425*44704f69SBart Van Assche case 'w':
1426*44704f69SBart Van Assche op->fwait = true;
1427*44704f69SBart Van Assche break;
1428*44704f69SBart Van Assche case 'x': /* false: TUR; true: request sense */
1429*44704f69SBart Van Assche op->poll_type = !! sg_get_num(optarg);
1430*44704f69SBart Van Assche op->poll_type_given = true;
1431*44704f69SBart Van Assche break;
1432*44704f69SBart Van Assche case 'y':
1433*44704f69SBart Van Assche op->verify = true;
1434*44704f69SBart Van Assche break;
1435*44704f69SBart Van Assche case '6':
1436*44704f69SBart Van Assche op->mode6 = true;
1437*44704f69SBart Van Assche break;
1438*44704f69SBart Van Assche default:
1439*44704f69SBart Van Assche usage();
1440*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
1441*44704f69SBart Van Assche }
1442*44704f69SBart Van Assche }
1443*44704f69SBart Van Assche if (optind < argc) {
1444*44704f69SBart Van Assche if (NULL == op->device_name) {
1445*44704f69SBart Van Assche op->device_name = argv[optind];
1446*44704f69SBart Van Assche ++optind;
1447*44704f69SBart Van Assche }
1448*44704f69SBart Van Assche }
1449*44704f69SBart Van Assche if (optind < argc) {
1450*44704f69SBart Van Assche for (; optind < argc; ++optind)
1451*44704f69SBart Van Assche pr2serr("Unexpected extra argument: %s\n",
1452*44704f69SBart Van Assche argv[optind]);
1453*44704f69SBart Van Assche usage();
1454*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
1455*44704f69SBart Van Assche }
1456*44704f69SBart Van Assche #ifdef DEBUG
1457*44704f69SBart Van Assche pr2serr("In DEBUG mode, ");
1458*44704f69SBart Van Assche if (op->verbose_given && op->version_given) {
1459*44704f69SBart Van Assche pr2serr("but override: '-vV' given, zero verbose and "
1460*44704f69SBart Van Assche "continue\n");
1461*44704f69SBart Van Assche op->verbose_given = false;
1462*44704f69SBart Van Assche op->version_given = false;
1463*44704f69SBart Van Assche op->verbose = 0;
1464*44704f69SBart Van Assche } else if (! op->verbose_given) {
1465*44704f69SBart Van Assche pr2serr("set '-vv'\n");
1466*44704f69SBart Van Assche op->verbose = 2;
1467*44704f69SBart Van Assche } else
1468*44704f69SBart Van Assche pr2serr("keep verbose=%d\n", op->verbose);
1469*44704f69SBart Van Assche #else
1470*44704f69SBart Van Assche if (op->verbose_given && op->version_given)
1471*44704f69SBart Van Assche pr2serr("Not in DEBUG mode, so '-vV' has no special action\n");
1472*44704f69SBart Van Assche #endif
1473*44704f69SBart Van Assche if (op->version_given) {
1474*44704f69SBart Van Assche pr2serr("sg_format version: %s\n", version_str);
1475*44704f69SBart Van Assche return SG_LIB_OK_FALSE;
1476*44704f69SBart Van Assche }
1477*44704f69SBart Van Assche if (NULL == op->device_name) {
1478*44704f69SBart Van Assche pr2serr("no DEVICE name given\n\n");
1479*44704f69SBart Van Assche usage();
1480*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
1481*44704f69SBart Van Assche }
1482*44704f69SBart Van Assche if (((int)(op->format > 0) + (int)(op->tape >= 0) + (int)op->preset)
1483*44704f69SBart Van Assche > 1) {
1484*44704f69SBart Van Assche pr2serr("Can choose only one of: '--format', '--tape=' and "
1485*44704f69SBart Van Assche "'--preset='\n");
1486*44704f69SBart Van Assche return SG_LIB_CONTRADICT;
1487*44704f69SBart Van Assche }
1488*44704f69SBart Van Assche if (op->ip_def && op->sec_init) {
1489*44704f69SBart Van Assche pr2serr("'--ip_def' and '--security' contradict, choose "
1490*44704f69SBart Van Assche "one\n");
1491*44704f69SBart Van Assche return SG_LIB_CONTRADICT;
1492*44704f69SBart Van Assche }
1493*44704f69SBart Van Assche if (op->resize) {
1494*44704f69SBart Van Assche if (op->format) {
1495*44704f69SBart Van Assche pr2serr("both '--format' and '--resize' not "
1496*44704f69SBart Van Assche "permitted\n");
1497*44704f69SBart Van Assche usage();
1498*44704f69SBart Van Assche return SG_LIB_CONTRADICT;
1499*44704f69SBart Van Assche } else if (0 == op->blk_count) {
1500*44704f69SBart Van Assche pr2serr("'--resize' needs a '--count' (other than "
1501*44704f69SBart Van Assche "0)\n");
1502*44704f69SBart Van Assche usage();
1503*44704f69SBart Van Assche return SG_LIB_CONTRADICT;
1504*44704f69SBart Van Assche } else if (0 != op->lblk_sz) {
1505*44704f69SBart Van Assche pr2serr("'--resize' not compatible with '--size'\n");
1506*44704f69SBart Van Assche usage();
1507*44704f69SBart Van Assche return SG_LIB_CONTRADICT;
1508*44704f69SBart Van Assche }
1509*44704f69SBart Van Assche }
1510*44704f69SBart Van Assche if ((op->pinfo > 0) || (op->rto_req > 0) || (op->fmtpinfo > 0)) {
1511*44704f69SBart Van Assche if ((op->pinfo || op->rto_req) && op->fmtpinfo) {
1512*44704f69SBart Van Assche pr2serr("confusing with both '--pinfo' or "
1513*44704f69SBart Van Assche "'--rto_req' together with\n'--fmtpinfo', "
1514*44704f69SBart Van Assche "best use '--fmtpinfo' only\n");
1515*44704f69SBart Van Assche usage();
1516*44704f69SBart Van Assche return SG_LIB_CONTRADICT;
1517*44704f69SBart Van Assche }
1518*44704f69SBart Van Assche if (op->pinfo)
1519*44704f69SBart Van Assche op->fmtpinfo |= 2;
1520*44704f69SBart Van Assche if (op->rto_req)
1521*44704f69SBart Van Assche op->fmtpinfo |= 1;
1522*44704f69SBart Van Assche }
1523*44704f69SBart Van Assche if ((op->ffmt > 0) && (! op->cmplst_given))
1524*44704f69SBart Van Assche op->cmplst = false; /* SBC-4 silent; FFMT&&CMPLST unlikely */
1525*44704f69SBart Van Assche return 0;
1526*44704f69SBart Van Assche }
1527*44704f69SBart Van Assche
1528*44704f69SBart Van Assche
1529*44704f69SBart Van Assche int
main(int argc,char ** argv)1530*44704f69SBart Van Assche main(int argc, char **argv)
1531*44704f69SBart Van Assche {
1532*44704f69SBart Van Assche int bd_lb_sz, calc_len, pdt, res, rq_lb_sz, vb;
1533*44704f69SBart Van Assche int fd = -1;
1534*44704f69SBart Van Assche int ret = 0;
1535*44704f69SBart Van Assche const int dbuff_sz = MAX_BUFF_SZ;
1536*44704f69SBart Van Assche const int inq_resp_sz = SAFE_STD_INQ_RESP_LEN;
1537*44704f69SBart Van Assche struct opts_t * op;
1538*44704f69SBart Van Assche uint8_t * dbuff;
1539*44704f69SBart Van Assche uint8_t * free_dbuff = NULL;
1540*44704f69SBart Van Assche uint8_t * inq_resp;
1541*44704f69SBart Van Assche uint8_t * free_inq_resp = NULL;
1542*44704f69SBart Van Assche struct opts_t opts;
1543*44704f69SBart Van Assche char b[80];
1544*44704f69SBart Van Assche
1545*44704f69SBart Van Assche op = &opts;
1546*44704f69SBart Van Assche memset(op, 0, sizeof(opts));
1547*44704f69SBart Van Assche ret = parse_cmd_line(op, argc, argv);
1548*44704f69SBart Van Assche if (ret)
1549*44704f69SBart Van Assche return (SG_LIB_OK_FALSE == ret) ? 0 : ret;
1550*44704f69SBart Van Assche vb = op->verbose;
1551*44704f69SBart Van Assche
1552*44704f69SBart Van Assche dbuff = sg_memalign(dbuff_sz, 0, &free_dbuff, false);
1553*44704f69SBart Van Assche inq_resp = sg_memalign(inq_resp_sz, 0, &free_inq_resp, false);
1554*44704f69SBart Van Assche if ((NULL == dbuff) || (NULL == inq_resp)) {
1555*44704f69SBart Van Assche pr2serr("Unable to allocate heap\n");
1556*44704f69SBart Van Assche ret = sg_convert_errno(ENOMEM);
1557*44704f69SBart Van Assche goto out;
1558*44704f69SBart Van Assche }
1559*44704f69SBart Van Assche
1560*44704f69SBart Van Assche if ((fd = sg_cmds_open_device(op->device_name, false, vb)) < 0) {
1561*44704f69SBart Van Assche pr2serr("error opening device file: %s: %s\n",
1562*44704f69SBart Van Assche op->device_name, safe_strerror(-fd));
1563*44704f69SBart Van Assche ret = sg_convert_errno(-fd);
1564*44704f69SBart Van Assche goto out;
1565*44704f69SBart Van Assche }
1566*44704f69SBart Van Assche
1567*44704f69SBart Van Assche if (op->format > 2)
1568*44704f69SBart Van Assche goto format_only;
1569*44704f69SBart Van Assche
1570*44704f69SBart Van Assche ret = print_dev_id(fd, inq_resp, inq_resp_sz, op);
1571*44704f69SBart Van Assche if (ret) {
1572*44704f69SBart Van Assche if (op->dry_run) {
1573*44704f69SBart Van Assche pr2serr("INQUIRY failed, assume device is a disk\n");
1574*44704f69SBart Van Assche pdt = 0;
1575*44704f69SBart Van Assche } else
1576*44704f69SBart Van Assche goto out;
1577*44704f69SBart Van Assche } else
1578*44704f69SBart Van Assche pdt = PDT_MASK & inq_resp[0];
1579*44704f69SBart Van Assche if (op->format) {
1580*44704f69SBart Van Assche if ((PDT_DISK != pdt) && (PDT_OPTICAL != pdt) &&
1581*44704f69SBart Van Assche (PDT_RBC != pdt) && (PDT_ZBC != pdt)) {
1582*44704f69SBart Van Assche pr2serr("This format is only defined for disks "
1583*44704f69SBart Van Assche "(using SBC-2+, ZBC or RBC) and MO media\n");
1584*44704f69SBart Van Assche ret = SG_LIB_CAT_MALFORMED;
1585*44704f69SBart Van Assche goto out;
1586*44704f69SBart Van Assche }
1587*44704f69SBart Van Assche } else if (op->tape >= 0) {
1588*44704f69SBart Van Assche if (! ((PDT_TAPE == pdt) || (PDT_MCHANGER == pdt) ||
1589*44704f69SBart Van Assche (PDT_ADC == pdt))) {
1590*44704f69SBart Van Assche pr2serr("This format is only defined for tapes\n");
1591*44704f69SBart Van Assche ret = SG_LIB_CAT_MALFORMED;
1592*44704f69SBart Van Assche goto out;
1593*44704f69SBart Van Assche }
1594*44704f69SBart Van Assche goto format_med;
1595*44704f69SBart Van Assche } else if (op->preset)
1596*44704f69SBart Van Assche goto format_with_pre;
1597*44704f69SBart Van Assche
1598*44704f69SBart Van Assche ret = fetch_block_desc(fd, dbuff, &calc_len, &bd_lb_sz, op);
1599*44704f69SBart Van Assche if (ret) {
1600*44704f69SBart Van Assche if (op->dry_run) {
1601*44704f69SBart Van Assche /* pick some numbers ... */
1602*44704f69SBart Van Assche calc_len = 1024 * 1024 * 1024;
1603*44704f69SBart Van Assche bd_lb_sz = 512;
1604*44704f69SBart Van Assche } else
1605*44704f69SBart Van Assche goto out;
1606*44704f69SBart Van Assche }
1607*44704f69SBart Van Assche rq_lb_sz = op->lblk_sz;
1608*44704f69SBart Van Assche if (op->resize || (op->format && ((op->blk_count != 0) ||
1609*44704f69SBart Van Assche ((rq_lb_sz > 0) && (rq_lb_sz != bd_lb_sz))))) {
1610*44704f69SBart Van Assche /* want to run MODE SELECT */
1611*44704f69SBart Van Assche if (op->dry_run) {
1612*44704f69SBart Van Assche pr2serr("Due to --dry-run option bypass MODE "
1613*44704f69SBart Van Assche "SELECT(%d) command\n", (op->mode6 ? 6 : 10));
1614*44704f69SBart Van Assche res = 0;
1615*44704f69SBart Van Assche } else {
1616*44704f69SBart Van Assche bool sp = true; /* may not be able to save pages */
1617*44704f69SBart Van Assche
1618*44704f69SBart Van Assche again_sp_false:
1619*44704f69SBart Van Assche if (op->mode6)
1620*44704f69SBart Van Assche res = sg_ll_mode_select6(fd, true /* PF */,
1621*44704f69SBart Van Assche sp, dbuff, calc_len,
1622*44704f69SBart Van Assche true, vb);
1623*44704f69SBart Van Assche else
1624*44704f69SBart Van Assche res = sg_ll_mode_select10(fd, true /* PF */,
1625*44704f69SBart Van Assche sp, dbuff, calc_len,
1626*44704f69SBart Van Assche true, vb);
1627*44704f69SBart Van Assche if ((SG_LIB_CAT_ILLEGAL_REQ == res) && sp) {
1628*44704f69SBart Van Assche pr2serr("Try MODE SELECT again with SP=0 "
1629*44704f69SBart Van Assche "this time\n");
1630*44704f69SBart Van Assche sp = false;
1631*44704f69SBart Van Assche goto again_sp_false;
1632*44704f69SBart Van Assche }
1633*44704f69SBart Van Assche }
1634*44704f69SBart Van Assche ret = res;
1635*44704f69SBart Van Assche if (res) {
1636*44704f69SBart Van Assche sg_get_category_sense_str(res, sizeof(b), b, vb);
1637*44704f69SBart Van Assche pr2serr("MODE SELECT command: %s\n", b);
1638*44704f69SBart Van Assche if (0 == vb)
1639*44704f69SBart Van Assche pr2serr(" try '-v' for more information\n");
1640*44704f69SBart Van Assche goto out;
1641*44704f69SBart Van Assche }
1642*44704f69SBart Van Assche }
1643*44704f69SBart Van Assche if (op->resize) {
1644*44704f69SBart Van Assche printf("Resize operation seems to have been successful\n");
1645*44704f69SBart Van Assche goto out;
1646*44704f69SBart Van Assche } else if (! op->format) {
1647*44704f69SBart Van Assche res = print_read_cap(fd, op);
1648*44704f69SBart Van Assche if (-2 == res) {
1649*44704f69SBart Van Assche op->do_rcap16 = true;
1650*44704f69SBart Van Assche res = print_read_cap(fd, op);
1651*44704f69SBart Van Assche }
1652*44704f69SBart Van Assche if (res < 0)
1653*44704f69SBart Van Assche ret = -1;
1654*44704f69SBart Van Assche if ((res > 0) && (bd_lb_sz > 0) &&
1655*44704f69SBart Van Assche (res != (int)bd_lb_sz)) {
1656*44704f69SBart Van Assche printf(" Warning: mode sense and read capacity "
1657*44704f69SBart Van Assche "report different block sizes [%d,%d]\n",
1658*44704f69SBart Van Assche bd_lb_sz, res);
1659*44704f69SBart Van Assche printf(" Probably needs format\n");
1660*44704f69SBart Van Assche }
1661*44704f69SBart Van Assche if ((PDT_TAPE == pdt) || (PDT_MCHANGER == pdt) ||
1662*44704f69SBart Van Assche (PDT_ADC == pdt))
1663*44704f69SBart Van Assche printf("No changes made. To format use '--tape='.\n");
1664*44704f69SBart Van Assche else
1665*44704f69SBart Van Assche printf("No changes made. To format use '--format'. "
1666*44704f69SBart Van Assche "To resize use '--resize'\n");
1667*44704f69SBart Van Assche goto out;
1668*44704f69SBart Van Assche }
1669*44704f69SBart Van Assche
1670*44704f69SBart Van Assche if (op->format) {
1671*44704f69SBart Van Assche format_only:
1672*44704f69SBart Van Assche if (! op->quick)
1673*44704f69SBart Van Assche sg_warn_and_wait("FORMAT UNIT", op->device_name, true);
1674*44704f69SBart Van Assche res = scsi_format_unit(fd, op);
1675*44704f69SBart Van Assche ret = res;
1676*44704f69SBart Van Assche if (res) {
1677*44704f69SBart Van Assche pr2serr("FORMAT UNIT failed\n");
1678*44704f69SBart Van Assche if (0 == vb)
1679*44704f69SBart Van Assche pr2serr(" try '-v' for more "
1680*44704f69SBart Van Assche "information\n");
1681*44704f69SBart Van Assche }
1682*44704f69SBart Van Assche }
1683*44704f69SBart Van Assche goto out;
1684*44704f69SBart Van Assche
1685*44704f69SBart Van Assche format_med:
1686*44704f69SBart Van Assche if (! op->poll_type_given) /* SSC-5 specifies REQUEST SENSE polling */
1687*44704f69SBart Van Assche op->poll_type = true;
1688*44704f69SBart Van Assche if (! op->quick)
1689*44704f69SBart Van Assche sg_warn_and_wait("FORMAT MEDIUM", op->device_name, true);
1690*44704f69SBart Van Assche res = scsi_format_medium(fd, op);
1691*44704f69SBart Van Assche ret = res;
1692*44704f69SBart Van Assche if (res) {
1693*44704f69SBart Van Assche pr2serr("FORMAT MEDIUM failed\n");
1694*44704f69SBart Van Assche if (0 == vb)
1695*44704f69SBart Van Assche pr2serr(" try '-v' for more information\n");
1696*44704f69SBart Van Assche }
1697*44704f69SBart Van Assche goto out;
1698*44704f69SBart Van Assche
1699*44704f69SBart Van Assche format_with_pre:
1700*44704f69SBart Van Assche if (! op->quick)
1701*44704f69SBart Van Assche sg_warn_and_wait("FORMAT WITH PRESET", op->device_name, true);
1702*44704f69SBart Van Assche res = scsi_format_with_preset(fd, op);
1703*44704f69SBart Van Assche ret = res;
1704*44704f69SBart Van Assche if (res) {
1705*44704f69SBart Van Assche pr2serr("FORMAT WITH PRESET failed\n");
1706*44704f69SBart Van Assche if (0 == vb)
1707*44704f69SBart Van Assche pr2serr(" try '-v' for more information\n");
1708*44704f69SBart Van Assche }
1709*44704f69SBart Van Assche
1710*44704f69SBart Van Assche out:
1711*44704f69SBart Van Assche if (free_dbuff)
1712*44704f69SBart Van Assche free(free_dbuff);
1713*44704f69SBart Van Assche if (free_inq_resp)
1714*44704f69SBart Van Assche free(free_inq_resp);
1715*44704f69SBart Van Assche if (fd >= 0) {
1716*44704f69SBart Van Assche res = sg_cmds_close_device(fd);
1717*44704f69SBart Van Assche if (res < 0) {
1718*44704f69SBart Van Assche pr2serr("close error: %s\n", safe_strerror(-res));
1719*44704f69SBart Van Assche if (0 == ret)
1720*44704f69SBart Van Assche ret = sg_convert_errno(-res);
1721*44704f69SBart Van Assche }
1722*44704f69SBart Van Assche }
1723*44704f69SBart Van Assche if (0 == vb) {
1724*44704f69SBart Van Assche if (! sg_if_can2stderr("sg_format failed: ", ret))
1725*44704f69SBart Van Assche pr2serr("Some error occurred, try again with '-v' "
1726*44704f69SBart Van Assche "or '-vv' for more information\n");
1727*44704f69SBart Van Assche }
1728*44704f69SBart Van Assche return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
1729*44704f69SBart Van Assche }
1730