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