xref: /aosp_15_r20/external/sg3_utils/src/sg_safte.c (revision 44704f698541f6367e81f991ef8bb54ccbf3fc18)
1*44704f69SBart Van Assche /*
2*44704f69SBart Van Assche  * Copyright (c) 2004-2018 Hannes Reinecke and 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 <stdint.h>
17*44704f69SBart Van Assche #include <string.h>
18*44704f69SBart Van Assche #include <ctype.h>
19*44704f69SBart Van Assche #include <getopt.h>
20*44704f69SBart Van Assche 
21*44704f69SBart Van Assche #ifdef HAVE_CONFIG_H
22*44704f69SBart Van Assche #include "config.h"
23*44704f69SBart Van Assche #endif
24*44704f69SBart Van Assche 
25*44704f69SBart Van Assche #include "sg_lib.h"
26*44704f69SBart Van Assche #include "sg_cmds_basic.h"
27*44704f69SBart Van Assche #include "sg_cmds_extra.h"
28*44704f69SBart Van Assche #include "sg_unaligned.h"
29*44704f69SBart Van Assche #include "sg_pr2serr.h"
30*44704f69SBart Van Assche 
31*44704f69SBart Van Assche /* A utility program for the Linux OS SCSI subsystem.
32*44704f69SBart Van Assche  *
33*44704f69SBart Van Assche  *  This program accesses a processor device which operates according
34*44704f69SBart Van Assche  *  to the 'SCSI Accessed Fault-Tolerant Enclosures' (SAF-TE) spec.
35*44704f69SBart Van Assche  */
36*44704f69SBart Van Assche 
37*44704f69SBart Van Assche static const char * version_str = "0.33 20180628";
38*44704f69SBart Van Assche 
39*44704f69SBart Van Assche 
40*44704f69SBart Van Assche #define SENSE_BUFF_LEN 64       /* Arbitrary, could be larger */
41*44704f69SBart Van Assche #define DEF_TIMEOUT 60000       /* 60,000 millisecs == 60 seconds */
42*44704f69SBart Van Assche #define EBUFF_SZ 256
43*44704f69SBart Van Assche 
44*44704f69SBart Van Assche #define RB_MODE_DESC 3
45*44704f69SBart Van Assche #define RWB_MODE_DATA 2
46*44704f69SBart Van Assche #define RWB_MODE_VENDOR 1
47*44704f69SBart Van Assche #define RB_DESC_LEN 4
48*44704f69SBart Van Assche 
49*44704f69SBart Van Assche #define SAFTE_CFG_FLAG_DOORLOCK 1
50*44704f69SBart Van Assche #define SAFTE_CFG_FLAG_ALARM 2
51*44704f69SBart Van Assche #define SAFTE_CFG_FLAG_CELSIUS 3
52*44704f69SBart Van Assche 
53*44704f69SBart Van Assche struct safte_cfg_t {
54*44704f69SBart Van Assche     int fans;
55*44704f69SBart Van Assche     int psupplies;
56*44704f69SBart Van Assche     int slots;
57*44704f69SBart Van Assche     int temps;
58*44704f69SBart Van Assche     int thermostats;
59*44704f69SBart Van Assche     int vendor_specific;
60*44704f69SBart Van Assche     int flags;
61*44704f69SBart Van Assche };
62*44704f69SBart Van Assche 
63*44704f69SBart Van Assche struct safte_cfg_t safte_cfg;
64*44704f69SBart Van Assche 
65*44704f69SBart Van Assche static unsigned int buf_capacity = 64;
66*44704f69SBart Van Assche 
67*44704f69SBart Van Assche static void
dStrRaw(const uint8_t * str,int len)68*44704f69SBart Van Assche dStrRaw(const uint8_t * str, int len)
69*44704f69SBart Van Assche {
70*44704f69SBart Van Assche     int k;
71*44704f69SBart Van Assche 
72*44704f69SBart Van Assche     for (k = 0; k < len; ++k)
73*44704f69SBart Van Assche         printf("%c", str[k]);
74*44704f69SBart Van Assche }
75*44704f69SBart Van Assche 
76*44704f69SBart Van Assche /* Buffer ID 0x0: Read Enclosure Configuration (mandatory) */
77*44704f69SBart Van Assche static int
read_safte_configuration(int sg_fd,uint8_t * rb_buff,unsigned int rb_len,int verbose)78*44704f69SBart Van Assche read_safte_configuration(int sg_fd, uint8_t *rb_buff,
79*44704f69SBart Van Assche                          unsigned int rb_len, int verbose)
80*44704f69SBart Van Assche {
81*44704f69SBart Van Assche     int res;
82*44704f69SBart Van Assche 
83*44704f69SBart Van Assche     if (rb_len < buf_capacity) {
84*44704f69SBart Van Assche         pr2serr("SCSI BUFFER size too small (%d/%d bytes)\n", rb_len,
85*44704f69SBart Van Assche                 buf_capacity);
86*44704f69SBart Van Assche         return SG_LIB_CAT_ILLEGAL_REQ;
87*44704f69SBart Van Assche     }
88*44704f69SBart Van Assche 
89*44704f69SBart Van Assche     if (verbose > 1)
90*44704f69SBart Van Assche         pr2serr("Use READ BUFFER,mode=vendor_specific,buff_id=0 to fetch "
91*44704f69SBart Van Assche                 "configuration\n");
92*44704f69SBart Van Assche     res = sg_ll_read_buffer(sg_fd, RWB_MODE_VENDOR, 0, 0,
93*44704f69SBart Van Assche                             rb_buff, rb_len, true, verbose);
94*44704f69SBart Van Assche     if (res && res != SG_LIB_CAT_RECOVERED)
95*44704f69SBart Van Assche         return res;
96*44704f69SBart Van Assche 
97*44704f69SBart Van Assche     safte_cfg.fans = rb_buff[0];
98*44704f69SBart Van Assche     safte_cfg.psupplies = rb_buff[1];
99*44704f69SBart Van Assche     safte_cfg.slots = rb_buff[2];
100*44704f69SBart Van Assche     safte_cfg.temps = rb_buff[4];
101*44704f69SBart Van Assche     if (rb_buff[3])
102*44704f69SBart Van Assche         safte_cfg.flags |= SAFTE_CFG_FLAG_DOORLOCK;
103*44704f69SBart Van Assche     if (rb_buff[5])
104*44704f69SBart Van Assche         safte_cfg.flags |= SAFTE_CFG_FLAG_ALARM;
105*44704f69SBart Van Assche     if (rb_buff[6] & 0x80)
106*44704f69SBart Van Assche         safte_cfg.flags |= SAFTE_CFG_FLAG_CELSIUS;
107*44704f69SBart Van Assche 
108*44704f69SBart Van Assche     safte_cfg.thermostats = rb_buff[6] & 0x0f;
109*44704f69SBart Van Assche     safte_cfg.vendor_specific = rb_buff[63];
110*44704f69SBart Van Assche 
111*44704f69SBart Van Assche     return 0;
112*44704f69SBart Van Assche }
113*44704f69SBart Van Assche 
114*44704f69SBart Van Assche static int
print_safte_configuration(void)115*44704f69SBart Van Assche print_safte_configuration(void)
116*44704f69SBart Van Assche {
117*44704f69SBart Van Assche     printf("Enclosure Configuration:\n");
118*44704f69SBart Van Assche     printf("\tNumber of Fans: %d\n", safte_cfg.fans);
119*44704f69SBart Van Assche     printf("\tNumber of Power Supplies: %d\n", safte_cfg.psupplies);
120*44704f69SBart Van Assche     printf("\tNumber of Device Slots: %d\n", safte_cfg.slots);
121*44704f69SBart Van Assche     printf("\tNumber of Temperature Sensors: %d\n", safte_cfg.temps);
122*44704f69SBart Van Assche     printf("\tNumber of Thermostats: %d\n", safte_cfg.thermostats);
123*44704f69SBart Van Assche     printf("\tVendor unique bytes: %d\n", safte_cfg.vendor_specific);
124*44704f69SBart Van Assche 
125*44704f69SBart Van Assche     return 0;
126*44704f69SBart Van Assche }
127*44704f69SBart Van Assche 
128*44704f69SBart Van Assche /* Buffer ID 0x01: Read Enclosure Status (mandatory) */
129*44704f69SBart Van Assche static int
do_safte_encl_status(int sg_fd,int do_hex,int do_raw,int verbose)130*44704f69SBart Van Assche do_safte_encl_status(int sg_fd, int do_hex, int do_raw, int verbose)
131*44704f69SBart Van Assche {
132*44704f69SBart Van Assche     int res, i, offset;
133*44704f69SBart Van Assche     unsigned int rb_len;
134*44704f69SBart Van Assche     uint8_t *rb_buff;
135*44704f69SBart Van Assche 
136*44704f69SBart Van Assche     rb_len = safte_cfg.fans + safte_cfg.psupplies + safte_cfg.slots +
137*44704f69SBart Van Assche         safte_cfg.temps + 5 + safte_cfg.vendor_specific;
138*44704f69SBart Van Assche     rb_buff = (uint8_t *)malloc(rb_len);
139*44704f69SBart Van Assche 
140*44704f69SBart Van Assche 
141*44704f69SBart Van Assche     if (verbose > 1)
142*44704f69SBart Van Assche         pr2serr("Use READ BUFFER,mode=vendor_specific,buff_id=1 to read "
143*44704f69SBart Van Assche                 "enclosure status\n");
144*44704f69SBart Van Assche     res = sg_ll_read_buffer(sg_fd, RWB_MODE_VENDOR, 1, 0,
145*44704f69SBart Van Assche                             rb_buff, rb_len, false, verbose);
146*44704f69SBart Van Assche     if (res && res != SG_LIB_CAT_RECOVERED)
147*44704f69SBart Van Assche         return res;
148*44704f69SBart Van Assche 
149*44704f69SBart Van Assche     if (do_raw > 1) {
150*44704f69SBart Van Assche         dStrRaw(rb_buff, buf_capacity);
151*44704f69SBart Van Assche         return 0;
152*44704f69SBart Van Assche     }
153*44704f69SBart Van Assche     if (do_hex > 1) {
154*44704f69SBart Van Assche         hex2stdout(rb_buff, buf_capacity, 1);
155*44704f69SBart Van Assche         return 0;
156*44704f69SBart Van Assche     }
157*44704f69SBart Van Assche     printf("Enclosure Status:\n");
158*44704f69SBart Van Assche     offset = 0;
159*44704f69SBart Van Assche     for (i = 0; i < safte_cfg.fans; i++) {
160*44704f69SBart Van Assche         printf("\tFan %d status: ", i);
161*44704f69SBart Van Assche         switch(rb_buff[i]) {
162*44704f69SBart Van Assche             case 0:
163*44704f69SBart Van Assche                 printf("operational\n");
164*44704f69SBart Van Assche                 break;
165*44704f69SBart Van Assche             case 1:
166*44704f69SBart Van Assche                 printf("malfunctioning\n");
167*44704f69SBart Van Assche                 break;
168*44704f69SBart Van Assche             case 2:
169*44704f69SBart Van Assche                 printf("not installed\n");
170*44704f69SBart Van Assche                 break;
171*44704f69SBart Van Assche             case 80:
172*44704f69SBart Van Assche                 printf("not reportable\n");
173*44704f69SBart Van Assche                 break;
174*44704f69SBart Van Assche             default:
175*44704f69SBart Van Assche                 printf("unknown\n");
176*44704f69SBart Van Assche                 break;
177*44704f69SBart Van Assche         }
178*44704f69SBart Van Assche     }
179*44704f69SBart Van Assche 
180*44704f69SBart Van Assche     offset += safte_cfg.fans;
181*44704f69SBart Van Assche     for (i = 0; i < safte_cfg.psupplies; i++) {
182*44704f69SBart Van Assche         printf("\tPower supply %d status: ", i);
183*44704f69SBart Van Assche         switch(rb_buff[i + offset]) {
184*44704f69SBart Van Assche             case 0:
185*44704f69SBart Van Assche                 printf("operational / on\n");
186*44704f69SBart Van Assche                 break;
187*44704f69SBart Van Assche             case 1:
188*44704f69SBart Van Assche                 printf("operational / off\n");
189*44704f69SBart Van Assche                 break;
190*44704f69SBart Van Assche             case 0x10:
191*44704f69SBart Van Assche                 printf("malfunctioning / on\n");
192*44704f69SBart Van Assche                 break;
193*44704f69SBart Van Assche             case 0x11:
194*44704f69SBart Van Assche                 printf("malfunctioning / off\n");
195*44704f69SBart Van Assche                 break;
196*44704f69SBart Van Assche             case 0x20:
197*44704f69SBart Van Assche                 printf("not present\n");
198*44704f69SBart Van Assche                 break;
199*44704f69SBart Van Assche             case 0x21:
200*44704f69SBart Van Assche                 printf("present\n");
201*44704f69SBart Van Assche                 break;
202*44704f69SBart Van Assche             case 0x80:
203*44704f69SBart Van Assche                 printf("not reportable\n");
204*44704f69SBart Van Assche                 break;
205*44704f69SBart Van Assche             default:
206*44704f69SBart Van Assche                 printf("unknown\n");
207*44704f69SBart Van Assche                 break;
208*44704f69SBart Van Assche         }
209*44704f69SBart Van Assche     }
210*44704f69SBart Van Assche 
211*44704f69SBart Van Assche     offset += safte_cfg.psupplies;
212*44704f69SBart Van Assche     for (i = 0; i < safte_cfg.slots; i++) {
213*44704f69SBart Van Assche         printf("\tDevice Slot %d: SCSI ID %d\n", i, rb_buff[i + offset]);
214*44704f69SBart Van Assche     }
215*44704f69SBart Van Assche 
216*44704f69SBart Van Assche     offset += safte_cfg.slots;
217*44704f69SBart Van Assche     if (safte_cfg.flags & SAFTE_CFG_FLAG_DOORLOCK) {
218*44704f69SBart Van Assche         switch(rb_buff[offset]) {
219*44704f69SBart Van Assche             case 0x0:
220*44704f69SBart Van Assche                 printf("\tDoor lock status: locked\n");
221*44704f69SBart Van Assche                 break;
222*44704f69SBart Van Assche             case 0x01:
223*44704f69SBart Van Assche                 printf("\tDoor lock status: unlocked\n");
224*44704f69SBart Van Assche                 break;
225*44704f69SBart Van Assche             case 0x80:
226*44704f69SBart Van Assche                 printf("\tDoor lock status: not reportable\n");
227*44704f69SBart Van Assche                 break;
228*44704f69SBart Van Assche         }
229*44704f69SBart Van Assche     } else {
230*44704f69SBart Van Assche         printf("\tDoor lock status: not installed\n");
231*44704f69SBart Van Assche     }
232*44704f69SBart Van Assche 
233*44704f69SBart Van Assche     offset++;
234*44704f69SBart Van Assche     if (!(safte_cfg.flags & SAFTE_CFG_FLAG_ALARM)) {
235*44704f69SBart Van Assche         printf("\tSpeaker status: not installed\n");
236*44704f69SBart Van Assche     } else {
237*44704f69SBart Van Assche         switch(rb_buff[offset]) {
238*44704f69SBart Van Assche             case 0x0:
239*44704f69SBart Van Assche                 printf("\tSpeaker status: off\n");
240*44704f69SBart Van Assche                 break;
241*44704f69SBart Van Assche             case 0x01:
242*44704f69SBart Van Assche                 printf("\tSpeaker status: on\n");
243*44704f69SBart Van Assche                 break;
244*44704f69SBart Van Assche         }
245*44704f69SBart Van Assche     }
246*44704f69SBart Van Assche 
247*44704f69SBart Van Assche     offset++;
248*44704f69SBart Van Assche     for (i = 0; i < safte_cfg.temps; i++) {
249*44704f69SBart Van Assche         int temp = rb_buff[i + offset];
250*44704f69SBart Van Assche         int is_celsius = !!(safte_cfg.flags & SAFTE_CFG_FLAG_CELSIUS);
251*44704f69SBart Van Assche 
252*44704f69SBart Van Assche         if (! is_celsius)
253*44704f69SBart Van Assche             temp -= 10;
254*44704f69SBart Van Assche 
255*44704f69SBart Van Assche         printf("\tTemperature sensor %d: %d deg %c\n", i, temp,
256*44704f69SBart Van Assche                is_celsius ? 'C' : 'F');
257*44704f69SBart Van Assche     }
258*44704f69SBart Van Assche 
259*44704f69SBart Van Assche     offset += safte_cfg.temps;
260*44704f69SBart Van Assche     if (safte_cfg.thermostats) {
261*44704f69SBart Van Assche         if (rb_buff[offset] & 0x80) {
262*44704f69SBart Van Assche             printf("\tEnclosure Temperature alert status: abnormal\n");
263*44704f69SBart Van Assche         } else {
264*44704f69SBart Van Assche             printf("\tEnclosure Temperature alert status: normal\n");
265*44704f69SBart Van Assche         }
266*44704f69SBart Van Assche     }
267*44704f69SBart Van Assche     return 0;
268*44704f69SBart Van Assche }
269*44704f69SBart Van Assche 
270*44704f69SBart Van Assche /* Buffer ID 0x02: Read Usage Statistics (optional) */
271*44704f69SBart Van Assche static int
do_safte_usage_statistics(int sg_fd,int do_hex,int do_raw,int verbose)272*44704f69SBart Van Assche do_safte_usage_statistics(int sg_fd, int do_hex, int do_raw, int verbose)
273*44704f69SBart Van Assche {
274*44704f69SBart Van Assche     int res;
275*44704f69SBart Van Assche     unsigned int rb_len;
276*44704f69SBart Van Assche     uint8_t *rb_buff;
277*44704f69SBart Van Assche     unsigned int minutes;
278*44704f69SBart Van Assche 
279*44704f69SBart Van Assche     rb_len = 16 + safte_cfg.vendor_specific;
280*44704f69SBart Van Assche     rb_buff = (uint8_t *)malloc(rb_len);
281*44704f69SBart Van Assche 
282*44704f69SBart Van Assche     if (verbose > 1)
283*44704f69SBart Van Assche         pr2serr("Use READ BUFFER,mode=vendor_specific,buff_id=2 to read "
284*44704f69SBart Van Assche                 "usage statistics\n");
285*44704f69SBart Van Assche     res = sg_ll_read_buffer(sg_fd, RWB_MODE_VENDOR, 2, 0,
286*44704f69SBart Van Assche                             rb_buff, rb_len, false, verbose);
287*44704f69SBart Van Assche     if (res) {
288*44704f69SBart Van Assche         if (res == SG_LIB_CAT_ILLEGAL_REQ) {
289*44704f69SBart Van Assche             printf("Usage Statistics:\n\tNot implemented\n");
290*44704f69SBart Van Assche             return 0;
291*44704f69SBart Van Assche         }
292*44704f69SBart Van Assche         if (res != SG_LIB_CAT_RECOVERED) {
293*44704f69SBart Van Assche             free(rb_buff);
294*44704f69SBart Van Assche             return res;
295*44704f69SBart Van Assche         }
296*44704f69SBart Van Assche     }
297*44704f69SBart Van Assche 
298*44704f69SBart Van Assche     if (do_raw > 1) {
299*44704f69SBart Van Assche         dStrRaw(rb_buff, buf_capacity);
300*44704f69SBart Van Assche         return 0;
301*44704f69SBart Van Assche     }
302*44704f69SBart Van Assche     if (do_hex > 1) {
303*44704f69SBart Van Assche         hex2stdout(rb_buff, buf_capacity, 1);
304*44704f69SBart Van Assche         return 0;
305*44704f69SBart Van Assche     }
306*44704f69SBart Van Assche     printf("Usage Statistics:\n");
307*44704f69SBart Van Assche     minutes = sg_get_unaligned_be32(rb_buff + 0);
308*44704f69SBart Van Assche     printf("\tPower on Minutes: %u\n", minutes);
309*44704f69SBart Van Assche     minutes = sg_get_unaligned_be32(rb_buff + 4);
310*44704f69SBart Van Assche     printf("\tPower on Cycles: %u\n", minutes);
311*44704f69SBart Van Assche 
312*44704f69SBart Van Assche     free(rb_buff);
313*44704f69SBart Van Assche     return 0;
314*44704f69SBart Van Assche }
315*44704f69SBart Van Assche 
316*44704f69SBart Van Assche /* Buffer ID 0x03: Read Device Insertions (optional) */
317*44704f69SBart Van Assche static int
do_safte_slot_insertions(int sg_fd,int do_hex,int do_raw,int verbose)318*44704f69SBart Van Assche do_safte_slot_insertions(int sg_fd, int do_hex, int do_raw, int verbose)
319*44704f69SBart Van Assche {
320*44704f69SBart Van Assche     int res, i;
321*44704f69SBart Van Assche     unsigned int rb_len;
322*44704f69SBart Van Assche     uint8_t *rb_buff, slot_status;
323*44704f69SBart Van Assche 
324*44704f69SBart Van Assche     rb_len = safte_cfg.slots * 2;
325*44704f69SBart Van Assche     rb_buff = (uint8_t *)malloc(rb_len);
326*44704f69SBart Van Assche 
327*44704f69SBart Van Assche     if (verbose > 1)
328*44704f69SBart Van Assche         pr2serr("Use READ BUFFER,mode=vendor_specific,buff_id=3 to read "
329*44704f69SBart Van Assche                 "device insertions\n");
330*44704f69SBart Van Assche     res = sg_ll_read_buffer(sg_fd, RWB_MODE_VENDOR, 3, 0,
331*44704f69SBart Van Assche                             rb_buff, rb_len, false, verbose);
332*44704f69SBart Van Assche     if (res ) {
333*44704f69SBart Van Assche         if (res == SG_LIB_CAT_ILLEGAL_REQ) {
334*44704f69SBart Van Assche                 printf("Slot insertions:\n\tNot implemented\n");
335*44704f69SBart Van Assche                 return 0;
336*44704f69SBart Van Assche         }
337*44704f69SBart Van Assche         if (res != SG_LIB_CAT_RECOVERED) {
338*44704f69SBart Van Assche                 free(rb_buff);
339*44704f69SBart Van Assche                 return res;
340*44704f69SBart Van Assche         }
341*44704f69SBart Van Assche     }
342*44704f69SBart Van Assche 
343*44704f69SBart Van Assche     if (do_raw > 1) {
344*44704f69SBart Van Assche         dStrRaw(rb_buff, buf_capacity);
345*44704f69SBart Van Assche         return 0;
346*44704f69SBart Van Assche     }
347*44704f69SBart Van Assche     if (do_hex > 1) {
348*44704f69SBart Van Assche         hex2stdout(rb_buff, buf_capacity, 1);
349*44704f69SBart Van Assche         return 0;
350*44704f69SBart Van Assche     }
351*44704f69SBart Van Assche     printf("Slot insertions:\n");
352*44704f69SBart Van Assche     for (i = 0; i < safte_cfg.slots; i++) {
353*44704f69SBart Van Assche         slot_status = sg_get_unaligned_be16(rb_buff + (i * 2));
354*44704f69SBart Van Assche         printf("\tSlot %d: %d insertions", i, slot_status);
355*44704f69SBart Van Assche     }
356*44704f69SBart Van Assche     free(rb_buff);
357*44704f69SBart Van Assche     return 0;
358*44704f69SBart Van Assche }
359*44704f69SBart Van Assche 
360*44704f69SBart Van Assche /* Buffer ID 0x04: Read Device Slot Status (mandatory) */
361*44704f69SBart Van Assche static int
do_safte_slot_status(int sg_fd,int do_hex,int do_raw,int verbose)362*44704f69SBart Van Assche do_safte_slot_status(int sg_fd, int do_hex, int do_raw, int verbose)
363*44704f69SBart Van Assche {
364*44704f69SBart Van Assche     int res, i;
365*44704f69SBart Van Assche     unsigned int rb_len;
366*44704f69SBart Van Assche     uint8_t *rb_buff, slot_status;
367*44704f69SBart Van Assche 
368*44704f69SBart Van Assche     rb_len = safte_cfg.slots * 4;
369*44704f69SBart Van Assche     rb_buff = (uint8_t *)malloc(rb_len);
370*44704f69SBart Van Assche 
371*44704f69SBart Van Assche     if (verbose > 1)
372*44704f69SBart Van Assche         pr2serr("Use READ BUFFER,mode=vendor_specific,buff_id=4 to read "
373*44704f69SBart Van Assche                 "device slot status\n");
374*44704f69SBart Van Assche     res = sg_ll_read_buffer(sg_fd, RWB_MODE_VENDOR, 4, 0,
375*44704f69SBart Van Assche                             rb_buff, rb_len, false, verbose);
376*44704f69SBart Van Assche     if (res && res != SG_LIB_CAT_RECOVERED) {
377*44704f69SBart Van Assche         free(rb_buff);
378*44704f69SBart Van Assche         return res;
379*44704f69SBart Van Assche     }
380*44704f69SBart Van Assche 
381*44704f69SBart Van Assche     if (do_raw > 1) {
382*44704f69SBart Van Assche         dStrRaw(rb_buff, buf_capacity);
383*44704f69SBart Van Assche         return 0;
384*44704f69SBart Van Assche     }
385*44704f69SBart Van Assche     if (do_hex > 1) {
386*44704f69SBart Van Assche         hex2stdout(rb_buff, buf_capacity, 1);
387*44704f69SBart Van Assche         return 0;
388*44704f69SBart Van Assche     }
389*44704f69SBart Van Assche     printf("Slot status:\n");
390*44704f69SBart Van Assche     for (i = 0; i < safte_cfg.slots; i++) {
391*44704f69SBart Van Assche         slot_status = rb_buff[i * 4 + 3];
392*44704f69SBart Van Assche         printf("\tSlot %d: ", i);
393*44704f69SBart Van Assche         if (slot_status & 0x7) {
394*44704f69SBart Van Assche             if (slot_status & 0x1)
395*44704f69SBart Van Assche                 printf("inserted ");
396*44704f69SBart Van Assche             if (slot_status & 0x2)
397*44704f69SBart Van Assche                 printf("ready ");
398*44704f69SBart Van Assche             if (slot_status & 0x4)
399*44704f69SBart Van Assche                 printf("activated ");
400*44704f69SBart Van Assche             printf("\n");
401*44704f69SBart Van Assche         } else {
402*44704f69SBart Van Assche             printf("empty\n");
403*44704f69SBart Van Assche         }
404*44704f69SBart Van Assche     }
405*44704f69SBart Van Assche     free(rb_buff);
406*44704f69SBart Van Assche     return 0;
407*44704f69SBart Van Assche }
408*44704f69SBart Van Assche 
409*44704f69SBart Van Assche /* Buffer ID 0x05: Read Global Flags (optional) */
410*44704f69SBart Van Assche static int
do_safte_global_flags(int sg_fd,int do_hex,int do_raw,int verbose)411*44704f69SBart Van Assche do_safte_global_flags(int sg_fd, int do_hex, int do_raw, int verbose)
412*44704f69SBart Van Assche {
413*44704f69SBart Van Assche     int res;
414*44704f69SBart Van Assche     unsigned int rb_len;
415*44704f69SBart Van Assche     uint8_t *rb_buff;
416*44704f69SBart Van Assche 
417*44704f69SBart Van Assche     rb_len = 16;
418*44704f69SBart Van Assche     rb_buff = (uint8_t *)malloc(rb_len);
419*44704f69SBart Van Assche 
420*44704f69SBart Van Assche     if (verbose > 1)
421*44704f69SBart Van Assche         pr2serr("Use READ BUFFER,mode=vendor_specific,buff_id=5 to read "
422*44704f69SBart Van Assche                 "global flags\n");
423*44704f69SBart Van Assche     res = sg_ll_read_buffer(sg_fd, RWB_MODE_VENDOR, 5, 0,
424*44704f69SBart Van Assche                             rb_buff, rb_len, false, verbose);
425*44704f69SBart Van Assche     if (res ) {
426*44704f69SBart Van Assche         if (res == SG_LIB_CAT_ILLEGAL_REQ) {
427*44704f69SBart Van Assche                 printf("Global Flags:\n\tNot implemented\n");
428*44704f69SBart Van Assche                 return 0;
429*44704f69SBart Van Assche         }
430*44704f69SBart Van Assche         if (res != SG_LIB_CAT_RECOVERED) {
431*44704f69SBart Van Assche                 free(rb_buff);
432*44704f69SBart Van Assche                 return res;
433*44704f69SBart Van Assche         }
434*44704f69SBart Van Assche     }
435*44704f69SBart Van Assche 
436*44704f69SBart Van Assche     if (do_raw > 1) {
437*44704f69SBart Van Assche         dStrRaw(rb_buff, buf_capacity);
438*44704f69SBart Van Assche         return 0;
439*44704f69SBart Van Assche     }
440*44704f69SBart Van Assche     if (do_hex > 1) {
441*44704f69SBart Van Assche         hex2stdout(rb_buff, buf_capacity, 1);
442*44704f69SBart Van Assche         return 0;
443*44704f69SBart Van Assche     }
444*44704f69SBart Van Assche     printf("Global Flags:\n");
445*44704f69SBart Van Assche     printf("\tAudible Alarm Control: %s\n",
446*44704f69SBart Van Assche            rb_buff[0] & 0x1?"on":"off");
447*44704f69SBart Van Assche     printf("\tGlobal Failure Indicator: %s\n",
448*44704f69SBart Van Assche            rb_buff[0] & 0x2?"on":"off");
449*44704f69SBart Van Assche     printf("\tGlobal Warning Indicator: %s\n",
450*44704f69SBart Van Assche            rb_buff[0] & 0x4?"on":"off");
451*44704f69SBart Van Assche     printf("\tEnclosure Power: %s\n",
452*44704f69SBart Van Assche            rb_buff[0] & 0x8?"on":"off");
453*44704f69SBart Van Assche     printf("\tCooling Failure: %s\n",
454*44704f69SBart Van Assche            rb_buff[0] & 0x10?"yes":"no");
455*44704f69SBart Van Assche     printf("\tPower Failure: %s\n",
456*44704f69SBart Van Assche            rb_buff[0] & 0x20?"yes":"no");
457*44704f69SBart Van Assche     printf("\tDrive Failure: %s\n",
458*44704f69SBart Van Assche            rb_buff[0] & 0x40?"yes":"no");
459*44704f69SBart Van Assche     printf("\tDrive Warning: %s\n",
460*44704f69SBart Van Assche            rb_buff[0] & 0x80?"yes":"no");
461*44704f69SBart Van Assche     printf("\tArray Failure: %s\n",
462*44704f69SBart Van Assche            rb_buff[1] & 0x1?"yes":"no");
463*44704f69SBart Van Assche     printf("\tArray Warning: %s\n",
464*44704f69SBart Van Assche            rb_buff[0] & 0x2?"yes":"no");
465*44704f69SBart Van Assche     printf("\tEnclosure Lock: %s\n",
466*44704f69SBart Van Assche            rb_buff[0] & 0x4?"on":"off");
467*44704f69SBart Van Assche     printf("\tEnclosure Identify: %s\n",
468*44704f69SBart Van Assche            rb_buff[0] & 0x8?"on":"off");
469*44704f69SBart Van Assche 
470*44704f69SBart Van Assche     free(rb_buff);
471*44704f69SBart Van Assche     return 0;
472*44704f69SBart Van Assche }
473*44704f69SBart Van Assche 
474*44704f69SBart Van Assche static void
usage()475*44704f69SBart Van Assche usage()
476*44704f69SBart Van Assche {
477*44704f69SBart Van Assche     pr2serr("Usage:  sg_safte [--config] [--devstatus] [--encstatus] "
478*44704f69SBart Van Assche             "[--flags] [--help]\n"
479*44704f69SBart Van Assche             "                 [--hex] [--insertions] [--raw] [--usage] "
480*44704f69SBart Van Assche             "[--verbose]\n"
481*44704f69SBart Van Assche             "                 [--version] DEVICE\n"
482*44704f69SBart Van Assche             "  where:\n"
483*44704f69SBart Van Assche             "    --config|-c         output enclosure configuration\n"
484*44704f69SBart Van Assche             "    --devstatus|-d      output device slot status\n"
485*44704f69SBart Van Assche             "    --encstatus|-s      output enclosure status\n"
486*44704f69SBart Van Assche             "    --flags|-f          output global flags\n"
487*44704f69SBart Van Assche             "    --help|-h           output command usage message then "
488*44704f69SBart Van Assche             "exit\n"
489*44704f69SBart Van Assche             "    --hex|-H            output enclosure config in hex\n"
490*44704f69SBart Van Assche             "    --insertions|-i     output insertion statistics\n"
491*44704f69SBart Van Assche             "    --raw|-r            output enclosure config in binary "
492*44704f69SBart Van Assche             "to stdout\n"
493*44704f69SBart Van Assche             "    --usage|-u          output usage statistics\n"
494*44704f69SBart Van Assche             "    --verbose|-v        increase verbosity\n"
495*44704f69SBart Van Assche             "    --version|-v        output version then exit\n\n"
496*44704f69SBart Van Assche             "Queries a SAF-TE processor device\n");
497*44704f69SBart Van Assche }
498*44704f69SBart Van Assche 
499*44704f69SBart Van Assche static struct option long_options[] = {
500*44704f69SBart Van Assche     {"config", 0, 0, 'c'},
501*44704f69SBart Van Assche     {"devstatus", 0, 0, 'd'},
502*44704f69SBart Van Assche     {"encstatus", 0, 0, 's'},
503*44704f69SBart Van Assche     {"flags", 0, 0, 'f'},
504*44704f69SBart Van Assche     {"help", 0, 0, 'h'},
505*44704f69SBart Van Assche     {"hex", 0, 0, 'H'},
506*44704f69SBart Van Assche     {"insertions", 0, 0, 'i'},
507*44704f69SBart Van Assche     {"raw", 0, 0, 'r'},
508*44704f69SBart Van Assche     {"usage", 0, 0, 'u'},
509*44704f69SBart Van Assche     {"verbose", 0, 0, 'v'},
510*44704f69SBart Van Assche     {"version", 0, 0, 'V'},
511*44704f69SBart Van Assche     {0, 0, 0, 0},
512*44704f69SBart Van Assche };
513*44704f69SBart Van Assche 
514*44704f69SBart Van Assche int
main(int argc,char * argv[])515*44704f69SBart Van Assche main(int argc, char * argv[])
516*44704f69SBart Van Assche {
517*44704f69SBart Van Assche     bool do_insertions = false;
518*44704f69SBart Van Assche     bool no_hex_raw;
519*44704f69SBart Van Assche     bool verbose_given = false;
520*44704f69SBart Van Assche     bool version_given = false;
521*44704f69SBart Van Assche     int c, ret, peri_type;
522*44704f69SBart Van Assche     int sg_fd = -1;
523*44704f69SBart Van Assche     int res = SG_LIB_CAT_OTHER;
524*44704f69SBart Van Assche     const char * device_name = NULL;
525*44704f69SBart Van Assche     char ebuff[EBUFF_SZ];
526*44704f69SBart Van Assche     uint8_t *rb_buff;
527*44704f69SBart Van Assche     bool do_config = false;
528*44704f69SBart Van Assche     bool do_status = false;
529*44704f69SBart Van Assche     bool do_slots = false;
530*44704f69SBart Van Assche     bool do_flags = false;
531*44704f69SBart Van Assche     bool do_usage = false;
532*44704f69SBart Van Assche     int do_hex = 0;
533*44704f69SBart Van Assche     int do_raw = 0;
534*44704f69SBart Van Assche     int verbose = 0;
535*44704f69SBart Van Assche     const char * cp;
536*44704f69SBart Van Assche     char buff[48];
537*44704f69SBart Van Assche     char b[80];
538*44704f69SBart Van Assche     struct sg_simple_inquiry_resp inq_resp;
539*44704f69SBart Van Assche     const char op_name[] = "READ BUFFER";
540*44704f69SBart Van Assche 
541*44704f69SBart Van Assche     while (1) {
542*44704f69SBart Van Assche         int option_index = 0;
543*44704f69SBart Van Assche 
544*44704f69SBart Van Assche         c = getopt_long(argc, argv, "cdfhHirsuvV?", long_options,
545*44704f69SBart Van Assche                         &option_index);
546*44704f69SBart Van Assche 
547*44704f69SBart Van Assche         if (c == -1)
548*44704f69SBart Van Assche             break;
549*44704f69SBart Van Assche 
550*44704f69SBart Van Assche         switch (c) {
551*44704f69SBart Van Assche             case 'c':
552*44704f69SBart Van Assche                 do_config = true;
553*44704f69SBart Van Assche                 break;
554*44704f69SBart Van Assche             case 'd':
555*44704f69SBart Van Assche                 do_slots = true;
556*44704f69SBart Van Assche                 break;
557*44704f69SBart Van Assche             case 'f':
558*44704f69SBart Van Assche                 do_flags = true;
559*44704f69SBart Van Assche                 break;
560*44704f69SBart Van Assche             case 'h':
561*44704f69SBart Van Assche             case '?':
562*44704f69SBart Van Assche                 usage();
563*44704f69SBart Van Assche                 return 0;
564*44704f69SBart Van Assche             case 'H':
565*44704f69SBart Van Assche                 ++do_hex;
566*44704f69SBart Van Assche                 break;
567*44704f69SBart Van Assche             case 'i':
568*44704f69SBart Van Assche                 do_insertions = true;
569*44704f69SBart Van Assche                 break;
570*44704f69SBart Van Assche             case 'r':
571*44704f69SBart Van Assche                 ++do_raw;
572*44704f69SBart Van Assche                 break;
573*44704f69SBart Van Assche             case 's':
574*44704f69SBart Van Assche                 do_status = true;
575*44704f69SBart Van Assche                 break;
576*44704f69SBart Van Assche             case 'u':
577*44704f69SBart Van Assche                 do_usage = true;
578*44704f69SBart Van Assche                 break;
579*44704f69SBart Van Assche             case 'v':
580*44704f69SBart Van Assche                 verbose_given = true;
581*44704f69SBart Van Assche                 ++verbose;
582*44704f69SBart Van Assche                 break;
583*44704f69SBart Van Assche             case 'V':
584*44704f69SBart Van Assche                 version_given = true;
585*44704f69SBart Van Assche                 break;
586*44704f69SBart Van Assche             default:
587*44704f69SBart Van Assche                 pr2serr("unrecognised option code 0x%x ??\n", c);
588*44704f69SBart Van Assche                 usage();
589*44704f69SBart Van Assche                 return SG_LIB_SYNTAX_ERROR;
590*44704f69SBart Van Assche         }
591*44704f69SBart Van Assche     }
592*44704f69SBart Van Assche     if (optind < argc) {
593*44704f69SBart Van Assche         if (NULL == device_name) {
594*44704f69SBart Van Assche             device_name = argv[optind];
595*44704f69SBart Van Assche             ++optind;
596*44704f69SBart Van Assche         }
597*44704f69SBart Van Assche         if (optind < argc) {
598*44704f69SBart Van Assche             for (; optind < argc; ++optind)
599*44704f69SBart Van Assche                 pr2serr("Unexpected extra argument: %s\n", argv[optind]);
600*44704f69SBart Van Assche             usage();
601*44704f69SBart Van Assche             return SG_LIB_SYNTAX_ERROR;
602*44704f69SBart Van Assche         }
603*44704f69SBart Van Assche     }
604*44704f69SBart Van Assche 
605*44704f69SBart Van Assche #ifdef DEBUG
606*44704f69SBart Van Assche     pr2serr("In DEBUG mode, ");
607*44704f69SBart Van Assche     if (verbose_given && version_given) {
608*44704f69SBart Van Assche         pr2serr("but override: '-vV' given, zero verbose and continue\n");
609*44704f69SBart Van Assche         verbose_given = false;
610*44704f69SBart Van Assche         version_given = false;
611*44704f69SBart Van Assche         verbose = 0;
612*44704f69SBart Van Assche     } else if (! verbose_given) {
613*44704f69SBart Van Assche         pr2serr("set '-vv'\n");
614*44704f69SBart Van Assche         verbose = 2;
615*44704f69SBart Van Assche     } else
616*44704f69SBart Van Assche         pr2serr("keep verbose=%d\n", verbose);
617*44704f69SBart Van Assche #else
618*44704f69SBart Van Assche     if (verbose_given && version_given)
619*44704f69SBart Van Assche         pr2serr("Not in DEBUG mode, so '-vV' has no special action\n");
620*44704f69SBart Van Assche #endif
621*44704f69SBart Van Assche     if (version_given) {
622*44704f69SBart Van Assche         pr2serr("Version string: %s\n", version_str);
623*44704f69SBart Van Assche         return 0;
624*44704f69SBart Van Assche     }
625*44704f69SBart Van Assche 
626*44704f69SBart Van Assche     if (NULL == device_name) {
627*44704f69SBart Van Assche         pr2serr("Missing device name!\n\n");
628*44704f69SBart Van Assche         usage();
629*44704f69SBart Van Assche         return SG_LIB_SYNTAX_ERROR;
630*44704f69SBart Van Assche     }
631*44704f69SBart Van Assche     if (do_raw) {
632*44704f69SBart Van Assche         if (sg_set_binary_mode(STDOUT_FILENO) < 0) {
633*44704f69SBart Van Assche             perror("sg_set_binary_mode");
634*44704f69SBart Van Assche             return SG_LIB_FILE_ERROR;
635*44704f69SBart Van Assche         }
636*44704f69SBart Van Assche     }
637*44704f69SBart Van Assche 
638*44704f69SBart Van Assche     if ((sg_fd = sg_cmds_open_device(device_name, false /* rw */, verbose))
639*44704f69SBart Van Assche         < 0) {
640*44704f69SBart Van Assche         if (verbose) {
641*44704f69SBart Van Assche             snprintf(ebuff, EBUFF_SZ, "sg_safte: error opening file: %s (rw)",
642*44704f69SBart Van Assche                      device_name);
643*44704f69SBart Van Assche             perror(ebuff);
644*44704f69SBart Van Assche         }
645*44704f69SBart Van Assche         ret = sg_convert_errno(-sg_fd);
646*44704f69SBart Van Assche         goto fini;
647*44704f69SBart Van Assche     }
648*44704f69SBart Van Assche     no_hex_raw = ((0 == do_hex) && (0 == do_raw));
649*44704f69SBart Van Assche 
650*44704f69SBart Van Assche     if (no_hex_raw) {
651*44704f69SBart Van Assche         if (0 == sg_simple_inquiry(sg_fd, &inq_resp, true, verbose)) {
652*44704f69SBart Van Assche             printf("  %.8s  %.16s  %.4s\n", inq_resp.vendor,
653*44704f69SBart Van Assche                    inq_resp.product, inq_resp.revision);
654*44704f69SBart Van Assche             peri_type = inq_resp.peripheral_type;
655*44704f69SBart Van Assche             cp = sg_get_pdt_str(peri_type, sizeof(buff), buff);
656*44704f69SBart Van Assche             if (strlen(cp) > 0)
657*44704f69SBart Van Assche                 printf("  Peripheral device type: %s\n", cp);
658*44704f69SBart Van Assche             else
659*44704f69SBart Van Assche                 printf("  Peripheral device type: 0x%x\n", peri_type);
660*44704f69SBart Van Assche         } else {
661*44704f69SBart Van Assche             pr2serr("sg_safte: %s doesn't respond to a SCSI INQUIRY\n",
662*44704f69SBart Van Assche                     device_name);
663*44704f69SBart Van Assche             return SG_LIB_CAT_OTHER;
664*44704f69SBart Van Assche         }
665*44704f69SBart Van Assche     }
666*44704f69SBart Van Assche 
667*44704f69SBart Van Assche     rb_buff = (uint8_t *)malloc(buf_capacity);
668*44704f69SBart Van Assche     if (!rb_buff)
669*44704f69SBart Van Assche         goto err_out;
670*44704f69SBart Van Assche 
671*44704f69SBart Van Assche     memset(rb_buff, 0, buf_capacity);
672*44704f69SBart Van Assche 
673*44704f69SBart Van Assche     res = read_safte_configuration(sg_fd, rb_buff, buf_capacity, verbose);
674*44704f69SBart Van Assche     switch (res) {
675*44704f69SBart Van Assche     case 0:
676*44704f69SBart Van Assche     case SG_LIB_CAT_RECOVERED:
677*44704f69SBart Van Assche         break;
678*44704f69SBart Van Assche     default:
679*44704f69SBart Van Assche         goto err_out;
680*44704f69SBart Van Assche     }
681*44704f69SBart Van Assche     if (1 == do_raw) {
682*44704f69SBart Van Assche         dStrRaw(rb_buff, buf_capacity);
683*44704f69SBart Van Assche         goto finish;
684*44704f69SBart Van Assche     }
685*44704f69SBart Van Assche     if (1 == do_hex) {
686*44704f69SBart Van Assche         hex2stdout(rb_buff, buf_capacity, 1);
687*44704f69SBart Van Assche         goto finish;
688*44704f69SBart Van Assche     }
689*44704f69SBart Van Assche 
690*44704f69SBart Van Assche     if (do_config && no_hex_raw)
691*44704f69SBart Van Assche         print_safte_configuration();
692*44704f69SBart Van Assche 
693*44704f69SBart Van Assche     if (do_status) {
694*44704f69SBart Van Assche         res = do_safte_encl_status(sg_fd, do_hex, do_raw, verbose);
695*44704f69SBart Van Assche         switch (res) {
696*44704f69SBart Van Assche             case 0:
697*44704f69SBart Van Assche             case SG_LIB_CAT_RECOVERED:
698*44704f69SBart Van Assche                 break;
699*44704f69SBart Van Assche             default:
700*44704f69SBart Van Assche                 goto err_out;
701*44704f69SBart Van Assche         }
702*44704f69SBart Van Assche     }
703*44704f69SBart Van Assche 
704*44704f69SBart Van Assche     if (do_usage) {
705*44704f69SBart Van Assche         res = do_safte_usage_statistics(sg_fd, do_hex, do_raw, verbose);
706*44704f69SBart Van Assche         switch (res) {
707*44704f69SBart Van Assche             case 0:
708*44704f69SBart Van Assche             case SG_LIB_CAT_RECOVERED:
709*44704f69SBart Van Assche                 break;
710*44704f69SBart Van Assche             default:
711*44704f69SBart Van Assche                 goto err_out;
712*44704f69SBart Van Assche         }
713*44704f69SBart Van Assche     }
714*44704f69SBart Van Assche 
715*44704f69SBart Van Assche     if (do_insertions) {
716*44704f69SBart Van Assche         res = do_safte_slot_insertions(sg_fd, do_hex, do_raw, verbose);
717*44704f69SBart Van Assche         switch (res) {
718*44704f69SBart Van Assche             case 0:
719*44704f69SBart Van Assche             case SG_LIB_CAT_RECOVERED:
720*44704f69SBart Van Assche                 break;
721*44704f69SBart Van Assche             default:
722*44704f69SBart Van Assche                 goto err_out;
723*44704f69SBart Van Assche         }
724*44704f69SBart Van Assche     }
725*44704f69SBart Van Assche 
726*44704f69SBart Van Assche     if (do_slots) {
727*44704f69SBart Van Assche         res = do_safte_slot_status(sg_fd, do_hex, do_raw, verbose);
728*44704f69SBart Van Assche         switch (res) {
729*44704f69SBart Van Assche             case 0:
730*44704f69SBart Van Assche             case SG_LIB_CAT_RECOVERED:
731*44704f69SBart Van Assche                 break;
732*44704f69SBart Van Assche             default:
733*44704f69SBart Van Assche                 goto err_out;
734*44704f69SBart Van Assche         }
735*44704f69SBart Van Assche     }
736*44704f69SBart Van Assche 
737*44704f69SBart Van Assche     if (do_flags) {
738*44704f69SBart Van Assche         res = do_safte_global_flags(sg_fd, do_hex, do_raw, verbose);
739*44704f69SBart Van Assche         switch (res) {
740*44704f69SBart Van Assche             case 0:
741*44704f69SBart Van Assche             case SG_LIB_CAT_RECOVERED:
742*44704f69SBart Van Assche                 break;
743*44704f69SBart Van Assche             default:
744*44704f69SBart Van Assche                 goto err_out;
745*44704f69SBart Van Assche         }
746*44704f69SBart Van Assche     }
747*44704f69SBart Van Assche finish:
748*44704f69SBart Van Assche     res = 0;
749*44704f69SBart Van Assche 
750*44704f69SBart Van Assche err_out:
751*44704f69SBart Van Assche     switch (res) {
752*44704f69SBart Van Assche     case 0:
753*44704f69SBart Van Assche     case SG_LIB_CAT_RECOVERED:
754*44704f69SBart Van Assche         break;
755*44704f69SBart Van Assche     default:
756*44704f69SBart Van Assche         sg_get_category_sense_str(res, sizeof(b), b, verbose);
757*44704f69SBart Van Assche         pr2serr("%s failed: %s\n", op_name, b);
758*44704f69SBart Van Assche         break;
759*44704f69SBart Van Assche     }
760*44704f69SBart Van Assche     ret = res;
761*44704f69SBart Van Assche fini:
762*44704f69SBart Van Assche     if (sg_fd >= 0) {
763*44704f69SBart Van Assche         res = sg_cmds_close_device(sg_fd);
764*44704f69SBart Van Assche         if (res < 0) {
765*44704f69SBart Van Assche             pr2serr("close error: %s\n", safe_strerror(-res));
766*44704f69SBart Van Assche             if (0 == ret)
767*44704f69SBart Van Assche                 ret = sg_convert_errno(-res);
768*44704f69SBart Van Assche         }
769*44704f69SBart Van Assche     }
770*44704f69SBart Van Assche     if (0 == verbose) {
771*44704f69SBart Van Assche         if (! sg_if_can2stderr("sg_safte failed: ", ret))
772*44704f69SBart Van Assche             pr2serr("Some error occurred, try again with '-v' "
773*44704f69SBart Van Assche                     "or '-vv' for more information\n");
774*44704f69SBart Van Assche     }
775*44704f69SBart Van Assche     return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
776*44704f69SBart Van Assche }
777