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