1 /*
2 * Copyright (c) 2009-2022 Douglas Gilbert.
3 * All rights reserved.
4 * Use of this source code is governed by a BSD-style
5 * license that can be found in the BSD_LICENSE file.
6 *
7 * SPDX-License-Identifier: BSD-2-Clause
8 */
9
10 #include <unistd.h>
11 #include <fcntl.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <stdarg.h>
15 #include <stdbool.h>
16 #include <string.h>
17 #include <errno.h>
18 #include <limits.h>
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <getopt.h>
22 #define __STDC_FORMAT_MACROS 1
23 #include <inttypes.h>
24
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28
29 #include "sg_lib.h"
30 #include "sg_pt.h"
31 #include "sg_cmds_basic.h"
32 #include "sg_cmds_extra.h"
33 #include "sg_unaligned.h"
34 #include "sg_pr2serr.h"
35
36 static const char * version_str = "1.34 20220127";
37
38
39 #define ME "sg_write_same: "
40
41 #define WRITE_SAME10_OP 0x41
42 #define WRITE_SAME16_OP 0x93
43 #define VARIABLE_LEN_OP 0x7f
44 #define WRITE_SAME32_SA 0xd
45 #define WRITE_SAME32_ADD 0x18
46 #define WRITE_SAME10_LEN 10
47 #define WRITE_SAME16_LEN 16
48 #define WRITE_SAME32_LEN 32
49 #define RCAP10_RESP_LEN 8
50 #define RCAP16_RESP_LEN 32
51 #define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */
52 #define DEF_TIMEOUT_SECS 60
53 #define DEF_WS_CDB_SIZE WRITE_SAME10_LEN
54 #define DEF_WS_NUMBLOCKS 1
55 #define MAX_XFER_LEN (64 * 1024)
56 #define EBUFF_SZ 512
57
58 #ifndef UINT32_MAX
59 #define UINT32_MAX ((uint32_t)-1)
60 #endif
61
62 static struct option long_options[] = {
63 {"10", no_argument, 0, 'R'},
64 {"16", no_argument, 0, 'S'},
65 {"32", no_argument, 0, 'T'},
66 {"anchor", no_argument, 0, 'a'},
67 {"ff", no_argument, 0, 'f'},
68 {"grpnum", required_argument, 0, 'g'},
69 {"help", no_argument, 0, 'h'},
70 {"in", required_argument, 0, 'i'},
71 {"lba", required_argument, 0, 'l'},
72 {"lbdata", no_argument, 0, 'L'},
73 {"ndob", no_argument, 0, 'N'},
74 {"num", required_argument, 0, 'n'},
75 {"pbdata", no_argument, 0, 'P'},
76 {"timeout", required_argument, 0, 't'},
77 {"unmap", no_argument, 0, 'U'},
78 {"verbose", no_argument, 0, 'v'},
79 {"version", no_argument, 0, 'V'},
80 {"wrprotect", required_argument, 0, 'w'},
81 {"xferlen", required_argument, 0, 'x'},
82 {0, 0, 0, 0},
83 };
84
85 struct opts_t {
86 bool anchor;
87 bool ff;
88 bool ndob;
89 bool lbdata;
90 bool pbdata;
91 bool unmap;
92 bool verbose_given;
93 bool version_given;
94 bool want_ws10;
95 int grpnum;
96 int numblocks;
97 int timeout;
98 int verbose;
99 int wrprotect;
100 int xfer_len;
101 int pref_cdb_size;
102 uint64_t lba;
103 char ifilename[256];
104 };
105
106
107 static void
usage()108 usage()
109 {
110 pr2serr("Usage: sg_write_same [--10] [--16] [--32] [--anchor] "
111 "[-ff] [--grpnum=GN]\n"
112 " [--help] [--in=IF] [--lba=LBA] [--lbdata] "
113 "[--ndob]\n"
114 " [--num=NUM] [--pbdata] [--timeout=TO] "
115 "[--unmap]\n"
116 " [--verbose] [--version] [--wrprotect=WRP] "
117 "[xferlen=LEN]\n"
118 " DEVICE\n"
119 " where:\n"
120 " --10|-R send WRITE SAME(10) (even if '--unmap' "
121 "is given)\n"
122 " --16|-S send WRITE SAME(16) (def: 10 unless "
123 "'--unmap' given,\n"
124 " LBA+NUM > 32 bits, or NUM > 65535; "
125 "then def 16)\n"
126 " --32|-T send WRITE SAME(32) (def: 10 or 16)\n"
127 " --anchor|-a set ANCHOR field in cdb\n"
128 " --ff|-f use buffer of 0xff bytes for fill "
129 "(def: 0x0 bytes)\n"
130 " --grpnum=GN|-g GN GN is group number field (def: 0)\n"
131 " --help|-h print out usage message\n"
132 " --in=IF|-i IF IF is file to fetch one block of data "
133 "from (use LEN\n"
134 " bytes or whole file). Block written to "
135 "DEVICE\n"
136 " --lba=LBA|-l LBA LBA is the logical block address to "
137 "start (def: 0)\n"
138 " --lbdata|-L set LBDATA bit (obsolete)\n"
139 " --ndob|-N set NDOB (no data-out buffer) bit in "
140 "cdb\n"
141 " --num=NUM|-n NUM NUM is number of logical blocks to "
142 "write (def: 1)\n"
143 " [Beware NUM==0 may mean: 'rest of "
144 "device']\n"
145 " --pbdata|-P set PBDATA bit (obsolete)\n"
146 " --timeout=TO|-t TO command timeout (unit: seconds) (def: "
147 "60)\n"
148 " --unmap|-U set UNMAP bit\n"
149 " --verbose|-v increase verbosity\n"
150 " --version|-V print version string then exit\n"
151 " --wrprotect=WPR|-w WPR WPR is the WRPROTECT field value "
152 "(def: 0)\n"
153 " --xferlen=LEN|-x LEN LEN is number of bytes from IF to "
154 "send to\n"
155 " DEVICE (def: IF file length)\n\n"
156 "Performs a SCSI WRITE SAME (10, 16 or 32) command. NDOB bit is "
157 "only\nsupported by the 16 and 32 byte variants. When set the "
158 "specified blocks\nwill be filled with zeros or the "
159 "'provisioning initialization pattern'\nas indicated by the "
160 "LBPRZ field. As a precaution one of the '--in=',\n'--lba=' or "
161 "'--num=' options is required.\nAnother implementation of WRITE "
162 "SAME is found in the sg_write_x utility.\n"
163 );
164 }
165
166 static int
do_write_same(int sg_fd,const struct opts_t * op,const void * dataoutp,int * act_cdb_lenp)167 do_write_same(int sg_fd, const struct opts_t * op, const void * dataoutp,
168 int * act_cdb_lenp)
169 {
170 int ret, res, sense_cat, cdb_len;
171 uint64_t llba;
172 uint8_t ws_cdb[WRITE_SAME32_LEN] SG_C_CPP_ZERO_INIT;
173 uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT;
174 struct sg_pt_base * ptvp;
175
176 cdb_len = op->pref_cdb_size;
177 if (WRITE_SAME10_LEN == cdb_len) {
178 llba = op->lba + op->numblocks;
179 if ((op->numblocks > 0xffff) || (llba > UINT32_MAX) ||
180 op->ndob || (op->unmap && (! op->want_ws10))) {
181 cdb_len = WRITE_SAME16_LEN;
182 if (op->verbose) {
183 const char * cp = "use WRITE SAME(16) instead of 10 byte "
184 "cdb";
185
186 if (op->numblocks > 0xffff)
187 pr2serr("%s since blocks exceed 65535\n", cp);
188 else if (llba > UINT32_MAX)
189 pr2serr("%s since LBA may exceed 32 bits\n", cp);
190 else
191 pr2serr("%s due to ndob or unmap settings\n", cp);
192 }
193 }
194 }
195 if (act_cdb_lenp)
196 *act_cdb_lenp = cdb_len;
197 switch (cdb_len) {
198 case WRITE_SAME10_LEN:
199 ws_cdb[0] = WRITE_SAME10_OP;
200 ws_cdb[1] = ((op->wrprotect & 0x7) << 5);
201 /* ANCHOR + UNMAP not allowed for WRITE_SAME10 in sbc3r24+r25 but
202 * a proposal has been made to allow it. Anticipate approval. */
203 if (op->anchor)
204 ws_cdb[1] |= 0x10;
205 if (op->unmap)
206 ws_cdb[1] |= 0x8;
207 if (op->pbdata)
208 ws_cdb[1] |= 0x4;
209 if (op->lbdata)
210 ws_cdb[1] |= 0x2;
211 sg_put_unaligned_be32((uint32_t)op->lba, ws_cdb + 2);
212 ws_cdb[6] = (op->grpnum & GRPNUM_MASK);
213 sg_put_unaligned_be16((uint16_t)op->numblocks, ws_cdb + 7);
214 break;
215 case WRITE_SAME16_LEN:
216 ws_cdb[0] = WRITE_SAME16_OP;
217 ws_cdb[1] = ((op->wrprotect & 0x7) << 5);
218 if (op->anchor)
219 ws_cdb[1] |= 0x10;
220 if (op->unmap)
221 ws_cdb[1] |= 0x8;
222 if (op->pbdata)
223 ws_cdb[1] |= 0x4;
224 if (op->lbdata)
225 ws_cdb[1] |= 0x2;
226 if (op->ndob)
227 ws_cdb[1] |= 0x1;
228 sg_put_unaligned_be64(op->lba, ws_cdb + 2);
229 sg_put_unaligned_be32((uint32_t)op->numblocks, ws_cdb + 10);
230 ws_cdb[14] = (op->grpnum & GRPNUM_MASK);
231 break;
232 case WRITE_SAME32_LEN:
233 ws_cdb[0] = VARIABLE_LEN_OP;
234 ws_cdb[6] = (op->grpnum & GRPNUM_MASK);
235 ws_cdb[7] = WRITE_SAME32_ADD;
236 sg_put_unaligned_be16((uint16_t)WRITE_SAME32_SA, ws_cdb + 8);
237 ws_cdb[10] = ((op->wrprotect & 0x7) << 5);
238 if (op->anchor)
239 ws_cdb[10] |= 0x10;
240 if (op->unmap)
241 ws_cdb[10] |= 0x8;
242 if (op->pbdata)
243 ws_cdb[10] |= 0x4;
244 if (op->lbdata)
245 ws_cdb[10] |= 0x2;
246 if (op->ndob)
247 ws_cdb[10] |= 0x1;
248 sg_put_unaligned_be64(op->lba, ws_cdb + 12);
249 sg_put_unaligned_be32((uint32_t)op->numblocks, ws_cdb + 28);
250 break;
251 default:
252 pr2serr("do_write_same: bad cdb length %d\n", cdb_len);
253 return -1;
254 }
255
256 if (op->verbose > 1) {
257 char b[128];
258
259 pr2serr(" Write same(%d) cdb: %s\n", cdb_len,
260 sg_get_command_str(ws_cdb, cdb_len, false, sizeof(b), b));
261 pr2serr(" Data-out buffer length=%d\n", op->xfer_len);
262 }
263 if ((op->verbose > 3) && (op->xfer_len > 0)) {
264 pr2serr(" Data-out buffer contents:\n");
265 hex2stderr((const uint8_t *)dataoutp, op->xfer_len, 1);
266 }
267 ptvp = construct_scsi_pt_obj();
268 if (NULL == ptvp) {
269 pr2serr("Write same(%d): out of memory\n", cdb_len);
270 return -1;
271 }
272 set_scsi_pt_cdb(ptvp, ws_cdb, cdb_len);
273 set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
274 set_scsi_pt_data_out(ptvp, (uint8_t *)dataoutp, op->xfer_len);
275 res = do_scsi_pt(ptvp, sg_fd, op->timeout, op->verbose);
276 ret = sg_cmds_process_resp(ptvp, "Write same", res, true /*noisy */,
277 op->verbose, &sense_cat);
278 if (-1 == ret) {
279 if (get_scsi_pt_transport_err(ptvp))
280 ret = SG_LIB_TRANSPORT_ERROR;
281 else
282 ret = sg_convert_errno(get_scsi_pt_os_err(ptvp));
283 } else if (-2 == ret) {
284 switch (sense_cat) {
285 case SG_LIB_CAT_RECOVERED:
286 case SG_LIB_CAT_NO_SENSE:
287 ret = 0;
288 break;
289 case SG_LIB_CAT_MEDIUM_HARD:
290 {
291 bool valid;
292 int slen;
293 uint64_t ull = 0;
294
295 slen = get_scsi_pt_sense_len(ptvp);
296 valid = sg_get_sense_info_fld(sense_b, slen, &ull);
297 if (valid)
298 pr2serr("Medium or hardware error starting at lba=%"
299 PRIu64 " [0x%" PRIx64 "]\n", ull, ull);
300 }
301 ret = sense_cat;
302 break;
303 case SG_LIB_CAT_ILLEGAL_REQ:
304 if (op->verbose)
305 sg_print_command_len(ws_cdb, cdb_len);
306 /* FALL THROUGH */
307 default:
308 ret = sense_cat;
309 break;
310 }
311 } else
312 ret = 0;
313
314 destruct_scsi_pt_obj(ptvp);
315 return ret;
316 }
317
318
319 int
main(int argc,char * argv[])320 main(int argc, char * argv[])
321 {
322 bool got_stdin = false;
323 bool if_given = false;
324 bool lba_given = false;
325 bool num_given = false;
326 bool prot_en;
327 int res, c, infd, act_cdb_len, vb, err;
328 int sg_fd = -1;
329 int ret = -1;
330 uint32_t block_size;
331 int64_t ll;
332 const char * device_name = NULL;
333 struct opts_t * op;
334 uint8_t * wBuff = NULL;
335 uint8_t * free_wBuff = NULL;
336 char ebuff[EBUFF_SZ];
337 char b[80];
338 uint8_t resp_buff[RCAP16_RESP_LEN];
339 struct opts_t opts;
340 struct stat a_stat;
341
342 op = &opts;
343 memset(op, 0, sizeof(opts));
344 op->numblocks = DEF_WS_NUMBLOCKS;
345 op->pref_cdb_size = DEF_WS_CDB_SIZE;
346 op->timeout = DEF_TIMEOUT_SECS;
347 while (1) {
348 int option_index = 0;
349
350 c = getopt_long(argc, argv, "afg:hi:l:Ln:NPRSt:TUvVw:x:",
351 long_options, &option_index);
352 if (c == -1)
353 break;
354
355 switch (c) {
356 case 'a':
357 op->anchor = true;
358 break;
359 case 'f':
360 op->ff = true;
361 break;
362 case 'g':
363 op->grpnum = sg_get_num(optarg);
364 if ((op->grpnum < 0) || (op->grpnum > 63)) {
365 pr2serr("bad argument to '--grpnum'\n");
366 return SG_LIB_SYNTAX_ERROR;
367 }
368 break;
369 case 'h':
370 case '?':
371 usage();
372 return 0;
373 case 'i':
374 strncpy(op->ifilename, optarg, sizeof(op->ifilename) - 1);
375 op->ifilename[sizeof(op->ifilename) - 1] = '\0';
376 if_given = true;
377 break;
378 case 'l':
379 ll = sg_get_llnum(optarg);
380 if (-1 == ll) {
381 pr2serr("bad argument to '--lba'\n");
382 return SG_LIB_SYNTAX_ERROR;
383 }
384 op->lba = (uint64_t)ll;
385 lba_given = true;
386 break;
387 case 'L':
388 op->lbdata = true;
389 break;
390 case 'n':
391 op->numblocks = sg_get_num(optarg);
392 if (op->numblocks < 0) {
393 pr2serr("bad argument to '--num'\n");
394 return SG_LIB_SYNTAX_ERROR;
395 }
396 num_given = true;
397 break;
398 case 'N':
399 op->ndob = true;
400 break;
401 case 'P':
402 op->pbdata = true;
403 break;
404 case 'R':
405 op->want_ws10 = true;
406 break;
407 case 'S':
408 if (DEF_WS_CDB_SIZE != op->pref_cdb_size) {
409 pr2serr("only one '--10', '--16' or '--32' please\n");
410 return SG_LIB_CONTRADICT;
411 }
412 op->pref_cdb_size = 16;
413 break;
414 case 't':
415 op->timeout = sg_get_num(optarg);
416 if (op->timeout < 0) {
417 pr2serr("bad argument to '--timeout'\n");
418 return SG_LIB_SYNTAX_ERROR;
419 }
420 break;
421 case 'T':
422 if (DEF_WS_CDB_SIZE != op->pref_cdb_size) {
423 pr2serr("only one '--10', '--16' or '--32' please\n");
424 return SG_LIB_CONTRADICT;
425 }
426 op->pref_cdb_size = 32;
427 break;
428 case 'U':
429 op->unmap = true;
430 break;
431 case 'v':
432 op->verbose_given = true;
433 ++op->verbose;
434 break;
435 case 'V':
436 op->version_given = true;
437 break;
438 case 'w':
439 op->wrprotect = sg_get_num(optarg);
440 if ((op->wrprotect < 0) || (op->wrprotect > 7)) {
441 pr2serr("bad argument to '--wrprotect'\n");
442 return SG_LIB_SYNTAX_ERROR;
443 }
444 break;
445 case 'x':
446 op->xfer_len = sg_get_num(optarg);
447 if (op->xfer_len < 0) {
448 pr2serr("bad argument to '--xferlen'\n");
449 return SG_LIB_SYNTAX_ERROR;
450 }
451 break;
452 default:
453 pr2serr("unrecognised option code 0x%x ??\n", c);
454 usage();
455 return SG_LIB_SYNTAX_ERROR;
456 }
457 }
458 if (optind < argc) {
459 if (NULL == device_name) {
460 device_name = argv[optind];
461 ++optind;
462 }
463 if (optind < argc) {
464 for (; optind < argc; ++optind)
465 pr2serr("Unexpected extra argument: %s\n", argv[optind]);
466 usage();
467 return SG_LIB_SYNTAX_ERROR;
468 }
469 }
470 if (op->want_ws10 && (DEF_WS_CDB_SIZE != op->pref_cdb_size)) {
471 pr2serr("only one '--10', '--16' or '--32' please\n");
472 return SG_LIB_CONTRADICT;
473 }
474
475 #ifdef DEBUG
476 pr2serr("In DEBUG mode, ");
477 if (op->verbose_given && op->version_given) {
478 pr2serr("but override: '-vV' given, zero verbose and continue\n");
479 op->verbose_given = false;
480 op->version_given = false;
481 op->verbose = 0;
482 } else if (! op->verbose_given) {
483 pr2serr("set '-vv'\n");
484 op->verbose = 2;
485 } else
486 pr2serr("keep verbose=%d\n", op->verbose);
487 #else
488 if (op->verbose_given && op->version_given)
489 pr2serr("Not in DEBUG mode, so '-vV' has no special action\n");
490 #endif
491 if (op->version_given) {
492 pr2serr(ME "version: %s\n", version_str);
493 return 0;
494 }
495
496 if (NULL == device_name) {
497 pr2serr("Missing device name!\n\n");
498 usage();
499 return SG_LIB_SYNTAX_ERROR;
500 }
501 vb = op->verbose;
502
503 if ((! if_given) && (! lba_given) && (! num_given)) {
504 pr2serr("As a precaution, one of '--in=', '--lba=' or '--num=' is "
505 "required\n");
506 return SG_LIB_CONTRADICT;
507 }
508
509 if (op->ndob) {
510 if (if_given) {
511 pr2serr("Can't have both --ndob and '--in='\n");
512 return SG_LIB_CONTRADICT;
513 }
514 if (0 != op->xfer_len) {
515 pr2serr("With --ndob only '--xferlen=0' (or not given) is "
516 "acceptable\n");
517 return SG_LIB_CONTRADICT;
518 }
519 } else if (op->ifilename[0]) {
520 got_stdin = (0 == strcmp(op->ifilename, "-"));
521 if (! got_stdin) {
522 memset(&a_stat, 0, sizeof(a_stat));
523 if (stat(op->ifilename, &a_stat) < 0) {
524 err = errno;
525 if (vb)
526 pr2serr("unable to stat(%s): %s\n", op->ifilename,
527 safe_strerror(err));
528 return sg_convert_errno(err);
529 }
530 if (op->xfer_len <= 0)
531 op->xfer_len = (int)a_stat.st_size;
532 }
533 }
534
535 sg_fd = sg_cmds_open_device(device_name, false /* rw */, vb);
536 if (sg_fd < 0) {
537 if (op->verbose)
538 pr2serr(ME "open error: %s: %s\n", device_name,
539 safe_strerror(-sg_fd));
540 ret = sg_convert_errno(-sg_fd);
541 goto err_out;
542 }
543
544 if (! op->ndob) {
545 prot_en = false;
546 if (0 == op->xfer_len) {
547 res = sg_ll_readcap_16(sg_fd, false /* pmi */, 0 /* llba */,
548 resp_buff, RCAP16_RESP_LEN, true,
549 (vb ? (vb - 1): 0));
550 if (SG_LIB_CAT_UNIT_ATTENTION == res) {
551 pr2serr("Read capacity(16) unit attention, try again\n");
552 res = sg_ll_readcap_16(sg_fd, false, 0, resp_buff,
553 RCAP16_RESP_LEN, true,
554 (vb ? (vb - 1): 0));
555 }
556 if (0 == res) {
557 if (vb > 3)
558 hex2stderr(resp_buff, RCAP16_RESP_LEN, 1);
559 block_size = sg_get_unaligned_be32(resp_buff + 8);
560 prot_en = !!(resp_buff[12] & 0x1);
561 op->xfer_len = block_size;
562 if (prot_en && (op->wrprotect > 0))
563 op->xfer_len += 8;
564 } else if ((SG_LIB_CAT_INVALID_OP == res) ||
565 (SG_LIB_CAT_ILLEGAL_REQ == res)) {
566 if (vb)
567 pr2serr("Read capacity(16) not supported, try Read "
568 "capacity(10)\n");
569 res = sg_ll_readcap_10(sg_fd, false /* pmi */, 0 /* lba */,
570 resp_buff, RCAP10_RESP_LEN, true,
571 (vb ? (vb - 1): 0));
572 if (0 == res) {
573 if (vb > 3)
574 hex2stderr(resp_buff, RCAP10_RESP_LEN, 1);
575 block_size = sg_get_unaligned_be32(resp_buff + 4);
576 op->xfer_len = block_size;
577 } else {
578 sg_get_category_sense_str(res, sizeof(b), b, vb);
579 pr2serr("Read capacity(10): %s\n", b);
580 pr2serr("Unable to calculate block size\n");
581 }
582 } else if (vb) {
583 sg_get_category_sense_str(res, sizeof(b), b, vb);
584 pr2serr("Read capacity(16): %s\n", b);
585 pr2serr("Unable to calculate block size\n");
586 }
587 }
588 if (op->xfer_len < 1) {
589 pr2serr("unable to deduce block size, please give '--xferlen=' "
590 "argument\n");
591 ret = SG_LIB_SYNTAX_ERROR;
592 goto err_out;
593 }
594 if (op->xfer_len > MAX_XFER_LEN) {
595 pr2serr("'--xferlen=%d is out of range ( want <= %d)\n",
596 op->xfer_len, MAX_XFER_LEN);
597 ret = SG_LIB_SYNTAX_ERROR;
598 goto err_out;
599 }
600 wBuff = (uint8_t *)sg_memalign(op->xfer_len, 0, &free_wBuff, false);
601 if (NULL == wBuff) {
602 pr2serr("unable to allocate %d bytes of memory with "
603 "sg_memalign()\n", op->xfer_len);
604 ret = sg_convert_errno(ENOMEM);
605 goto err_out;
606 }
607 if (op->ff)
608 memset(wBuff, 0xff, op->xfer_len);
609 if (op->ifilename[0]) {
610 if (got_stdin) {
611 infd = STDIN_FILENO;
612 if (sg_set_binary_mode(STDIN_FILENO) < 0)
613 perror("sg_set_binary_mode");
614 } else {
615 if ((infd = open(op->ifilename, O_RDONLY)) < 0) {
616 ret = sg_convert_errno(errno);
617 snprintf(ebuff, EBUFF_SZ, ME "could not open %.400s for "
618 "reading", op->ifilename);
619 perror(ebuff);
620 goto err_out;
621 } else if (sg_set_binary_mode(infd) < 0)
622 perror("sg_set_binary_mode");
623 }
624 res = read(infd, wBuff, op->xfer_len);
625 if (res < 0) {
626 ret = sg_convert_errno(errno);
627 snprintf(ebuff, EBUFF_SZ, ME "couldn't read from %.400s",
628 op->ifilename);
629 perror(ebuff);
630 if (! got_stdin)
631 close(infd);
632 goto err_out;
633 }
634 if (res < op->xfer_len) {
635 pr2serr("tried to read %d bytes from %s, got %d bytes\n",
636 op->xfer_len, op->ifilename, res);
637 pr2serr(" so pad with 0x0 bytes and continue\n");
638 }
639 if (! got_stdin)
640 close(infd);
641 } else {
642 if (vb)
643 pr2serr("Default data-out buffer set to %d zeros\n",
644 op->xfer_len);
645 if (prot_en && (op->wrprotect > 0)) {
646 /* default for protection is 0xff, rest get 0x0 */
647 memset(wBuff + op->xfer_len - 8, 0xff, 8);
648 if (vb)
649 pr2serr(" ... apart from last 8 bytes which are set to "
650 "0xff\n");
651 }
652 }
653 }
654
655 ret = do_write_same(sg_fd, op, wBuff, &act_cdb_len);
656 if (ret) {
657 sg_get_category_sense_str(ret, sizeof(b), b, vb);
658 pr2serr("Write same(%d): %s\n", act_cdb_len, b);
659 }
660
661 err_out:
662 if (free_wBuff)
663 free(free_wBuff);
664 if (sg_fd >= 0) {
665 res = sg_cmds_close_device(sg_fd);
666 if (res < 0) {
667 pr2serr("close error: %s\n", safe_strerror(-res));
668 if (0 == ret)
669 ret = sg_convert_errno(-res);
670 }
671 }
672 if (0 == op->verbose) {
673 if (! sg_if_can2stderr("sg_write_same failed: ", ret))
674 pr2serr("Some error occurred, try again with '-v' "
675 "or '-vv' for more information\n");
676 }
677 return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
678 }
679