xref: /aosp_15_r20/external/sg3_utils/src/sg_copy_results.c (revision 44704f698541f6367e81f991ef8bb54ccbf3fc18)
1*44704f69SBart Van Assche /*
2*44704f69SBart Van Assche  * Copyright (c) 2011-2018 Hannes Reinecke, SUSE Labs
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 #include <unistd.h>
8*44704f69SBart Van Assche #include <fcntl.h>
9*44704f69SBart Van Assche #include <stdio.h>
10*44704f69SBart Van Assche #include <stdlib.h>
11*44704f69SBart Van Assche #include <stdarg.h>
12*44704f69SBart Van Assche #include <stdbool.h>
13*44704f69SBart Van Assche #include <string.h>
14*44704f69SBart Van Assche #include <errno.h>
15*44704f69SBart Van Assche #include <getopt.h>
16*44704f69SBart Van Assche #define __STDC_FORMAT_MACROS 1
17*44704f69SBart Van Assche #include <inttypes.h>
18*44704f69SBart Van Assche 
19*44704f69SBart Van Assche #ifdef HAVE_CONFIG_H
20*44704f69SBart Van Assche #include "config.h"
21*44704f69SBart Van Assche #endif
22*44704f69SBart Van Assche #include "sg_lib.h"
23*44704f69SBart Van Assche #include "sg_cmds_basic.h"
24*44704f69SBart Van Assche #include "sg_cmds_extra.h"
25*44704f69SBart Van Assche #include "sg_unaligned.h"
26*44704f69SBart Van Assche #include "sg_pr2serr.h"
27*44704f69SBart Van Assche 
28*44704f69SBart Van Assche /*
29*44704f69SBart Van Assche  * A utility program for the Linux OS SCSI subsystem.
30*44704f69SBart Van Assche  *  Copyright (C) 2004-2010 D. Gilbert
31*44704f69SBart Van Assche  * This program is free software; you can redistribute it and/or modify
32*44704f69SBart Van Assche  * it under the terms of the GNU General Public License as published by
33*44704f69SBart Van Assche  * the Free Software Foundation; either version 2, or (at your option)
34*44704f69SBart Van Assche  * any later version.
35*44704f69SBart Van Assche  *
36*44704f69SBart Van Assche  * SPDX-License-Identifier: GPL-2.0-or-later
37*44704f69SBart Van Assche  *
38*44704f69SBart Van Assche  * This program issues the SCSI command RECEIVE COPY RESULTS to a given
39*44704f69SBart Van Assche  * SCSI device.
40*44704f69SBart Van Assche  * It sends the command with the service action passed as the sa argument,
41*44704f69SBart Van Assche  * and the optional list identifier passed as the list_id argument.
42*44704f69SBart Van Assche  */
43*44704f69SBart Van Assche 
44*44704f69SBart Van Assche static const char * version_str = "1.23 20180625";
45*44704f69SBart Van Assche 
46*44704f69SBart Van Assche 
47*44704f69SBart Van Assche #define MAX_XFER_LEN 10000
48*44704f69SBart Van Assche 
49*44704f69SBart Van Assche 
50*44704f69SBart Van Assche #define ME "sg_copy_results: "
51*44704f69SBart Van Assche 
52*44704f69SBart Van Assche #define EBUFF_SZ 256
53*44704f69SBart Van Assche 
54*44704f69SBart Van Assche struct descriptor_type {
55*44704f69SBart Van Assche     int code;
56*44704f69SBart Van Assche     char desc[124];
57*44704f69SBart Van Assche };
58*44704f69SBart Van Assche 
59*44704f69SBart Van Assche struct descriptor_type target_descriptor_codes[] = {
60*44704f69SBart Van Assche     { 0xe0, "Fibre Channel N_Port_Name"},
61*44704f69SBart Van Assche     { 0xe1, "Fibre Channel N_port_ID"},
62*44704f69SBart Van Assche     { 0xe2, "Fibre Channesl N_port_ID with N_Port_Name checking"},
63*44704f69SBart Van Assche     { 0xe3, "Parallel Interface T_L" },
64*44704f69SBart Van Assche     { 0xe4, "Identification descriptor" },
65*44704f69SBart Van Assche     { 0xe5, "IPv4" },
66*44704f69SBart Van Assche     { 0xe6, "Alias" },
67*44704f69SBart Van Assche     { 0xe7, "RDMA" },
68*44704f69SBart Van Assche     { 0xe8, "IEEE 1395 EUI-64" },
69*44704f69SBart Van Assche     { 0xe9, "SAS Serial SCSI Protocol" },
70*44704f69SBart Van Assche     { 0xea, "IPv6" },
71*44704f69SBart Van Assche     { 0xeb, "IP Copy Service" },
72*44704f69SBart Van Assche     { -1, "" }
73*44704f69SBart Van Assche };
74*44704f69SBart Van Assche 
75*44704f69SBart Van Assche struct descriptor_type segment_descriptor_codes [] = {
76*44704f69SBart Van Assche     { 0x00, "Copy from block device to stream device" },
77*44704f69SBart Van Assche     { 0x01, "Copy from stream device to block device" },
78*44704f69SBart Van Assche     { 0x02, "Copy from block device to block device" },
79*44704f69SBart Van Assche     { 0x03, "Copy from stream device to stream device" },
80*44704f69SBart Van Assche     { 0x04, "Copy inline data to stream device" },
81*44704f69SBart Van Assche     { 0x05, "Copy embedded data to stream device" },
82*44704f69SBart Van Assche     { 0x06, "Read from stream device and discard" },
83*44704f69SBart Van Assche     { 0x07, "Verify block or stream device operation" },
84*44704f69SBart Van Assche     { 0x08, "Copy block device with offset to stream device" },
85*44704f69SBart Van Assche     { 0x09, "Copy stream device to block device with offset" },
86*44704f69SBart Van Assche     { 0x0A, "Copy block device with offset to block device with offset" },
87*44704f69SBart Van Assche     { 0x0B, "Copy from block device to stream device "
88*44704f69SBart Van Assche       "and hold a copy of processed data for the application client" },
89*44704f69SBart Van Assche     { 0x0C, "Copy from stream device to block device "
90*44704f69SBart Van Assche       "and hold a copy of processed data for the application client" },
91*44704f69SBart Van Assche     { 0x0D, "Copy from block device to block device "
92*44704f69SBart Van Assche       "and hold a copy of processed data for the application client" },
93*44704f69SBart Van Assche     { 0x0E, "Copy from stream device to stream device "
94*44704f69SBart Van Assche       "and hold a copy of processed data for the application client" },
95*44704f69SBart Van Assche     { 0x0F, "Read from stream device "
96*44704f69SBart Van Assche       "and hold a copy of processed data for the application client" },
97*44704f69SBart Van Assche     { 0x10, "Write filemarks to sequential-access device" },
98*44704f69SBart Van Assche     { 0x11, "Space records or filemarks on sequential-access device" },
99*44704f69SBart Van Assche     { 0x12, "Locate on sequential-access device" },
100*44704f69SBart Van Assche     { 0x13, "Image copy from sequential-access device to sequential-access "
101*44704f69SBart Van Assche             "device" },
102*44704f69SBart Van Assche     { 0x14, "Register persistent reservation key" },
103*44704f69SBart Van Assche     { 0x15, "Third party persistent reservations source I_T nexus" },
104*44704f69SBart Van Assche     { -1, "" }
105*44704f69SBart Van Assche };
106*44704f69SBart Van Assche 
107*44704f69SBart Van Assche 
108*44704f69SBart Van Assche static void
scsi_failed_segment_details(uint8_t * rcBuff,unsigned int rcBuffLen)109*44704f69SBart Van Assche scsi_failed_segment_details(uint8_t *rcBuff, unsigned int rcBuffLen)
110*44704f69SBart Van Assche {
111*44704f69SBart Van Assche     int senseLen;
112*44704f69SBart Van Assche     unsigned int len;
113*44704f69SBart Van Assche     char senseBuff[1024];
114*44704f69SBart Van Assche 
115*44704f69SBart Van Assche     if (rcBuffLen < 4) {
116*44704f69SBart Van Assche         pr2serr("  <<not enough data to procedd report>>\n");
117*44704f69SBart Van Assche         return;
118*44704f69SBart Van Assche     }
119*44704f69SBart Van Assche     len = sg_get_unaligned_be32(rcBuff + 0);
120*44704f69SBart Van Assche     if (len + 4 > rcBuffLen) {
121*44704f69SBart Van Assche         pr2serr("  <<report len %d > %d too long for internal buffer, output "
122*44704f69SBart Van Assche                 "truncated\n", len, rcBuffLen);
123*44704f69SBart Van Assche     }
124*44704f69SBart Van Assche     if (len < 52) {
125*44704f69SBart Van Assche         pr2serr("  <<no segment details, response data length %d\n", len);
126*44704f69SBart Van Assche         return;
127*44704f69SBart Van Assche     }
128*44704f69SBart Van Assche     printf("Receive copy results (failed segment details):\n");
129*44704f69SBart Van Assche     printf("    Extended copy command status: %d\n", rcBuff[56]);
130*44704f69SBart Van Assche     senseLen = sg_get_unaligned_be16(rcBuff + 58);
131*44704f69SBart Van Assche     sg_get_sense_str("    ", &rcBuff[60], senseLen, 0, 1024, senseBuff);
132*44704f69SBart Van Assche     printf("%s", senseBuff);
133*44704f69SBart Van Assche }
134*44704f69SBart Van Assche 
135*44704f69SBart Van Assche static void
scsi_copy_status(uint8_t * rcBuff,unsigned int rcBuffLen)136*44704f69SBart Van Assche scsi_copy_status(uint8_t *rcBuff, unsigned int rcBuffLen)
137*44704f69SBart Van Assche {
138*44704f69SBart Van Assche     unsigned int len;
139*44704f69SBart Van Assche 
140*44704f69SBart Van Assche     if (rcBuffLen < 4) {
141*44704f69SBart Van Assche         pr2serr("  <<not enough data to proceed report>>\n");
142*44704f69SBart Van Assche         return;
143*44704f69SBart Van Assche     }
144*44704f69SBart Van Assche     len = sg_get_unaligned_be32(rcBuff + 0);
145*44704f69SBart Van Assche     if (len + 4 > rcBuffLen) {
146*44704f69SBart Van Assche         pr2serr("  <<report len %d > %d too long for internal buffer, output "
147*44704f69SBart Van Assche                 "truncated\n", len, rcBuffLen);
148*44704f69SBart Van Assche     }
149*44704f69SBart Van Assche     printf("Receive copy results (copy status):\n");
150*44704f69SBart Van Assche     printf("    Held data discarded: %s\n", rcBuff[4] & 0x80 ? "Yes":"No");
151*44704f69SBart Van Assche     printf("    Copy manager status: ");
152*44704f69SBart Van Assche     switch (rcBuff[4] & 0x7f) {
153*44704f69SBart Van Assche     case 0:
154*44704f69SBart Van Assche         printf("Operation in progress\n");
155*44704f69SBart Van Assche         break;
156*44704f69SBart Van Assche     case 1:
157*44704f69SBart Van Assche         printf("Operation completed without errors\n");
158*44704f69SBart Van Assche         break;
159*44704f69SBart Van Assche     case 2:
160*44704f69SBart Van Assche         printf("Operation completed with errors\n");
161*44704f69SBart Van Assche         break;
162*44704f69SBart Van Assche     default:
163*44704f69SBart Van Assche         printf("Unknown/Reserved\n");
164*44704f69SBart Van Assche         break;
165*44704f69SBart Van Assche     }
166*44704f69SBart Van Assche     printf("    Segments processed: %u\n", sg_get_unaligned_be16(rcBuff + 5));
167*44704f69SBart Van Assche     printf("    Transfer count units: %u\n", rcBuff[7]);
168*44704f69SBart Van Assche     printf("    Transfer count: %u\n", sg_get_unaligned_be32(rcBuff + 8));
169*44704f69SBart Van Assche }
170*44704f69SBart Van Assche 
171*44704f69SBart Van Assche static void
scsi_operating_parameters(uint8_t * rcBuff,unsigned int rcBuffLen)172*44704f69SBart Van Assche scsi_operating_parameters(uint8_t *rcBuff, unsigned int rcBuffLen)
173*44704f69SBart Van Assche {
174*44704f69SBart Van Assche     unsigned int len, n;
175*44704f69SBart Van Assche 
176*44704f69SBart Van Assche     len = sg_get_unaligned_be32(rcBuff + 0);
177*44704f69SBart Van Assche     if (len + 4 > rcBuffLen) {
178*44704f69SBart Van Assche         pr2serr("  <<report len %d > %d too long for internal buffer, output "
179*44704f69SBart Van Assche                 "truncated\n", len, rcBuffLen);
180*44704f69SBart Van Assche     }
181*44704f69SBart Van Assche     printf("Receive copy results (report operating parameters):\n");
182*44704f69SBart Van Assche     printf("    Supports no list identifier (SNLID): %s\n",
183*44704f69SBart Van Assche            rcBuff[4] & 1 ? "yes" : "no");
184*44704f69SBart Van Assche     n = sg_get_unaligned_be16(rcBuff + 8);
185*44704f69SBart Van Assche     printf("    Maximum target descriptor count: %u\n", n);
186*44704f69SBart Van Assche     n = sg_get_unaligned_be16(rcBuff + 10);
187*44704f69SBart Van Assche     printf("    Maximum segment descriptor count: %u\n", n);
188*44704f69SBart Van Assche     n = sg_get_unaligned_be32(rcBuff + 12);
189*44704f69SBart Van Assche     printf("    Maximum descriptor list length: %u bytes\n", n);
190*44704f69SBart Van Assche     n = sg_get_unaligned_be32(rcBuff + 16);
191*44704f69SBart Van Assche     printf("    Maximum segment length: %u bytes\n", n);
192*44704f69SBart Van Assche     n = sg_get_unaligned_be32(rcBuff + 20);
193*44704f69SBart Van Assche     if (n == 0) {
194*44704f69SBart Van Assche         printf("    Inline data not supported\n");
195*44704f69SBart Van Assche     } else {
196*44704f69SBart Van Assche         printf("    Maximum inline data length: %u bytes\n", n);
197*44704f69SBart Van Assche     }
198*44704f69SBart Van Assche     n = sg_get_unaligned_be32(rcBuff + 24);
199*44704f69SBart Van Assche     printf("    Held data limit: %u bytes\n", n);
200*44704f69SBart Van Assche     n = sg_get_unaligned_be32(rcBuff + 28);
201*44704f69SBart Van Assche     printf("    Maximum stream device transfer size: %u bytes\n", n);
202*44704f69SBart Van Assche     n = sg_get_unaligned_be16(rcBuff + 34);
203*44704f69SBart Van Assche     printf("    Total concurrent copies: %u\n", n);
204*44704f69SBart Van Assche     printf("    Maximum concurrent copies: %u\n", rcBuff[36]);
205*44704f69SBart Van Assche     if (rcBuff[37] > 30)
206*44704f69SBart Van Assche         printf("    Data segment granularity: 2**%u bytes\n", rcBuff[37]);
207*44704f69SBart Van Assche     else
208*44704f69SBart Van Assche         printf("    Data segment granularity: %u bytes\n",
209*44704f69SBart Van Assche                (unsigned int)(1 << rcBuff[37]));
210*44704f69SBart Van Assche     if (rcBuff[38] > 30)
211*44704f69SBart Van Assche         printf("    Inline data granularity: %u bytes\n", rcBuff[38]);
212*44704f69SBart Van Assche     else
213*44704f69SBart Van Assche         printf("    Inline data granularity: %u bytes\n",
214*44704f69SBart Van Assche                (unsigned int)(1 << rcBuff[38]));
215*44704f69SBart Van Assche     if (rcBuff[39] > 30)
216*44704f69SBart Van Assche         printf("    Held data granularity: 2**%u bytes\n", rcBuff[39]);
217*44704f69SBart Van Assche     else
218*44704f69SBart Van Assche         printf("    Held data granularity: %u bytes\n",
219*44704f69SBart Van Assche                (unsigned int)(1 << rcBuff[39]));
220*44704f69SBart Van Assche 
221*44704f69SBart Van Assche     printf("    Implemented descriptor list:\n");
222*44704f69SBart Van Assche     for (n = 0; n < rcBuff[43]; n++) {
223*44704f69SBart Van Assche         int code = rcBuff[44 + n];
224*44704f69SBart Van Assche 
225*44704f69SBart Van Assche         if (code < 0x16) {
226*44704f69SBart Van Assche             struct descriptor_type *seg_desc = segment_descriptor_codes;
227*44704f69SBart Van Assche             while (strlen(seg_desc->desc)) {
228*44704f69SBart Van Assche                 if (seg_desc->code == code)
229*44704f69SBart Van Assche                     break;
230*44704f69SBart Van Assche                 seg_desc++;
231*44704f69SBart Van Assche             }
232*44704f69SBart Van Assche             printf("        Segment descriptor 0x%02x: %s\n", code,
233*44704f69SBart Van Assche                    strlen(seg_desc->desc) ? seg_desc->desc : "Reserved");
234*44704f69SBart Van Assche         } else if (code < 0xc0) {
235*44704f69SBart Van Assche             printf("        Segment descriptor 0x%02x: Reserved\n", code);
236*44704f69SBart Van Assche         } else if (code < 0xe0) {
237*44704f69SBart Van Assche             printf("        Vendor specific descriptor 0x%02x\n", code);
238*44704f69SBart Van Assche         } else {
239*44704f69SBart Van Assche             struct descriptor_type *tgt_desc = target_descriptor_codes;
240*44704f69SBart Van Assche 
241*44704f69SBart Van Assche             while (strlen(tgt_desc->desc)) {
242*44704f69SBart Van Assche                 if (tgt_desc->code == code)
243*44704f69SBart Van Assche                     break;
244*44704f69SBart Van Assche                 tgt_desc++;
245*44704f69SBart Van Assche             }
246*44704f69SBart Van Assche             printf("        Target descriptor 0x%02x: %s\n", code,
247*44704f69SBart Van Assche                    strlen(tgt_desc->desc) ? tgt_desc->desc : "Reserved");
248*44704f69SBart Van Assche         }
249*44704f69SBart Van Assche     }
250*44704f69SBart Van Assche     printf("\n");
251*44704f69SBart Van Assche }
252*44704f69SBart Van Assche 
253*44704f69SBart Van Assche static struct option long_options[] = {
254*44704f69SBart Van Assche         {"failed", no_argument, 0, 'f'},
255*44704f69SBart Van Assche         {"help", no_argument, 0, 'h'},
256*44704f69SBart Van Assche         {"hex", no_argument, 0, 'H'},
257*44704f69SBart Van Assche         {"list_id", required_argument, 0, 'l'},
258*44704f69SBart Van Assche         {"list-id", required_argument, 0, 'l'},
259*44704f69SBart Van Assche         {"params", no_argument, 0, 'p'},
260*44704f69SBart Van Assche         {"readonly", no_argument, 0, 'R'},
261*44704f69SBart Van Assche         {"receive", no_argument, 0, 'r'},
262*44704f69SBart Van Assche         {"status", no_argument, 0, 's'},
263*44704f69SBart Van Assche         {"verbose", no_argument, 0, 'v'},
264*44704f69SBart Van Assche         {"version", no_argument, 0, 'V'},
265*44704f69SBart Van Assche         {"xfer_len", required_argument, 0, 'x'},
266*44704f69SBart Van Assche         {0, 0, 0, 0},
267*44704f69SBart Van Assche };
268*44704f69SBart Van Assche 
269*44704f69SBart Van Assche static void
usage()270*44704f69SBart Van Assche usage()
271*44704f69SBart Van Assche {
272*44704f69SBart Van Assche   pr2serr("Usage: "
273*44704f69SBart Van Assche           "sg_copy_results [--failed|--params|--receive|--status] [--help]\n"
274*44704f69SBart Van Assche           "                       [--hex] [--list_id=ID] [--readonly] "
275*44704f69SBart Van Assche           "[--verbose]\n"
276*44704f69SBart Van Assche           "                       [--version] [--xfer_len=BTL] DEVICE\n"
277*44704f69SBart Van Assche           "  where:\n"
278*44704f69SBart Van Assche           "    --failed|-f          use FAILED SEGMENT DETAILS service "
279*44704f69SBart Van Assche           "action\n"
280*44704f69SBart Van Assche           "    --help|-h            print out usage message\n"
281*44704f69SBart Van Assche           "    --hex|-H             print out response buffer in hex\n"
282*44704f69SBart Van Assche           "    --list_id=ID|-l ID   list identifier (default: 0)\n"
283*44704f69SBart Van Assche           "    --params|-p          use OPERATING PARAMETERS service "
284*44704f69SBart Van Assche           "action\n"
285*44704f69SBart Van Assche           "    --readonly|-R        open DEVICE read-only (def: read-write)\n"
286*44704f69SBart Van Assche           "    --receive|-r         use RECEIVE DATA service action\n"
287*44704f69SBart Van Assche           "    --status|-s          use COPY STATUS service action\n"
288*44704f69SBart Van Assche           "    --verbose|-v         increase verbosity\n"
289*44704f69SBart Van Assche           "    --version|-V         print version string then exit\n"
290*44704f69SBart Van Assche           "    --xfer_len=BTL|-x BTL    byte transfer length (< 10000) "
291*44704f69SBart Van Assche           "(default:\n"
292*44704f69SBart Van Assche           "                             520 bytes)\n\n"
293*44704f69SBart Van Assche           "Performs a SCSI RECEIVE COPY RESULTS command. Returns the "
294*44704f69SBart Van Assche           "response as\nspecified by the service action parameters.\n"
295*44704f69SBart Van Assche           );
296*44704f69SBart Van Assche }
297*44704f69SBart Van Assche 
298*44704f69SBart Van Assche static const char * rec_copy_name_arr[] = {
299*44704f69SBart Van Assche     "Receive copy status(LID1)",
300*44704f69SBart Van Assche     "Receive copy data(LID1)",
301*44704f69SBart Van Assche     "Receive copy [0x2]",
302*44704f69SBart Van Assche     "Receive copy operating parameters",
303*44704f69SBart Van Assche     "Receive copy failure details(LID1)",
304*44704f69SBart Van Assche };
305*44704f69SBart Van Assche 
306*44704f69SBart Van Assche int
main(int argc,char * argv[])307*44704f69SBart Van Assche main(int argc, char * argv[])
308*44704f69SBart Van Assche {
309*44704f69SBart Van Assche     bool do_hex = false;
310*44704f69SBart Van Assche     bool o_readonly = false;
311*44704f69SBart Van Assche     bool verbose_given = false;
312*44704f69SBart Van Assche     bool version_given = false;
313*44704f69SBart Van Assche     int res, c, k;
314*44704f69SBart Van Assche     int ret = 1;
315*44704f69SBart Van Assche     int sa = 3;
316*44704f69SBart Van Assche     int sg_fd = -1;
317*44704f69SBart Van Assche     int verbose = 0;
318*44704f69SBart Van Assche     int xfer_len = 520;
319*44704f69SBart Van Assche     uint32_t list_id = 0;
320*44704f69SBart Van Assche     const char * cp;
321*44704f69SBart Van Assche     uint8_t * cpResultBuff = NULL;
322*44704f69SBart Van Assche     uint8_t * free_cprb = NULL;
323*44704f69SBart Van Assche     const char * device_name = NULL;
324*44704f69SBart Van Assche     char file_name[256];
325*44704f69SBart Van Assche 
326*44704f69SBart Van Assche     memset(file_name, 0, sizeof file_name);
327*44704f69SBart Van Assche     while (1) {
328*44704f69SBart Van Assche         int option_index = 0;
329*44704f69SBart Van Assche 
330*44704f69SBart Van Assche         c = getopt_long(argc, argv, "fhHl:prRsvVx:", long_options,
331*44704f69SBart Van Assche                         &option_index);
332*44704f69SBart Van Assche         if (c == -1)
333*44704f69SBart Van Assche             break;
334*44704f69SBart Van Assche 
335*44704f69SBart Van Assche         switch (c) {
336*44704f69SBart Van Assche         case 'f':
337*44704f69SBart Van Assche             sa = 4;
338*44704f69SBart Van Assche             break;
339*44704f69SBart Van Assche         case 'H':
340*44704f69SBart Van Assche             do_hex = true;
341*44704f69SBart Van Assche             break;
342*44704f69SBart Van Assche         case 'h':
343*44704f69SBart Van Assche         case '?':
344*44704f69SBart Van Assche             usage();
345*44704f69SBart Van Assche             return 0;
346*44704f69SBart Van Assche         case 'l':
347*44704f69SBart Van Assche             k = sg_get_num(optarg);
348*44704f69SBart Van Assche             if (-1 == k) {
349*44704f69SBart Van Assche                 pr2serr("bad argument to '--list_id'\n");
350*44704f69SBart Van Assche                 return SG_LIB_SYNTAX_ERROR;
351*44704f69SBart Van Assche             }
352*44704f69SBart Van Assche             list_id = (uint32_t)k;
353*44704f69SBart Van Assche             break;
354*44704f69SBart Van Assche         case 'p':
355*44704f69SBart Van Assche             sa = 3;
356*44704f69SBart Van Assche             break;
357*44704f69SBart Van Assche         case 'r':
358*44704f69SBart Van Assche             sa = 1;
359*44704f69SBart Van Assche             break;
360*44704f69SBart Van Assche         case 'R':
361*44704f69SBart Van Assche             o_readonly = true;
362*44704f69SBart Van Assche             break;
363*44704f69SBart Van Assche         case 's':
364*44704f69SBart Van Assche             sa = 0;
365*44704f69SBart Van Assche             break;
366*44704f69SBart Van Assche         case 'v':
367*44704f69SBart Van Assche             ++verbose;
368*44704f69SBart Van Assche             verbose_given = true;
369*44704f69SBart Van Assche             break;
370*44704f69SBart Van Assche         case 'V':
371*44704f69SBart Van Assche             version_given = true;
372*44704f69SBart Van Assche             break;
373*44704f69SBart Van Assche         case 'x':
374*44704f69SBart Van Assche             xfer_len = sg_get_num(optarg);
375*44704f69SBart Van Assche             if (-1 == xfer_len) {
376*44704f69SBart Van Assche                 pr2serr("bad argument to '--xfer_len'\n");
377*44704f69SBart Van Assche                 return SG_LIB_SYNTAX_ERROR;
378*44704f69SBart Van Assche             }
379*44704f69SBart Van Assche             break;
380*44704f69SBart Van Assche         default:
381*44704f69SBart Van Assche             pr2serr("unrecognised option code 0x%x ??\n", c);
382*44704f69SBart Van Assche             usage();
383*44704f69SBart Van Assche             return SG_LIB_SYNTAX_ERROR;
384*44704f69SBart Van Assche         }
385*44704f69SBart Van Assche     }
386*44704f69SBart Van Assche     if (optind < argc) {
387*44704f69SBart Van Assche         if (NULL == device_name) {
388*44704f69SBart Van Assche             device_name = argv[optind];
389*44704f69SBart Van Assche             ++optind;
390*44704f69SBart Van Assche         }
391*44704f69SBart Van Assche         if (optind < argc) {
392*44704f69SBart Van Assche             for (; optind < argc; ++optind)
393*44704f69SBart Van Assche                 pr2serr("Unexpected extra argument: %s\n", argv[optind]);
394*44704f69SBart Van Assche             usage();
395*44704f69SBart Van Assche             return SG_LIB_SYNTAX_ERROR;
396*44704f69SBart Van Assche         }
397*44704f69SBart Van Assche     }
398*44704f69SBart Van Assche 
399*44704f69SBart Van Assche #ifdef DEBUG
400*44704f69SBart Van Assche     pr2serr("In DEBUG mode, ");
401*44704f69SBart Van Assche     if (verbose_given && version_given) {
402*44704f69SBart Van Assche         pr2serr("but override: '-vV' given, zero verbose and continue\n");
403*44704f69SBart Van Assche         verbose_given = false;
404*44704f69SBart Van Assche         version_given = false;
405*44704f69SBart Van Assche         verbose = 0;
406*44704f69SBart Van Assche     } else if (! verbose_given) {
407*44704f69SBart Van Assche         pr2serr("set '-vv'\n");
408*44704f69SBart Van Assche         verbose = 2;
409*44704f69SBart Van Assche     } else
410*44704f69SBart Van Assche         pr2serr("keep verbose=%d\n", verbose);
411*44704f69SBart Van Assche #else
412*44704f69SBart Van Assche     if (verbose_given && version_given)
413*44704f69SBart Van Assche         pr2serr("Not in DEBUG mode, so '-vV' has no special action\n");
414*44704f69SBart Van Assche #endif
415*44704f69SBart Van Assche     if (version_given) {
416*44704f69SBart Van Assche         pr2serr(ME "version: %s\n", version_str);
417*44704f69SBart Van Assche         return 0;
418*44704f69SBart Van Assche     }
419*44704f69SBart Van Assche 
420*44704f69SBart Van Assche     if (NULL == device_name) {
421*44704f69SBart Van Assche         pr2serr("missing device name!\n\n");
422*44704f69SBart Van Assche         usage();
423*44704f69SBart Van Assche         return SG_LIB_SYNTAX_ERROR;
424*44704f69SBart Van Assche     }
425*44704f69SBart Van Assche     if (xfer_len >= MAX_XFER_LEN) {
426*44704f69SBart Van Assche         pr2serr("xfer_len (%d) is out of range ( < %d)\n", xfer_len,
427*44704f69SBart Van Assche                 MAX_XFER_LEN);
428*44704f69SBart Van Assche         usage();
429*44704f69SBart Van Assche         return SG_LIB_SYNTAX_ERROR;
430*44704f69SBart Van Assche     }
431*44704f69SBart Van Assche 
432*44704f69SBart Van Assche     cpResultBuff = (uint8_t *)sg_memalign(xfer_len, 0, &free_cprb,
433*44704f69SBart Van Assche                                           verbose > 3);
434*44704f69SBart Van Assche     if (NULL == cpResultBuff) {
435*44704f69SBart Van Assche             pr2serr(ME "out of memory\n");
436*44704f69SBart Van Assche             return sg_convert_errno(ENOMEM);
437*44704f69SBart Van Assche     }
438*44704f69SBart Van Assche 
439*44704f69SBart Van Assche     sg_fd = sg_cmds_open_device(device_name, o_readonly, verbose);
440*44704f69SBart Van Assche     if (sg_fd < 0) {
441*44704f69SBart Van Assche         if (verbose)
442*44704f69SBart Van Assche             pr2serr(ME "open error: %s: %s\n", device_name,
443*44704f69SBart Van Assche                     safe_strerror(-sg_fd));
444*44704f69SBart Van Assche         ret = sg_convert_errno(-sg_fd);
445*44704f69SBart Van Assche         goto finish;
446*44704f69SBart Van Assche     }
447*44704f69SBart Van Assche 
448*44704f69SBart Van Assche     if ((sa < 0) || (sa >= (int)SG_ARRAY_SIZE(rec_copy_name_arr)))
449*44704f69SBart Van Assche         cp = "Out of range service action";
450*44704f69SBart Van Assche     else
451*44704f69SBart Van Assche         cp = rec_copy_name_arr[sa];
452*44704f69SBart Van Assche     if (verbose)
453*44704f69SBart Van Assche         pr2serr(ME "issue %s to device %s\n\t\txfer_len= %d (0x%x), list_id=%"
454*44704f69SBart Van Assche                 PRIu32 "\n", cp, device_name, xfer_len, xfer_len, list_id);
455*44704f69SBart Van Assche 
456*44704f69SBart Van Assche     res = sg_ll_receive_copy_results(sg_fd, sa, list_id, cpResultBuff,
457*44704f69SBart Van Assche                                      xfer_len, true, verbose);
458*44704f69SBart Van Assche     ret = res;
459*44704f69SBart Van Assche     if (res) {
460*44704f69SBart Van Assche         char b[80];
461*44704f69SBart Van Assche 
462*44704f69SBart Van Assche         sg_get_category_sense_str(res, sizeof(b), b, verbose);
463*44704f69SBart Van Assche         pr2serr("  SCSI %s failed: %s\n", cp, b);
464*44704f69SBart Van Assche         goto finish;
465*44704f69SBart Van Assche     }
466*44704f69SBart Van Assche     if (do_hex) {
467*44704f69SBart Van Assche         hex2stdout(cpResultBuff, xfer_len, 1);
468*44704f69SBart Van Assche         goto finish;
469*44704f69SBart Van Assche     }
470*44704f69SBart Van Assche     switch (sa) {
471*44704f69SBart Van Assche     case 4: /* Failed segment details */
472*44704f69SBart Van Assche         scsi_failed_segment_details(cpResultBuff, xfer_len);
473*44704f69SBart Van Assche         break;
474*44704f69SBart Van Assche     case 3: /* Operating parameters */
475*44704f69SBart Van Assche         scsi_operating_parameters(cpResultBuff, xfer_len);
476*44704f69SBart Van Assche         break;
477*44704f69SBart Van Assche     case 0: /* Copy status */
478*44704f69SBart Van Assche         scsi_copy_status(cpResultBuff, xfer_len);
479*44704f69SBart Van Assche         break;
480*44704f69SBart Van Assche     default:
481*44704f69SBart Van Assche         hex2stdout(cpResultBuff, xfer_len, 1);
482*44704f69SBart Van Assche         break;
483*44704f69SBart Van Assche     }
484*44704f69SBart Van Assche 
485*44704f69SBart Van Assche finish:
486*44704f69SBart Van Assche     if (free_cprb)
487*44704f69SBart Van Assche         free(free_cprb);
488*44704f69SBart Van Assche     if (sg_fd >= 0) {
489*44704f69SBart Van Assche         res = sg_cmds_close_device(sg_fd);
490*44704f69SBart Van Assche         if (res < 0) {
491*44704f69SBart Van Assche             pr2serr(ME "close error: %s\n", safe_strerror(-res));
492*44704f69SBart Van Assche             if (0 == ret)
493*44704f69SBart Van Assche                 ret = sg_convert_errno(-res);
494*44704f69SBart Van Assche         }
495*44704f69SBart Van Assche     }
496*44704f69SBart Van Assche     if (0 == verbose) {
497*44704f69SBart Van Assche         if (! sg_if_can2stderr("sg_copy_results failed: ", ret))
498*44704f69SBart Van Assche             pr2serr("Some error occurred, try again with '-v' or '-vv' for "
499*44704f69SBart Van Assche                     "more information\n");
500*44704f69SBart Van Assche     }
501*44704f69SBart Van Assche     return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
502*44704f69SBart Van Assche }
503