xref: /aosp_15_r20/external/sg3_utils/src/sg_write_x.c (revision 44704f698541f6367e81f991ef8bb54ccbf3fc18)
1 /*
2  * Copyright (c) 2017-2022 Douglas Gilbert.
3  * All rights reserved.
4  * Use of this source code is governed by a BSD-style
5  * license that can be found in the BSD_LICENSE file.
6  *
7  * SPDX-License-Identifier: BSD-2-Clause
8  *
9  * The utility can send six variants of the SCSI WRITE command: (normal)
10  * WRITE(16 or 32), WRITE ATOMIC(16 or 32), ORWRITE(16 or 32),
11  * WRITE SAME(16 or 32), WRITE SCATTERED (16 or 32) or WRITE
12  * STREAM(16 or 32).
13  */
14 
15 #include <unistd.h>
16 #include <fcntl.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <stdarg.h>
20 #include <stdbool.h>
21 #include <string.h>
22 #include <errno.h>
23 #include <limits.h>
24 #include <ctype.h>
25 #include <sys/types.h>  /* needed for lseek() */
26 #include <sys/stat.h>
27 #include <getopt.h>
28 #define __STDC_FORMAT_MACROS 1
29 #include <inttypes.h>
30 
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
34 #include "sg_lib.h"
35 #include "sg_pt.h"
36 #include "sg_cmds_basic.h"
37 #include "sg_cmds_extra.h"
38 #include "sg_unaligned.h"
39 #include "sg_pr2serr.h"
40 
41 static const char * version_str = "1.31 20220217";
42 
43 /* Protection Information refers to 8 bytes of extra information usually
44  * associated with each logical block and is often abbreviated to PI while
45  * its fields: reference-tag (4 bytes), application-tag (2 bytes) and
46  * tag-mask (2 bytes) are often abbreviated to RT, AT and TM respectively.
47  * And the LBA Range Descriptor associated with the WRITE SCATTERED command
48  * is abbreviated to RD. A degenerate RD is one where length components,
49  ( and perhaps the LBA, are zero; it is not illegal according to T10 but are
50  * a little tricky to handle when scanning and little extra information
51  * is provided. */
52 
53 #define ORWRITE16_OP 0x8b
54 #define WRITE_16_OP 0x8a
55 #define WRITE_ATOMIC16_OP 0x9c
56 #define WRITE_SAME16_OP 0x93
57 #define SERVICE_ACTION_OUT_16_OP 0x9f   /* WRITE SCATTERED (16) uses this */
58 #define WRITE_SCATTERED16_SA 0x12
59 #define WRITE_STREAM16_OP 0x9a
60 #define VARIABLE_LEN_OP 0x7f
61 #define ORWRITE32_SA 0xe
62 #define WRITE_32_SA 0xb
63 #define WRITE_ATOMIC32_SA 0xf
64 #define WRITE_SAME_SA 0xd
65 #define WRITE_SCATTERED32_SA 0x11
66 #define WRITE_STREAM32_SA 0x10
67 #define WRITE_X_16_LEN 16
68 #define WRITE_X_32_LEN 32
69 #define WRITE_X_32_ADD 0x18
70 #define RCAP10_RESP_LEN 8
71 #define RCAP16_RESP_LEN 32
72 #define SENSE_BUFF_LEN 64       /* Arbitrary, could be larger */
73 #define DEF_TIMEOUT_SECS 120    /* might need more for large NUM */
74 #define DEF_WR_NUMBLOCKS 0      /* do nothing; for safety */
75 #define DEF_RT 0xffffffff
76 #define DEF_AT 0xffff
77 #define DEF_TM 0xffff
78 #define EBUFF_SZ 256
79 
80 #define MAX_NUM_ADDR 128
81 
82 #ifndef UINT32_MAX
83 #define UINT32_MAX ((uint32_t)-1)
84 #endif
85 #ifndef UINT16_MAX
86 #define UINT16_MAX ((uint16_t)-1)
87 #endif
88 
89 static struct option long_options[] = {
90     {"32", no_argument, 0, '3'},
91     {"16", no_argument, 0, '6'},
92     {"app-tag", required_argument, 0, 'a'},
93     {"app_tag", required_argument, 0, 'a'},
94     {"atomic", required_argument, 0, 'A'},
95     {"bmop", required_argument, 0, 'B'},
96     {"bs", required_argument, 0, 'b'},
97     {"combined", required_argument, 0, 'c'},
98     {"dld", required_argument, 0, 'D'},
99     {"dpo", no_argument, 0, 'd'},
100     {"dry-run", no_argument, 0, 'x'},
101     {"dry_run", no_argument, 0, 'x'},
102     {"fua", no_argument, 0, 'f'},
103     {"grpnum", required_argument, 0, 'g'},
104     {"generation", required_argument, 0, 'G'},
105     {"help", no_argument, 0, 'h'},
106     {"in", required_argument, 0, 'i'},
107     {"lba", required_argument, 0, 'l'},
108     {"normal", no_argument, 0, 'N'},
109     {"num", required_argument, 0, 'n'},
110     {"offset", required_argument, 0, 'o'},
111     {"or", no_argument, 0, 'O'},
112     {"quiet", no_argument, 0, 'Q'},
113     {"ref-tag", required_argument, 0, 'r'},
114     {"ref_tag", required_argument, 0, 'r'},
115     {"same", required_argument, 0, 'M'},
116     {"scat-file", required_argument, 0, 'q'},
117     {"scat_file", required_argument, 0, 'q'},
118     {"scat-raw", no_argument, 0, 'R'},
119     {"scat_raw", no_argument, 0, 'R'},
120     {"scattered", required_argument, 0, 'S'},
121     {"stream", required_argument, 0, 'T'},
122     {"strict", no_argument, 0, 's'},
123     {"tag-mask", required_argument, 0, 't'},
124     {"tag_mask", required_argument, 0, 't'},
125     {"timeout", required_argument, 0, 'I'},
126     {"unmap", required_argument, 0, 'u'},
127     {"verbose", no_argument, 0, 'v'},
128     {"version", no_argument, 0, 'V'},
129     {"wrprotect", required_argument, 0, 'w'},
130     {0, 0, 0, 0},
131 };
132 
133 struct opts_t {
134     bool do_16;                 /* default when --32 not given */
135     bool do_32;
136     bool do_anchor;             /* from  --unmap=U_A , bit 1; WRITE SAME */
137     bool do_atomic;             /* selects  WRITE ATOMIC(16 or 32) */
138                                 /*  --atomic=AB  AB --> .atomic_boundary */
139     bool do_combined;           /* -c DOF --> .scat_lbdof */
140     bool do_or;                 /* -O  ORWRITE(16 or 32) */
141     bool do_quiet;              /* -Q  suppress some messages */
142     bool do_scat_raw;
143     bool do_same;               /* -M  WRITE SAME(16 or 32) */
144                                 /*  --same=NDOB  NDOB --> .ndob */
145     bool do_scattered;          /* -S  WRITE SCATTERED(16 or 32) */
146                                 /*  --scattered=RD  RD --> .scat_num_lbard */
147     bool do_stream;             /* -T  WRITE STREAM(16 or 32) */
148                                 /*  --stream=ID  ID --> .str_id */
149     bool do_unmap;              /* from --unmap=U_A , bit 0; WRITE SAME */
150     bool do_write_normal;       /* -N  WRITE (16 or 32) */
151     bool expect_pi_do;          /* expect protection information (PI) which
152                                  * is 8 bytes long following each logical
153                                  * block in the data out buffer. */
154     bool dpo;                   /* "Disable Page Out" bit field */
155     bool fua;           /* "Force Unit Access" bit field */
156     bool ndob;          /* "No Data-Out Buffer" from --same=NDOB */
157     bool verbose_given;
158     bool version_given;
159     int dld;            /* "Duration Limit Descriptor" bit mask; bit 0 -->
160                          * DLD0, bit 1 --> DLD1, bit 2 --> DLD2
161                          * only WRITE(16) and WRITE SCATTERED(16) */
162     int dry_run;        /* temporary write when used more than once */
163     int grpnum;         /* "Group Number", 0 to 0x3f (GRPNUM_MASK) */
164     int help;
165     int pi_type;        /* -1: unknown: 0: type 0 (none): 1: type 1 */
166     int strict;         /* > 0, report then exit on questionable meta data */
167     int timeout;        /* timeout (in seconds) to abort SCSI commands */
168     int verbose;        /* incremented for each -v */
169     int wrprotect;      /* is ORPROTECT field for ORWRITE */
170     uint8_t bmop;       /* bit mask operators for ORWRITE(32) */
171     uint8_t pgp;        /* previous generation processing for ORWRITE(32) */
172     uint16_t app_tag;   /* part of protection information (def: 0xffff) */
173     uint16_t atomic_boundary;   /* when 0 atomic write spans given length */
174     uint16_t scat_lbdof; /* by construction this must be >= 1 */
175     uint16_t scat_num_lbard;    /* RD from --scattered=RD, number of LBA
176                                  * Range Descriptors */
177     uint16_t str_id;    /* (stream ID) is for WRITE STREAM */
178     uint16_t tag_mask;  /* part of protection information (def: 0xffff) */
179     uint32_t bs;        /* logical block size (def: 0). 0 implies use READ
180                          * CAPACITY(10 or 16) to determine */
181     uint32_t bs_pi_do;  /* logical block size plus PI, if any. This value is
182                          * used as the actual block size */
183     uint32_t if_dlen;   /* bytes to read after .if_offset from .if_name,
184                          * if 0 given, read rest of .if_name */
185     uint32_t numblocks; /* defaults to 0, number of blocks (of user data) to
186                          * write */
187     uint32_t orw_eog;   /* from --generation=EOG,NOG (first argument) */
188     uint32_t orw_nog;   /* from --generation=EOG,NOG (for ORWRITE) */
189     uint32_t ref_tag;   /* part of protection information (def: 0xffffffff) */
190     uint64_t lba;       /* "Logical Block Address", for non-scattered use */
191     uint64_t if_offset; /* byte offset in .if_name to start reading */
192     uint64_t tot_lbs;   /* from READ CAPACITY */
193     ssize_t xfer_bytes;     /* derived value: bs_pi_do * numblocks */
194                             /* for WRITE SCATTERED .xfer_bytes < do_len */
195     const char * device_name;
196     const char * if_name;       /* from --in=IF */
197     const char * scat_filename; /* from --scat-file=SF */
198     const char * cmd_name;      /* e.g. 'Write atomic' */
199     char cdb_name[24];          /* e.g. 'Write atomic(16)' */
200 };
201 
202 static const char * xx_wr_fname = "sg_write_x.bin";
203 static const uint32_t lbard_sz = 32;
204 static const char * lbard_str = "LBA range descriptor";
205 
206 
207 static void
usage(int do_help)208 usage(int do_help)
209 {
210     if (do_help < 2) {
211         pr2serr("Usage:\n"
212             "sg_write_x [--16] [--32] [--app-tag=AT] [--atomic=AB] "
213             "[--bmop=OP,PGP]\n"
214             "           [--bs=BS] [--combined=DOF] [--dld=DLD] [--dpo] "
215             "[--dry-run]\n"
216             "           [--fua] [--generation=EOG,NOG] [--grpnum=GN] "
217             "[--help] --in=IF\n"
218             "           [--lba=LBA,LBA...] [--normal] [--num=NUM,NUM...]\n"
219             "           [--offset=OFF[,DLEN]] [--or] [--quiet] "
220             "[--ref-tag=RT]\n"
221             "           [--same=NDOB] [--scat-file=SF] [--scat-raw] "
222             "[--scattered=RD]\n"
223             "           [--stream=ID] [--strict] [--tag-mask=TM] "
224             "[--timeout=TO]\n"
225             "           [--unmap=U_A] [--verbose] [--version] "
226             "[--wrprotect=WRP]\n"
227             "           DEVICE\n");
228         if (1 != do_help) {
229             pr2serr("\nOr the corresponding short option usage:\n"
230                 "sg_write_x [-6] [-3] [-a AT] [-A AB] [-B OP,PGP] [-b BS] "
231                 "[-c DOF] [-D DLD]\n"
232                 "           [-d] [-x] [-f] [-G EOG,NOG] [-g GN] [-h] -i IF "
233                 "[-l LBA,LBA...]\n"
234                 "           [-N] [-n NUM,NUM...] [-o OFF[,DLEN]] [-O] [-Q] "
235                 "[-r RT] [-M NDOB]\n"
236                 "           [-q SF] [-R] [-S RD] [-T ID] [-s] [-t TM] [-I TO] "
237                 "[-u U_A] [-v]\n"
238                 "           [-V] [-w WPR] DEVICE\n"
239                    );
240             pr2serr("\nUse '-h' or '--help' for more help\n");
241             return;
242         }
243         pr2serr("  where:\n"
244             "    --16|-6            send 16 byte cdb variant (this is "
245             "default action)\n"
246             "    --32|-3            send 32 byte cdb variant of command "
247             "(def: 16 byte)\n"
248             "    --app-tag=AT|-a AT    expected application tag field "
249             "(def: 0xffff)\n"
250             "    --atomic=AB|-A AB    send WRITE ATOMIC command with AB "
251             "being its\n"
252             "                         Atomic Boundary field (0 to 0xffff)\n"
253             "    --bmop=OP,PGP|-p OP,PGP    set BMOP field to OP and "
254             " Previous\n"
255             "                               Generation Processing field "
256             "to PGP\n"
257             "    --bs=BS|-b BS      block size (def: use READ CAPACITY), "
258             "if power of\n"
259             "                       2: logical block size, otherwise: "
260             "actual block size\n"
261             "    --combined=DOF|-c DOF    scatter list and data combined "
262             "for WRITE\n"
263             "                             SCATTERED, data starting at "
264             "offset DOF which\n"
265             "                             has units of sizeof(LB+PI); "
266             "sizeof(PI)=8n or 0\n"
267             "    --dld=DLD|-D DLD    set duration limit descriptor (dld) "
268             "bits (def: 0)\n"
269             "    --dpo|-d           set DPO (disable page out) field "
270             "(def: clear)\n"
271             "    --dry-run|-x       exit just before sending SCSI write "
272             "command\n"
273             "    --fua|-f           set FUA (force unit access) field "
274             "(def: clear)\n"
275             "    --generation=EOG,NOG    set Expected ORWgeneration field "
276             "to EOG\n"
277             "        |-G EOG,NOG         and New ORWgeneration field to "
278             "NOG\n"
279             );
280         pr2serr(
281             "    --grpnum=GN|-g GN    GN is group number field (def: 0, "
282             "range: 0 to 31)\n"
283             "    --help|-h          use multiple times for different "
284             "usage messages\n"
285             "    --in=IF|-i IF      IF is file to fetch NUM blocks of "
286             "data from.\n"
287             "                       Blocks written to DEVICE. 1 or no "
288             "blocks read\n"
289             "                       in the case of WRITE SAME\n"
290             "    --lba=LBA,LBA...     list of LBAs (Logical Block Addresses) "
291             "to start\n"
292             "        |-l LBA,LBA...   writes (def: --lba=0). Alternative is "
293             "--scat-file=SF\n"
294             "    --normal|-N        send 'normal' WRITE command (default "
295             "when no other\n"
296             "                       command option given)\n"
297             "    --num=NUM,NUM...     NUM is number of logical blocks to "
298             "write (def:\n"
299             "        |-n NUM,NUM...   --num=0). Number of block sent is "
300             "sum of NUMs\n"
301             "    --offset=OFF[,DLEN]    OFF is byte offset in IF to start "
302             "reading from\n"
303             "        |-o OFF[,DLEN]     (def: 0), then read DLEN bytes(def: "
304             "rest of IF)\n"
305             "    --or|-O            send ORWRITE command\n"
306             "    --quiet|-Q         suppress some informational messages\n"
307             "    --ref-tag=RT|-r RT     expected reference tag field (def: "
308             "0xffffffff)\n"
309             "    --same=NDOB|-M NDOB    send WRITE SAME command. NDOB (no "
310             "data out buffer)\n"
311             "                           can be either 0 (do send buffer) or "
312             "1 (don't)\n"
313             "    --scat-file=SF|-q SF    file containing LBA, NUM pairs, "
314             "see manpage\n"
315             "    --scat-raw|-R      read --scat_file=SF as binary (def: "
316             "ASCII hex)\n"
317             "    --scattered=RD|-S RD    send WRITE SCATTERED command with "
318             "RD range\n"
319             "                            descriptors (RD can be 0 when "
320             "--combined= given)\n"
321             "    --stream=ID|-T ID    send WRITE STREAM command with its "
322             "STR_ID\n"
323             "                         field set to ID\n"
324             "    --strict|-s        exit if read less than requested from "
325             "IF ;\n"
326             "                       require variety of WRITE to be given "
327             "as option\n"
328             "    --tag-mask=TM|-t TM    tag mask field (def: 0xffff)\n"
329             "    --timeout=TO|-I TO    command timeout (unit: seconds) "
330             "(def: 120)\n"
331             "    --unmap=U_A|-u U_A    0 clears both UNMAP and ANCHOR bits "
332             "(default),\n"
333             "                          1 sets UNMAP, 2 sets ANCHOR, 3 sets "
334             "both\n"
335             "    --verbose|-v       increase verbosity\n"
336             "    --version|-V       print version string then exit\n"
337             "    --wrprotect=WPR|-w WPR    WPR is the WRPROTECT field "
338             "value (def: 0)\n\n"
339             "Performs a SCSI WRITE (normal), ORWRITE, WRITE ATOMIC, WRITE "
340             "SAME, WRITE\nSCATTERED, or WRITE STREAM command. A 16 or 32 "
341             "byte cdb variant can be\nselected. The --in=IF option (data to "
342             "be written) is required apart from\nwhen --same=1 (i.e. when "
343             "NDOB is set). If no WRITE variant option is given\nthen, in "
344             "the absence of --strict, a (normal) WRITE is performed. Only "
345             "WRITE\nSCATTERED uses multiple LBAs and NUMs, or a SF file "
346             "with multiple pairs.\nThe --num=NUM field defaults to 0 (do "
347             "nothing) for safety. Using '-h'\nmultiple times shows the "
348             "applicable options for each command variant.\n"
349             );
350     } else if (2 == do_help) {
351         printf("WRITE ATOMIC (16 or 32) applicable options:\n"
352             "  sg_write_x --atomic=AB --in=IF [--16] [--32] [--app-tag=AT] "
353             "[--bs=BS]\n"
354             "             [--dpo] [--fua] [--grpnum=GN] [--lba=LBA] "
355             "[--num=NUM]\n"
356             "             [--offset=OFF[,DLEN]] [--ref-tag=RT] [--strict] "
357             "[--tag-mask=TM]\n"
358             "             [--timeout=TO] [--wrprotect=WRP] DEVICE\n"
359             "\n"
360             "normal WRITE (32) applicable options:\n"
361             "  sg_write_x --normal --in=IF --32 [--app-tag=AT] [--bs=BS] "
362             "[--dpo] [--fua]\n"
363             "             [--grpnum=GN] [--lba=LBA] [--num=NUM] "
364             "[--offset=OFF[,DLEN]]\n"
365             "             [--ref-tag=RT] [--strict] [--tag-mask=TM] "
366             "[--timeout=TO]\n"
367             "             [--wrprotect=WRP] DEVICE\n"
368             "\n"
369             "normal WRITE (16) applicable options:\n"
370             "  sg_write_x --normal --in=IF [--16] [--bs=BS] [--dld=DLD] "
371             "[--dpo] [--fua]\n"
372             "            [--grpnum=GN] [--lba=LBA] [--num=NUM] "
373             "[--offset=OFF[,DLEN]]\n"
374             "            [--strict] [--timeout=TO] [--verbose] "
375             "[--wrprotect=WRP] DEVICE\n"
376             "\n"
377             "ORWRITE (32) applicable options:\n"
378             "  sg_write_x --or --in=IF --32 [--bmop=OP,PGP] [--bs=BS] "
379             "[--dpo] [--fua]\n"
380             "             [--generation=EOG,NOG] [--grpnum=GN] [--lba=LBA] "
381             "[--num=NUM]\n"
382             "             [--offset=OFF{,DLEN]] [--strict] [--timeout=TO]\n"
383             "             [--wrprotect=ORP] DEVICE\n"
384             "\n"
385             "ORWRITE (16) applicable options:\n"
386             "  sg_write_x --or --in=IF [--16] [--bs=BS] [--dpo] [--fua] "
387             "[--grpnum=GN]\n"
388             "             [--lba=LBA] [--num=NUM] [--offset=OFF[,DLEN]] "
389             "[--strict]\n"
390             "             [--timeout=TO] [--wrprotect=ORP] DEVICE\n"
391             "\n"
392               );
393     } else if (3 == do_help) {
394         printf("WRITE SAME (32) applicable options:\n"
395             "  sg_write_x --same=NDOB --32 [--app-tag=AT] [--bs=BS] "
396             "[--grpnum=GN]\n"
397             "             [--in=IF] [--lba=LBA] [--num=NUM] "
398             "[--offset=OFF[,DLEN]]\n"
399             "             [--ref-tag=RT] [--strict] [--tag-mask=TM] "
400             "[--timeout=TO]\n"
401             "             [--unmap=U_A] [--wrprotect=WRP] DEVICE\n"
402             "\n"
403             "WRITE SCATTERED (32) applicable options:\n"
404             "  sg_write_x --scattered --in=IF --32 [--app-tag=AT] "
405             "[--bs=BS]\n"
406             "             [--combined=DOF] [--dpo] [--fua] [--grpnum=GN]\n"
407             "             [--lba=LBA,LBA...] [--num=NUM,NUM...] "
408             "[--offset=OFF[,DLEN]]\n"
409             "             [--ref-tag=RT] [--scat-file=SF] [--scat-raw] "
410             "[--strict]\n"
411             "             [--tag-mask=TM] [--timeout=TO] [--wrprotect=WRP] "
412             "DEVICE\n"
413             "\n"
414             "WRITE SCATTERED (16) applicable options:\n"
415             "  sg_write_x --scattered --in=IF [--bs=BS] [--combined=DOF] "
416             "[--dld=DLD]\n"
417             "             [--dpo] [--fua] [--grpnum=GN] [--lba=LBA,LBA...]\n"
418             "             [--num=NUM,NUM...] [--offset=OFF[,DLEN]] "
419             "[--scat-raw]\n"
420             "             [--scat-file=SF] [--strict] [--timeout=TO] "
421             "[--wrprotect=WRP]\n"
422             "             DEVICE\n"
423             "\n"
424             "WRITE STREAM (32) applicable options:\n"
425             "  sg_write_x --stream=ID --in=IF --32 [--app-tag=AT] "
426             "[--bs=BS] [--dpo]\n"
427             "             [--fua] [--grpnum=GN] [--lba=LBA] [--num=NUM]\n"
428             "             [--offset=OFF[,DLEN]] [--ref-tag=RT] [--strict] "
429             "[--tag-mask=TM]\n"
430             "             [--timeout=TO] [--verbose] [--wrprotect=WRP] "
431             "DEVICE\n"
432             "\n"
433             "WRITE STREAM (16) applicable options:\n"
434             "  sg_write_x --stream=ID --in=IF [--16] [--bs=BS] [--dpo] "
435             "[--fua]\n"
436             "             [--grpnum=GN] [--lba=LBA] [--num=NUM] "
437             "[--offset=OFF[,DLEN]]\n"
438             "             [--strict] [--timeout=TO] [--wrprotect=WRP] "
439             "DEVICE\n"
440             "\n"
441               );
442     } else {
443         printf("Notes:\n"
444             " - all 32 byte cdb variants, apart from ORWRITE(32), need type "
445             "1, 2, or 3\n"
446             "   protection information active on the DEVICE\n"
447             " - all commands can take one or more --verbose (-v) options "
448             "and/or the\n"
449             "   --dry-run option\n"
450             " - all WRITE X commands will accept --scat-file=SF and "
451             "optionally --scat-raw\n"
452             "   options but only the first lba,num pair is used (any "
453             "more are ignored)\n"
454             " - when '--rscat-aw --scat-file=SF' are used then the binary "
455             "format expected in\n"
456             "   SF is as defined for the WRITE SCATTERED commands. "
457             "That is 32 bytes\n"
458             "   of zeros followed by the first LBA range descriptor "
459             "followed by the\n"
460             "   second LBA range descriptor, etc. Each LBA range "
461             "descriptor is 32 bytes\n"
462             "   long with an 8 byte LBA at offset 0 and a 4 byte "
463             "number_of_logical_\n"
464             "   blocks at offset 8 (both big endian). The 'pad' following "
465             "the last LBA\n"
466             "   range descriptor does not need to be given\n"
467             " - WRITE SCATTERED(32) additionally has expected initial "
468             "LB reference tag,\n"
469             "   application tag and LB application tag mask fields in the "
470             "LBA range\n"
471             "   descriptor. If --strict is given then all reserved fields "
472             "are checked\n"
473             "   for zeros, an error is generated for non zero bytes.\n"
474             " - when '--lba=LBA,LBA...' is used on commands other than "
475             "WRITE SCATTERED\n"
476             "   then only the first LBA value is used.\n"
477             " - when '--num=NUM,NUM...' is used on commands other than "
478             "WRITE SCATTERED\n"
479             "   then only the first NUM value is used.\n"
480             " - whenever '--lba=LBA,LBA...' is used then "
481             "'--num=NUM,NUM...' should\n"
482             "   also be used. Also they should have the same number of "
483             "elements.\n"
484               );
485     }
486 }
487 
488 /* Returns 0 if successful, else sg3_utils error code. */
489 static int
bin_read(int fd,uint8_t * up,uint32_t len,const char * fname)490 bin_read(int fd, uint8_t * up, uint32_t len, const char * fname)
491 {
492     int res, err;
493 
494     res = read(fd, up, len);
495     if (res < 0) {
496         err = errno;
497         pr2serr("Error doing read of %s file: %s\n", fname,
498                 safe_strerror(err));
499         return sg_convert_errno(err);
500     }
501     if ((uint32_t)res < len) {
502         pr2serr("Short (%u) read of %s file, wanted %u\n", (unsigned int)res,
503                 fname, len);
504         return SG_LIB_FILE_ERROR;
505     }
506     return 0;
507 }
508 
509 /* Returns true if num_of_f_chars of ASCII 'f' or 'F' characters are found
510  * in sequence. Any leading "0x" or "0X" is ignored; otherwise false is
511  * returned (and the comparison stops when the first mismatch is found).
512  * For example a sequence of 'f' characters in a null terminated C string
513  * that is two characters shorter than the requested num_of_f_chars will
514  * compare the null character in the string with 'f', find them unequal,
515  * stop comparing and return false. */
516 static bool
all_ascii_f_s(const char * cp,int num_of_f_chars)517 all_ascii_f_s(const char * cp, int num_of_f_chars)
518 {
519     if ((NULL == cp) || (num_of_f_chars < 1))
520         return false;   /* define degenerate cases */
521     if (('0' == cp[0]) && (('x' == cp[1]) || ('X' == cp[1])))
522         cp += 2;
523     for ( ; num_of_f_chars >= 0 ; --num_of_f_chars, ++cp) {
524         if ('F' != toupper((uint8_t)*cp))
525             return false;
526     }
527     return true;
528 }
529 
530 /* Read numbers (up to 64 bits in size) from command line (comma (or
531  * (single) space) separated list). Assumed decimal unless prefixed
532  * by '0x', '0X' or contains trailing 'h' or 'H' (which indicate hex).
533  * Returns 0 if ok, or 1 if error. */
534 static int
build_lba_arr(const char * inp,uint64_t * lba_arr,uint32_t * lba_arr_len,int max_arr_len)535 build_lba_arr(const char * inp, uint64_t * lba_arr, uint32_t * lba_arr_len,
536               int max_arr_len)
537 {
538     int in_len, k;
539     int64_t ll;
540     const char * lcp;
541     char * cp;
542     char * c2p;
543 
544     if ((NULL == inp) || (NULL == lba_arr) ||
545         (NULL == lba_arr_len))
546         return 1;
547     lcp = inp;
548     in_len = strlen(inp);
549     if (0 == in_len)
550         *lba_arr_len = 0;
551     if ('-' == inp[0]) {        /* read from stdin */
552         pr2serr("'--lba' cannot be read from stdin\n");
553         return 1;
554     } else {        /* list of numbers (default decimal) on command line */
555         k = strspn(inp, "0123456789aAbBcCdDeEfFhHxXiIkKmMgGtTpP, ");
556         if (in_len != k) {
557             pr2serr("build_lba_arr: error at pos %d\n", k + 1);
558             return 1;
559         }
560         for (k = 0; k < max_arr_len; ++k) {
561             ll = sg_get_llnum(lcp);
562             if (-1 != ll) {
563                 lba_arr[k] = (uint64_t)ll;
564                 cp = (char *)strchr(lcp, ',');
565                 c2p = (char *)strchr(lcp, ' ');
566                 if (NULL == cp)
567                     cp = c2p;
568                 if (NULL == cp)
569                     break;
570                 if (c2p && (c2p < cp))
571                     cp = c2p;
572                 lcp = cp + 1;
573             } else {
574                 pr2serr("build_lba_arr: error at pos %d\n",
575                         (int)(lcp - inp + 1));
576                 return 1;
577             }
578         }
579         *lba_arr_len = (uint32_t)(k + 1);
580         if (k == max_arr_len) {
581             pr2serr("build_lba_arr: array length exceeded\n");
582             return 1;
583         }
584     }
585     return 0;
586 }
587 
588 /* Read numbers (up to 32 bits in size) from command line (comma (or
589  * (single) space) separated list). Assumed decimal unless prefixed
590  * by '0x', '0X' or contains trailing 'h' or 'H' (which indicate hex).
591  * Returns 0 if ok, else a sg3_utils error code is returned. */
592 static int
build_num_arr(const char * inp,uint32_t * num_arr,uint32_t * num_arr_len,int max_arr_len)593 build_num_arr(const char * inp, uint32_t * num_arr, uint32_t * num_arr_len,
594               int max_arr_len)
595 {
596     int in_len, k;
597     const char * lcp;
598     int64_t ll;
599     char * cp;
600     char * c2p;
601 
602     if ((NULL == inp) || (NULL == num_arr) ||
603         (NULL == num_arr_len))
604         return SG_LIB_LOGIC_ERROR;
605     lcp = inp;
606     in_len = strlen(inp);
607     if (0 == in_len)
608         *num_arr_len = 0;
609     if ('-' == inp[0]) {        /* read from stdin */
610         pr2serr("'--len' cannot be read from stdin\n");
611         return SG_LIB_SYNTAX_ERROR;
612     } else {        /* list of numbers (default decimal) on command line */
613         k = strspn(inp, "0123456789aAbBcCdDeEfFhHxXiIkKmMgGtTpP, ");
614         if (in_len != k) {
615             pr2serr("%s: error at pos %d\n", __func__, k + 1);
616             return SG_LIB_SYNTAX_ERROR;
617         }
618         for (k = 0; k < max_arr_len; ++k) {
619             ll = sg_get_llnum(lcp);
620             if (-1 != ll) {
621                 if (ll > UINT32_MAX) {
622                     pr2serr("%s: number exceeds 32 bits at pos %d\n",
623                             __func__, (int)(lcp - inp + 1));
624                     return SG_LIB_SYNTAX_ERROR;
625                 }
626                 num_arr[k] = (uint32_t)ll;
627                 cp = (char *)strchr(lcp, ',');
628                 c2p = (char *)strchr(lcp, ' ');
629                 if (NULL == cp)
630                     cp = c2p;
631                 if (NULL == cp)
632                     break;
633                 if (c2p && (c2p < cp))
634                     cp = c2p;
635                 lcp = cp + 1;
636             } else {
637                 pr2serr("%s: error at pos %d\n", __func__,
638                         (int)(lcp - inp + 1));
639                 return SG_LIB_SYNTAX_ERROR;
640             }
641         }
642         *num_arr_len = (uint32_t)(k + 1);
643         if (k == max_arr_len) {
644             pr2serr("%s: array length exceeded\n", __func__);
645             return SG_LIB_SYNTAX_ERROR;
646         }
647     }
648     return 0;
649 }
650 
651 /* Tries to parse LBA,NUM[,RT,AP,TM] on one line, comma separated. Returns
652  * 0 if parsed ok, else 999 if nothing parsed, else error (currently always
653  * SG_LIB_SYNTAX_ERROR). If protection information fields not given, then
654  * default values are given (i.e. all 0xff bytes). Ignores all spaces and
655  * tabs and everything after '#' on lcp (assumed to be an ASCII line that
656  * is null terminated). If successful and 'up' is non NULL then writes a
657  * LBA range descriptor starting at 'up'. */
658 static int
parse_scat_pi_line(const char * lcp,uint8_t * up,uint32_t * sum_num)659 parse_scat_pi_line(const char * lcp, uint8_t * up, uint32_t * sum_num)
660 {
661     bool ok;
662     int k;
663     int64_t ll;
664     const char * cp;
665     const char * bp;
666     char c[1024];
667 
668     bp = c;
669     cp = strchr(lcp, '#');
670     lcp += strspn(lcp, " \t");
671     if (('\0' == *lcp) || (cp && (lcp >= cp)))
672         return 999;   /* blank line or blank prior to first '#' */
673     if (cp) {   /* copy from first non whitespace ... */
674         memcpy(c, lcp, cp - lcp);  /* ... to just prior to first '#' */
675         c[cp - lcp] = '\0';
676     } else {
677         /* ... to end of line, including null */
678         snprintf(c, sizeof(c), "%s", lcp);
679     }
680     ll = sg_get_llnum(bp);
681     ok = ((-1 != ll) || all_ascii_f_s(bp, 16));
682     if (! ok) {
683         pr2serr("%s: error reading LBA (first) item on ", __func__);
684         return SG_LIB_SYNTAX_ERROR;
685     }
686     if (up)
687         sg_put_unaligned_be64((uint64_t)ll, up + 0);
688     ok = false;
689     cp = strchr(bp, ',');
690     if (cp) {
691         bp = cp + 1;
692         if (*bp) {
693             ll = sg_get_llnum(bp);
694             if (-1 != ll)
695                 ok = true;
696         }
697     }
698     if ((! ok) || (ll > UINT32_MAX)) {
699         pr2serr("%s: error reading NUM (second) item on ", __func__);
700         return SG_LIB_SYNTAX_ERROR;
701     }
702     if (up)
703         sg_put_unaligned_be32((uint32_t)ll, up + 8);
704     if (sum_num)
705         *sum_num += (uint32_t)ll;
706     /* now for 3 PI items */
707     for (k = 0; k < 3; ++k) {
708         ok = true;
709         cp = strchr(bp, ',');
710         if (NULL == cp)
711             break;
712         bp = cp + 1;
713         if (*bp) {
714             cp += strspn(bp, " \t");
715             if ('\0' == *cp)
716                 break;
717             else if (',' == *cp) {
718                 if (0 == k)
719                     ll = DEF_RT;
720                 else
721                     ll = DEF_AT; /* DEF_AT and DEF_TM have same value */
722             } else {
723                 ll = sg_get_llnum(bp);
724                 if (-1 == ll)
725                     ok = false;
726             }
727         }
728         if (! ok) {
729             pr2serr("%s: error reading item %d NUM item on ", __func__,
730                     k + 3);
731             break;
732         }
733         switch (k) {
734         case 0:
735             if (ll > UINT32_MAX) {
736                 pr2serr("%s: error with item 3, >0xffffffff; on ", __func__);
737                 ok = false;
738             } else if (up)
739                 sg_put_unaligned_be32((uint32_t)ll, up + 12);
740             break;
741         case 1:
742             if (ll > UINT16_MAX) {
743                 pr2serr("%s: error with item 4, >0xffff; on ", __func__);
744                 ok = false;
745             } else if (up)
746                 sg_put_unaligned_be16((uint16_t)ll, up + 16);
747             break;
748         case 2:
749             if (ll > UINT16_MAX) {
750                 pr2serr("%s: error with item 5, >0xffff; on ", __func__);
751                 ok = false;
752             } else if (up)
753                 sg_put_unaligned_be16((uint16_t)ll, up + 18);
754             break;
755         }
756         if (! ok)
757             break;
758     }
759     if (! ok)
760         return SG_LIB_SYNTAX_ERROR;
761     for ( ; k < 3; ++k) {
762         switch (k) {
763         case 0:
764             if (up)
765                 sg_put_unaligned_be32((uint32_t)DEF_RT, up + 12);
766             break;
767         case 1:
768             if (up)
769                 sg_put_unaligned_be16((uint16_t)DEF_AT, up + 16);
770             break;
771         case 2:
772             if (up)
773                 sg_put_unaligned_be16((uint16_t)DEF_TM, up + 18);
774             break;
775         }
776     }
777     return 0;
778 }
779 
780 /* Read pairs or quintets from a scat_file and places them in a T10 scatter
781  * list array is built starting at at t10_scat_list_out (i.e. as per T10 the
782  * first 32 bytes are zeros followed by the first LBA range descriptor (also
783  * 32 bytes long) then the second LBA range descriptor, etc. The pointer
784  * t10_scat_list_out may be NULL in which case the T10 list array is not
785  * built but all other operations take place; this can be useful for sizing
786  * how large the area holding that list needs to be. The max_list_blen may
787  * also be 0. If do_16 is true then only LBA,NUM pairs are expected,
788  * loosely formatted with numbers found alternating between LBA and NUM, with
789  * an even number of elements required overall. If do_16 is false then a
790  * stricter format for quintets is expected: each non comment line should
791  * contain: LBA,NUM[,RT,AT,TM] . If RT,AT,TM are not given then they assume
792  * their defaults (i.e. 0xffffffff, 0xffff, 0xffff). Each number (64 bits for
793  * the LBA, 32 bits for NUM and RT, 16 bit for AT and TM) may be a comma,
794  * space or tab separated list. Assumed decimal unless prefixed by '0x', '0X'
795  * or contains trailing 'h' or 'H' (which indicate hex). Returns 0 if ok,
796  * else error number. If ok also yields the number of LBA range descriptors
797  * written in num_scat_elems and the sum of NUM elements found. Note that
798  * sum_num is not initialized to 0. If parse_one is true then exits
799  * after one LBA range descriptor is decoded. */
800 static int
build_t10_scat(const char * scat_fname,bool do_16,bool parse_one,uint8_t * t10_scat_list_out,uint16_t * num_scat_elems,uint32_t * sum_num,uint32_t max_list_blen)801 build_t10_scat(const char * scat_fname, bool do_16, bool parse_one,
802                uint8_t * t10_scat_list_out, uint16_t * num_scat_elems,
803                uint32_t * sum_num, uint32_t max_list_blen)
804 {
805     bool have_stdin = false;
806     bool del_fp = false;
807     bool bit0, ok;
808     int off = 0;
809     int in_len, k, j, m, n, res, err;
810     int64_t ll;
811     char * lcp;
812     uint8_t * up = t10_scat_list_out;
813     FILE * fp = NULL;
814     char line[1024];
815 
816     if (up) {
817         if (max_list_blen < 64) {
818             pr2serr("%s: t10_scat_list_out is too short\n", __func__);
819             return SG_LIB_SYNTAX_ERROR;
820         }
821         memset(up, 0, max_list_blen);
822     }
823     n = lbard_sz;
824 
825     have_stdin = ((1 == strlen(scat_fname)) && ('-' == scat_fname[0]));
826     if (have_stdin) {
827         fp = stdin;
828         scat_fname = "<stdin>";
829     } else {
830         fp = fopen(scat_fname, "r");
831         if (NULL == fp) {
832             err = errno;
833             pr2serr("%s: unable to open %s: %s\n", __func__, scat_fname,
834                     safe_strerror(err));
835             return sg_convert_errno(err);
836         }
837         del_fp = true;
838     }
839     for (j = 0; j < 1024; ++j) {/* loop over lines in file */
840         if ((max_list_blen > 0) && ((n + lbard_sz) > max_list_blen))
841             goto fini;
842         if (NULL == fgets(line, sizeof(line), fp))
843             break;
844         // could improve with carry_over logic if sizeof(line) too small
845         in_len = strlen(line);
846         if (in_len > 0) {
847             if ('\n' == line[in_len - 1]) {
848                 --in_len;
849                 line[in_len] = '\0';
850             }
851         }
852         if (in_len < 1)
853             continue;
854         lcp = line;
855         m = strspn(lcp, " \t");
856         if (m == in_len)
857             continue;
858         lcp += m;
859         in_len -= m;
860         if ('#' == *lcp)    /* Comment? If so skip rest of line */
861             continue;
862         k = strspn(lcp, "0123456789aAbBcCdDeEfFhHxXiIkKmMgGtTpP ,\t");
863         if ((k < in_len) && ('#' != lcp[k])) {
864             pr2serr("%s: syntax error in %s at line %d, pos %d\n",
865                     __func__, scat_fname, j + 1, m + k + 1);
866             goto bad_exit;
867         }
868         if (! do_16) {
869             res = parse_scat_pi_line(lcp, up ? (up + n) : up, sum_num);
870             if (999 == res)
871                 ;
872             else if (0 == res) {
873                 n += lbard_sz;
874                 if (parse_one)
875                     goto fini;
876             } else {
877                 if (SG_LIB_CAT_NOT_READY == res)
878                     goto bad_mem_exit;
879                 pr2serr("line %d in %s\n", j + 1, scat_fname);
880                 goto bad_exit;
881             }
882             continue;
883         }
884         for (k = 0; k < 1024; ++k) {
885             ll = sg_get_llnum(lcp);
886             ok = ((-1 != ll) || all_ascii_f_s(lcp, 16));
887             if (ok) {
888                 bit0 = !! (0x1 & (off + k));
889                 if (bit0) {
890                     if (ll > UINT32_MAX) {
891                         pr2serr("%s: number exceeds 32 bits in line %d, at "
892                                 "pos %d of %s\n", __func__, j + 1,
893                                 (int)(lcp - line + 1), scat_fname);
894                         goto bad_exit;
895                     }
896                     if (up)
897                         sg_put_unaligned_be32((uint32_t)ll, up + n + 8);
898                     if (sum_num)
899                         *sum_num += (uint32_t)ll;
900                     n += lbard_sz;  /* skip to next LBA range descriptor */
901                     if (parse_one)
902                         goto fini;
903                 } else {
904                     if (up)
905                         sg_put_unaligned_be64((uint64_t)ll, up + n + 0);
906                 }
907                 lcp = strpbrk(lcp, " ,\t");
908                 if (NULL == lcp)
909                     break;
910                 lcp += strspn(lcp, " ,\t");
911                 if ('\0' == *lcp)
912                     break;
913             } else {        /* no valid number found */
914                 if ('#' == *lcp) {
915                     --k;
916                     break;
917                 }
918                 pr2serr("%s: error on line %d, at pos %d\n", __func__, j + 1,
919                         (int)(lcp - line + 1));
920                 goto bad_exit;
921             }
922         }   /* inner for loop(k) over line elements */
923         off += (k + 1);
924     }       /* outer for loop(j) over lines */
925     if (do_16 && (0x1 & off)) {
926         pr2serr("%s: expect LBA,NUM pairs but decoded odd number\n  from "
927                 "%s\n", __func__, scat_fname);
928         goto bad_exit;
929     }
930 fini:
931     *num_scat_elems = (n / lbard_sz) - 1;
932     if (del_fp)
933         fclose(fp);
934     return 0;
935 bad_exit:
936     if (del_fp)
937         fclose(fp);
938     return SG_LIB_SYNTAX_ERROR;
939 bad_mem_exit:
940     if (del_fp)
941         fclose(fp);
942     return SG_LIB_CAT_NOT_READY;        /* flag output buffer too small */
943 }
944 
945 static bool
is_pi_default(const struct opts_t * op)946 is_pi_default(const struct opts_t * op)
947 {
948     return ((DEF_AT == op->app_tag) && (DEF_RT == op->ref_tag) &&
949             (DEF_TM == op->tag_mask));
950 }
951 
952 /* Given a t10 parameter list header (32 zero bytes) for WRITE SCATTERED
953  * (16 or 32) followed by n RDs with a total length of at least
954  * max_lbrds_blen bytes, find "n" and increment where num_lbard points
955  * n times. Further get the LBA length component from each RD and add each
956  * length into where sum_num points. Note: the caller probably wants to zero
957  * where num_lbard and sum_num point before invoking this function. If all
958  * goes well return true, else false. If a degenerate RD is detected then
959  * if 'RD' (from --scattered=RD) is 0 then stop looking for further RDs;
960  * otherwise keep going. Currently overlapping LBA range descriptors are no
961  * checked for. If op->strict > 0 then the first 32 bytes are checked for
962  * zeros; any non-zero bytes will report to stderr, stop the check and
963  * return false. If op->strict > 0 then the trailing 20 or 12 bytes (only
964  * 12 if RT, AT and TM fields (for PI) are present) are checked for zeros;
965  * any non-zero bytes cause the same action as the previous check. If
966  * the number of RDs (when 'RD' from --scattered=RD > 0) is greater than
967  * the number of RDs found then a report is sent to stderr and if op->strict
968  * > 0 then returns false, else returns true.  */
969 static bool
check_lbrds(const uint8_t * up,uint32_t max_lbrds_blen,const struct opts_t * op,uint16_t * num_lbard,uint32_t * sum_num)970 check_lbrds(const uint8_t * up, uint32_t max_lbrds_blen,
971             const struct opts_t * op, uint16_t * num_lbard,
972             uint32_t * sum_num)
973 {
974     bool ok;
975     int k, j, n;
976     const int max_lbrd_start = max_lbrds_blen - lbard_sz;
977     int vb = op->verbose;
978 
979     if (op->strict) {
980         if (max_lbrds_blen < lbard_sz) {
981             pr2serr("%s: %ss too short (%d < 32)\n", __func__, lbard_str,
982                     max_lbrds_blen);
983             return false;
984         }
985         if (! sg_all_zeros(up, lbard_sz)) {
986             pr2serr("%s: first 32 bytes of WRITE SCATTERED data-out buffer "
987                     "should be zero.\nFound non-zero byte.\n", __func__);
988             return false;
989         }
990     }
991     if (max_lbrds_blen < (2 * lbard_sz)) {
992         *num_lbard = 0;
993         return true;
994     }
995     n = op->scat_num_lbard ? (int)op->scat_num_lbard : -1;
996     for (k = lbard_sz, j = 0; k < max_lbrd_start; k += lbard_sz, ++j) {
997         if ((n < 0) && sg_all_zeros(up + k + 0, 12)) { /* degenerate LBA */
998             if (vb)   /* ... range descriptor terminator if --scattered=0 */
999                 pr2serr("%s: degenerate %s stops scan at k=%d (num_rds=%d)\n",
1000                         __func__, lbard_str, k, j);
1001             break;
1002         }
1003         *sum_num += sg_get_unaligned_be32(up + k + 8);
1004         *num_lbard += 1;
1005         if (op->strict) {
1006             ok = true;
1007             if (op->wrprotect) {
1008                 if (! sg_all_zeros(up + k + 20, 12))
1009                     ok = false;
1010             } else if (! sg_all_zeros(up + k + 12, 20))
1011                 ok = false;
1012             if (! ok) {
1013                 pr2serr("%s: %s %d non zero in reserved fields\n", __func__,
1014                         lbard_str, (k / lbard_sz) - 1);
1015                 return false;
1016             }
1017         }
1018         if (n >= 0) {
1019             if (--n <= 0)
1020                 break;
1021         }
1022     }
1023     if ((k < max_lbrd_start) && op->strict) { /* check pad all zeros */
1024         k += lbard_sz;
1025         j = max_lbrds_blen - k;
1026         if (! sg_all_zeros(up + k, j)) {
1027             pr2serr("%s: pad (%d bytes) following %ss is non zero\n",
1028                     __func__, j, lbard_str);
1029             return false;
1030         }
1031     }
1032     if (vb > 2)
1033         pr2serr("%s: about to return true, num_lbard=%u, sum_num=%u "
1034                 "[k=%d, n=%d]\n", __func__, *num_lbard, *sum_num, k, n);
1035     return true;
1036 }
1037 
1038 static int
sum_num_lbards(const uint8_t * up,int num_lbards)1039 sum_num_lbards(const uint8_t * up, int num_lbards)
1040 {
1041     int sum = 0;
1042     int k, n;
1043 
1044     for (k = 0, n = lbard_sz; k < num_lbards; ++k, n += lbard_sz)
1045         sum += sg_get_unaligned_be32(up + n + 8);
1046     return sum;
1047 }
1048 
1049 /* Returns 0 if successful, else sg3_utils error code. */
1050 static int
do_write_x(int sg_fd,const void * dataoutp,int dout_len,const struct opts_t * op)1051 do_write_x(int sg_fd, const void * dataoutp, int dout_len,
1052            const struct opts_t * op)
1053 {
1054     int k, ret, res, sense_cat, cdb_len, vb, err;
1055     uint8_t x_cdb[WRITE_X_32_LEN];        /* use for both lengths */
1056     uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT;
1057     struct sg_pt_base * ptvp;
1058 
1059     memset(x_cdb, 0, sizeof(x_cdb));
1060     vb = op->verbose;
1061     cdb_len = op->do_16 ? WRITE_X_16_LEN : WRITE_X_32_LEN;
1062     if (16 == cdb_len) {
1063         if (! op->do_scattered)
1064             sg_put_unaligned_be64(op->lba, x_cdb + 2);
1065         x_cdb[14] = (op->grpnum & GRPNUM_MASK);
1066     } else {
1067         x_cdb[0] = VARIABLE_LEN_OP;
1068         x_cdb[6] = (op->grpnum & GRPNUM_MASK);
1069         x_cdb[7] = WRITE_X_32_ADD;
1070         if (! op->do_scattered)
1071             sg_put_unaligned_be64(op->lba, x_cdb + 12);
1072     }
1073     if (op->do_write_normal) {
1074         if (16 == cdb_len)  {
1075             x_cdb[0] = WRITE_16_OP;
1076             x_cdb[1] = ((op->wrprotect & 0x7) << 5);
1077             if (op->dpo)
1078                 x_cdb[1] |= 0x10;
1079             if (op->fua)
1080                 x_cdb[1] |= 0x8;
1081             if (op->dld) {
1082                 if (op->dld & 1)
1083                     x_cdb[14] |= 0x40;
1084                 if (op->dld & 2)
1085                     x_cdb[14] |= 0x80;
1086                 if (op->dld & 4)
1087                     x_cdb[1] |= 0x1;
1088             }
1089             sg_put_unaligned_be32(op->numblocks, x_cdb + 10);
1090         } else {        /* 32 byte WRITE */
1091             sg_put_unaligned_be16((uint16_t)WRITE_32_SA, x_cdb + 8);
1092             x_cdb[10] = ((op->wrprotect & 0x7) << 5);
1093             if (op->dpo)
1094                 x_cdb[10] |= 0x10;
1095             if (op->fua)
1096                 x_cdb[10] |= 0x8;
1097             if (op->dld) {      /* added in sbc4r19 */
1098                 if (op->dld & 1)
1099                     x_cdb[11] |= 0x1;
1100                 if (op->dld & 2)
1101                     x_cdb[11] |= 0x2;
1102                 if (op->dld & 4)
1103                     x_cdb[11] |= 0x4;
1104             }
1105             sg_put_unaligned_be32(op->ref_tag, x_cdb + 20);
1106             sg_put_unaligned_be16(op->app_tag, x_cdb + 24);
1107             sg_put_unaligned_be16(op->tag_mask, x_cdb + 26);
1108             sg_put_unaligned_be32(op->numblocks, x_cdb + 28);
1109         }
1110     } else if (op->do_atomic) {
1111         if (16 == cdb_len)  {
1112             if (op->numblocks > UINT16_MAX) {
1113                 pr2serr("Need WRITE ATOMIC(32) since blocks exceed 65535\n");
1114                 return SG_LIB_SYNTAX_ERROR;
1115             }
1116             x_cdb[0] = WRITE_ATOMIC16_OP;
1117             x_cdb[1] = ((op->wrprotect & 0x7) << 5);
1118             if (op->dpo)
1119                 x_cdb[1] |= 0x10;
1120             if (op->fua)
1121                 x_cdb[1] |= 0x8;
1122             sg_put_unaligned_be16(op->atomic_boundary, x_cdb + 10);
1123             sg_put_unaligned_be16((uint16_t)op->numblocks, x_cdb + 12);
1124         } else {        /* 32 byte WRITE ATOMIC */
1125             sg_put_unaligned_be16(op->atomic_boundary, x_cdb + 4);
1126             sg_put_unaligned_be16((uint16_t)WRITE_ATOMIC32_SA, x_cdb + 8);
1127             x_cdb[10] = ((op->wrprotect & 0x7) << 5);
1128             if (op->dpo)
1129                 x_cdb[10] |= 0x10;
1130             if (op->fua)
1131                 x_cdb[10] |= 0x8;
1132             sg_put_unaligned_be32(op->ref_tag, x_cdb + 20);
1133             sg_put_unaligned_be16(op->app_tag, x_cdb + 24);
1134             sg_put_unaligned_be16(op->tag_mask, x_cdb + 26);
1135             sg_put_unaligned_be32(op->numblocks, x_cdb + 28);
1136         }
1137     } else if (op->do_or) {     /* ORWRITE(16 or 32) */
1138         if (16 == cdb_len) {
1139             x_cdb[0] = ORWRITE16_OP;
1140             x_cdb[1] = ((op->wrprotect & 0x7) << 5);  /* actually ORPROTECT */
1141             if (op->dpo)
1142                 x_cdb[1] |= 0x10;
1143             if (op->fua)
1144                 x_cdb[1] |= 0x8;
1145             sg_put_unaligned_be32(op->numblocks, x_cdb + 10);
1146         } else {
1147             x_cdb[2] = op->bmop;
1148             x_cdb[3] = op->pgp;
1149             sg_put_unaligned_be16((uint16_t)ORWRITE32_SA, x_cdb + 8);
1150             x_cdb[10] = ((op->wrprotect & 0x7) << 5);
1151             if (op->dpo)
1152                 x_cdb[10] |= 0x10;
1153             if (op->fua)
1154                 x_cdb[10] |= 0x8;
1155             sg_put_unaligned_be32(op->orw_eog, x_cdb + 20);
1156             sg_put_unaligned_be32(op->orw_nog, x_cdb + 24);
1157             sg_put_unaligned_be32(op->numblocks, x_cdb + 28);
1158         }
1159     } else if (op->do_same) {
1160         if (16 == cdb_len) {
1161             x_cdb[0] = WRITE_SAME16_OP;
1162             x_cdb[1] = ((op->wrprotect & 0x7) << 5);
1163             if (op->do_anchor)
1164                 x_cdb[1] |= 0x10;
1165             if (op->do_unmap)
1166                 x_cdb[1] |= 0x8;
1167             if (op->ndob)
1168                 x_cdb[1] |= 0x1;
1169             sg_put_unaligned_be32(op->numblocks, x_cdb + 10);
1170         } else {
1171             sg_put_unaligned_be16((uint16_t)WRITE_SAME_SA, x_cdb + 8);
1172             x_cdb[10] = ((op->wrprotect & 0x7) << 5);
1173             if (op->do_anchor)
1174                 x_cdb[10] |= 0x10;
1175             if (op->do_unmap)
1176                 x_cdb[10] |= 0x8;
1177             if (op->ndob)
1178                 x_cdb[10] |= 0x1;
1179             /* Expected initial logical block reference tag */
1180             sg_put_unaligned_be32(op->ref_tag, x_cdb + 20);
1181             sg_put_unaligned_be16(op->app_tag, x_cdb + 24);
1182             sg_put_unaligned_be16(op->tag_mask, x_cdb + 26);
1183             sg_put_unaligned_be32(op->numblocks, x_cdb + 28);
1184         }
1185     } else if (op->do_scattered) {
1186         if (16 == cdb_len) {
1187             x_cdb[0] = SERVICE_ACTION_OUT_16_OP;
1188             x_cdb[1] = WRITE_SCATTERED16_SA;
1189             x_cdb[2] = ((op->wrprotect & 0x7) << 5);
1190             if (op->dpo)
1191                 x_cdb[2] |= 0x10;
1192             if (op->fua)
1193                 x_cdb[2] |= 0x8;
1194             if (op->dld) {
1195                 if (op->dld & 1)
1196                     x_cdb[14] |= 0x40;
1197                 if (op->dld & 2)
1198                     x_cdb[14] |= 0x80;
1199                 if (op->dld & 4)
1200                     x_cdb[2] |= 0x1;
1201             }
1202             sg_put_unaligned_be16(op->scat_lbdof, x_cdb + 4);
1203             sg_put_unaligned_be16(op->scat_num_lbard, x_cdb + 8);
1204             /* Spec says Buffer Transfer Length field (BTL) is the number
1205              * of (user) Logical Blocks in the data-out buffer and that BTL
1206              * may be 0. So the total data-out buffer length in bytes is:
1207              *      (scat_lbdof + numblocks) * actual_block_size   */
1208             sg_put_unaligned_be32(op->numblocks, x_cdb + 10);
1209         } else {
1210             sg_put_unaligned_be16((uint16_t)WRITE_SCATTERED32_SA, x_cdb + 8);
1211             x_cdb[10] = ((op->wrprotect & 0x7) << 5);
1212             if (op->dpo)
1213                 x_cdb[10] |= 0x10;
1214             if (op->fua)
1215                 x_cdb[10] |= 0x8;
1216             sg_put_unaligned_be16(op->scat_lbdof, x_cdb + 12);
1217             sg_put_unaligned_be16(op->scat_num_lbard, x_cdb + 16);
1218             sg_put_unaligned_be32(op->numblocks, x_cdb + 28);
1219             /* ref_tag, app_tag and tag_mask placed in scatter list */
1220         }
1221     } else if (op->do_stream) {
1222         if (16 == cdb_len) {
1223             x_cdb[0] = WRITE_STREAM16_OP;
1224             x_cdb[1] = ((op->wrprotect & 0x7) << 5);
1225             if (op->dpo)
1226                 x_cdb[1] |= 0x10;
1227             if (op->fua)
1228                 x_cdb[1] |= 0x8;
1229             sg_put_unaligned_be16(op->str_id, x_cdb + 10);
1230             sg_put_unaligned_be16((uint16_t)op->numblocks, x_cdb + 12);
1231         } else {
1232             sg_put_unaligned_be16(op->str_id, x_cdb + 4);
1233             sg_put_unaligned_be16((uint16_t)WRITE_STREAM32_SA, x_cdb + 8);
1234             x_cdb[10] = ((op->wrprotect & 0x7) << 5);
1235             if (op->dpo)
1236                 x_cdb[10] |= 0x10;
1237             if (op->fua)
1238                 x_cdb[10] |= 0x8;
1239             sg_put_unaligned_be32(op->ref_tag, x_cdb + 20);
1240             sg_put_unaligned_be16(op->app_tag, x_cdb + 24);
1241             sg_put_unaligned_be16(op->tag_mask, x_cdb + 26);
1242             sg_put_unaligned_be32(op->numblocks, x_cdb + 28);
1243         }
1244     } else {
1245         pr2serr("%s: bad cdb name or length (%d)\n", __func__, cdb_len);
1246         return SG_LIB_SYNTAX_ERROR;
1247     }
1248 
1249     if (vb > 1) {
1250         char b[128];
1251 
1252         pr2serr("    %s cdb: %s\n", op->cdb_name,
1253                 sg_get_command_str(x_cdb, cdb_len, false, sizeof(b), b));
1254     }
1255     if (op->do_scattered && (vb > 2) && (dout_len > 31)) {
1256         uint32_t sod_off = op->bs_pi_do * op->scat_lbdof;
1257         const uint8_t * up = (const uint8_t *)dataoutp;
1258 
1259         pr2serr("    %s scatter list, number of %ss: %u\n", op->cdb_name,
1260                 lbard_str, op->scat_num_lbard);
1261         pr2serr("      byte offset of data_to_write: %u, dout_len: %d\n",
1262                 sod_off, dout_len);
1263         up += lbard_sz;       /* step over parameter list header */
1264         for (k = 0; k < (int)op->scat_num_lbard; ++k, up += lbard_sz) {
1265             pr2serr("        desc %d: LBA=0x%" PRIx64 " numblocks=%" PRIu32
1266                     "%s", k, sg_get_unaligned_be64(up + 0),
1267                     sg_get_unaligned_be32(up + 8), (op->do_16 ? "\n" : " "));
1268             if (op->do_32)
1269                 pr2serr("rt=0x%x at=0x%x tm=0x%x\n",
1270                         sg_get_unaligned_be32(up + 12),
1271                         sg_get_unaligned_be16(up + 16),
1272                         sg_get_unaligned_be16(up + 18));
1273             if ((uint32_t)(((k + 2) * lbard_sz) + 20) > sod_off) {
1274                 pr2serr("Warning: possible clash of descriptor %u with "
1275                         "data_to_write\n", k);
1276                 if (op->strict > 1)
1277                     return SG_LIB_FILE_ERROR;
1278             }
1279         }
1280     }
1281     if ((vb > 3) && (dout_len > 0)) {
1282         if ((dout_len > 1024) && (vb < 7)) {
1283             pr2serr("    Data-out buffer contents (first 1024 of %u "
1284                     "bytes):\n", dout_len);
1285             hex2stdout((const uint8_t *)dataoutp, 1024, 1);
1286             pr2serr("    Above: dout's first 1024 of %u bytes [%s]\n",
1287                     dout_len, op->cdb_name);
1288         } else {
1289             pr2serr("    Data-out buffer contents (length=%u):\n", dout_len);
1290             hex2stderr((const uint8_t *)dataoutp, (int)dout_len, 1);
1291         }
1292     }
1293     if (op->dry_run) {
1294         if (vb)
1295             pr2serr("Exit just before sending %s due to --dry-run\n",
1296                     op->cdb_name);
1297         if (op->dry_run > 1) {
1298             int w_fd;
1299 
1300             w_fd = open(xx_wr_fname, O_WRONLY | O_CREAT | O_TRUNC, 0644);
1301             if (w_fd < 0) {
1302                 err = errno;
1303                 perror(xx_wr_fname);
1304                 return sg_convert_errno(err);
1305             }
1306             res = write(w_fd, dataoutp, dout_len);
1307             if (res < 0) {
1308                 err = errno;
1309                 perror(xx_wr_fname);
1310                 close(w_fd);
1311                 return sg_convert_errno(err);
1312             }
1313             close(w_fd);
1314             printf("Wrote %u bytes to %s", dout_len, xx_wr_fname);
1315             if (op->do_scattered)
1316                 printf(", LB data offset: %u\nNumber of %ss: %u\n",
1317                        op->scat_lbdof, lbard_str, op->scat_num_lbard);
1318             else
1319                 printf("\n");
1320         }
1321         return 0;
1322     }
1323     ptvp = construct_scsi_pt_obj();
1324     if (NULL == ptvp) {
1325         pr2serr("%s: out of memory\n", op->cdb_name);
1326         return sg_convert_errno(ENOMEM);
1327     }
1328     set_scsi_pt_cdb(ptvp, x_cdb, cdb_len);
1329     set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
1330     if (dout_len > 0)
1331         set_scsi_pt_data_out(ptvp, (uint8_t *)dataoutp, dout_len);
1332     else if (vb && (! op->ndob))
1333         pr2serr("%s:  dout_len==0, so empty dout buffer\n",
1334                 op->cdb_name);
1335     res = do_scsi_pt(ptvp, sg_fd, op->timeout, vb);
1336     ret = sg_cmds_process_resp(ptvp, op->cdb_name, res, true /*noisy */, vb,
1337                                &sense_cat);
1338     if (-1 == ret) {
1339         if (get_scsi_pt_transport_err(ptvp))
1340             ret = SG_LIB_TRANSPORT_ERROR;
1341         else
1342             ret = sg_convert_errno(get_scsi_pt_os_err(ptvp));
1343     } else if (-2 == ret) {
1344         switch (sense_cat) {
1345         case SG_LIB_CAT_RECOVERED:
1346         case SG_LIB_CAT_NO_SENSE:
1347             ret = 0;
1348             break;
1349         case SG_LIB_CAT_MEDIUM_HARD:
1350             {
1351                 bool valid;
1352                 int slen;
1353                 uint64_t ull = 0;
1354 
1355                 slen = get_scsi_pt_sense_len(ptvp);
1356                 valid = sg_get_sense_info_fld(sense_b, slen, &ull);
1357                 if (valid) {
1358                     pr2serr("Medium or hardware error starting at ");
1359                     if (op->do_scattered) {
1360                         if (0 == ull)
1361                             pr2serr("%s=<not reported>\n", lbard_str);
1362                         else
1363                             pr2serr("%s=%" PRIu64 " (origin 0)\n", lbard_str,
1364                                     ull - 1);
1365                         if (sg_get_sense_cmd_spec_fld(sense_b, slen, &ull)) {
1366                             if (0 == ull)
1367                                 pr2serr("  Number of successfully written "
1368                                         "%ss is 0 or not reported\n",
1369                                         lbard_str);
1370                             else
1371                                 pr2serr("  Number of successfully written "
1372                                         "%ss is %u\n", lbard_str,
1373                                         (uint32_t)ull);
1374                         }
1375                     } else
1376                         pr2serr("lba=%" PRIu64 " [0x%" PRIx64 "]\n", ull,
1377                                 ull);
1378                 }
1379             }
1380             ret = sense_cat;
1381             break;
1382         case SG_LIB_CAT_ILLEGAL_REQ:
1383             if (vb)
1384                 sg_print_command_len(x_cdb, cdb_len);
1385             ret = sense_cat;
1386             break;
1387         default:
1388             ret = sense_cat;
1389             break;
1390         }
1391     } else
1392         ret = 0;
1393 
1394     destruct_scsi_pt_obj(ptvp);
1395     return ret;
1396 }
1397 
1398 /* Returns 0 if successful, else sg3_utils error code. */
1399 static int
do_read_capacity(int sg_fd,struct opts_t * op)1400 do_read_capacity(int sg_fd, struct opts_t *op)
1401 {
1402     bool prot_en = false;
1403     int res;
1404     int vb = op->verbose;
1405     char b[80];
1406     uint8_t resp_buff[RCAP16_RESP_LEN];
1407 
1408     res = sg_ll_readcap_16(sg_fd, false /* pmi */, 0 /* llba */, resp_buff,
1409                            RCAP16_RESP_LEN, true, (vb ? (vb - 1): 0));
1410     if (SG_LIB_CAT_UNIT_ATTENTION == res) {
1411         pr2serr("Read capacity(16) unit attention, try again\n");
1412         res = sg_ll_readcap_16(sg_fd, false, 0, resp_buff, RCAP16_RESP_LEN,
1413                                true, (vb ? (vb - 1): 0));
1414     }
1415     if (0 == res) {
1416         uint32_t pi_len = 0;
1417 
1418         if (vb > 3) {
1419             pr2serr("Read capacity(16) response:\n");
1420             hex2stderr(resp_buff, RCAP16_RESP_LEN, 1);
1421         }
1422         op->bs = sg_get_unaligned_be32(resp_buff + 8);
1423         op->tot_lbs = sg_get_unaligned_be64(resp_buff + 0) + 1;
1424         prot_en = !!(resp_buff[12] & 0x1);
1425         if (prot_en) {
1426             uint32_t pi_exp;
1427 
1428             op->pi_type = ((resp_buff[12] >> 1) & 0x7) + 1;
1429             pi_exp = 0xf & (resp_buff[13] >> 4);
1430             pi_len = 8 * (1 << pi_exp);
1431             if (op->wrprotect > 0) {
1432                 op->bs_pi_do = op->bs + pi_len;
1433                 if (vb > 1)
1434                     pr2serr("  For data out buffer purposes the effective "
1435                             "block size is %u (lb size\n  is %u) because "
1436                             "PROT_EN=1, PI_EXP=%u and WRPROTECT>0\n", op->bs,
1437                             pi_exp, op->bs_pi_do);
1438            }
1439         } else {    /* device formatted to PI type 0 (i.e. none) */
1440             op->pi_type = 0;
1441             if (op->wrprotect > 0) {
1442                 if (vb)
1443                     pr2serr("--wrprotect (%d) expects PI but %s says it "
1444                             "has none\n", op->wrprotect, op->device_name);
1445                 if (op->strict)
1446                     return SG_LIB_FILE_ERROR;
1447                 else if (vb)
1448                     pr2serr("  ... continue but could be dangerous\n");
1449             }
1450         }
1451         if (vb) {
1452             uint8_t d[2];
1453 
1454             pr2serr("Read capacity(16) response fields:\n");
1455             pr2serr("  Last_LBA=0x%" PRIx64 "  LB size: %u (with PI: "
1456                     "%u) bytes  p_type=%u\n", op->tot_lbs - 1,
1457                     op->bs, op->bs + (prot_en ? pi_len : 0),
1458                     ((resp_buff[12] >> 1) & 0x7));
1459             pr2serr("  prot_en=%u [PI type=%u] p_i_exp=%u  lbppb_exp=%u  "
1460                     "lbpme,rz=%u,", prot_en, op->pi_type,
1461                     ((resp_buff[13] >> 4) & 0xf), (resp_buff[13] & 0xf),
1462                     !!(resp_buff[14] & 0x80));
1463             memcpy(d, resp_buff + 14, 2);
1464             d[0] &= 0x3f;
1465             pr2serr("%u  low_ali_lba=%u\n", !!(resp_buff[14] & 0x40),
1466                     sg_get_unaligned_be16(d));
1467         }
1468     } else if ((SG_LIB_CAT_INVALID_OP == res) ||
1469                (SG_LIB_CAT_ILLEGAL_REQ == res)) {
1470         if (vb)
1471             pr2serr("Read capacity(16) not supported, try Read "
1472                     "capacity(10)\n");
1473         res = sg_ll_readcap_10(sg_fd, false /* pmi */, 0 /* lba */,
1474                                resp_buff, RCAP10_RESP_LEN, true,
1475                                (vb ? (vb - 1): 0));
1476         if (0 == res) {
1477             if (vb > 3) {
1478                 pr2serr("Read capacity(10) response:\n");
1479                 hex2stderr(resp_buff, RCAP10_RESP_LEN, 1);
1480             }
1481             op->tot_lbs = sg_get_unaligned_be32(resp_buff + 0) + 1;
1482             op->bs = sg_get_unaligned_be32(resp_buff + 4);
1483         } else {
1484             strcpy(b,"OS error");
1485             if (res > 0)
1486                 sg_get_category_sense_str(res, sizeof(b), b, vb);
1487             else
1488                 snprintf(b, sizeof(b), "error: %d", res);
1489             pr2serr("Read capacity(10): %s\n", b);
1490             pr2serr("Unable to calculate block size\n");
1491             return (res > 0) ? res : SG_LIB_FILE_ERROR;
1492         }
1493     } else {
1494         if (vb) {
1495             strcpy(b,"OS error");
1496             if (res > 0)
1497                 sg_get_category_sense_str(res, sizeof(b), b, vb);
1498             pr2serr("Read capacity(16): %s\n", b);
1499             pr2serr("Unable to calculate block size\n");
1500         }
1501         return (res > 0) ? res : SG_LIB_FILE_ERROR;
1502     }
1503     op->bs_pi_do = op->expect_pi_do ? (op->bs + 8) : op->bs;
1504     return 0;
1505 }
1506 
1507 #define WANT_ZERO_EXIT 9999
1508 static const char * const opt_long_ctl_str =
1509     "36a:A:b:B:c:dD:Efg:G:hi:I:l:M:n:No:Oq:Qr:RsS:t:T:u:vVw:x";
1510 
1511 /* command line processing, options and arguments. Returns 0 if ok,
1512  * returns WANT_ZERO_EXIT so upper level yields an exist status of zero.
1513  * Other return values (mainly SG_LIB_SYNTAX_ERROR) indicate errors. */
1514 static int
parse_cmd_line(struct opts_t * op,int argc,char * argv[],const char ** lba_opp,const char ** num_opp)1515 parse_cmd_line(struct opts_t *op, int argc, char *argv[],
1516                const char ** lba_opp, const char ** num_opp)
1517 {
1518     bool fail_if_strict = false;
1519     int c, j;
1520     int64_t ll;
1521     const char * cp;
1522 
1523     while (1) {
1524         int opt_ind = 0;
1525 
1526         c = getopt_long(argc, argv, opt_long_ctl_str, long_options, &opt_ind);
1527         if (c == -1)
1528             break;
1529 
1530         switch (c) {
1531         case '3':       /* same as --32 */
1532             op->do_32 = true;
1533             break;
1534         case '6':       /* same as --16 */
1535             op->do_16 = true;
1536             break;
1537         case 'a':
1538             j = sg_get_num(optarg);
1539             if ((j < 0) || (j > (int)UINT16_MAX)) {
1540                 pr2serr("bad argument to '--app-tag='. Expect 0 to 0xffff "
1541                         "inclusive\n");
1542                 return SG_LIB_SYNTAX_ERROR;
1543             }
1544             op->app_tag = (uint16_t)j;
1545             break;
1546         case 'A':
1547             j = sg_get_num(optarg);
1548             if ((j < 0) || (j > (int)UINT16_MAX)) {
1549                 pr2serr("bad argument to '--atomic='. Expect 0 to 0xffff "
1550                         "inclusive\n");
1551                 return SG_LIB_SYNTAX_ERROR;
1552             }
1553             op->atomic_boundary = (uint16_t)j;
1554             op->do_atomic = true;
1555             op->cmd_name = "Write atomic";
1556             break;
1557         case 'b':                        /* logical block size in bytes */
1558             j = sg_get_num(optarg); /* 0 -> look up with READ CAPACITY */
1559             if ((j < 0) || (j > (1 << 28))) {
1560                 pr2serr("bad argument to '--bs='. Expect 0 or greater\n");
1561                 return SG_LIB_SYNTAX_ERROR;
1562             }
1563             if (j > 0) {
1564                 int k;
1565                 int m = j;
1566                 int highest_ind;
1567 
1568                 if (j < 512) {
1569                     pr2serr("warning: --bs=BS value is < 512 which seems too "
1570                             "small, continue\n");
1571                     fail_if_strict = true;
1572                 }
1573                 if (0 != (j % 8)) {
1574                     pr2serr("warning: --bs=BS value is not a multiple of 8, "
1575                             "unexpected, continue\n");
1576                     fail_if_strict = true;
1577                 }
1578                 for (k = 0, highest_ind = 0; k < 28; ++ k, m >>= 1) {
1579                     if (1 & m)
1580                         highest_ind = k;
1581                 }       /* loop should get log_base2(j) */
1582                 k = 1 << highest_ind;
1583                 if (j == k) {   /* j is a power of two; actual and logical
1584                                  * block size is assumed to be the same */
1585                     op->bs = (uint32_t)j;
1586                     op->bs_pi_do = op->bs;
1587                 } else {  /* j is not power_of_two, use as actual LB size */
1588                     op->bs = (uint32_t)k;       /* power_of_two less than j */
1589                     op->bs_pi_do = (uint32_t)j;
1590                 }
1591             } else {    /* j==0, let READCAP sort this out */
1592                 op->bs = 0;
1593                 op->bs_pi_do = 0;
1594             }
1595             break;
1596         case 'B':       /* --bmop=OP,PGP (for ORWRITE(32)) */
1597             j = sg_get_num(optarg);
1598             if ((j < 0) || (j > 7)) {
1599                 pr2serr("bad first argument to '--bmop='\n");
1600                 return SG_LIB_SYNTAX_ERROR;
1601             }
1602             op->bmop = (uint8_t)j;
1603             if ((cp = strchr(optarg, ','))) {
1604                 j = sg_get_num(cp + 1);
1605                 if ((j < 0) || (j > 15)) {
1606                     pr2serr("bad second argument to '--bmop='\n");
1607                     return SG_LIB_SYNTAX_ERROR;
1608                 }
1609                 op->pgp = (uint8_t)j;
1610             }
1611             break;
1612         case 'c':       /* --combined=DOF for W SCATTERED, DOF: data offset */
1613             j = sg_get_num(optarg);
1614             if (j < 0) {
1615                 pr2serr("bad argument to '--combined='. Expect 0 to "
1616                         "0x7fffffff\n");
1617                 return SG_LIB_SYNTAX_ERROR;
1618             }
1619             op->scat_lbdof = (uint16_t)j;
1620             op->do_combined = true;
1621             break;
1622         case 'd':
1623             op->dpo = true;
1624             break;
1625         case 'D':
1626             op->dld = sg_get_num(optarg);
1627             if ((op->dld < 0) || (op->dld > 7))  {
1628                 pr2serr("bad argument to '--dld=', expect 0 to 7 "
1629                         "inclusive\n");
1630                 return SG_LIB_SYNTAX_ERROR;
1631             }
1632             break;
1633         case 'f':
1634             op->fua = true;
1635             break;
1636         case 'g':
1637             op->grpnum = sg_get_num(optarg);
1638             if ((op->grpnum < 0) || (op->grpnum > 63))  {
1639                 pr2serr("bad argument to '--grpnum'\n");
1640                 return SG_LIB_SYNTAX_ERROR;
1641             }
1642             break;
1643         case 'G':       /* --generation=EOG,NOG */
1644             ll = sg_get_llnum(optarg);
1645             if ((ll < 0) || (ll > UINT32_MAX)) {
1646                 pr2serr("bad first argument to '--generation='\n");
1647                 return SG_LIB_SYNTAX_ERROR;
1648             }
1649             op->orw_eog = (uint32_t)ll;
1650             if ((cp = strchr(optarg, ','))) {
1651                 ll = sg_get_llnum(cp + 1);
1652                 if ((ll < 0) || (ll > UINT32_MAX)) {
1653                     pr2serr("bad second argument to '--generation='\n");
1654                     return SG_LIB_SYNTAX_ERROR;
1655                 }
1656                 op->orw_nog = (uint32_t)ll;
1657             } else {
1658                 pr2serr("need two arguments with --generation=EOG,NOG and "
1659                         "they must be comma separated\n");
1660                 return SG_LIB_SYNTAX_ERROR;
1661             }
1662             break;
1663         case 'h':
1664             ++op->help;
1665             break;
1666         case '?':
1667             pr2serr("\n");
1668             usage((op->help > 0) ? op->help : 0);
1669             return SG_LIB_SYNTAX_ERROR;
1670         case 'i':
1671             op->if_name = optarg;
1672             break;
1673         case 'I':
1674             op->timeout = sg_get_num(optarg);
1675             if (op->timeout < 0)  {
1676                 pr2serr("bad argument to '--timeout='\n");
1677                 return SG_LIB_SYNTAX_ERROR;
1678             }
1679             break;
1680         case 'l':
1681             if (*lba_opp) {
1682                 pr2serr("only expect '--lba=' option once\n");
1683                 return SG_LIB_SYNTAX_ERROR;
1684             }
1685             *lba_opp = optarg;
1686             break;
1687         case 'M':               /* WRITE SAME */
1688             j = sg_get_num(optarg);
1689             if ((j < 0) || (j > 1))  {
1690                 pr2serr("bad argument to '--same', expect 0 or 1\n");
1691                 return SG_LIB_SYNTAX_ERROR;
1692             }
1693             op->ndob = (bool)j;
1694             op->do_same = true;
1695             op->cmd_name = "Write same";
1696             break;
1697         case 'n':
1698             if (*num_opp) {
1699                 pr2serr("only expect '--num=' option once\n");
1700                 return SG_LIB_SYNTAX_ERROR;
1701             }
1702             *num_opp = optarg;
1703             break;
1704         case 'N':
1705             op->do_write_normal = true;
1706             op->cmd_name = "Write";
1707             break;
1708         case 'o':
1709             ll = sg_get_llnum(optarg);
1710             if (-1 == ll) {
1711                 pr2serr("bad first argument to '--offset='\n");
1712                 return SG_LIB_SYNTAX_ERROR;
1713             }
1714             op->if_offset = (uint64_t)ll;
1715             if ((cp = strchr(optarg, ','))) {
1716                 ll = sg_get_llnum(cp + 1);
1717                 if (-1 == ll) {
1718                     pr2serr("bad second argument to '--offset='\n");
1719                     return SG_LIB_SYNTAX_ERROR;
1720                 }
1721                 if (ll > UINT32_MAX) {
1722                     pr2serr("bad second argument to '--offset=', cannot "
1723                             "exceed 32 bits\n");
1724                     return SG_LIB_SYNTAX_ERROR;
1725                 }
1726                 op->if_dlen = (uint32_t)ll;
1727             }
1728             break;
1729         case 'O':
1730             op->do_or = true;
1731             op->cmd_name = "Orwrite";
1732             break;
1733         case 'q':
1734             op->scat_filename = optarg;
1735             break;
1736         case 'Q':
1737             op->do_quiet = true;
1738             break;
1739         case 'R':
1740             op->do_scat_raw = true;
1741             break;
1742         case 'r':               /* same as --ref-tag= */
1743             ll = sg_get_llnum(optarg);
1744             if ((ll < 0) || (ll > UINT32_MAX)) {
1745                 pr2serr("bad argument to '--ref-tag='. Expect 0 to "
1746                         "0xffffffff inclusive\n");
1747                 return SG_LIB_SYNTAX_ERROR;
1748             }
1749             op->ref_tag = (uint32_t)ll;
1750             break;
1751         case 's':
1752             ++op->strict;
1753             break;
1754         case 'S':
1755             j = sg_get_num(optarg);
1756             if ((j < 0) || (j > (int)UINT16_MAX)) {
1757                 pr2serr("bad argument to '--scattered='. Expect 0 to 0xffff "
1758                         "inclusive\n");
1759                 return SG_LIB_SYNTAX_ERROR;
1760             }
1761             op->scat_num_lbard = (uint16_t)j;
1762             op->do_scattered = true;
1763             op->cmd_name = "Write scattered";
1764             break;
1765         case 't':               /* same as --tag-mask= */
1766             j = sg_get_num(optarg);
1767             if ((j < 0) || (j > (int)UINT16_MAX)) {
1768                 pr2serr("bad argument to '--tag-mask='. Expect 0 to 0xffff "
1769                         "inclusive\n");
1770                 return SG_LIB_SYNTAX_ERROR;
1771             }
1772             op->tag_mask = (uint16_t)j;
1773             break;
1774         case 'T':               /* WRITE STREAM */
1775             j = sg_get_num(optarg);
1776             if ((j < 0) || (j > (int)UINT16_MAX)) {
1777                 pr2serr("bad argument to '--stream=', expect 0 to 65535\n");
1778                 return SG_LIB_SYNTAX_ERROR;
1779             }
1780             op->str_id = (uint16_t)j;
1781             op->do_stream = true;
1782             op->cmd_name = "Write stream";
1783             break;
1784         case 'u':               /* WRITE SAME, UNMAP and ANCHOR bit */
1785             j = sg_get_num(optarg);
1786             if ((j < 0) || (j > 3)) {
1787                 pr2serr("bad argument to '--unmap=', expect 0 to "
1788                         "3\n");
1789                 return SG_LIB_SYNTAX_ERROR;
1790             }
1791             op->do_unmap = !!(1 & j);
1792             op->do_anchor = !!(2 & j);
1793             break;
1794         case 'v':
1795             op->verbose_given = true;
1796             ++op->verbose;
1797             break;
1798         case 'V':
1799             op->version_given = true;
1800             break;
1801         case 'w':       /* WRPROTECT field (or ORPROTECT for ORWRITE) */
1802             op->wrprotect = sg_get_num(optarg);
1803             if ((op->wrprotect < 0) || (op->wrprotect > 7))  {
1804                 pr2serr("bad argument to '--wrprotect'\n");
1805                 return SG_LIB_SYNTAX_ERROR;
1806             }
1807             op->expect_pi_do = (op->wrprotect > 0);
1808             break;
1809         case 'x':
1810             ++op->dry_run;
1811             break;
1812         default:
1813             pr2serr("unrecognised option code 0x%x ??\n", c);
1814             usage((op->help > 0) ? op->help : 0);
1815             return SG_LIB_SYNTAX_ERROR;
1816         }
1817     }
1818     if (optind < argc) {
1819         if (NULL == op->device_name) {
1820             op->device_name = argv[optind];
1821             ++optind;
1822         }
1823         if (optind < argc) {
1824             for (; optind < argc; ++optind)
1825                 pr2serr("Unexpected extra argument: %s\n", argv[optind]);
1826             usage((op->help > 0) ? op->help : 0);
1827             return SG_LIB_SYNTAX_ERROR;
1828         }
1829     }
1830     if (op->strict && fail_if_strict)
1831         return SG_LIB_SYNTAX_ERROR;
1832     return 0;
1833 }
1834 
1835 static int
process_scattered(int sg_fd,int infd,uint32_t if_len,uint32_t if_rlen,int sfr_fd,uint32_t sf_len,uint64_t * addr_arr,uint32_t addr_arr_len,uint32_t * num_arr,uint16_t num_lbard,uint32_t sum_num,struct opts_t * op)1836 process_scattered(int sg_fd, int infd, uint32_t if_len, uint32_t if_rlen,
1837                   int sfr_fd, uint32_t sf_len, uint64_t * addr_arr,
1838                   uint32_t addr_arr_len, uint32_t * num_arr,
1839                   uint16_t num_lbard, uint32_t sum_num, struct opts_t * op)
1840 {
1841     int k, n, ret;
1842     int vb = op->verbose;
1843     uint32_t d, dd, nn, do_len;
1844     uint8_t * up = NULL;
1845     uint8_t * free_up = NULL;
1846     char b[80];
1847 
1848     if (op->do_combined) {      /* --combined=DOF (.scat_lbdof) */
1849         if (op->scat_lbdof > 0)
1850             d = op->scat_lbdof * op->bs_pi_do;
1851         else if (op->scat_num_lbard > 0) {
1852             d = lbard_sz * (1 + op->scat_num_lbard);
1853             if (0 != (d % op->bs_pi_do))
1854                 d = ((d / op->bs_pi_do) + 1) * op->bs_pi_do;
1855         } else if (if_len > 0) {
1856             d = if_len;
1857             if (0 != (d % op->bs_pi_do))
1858                 d = ((d / op->bs_pi_do) + 1) * op->bs_pi_do;
1859         } else {
1860             pr2serr("With --combined= if DOF, RD are 0 and IF has an "
1861                     "unknown length\nthen give up\n");
1862             return SG_LIB_CONTRADICT;
1863         }
1864         up = sg_memalign(d, 0, &free_up, false);
1865         if (NULL == up) {
1866             pr2serr("unable to allocate aligned memory for "
1867                     "scatterlist+data\n");
1868             return sg_convert_errno(ENOMEM);
1869         }
1870         ret = bin_read(infd, up, ((if_len < d) ? if_len : d), "IF c1");
1871         if (ret)
1872             goto finii;
1873         if (! check_lbrds(up, d, op, &num_lbard, &sum_num))
1874             goto file_err_outt;
1875         if ((op->scat_num_lbard > 0) && (op->scat_num_lbard != num_lbard)) {
1876             bool rd_gt = (op->scat_num_lbard > num_lbard);
1877 
1878             if (rd_gt || op->strict || vb) {
1879                 pr2serr("RD (%u) %s number of %ss (%u) found in IF\n",
1880                         op->scat_num_lbard, (rd_gt ? ">" : "<"), lbard_str,
1881                         num_lbard);
1882                 if (rd_gt)
1883                     goto file_err_outt;
1884                 else if (op->strict)
1885                     goto file_err_outt;
1886             }
1887             num_lbard = op->scat_num_lbard;
1888             sum_num = sum_num_lbards(up, op->scat_num_lbard);
1889         } else
1890             op->scat_num_lbard = num_lbard;
1891         dd = lbard_sz * (num_lbard + 1);
1892         if (0 != (dd % op->bs_pi_do))
1893             dd = ((dd / op->bs_pi_do) + 1) * op->bs_pi_do; /* round up */
1894         nn = op->scat_lbdof * op->bs_pi_do;
1895         if (dd != nn) {
1896             bool dd_gt = (dd > nn);
1897 
1898             if (dd_gt) {
1899                 pr2serr("%s: Cannot fit %ss (%u) in given LB data offset "
1900                         "(%u)\n", __func__, lbard_str, num_lbard,
1901                         op->scat_lbdof);
1902                 goto file_err_outt;
1903             }
1904             if (vb || op->strict)
1905                 pr2serr("%s: empty blocks before LB data offset (%u), could "
1906                         "be okay\n", __func__, op->scat_lbdof);
1907             if (op->strict) {
1908                 pr2serr("Exiting due to --strict; perhaps try again with "
1909                         "--combined=%u\n", dd / op->bs_pi_do);
1910                 goto file_err_outt;
1911             }
1912             dd = nn;
1913         }
1914         dd += (sum_num * op->bs_pi_do);
1915         if (dd > d) {
1916             uint8_t * u2p;
1917             uint8_t * free_u2p;
1918 
1919             if (dd != if_len) {
1920                 bool dd_gt = (dd > if_len);
1921 
1922                 if (dd_gt || op->strict || vb) {
1923                     pr2serr("Calculated dout length (%u) %s bytes available "
1924                             "in IF (%u)\n", dd, (dd_gt ? ">" : "<"), if_len);
1925                     if (dd_gt)
1926                         goto file_err_outt;
1927                     else if (op->strict)
1928                         goto file_err_outt;
1929                 }
1930             }
1931             u2p = sg_memalign(dd, 0, &free_u2p, false);
1932             if (NULL == u2p) {
1933                 pr2serr("unable to allocate memory for final "
1934                         "scatterlist+data\n");
1935                 ret = sg_convert_errno(ENOMEM);
1936                 goto finii;
1937             }
1938             memcpy(u2p, up, d);
1939             free(free_up);
1940             up = u2p;
1941             free_up = free_u2p;
1942             ret = bin_read(infd, up + d, dd - d, "IF c2");
1943             if (ret)
1944                 goto finii;
1945         }
1946         do_len = dd;
1947         op->numblocks = sum_num;
1948         op->xfer_bytes = sum_num * op->bs_pi_do;
1949         goto do_io;
1950     }
1951 
1952     /* other than do_combined, so --scat-file= or --lba= */
1953     if (addr_arr_len > 0)
1954         num_lbard = addr_arr_len;
1955 
1956     if (op->scat_filename && (! op->do_scat_raw)) {
1957         d = lbard_sz * (num_lbard + 1);
1958         nn = d;
1959         op->scat_lbdof = d / op->bs_pi_do;
1960         if (0 != (d % op->bs_pi_do))  /* if not multiple, round up */
1961             op->scat_lbdof += 1;
1962         dd = op->scat_lbdof * op->bs_pi_do;
1963         d = sum_num * op->bs_pi_do;
1964         do_len = dd + d;
1965         /* zeroed data-out buffer for SL+DATA */
1966         up = sg_memalign(do_len, 0, &free_up, false);
1967         if (NULL == up) {
1968             pr2serr("unable to allocate aligned memory for "
1969                     "scatterlist+data\n");
1970             return sg_convert_errno(ENOMEM);
1971         }
1972         num_lbard = 0;
1973         sum_num = 0;
1974         nn = (nn > lbard_sz) ? nn : (op->scat_lbdof *  op->bs_pi_do);
1975         ret = build_t10_scat(op->scat_filename, op->do_16, ! op->do_scattered,
1976                              up, &num_lbard, &sum_num, nn);
1977         if (ret)
1978             goto finii;
1979         /* Calculate number of bytes to read from IF (place in 'd') */
1980         d = sum_num * op->bs_pi_do;
1981         if (op->if_dlen > d) {
1982             if (op->strict || vb) {
1983                 pr2serr("DLEN > than bytes implied by sum of scatter "
1984                         "list NUMs (%u)\n", d);
1985                 if (vb > 1)
1986                     pr2serr("  num_lbard=%u, sum_num=%u actual_bs=%u",
1987                             num_lbard, sum_num, op->bs_pi_do);
1988                 if (op->strict)
1989                     goto file_err_outt;
1990             }
1991         } else if ((op->if_dlen > 0) && (op->if_dlen < d))
1992             d = op->if_dlen;
1993         if ((if_rlen > 0) && (if_rlen != d)) {
1994             bool readable_lt = (if_rlen < d);
1995 
1996             if (vb)
1997                 pr2serr("readable length (%u) of IF %s bytes implied by "
1998                         "sum of\nscatter list NUMs (%u) and DLEN\n",
1999                         (uint32_t)if_rlen,
2000                         readable_lt ? "<" : ">", d);
2001             if (op->strict) {
2002                 if ((op->strict > 1) || (! readable_lt))
2003                     goto file_err_outt;
2004             }
2005             if (readable_lt)
2006                 d = if_rlen;
2007         }
2008         if (0 != (d % op->bs_pi_do)) {
2009             if (vb || (op->strict > 1)) {
2010                 pr2serr("Calculated data-out length (0x%x) not a "
2011                         "multiple of BS (%u", d, op->bs);
2012                 if (op->bs != op->bs_pi_do)
2013                     pr2serr(" + %d(PI)", (int)op->bs_pi_do - (int)op->bs);
2014                 if (op->strict > 1) {
2015                     pr2serr(")\nexiting ...\n");
2016                     goto file_err_outt;
2017                 } else
2018                     pr2serr(")\nzero pad and continue ...\n");
2019             }
2020         }
2021         ret = bin_read(infd, up + (op->scat_lbdof * op->bs_pi_do), d,
2022                        "IF 3");
2023         if (ret)
2024             goto finii;
2025         do_len = ((op->scat_lbdof + sum_num) * op->bs_pi_do);
2026         op->numblocks = sum_num;
2027         op->xfer_bytes = sum_num * op->bs_pi_do;
2028         /* dout for scattered write with ASCII scat_file ready */
2029     } else if (op->do_scat_raw) {
2030         bool if_len_gt = false;
2031 
2032         /* guessing game for length of buffer */
2033         if (op->scat_num_lbard > 0) {
2034             dd = (op->scat_num_lbard + 1) * lbard_sz;
2035             if (sf_len < dd) {
2036                 pr2serr("SF not long enough (%u bytes) to provide RD "
2037                         "(%u) %ss\n", sf_len, dd, lbard_str);
2038                 goto file_err_outt;
2039             }
2040             nn = dd / op->bs_pi_do;
2041             if (0 != (dd % op->bs_pi_do))
2042                 nn +=1;
2043             dd = nn * op->bs_pi_do;
2044         } else
2045             dd = op->bs_pi_do;      /* guess */
2046         if (if_len > 0) {
2047             nn = if_len / op->bs_pi_do;
2048             if (0 != (if_len % op->bs_pi_do))
2049                 nn += 1;
2050             d = nn * op->bs_pi_do;
2051         } else
2052             d = op->bs_pi_do;      /* guess one LB */
2053         /* zero data-out buffer for SL+DATA */
2054         nn = dd + d;
2055         up = sg_memalign(nn, 0, &free_up, false);
2056         if (NULL == up) {
2057             pr2serr("unable to allocate aligned memory for "
2058                     "scatterlist+data\n");
2059             ret = sg_convert_errno(ENOMEM);
2060             goto finii;
2061         }
2062         ret = bin_read(sfr_fd, up, sf_len, "SF");
2063         if (ret)
2064             goto finii;
2065         if (! check_lbrds(up, dd, op, &num_lbard, &sum_num))
2066             goto file_err_outt;
2067         if (num_lbard != op->scat_num_lbard) {
2068             pr2serr("Try again with --scattered=%u\n", num_lbard);
2069             goto file_err_outt;
2070         }
2071         if ((sum_num * op->bs_pi_do) > d) {
2072             uint8_t * u2p;
2073             uint8_t * free_u2p;
2074 
2075             d = sum_num * op->bs_pi_do;
2076             nn = dd + d;
2077             u2p = sg_memalign(nn, 0, &free_u2p, false);
2078             if (NULL == u2p) {
2079                 pr2serr("unable to allocate memory for final "
2080                         "scatterlist+data\n");
2081                 ret = sg_convert_errno(ENOMEM);
2082                 goto finii;
2083             }
2084             memcpy(u2p, up, dd);
2085             free(free_up);
2086             up = u2p;
2087             free_up = free_u2p;
2088         }
2089         if ((if_len != (nn - d)) && (op->strict || vb)) {
2090             if_len_gt = (if_len > (nn - d));
2091             pr2serr("IF length (%u) %s 'sum_num' bytes (%u), ", if_len,
2092                     (if_len_gt ? ">" : "<"), nn - d);
2093             if (op->strict > 1) {
2094                 pr2serr("exiting (strict=%d)\n", op->strict);
2095                 goto file_err_outt;
2096             } else
2097                 pr2serr("continuing ...\n");
2098         }
2099         ret = bin_read(infd, up + d, (if_len_gt ? nn - d : if_len), "IF 4");
2100         if (ret)
2101             goto finii;
2102         do_len = (num_lbard + sum_num) * op->bs_pi_do;
2103         op->numblocks = sum_num;
2104         op->xfer_bytes = sum_num * op->bs_pi_do;
2105     } else if (addr_arr_len > 0) {  /* build RDs for --lba= --num= */
2106         if ((op->scat_num_lbard > 0) && (op->scat_num_lbard > addr_arr_len)) {
2107             pr2serr("%s: number given to --scattered= (%u) exceeds number of "
2108                     "--lba= elements (%u)\n", __func__, op->scat_num_lbard,
2109                     addr_arr_len);
2110             return SG_LIB_CONTRADICT;
2111         }
2112         d = lbard_sz * (num_lbard + 1);
2113         op->scat_lbdof = d / op->bs_pi_do;
2114         if (0 != (d % op->bs_pi_do))  /* if not multiple, round up */
2115             op->scat_lbdof += 1;
2116         for (sum_num = 0, k = 0; k < (int)addr_arr_len; ++k)
2117             sum_num += num_arr[k];
2118         do_len = ((op->scat_lbdof + sum_num) * op->bs_pi_do);
2119         up = sg_memalign(do_len, 0, &free_up, false);
2120         if (NULL == up) {
2121             pr2serr("unable to allocate aligned memory for "
2122                     "scatterlist+data\n");
2123             ret = sg_convert_errno(ENOMEM);
2124             goto finii;
2125         }
2126         for (n = lbard_sz, k = 0; k < (int)addr_arr_len; ++k,
2127              n += lbard_sz) {
2128             sg_put_unaligned_be64(addr_arr[k], up + n + 0);
2129             sg_put_unaligned_be32(num_arr[k], up + n + 8);
2130             if (op->do_32) {
2131                 if (0 == k) {
2132                     sg_put_unaligned_be32(op->ref_tag, up + n + 12);
2133                     sg_put_unaligned_be16(op->app_tag, up + n + 16);
2134                     sg_put_unaligned_be16(op->tag_mask, up + n + 18);
2135                 } else {
2136                     sg_put_unaligned_be32((uint32_t)DEF_RT, up + n + 12);
2137                     sg_put_unaligned_be16((uint16_t)DEF_AT, up + n + 16);
2138                     sg_put_unaligned_be16((uint16_t)DEF_TM, up + n + 18);
2139                 }
2140             }
2141         }
2142         op->numblocks = sum_num;
2143     } else {
2144         pr2serr("How did we get here??\n");
2145         goto syntax_err_outt;
2146     }
2147 do_io:
2148     ret = do_write_x(sg_fd, up, do_len, op);
2149     if (ret) {
2150         strcpy(b,"OS error");
2151         if (ret > 0)
2152             sg_get_category_sense_str(ret, sizeof(b), b, vb);
2153         pr2serr("%s: %s\n", op->cdb_name, b);
2154     }
2155     goto finii;
2156 
2157 syntax_err_outt:
2158     ret = SG_LIB_SYNTAX_ERROR;
2159     goto finii;
2160 file_err_outt:
2161     ret = SG_LIB_FILE_ERROR;
2162 finii:
2163     if (free_up)
2164         free(free_up);
2165     return ret;
2166 }
2167 
2168 
2169 int
main(int argc,char * argv[])2170 main(int argc, char * argv[])
2171 {
2172     bool got_stdin = false;
2173     bool got_stat = false;
2174     bool if_reg_file = false;
2175     int n, err, vb;
2176     int infd = -1;
2177     int sg_fd = -1;
2178     int sfr_fd = -1;
2179     int ret = -1;
2180     uint32_t nn, addr_arr_len, num_arr_len;     /* --lba= */
2181     uint32_t do_len = 0;
2182     uint16_t num_lbard = 0;
2183     uint32_t if_len = 0;    /* after accounting for OFF,DLEN and moving file
2184                              * file pointer to OFF, is bytes available in IF */
2185     uint32_t sf_len = 0;
2186     uint32_t sum_num = 0;
2187     ssize_t res;
2188     off_t if_readable_len = 0;  /* similar to if_len but doesn't take DLEN
2189                                  * into account */
2190     struct opts_t * op;
2191     const char * lba_op = NULL;
2192     const char * num_op = NULL;
2193     uint8_t * up = NULL;
2194     uint8_t * free_up = NULL;
2195     char ebuff[EBUFF_SZ];
2196     char b[80];
2197     uint64_t addr_arr[MAX_NUM_ADDR];
2198     uint32_t num_arr[MAX_NUM_ADDR];
2199     struct stat if_stat, sf_stat;
2200     struct opts_t opts SG_C_CPP_ZERO_INIT;
2201 
2202     op = &opts;
2203     memset(&if_stat, 0, sizeof(if_stat));
2204     memset(&sf_stat, 0, sizeof(sf_stat));
2205     op->numblocks = DEF_WR_NUMBLOCKS;
2206     op->pi_type = -1;           /* Protection information type unknown */
2207     op->ref_tag = DEF_RT;       /* first 4 bytes of 8 byte protection info */
2208     op->app_tag = DEF_AT;       /* 2 bytes of protection information */
2209     op->tag_mask = DEF_TM;      /* final 2 bytes of protection information */
2210     op->timeout = DEF_TIMEOUT_SECS;
2211 
2212     /* Process command line */
2213     ret = parse_cmd_line(op, argc, argv, &lba_op, &num_op);
2214     if (ret) {
2215         if (WANT_ZERO_EXIT == ret)
2216             return 0;
2217         return ret;
2218     }
2219     if (op->help > 0) {
2220         usage(op->help);
2221         return 0;
2222     }
2223 
2224 #ifdef DEBUG
2225     pr2serr("In DEBUG mode, ");
2226     if (op->verbose_given && op->version_given) {
2227         pr2serr("but override: '-vV' given, zero verbose and continue\n");
2228         op->verbose_given = false;
2229         op->version_given = false;
2230         op->verbose = 0;
2231     } else if (! op->verbose_given) {
2232         pr2serr("set '-vv'\n");
2233         op->verbose = 2;
2234     } else
2235         pr2serr("keep verbose=%d\n", op->verbose);
2236 #else
2237     if (op->verbose_given && op->version_given)
2238         pr2serr("Not in DEBUG mode, so '-vV' has no special action\n");
2239 #endif
2240     if (op->version_given) {
2241         pr2serr("sg_write_x version: %s\n", version_str);
2242         return WANT_ZERO_EXIT;
2243     }
2244 
2245     vb = op->verbose;
2246     /* sanity checks */
2247     if ((! op->do_16) && (! op->do_32)) {
2248         op->do_16 = true;
2249         if (vb > 1)
2250             pr2serr("Since neither --16 nor --32 given, choose --16\n");
2251     } else if (op->do_16 && op->do_32) {
2252         op->do_16 = false;
2253         if (vb > 1)
2254             pr2serr("Since both --16 and --32 given, choose --32\n");
2255     }
2256     n = (int)op->do_atomic + (int)op->do_write_normal + (int)op->do_or +
2257         (int)op->do_same + (int)op->do_scattered + (int)op->do_stream;
2258     if (n > 1) {
2259         pr2serr("Can only select one command; so only one of --atomic, "
2260                 "--normal, --or,\n--same=, --scattered= or --stream=\n") ;
2261         return SG_LIB_CONTRADICT;
2262     } else if (n < 1) {
2263         if (op->strict) {
2264             pr2serr("With --strict won't default to a normal WRITE, add "
2265                     "--normal\n");
2266             return SG_LIB_CONTRADICT;
2267         } else {
2268             op->do_write_normal = true;
2269             op->cmd_name = "Write";
2270             if (vb)
2271                 pr2serr("No command selected so choose 'normal' WRITE\n");
2272         }
2273     }
2274     snprintf(op->cdb_name, sizeof(op->cdb_name), "%s(%d)", op->cmd_name,
2275              (op->do_16 ? 16 : 32));
2276     if (op->do_combined) {
2277         if (! op->do_scattered) {
2278             pr2serr("--combined=DOF only allowed with --scattered=RD (i.e. "
2279                     "only with\nWRITE SCATTERED command)\n");
2280             return SG_LIB_CONTRADICT;
2281         }
2282         if (op->scat_filename) {
2283             pr2serr("Ambiguous: got --combined=DOF and --scat-file=SF .\n"
2284                     "Give one, the other or neither\n");
2285             return SG_LIB_CONTRADICT;
2286         }
2287         if (lba_op || num_op) {
2288             pr2serr("--scattered=RD --combined=DOF does not use --lba= or "
2289                     "--num=\nPlease remove.\n");
2290             return SG_LIB_CONTRADICT;
2291         }
2292         if (op->do_scat_raw) {
2293             pr2serr("Ambiguous: don't expect --combined=DOF and --scat-raw\n"
2294                     "Give one or the other\n");
2295             return SG_LIB_CONTRADICT;
2296         }
2297     }
2298     if ((NULL == op->scat_filename) && op->do_scat_raw) {
2299         pr2serr("--scat-raw only applies to the --scat-file=SF option\n"
2300                 "--scat-raw without the --scat-file=SF option is an "
2301                 "error\n");
2302         return SG_LIB_CONTRADICT;
2303     }
2304     n = (!! op->scat_filename) + (!! (lba_op || num_op)) +
2305         (!! op->do_combined);
2306     if (n > 1) {
2307         pr2serr("want one and only one of: (--lba=LBA and/or --num=NUM), or\n"
2308                 "--scat-file=SF, or --combined=DOF\n");
2309         return SG_LIB_CONTRADICT;
2310     }
2311     if (op->scat_filename && (1 == strlen(op->scat_filename)) &&
2312         ('-' == op->scat_filename[0])) {
2313         pr2serr("don't accept '-' (implying stdin) as a filename in "
2314                 "--scat-file=SF\n");
2315         return SG_LIB_CONTRADICT;
2316     }
2317     if (vb && op->do_16 && (! is_pi_default(op)))
2318         pr2serr("--app-tag=, --ref-tag= and --tag-mask= options ignored "
2319                 "with 16 byte commands\n");
2320 
2321     /* examine .if_name . Open, move to .if_offset, calculate length that we
2322      * want to read. */
2323     if (! op->ndob) {           /* as long as --same=1 is not active */
2324         if_len = op->if_dlen;   /* from --offset=OFF,DLEN; defaults to 0 */
2325         if (NULL == op->if_name) {
2326             pr2serr("Need --if=FN option to be given, exiting.\n");
2327             if (vb > 1)
2328                 pr2serr("To write zeros use --in=/dev/zero\n");
2329             pr2serr("\n");
2330             usage((op->help > 0) ? op->help : 0);
2331             return SG_LIB_SYNTAX_ERROR;
2332         }
2333         if ((1 == strlen(op->if_name)) && ('-' == op->if_name[0])) {
2334             got_stdin = true;
2335             infd = STDIN_FILENO;
2336             if (sg_set_binary_mode(STDIN_FILENO) < 0) {
2337                 perror("sg_set_binary_mode");
2338                 return SG_LIB_FILE_ERROR;
2339             }
2340         } else {
2341             if ((infd = open(op->if_name, O_RDONLY)) < 0) {
2342                 err = errno;
2343                 snprintf(ebuff, EBUFF_SZ, "could not open %s for reading",
2344                          op->if_name);
2345                 perror(ebuff);
2346                 return sg_convert_errno(err);
2347             }
2348             if (sg_set_binary_mode(infd) < 0) {
2349                 perror("sg_set_binary_mode");
2350                 return SG_LIB_FILE_ERROR;
2351             }
2352             if (fstat(infd, &if_stat) < 0) {
2353                 err = errno;
2354                 snprintf(ebuff, EBUFF_SZ, "could not fstat %s", op->if_name);
2355                 perror(ebuff);
2356                 return sg_convert_errno(err);
2357             }
2358             got_stat = true;
2359             if (S_ISREG(if_stat.st_mode)) {
2360                 if_reg_file = true;
2361                 if_readable_len = if_stat.st_size;
2362                 if (0 == if_len)
2363                     if_len = if_readable_len;
2364             }
2365         }
2366         if (got_stat && if_readable_len &&
2367             ((int64_t)op->if_offset >= (if_readable_len - 1))) {
2368             pr2serr("Offset (%" PRIu64 ") is at or beyond IF byte length (%"
2369                     PRIu64 ")\n", op->if_offset, (uint64_t)if_readable_len);
2370             goto file_err_out;
2371         }
2372         if (op->if_offset > 0) {
2373             off_t off = op->if_offset;
2374             off_t h = if_readable_len;
2375 
2376             if (if_reg_file) {
2377                 /* lseek() won't work with stdin, pipes or sockets, etc */
2378                 if (lseek(infd, off, SEEK_SET) < 0) {
2379                     err = errno;
2380                     snprintf(ebuff,  EBUFF_SZ, "couldn't offset to required "
2381                             "position on %s", op->if_name);
2382                     perror(ebuff);
2383                     ret = sg_convert_errno(err);
2384                     goto err_out;
2385                 }
2386                 if_readable_len -= op->if_offset;
2387                 if (if_readable_len <= 0) {
2388                     pr2serr("--offset [0x%" PRIx64 "] at or beyond file "
2389                             "length[0x%" PRIx64 "]\n",
2390                             (uint64_t)op->if_offset, (uint64_t)h);
2391                     goto file_err_out;
2392                 }
2393                 if (op->strict && ((off_t)op->if_dlen > if_readable_len)) {
2394                     pr2serr("after accounting for OFF, DLEN exceeds %s "
2395                             "remaining length (%u bytes)\n",
2396                             op->if_name, (uint32_t)if_readable_len);
2397                     goto file_err_out;
2398                 }
2399                 if_len = (uint32_t)((if_readable_len < (off_t)if_len) ?
2400                                 if_readable_len : (off_t)if_len);
2401                 if (vb > 2)
2402                     pr2serr("Moved IF byte pointer to %u, if_len=%u, "
2403                             "if_readable_len=%u\n", (uint32_t)op->if_offset,
2404                             if_len, (uint32_t)if_readable_len);
2405             } else {
2406                 if (vb)
2407                     pr2serr("--offset=OFF ignored when IF is stdin, pipe, "
2408                             "socket, etc\nDLEN, if given, is used\n");
2409             }
2410         }
2411     }
2412     /* Check device name has been given */
2413     if (NULL == op->device_name) {
2414         pr2serr("missing device name!\n");
2415         usage((op->help > 0) ? op->help : 0);
2416         goto syntax_err_out;
2417     }
2418 
2419     /* Open device file, do READ CAPACITY(16, maybe 10) if no BS */
2420     sg_fd = sg_cmds_open_device(op->device_name, false /* rw */, vb);
2421     if (sg_fd < 0) {
2422         if (op->verbose)
2423             pr2serr("open error: %s: %s\n", op->device_name,
2424                     safe_strerror(-sg_fd));
2425         ret = sg_convert_errno(-sg_fd);
2426         goto fini;
2427     }
2428     if (0 == op->bs) {  /* ask DEVICE about logical/actual block size */
2429         ret = do_read_capacity(sg_fd, op);
2430         if (ret)
2431             goto err_out;
2432     }
2433     if ((0 == op->bs_pi_do) || (0 == op->bs)) {
2434         pr2serr("Logic error, need block size by now\n");
2435         goto syntax_err_out;
2436     }
2437     if (! op->ndob) {
2438         if (0 != (if_len % op->bs_pi_do)) {
2439             if (op->strict > 1) {
2440                 pr2serr("Error: number of bytes to read from IF [%u] is "
2441                         "not a multiple\nblock size %u (including "
2442                         "protection information)\n", (unsigned int)if_len,
2443                         op->bs_pi_do);
2444                 goto file_err_out;
2445             }
2446             if (op->strict || vb)
2447                 pr2serr("Warning: number of bytes to read from IF [%u] is "
2448                         "not a multiple\nof actual block size %u; pad with "
2449                         "zeros\n", (unsigned int)if_len, op->bs_pi_do);
2450         }
2451     }
2452 
2453     /* decode --lba= and --num= options */
2454     memset(addr_arr, 0, sizeof(addr_arr));
2455     memset(num_arr, 0, sizeof(num_arr));
2456     addr_arr_len = 0;
2457     num_arr_len = 0;
2458     if (lba_op) {
2459         if (0 != build_lba_arr(lba_op, addr_arr, &addr_arr_len,
2460                                MAX_NUM_ADDR)) {
2461             pr2serr("bad argument to '--lba'\n");
2462             goto syntax_err_out;
2463         }
2464     }
2465     if (num_op) {
2466         if (0 != build_num_arr(num_op, num_arr, &num_arr_len,
2467                                MAX_NUM_ADDR)) {
2468             pr2serr("bad argument to '--num'\n");
2469             goto err_out;
2470         }
2471     }
2472     if (((addr_arr_len > 1) && (addr_arr_len != num_arr_len)) ||
2473         ((0 == addr_arr_len) && (num_arr_len > 1))) {
2474         /* allow all combinations of 0 or 1 element --lba= with 0 or 1
2475          * element --num=, otherwise this error ... */
2476         pr2serr("need same number of arguments to '--lba=' and '--num=' "
2477                     "options\n");
2478         ret = SG_LIB_CONTRADICT;
2479         goto err_out;
2480     }
2481     if ((0 == addr_arr_len) && (1 == num_arr_len)) {
2482         if (num_arr[0] > 0) {
2483             pr2serr("won't write %u blocks without an explicit --lba= "
2484                     "option\n", num_arr[0]);
2485             goto syntax_err_out;
2486         }
2487         addr_arr_len = 1;  /* allow --num=0 without --lba= since it is safe */
2488     }
2489     /* Everything can use a SF, except --same=1 (when op->ndob==true) */
2490     if (op->scat_filename) {
2491         if (stat(op->scat_filename, &sf_stat) < 0) {
2492             err = errno;
2493             pr2serr("Unable to stat(%s) as SF: %s\n", op->scat_filename,
2494                     safe_strerror(err));
2495             ret = sg_convert_errno(err);
2496             goto err_out;
2497         }
2498         if (op->do_scat_raw) {
2499             if (! S_ISREG(sf_stat.st_mode)) {
2500                 pr2serr("Expect scatter file to be a regular file\n");
2501                 goto file_err_out;
2502             }
2503             sf_len = sf_stat.st_size;
2504             sfr_fd = open(op->scat_filename, O_RDONLY);
2505             if (sfr_fd < 0) {
2506                 err = errno;
2507                 pr2serr("Failed to open %s for raw read: %s\n",
2508                         op->scat_filename, safe_strerror(err));
2509                 ret = sg_convert_errno(err);
2510                 goto err_out;
2511             }
2512             if (sg_set_binary_mode(sfr_fd) < 0) {
2513                 perror("sg_set_binary_mode");
2514                 goto file_err_out;
2515             }
2516         } else { /* scat_file should contain ASCII hex, preliminary parse */
2517             nn = (op->scat_num_lbard > 0) ?
2518                                 lbard_sz * (1 + op->scat_num_lbard) : 0;
2519             ret = build_t10_scat(op->scat_filename, op->do_16,
2520                                  ! op->do_scattered, NULL, &num_lbard,
2521                                  &sum_num, nn);
2522             if (ret)
2523                 goto err_out;
2524             if ((op->scat_num_lbard > 0) &&
2525                 (num_lbard != op->scat_num_lbard)) {
2526                 bool rd_gt = (op->scat_num_lbard > num_lbard);
2527 
2528                 if (rd_gt || op->strict || vb) {
2529                     pr2serr("RD (%u) %s number of %ss (%u) found in SF\n",
2530                             op->scat_num_lbard, (rd_gt ? ">" : "<"),
2531                             lbard_str, num_lbard);
2532                     if (rd_gt)
2533                         goto file_err_out;
2534                     else if (op->strict)
2535                         goto file_err_out;
2536                 }
2537             }
2538         }
2539     }
2540 
2541     if (op->do_scattered) {
2542         ret = process_scattered(sg_fd, infd, if_len, if_readable_len, sfr_fd,
2543                                 sf_len, addr_arr, addr_arr_len, num_arr,
2544                                 num_lbard, sum_num, op);
2545         goto fini;
2546     }
2547 
2548     /* other than scattered */
2549     if (addr_arr_len > 0) {
2550         op->lba = addr_arr[0];
2551         op->numblocks = num_arr[0];
2552         if (vb && (addr_arr_len > 1))
2553             pr2serr("warning: %d LBA,number_of_blocks pairs found, only "
2554                     "taking first\n", addr_arr_len);
2555     } else if (op->scat_filename && (! op->do_scat_raw)) {
2556         uint8_t upp[96];
2557 
2558         sum_num = 0;
2559         ret = build_t10_scat(op->scat_filename, op->do_16,
2560                              true /* parse one */, upp, &num_lbard,
2561                              &sum_num, sizeof(upp));
2562         if (ret)
2563             goto err_out;
2564         if (vb && (num_lbard > 1))
2565             pr2serr("warning: %d LBA,number_of_blocks pairs found, only "
2566                     "taking first\n", num_lbard);
2567         if (vb > 2)
2568             pr2serr("after build_t10_scat, num_lbard=%u, sum_num=%u\n",
2569                     num_lbard, sum_num);
2570         if (1 != num_lbard) {
2571             pr2serr("Unable to decode one LBA range descriptor from %s\n",
2572                     op->scat_filename);
2573             goto file_err_out;
2574         }
2575         op->lba = sg_get_unaligned_be64(upp + 32 + 0);
2576         op->numblocks = sg_get_unaligned_be32(upp + 32 + 8);
2577         if (op->do_32) {
2578             op->ref_tag = sg_get_unaligned_be32(upp + 32 + 12);
2579             op->app_tag = sg_get_unaligned_be16(upp + 32 + 16);
2580             op->tag_mask = sg_get_unaligned_be16(upp + 32 + 18);
2581         }
2582     } else if (op->do_scat_raw) {
2583         uint8_t upp[64];
2584 
2585         if (sf_len < (2 * lbard_sz)) {
2586             pr2serr("raw scatter file must be at least 64 bytes long "
2587                     "(length: %u)\n", sf_len);
2588             goto file_err_out;
2589         }
2590         ret = bin_read(sfr_fd, upp, sizeof(upp), "SF");
2591         if (ret)
2592             goto err_out;
2593         if (! check_lbrds(upp, sizeof(upp), op, &num_lbard, &sum_num))
2594             goto file_err_out;
2595         if (1 != num_lbard) {
2596             pr2serr("No %ss found in SF (num=%u)\n", lbard_str, num_lbard);
2597             goto file_err_out;
2598         }
2599         op->lba = sg_get_unaligned_be64(upp + 16);
2600         op->numblocks = sg_get_unaligned_be32(upp + 16 + 8);
2601         do_len = sum_num * op->bs_pi_do;
2602         op->xfer_bytes = do_len;
2603     } else {
2604         pr2serr("No LBA or number_of_blocks given, try using --lba= and "
2605                 "--num=\n");
2606         goto syntax_err_out;
2607     }
2608     if (op->do_same)
2609         op->xfer_bytes = op->ndob ? 0 : op->bs_pi_do;
2610     else    /* WRITE, ORWRITE, WRITE ATOMIC or WRITE STREAM */
2611         op->xfer_bytes = op->numblocks * op->bs_pi_do;
2612     do_len = op->xfer_bytes;
2613 
2614     if (do_len > 0) {
2615         /* fill allocated buffer with zeros */
2616         up = sg_memalign(do_len, 0, &free_up, false);
2617         if (NULL == up) {
2618             pr2serr("unable to allocate %u bytes of memory\n", do_len);
2619             ret = sg_convert_errno(ENOMEM);
2620             goto err_out;
2621         }
2622         ret = bin_read(infd, up, ((if_len < do_len) ? if_len : do_len),
2623                        "IF 5");
2624         if (ret)
2625             goto fini;
2626     } else
2627         up = NULL;
2628 
2629     ret = do_write_x(sg_fd, up, do_len, op);
2630     if (ret && (! op->do_quiet)) {
2631         strcpy(b,"OS error");
2632         if (ret > 0)
2633             sg_get_category_sense_str(ret, sizeof(b), b, vb);
2634         pr2serr("%s: %s\n", op->cdb_name, b);
2635     }
2636     goto fini;
2637 
2638 syntax_err_out:
2639     ret = SG_LIB_SYNTAX_ERROR;
2640     goto err_out;
2641 file_err_out:
2642     ret = SG_LIB_FILE_ERROR;
2643 err_out:
2644 fini:
2645     if (free_up)
2646         free(free_up);
2647     if (sg_fd >= 0) {
2648         res = sg_cmds_close_device(sg_fd);
2649         if (res < 0) {
2650             if (! op->do_quiet)
2651                 pr2serr("sg_fd close error: %s\n", safe_strerror(-res));
2652             if (0 == ret)
2653                 ret = SG_LIB_FILE_ERROR;
2654         }
2655     }
2656     if (sfr_fd >= 0) {
2657         if (close(sfr_fd) < 0) {
2658             if (! op->do_quiet)
2659                 perror("sfr_fd close error");
2660             if (0 == ret)
2661                 ret = SG_LIB_FILE_ERROR;
2662         }
2663     }
2664     if ((! got_stdin) && (infd >= 0)) {
2665         if (close(infd) < 0) {
2666             if (! op->do_quiet)
2667                 perror("infd close error");
2668             if (0 == ret)
2669                 ret = SG_LIB_FILE_ERROR;
2670         }
2671     }
2672     if ((0 == op->verbose) && (! op->do_quiet)) {
2673         if (! sg_if_can2stderr("sg_write_x failed: ", ret))
2674             pr2serr("Some error occurred, try again with '-v' or '-vv' for "
2675                     "more information\n");
2676     }
2677     return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
2678 }
2679