1*44704f69SBart Van Assche /*
2*44704f69SBart Van Assche * Copyright (c) 2014-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 * This program issues the SCSI command WRITE AND VERIFY to a given SCSI
10*44704f69SBart Van Assche * device. It sends the command with the logical block address passed as the
11*44704f69SBart Van Assche * LBA argument, for the given number of blocks. The number of bytes sent is
12*44704f69SBart Van Assche * supplied separately, either by the size of the given file (IF) or
13*44704f69SBart Van Assche * explicitly with ILEN.
14*44704f69SBart Van Assche *
15*44704f69SBart Van Assche * This code was contributed by Bruno Goncalves
16*44704f69SBart Van Assche */
17*44704f69SBart Van Assche
18*44704f69SBart Van Assche #include <unistd.h>
19*44704f69SBart Van Assche #include <fcntl.h>
20*44704f69SBart Van Assche #include <stdio.h>
21*44704f69SBart Van Assche #include <stdlib.h>
22*44704f69SBart Van Assche #include <stdarg.h>
23*44704f69SBart Van Assche #include <stdbool.h>
24*44704f69SBart Van Assche #include <string.h>
25*44704f69SBart Van Assche #include <errno.h>
26*44704f69SBart Van Assche #include <limits.h>
27*44704f69SBart Van Assche #include <getopt.h>
28*44704f69SBart Van Assche #include <sys/types.h>
29*44704f69SBart Van Assche #include <sys/stat.h>
30*44704f69SBart Van Assche #define __STDC_FORMAT_MACROS 1
31*44704f69SBart Van Assche #include <inttypes.h>
32*44704f69SBart Van Assche
33*44704f69SBart Van Assche #ifdef HAVE_CONFIG_H
34*44704f69SBart Van Assche #include "config.h"
35*44704f69SBart Van Assche #endif
36*44704f69SBart Van Assche
37*44704f69SBart Van Assche #include "sg_lib.h"
38*44704f69SBart Van Assche #include "sg_pt.h"
39*44704f69SBart Van Assche #include "sg_cmds_basic.h"
40*44704f69SBart Van Assche #include "sg_unaligned.h"
41*44704f69SBart Van Assche #include "sg_pr2serr.h"
42*44704f69SBart Van Assche
43*44704f69SBart Van Assche static const char * version_str = "1.21 20220127";
44*44704f69SBart Van Assche
45*44704f69SBart Van Assche
46*44704f69SBart Van Assche #define ME "sg_write_verify: "
47*44704f69SBart Van Assche
48*44704f69SBart Van Assche #define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */
49*44704f69SBart Van Assche
50*44704f69SBart Van Assche #define WRITE_VERIFY10_CMD 0x2e
51*44704f69SBart Van Assche #define WRITE_VERIFY10_CMDLEN 10
52*44704f69SBart Van Assche #define WRITE_VERIFY16_CMD 0x8e
53*44704f69SBart Van Assche #define WRITE_VERIFY16_CMDLEN 16
54*44704f69SBart Van Assche
55*44704f69SBart Van Assche #define WRPROTECT_MASK (0x7)
56*44704f69SBart Van Assche #define WRPROTECT_SHIFT (5)
57*44704f69SBart Van Assche
58*44704f69SBart Van Assche #define DEF_TIMEOUT_SECS 60
59*44704f69SBart Van Assche
60*44704f69SBart Van Assche
61*44704f69SBart Van Assche static struct option long_options[] = {
62*44704f69SBart Van Assche {"16", no_argument, 0, 'S'},
63*44704f69SBart Van Assche {"bytchk", required_argument, 0, 'b'},
64*44704f69SBart Van Assche {"dpo", no_argument, 0, 'd'},
65*44704f69SBart Van Assche {"group", required_argument, 0, 'g'},
66*44704f69SBart Van Assche {"help", no_argument, 0, 'h'},
67*44704f69SBart Van Assche {"ilen", required_argument, 0, 'I'},
68*44704f69SBart Van Assche {"in", required_argument, 0, 'i'},
69*44704f69SBart Van Assche {"lba", required_argument, 0, 'l'},
70*44704f69SBart Van Assche {"num", required_argument, 0, 'n'},
71*44704f69SBart Van Assche {"repeat", no_argument, 0, 'R'},
72*44704f69SBart Van Assche {"timeout", required_argument, 0, 't'},
73*44704f69SBart Van Assche {"verbose", no_argument, 0, 'v'},
74*44704f69SBart Van Assche {"version", no_argument, 0, 'V'},
75*44704f69SBart Van Assche {"wrprotect", required_argument, 0, 'w'},
76*44704f69SBart Van Assche {0, 0, 0, 0},
77*44704f69SBart Van Assche };
78*44704f69SBart Van Assche
79*44704f69SBart Van Assche
80*44704f69SBart Van Assche static void
usage()81*44704f69SBart Van Assche usage()
82*44704f69SBart Van Assche {
83*44704f69SBart Van Assche pr2serr("Usage: sg_write_verify [--16] [--bytchk=BC] [--dpo] [--group=GN] "
84*44704f69SBart Van Assche "[--help]\n"
85*44704f69SBart Van Assche " [--ilen=IL] [--in=IF] --lba=LBA "
86*44704f69SBart Van Assche "[--num=NUM]\n"
87*44704f69SBart Van Assche " [--repeat] [--timeout=TO] [--verbose] "
88*44704f69SBart Van Assche "[--version]\n"
89*44704f69SBart Van Assche " [--wrprotect=WPR] DEVICE\n"
90*44704f69SBart Van Assche " where:\n"
91*44704f69SBart Van Assche " --16|-S do WRITE AND VERIFY(16) (default: 10)\n"
92*44704f69SBart Van Assche " --bytchk=BC|-b BC set BYTCHK field (default: 0)\n"
93*44704f69SBart Van Assche " --dpo|-d set DPO bit (default: 0)\n"
94*44704f69SBart Van Assche " --group=GN|-g GN GN is group number (default: 0)\n"
95*44704f69SBart Van Assche " --help|-h print out usage message\n"
96*44704f69SBart Van Assche " --ilen=IL| -I IL input (file) length in bytes, becomes "
97*44704f69SBart Van Assche "data-out\n"
98*44704f69SBart Van Assche " buffer length (def: deduced from IF "
99*44704f69SBart Van Assche "size)\n"
100*44704f69SBart Van Assche " --in=IF|-i IF IF is a file containing the data to "
101*44704f69SBart Van Assche "be written\n"
102*44704f69SBart Van Assche " --lba=LBA|-l LBA LBA of the first block to write "
103*44704f69SBart Van Assche "and verify;\n"
104*44704f69SBart Van Assche " no default, must be given\n"
105*44704f69SBart Van Assche " --num=NUM|-n NUM logical blocks to write and verify "
106*44704f69SBart Van Assche "(def: 1)\n"
107*44704f69SBart Van Assche " --repeat|-R while IF still has data to read, send "
108*44704f69SBart Van Assche "another\n"
109*44704f69SBart Van Assche " command, bumping LBA with up to NUM "
110*44704f69SBart Van Assche "blocks again\n"
111*44704f69SBart Van Assche " --timeout=TO|-t TO command timeout in seconds (def: 60)\n"
112*44704f69SBart Van Assche " --verbose|-v increase verbosity\n"
113*44704f69SBart Van Assche " --version|-V print version string then exit\n"
114*44704f69SBart Van Assche " --wrprotect|-w WPR WPR is the WRPROTECT field value "
115*44704f69SBart Van Assche "(def: 0)\n\n"
116*44704f69SBart Van Assche "Performs a SCSI WRITE AND VERIFY (10 or 16) command on DEVICE, "
117*44704f69SBart Van Assche "startings\nat LBA for NUM logical blocks. More commands "
118*44704f69SBart Van Assche "performed only if '--repeat'\noption given. Data to be written "
119*44704f69SBart Van Assche "is fetched from the IF file.\n"
120*44704f69SBart Van Assche );
121*44704f69SBart Van Assche }
122*44704f69SBart Van Assche
123*44704f69SBart Van Assche /* Invokes a SCSI WRITE AND VERIFY according with CDB. Returns 0 -> success,
124*44704f69SBart Van Assche * various SG_LIB_CAT_* positive values or -1 -> other errors */
125*44704f69SBart Van Assche static int
run_scsi_transaction(int sg_fd,const uint8_t * cdbp,int cdb_len,uint8_t * dop,int do_len,int timeout,bool noisy,int verbose)126*44704f69SBart Van Assche run_scsi_transaction(int sg_fd, const uint8_t *cdbp, int cdb_len,
127*44704f69SBart Van Assche uint8_t *dop, int do_len, int timeout,
128*44704f69SBart Van Assche bool noisy, int verbose)
129*44704f69SBart Van Assche {
130*44704f69SBart Van Assche int res, sense_cat, ret;
131*44704f69SBart Van Assche struct sg_pt_base * ptvp;
132*44704f69SBart Van Assche uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT;
133*44704f69SBart Van Assche char b[32];
134*44704f69SBart Van Assche
135*44704f69SBart Van Assche snprintf(b, sizeof(b), "Write and verify(%d)", cdb_len);
136*44704f69SBart Van Assche if (verbose) {
137*44704f69SBart Van Assche char d[128];
138*44704f69SBart Van Assche
139*44704f69SBart Van Assche pr2serr(" %s cdb: %s\n", b,
140*44704f69SBart Van Assche sg_get_command_str(cdbp, cdb_len, false, sizeof(d), d));
141*44704f69SBart Van Assche if ((verbose > 2) && dop && do_len) {
142*44704f69SBart Van Assche pr2serr(" Data out buffer [%d bytes]:\n", do_len);
143*44704f69SBart Van Assche hex2stderr(dop, do_len, -1);
144*44704f69SBart Van Assche }
145*44704f69SBart Van Assche }
146*44704f69SBart Van Assche ptvp = construct_scsi_pt_obj();
147*44704f69SBart Van Assche if (NULL == ptvp) {
148*44704f69SBart Van Assche pr2serr("%s: out of memory\n", b);
149*44704f69SBart Van Assche return -1;
150*44704f69SBart Van Assche }
151*44704f69SBart Van Assche set_scsi_pt_cdb(ptvp, cdbp, cdb_len);
152*44704f69SBart Van Assche set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
153*44704f69SBart Van Assche set_scsi_pt_data_out(ptvp, dop, do_len);
154*44704f69SBart Van Assche res = do_scsi_pt(ptvp, sg_fd, timeout, verbose);
155*44704f69SBart Van Assche ret = sg_cmds_process_resp(ptvp, b, res, noisy, verbose, &sense_cat);
156*44704f69SBart Van Assche if (-1 == ret) {
157*44704f69SBart Van Assche if (get_scsi_pt_transport_err(ptvp))
158*44704f69SBart Van Assche ret = SG_LIB_TRANSPORT_ERROR;
159*44704f69SBart Van Assche else
160*44704f69SBart Van Assche ret = sg_convert_errno(get_scsi_pt_os_err(ptvp));
161*44704f69SBart Van Assche } else if (-2 == ret) {
162*44704f69SBart Van Assche switch (sense_cat) {
163*44704f69SBart Van Assche case SG_LIB_CAT_RECOVERED:
164*44704f69SBart Van Assche case SG_LIB_CAT_NO_SENSE:
165*44704f69SBart Van Assche ret = 0;
166*44704f69SBart Van Assche break;
167*44704f69SBart Van Assche case SG_LIB_CAT_MEDIUM_HARD: /* write or verify failed */
168*44704f69SBart Van Assche {
169*44704f69SBart Van Assche bool valid;
170*44704f69SBart Van Assche int slen;
171*44704f69SBart Van Assche uint64_t ull = 0;
172*44704f69SBart Van Assche
173*44704f69SBart Van Assche slen = get_scsi_pt_sense_len(ptvp);
174*44704f69SBart Van Assche valid = sg_get_sense_info_fld(sense_b, slen, &ull);
175*44704f69SBart Van Assche if (valid)
176*44704f69SBart Van Assche pr2serr("Medium or hardware error starting at lba=%"
177*44704f69SBart Van Assche PRIu64 " [0x%" PRIx64 "]\n", ull, ull);
178*44704f69SBart Van Assche }
179*44704f69SBart Van Assche ret = sense_cat;
180*44704f69SBart Van Assche break;
181*44704f69SBart Van Assche case SG_LIB_CAT_ILLEGAL_REQ:
182*44704f69SBart Van Assche if (verbose)
183*44704f69SBart Van Assche sg_print_command_len(cdbp, cdb_len);
184*44704f69SBart Van Assche /* FALL THROUGH */
185*44704f69SBart Van Assche case SG_LIB_CAT_PROTECTION: /* PI failure */
186*44704f69SBart Van Assche case SG_LIB_CAT_MISCOMPARE: /* only in bytchk=1 case */
187*44704f69SBart Van Assche default:
188*44704f69SBart Van Assche ret = sense_cat;
189*44704f69SBart Van Assche break;
190*44704f69SBart Van Assche }
191*44704f69SBart Van Assche } else
192*44704f69SBart Van Assche ret = 0;
193*44704f69SBart Van Assche
194*44704f69SBart Van Assche destruct_scsi_pt_obj(ptvp);
195*44704f69SBart Van Assche return ret;
196*44704f69SBart Van Assche }
197*44704f69SBart Van Assche
198*44704f69SBart Van Assche /* Invokes a SCSI WRITE AND VERIFY (10) command (SBC). Returns 0 -> success,
199*44704f69SBart Van Assche * various SG_LIB_CAT_* positive values or -1 -> other errors */
200*44704f69SBart Van Assche static int
sg_ll_write_verify10(int sg_fd,int wrprotect,bool dpo,int bytchk,unsigned int lba,int num_lb,int group,uint8_t * dop,int do_len,int timeout,bool noisy,int verbose)201*44704f69SBart Van Assche sg_ll_write_verify10(int sg_fd, int wrprotect, bool dpo, int bytchk,
202*44704f69SBart Van Assche unsigned int lba, int num_lb, int group,
203*44704f69SBart Van Assche uint8_t *dop, int do_len, int timeout,
204*44704f69SBart Van Assche bool noisy, int verbose)
205*44704f69SBart Van Assche {
206*44704f69SBart Van Assche int ret;
207*44704f69SBart Van Assche uint8_t wv_cdb[WRITE_VERIFY10_CMDLEN];
208*44704f69SBart Van Assche
209*44704f69SBart Van Assche memset(wv_cdb, 0, WRITE_VERIFY10_CMDLEN);
210*44704f69SBart Van Assche wv_cdb[0] = WRITE_VERIFY10_CMD;
211*44704f69SBart Van Assche wv_cdb[1] = ((wrprotect & WRPROTECT_MASK) << WRPROTECT_SHIFT);
212*44704f69SBart Van Assche if (dpo)
213*44704f69SBart Van Assche wv_cdb[1] |= 0x10;
214*44704f69SBart Van Assche if (bytchk)
215*44704f69SBart Van Assche wv_cdb[1] |= ((bytchk & 0x3) << 1);
216*44704f69SBart Van Assche
217*44704f69SBart Van Assche sg_put_unaligned_be32((uint32_t)lba, wv_cdb + 2);
218*44704f69SBart Van Assche wv_cdb[6] = group & GRPNUM_MASK;
219*44704f69SBart Van Assche sg_put_unaligned_be16((uint16_t)num_lb, wv_cdb + 7);
220*44704f69SBart Van Assche ret = run_scsi_transaction(sg_fd, wv_cdb, sizeof(wv_cdb), dop, do_len,
221*44704f69SBart Van Assche timeout, noisy, verbose);
222*44704f69SBart Van Assche return ret;
223*44704f69SBart Van Assche }
224*44704f69SBart Van Assche
225*44704f69SBart Van Assche /* Invokes a SCSI WRITE AND VERIFY (16) command (SBC). Returns 0 -> success,
226*44704f69SBart Van Assche * various SG_LIB_CAT_* positive values or -1 -> other errors */
227*44704f69SBart Van Assche static int
sg_ll_write_verify16(int sg_fd,int wrprotect,bool dpo,int bytchk,uint64_t llba,int num_lb,int group,uint8_t * dop,int do_len,int timeout,bool noisy,int verbose)228*44704f69SBart Van Assche sg_ll_write_verify16(int sg_fd, int wrprotect, bool dpo, int bytchk,
229*44704f69SBart Van Assche uint64_t llba, int num_lb, int group, uint8_t *dop,
230*44704f69SBart Van Assche int do_len, int timeout, bool noisy, int verbose)
231*44704f69SBart Van Assche {
232*44704f69SBart Van Assche int ret;
233*44704f69SBart Van Assche uint8_t wv_cdb[WRITE_VERIFY16_CMDLEN];
234*44704f69SBart Van Assche
235*44704f69SBart Van Assche
236*44704f69SBart Van Assche memset(wv_cdb, 0, sizeof(wv_cdb));
237*44704f69SBart Van Assche wv_cdb[0] = WRITE_VERIFY16_CMD;
238*44704f69SBart Van Assche wv_cdb[1] = ((wrprotect & WRPROTECT_MASK) << WRPROTECT_SHIFT);
239*44704f69SBart Van Assche if (dpo)
240*44704f69SBart Van Assche wv_cdb[1] |= 0x10;
241*44704f69SBart Van Assche if (bytchk)
242*44704f69SBart Van Assche wv_cdb[1] |= ((bytchk & 0x3) << 1);
243*44704f69SBart Van Assche
244*44704f69SBart Van Assche sg_put_unaligned_be64(llba, wv_cdb + 2);
245*44704f69SBart Van Assche sg_put_unaligned_be32((uint32_t)num_lb, wv_cdb + 10);
246*44704f69SBart Van Assche wv_cdb[14] = group & GRPNUM_MASK;
247*44704f69SBart Van Assche ret = run_scsi_transaction(sg_fd, wv_cdb, sizeof(wv_cdb), dop, do_len,
248*44704f69SBart Van Assche timeout, noisy, verbose);
249*44704f69SBart Van Assche return ret;
250*44704f69SBart Van Assche }
251*44704f69SBart Van Assche
252*44704f69SBart Van Assche /* Returns file descriptor ( >= 0) if successful. Else a negated sg3_utils
253*44704f69SBart Van Assche * error code is returned. */
254*44704f69SBart Van Assche static int
open_if(const char * fn,int got_stdin)255*44704f69SBart Van Assche open_if(const char * fn, int got_stdin)
256*44704f69SBart Van Assche {
257*44704f69SBart Van Assche int fd, err;
258*44704f69SBart Van Assche
259*44704f69SBart Van Assche if (got_stdin)
260*44704f69SBart Van Assche fd = STDIN_FILENO;
261*44704f69SBart Van Assche else {
262*44704f69SBart Van Assche fd = open(fn, O_RDONLY);
263*44704f69SBart Van Assche if (fd < 0) {
264*44704f69SBart Van Assche err = errno;
265*44704f69SBart Van Assche pr2serr(ME "open error: %s: %s\n", fn, safe_strerror(err));
266*44704f69SBart Van Assche return -sg_convert_errno(err);
267*44704f69SBart Van Assche }
268*44704f69SBart Van Assche }
269*44704f69SBart Van Assche if (sg_set_binary_mode(fd) < 0) {
270*44704f69SBart Van Assche perror("sg_set_binary_mode");
271*44704f69SBart Van Assche return -SG_LIB_FILE_ERROR;
272*44704f69SBart Van Assche }
273*44704f69SBart Van Assche return fd;
274*44704f69SBart Van Assche }
275*44704f69SBart Van Assche
276*44704f69SBart Van Assche int
main(int argc,char * argv[])277*44704f69SBart Van Assche main(int argc, char * argv[])
278*44704f69SBart Van Assche {
279*44704f69SBart Van Assche bool do_16 = false;
280*44704f69SBart Van Assche bool dpo = false;
281*44704f69SBart Van Assche bool first_time;
282*44704f69SBart Van Assche bool given_do_16 = false;
283*44704f69SBart Van Assche bool has_filename = false;
284*44704f69SBart Van Assche bool lba_given = false;
285*44704f69SBart Van Assche bool repeat = false;
286*44704f69SBart Van Assche bool verbose_given = false;
287*44704f69SBart Van Assche bool version_given = false;
288*44704f69SBart Van Assche int sg_fd, res, c, n;
289*44704f69SBart Van Assche int bytchk = 0;
290*44704f69SBart Van Assche int group = 0;
291*44704f69SBart Van Assche int ilen = -1;
292*44704f69SBart Van Assche int ifd = -1;
293*44704f69SBart Van Assche int b_p_lb = 512;
294*44704f69SBart Van Assche int ret = 1;
295*44704f69SBart Van Assche int timeout = DEF_TIMEOUT_SECS;
296*44704f69SBart Van Assche int tnum_lb_wr = 0;
297*44704f69SBart Van Assche int verbose = 0;
298*44704f69SBart Van Assche int wrprotect = 0;
299*44704f69SBart Van Assche uint32_t num_lb = 1;
300*44704f69SBart Van Assche uint32_t snum_lb = 1;
301*44704f69SBart Van Assche uint64_t llba = 0;
302*44704f69SBart Van Assche int64_t ll;
303*44704f69SBart Van Assche uint8_t * wvb = NULL;
304*44704f69SBart Van Assche uint8_t * wrkBuff = NULL;
305*44704f69SBart Van Assche uint8_t * free_wrkBuff = NULL;
306*44704f69SBart Van Assche const char * device_name = NULL;
307*44704f69SBart Van Assche const char * ifnp;
308*44704f69SBart Van Assche char cmd_name[32];
309*44704f69SBart Van Assche
310*44704f69SBart Van Assche ifnp = ""; /* keep MinGW quiet */
311*44704f69SBart Van Assche while (1) {
312*44704f69SBart Van Assche int option_index = 0;
313*44704f69SBart Van Assche
314*44704f69SBart Van Assche c = getopt_long(argc, argv, "b:dg:hi:I:l:n:RSt:w:vV", long_options,
315*44704f69SBart Van Assche &option_index);
316*44704f69SBart Van Assche if (c == -1)
317*44704f69SBart Van Assche break;
318*44704f69SBart Van Assche
319*44704f69SBart Van Assche switch (c) {
320*44704f69SBart Van Assche case 'b':
321*44704f69SBart Van Assche /* Only bytchk=0 and =1 are meaningful for this command in
322*44704f69SBart Van Assche * sbc4r02 (not =2 nor =3) but that may change in the future. */
323*44704f69SBart Van Assche bytchk = sg_get_num(optarg);
324*44704f69SBart Van Assche if ((bytchk < 0) || (bytchk > 3)) {
325*44704f69SBart Van Assche pr2serr("argument to '--bytchk' expected to be 0 to 3\n");
326*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
327*44704f69SBart Van Assche }
328*44704f69SBart Van Assche break;
329*44704f69SBart Van Assche case 'd':
330*44704f69SBart Van Assche dpo = true;
331*44704f69SBart Van Assche break;
332*44704f69SBart Van Assche case 'g':
333*44704f69SBart Van Assche group = sg_get_num(optarg);
334*44704f69SBart Van Assche if ((group < 0) || (group > 63)) {
335*44704f69SBart Van Assche pr2serr("argument to '--group' expected to be 0 to 63\n");
336*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
337*44704f69SBart Van Assche }
338*44704f69SBart Van Assche break;
339*44704f69SBart Van Assche case 'h':
340*44704f69SBart Van Assche case '?':
341*44704f69SBart Van Assche usage();
342*44704f69SBart Van Assche return 0;
343*44704f69SBart Van Assche case 'i':
344*44704f69SBart Van Assche ifnp = optarg;
345*44704f69SBart Van Assche has_filename = true;
346*44704f69SBart Van Assche break;
347*44704f69SBart Van Assche case 'I':
348*44704f69SBart Van Assche ilen = sg_get_num(optarg);
349*44704f69SBart Van Assche if (-1 == ilen) {
350*44704f69SBart Van Assche pr2serr("bad argument to '--ilen'\n");
351*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
352*44704f69SBart Van Assche }
353*44704f69SBart Van Assche break;
354*44704f69SBart Van Assche case 'l':
355*44704f69SBart Van Assche if (lba_given) {
356*44704f69SBart Van Assche pr2serr("must have one and only one '--lba'\n");
357*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
358*44704f69SBart Van Assche }
359*44704f69SBart Van Assche ll = sg_get_llnum(optarg);
360*44704f69SBart Van Assche if (ll < 0) {
361*44704f69SBart Van Assche pr2serr("bad argument to '--lba'\n");
362*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
363*44704f69SBart Van Assche }
364*44704f69SBart Van Assche llba = (uint64_t)ll;
365*44704f69SBart Van Assche lba_given = true;
366*44704f69SBart Van Assche break;
367*44704f69SBart Van Assche case 'n':
368*44704f69SBart Van Assche n = sg_get_num(optarg);
369*44704f69SBart Van Assche if (-1 == n) {
370*44704f69SBart Van Assche pr2serr("bad argument to '--num'\n");
371*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
372*44704f69SBart Van Assche }
373*44704f69SBart Van Assche num_lb = (uint32_t)n;
374*44704f69SBart Van Assche break;
375*44704f69SBart Van Assche case 'R':
376*44704f69SBart Van Assche repeat = true;
377*44704f69SBart Van Assche break;
378*44704f69SBart Van Assche case 'S':
379*44704f69SBart Van Assche do_16 = true;
380*44704f69SBart Van Assche given_do_16 = true;
381*44704f69SBart Van Assche break;
382*44704f69SBart Van Assche case 't':
383*44704f69SBart Van Assche timeout = sg_get_num(optarg);
384*44704f69SBart Van Assche if (timeout < 1) {
385*44704f69SBart Van Assche pr2serr("bad argument to '--timeout'\n");
386*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
387*44704f69SBart Van Assche }
388*44704f69SBart Van Assche break;
389*44704f69SBart Van Assche case 'v':
390*44704f69SBart Van Assche verbose_given = true;
391*44704f69SBart Van Assche ++verbose;
392*44704f69SBart Van Assche break;
393*44704f69SBart Van Assche case 'V':
394*44704f69SBart Van Assche version_given = true;
395*44704f69SBart Van Assche break;
396*44704f69SBart Van Assche case 'w':
397*44704f69SBart Van Assche wrprotect = sg_get_num(optarg);
398*44704f69SBart Van Assche if ((wrprotect < 0) || (wrprotect > 7)) {
399*44704f69SBart Van Assche pr2serr("wrprotect (%d) is out of range ( < %d)\n", wrprotect,
400*44704f69SBart Van Assche 7);
401*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
402*44704f69SBart Van Assche }
403*44704f69SBart Van Assche
404*44704f69SBart Van Assche break;
405*44704f69SBart Van Assche default:
406*44704f69SBart Van Assche pr2serr("unrecognised option code 0x%x ??\n", c);
407*44704f69SBart Van Assche usage();
408*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
409*44704f69SBart Van Assche }
410*44704f69SBart Van Assche }
411*44704f69SBart Van Assche if (optind < argc) {
412*44704f69SBart Van Assche if (NULL == device_name) {
413*44704f69SBart Van Assche device_name = argv[optind];
414*44704f69SBart Van Assche ++optind;
415*44704f69SBart Van Assche }
416*44704f69SBart Van Assche if (optind < argc) {
417*44704f69SBart Van Assche for (; optind < argc; ++optind)
418*44704f69SBart Van Assche pr2serr("Unexpected extra argument: %s\n", argv[optind]);
419*44704f69SBart Van Assche usage();
420*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
421*44704f69SBart Van Assche }
422*44704f69SBart Van Assche }
423*44704f69SBart Van Assche
424*44704f69SBart Van Assche #ifdef DEBUG
425*44704f69SBart Van Assche pr2serr("In DEBUG mode, ");
426*44704f69SBart Van Assche if (verbose_given && version_given) {
427*44704f69SBart Van Assche pr2serr("but override: '-vV' given, zero verbose and continue\n");
428*44704f69SBart Van Assche verbose_given = false;
429*44704f69SBart Van Assche version_given = false;
430*44704f69SBart Van Assche verbose = 0;
431*44704f69SBart Van Assche } else if (! verbose_given) {
432*44704f69SBart Van Assche pr2serr("set '-vv'\n");
433*44704f69SBart Van Assche verbose = 2;
434*44704f69SBart Van Assche } else
435*44704f69SBart Van Assche pr2serr("keep verbose=%d\n", verbose);
436*44704f69SBart Van Assche #else
437*44704f69SBart Van Assche if (verbose_given && version_given)
438*44704f69SBart Van Assche pr2serr("Not in DEBUG mode, so '-vV' has no special action\n");
439*44704f69SBart Van Assche #endif
440*44704f69SBart Van Assche if (version_given) {
441*44704f69SBart Van Assche pr2serr(ME "version: %s\n", version_str);
442*44704f69SBart Van Assche return 0;
443*44704f69SBart Van Assche }
444*44704f69SBart Van Assche
445*44704f69SBart Van Assche if (NULL == device_name) {
446*44704f69SBart Van Assche pr2serr("Missing device name!\n\n");
447*44704f69SBart Van Assche usage();
448*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
449*44704f69SBart Van Assche }
450*44704f69SBart Van Assche if (! lba_given) {
451*44704f69SBart Van Assche pr2serr("need a --lba=LBA option\n");
452*44704f69SBart Van Assche usage();
453*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
454*44704f69SBart Van Assche }
455*44704f69SBart Van Assche if (repeat) {
456*44704f69SBart Van Assche if (! has_filename) {
457*44704f69SBart Van Assche pr2serr("with '--repeat' need '--in=IF' option\n");
458*44704f69SBart Van Assche usage();
459*44704f69SBart Van Assche return SG_LIB_CONTRADICT;
460*44704f69SBart Van Assche }
461*44704f69SBart Van Assche if (ilen < 1) {
462*44704f69SBart Van Assche pr2serr("with '--repeat' need '--ilen=ILEN' option\n");
463*44704f69SBart Van Assche usage();
464*44704f69SBart Van Assche return SG_LIB_CONTRADICT;
465*44704f69SBart Van Assche } else {
466*44704f69SBart Van Assche b_p_lb = ilen / num_lb;
467*44704f69SBart Van Assche if (b_p_lb < 64) {
468*44704f69SBart Van Assche pr2serr("calculated %d bytes per logical block, too small\n",
469*44704f69SBart Van Assche b_p_lb);
470*44704f69SBart Van Assche usage();
471*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
472*44704f69SBart Van Assche }
473*44704f69SBart Van Assche }
474*44704f69SBart Van Assche }
475*44704f69SBart Van Assche
476*44704f69SBart Van Assche sg_fd = sg_cmds_open_device(device_name, false /* rw */, verbose);
477*44704f69SBart Van Assche if (sg_fd < 0) {
478*44704f69SBart Van Assche ret = sg_convert_errno(-sg_fd);
479*44704f69SBart Van Assche pr2serr(ME "open error: %s: %s\n", device_name, safe_strerror(-sg_fd));
480*44704f69SBart Van Assche goto err_out;
481*44704f69SBart Van Assche }
482*44704f69SBart Van Assche
483*44704f69SBart Van Assche if ((! do_16) && (llba > UINT_MAX))
484*44704f69SBart Van Assche do_16 = true;
485*44704f69SBart Van Assche if ((! do_16) && (num_lb > 0xffff))
486*44704f69SBart Van Assche do_16 = true;
487*44704f69SBart Van Assche snprintf(cmd_name, sizeof(cmd_name), "Write and verify(%d)",
488*44704f69SBart Van Assche (do_16 ? 16 : 10));
489*44704f69SBart Van Assche if (verbose && (! given_do_16) && do_16)
490*44704f69SBart Van Assche pr2serr("Switching to %s because LBA or NUM too large\n", cmd_name);
491*44704f69SBart Van Assche if (verbose) {
492*44704f69SBart Van Assche pr2serr("Issue %s to device %s\n\tilen=%d", cmd_name, device_name,
493*44704f69SBart Van Assche ilen);
494*44704f69SBart Van Assche if (ilen > 0)
495*44704f69SBart Van Assche pr2serr(" [0x%x]", ilen);
496*44704f69SBart Van Assche pr2serr(", lba=%" PRIu64 " [0x%" PRIx64 "]\n\twrprotect=%d, dpo=%d, "
497*44704f69SBart Van Assche "bytchk=%d, group=%d, repeat=%d\n", llba, llba, wrprotect,
498*44704f69SBart Van Assche (int)dpo, bytchk, group, (int)repeat);
499*44704f69SBart Van Assche }
500*44704f69SBart Van Assche
501*44704f69SBart Van Assche first_time = true;
502*44704f69SBart Van Assche do {
503*44704f69SBart Van Assche if (first_time) {
504*44704f69SBart Van Assche //If a file with data to write has been provided
505*44704f69SBart Van Assche if (has_filename) {
506*44704f69SBart Van Assche struct stat a_stat;
507*44704f69SBart Van Assche
508*44704f69SBart Van Assche if ((1 == strlen(ifnp)) && ('-' == ifnp[0])) {
509*44704f69SBart Van Assche ifd = STDIN_FILENO;
510*44704f69SBart Van Assche ifnp = "<stdin>";
511*44704f69SBart Van Assche if (verbose > 1)
512*44704f69SBart Van Assche pr2serr("Reading input data from stdin\n");
513*44704f69SBart Van Assche } else {
514*44704f69SBart Van Assche ifd = open_if(ifnp, 0);
515*44704f69SBart Van Assche if (ifd < 0) {
516*44704f69SBart Van Assche ret = -ifd;
517*44704f69SBart Van Assche goto err_out;
518*44704f69SBart Van Assche }
519*44704f69SBart Van Assche }
520*44704f69SBart Van Assche if (ilen < 1) {
521*44704f69SBart Van Assche if (fstat(ifd, &a_stat) < 0) {
522*44704f69SBart Van Assche pr2serr("Could not fstat(%s)\n", ifnp);
523*44704f69SBart Van Assche goto err_out;
524*44704f69SBart Van Assche }
525*44704f69SBart Van Assche if (! S_ISREG(a_stat.st_mode)) {
526*44704f69SBart Van Assche pr2serr("Cannot determine IF size, please give "
527*44704f69SBart Van Assche "'--ilen='\n");
528*44704f69SBart Van Assche goto err_out;
529*44704f69SBart Van Assche }
530*44704f69SBart Van Assche ilen = (int)a_stat.st_size;
531*44704f69SBart Van Assche if (ilen < 1) {
532*44704f69SBart Van Assche pr2serr("%s file size too small\n", ifnp);
533*44704f69SBart Van Assche goto err_out;
534*44704f69SBart Van Assche } else if (verbose)
535*44704f69SBart Van Assche pr2serr("Using file size of %d bytes\n", ilen);
536*44704f69SBart Van Assche }
537*44704f69SBart Van Assche if (NULL == (wrkBuff = (uint8_t *)sg_memalign(ilen, 0,
538*44704f69SBart Van Assche &free_wrkBuff, verbose > 3))) {
539*44704f69SBart Van Assche pr2serr(ME "out of memory\n");
540*44704f69SBart Van Assche ret = sg_convert_errno(ENOMEM);
541*44704f69SBart Van Assche goto err_out;
542*44704f69SBart Van Assche }
543*44704f69SBart Van Assche wvb = (uint8_t *)wrkBuff;
544*44704f69SBart Van Assche res = read(ifd, wvb, ilen);
545*44704f69SBart Van Assche if (res < 0) {
546*44704f69SBart Van Assche pr2serr("Could not read from %s", ifnp);
547*44704f69SBart Van Assche goto err_out;
548*44704f69SBart Van Assche }
549*44704f69SBart Van Assche if (res < ilen) {
550*44704f69SBart Van Assche pr2serr("Read only %d bytes (expected %d) from %s\n", res,
551*44704f69SBart Van Assche ilen, ifnp);
552*44704f69SBart Van Assche if (repeat)
553*44704f69SBart Van Assche pr2serr("Will scale subsequent pieces when "
554*44704f69SBart Van Assche "repeat=true, but this is first\n");
555*44704f69SBart Van Assche goto err_out;
556*44704f69SBart Van Assche }
557*44704f69SBart Van Assche } else {
558*44704f69SBart Van Assche if (ilen < 1) {
559*44704f69SBart Van Assche if (verbose)
560*44704f69SBart Van Assche pr2serr("Default write length to %d*%d=%d bytes\n",
561*44704f69SBart Van Assche num_lb, 512, 512 * num_lb);
562*44704f69SBart Van Assche ilen = 512 * num_lb;
563*44704f69SBart Van Assche }
564*44704f69SBart Van Assche if (NULL == (wrkBuff = (uint8_t *)sg_memalign(ilen, 0,
565*44704f69SBart Van Assche &free_wrkBuff, verbose > 3))) {
566*44704f69SBart Van Assche pr2serr(ME "out of memory\n");
567*44704f69SBart Van Assche ret = sg_convert_errno(ENOMEM);
568*44704f69SBart Van Assche goto err_out;
569*44704f69SBart Van Assche }
570*44704f69SBart Van Assche wvb = (uint8_t *)wrkBuff;
571*44704f69SBart Van Assche /* Not sure about this: default contents to 0xff bytes */
572*44704f69SBart Van Assche memset(wrkBuff, 0xff, ilen);
573*44704f69SBart Van Assche }
574*44704f69SBart Van Assche first_time = false;
575*44704f69SBart Van Assche snum_lb = num_lb;
576*44704f69SBart Van Assche } else { /* repeat=true, first_time=false, must be reading file */
577*44704f69SBart Van Assche llba += snum_lb;
578*44704f69SBart Van Assche res = read(ifd, wvb, ilen);
579*44704f69SBart Van Assche if (res < 0) {
580*44704f69SBart Van Assche pr2serr("Could not read from %s", ifnp);
581*44704f69SBart Van Assche goto err_out;
582*44704f69SBart Van Assche } else {
583*44704f69SBart Van Assche if (verbose > 1)
584*44704f69SBart Van Assche pr2serr("Subsequent read from %s got %d bytes\n", ifnp, res);
585*44704f69SBart Van Assche if (0 == res)
586*44704f69SBart Van Assche break;
587*44704f69SBart Van Assche if (res < ilen) {
588*44704f69SBart Van Assche snum_lb = (uint32_t)(res / b_p_lb);
589*44704f69SBart Van Assche n = res % b_p_lb;
590*44704f69SBart Van Assche if (0 != n)
591*44704f69SBart Van Assche pr2serr(">>> warning: ignoring last %d bytes of %s\n",
592*44704f69SBart Van Assche n, ifnp);
593*44704f69SBart Van Assche if (snum_lb < 1)
594*44704f69SBart Van Assche break;
595*44704f69SBart Van Assche }
596*44704f69SBart Van Assche }
597*44704f69SBart Van Assche }
598*44704f69SBart Van Assche if (do_16)
599*44704f69SBart Van Assche res = sg_ll_write_verify16(sg_fd, wrprotect, dpo, bytchk, llba,
600*44704f69SBart Van Assche snum_lb, group, wvb, ilen, timeout,
601*44704f69SBart Van Assche verbose > 0, verbose);
602*44704f69SBart Van Assche else
603*44704f69SBart Van Assche res = sg_ll_write_verify10(sg_fd, wrprotect, dpo, bytchk,
604*44704f69SBart Van Assche (unsigned int)llba, snum_lb, group,
605*44704f69SBart Van Assche wvb, ilen, timeout, verbose > 0,
606*44704f69SBart Van Assche verbose);
607*44704f69SBart Van Assche ret = res;
608*44704f69SBart Van Assche if (repeat && (0 == ret))
609*44704f69SBart Van Assche tnum_lb_wr += snum_lb;
610*44704f69SBart Van Assche if (ret || (snum_lb != num_lb))
611*44704f69SBart Van Assche break;
612*44704f69SBart Van Assche } while (repeat);
613*44704f69SBart Van Assche
614*44704f69SBart Van Assche err_out:
615*44704f69SBart Van Assche if (repeat)
616*44704f69SBart Van Assche pr2serr("%d [0x%x] logical blocks written, in total\n", tnum_lb_wr,
617*44704f69SBart Van Assche tnum_lb_wr);
618*44704f69SBart Van Assche if (free_wrkBuff)
619*44704f69SBart Van Assche free(free_wrkBuff);
620*44704f69SBart Van Assche if ((ifd >= 0) && (STDIN_FILENO != ifd))
621*44704f69SBart Van Assche close(ifd);
622*44704f69SBart Van Assche res = sg_cmds_close_device(sg_fd);
623*44704f69SBart Van Assche if (res < 0) {
624*44704f69SBart Van Assche pr2serr("close error: %s\n", safe_strerror(-res));
625*44704f69SBart Van Assche if (0 == ret)
626*44704f69SBart Van Assche ret = sg_convert_errno(-res);
627*44704f69SBart Van Assche }
628*44704f69SBart Van Assche if (ret && (0 == verbose)) {
629*44704f69SBart Van Assche if (! sg_if_can2stderr("sg_write_verify failed: ", ret))
630*44704f69SBart Van Assche pr2serr("Some error occurred, try again with '-v' "
631*44704f69SBart Van Assche "or '-vv' for more information\n");
632*44704f69SBart Van Assche }
633*44704f69SBart Van Assche return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
634*44704f69SBart Van Assche }
635