xref: /aosp_15_r20/external/sg3_utils/src/sg_reassign.c (revision 44704f698541f6367e81f991ef8bb54ccbf3fc18)
1*44704f69SBart Van Assche /*
2*44704f69SBart Van Assche  * Copyright (c) 2005-2019 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 
10*44704f69SBart Van Assche #include <unistd.h>
11*44704f69SBart Van Assche #include <fcntl.h>
12*44704f69SBart Van Assche #include <stdio.h>
13*44704f69SBart Van Assche #include <stdlib.h>
14*44704f69SBart Van Assche #include <stdarg.h>
15*44704f69SBart Van Assche #include <stdbool.h>
16*44704f69SBart Van Assche #include <string.h>
17*44704f69SBart Van Assche #include <ctype.h>
18*44704f69SBart Van Assche #include <getopt.h>
19*44704f69SBart Van Assche #include <limits.h>
20*44704f69SBart Van Assche #define __STDC_FORMAT_MACROS 1
21*44704f69SBart Van Assche #include <inttypes.h>
22*44704f69SBart Van Assche 
23*44704f69SBart Van Assche #ifdef HAVE_CONFIG_H
24*44704f69SBart Van Assche #include "config.h"
25*44704f69SBart Van Assche #endif
26*44704f69SBart Van Assche 
27*44704f69SBart Van Assche #include "sg_lib.h"
28*44704f69SBart Van Assche #include "sg_cmds_basic.h"
29*44704f69SBart Van Assche #include "sg_cmds_extra.h"
30*44704f69SBart Van Assche #include "sg_unaligned.h"
31*44704f69SBart Van Assche #include "sg_pr2serr.h"
32*44704f69SBart Van Assche 
33*44704f69SBart Van Assche /* A utility program originally written for the Linux OS SCSI subsystem.
34*44704f69SBart Van Assche  *
35*44704f69SBart Van Assche  * This utility invokes the REASSIGN BLOCKS SCSI command to reassign
36*44704f69SBart Van Assche  * an existing (possibly damaged) lba on a direct access device (e.g.
37*44704f69SBart Van Assche  * a disk) to a new physical location. The previous contents is
38*44704f69SBart Van Assche  * recoverable then it is written to the remapped lba otherwise
39*44704f69SBart Van Assche  * vendor specific data is written.
40*44704f69SBart Van Assche  */
41*44704f69SBart Van Assche 
42*44704f69SBart Van Assche static const char * version_str = "1.27 20191001";
43*44704f69SBart Van Assche 
44*44704f69SBart Van Assche #define DEF_DEFECT_LIST_FORMAT 4        /* bytes from index */
45*44704f69SBart Van Assche 
46*44704f69SBart Van Assche #define MAX_NUM_ADDR 1024
47*44704f69SBart Van Assche 
48*44704f69SBart Van Assche #ifndef UINT32_MAX
49*44704f69SBart Van Assche #define UINT32_MAX ((uint32_t)-1)
50*44704f69SBart Van Assche #endif
51*44704f69SBart Van Assche 
52*44704f69SBart Van Assche 
53*44704f69SBart Van Assche static struct option long_options[] = {
54*44704f69SBart Van Assche         {"address", required_argument, 0, 'a'},
55*44704f69SBart Van Assche         {"dummy", no_argument, 0, 'd'},
56*44704f69SBart Van Assche         {"eight", required_argument, 0, 'e'},
57*44704f69SBart Van Assche         {"grown", no_argument, 0, 'g'},
58*44704f69SBart Van Assche         {"help", no_argument, 0, 'h'},
59*44704f69SBart Van Assche         {"hex", no_argument, 0, 'H'},
60*44704f69SBart Van Assche         {"longlist", required_argument, 0, 'l'},
61*44704f69SBart Van Assche         {"primary", no_argument, 0, 'p'},
62*44704f69SBart Van Assche         {"verbose", no_argument, 0, 'v'},
63*44704f69SBart Van Assche         {"version", no_argument, 0, 'V'},
64*44704f69SBart Van Assche         {0, 0, 0, 0},
65*44704f69SBart Van Assche };
66*44704f69SBart Van Assche 
67*44704f69SBart Van Assche static void
usage()68*44704f69SBart Van Assche usage()
69*44704f69SBart Van Assche {
70*44704f69SBart Van Assche     pr2serr("Usage: sg_reassign [--address=A,A...] [--dummy] [--eight=0|1] "
71*44704f69SBart Van Assche             "[--grown]\n"
72*44704f69SBart Van Assche             "                   [--help] [--hex] [--longlist=0|1] "
73*44704f69SBart Van Assche             "[--primary] [--verbose]\n"
74*44704f69SBart Van Assche             "                   [--version] DEVICE\n"
75*44704f69SBart Van Assche             "  where:\n"
76*44704f69SBart Van Assche             "    --address=A,A...|-a A,A...    comma separated logical block "
77*44704f69SBart Van Assche             "addresses\n"
78*44704f69SBart Van Assche             "                                  one or more, assumed to be "
79*44704f69SBart Van Assche             "decimal\n"
80*44704f69SBart Van Assche             "    --address=-|-a -    read stdin for logical block "
81*44704f69SBart Van Assche             "addresses\n"
82*44704f69SBart Van Assche             "    --dummy|-d          prepare but do not execute REASSIGN "
83*44704f69SBart Van Assche             "BLOCKS command\n"
84*44704f69SBart Van Assche             "    --eight=0|1\n"
85*44704f69SBart Van Assche             "      -e 0|1            force eight byte (64 bit) lbas "
86*44704f69SBart Van Assche             "when 1,\n"
87*44704f69SBart Van Assche             "                        four byte (32 bit) lbas when 0 "
88*44704f69SBart Van Assche             "(def)\n"
89*44704f69SBart Van Assche             "    --grown|-g          fetch grown defect list length, "
90*44704f69SBart Van Assche             "don't reassign\n"
91*44704f69SBart Van Assche             "    --help|-h           print out usage message\n"
92*44704f69SBart Van Assche             "    --hex|-H            print response in hex (for '-g' or "
93*44704f69SBart Van Assche             "'-p')\n"
94*44704f69SBart Van Assche             "    --longlist=0|1\n"
95*44704f69SBart Van Assche             "       -l 0|1           use 4 byte list length when 1, safe to "
96*44704f69SBart Van Assche             "ignore\n"
97*44704f69SBart Van Assche             "                        (def: 0 (2 byte list length))\n"
98*44704f69SBart Van Assche             "    --primary|-p        fetch primary defect list length, "
99*44704f69SBart Van Assche             "don't reassign\n"
100*44704f69SBart Van Assche             "    --verbose|-v        increase verbosity\n"
101*44704f69SBart Van Assche             "    --version|-V        print version string and exit\n\n"
102*44704f69SBart Van Assche             "Perform a SCSI REASSIGN BLOCKS command (or READ DEFECT LIST)\n");
103*44704f69SBart Van Assche }
104*44704f69SBart Van Assche 
105*44704f69SBart Van Assche /* Read numbers (up to 64 bits in size) from command line (comma (or
106*44704f69SBart Van Assche  * (single) space) separated list) or from stdin (one per line, comma
107*44704f69SBart Van Assche  * separated list or space separated list). Assumed decimal unless prefixed
108*44704f69SBart Van Assche  * by '0x', '0X' or contains trailing 'h' or 'H' (which indicate hex).
109*44704f69SBart Van Assche  * Returns 0 if ok, or error code. */
110*44704f69SBart Van Assche static int
build_lba_arr(const char * inp,uint64_t * lba_arr,int * lba_arr_len,int max_arr_len)111*44704f69SBart Van Assche build_lba_arr(const char * inp, uint64_t * lba_arr,
112*44704f69SBart Van Assche               int * lba_arr_len, int max_arr_len)
113*44704f69SBart Van Assche {
114*44704f69SBart Van Assche     int in_len, k, j, m;
115*44704f69SBart Van Assche     const char * lcp;
116*44704f69SBart Van Assche     int64_t ll;
117*44704f69SBart Van Assche     char * cp;
118*44704f69SBart Van Assche     char * c2p;
119*44704f69SBart Van Assche 
120*44704f69SBart Van Assche     if ((NULL == inp) || (NULL == lba_arr) ||
121*44704f69SBart Van Assche         (NULL == lba_arr_len))
122*44704f69SBart Van Assche         return SG_LIB_LOGIC_ERROR;
123*44704f69SBart Van Assche     lcp = inp;
124*44704f69SBart Van Assche     in_len = strlen(inp);
125*44704f69SBart Van Assche     if (0 == in_len)
126*44704f69SBart Van Assche         *lba_arr_len = 0;
127*44704f69SBart Van Assche     if ('-' == inp[0]) {        /* read from stdin */
128*44704f69SBart Van Assche         char line[1024];
129*44704f69SBart Van Assche         int off = 0;
130*44704f69SBart Van Assche 
131*44704f69SBart Van Assche         for (j = 0; j < 512; ++j) {
132*44704f69SBart Van Assche             if (NULL == fgets(line, sizeof(line), stdin))
133*44704f69SBart Van Assche                 break;
134*44704f69SBart Van Assche             // could improve with carry_over logic if sizeof(line) too small
135*44704f69SBart Van Assche             in_len = strlen(line);
136*44704f69SBart Van Assche             if (in_len > 0) {
137*44704f69SBart Van Assche                 if ('\n' == line[in_len - 1]) {
138*44704f69SBart Van Assche                     --in_len;
139*44704f69SBart Van Assche                     line[in_len] = '\0';
140*44704f69SBart Van Assche                 }
141*44704f69SBart Van Assche             }
142*44704f69SBart Van Assche             if (in_len < 1)
143*44704f69SBart Van Assche                 continue;
144*44704f69SBart Van Assche             lcp = line;
145*44704f69SBart Van Assche             m = strspn(lcp, " \t");
146*44704f69SBart Van Assche             if (m == in_len)
147*44704f69SBart Van Assche                 continue;
148*44704f69SBart Van Assche             lcp += m;
149*44704f69SBart Van Assche             in_len -= m;
150*44704f69SBart Van Assche             if ('#' == *lcp)
151*44704f69SBart Van Assche                 continue;
152*44704f69SBart Van Assche             k = strspn(lcp, "0123456789aAbBcCdDeEfFhHxX ,\t");
153*44704f69SBart Van Assche             if ((k < in_len) && ('#' != lcp[k])) {
154*44704f69SBart Van Assche                 pr2serr("%s: syntax error at line %d, pos %d\n", __func__,
155*44704f69SBart Van Assche                         j + 1, m + k + 1);
156*44704f69SBart Van Assche                 return SG_LIB_SYNTAX_ERROR;
157*44704f69SBart Van Assche             }
158*44704f69SBart Van Assche             for (k = 0; k < 1024; ++k) {
159*44704f69SBart Van Assche                 ll = sg_get_llnum_nomult(lcp);
160*44704f69SBart Van Assche                 if (-1 != ll) {
161*44704f69SBart Van Assche                     if ((off + k) >= max_arr_len) {
162*44704f69SBart Van Assche                         pr2serr("%s: array length exceeded\n", __func__);
163*44704f69SBart Van Assche                         return SG_LIB_SYNTAX_ERROR;
164*44704f69SBart Van Assche                     }
165*44704f69SBart Van Assche                     lba_arr[off + k] = (uint64_t)ll;
166*44704f69SBart Van Assche                     lcp = strpbrk(lcp, " ,\t");
167*44704f69SBart Van Assche                     if (NULL == lcp)
168*44704f69SBart Van Assche                         break;
169*44704f69SBart Van Assche                     lcp += strspn(lcp, " ,\t");
170*44704f69SBart Van Assche                     if ('\0' == *lcp)
171*44704f69SBart Van Assche                         break;
172*44704f69SBart Van Assche                 } else {
173*44704f69SBart Van Assche                     if ('#' == *lcp) {
174*44704f69SBart Van Assche                         --k;
175*44704f69SBart Van Assche                         break;
176*44704f69SBart Van Assche                     }
177*44704f69SBart Van Assche                     pr2serr("%s: error in line %d, at pos %d\n", __func__,
178*44704f69SBart Van Assche                             j + 1, (int)(lcp - line + 1));
179*44704f69SBart Van Assche                     return SG_LIB_SYNTAX_ERROR;
180*44704f69SBart Van Assche                 }
181*44704f69SBart Van Assche             }
182*44704f69SBart Van Assche             off += (k + 1);
183*44704f69SBart Van Assche         }
184*44704f69SBart Van Assche         *lba_arr_len = off;
185*44704f69SBart Van Assche     } else {        /* list of numbers (default decimal) on command line */
186*44704f69SBart Van Assche         k = strspn(inp, "0123456789aAbBcCdDeEfFhHxX, ");
187*44704f69SBart Van Assche         if (in_len != k) {
188*44704f69SBart Van Assche             pr2serr("%s: error at pos %d\n", __func__, k + 1);
189*44704f69SBart Van Assche             return SG_LIB_SYNTAX_ERROR;
190*44704f69SBart Van Assche         }
191*44704f69SBart Van Assche         for (k = 0; k < max_arr_len; ++k) {
192*44704f69SBart Van Assche             ll = sg_get_llnum_nomult(lcp);
193*44704f69SBart Van Assche             if (-1 != ll) {
194*44704f69SBart Van Assche                 lba_arr[k] = (uint64_t)ll;
195*44704f69SBart Van Assche                 cp = (char *)strchr(lcp, ',');
196*44704f69SBart Van Assche                 c2p = (char *)strchr(lcp, ' ');
197*44704f69SBart Van Assche                 if (NULL == cp)
198*44704f69SBart Van Assche                     cp = c2p;
199*44704f69SBart Van Assche                 if (NULL == cp)
200*44704f69SBart Van Assche                     break;
201*44704f69SBart Van Assche                 if (c2p && (c2p < cp))
202*44704f69SBart Van Assche                     cp = c2p;
203*44704f69SBart Van Assche                 lcp = cp + 1;
204*44704f69SBart Van Assche             } else {
205*44704f69SBart Van Assche                 pr2serr("%s: error at pos %d\n", __func__,
206*44704f69SBart Van Assche                         (int)(lcp - inp + 1));
207*44704f69SBart Van Assche                 return SG_LIB_SYNTAX_ERROR;
208*44704f69SBart Van Assche             }
209*44704f69SBart Van Assche         }
210*44704f69SBart Van Assche         *lba_arr_len = k + 1;
211*44704f69SBart Van Assche         if (k == max_arr_len) {
212*44704f69SBart Van Assche             pr2serr("%s: array length exceeded\n", __func__);
213*44704f69SBart Van Assche             return SG_LIB_SYNTAX_ERROR;
214*44704f69SBart Van Assche         }
215*44704f69SBart Van Assche     }
216*44704f69SBart Van Assche     return 0;
217*44704f69SBart Van Assche }
218*44704f69SBart Van Assche 
219*44704f69SBart Van Assche 
220*44704f69SBart Van Assche int
main(int argc,char * argv[])221*44704f69SBart Van Assche main(int argc, char * argv[])
222*44704f69SBart Van Assche {
223*44704f69SBart Van Assche     bool dummy = false;
224*44704f69SBart Van Assche     bool eight = false;
225*44704f69SBart Van Assche     bool eight_given = false;
226*44704f69SBart Van Assche     bool got_addr = false;
227*44704f69SBart Van Assche     bool longlist = false;
228*44704f69SBart Van Assche     bool primary = false;
229*44704f69SBart Van Assche     bool grown = false;
230*44704f69SBart Van Assche     bool verbose_given = false;
231*44704f69SBart Van Assche     bool version_given = false;
232*44704f69SBart Van Assche     int res, c, num, k, j;
233*44704f69SBart Van Assche     int sg_fd = -1;
234*44704f69SBart Van Assche     int addr_arr_len = 0;
235*44704f69SBart Van Assche     int do_hex = 0;
236*44704f69SBart Van Assche     int verbose = 0;
237*44704f69SBart Van Assche     const char * device_name = NULL;
238*44704f69SBart Van Assche     uint64_t addr_arr[MAX_NUM_ADDR];
239*44704f69SBart Van Assche     uint8_t param_arr[4 + (MAX_NUM_ADDR * 8)];
240*44704f69SBart Van Assche     char b[80];
241*44704f69SBart Van Assche     int param_len = 4;
242*44704f69SBart Van Assche     int ret = 0;
243*44704f69SBart Van Assche 
244*44704f69SBart Van Assche     while (1) {
245*44704f69SBart Van Assche         int option_index = 0;
246*44704f69SBart Van Assche 
247*44704f69SBart Van Assche         c = getopt_long(argc, argv, "a:de:ghHl:pvV", long_options,
248*44704f69SBart Van Assche                         &option_index);
249*44704f69SBart Van Assche         if (c == -1)
250*44704f69SBart Van Assche             break;
251*44704f69SBart Van Assche 
252*44704f69SBart Van Assche         switch (c) {
253*44704f69SBart Van Assche         case 'a':
254*44704f69SBart Van Assche             memset(addr_arr, 0, sizeof(addr_arr));
255*44704f69SBart Van Assche             if ((res = build_lba_arr(optarg, addr_arr, &addr_arr_len,
256*44704f69SBart Van Assche                                      MAX_NUM_ADDR))) {
257*44704f69SBart Van Assche                 pr2serr("bad argument to '--address'\n");
258*44704f69SBart Van Assche                 return res;
259*44704f69SBart Van Assche             }
260*44704f69SBart Van Assche             got_addr = true;
261*44704f69SBart Van Assche             break;
262*44704f69SBart Van Assche         case 'd':
263*44704f69SBart Van Assche             dummy = true;
264*44704f69SBart Van Assche             break;
265*44704f69SBart Van Assche         case 'e':
266*44704f69SBart Van Assche             num = sscanf(optarg, "%d", &res);
267*44704f69SBart Van Assche             if ((1 == num) && ((0 == res) || (1 == res)))
268*44704f69SBart Van Assche                 eight = !! res;
269*44704f69SBart Van Assche             else {
270*44704f69SBart Van Assche                 pr2serr("value for '--eight=' must be 0 or 1\n");
271*44704f69SBart Van Assche                 return SG_LIB_SYNTAX_ERROR;
272*44704f69SBart Van Assche             }
273*44704f69SBart Van Assche             eight_given = true;
274*44704f69SBart Van Assche             break;
275*44704f69SBart Van Assche         case 'g':
276*44704f69SBart Van Assche             grown = true;
277*44704f69SBart Van Assche             break;
278*44704f69SBart Van Assche         case 'h':
279*44704f69SBart Van Assche         case '?':
280*44704f69SBart Van Assche             usage();
281*44704f69SBart Van Assche             return 0;
282*44704f69SBart Van Assche         case 'H':
283*44704f69SBart Van Assche             ++do_hex;
284*44704f69SBart Van Assche             break;
285*44704f69SBart Van Assche         case 'l':
286*44704f69SBart Van Assche             num = sscanf(optarg, "%d", &res);
287*44704f69SBart Van Assche             if ((1 == num) && ((0 == res) || (1 == res)))
288*44704f69SBart Van Assche                 longlist = !!res;
289*44704f69SBart Van Assche             else {
290*44704f69SBart Van Assche                 pr2serr("value for '--longlist=' must be 0 or 1\n");
291*44704f69SBart Van Assche                 return SG_LIB_SYNTAX_ERROR;
292*44704f69SBart Van Assche             }
293*44704f69SBart Van Assche             break;
294*44704f69SBart Van Assche         case 'p':
295*44704f69SBart Van Assche             primary = true;
296*44704f69SBart Van Assche             break;
297*44704f69SBart Van Assche         case 'v':
298*44704f69SBart Van Assche             verbose_given = true;
299*44704f69SBart Van Assche             ++verbose;
300*44704f69SBart Van Assche             break;
301*44704f69SBart Van Assche         case 'V':
302*44704f69SBart Van Assche             version_given = true;
303*44704f69SBart Van Assche             break;
304*44704f69SBart Van Assche         default:
305*44704f69SBart Van Assche             pr2serr("unrecognised option code 0x%x ??\n", c);
306*44704f69SBart Van Assche             usage();
307*44704f69SBart Van Assche             return SG_LIB_SYNTAX_ERROR;
308*44704f69SBart Van Assche         }
309*44704f69SBart Van Assche     }
310*44704f69SBart Van Assche     if (optind < argc) {
311*44704f69SBart Van Assche         if (NULL == device_name) {
312*44704f69SBart Van Assche             device_name = argv[optind];
313*44704f69SBart Van Assche             ++optind;
314*44704f69SBart Van Assche         }
315*44704f69SBart Van Assche         if (optind < argc) {
316*44704f69SBart Van Assche             for (; optind < argc; ++optind)
317*44704f69SBart Van Assche                 pr2serr("Unexpected extra argument: %s\n", argv[optind]);
318*44704f69SBart Van Assche             usage();
319*44704f69SBart Van Assche             return SG_LIB_SYNTAX_ERROR;
320*44704f69SBart Van Assche         }
321*44704f69SBart Van Assche     }
322*44704f69SBart Van Assche #ifdef DEBUG
323*44704f69SBart Van Assche     pr2serr("In DEBUG mode, ");
324*44704f69SBart Van Assche     if (verbose_given && version_given) {
325*44704f69SBart Van Assche         pr2serr("but override: '-vV' given, zero verbose and continue\n");
326*44704f69SBart Van Assche         verbose_given = false;
327*44704f69SBart Van Assche         version_given = false;
328*44704f69SBart Van Assche         verbose = 0;
329*44704f69SBart Van Assche     } else if (! verbose_given) {
330*44704f69SBart Van Assche         pr2serr("set '-vv'\n");
331*44704f69SBart Van Assche         verbose = 2;
332*44704f69SBart Van Assche     } else
333*44704f69SBart Van Assche         pr2serr("keep verbose=%d\n", verbose);
334*44704f69SBart Van Assche #else
335*44704f69SBart Van Assche     if (verbose_given && version_given)
336*44704f69SBart Van Assche         pr2serr("Not in DEBUG mode, so '-vV' has no special action\n");
337*44704f69SBart Van Assche #endif
338*44704f69SBart Van Assche     if (version_given) {
339*44704f69SBart Van Assche         pr2serr("version: %s\n", version_str);
340*44704f69SBart Van Assche         return 0;
341*44704f69SBart Van Assche     }
342*44704f69SBart Van Assche 
343*44704f69SBart Van Assche     if (NULL == device_name) {
344*44704f69SBart Van Assche         pr2serr("Missing device name!\n\n");
345*44704f69SBart Van Assche         usage();
346*44704f69SBart Van Assche         return SG_LIB_SYNTAX_ERROR;
347*44704f69SBart Van Assche     }
348*44704f69SBart Van Assche     if (grown || primary) {
349*44704f69SBart Van Assche         if (got_addr) {
350*44704f69SBart Van Assche             pr2serr("can't have '--address=' with '--grown' or '--primary'\n");
351*44704f69SBart Van Assche             usage();
352*44704f69SBart Van Assche             return SG_LIB_CONTRADICT;
353*44704f69SBart Van Assche         }
354*44704f69SBart Van Assche     } else if ((! got_addr) || (addr_arr_len < 1)) {
355*44704f69SBart Van Assche         pr2serr("need at least one address (see '--address=')\n");
356*44704f69SBart Van Assche         usage();
357*44704f69SBart Van Assche         return SG_LIB_SYNTAX_ERROR;
358*44704f69SBart Van Assche     }
359*44704f69SBart Van Assche     if (got_addr) {
360*44704f69SBart Van Assche         for (k = 0; k < addr_arr_len; ++k) {
361*44704f69SBart Van Assche             if (addr_arr[k] >= UINT32_MAX) {
362*44704f69SBart Van Assche                 if (! eight_given) {
363*44704f69SBart Van Assche                     eight = true;
364*44704f69SBart Van Assche                     break;
365*44704f69SBart Van Assche                 } else if (! eight) {
366*44704f69SBart Van Assche                     pr2serr("address number %d exceeds 32 bits so "
367*44704f69SBart Van Assche                             "'--eight=0' invalid\n", k + 1);
368*44704f69SBart Van Assche                     return SG_LIB_CONTRADICT;
369*44704f69SBart Van Assche                 }
370*44704f69SBart Van Assche             }
371*44704f69SBart Van Assche         }
372*44704f69SBart Van Assche         if (! eight_given)
373*44704f69SBart Van Assche             eight = false;
374*44704f69SBart Van Assche 
375*44704f69SBart Van Assche         k = 4;
376*44704f69SBart Van Assche         for (j = 0; j < addr_arr_len; ++j) {
377*44704f69SBart Van Assche             if (eight) {
378*44704f69SBart Van Assche                 sg_put_unaligned_be64(addr_arr[j], param_arr + k);
379*44704f69SBart Van Assche                 k += 8;
380*44704f69SBart Van Assche             } else {
381*44704f69SBart Van Assche                 sg_put_unaligned_be32((uint32_t)addr_arr[j], param_arr + k);
382*44704f69SBart Van Assche                 k += 4;
383*44704f69SBart Van Assche             }
384*44704f69SBart Van Assche         }
385*44704f69SBart Van Assche         param_len = k;
386*44704f69SBart Van Assche         k -= 4;
387*44704f69SBart Van Assche         if (longlist)
388*44704f69SBart Van Assche             sg_put_unaligned_be32((uint32_t)k, param_arr + 0);
389*44704f69SBart Van Assche         else
390*44704f69SBart Van Assche             sg_put_unaligned_be16((uint16_t)k, param_arr + 2);
391*44704f69SBart Van Assche     }
392*44704f69SBart Van Assche 
393*44704f69SBart Van Assche     sg_fd = sg_cmds_open_device(device_name, false /* rw */, verbose);
394*44704f69SBart Van Assche     if (sg_fd < 0) {
395*44704f69SBart Van Assche         if (verbose)
396*44704f69SBart Van Assche             pr2serr("open error: %s: %s\n", device_name,
397*44704f69SBart Van Assche                     safe_strerror(-sg_fd));
398*44704f69SBart Van Assche         ret = sg_convert_errno(-sg_fd);
399*44704f69SBart Van Assche         goto err_out;
400*44704f69SBart Van Assche     }
401*44704f69SBart Van Assche 
402*44704f69SBart Van Assche     if (got_addr) {
403*44704f69SBart Van Assche         if (dummy) {
404*44704f69SBart Van Assche             pr2serr(">>> dummy: REASSIGN BLOCKS not executed\n");
405*44704f69SBart Van Assche             if (verbose) {
406*44704f69SBart Van Assche                 pr2serr("  Would have reassigned these blocks:\n");
407*44704f69SBart Van Assche                 for (j = 0; j < addr_arr_len; ++j)
408*44704f69SBart Van Assche                     printf("    0x%" PRIx64 "\n", addr_arr[j]);
409*44704f69SBart Van Assche             }
410*44704f69SBart Van Assche             return 0;
411*44704f69SBart Van Assche         }
412*44704f69SBart Van Assche         res = sg_ll_reassign_blocks(sg_fd, eight, longlist, param_arr,
413*44704f69SBart Van Assche                                     param_len, true, verbose);
414*44704f69SBart Van Assche         ret = res;
415*44704f69SBart Van Assche         if (res) {
416*44704f69SBart Van Assche             sg_get_category_sense_str(res, sizeof(b), b, verbose);
417*44704f69SBart Van Assche             pr2serr("REASSIGN BLOCKS: %s\n", b);
418*44704f69SBart Van Assche             goto err_out;
419*44704f69SBart Van Assche         }
420*44704f69SBart Van Assche     } else /* if (grown || primary) */ {
421*44704f69SBart Van Assche         int dl_format = DEF_DEFECT_LIST_FORMAT;
422*44704f69SBart Van Assche         int div = 0;
423*44704f69SBart Van Assche         int dl_len;
424*44704f69SBart Van Assche         bool got_grown, got_primary;
425*44704f69SBart Van Assche         const char * lstp;
426*44704f69SBart Van Assche 
427*44704f69SBart Van Assche         param_len = 4;
428*44704f69SBart Van Assche         memset(param_arr, 0, param_len);
429*44704f69SBart Van Assche         res = sg_ll_read_defect10(sg_fd, primary, grown, dl_format,
430*44704f69SBart Van Assche                                   param_arr, param_len, false, verbose);
431*44704f69SBart Van Assche         ret = res;
432*44704f69SBart Van Assche         if (res) {
433*44704f69SBart Van Assche             sg_get_category_sense_str(res, sizeof(b), b, verbose);
434*44704f69SBart Van Assche             pr2serr("READ DEFECT DATA(10): %s\n", b);
435*44704f69SBart Van Assche             goto err_out;
436*44704f69SBart Van Assche         }
437*44704f69SBart Van Assche         if (do_hex) {
438*44704f69SBart Van Assche             hex2stdout(param_arr, param_len, 1);
439*44704f69SBart Van Assche             goto err_out;       /* ret is zero */
440*44704f69SBart Van Assche         }
441*44704f69SBart Van Assche         got_grown = !!(param_arr[1] & 0x8);
442*44704f69SBart Van Assche         got_primary = !!(param_arr[1] & 0x10);
443*44704f69SBart Van Assche         if (got_grown && got_primary)
444*44704f69SBart Van Assche             lstp = "grown and primary defect lists";
445*44704f69SBart Van Assche         else if (got_grown)
446*44704f69SBart Van Assche             lstp = "grown defect list";
447*44704f69SBart Van Assche         else if (got_primary)
448*44704f69SBart Van Assche             lstp = "primary defect list";
449*44704f69SBart Van Assche         else {
450*44704f69SBart Van Assche             pr2serr("didn't get grown or primary list in response\n");
451*44704f69SBart Van Assche             goto err_out;
452*44704f69SBart Van Assche         }
453*44704f69SBart Van Assche         if (verbose)
454*44704f69SBart Van Assche             pr2serr("asked for defect list format %d, got %d\n", dl_format,
455*44704f69SBart Van Assche                     (param_arr[1] & 0x7));
456*44704f69SBart Van Assche         dl_format = (param_arr[1] & 0x7);
457*44704f69SBart Van Assche         switch (dl_format) {    /* Defect list formats: */
458*44704f69SBart Van Assche             case 0:     /* short block */
459*44704f69SBart Van Assche                 div = 4;
460*44704f69SBart Van Assche                 break;
461*44704f69SBart Van Assche             case 1:     /* extended bytes from index */
462*44704f69SBart Van Assche                 div = 8;
463*44704f69SBart Van Assche                 break;
464*44704f69SBart Van Assche             case 2:     /* extended physical sector */
465*44704f69SBart Van Assche                 div = 8;
466*44704f69SBart Van Assche                 break;
467*44704f69SBart Van Assche             case 3:     /* long block */
468*44704f69SBart Van Assche             case 4:     /* bytes from index */
469*44704f69SBart Van Assche             case 5:     /* physical sector */
470*44704f69SBart Van Assche                 div = 8;
471*44704f69SBart Van Assche                 break;
472*44704f69SBart Van Assche             case 6:     /* vendor specific */
473*44704f69SBart Van Assche                 if (verbose)
474*44704f69SBart Van Assche                     pr2serr("defect list format: vendor specific\n");
475*44704f69SBart Van Assche                 break;
476*44704f69SBart Van Assche             default:
477*44704f69SBart Van Assche                 pr2serr("defect list format %d unknown\n", dl_format);
478*44704f69SBart Van Assche                 break;
479*44704f69SBart Van Assche         }
480*44704f69SBart Van Assche         dl_len = sg_get_unaligned_be16(param_arr + 2);
481*44704f69SBart Van Assche         if (0 == dl_len)
482*44704f69SBart Van Assche             printf(">> Elements in %s: 0\n", lstp);
483*44704f69SBart Van Assche         else {
484*44704f69SBart Van Assche             if (0 == div)
485*44704f69SBart Van Assche                 printf(">> %s length=%d bytes [unknown number of elements]\n",
486*44704f69SBart Van Assche                        lstp, dl_len);
487*44704f69SBart Van Assche             else
488*44704f69SBart Van Assche                 printf(">> Elements in %s: %d\n", lstp,
489*44704f69SBart Van Assche                        dl_len / div);
490*44704f69SBart Van Assche         }
491*44704f69SBart Van Assche     }
492*44704f69SBart Van Assche 
493*44704f69SBart Van Assche err_out:
494*44704f69SBart Van Assche     if (sg_fd >= 0) {
495*44704f69SBart Van Assche         res = sg_cmds_close_device(sg_fd);
496*44704f69SBart Van Assche         if (res < 0) {
497*44704f69SBart Van Assche             pr2serr("close error: %s\n", safe_strerror(-res));
498*44704f69SBart Van Assche             if (0 == ret)
499*44704f69SBart Van Assche                 ret = sg_convert_errno(-res);
500*44704f69SBart Van Assche         }
501*44704f69SBart Van Assche     }
502*44704f69SBart Van Assche     if (0 == verbose) {
503*44704f69SBart Van Assche         if (! sg_if_can2stderr("sg_reassign failed: ", ret))
504*44704f69SBart Van Assche             pr2serr("Some error occurred, try again with '-v' "
505*44704f69SBart Van Assche                     "or '-vv' for more information\n");
506*44704f69SBart Van Assche     }
507*44704f69SBart Van Assche     return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
508*44704f69SBart Van Assche }
509