1*44704f69SBart Van Assche /*
2*44704f69SBart Van Assche * sg_rdac
3*44704f69SBart Van Assche *
4*44704f69SBart Van Assche * Retrieve / set RDAC options.
5*44704f69SBart Van Assche *
6*44704f69SBart Van Assche * Copyright (C) 2006-2018 Hannes Reinecke <[email protected]>
7*44704f69SBart Van Assche *
8*44704f69SBart Van Assche * Based on sg_modes.c and sg_emc_trespass.c; credits from there apply.
9*44704f69SBart Van Assche *
10*44704f69SBart Van Assche * This program is free software; you can redistribute it and/or modify
11*44704f69SBart Van Assche * it under the terms of the GNU General Public License as published by
12*44704f69SBart Van Assche * the Free Software Foundation; either version 2, or (at your option)
13*44704f69SBart Van Assche * any later version.
14*44704f69SBart Van Assche *
15*44704f69SBart Van Assche * SPDX-License-Identifier: GPL-2.0-or-later
16*44704f69SBart Van Assche */
17*44704f69SBart Van Assche
18*44704f69SBart Van Assche #include <stdio.h>
19*44704f69SBart Van Assche #include <stdlib.h>
20*44704f69SBart Van Assche #include <stdarg.h>
21*44704f69SBart Van Assche #include <stdbool.h>
22*44704f69SBart Van Assche #include <unistd.h>
23*44704f69SBart Van Assche #include <string.h>
24*44704f69SBart Van Assche
25*44704f69SBart Van Assche #ifdef HAVE_CONFIG_H
26*44704f69SBart Van Assche #include "config.h"
27*44704f69SBart Van Assche #endif
28*44704f69SBart Van Assche
29*44704f69SBart Van Assche #include "sg_lib.h"
30*44704f69SBart Van Assche #include "sg_cmds_basic.h"
31*44704f69SBart Van Assche #include "sg_unaligned.h"
32*44704f69SBart Van Assche #include "sg_pr2serr.h"
33*44704f69SBart Van Assche
34*44704f69SBart Van Assche
35*44704f69SBart Van Assche static const char * version_str = "1.17 20180512";
36*44704f69SBart Van Assche
37*44704f69SBart Van Assche uint8_t mode6_hdr[] = {
38*44704f69SBart Van Assche 0x75, /* Length */
39*44704f69SBart Van Assche 0, /* medium */
40*44704f69SBart Van Assche 0, /* params */
41*44704f69SBart Van Assche 8, /* Block descriptor length */
42*44704f69SBart Van Assche };
43*44704f69SBart Van Assche
44*44704f69SBart Van Assche uint8_t mode10_hdr[] = {
45*44704f69SBart Van Assche 0x01, 0x18, /* Length */
46*44704f69SBart Van Assche 0, /* medium */
47*44704f69SBart Van Assche 0, /* params */
48*44704f69SBart Van Assche 0, 0, /* reserved */
49*44704f69SBart Van Assche 0, 0, /* block descriptor length */
50*44704f69SBart Van Assche };
51*44704f69SBart Van Assche
52*44704f69SBart Van Assche uint8_t block_descriptor[] = {
53*44704f69SBart Van Assche 0, /* Density code */
54*44704f69SBart Van Assche 0, 0, 0, /* Number of blocks */
55*44704f69SBart Van Assche 0, /* Reserved */
56*44704f69SBart Van Assche 0, 0x02, 0, /* 512 byte blocks */
57*44704f69SBart Van Assche };
58*44704f69SBart Van Assche
59*44704f69SBart Van Assche struct rdac_page_common {
60*44704f69SBart Van Assche uint8_t current_serial[16];
61*44704f69SBart Van Assche uint8_t alternate_serial[16];
62*44704f69SBart Van Assche uint8_t current_mode_msb;
63*44704f69SBart Van Assche uint8_t current_mode_lsb;
64*44704f69SBart Van Assche uint8_t alternate_mode_msb;
65*44704f69SBart Van Assche uint8_t alternate_mode_lsb;
66*44704f69SBart Van Assche uint8_t quiescence;
67*44704f69SBart Van Assche uint8_t options;
68*44704f69SBart Van Assche };
69*44704f69SBart Van Assche
70*44704f69SBart Van Assche struct rdac_legacy_page {
71*44704f69SBart Van Assche uint8_t page_code;
72*44704f69SBart Van Assche uint8_t page_length;
73*44704f69SBart Van Assche struct rdac_page_common attr;
74*44704f69SBart Van Assche uint8_t lun_table[32];
75*44704f69SBart Van Assche uint8_t lun_table_exp[32];
76*44704f69SBart Van Assche unsigned short reserved;
77*44704f69SBart Van Assche };
78*44704f69SBart Van Assche
79*44704f69SBart Van Assche struct rdac_expanded_page {
80*44704f69SBart Van Assche uint8_t page_code;
81*44704f69SBart Van Assche uint8_t subpage_code;
82*44704f69SBart Van Assche uint8_t page_length[2];
83*44704f69SBart Van Assche struct rdac_page_common attr;
84*44704f69SBart Van Assche uint8_t lun_table[256];
85*44704f69SBart Van Assche uint8_t reserved[2];
86*44704f69SBart Van Assche };
87*44704f69SBart Van Assche
88*44704f69SBart Van Assche static int do_verbose = 0;
89*44704f69SBart Van Assche
dump_mode_page(uint8_t * page,int len)90*44704f69SBart Van Assche static void dump_mode_page( uint8_t *page, int len )
91*44704f69SBart Van Assche {
92*44704f69SBart Van Assche int i, k;
93*44704f69SBart Van Assche
94*44704f69SBart Van Assche for (k = 0; k < len; k += 16) {
95*44704f69SBart Van Assche
96*44704f69SBart Van Assche printf("%x:",k / 16);
97*44704f69SBart Van Assche for (i = 0; i < 16; i++) {
98*44704f69SBart Van Assche printf(" %02x", page[k + i]);
99*44704f69SBart Van Assche if (k + i >= len) {
100*44704f69SBart Van Assche printf("\n");
101*44704f69SBart Van Assche break;
102*44704f69SBart Van Assche }
103*44704f69SBart Van Assche }
104*44704f69SBart Van Assche printf("\n");
105*44704f69SBart Van Assche }
106*44704f69SBart Van Assche
107*44704f69SBart Van Assche }
108*44704f69SBart Van Assche
109*44704f69SBart Van Assche #define MX_ALLOC_LEN (1024 * 4)
110*44704f69SBart Van Assche #define RDAC_CONTROLLER_PAGE 0x2c
111*44704f69SBart Van Assche #define RDAC_CONTROLLER_PAGE_LEN 0x68
112*44704f69SBart Van Assche #define LEGACY_PAGE 0x00
113*44704f69SBart Van Assche #define EXPANDED_LUN_SPACE_PAGE 0x01
114*44704f69SBart Van Assche #define EXPANDED_LUN_SPACE_PAGE_LEN 0x128
115*44704f69SBart Van Assche #define RDAC_FAIL_ALL_PATHS 0x1
116*44704f69SBart Van Assche #define RDAC_FAIL_SELECTED_PATHS 0x2
117*44704f69SBart Van Assche #define RDAC_FORCE_QUIESCENCE 0x2
118*44704f69SBart Van Assche #define RDAC_QUIESCENCE_TIME 10
119*44704f69SBart Van Assche
fail_all_paths(int fd,bool use_6_byte)120*44704f69SBart Van Assche static int fail_all_paths(int fd, bool use_6_byte)
121*44704f69SBart Van Assche {
122*44704f69SBart Van Assche struct rdac_legacy_page *rdac_page;
123*44704f69SBart Van Assche struct rdac_expanded_page *rdac_page_exp;
124*44704f69SBart Van Assche struct rdac_page_common *rdac_common = NULL;
125*44704f69SBart Van Assche uint8_t fail_paths_pg[308];
126*44704f69SBart Van Assche
127*44704f69SBart Van Assche int res;
128*44704f69SBart Van Assche char b[80];
129*44704f69SBart Van Assche
130*44704f69SBart Van Assche memset(fail_paths_pg, 0, 308);
131*44704f69SBart Van Assche if (use_6_byte) {
132*44704f69SBart Van Assche memcpy(fail_paths_pg, mode6_hdr, 4);
133*44704f69SBart Van Assche memcpy(fail_paths_pg + 4, block_descriptor, 8);
134*44704f69SBart Van Assche rdac_page = (struct rdac_legacy_page *)(fail_paths_pg + 4 + 8);
135*44704f69SBart Van Assche rdac_page->page_code = RDAC_CONTROLLER_PAGE;
136*44704f69SBart Van Assche rdac_page->page_length = RDAC_CONTROLLER_PAGE_LEN;
137*44704f69SBart Van Assche rdac_common = &rdac_page->attr;
138*44704f69SBart Van Assche } else {
139*44704f69SBart Van Assche memcpy(fail_paths_pg, mode10_hdr, 8);
140*44704f69SBart Van Assche rdac_page_exp = (struct rdac_expanded_page *)
141*44704f69SBart Van Assche (fail_paths_pg + 8);
142*44704f69SBart Van Assche rdac_page_exp->page_code = RDAC_CONTROLLER_PAGE | 0x40;
143*44704f69SBart Van Assche rdac_page_exp->subpage_code = 0x1;
144*44704f69SBart Van Assche sg_put_unaligned_be16(EXPANDED_LUN_SPACE_PAGE_LEN,
145*44704f69SBart Van Assche rdac_page_exp->page_length + 0);
146*44704f69SBart Van Assche rdac_common = &rdac_page_exp->attr;
147*44704f69SBart Van Assche }
148*44704f69SBart Van Assche
149*44704f69SBart Van Assche rdac_common->current_mode_lsb = RDAC_FAIL_ALL_PATHS;
150*44704f69SBart Van Assche rdac_common->quiescence = RDAC_QUIESCENCE_TIME;
151*44704f69SBart Van Assche rdac_common->options = RDAC_FORCE_QUIESCENCE;
152*44704f69SBart Van Assche
153*44704f69SBart Van Assche if (use_6_byte) {
154*44704f69SBart Van Assche res = sg_ll_mode_select6(fd, 1 /* pf */, 0 /* sp */,
155*44704f69SBart Van Assche fail_paths_pg, 118,
156*44704f69SBart Van Assche true, (do_verbose ? 2 : 0));
157*44704f69SBart Van Assche } else {
158*44704f69SBart Van Assche res = sg_ll_mode_select10(fd, 1 /* pf */, 0 /* sp */,
159*44704f69SBart Van Assche fail_paths_pg, 308,
160*44704f69SBart Van Assche true, (do_verbose ? 2: 0));
161*44704f69SBart Van Assche }
162*44704f69SBart Van Assche
163*44704f69SBart Van Assche switch (res) {
164*44704f69SBart Van Assche case 0:
165*44704f69SBart Van Assche if (do_verbose)
166*44704f69SBart Van Assche pr2serr("fail paths successful\n");
167*44704f69SBart Van Assche break;
168*44704f69SBart Van Assche default:
169*44704f69SBart Van Assche sg_get_category_sense_str(res, sizeof(b), b, do_verbose);
170*44704f69SBart Van Assche pr2serr("fail paths failed: %s\n", b);
171*44704f69SBart Van Assche break;
172*44704f69SBart Van Assche }
173*44704f69SBart Van Assche
174*44704f69SBart Van Assche return res;
175*44704f69SBart Van Assche }
176*44704f69SBart Van Assche
fail_this_path(int fd,int lun,bool use_6_byte)177*44704f69SBart Van Assche static int fail_this_path(int fd, int lun, bool use_6_byte)
178*44704f69SBart Van Assche {
179*44704f69SBart Van Assche int res;
180*44704f69SBart Van Assche struct rdac_legacy_page *rdac_page;
181*44704f69SBart Van Assche struct rdac_expanded_page *rdac_page_exp;
182*44704f69SBart Van Assche struct rdac_page_common *rdac_common = NULL;
183*44704f69SBart Van Assche uint8_t fail_paths_pg[308];
184*44704f69SBart Van Assche char b[80];
185*44704f69SBart Van Assche
186*44704f69SBart Van Assche if (use_6_byte) {
187*44704f69SBart Van Assche if (lun > 31) {
188*44704f69SBart Van Assche pr2serr("must use 10 byte cdb to fail luns over 31\n");
189*44704f69SBart Van Assche return -1;
190*44704f69SBart Van Assche }
191*44704f69SBart Van Assche } else { /* 10 byte cdb case */
192*44704f69SBart Van Assche if (lun > 255) {
193*44704f69SBart Van Assche pr2serr("lun cannot exceed 255\n");
194*44704f69SBart Van Assche return -1;
195*44704f69SBart Van Assche }
196*44704f69SBart Van Assche }
197*44704f69SBart Van Assche
198*44704f69SBart Van Assche memset(fail_paths_pg, 0, 308);
199*44704f69SBart Van Assche if (use_6_byte) {
200*44704f69SBart Van Assche memcpy(fail_paths_pg, mode6_hdr, 4);
201*44704f69SBart Van Assche memcpy(fail_paths_pg + 4, block_descriptor, 8);
202*44704f69SBart Van Assche rdac_page = (struct rdac_legacy_page *)(fail_paths_pg + 4 + 8);
203*44704f69SBart Van Assche rdac_page->page_code = RDAC_CONTROLLER_PAGE;
204*44704f69SBart Van Assche rdac_page->page_length = RDAC_CONTROLLER_PAGE_LEN;
205*44704f69SBart Van Assche rdac_common = &rdac_page->attr;
206*44704f69SBart Van Assche memset(rdac_page->lun_table, 0x0, 32);
207*44704f69SBart Van Assche rdac_page->lun_table[lun] = 0x81;
208*44704f69SBart Van Assche } else {
209*44704f69SBart Van Assche memcpy(fail_paths_pg, mode10_hdr, 8);
210*44704f69SBart Van Assche rdac_page_exp = (struct rdac_expanded_page *)
211*44704f69SBart Van Assche (fail_paths_pg + 8);
212*44704f69SBart Van Assche rdac_page_exp->page_code = RDAC_CONTROLLER_PAGE | 0x40;
213*44704f69SBart Van Assche rdac_page_exp->subpage_code = 0x1;
214*44704f69SBart Van Assche sg_put_unaligned_be16(EXPANDED_LUN_SPACE_PAGE_LEN,
215*44704f69SBart Van Assche rdac_page_exp->page_length + 0);
216*44704f69SBart Van Assche rdac_common = &rdac_page_exp->attr;
217*44704f69SBart Van Assche memset(rdac_page_exp->lun_table, 0x0, 256);
218*44704f69SBart Van Assche rdac_page_exp->lun_table[lun] = 0x81;
219*44704f69SBart Van Assche }
220*44704f69SBart Van Assche
221*44704f69SBart Van Assche rdac_common->current_mode_lsb = RDAC_FAIL_SELECTED_PATHS;
222*44704f69SBart Van Assche rdac_common->quiescence = RDAC_QUIESCENCE_TIME;
223*44704f69SBart Van Assche rdac_common->options = RDAC_FORCE_QUIESCENCE;
224*44704f69SBart Van Assche
225*44704f69SBart Van Assche if (use_6_byte) {
226*44704f69SBart Van Assche res = sg_ll_mode_select6(fd, 1 /* pf */, 0 /* sp */,
227*44704f69SBart Van Assche fail_paths_pg, 118,
228*44704f69SBart Van Assche true, (do_verbose ? 2 : 0));
229*44704f69SBart Van Assche } else {
230*44704f69SBart Van Assche res = sg_ll_mode_select10(fd, 1 /* pf */, 0 /* sp */,
231*44704f69SBart Van Assche fail_paths_pg, 308,
232*44704f69SBart Van Assche true, (do_verbose ? 2: 0));
233*44704f69SBart Van Assche }
234*44704f69SBart Van Assche
235*44704f69SBart Van Assche switch (res) {
236*44704f69SBart Van Assche case 0:
237*44704f69SBart Van Assche if (do_verbose)
238*44704f69SBart Van Assche pr2serr("fail paths successful\n");
239*44704f69SBart Van Assche break;
240*44704f69SBart Van Assche default:
241*44704f69SBart Van Assche sg_get_category_sense_str(res, sizeof(b), b, do_verbose);
242*44704f69SBart Van Assche pr2serr("fail paths page (lun=%d) failed: %s\n", lun, b);
243*44704f69SBart Van Assche break;
244*44704f69SBart Van Assche }
245*44704f69SBart Van Assche
246*44704f69SBart Van Assche return res;
247*44704f69SBart Van Assche }
248*44704f69SBart Van Assche
print_rdac_mode(uint8_t * ptr,bool exp_subpg)249*44704f69SBart Van Assche static void print_rdac_mode(uint8_t *ptr, bool exp_subpg)
250*44704f69SBart Van Assche {
251*44704f69SBart Van Assche int i, k, bd_len, lun_table_len;
252*44704f69SBart Van Assche uint8_t * lun_table = NULL;
253*44704f69SBart Van Assche struct rdac_legacy_page *legacy;
254*44704f69SBart Van Assche struct rdac_expanded_page *expanded;
255*44704f69SBart Van Assche struct rdac_page_common *rdac_ptr = NULL;
256*44704f69SBart Van Assche
257*44704f69SBart Van Assche if (exp_subpg) {
258*44704f69SBart Van Assche bd_len = ptr[7];
259*44704f69SBart Van Assche expanded = (struct rdac_expanded_page *)(ptr + 8 + bd_len);
260*44704f69SBart Van Assche rdac_ptr = &expanded->attr;
261*44704f69SBart Van Assche lun_table = expanded->lun_table;
262*44704f69SBart Van Assche lun_table_len = 256;
263*44704f69SBart Van Assche } else {
264*44704f69SBart Van Assche bd_len = ptr[3];
265*44704f69SBart Van Assche legacy = (struct rdac_legacy_page *)(ptr + 4 + bd_len);
266*44704f69SBart Van Assche rdac_ptr = &legacy->attr;
267*44704f69SBart Van Assche lun_table = legacy->lun_table;
268*44704f69SBart Van Assche lun_table_len = 32;
269*44704f69SBart Van Assche }
270*44704f69SBart Van Assche
271*44704f69SBart Van Assche printf("RDAC %s page\n", exp_subpg ? "Expanded" : "Legacy");
272*44704f69SBart Van Assche printf(" Controller serial: %s\n",
273*44704f69SBart Van Assche rdac_ptr->current_serial);
274*44704f69SBart Van Assche printf(" Alternate controller serial: %s\n",
275*44704f69SBart Van Assche rdac_ptr->alternate_serial);
276*44704f69SBart Van Assche printf(" RDAC mode (redundant processor): ");
277*44704f69SBart Van Assche switch (rdac_ptr->current_mode_msb) {
278*44704f69SBart Van Assche case 0x00:
279*44704f69SBart Van Assche printf("alternate controller not present; ");
280*44704f69SBart Van Assche break;
281*44704f69SBart Van Assche case 0x01:
282*44704f69SBart Van Assche printf("alternate controller present; ");
283*44704f69SBart Van Assche break;
284*44704f69SBart Van Assche default:
285*44704f69SBart Van Assche printf("(Unknown controller status 0x%x); ",
286*44704f69SBart Van Assche rdac_ptr->current_mode_msb);
287*44704f69SBart Van Assche break;
288*44704f69SBart Van Assche }
289*44704f69SBart Van Assche switch (rdac_ptr->current_mode_lsb) {
290*44704f69SBart Van Assche case 0x0:
291*44704f69SBart Van Assche printf("inactive\n");
292*44704f69SBart Van Assche break;
293*44704f69SBart Van Assche case 0x1:
294*44704f69SBart Van Assche printf("active\n");
295*44704f69SBart Van Assche break;
296*44704f69SBart Van Assche case 0x2:
297*44704f69SBart Van Assche printf("Dual active mode\n");
298*44704f69SBart Van Assche break;
299*44704f69SBart Van Assche default:
300*44704f69SBart Van Assche printf("(Unknown mode 0x%x)\n",
301*44704f69SBart Van Assche rdac_ptr->current_mode_lsb);
302*44704f69SBart Van Assche }
303*44704f69SBart Van Assche
304*44704f69SBart Van Assche printf(" RDAC mode (alternate processor): ");
305*44704f69SBart Van Assche switch (rdac_ptr->alternate_mode_msb) {
306*44704f69SBart Van Assche case 0x00:
307*44704f69SBart Van Assche printf("alternate controller not present; ");
308*44704f69SBart Van Assche break;
309*44704f69SBart Van Assche case 0x01:
310*44704f69SBart Van Assche printf("alternate controller present; ");
311*44704f69SBart Van Assche break;
312*44704f69SBart Van Assche default:
313*44704f69SBart Van Assche printf("(Unknown status 0x%x); ",
314*44704f69SBart Van Assche rdac_ptr->alternate_mode_msb);
315*44704f69SBart Van Assche break;
316*44704f69SBart Van Assche }
317*44704f69SBart Van Assche switch (rdac_ptr->alternate_mode_lsb) {
318*44704f69SBart Van Assche case 0x0:
319*44704f69SBart Van Assche printf("inactive\n");
320*44704f69SBart Van Assche break;
321*44704f69SBart Van Assche case 0x1:
322*44704f69SBart Van Assche printf("active\n");
323*44704f69SBart Van Assche break;
324*44704f69SBart Van Assche case 0x2:
325*44704f69SBart Van Assche printf("Dual active mode\n");
326*44704f69SBart Van Assche break;
327*44704f69SBart Van Assche case 0x3:
328*44704f69SBart Van Assche printf("Not present\n");
329*44704f69SBart Van Assche break;
330*44704f69SBart Van Assche case 0x4:
331*44704f69SBart Van Assche printf("held in reset\n");
332*44704f69SBart Van Assche break;
333*44704f69SBart Van Assche default:
334*44704f69SBart Van Assche printf("(Unknown mode 0x%x)\n",
335*44704f69SBart Van Assche rdac_ptr->alternate_mode_lsb);
336*44704f69SBart Van Assche }
337*44704f69SBart Van Assche printf(" Quiescence timeout: %d\n", rdac_ptr->quiescence);
338*44704f69SBart Van Assche printf(" RDAC option 0x%x\n", rdac_ptr->options);
339*44704f69SBart Van Assche printf(" ALUA: %s\n", (rdac_ptr->options & 0x4 ? "Enabled" :
340*44704f69SBart Van Assche "Disabled" ));
341*44704f69SBart Van Assche printf(" Force Quiescence: %s\n", (rdac_ptr->options & 0x2 ?
342*44704f69SBart Van Assche "Enabled" : "Disabled" ));
343*44704f69SBart Van Assche printf (" LUN Table: (p = preferred, a = alternate, u = utm lun)\n");
344*44704f69SBart Van Assche printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f\n");
345*44704f69SBart Van Assche for (k = 0; k < lun_table_len; k += 16) {
346*44704f69SBart Van Assche printf(" 0x%x:",k / 16);
347*44704f69SBart Van Assche for (i = 0; i < 16; i++) {
348*44704f69SBart Van Assche switch (lun_table[k + i]) {
349*44704f69SBart Van Assche case 0x0:
350*44704f69SBart Van Assche printf(" x");
351*44704f69SBart Van Assche break;
352*44704f69SBart Van Assche case 0x1:
353*44704f69SBart Van Assche printf(" p");
354*44704f69SBart Van Assche break;
355*44704f69SBart Van Assche case 0x2:
356*44704f69SBart Van Assche printf(" a");
357*44704f69SBart Van Assche break;
358*44704f69SBart Van Assche case 0x3:
359*44704f69SBart Van Assche printf(" u");
360*44704f69SBart Van Assche break;
361*44704f69SBart Van Assche default:
362*44704f69SBart Van Assche printf(" ?");
363*44704f69SBart Van Assche break;
364*44704f69SBart Van Assche }
365*44704f69SBart Van Assche if (i == 7) {
366*44704f69SBart Van Assche printf(" ");
367*44704f69SBart Van Assche }
368*44704f69SBart Van Assche }
369*44704f69SBart Van Assche printf("\n");
370*44704f69SBart Van Assche }
371*44704f69SBart Van Assche }
372*44704f69SBart Van Assche
usage()373*44704f69SBart Van Assche static void usage()
374*44704f69SBart Van Assche {
375*44704f69SBart Van Assche printf("Usage: sg_rdac [-6] [-a] [-f=LUN] [-v] [-V] DEVICE\n"
376*44704f69SBart Van Assche " where:\n"
377*44704f69SBart Van Assche " -6 use 6 byte cdbs for mode sense/select\n"
378*44704f69SBart Van Assche " -a transfer all devices to the controller\n"
379*44704f69SBart Van Assche " serving DEVICE.\n"
380*44704f69SBart Van Assche " -f=LUN transfer the device at LUN to the\n"
381*44704f69SBart Van Assche " controller serving DEVICE\n"
382*44704f69SBart Van Assche " -v verbose\n"
383*44704f69SBart Van Assche " -V print version then exit\n\n"
384*44704f69SBart Van Assche " Display/Modify RDAC Redundant Controller Page 0x2c.\n"
385*44704f69SBart Van Assche " If [-a] or [-f] is not specified the current settings"
386*44704f69SBart Van Assche " are displayed.\n");
387*44704f69SBart Van Assche }
388*44704f69SBart Van Assche
main(int argc,char * argv[])389*44704f69SBart Van Assche int main(int argc, char * argv[])
390*44704f69SBart Van Assche {
391*44704f69SBart Van Assche bool fail_all = false;
392*44704f69SBart Van Assche bool fail_path = false;
393*44704f69SBart Van Assche bool use_6_byte = false;
394*44704f69SBart Van Assche int res, fd, k, resid, len, lun = -1;
395*44704f69SBart Van Assche int ret = 0;
396*44704f69SBart Van Assche char **argptr;
397*44704f69SBart Van Assche char * file_name = 0;
398*44704f69SBart Van Assche uint8_t rsp_buff[MX_ALLOC_LEN];
399*44704f69SBart Van Assche
400*44704f69SBart Van Assche if (argc < 2) {
401*44704f69SBart Van Assche usage ();
402*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
403*44704f69SBart Van Assche }
404*44704f69SBart Van Assche
405*44704f69SBart Van Assche for (k = 1; k < argc; ++k) {
406*44704f69SBart Van Assche argptr = argv + k;
407*44704f69SBart Van Assche if (!strcmp (*argptr, "-v"))
408*44704f69SBart Van Assche ++do_verbose;
409*44704f69SBart Van Assche else if (!strncmp(*argptr, "-f=",3)) {
410*44704f69SBart Van Assche fail_path = true;
411*44704f69SBart Van Assche lun = strtoul(*argptr + 3, NULL, 0);
412*44704f69SBart Van Assche }
413*44704f69SBart Van Assche else if (!strcmp(*argptr, "-a")) {
414*44704f69SBart Van Assche fail_all = true;
415*44704f69SBart Van Assche }
416*44704f69SBart Van Assche else if (!strcmp(*argptr, "-6")) {
417*44704f69SBart Van Assche use_6_byte = true;
418*44704f69SBart Van Assche }
419*44704f69SBart Van Assche else if (!strcmp(*argptr, "-V")) {
420*44704f69SBart Van Assche pr2serr("sg_rdac version: %s\n", version_str);
421*44704f69SBart Van Assche return 0;
422*44704f69SBart Van Assche }
423*44704f69SBart Van Assche else if (*argv[k] == '-') {
424*44704f69SBart Van Assche pr2serr("Unrecognized switch: %s\n", argv[k]);
425*44704f69SBart Van Assche file_name = 0;
426*44704f69SBart Van Assche break;
427*44704f69SBart Van Assche }
428*44704f69SBart Van Assche else if (0 == file_name)
429*44704f69SBart Van Assche file_name = argv[k];
430*44704f69SBart Van Assche else {
431*44704f69SBart Van Assche pr2serr("too many arguments\n");
432*44704f69SBart Van Assche file_name = 0;
433*44704f69SBart Van Assche break;
434*44704f69SBart Van Assche }
435*44704f69SBart Van Assche }
436*44704f69SBart Van Assche if (0 == file_name) {
437*44704f69SBart Van Assche usage();
438*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
439*44704f69SBart Van Assche }
440*44704f69SBart Van Assche
441*44704f69SBart Van Assche fd = sg_cmds_open_device(file_name, false /* rw */, do_verbose);
442*44704f69SBart Van Assche if (fd < 0) {
443*44704f69SBart Van Assche pr2serr("open error: %s: %s\n", file_name, safe_strerror(-fd));
444*44704f69SBart Van Assche usage();
445*44704f69SBart Van Assche ret = sg_convert_errno(-fd);
446*44704f69SBart Van Assche goto fini;
447*44704f69SBart Van Assche }
448*44704f69SBart Van Assche
449*44704f69SBart Van Assche if (fail_all) {
450*44704f69SBart Van Assche res = fail_all_paths(fd, use_6_byte);
451*44704f69SBart Van Assche } else if (fail_path) {
452*44704f69SBart Van Assche res = fail_this_path(fd, lun, use_6_byte);
453*44704f69SBart Van Assche } else {
454*44704f69SBart Van Assche resid = 0;
455*44704f69SBart Van Assche if (use_6_byte)
456*44704f69SBart Van Assche res = sg_ll_mode_sense6(fd, /* DBD */ false,
457*44704f69SBart Van Assche /* PC */ 0,
458*44704f69SBart Van Assche 0x2c /* page */,
459*44704f69SBart Van Assche 0 /*subpage */,
460*44704f69SBart Van Assche rsp_buff, 252,
461*44704f69SBart Van Assche true, do_verbose);
462*44704f69SBart Van Assche else
463*44704f69SBart Van Assche res = sg_ll_mode_sense10_v2(fd, /* llbaa */ false,
464*44704f69SBart Van Assche /* DBD */ false,
465*44704f69SBart Van Assche /* page control */0,
466*44704f69SBart Van Assche 0x2c, 0x1 /* subpage */,
467*44704f69SBart Van Assche rsp_buff, 308, 0, &resid,
468*44704f69SBart Van Assche true, do_verbose);
469*44704f69SBart Van Assche
470*44704f69SBart Van Assche if (! res) {
471*44704f69SBart Van Assche len = sg_msense_calc_length(rsp_buff, 308, use_6_byte,
472*44704f69SBart Van Assche NULL);
473*44704f69SBart Van Assche if (resid > 0) {
474*44704f69SBart Van Assche len = ((308 - resid) < len) ? (308 - resid) :
475*44704f69SBart Van Assche len;
476*44704f69SBart Van Assche if (len < 2)
477*44704f69SBart Van Assche pr2serr("MS(10) residual value (%d) "
478*44704f69SBart Van Assche "a worry\n", resid);
479*44704f69SBart Van Assche }
480*44704f69SBart Van Assche if (do_verbose && (len > 1))
481*44704f69SBart Van Assche dump_mode_page(rsp_buff, len);
482*44704f69SBart Van Assche print_rdac_mode(rsp_buff, ! use_6_byte);
483*44704f69SBart Van Assche } else {
484*44704f69SBart Van Assche if (SG_LIB_CAT_INVALID_OP == res)
485*44704f69SBart Van Assche pr2serr(">>>>>> try again without the '-6' "
486*44704f69SBart Van Assche "switch for a 10 byte MODE SENSE "
487*44704f69SBart Van Assche "command\n");
488*44704f69SBart Van Assche else if (SG_LIB_CAT_ILLEGAL_REQ == res)
489*44704f69SBart Van Assche pr2serr("mode sense: invalid field in cdb "
490*44704f69SBart Van Assche "(perhaps subpages or page control "
491*44704f69SBart Van Assche "(PC) not supported)\n");
492*44704f69SBart Van Assche else {
493*44704f69SBart Van Assche char b[80];
494*44704f69SBart Van Assche
495*44704f69SBart Van Assche sg_get_category_sense_str(res, sizeof(b), b,
496*44704f69SBart Van Assche do_verbose);
497*44704f69SBart Van Assche pr2serr("mode sense failed: %s\n", b);
498*44704f69SBart Van Assche }
499*44704f69SBart Van Assche }
500*44704f69SBart Van Assche }
501*44704f69SBart Van Assche ret = res;
502*44704f69SBart Van Assche
503*44704f69SBart Van Assche res = sg_cmds_close_device(fd);
504*44704f69SBart Van Assche if (res < 0) {
505*44704f69SBart Van Assche pr2serr("close error: %s\n", safe_strerror(-res));
506*44704f69SBart Van Assche if (0 == ret)
507*44704f69SBart Van Assche ret = sg_convert_errno(res);
508*44704f69SBart Van Assche }
509*44704f69SBart Van Assche fini:
510*44704f69SBart Van Assche if (0 == do_verbose) {
511*44704f69SBart Van Assche if (! sg_if_can2stderr("sg_rdac failed: ", ret))
512*44704f69SBart Van Assche pr2serr("Some error occurred, try again with '-v' "
513*44704f69SBart Van Assche "or '-vv' for more information\n");
514*44704f69SBart Van Assche }
515*44704f69SBart Van Assche return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
516*44704f69SBart Van Assche }
517