xref: /aosp_15_r20/external/sg3_utils/src/sg_format.c (revision 44704f698541f6367e81f991ef8bb54ccbf3fc18)
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