xref: /aosp_15_r20/external/sg3_utils/src/sg_write_same.c (revision 44704f698541f6367e81f991ef8bb54ccbf3fc18)
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