blob: b0d1cdcfd51a46239bf354a0a02a2985161e04bf [file] [log] [blame]
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +00001/*
2 * sg_rdac
3 *
4 * Retrieve / set RDAC options.
5 *
Douglas Gilbert25208652018-02-22 07:00:28 +00006 * Copyright (C) 2006-2018 Hannes Reinecke <hare@suse.de>
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +00007 *
8 * Based on sg_modes.c and sg_emc_trespass.c; credits from there apply.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2, or (at your option)
13 * any later version.
Douglas Gilbert4445eec2018-12-07 16:42:06 +000014 *
15 * SPDX-License-Identifier: GPL-2.0-or-later
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +000016 */
17
18#include <stdio.h>
19#include <stdlib.h>
Douglas Gilbertb2e59f42017-10-09 23:49:50 +000020#include <stdarg.h>
21#include <stdbool.h>
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +000022#include <unistd.h>
23#include <string.h>
Douglas Gilbert75026472007-06-27 03:51:21 +000024
Douglas Gilbert178524c2007-07-13 22:30:32 +000025#ifdef HAVE_CONFIG_H
26#include "config.h"
27#endif
Douglas Gilbert25208652018-02-22 07:00:28 +000028
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +000029#include "sg_lib.h"
Douglas Gilbert543a9ec2007-06-27 03:26:00 +000030#include "sg_cmds_basic.h"
Douglas Gilberte359da12015-12-10 18:29:41 +000031#include "sg_unaligned.h"
Douglas Gilbert9fbc8842015-12-20 16:23:44 +000032#include "sg_pr2serr.h"
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +000033
34
Douglas Gilbert856fb912018-05-15 20:44:45 +000035static const char * version_str = "1.17 20180512";
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +000036
Douglas Gilbert25208652018-02-22 07:00:28 +000037uint8_t mode6_hdr[] = {
Douglas Gilbertbaa91c32015-04-01 21:45:22 +000038 0x75, /* Length */
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +000039 0, /* medium */
40 0, /* params */
41 8, /* Block descriptor length */
42};
43
Douglas Gilbert25208652018-02-22 07:00:28 +000044uint8_t mode10_hdr[] = {
Douglas Gilbertbaa91c32015-04-01 21:45:22 +000045 0x01, 0x18, /* Length */
46 0, /* medium */
47 0, /* params */
48 0, 0, /* reserved */
49 0, 0, /* block descriptor length */
50};
51
Douglas Gilbert25208652018-02-22 07:00:28 +000052uint8_t block_descriptor[] = {
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +000053 0, /* Density code */
54 0, 0, 0, /* Number of blocks */
55 0, /* Reserved */
56 0, 0x02, 0, /* 512 byte blocks */
57};
58
Douglas Gilbertbaa91c32015-04-01 21:45:22 +000059struct rdac_page_common {
Douglas Gilbert25208652018-02-22 07:00:28 +000060 uint8_t current_serial[16];
61 uint8_t alternate_serial[16];
62 uint8_t current_mode_msb;
63 uint8_t current_mode_lsb;
64 uint8_t alternate_mode_msb;
65 uint8_t alternate_mode_lsb;
66 uint8_t quiescence;
67 uint8_t options;
Douglas Gilbertbaa91c32015-04-01 21:45:22 +000068};
69
70struct rdac_legacy_page {
Douglas Gilbert25208652018-02-22 07:00:28 +000071 uint8_t page_code;
72 uint8_t page_length;
Douglas Gilbertbaa91c32015-04-01 21:45:22 +000073 struct rdac_page_common attr;
Douglas Gilbert25208652018-02-22 07:00:28 +000074 uint8_t lun_table[32];
75 uint8_t lun_table_exp[32];
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +000076 unsigned short reserved;
77};
78
Douglas Gilbertbaa91c32015-04-01 21:45:22 +000079struct rdac_expanded_page {
Douglas Gilbert25208652018-02-22 07:00:28 +000080 uint8_t page_code;
81 uint8_t subpage_code;
82 uint8_t page_length[2];
Douglas Gilbertbaa91c32015-04-01 21:45:22 +000083 struct rdac_page_common attr;
Douglas Gilbert25208652018-02-22 07:00:28 +000084 uint8_t lun_table[256];
85 uint8_t reserved[2];
Douglas Gilbertbaa91c32015-04-01 21:45:22 +000086};
87
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +000088static int do_verbose = 0;
89
Douglas Gilbert25208652018-02-22 07:00:28 +000090static void dump_mode_page( uint8_t *page, int len )
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +000091{
92 int i, k;
93
94 for (k = 0; k < len; k += 16) {
95
96 printf("%x:",k / 16);
97 for (i = 0; i < 16; i++) {
98 printf(" %02x", page[k + i]);
99 if (k + i >= len) {
100 printf("\n");
101 break;
102 }
103 }
104 printf("\n");
105 }
106
107}
108
109#define MX_ALLOC_LEN (1024 * 4)
110#define RDAC_CONTROLLER_PAGE 0x2c
111#define RDAC_CONTROLLER_PAGE_LEN 0x68
112#define LEGACY_PAGE 0x00
113#define EXPANDED_LUN_SPACE_PAGE 0x01
Douglas Gilbertbaa91c32015-04-01 21:45:22 +0000114#define EXPANDED_LUN_SPACE_PAGE_LEN 0x128
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +0000115#define RDAC_FAIL_ALL_PATHS 0x1
116#define RDAC_FAIL_SELECTED_PATHS 0x2
117#define RDAC_FORCE_QUIESCENCE 0x2
118#define RDAC_QUIESCENCE_TIME 10
119
Douglas Gilbertb2e59f42017-10-09 23:49:50 +0000120static int fail_all_paths(int fd, bool use_6_byte)
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +0000121{
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +0000122 struct rdac_legacy_page *rdac_page;
Douglas Gilbertbaa91c32015-04-01 21:45:22 +0000123 struct rdac_expanded_page *rdac_page_exp;
124 struct rdac_page_common *rdac_common = NULL;
Douglas Gilbert25208652018-02-22 07:00:28 +0000125 uint8_t fail_paths_pg[308];
Douglas Gilbertbaa91c32015-04-01 21:45:22 +0000126
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +0000127 int res;
Douglas Gilbert80bb62d2014-05-16 22:51:01 +0000128 char b[80];
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +0000129
Douglas Gilbertbaa91c32015-04-01 21:45:22 +0000130 memset(fail_paths_pg, 0, 308);
131 if (use_6_byte) {
132 memcpy(fail_paths_pg, mode6_hdr, 4);
133 memcpy(fail_paths_pg + 4, block_descriptor, 8);
134 rdac_page = (struct rdac_legacy_page *)(fail_paths_pg + 4 + 8);
135 rdac_page->page_code = RDAC_CONTROLLER_PAGE;
136 rdac_page->page_length = RDAC_CONTROLLER_PAGE_LEN;
137 rdac_common = &rdac_page->attr;
138 } else {
139 memcpy(fail_paths_pg, mode10_hdr, 8);
Douglas Gilberte3aba382015-04-10 15:00:15 +0000140 rdac_page_exp = (struct rdac_expanded_page *)
141 (fail_paths_pg + 8);
Douglas Gilbertbaa91c32015-04-01 21:45:22 +0000142 rdac_page_exp->page_code = RDAC_CONTROLLER_PAGE | 0x40;
143 rdac_page_exp->subpage_code = 0x1;
Douglas Gilberte359da12015-12-10 18:29:41 +0000144 sg_put_unaligned_be16(EXPANDED_LUN_SPACE_PAGE_LEN,
145 rdac_page_exp->page_length + 0);
Douglas Gilbertbaa91c32015-04-01 21:45:22 +0000146 rdac_common = &rdac_page_exp->attr;
147 }
Douglas Gilbert1ed38622008-06-04 18:56:15 +0000148
Douglas Gilbertbaa91c32015-04-01 21:45:22 +0000149 rdac_common->current_mode_lsb = RDAC_FAIL_ALL_PATHS;
150 rdac_common->quiescence = RDAC_QUIESCENCE_TIME;
151 rdac_common->options = RDAC_FORCE_QUIESCENCE;
152
153 if (use_6_byte) {
154 res = sg_ll_mode_select6(fd, 1 /* pf */, 0 /* sp */,
155 fail_paths_pg, 118,
Douglas Gilbert3c285ac2017-09-18 19:15:01 +0000156 true, (do_verbose ? 2 : 0));
Douglas Gilbertbaa91c32015-04-01 21:45:22 +0000157 } else {
158 res = sg_ll_mode_select10(fd, 1 /* pf */, 0 /* sp */,
159 fail_paths_pg, 308,
Douglas Gilbert3c285ac2017-09-18 19:15:01 +0000160 true, (do_verbose ? 2: 0));
Douglas Gilbertbaa91c32015-04-01 21:45:22 +0000161 }
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +0000162
163 switch (res) {
164 case 0:
165 if (do_verbose)
Douglas Gilbert9fbc8842015-12-20 16:23:44 +0000166 pr2serr("fail paths successful\n");
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +0000167 break;
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +0000168 default:
Douglas Gilbert80bb62d2014-05-16 22:51:01 +0000169 sg_get_category_sense_str(res, sizeof(b), b, do_verbose);
Douglas Gilbert9fbc8842015-12-20 16:23:44 +0000170 pr2serr("fail paths failed: %s\n", b);
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +0000171 break;
172 }
173
174 return res;
175}
176
Douglas Gilbertb2e59f42017-10-09 23:49:50 +0000177static int fail_this_path(int fd, int lun, bool use_6_byte)
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +0000178{
Douglas Gilbertb2e59f42017-10-09 23:49:50 +0000179 int res;
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +0000180 struct rdac_legacy_page *rdac_page;
Douglas Gilbertbaa91c32015-04-01 21:45:22 +0000181 struct rdac_expanded_page *rdac_page_exp;
182 struct rdac_page_common *rdac_common = NULL;
Douglas Gilbert25208652018-02-22 07:00:28 +0000183 uint8_t fail_paths_pg[308];
Douglas Gilbert80bb62d2014-05-16 22:51:01 +0000184 char b[80];
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +0000185
Douglas Gilbert8e843ee2016-04-30 18:01:03 +0000186 if (use_6_byte) {
187 if (lun > 31) {
188 pr2serr("must use 10 byte cdb to fail luns over 31\n");
189 return -1;
190 }
191 } else { /* 10 byte cdb case */
192 if (lun > 255) {
193 pr2serr("lun cannot exceed 255\n");
194 return -1;
195 }
Douglas Gilbertbaa91c32015-04-01 21:45:22 +0000196 }
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +0000197
Douglas Gilbertbaa91c32015-04-01 21:45:22 +0000198 memset(fail_paths_pg, 0, 308);
199 if (use_6_byte) {
200 memcpy(fail_paths_pg, mode6_hdr, 4);
201 memcpy(fail_paths_pg + 4, block_descriptor, 8);
202 rdac_page = (struct rdac_legacy_page *)(fail_paths_pg + 4 + 8);
203 rdac_page->page_code = RDAC_CONTROLLER_PAGE;
204 rdac_page->page_length = RDAC_CONTROLLER_PAGE_LEN;
205 rdac_common = &rdac_page->attr;
206 memset(rdac_page->lun_table, 0x0, 32);
207 rdac_page->lun_table[lun] = 0x81;
208 } else {
209 memcpy(fail_paths_pg, mode10_hdr, 8);
Douglas Gilberte3aba382015-04-10 15:00:15 +0000210 rdac_page_exp = (struct rdac_expanded_page *)
211 (fail_paths_pg + 8);
Douglas Gilbertbaa91c32015-04-01 21:45:22 +0000212 rdac_page_exp->page_code = RDAC_CONTROLLER_PAGE | 0x40;
213 rdac_page_exp->subpage_code = 0x1;
Douglas Gilberte359da12015-12-10 18:29:41 +0000214 sg_put_unaligned_be16(EXPANDED_LUN_SPACE_PAGE_LEN,
215 rdac_page_exp->page_length + 0);
Douglas Gilbertbaa91c32015-04-01 21:45:22 +0000216 rdac_common = &rdac_page_exp->attr;
217 memset(rdac_page_exp->lun_table, 0x0, 256);
218 rdac_page_exp->lun_table[lun] = 0x81;
219 }
220
221 rdac_common->current_mode_lsb = RDAC_FAIL_SELECTED_PATHS;
222 rdac_common->quiescence = RDAC_QUIESCENCE_TIME;
223 rdac_common->options = RDAC_FORCE_QUIESCENCE;
224
225 if (use_6_byte) {
226 res = sg_ll_mode_select6(fd, 1 /* pf */, 0 /* sp */,
227 fail_paths_pg, 118,
Douglas Gilbert3c285ac2017-09-18 19:15:01 +0000228 true, (do_verbose ? 2 : 0));
Douglas Gilbertbaa91c32015-04-01 21:45:22 +0000229 } else {
230 res = sg_ll_mode_select10(fd, 1 /* pf */, 0 /* sp */,
231 fail_paths_pg, 308,
Douglas Gilbert3c285ac2017-09-18 19:15:01 +0000232 true, (do_verbose ? 2: 0));
Douglas Gilbertbaa91c32015-04-01 21:45:22 +0000233 }
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +0000234
235 switch (res) {
236 case 0:
237 if (do_verbose)
Douglas Gilbert9fbc8842015-12-20 16:23:44 +0000238 pr2serr("fail paths successful\n");
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +0000239 break;
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +0000240 default:
Douglas Gilbert80bb62d2014-05-16 22:51:01 +0000241 sg_get_category_sense_str(res, sizeof(b), b, do_verbose);
Douglas Gilbert9fbc8842015-12-20 16:23:44 +0000242 pr2serr("fail paths page (lun=%d) failed: %s\n", lun, b);
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +0000243 break;
244 }
245
246 return res;
247}
248
Douglas Gilbert25208652018-02-22 07:00:28 +0000249static void print_rdac_mode(uint8_t *ptr, bool exp_subpg)
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +0000250{
Douglas Gilbertb2e59f42017-10-09 23:49:50 +0000251 int i, k, bd_len, lun_table_len;
Douglas Gilbert25208652018-02-22 07:00:28 +0000252 uint8_t * lun_table = NULL;
Douglas Gilbertbaa91c32015-04-01 21:45:22 +0000253 struct rdac_legacy_page *legacy;
254 struct rdac_expanded_page *expanded;
255 struct rdac_page_common *rdac_ptr = NULL;
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +0000256
Douglas Gilbert9a9577a2017-10-22 17:32:39 +0000257 if (exp_subpg) {
Douglas Gilbertbaa91c32015-04-01 21:45:22 +0000258 bd_len = ptr[7];
259 expanded = (struct rdac_expanded_page *)(ptr + 8 + bd_len);
260 rdac_ptr = &expanded->attr;
261 lun_table = expanded->lun_table;
262 lun_table_len = 256;
263 } else {
264 bd_len = ptr[3];
265 legacy = (struct rdac_legacy_page *)(ptr + 4 + bd_len);
266 rdac_ptr = &legacy->attr;
267 lun_table = legacy->lun_table;
268 lun_table_len = 32;
269 }
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +0000270
Douglas Gilbert9a9577a2017-10-22 17:32:39 +0000271 printf("RDAC %s page\n", exp_subpg ? "Expanded" : "Legacy");
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +0000272 printf(" Controller serial: %s\n",
273 rdac_ptr->current_serial);
274 printf(" Alternate controller serial: %s\n",
275 rdac_ptr->alternate_serial);
276 printf(" RDAC mode (redundant processor): ");
277 switch (rdac_ptr->current_mode_msb) {
278 case 0x00:
279 printf("alternate controller not present; ");
280 break;
281 case 0x01:
282 printf("alternate controller present; ");
283 break;
284 default:
Douglas Gilbert7a31f052009-07-24 19:58:51 +0000285 printf("(Unknown controller status 0x%x); ",
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +0000286 rdac_ptr->current_mode_msb);
287 break;
288 }
289 switch (rdac_ptr->current_mode_lsb) {
290 case 0x0:
291 printf("inactive\n");
292 break;
293 case 0x1:
294 printf("active\n");
295 break;
296 case 0x2:
297 printf("Dual active mode\n");
298 break;
299 default:
Douglas Gilbert7a31f052009-07-24 19:58:51 +0000300 printf("(Unknown mode 0x%x)\n",
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +0000301 rdac_ptr->current_mode_lsb);
302 }
303
304 printf(" RDAC mode (alternate processor): ");
305 switch (rdac_ptr->alternate_mode_msb) {
306 case 0x00:
307 printf("alternate controller not present; ");
308 break;
309 case 0x01:
310 printf("alternate controller present; ");
311 break;
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +0000312 default:
Douglas Gilbert7a31f052009-07-24 19:58:51 +0000313 printf("(Unknown status 0x%x); ",
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +0000314 rdac_ptr->alternate_mode_msb);
315 break;
316 }
317 switch (rdac_ptr->alternate_mode_lsb) {
318 case 0x0:
319 printf("inactive\n");
320 break;
321 case 0x1:
322 printf("active\n");
323 break;
324 case 0x2:
325 printf("Dual active mode\n");
326 break;
Douglas Gilbertbaa91c32015-04-01 21:45:22 +0000327 case 0x3:
328 printf("Not present\n");
329 break;
330 case 0x4:
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +0000331 printf("held in reset\n");
332 break;
333 default:
Douglas Gilbert7a31f052009-07-24 19:58:51 +0000334 printf("(Unknown mode 0x%x)\n",
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +0000335 rdac_ptr->alternate_mode_lsb);
336 }
337 printf(" Quiescence timeout: %d\n", rdac_ptr->quiescence);
Douglas Gilbert7a31f052009-07-24 19:58:51 +0000338 printf(" RDAC option 0x%x\n", rdac_ptr->options);
Douglas Gilberte3aba382015-04-10 15:00:15 +0000339 printf(" ALUA: %s\n", (rdac_ptr->options & 0x4 ? "Enabled" :
340 "Disabled" ));
341 printf(" Force Quiescence: %s\n", (rdac_ptr->options & 0x2 ?
342 "Enabled" : "Disabled" ));
Douglas Gilbertbaa91c32015-04-01 21:45:22 +0000343 printf (" LUN Table: (p = preferred, a = alternate, u = utm lun)\n");
344 printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f\n");
345 for (k = 0; k < lun_table_len; k += 16) {
346 printf(" 0x%x:",k / 16);
347 for (i = 0; i < 16; i++) {
348 switch (lun_table[k + i]) {
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +0000349 case 0x0:
350 printf(" x");
351 break;
352 case 0x1:
353 printf(" p");
354 break;
355 case 0x2:
356 printf(" a");
357 break;
358 case 0x3:
359 printf(" u");
360 break;
361 default:
362 printf(" ?");
363 break;
364 }
Douglas Gilbertbaa91c32015-04-01 21:45:22 +0000365 if (i == 7) {
366 printf(" ");
367 }
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +0000368 }
369 printf("\n");
370 }
371}
372
373static void usage()
374{
Douglas Gilbertbaa91c32015-04-01 21:45:22 +0000375 printf("Usage: sg_rdac [-6] [-a] [-f=LUN] [-v] [-V] DEVICE\n"
Douglas Gilbert75026472007-06-27 03:51:21 +0000376 " where:\n"
Douglas Gilbertbaa91c32015-04-01 21:45:22 +0000377 " -6 use 6 byte cdbs for mode sense/select\n"
Douglas Gilbert75026472007-06-27 03:51:21 +0000378 " -a transfer all devices to the controller\n"
379 " serving DEVICE.\n"
380 " -f=LUN transfer the device at LUN to the\n"
381 " controller serving DEVICE\n"
382 " -v verbose\n"
383 " -V print version then exit\n\n"
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +0000384 " Display/Modify RDAC Redundant Controller Page 0x2c.\n"
385 " If [-a] or [-f] is not specified the current settings"
386 " are displayed.\n");
387}
388
389int main(int argc, char * argv[])
390{
Douglas Gilbertb2e59f42017-10-09 23:49:50 +0000391 bool fail_all = false;
392 bool fail_path = false;
393 bool use_6_byte = false;
Douglas Gilbert9a9577a2017-10-22 17:32:39 +0000394 int res, fd, k, resid, len, lun = -1;
Douglas Gilbertb2e59f42017-10-09 23:49:50 +0000395 int ret = 0;
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +0000396 char **argptr;
397 char * file_name = 0;
Douglas Gilbert25208652018-02-22 07:00:28 +0000398 uint8_t rsp_buff[MX_ALLOC_LEN];
Douglas Gilbert1ed38622008-06-04 18:56:15 +0000399
Douglas Gilbert543a9ec2007-06-27 03:26:00 +0000400 if (argc < 2) {
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +0000401 usage ();
Douglas Gilbert543a9ec2007-06-27 03:26:00 +0000402 return SG_LIB_SYNTAX_ERROR;
403 }
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +0000404
405 for (k = 1; k < argc; ++k) {
406 argptr = argv + k;
407 if (!strcmp (*argptr, "-v"))
408 ++do_verbose;
409 else if (!strncmp(*argptr, "-f=",3)) {
Douglas Gilbertb2e59f42017-10-09 23:49:50 +0000410 fail_path = true;
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +0000411 lun = strtoul(*argptr + 3, NULL, 0);
412 }
413 else if (!strcmp(*argptr, "-a")) {
Douglas Gilbertb2e59f42017-10-09 23:49:50 +0000414 fail_all = true;
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +0000415 }
Douglas Gilbertbaa91c32015-04-01 21:45:22 +0000416 else if (!strcmp(*argptr, "-6")) {
Douglas Gilbertb2e59f42017-10-09 23:49:50 +0000417 use_6_byte = true;
Douglas Gilbertbaa91c32015-04-01 21:45:22 +0000418 }
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +0000419 else if (!strcmp(*argptr, "-V")) {
Douglas Gilbert9fbc8842015-12-20 16:23:44 +0000420 pr2serr("sg_rdac version: %s\n", version_str);
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +0000421 return 0;
422 }
423 else if (*argv[k] == '-') {
Douglas Gilbert9fbc8842015-12-20 16:23:44 +0000424 pr2serr("Unrecognized switch: %s\n", argv[k]);
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +0000425 file_name = 0;
426 break;
427 }
428 else if (0 == file_name)
429 file_name = argv[k];
430 else {
Douglas Gilbert9fbc8842015-12-20 16:23:44 +0000431 pr2serr("too many arguments\n");
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +0000432 file_name = 0;
433 break;
434 }
435 }
436 if (0 == file_name) {
437 usage();
438 return SG_LIB_SYNTAX_ERROR;
439 }
Douglas Gilbert75026472007-06-27 03:51:21 +0000440
Douglas Gilbertb2e59f42017-10-09 23:49:50 +0000441 fd = sg_cmds_open_device(file_name, false /* rw */, do_verbose);
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +0000442 if (fd < 0) {
Douglas Gilbert9fbc8842015-12-20 16:23:44 +0000443 pr2serr("open error: %s: %s\n", file_name, safe_strerror(-fd));
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +0000444 usage();
Douglas Gilbert856fb912018-05-15 20:44:45 +0000445 ret = sg_convert_errno(-fd);
446 goto fini;
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +0000447 }
Douglas Gilbert1ed38622008-06-04 18:56:15 +0000448
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +0000449 if (fail_all) {
Douglas Gilbertbaa91c32015-04-01 21:45:22 +0000450 res = fail_all_paths(fd, use_6_byte);
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +0000451 } else if (fail_path) {
Douglas Gilbertbaa91c32015-04-01 21:45:22 +0000452 res = fail_this_path(fd, lun, use_6_byte);
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +0000453 } else {
Douglas Gilbert9a9577a2017-10-22 17:32:39 +0000454 resid = 0;
Douglas Gilberte3aba382015-04-10 15:00:15 +0000455 if (use_6_byte)
Douglas Gilbertb2e59f42017-10-09 23:49:50 +0000456 res = sg_ll_mode_sense6(fd, /* DBD */ false,
457 /* PC */ 0,
458 0x2c /* page */,
459 0 /*subpage */,
460 rsp_buff, 252,
Douglas Gilbert3c285ac2017-09-18 19:15:01 +0000461 true, do_verbose);
Douglas Gilberte3aba382015-04-10 15:00:15 +0000462 else
Douglas Gilbert9a9577a2017-10-22 17:32:39 +0000463 res = sg_ll_mode_sense10_v2(fd, /* llbaa */ false,
464 /* DBD */ false,
465 /* page control */0,
466 0x2c, 0x1 /* subpage */,
467 rsp_buff, 308, 0, &resid,
468 true, do_verbose);
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +0000469
Douglas Gilbert9a9577a2017-10-22 17:32:39 +0000470 if (! res) {
Douglas Gilbertd0cecdd2017-10-31 02:18:16 +0000471 len = sg_msense_calc_length(rsp_buff, 308, use_6_byte,
472 NULL);
Douglas Gilbert9a9577a2017-10-22 17:32:39 +0000473 if (resid > 0) {
474 len = ((308 - resid) < len) ? (308 - resid) :
475 len;
476 if (len < 2)
477 pr2serr("MS(10) residual value (%d) "
478 "a worry\n", resid);
479 }
480 if (do_verbose && (len > 1))
481 dump_mode_page(rsp_buff, len);
482 print_rdac_mode(rsp_buff, ! use_6_byte);
Douglas Gilbert80bb62d2014-05-16 22:51:01 +0000483 } else {
484 if (SG_LIB_CAT_INVALID_OP == res)
Douglas Gilbert9fbc8842015-12-20 16:23:44 +0000485 pr2serr(">>>>>> try again without the '-6' "
486 "switch for a 10 byte MODE SENSE "
487 "command\n");
Douglas Gilbert80bb62d2014-05-16 22:51:01 +0000488 else if (SG_LIB_CAT_ILLEGAL_REQ == res)
Douglas Gilbert9fbc8842015-12-20 16:23:44 +0000489 pr2serr("mode sense: invalid field in cdb "
490 "(perhaps subpages or page control "
491 "(PC) not supported)\n");
Douglas Gilbert80bb62d2014-05-16 22:51:01 +0000492 else {
493 char b[80];
494
495 sg_get_category_sense_str(res, sizeof(b), b,
496 do_verbose);
Douglas Gilbert9fbc8842015-12-20 16:23:44 +0000497 pr2serr("mode sense failed: %s\n", b);
Douglas Gilbert80bb62d2014-05-16 22:51:01 +0000498 }
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +0000499 }
500 }
501 ret = res;
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +0000502
Douglas Gilbert75026472007-06-27 03:51:21 +0000503 res = sg_cmds_close_device(fd);
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +0000504 if (res < 0) {
Douglas Gilbert9fbc8842015-12-20 16:23:44 +0000505 pr2serr("close error: %s\n", safe_strerror(-res));
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +0000506 if (0 == ret)
Douglas Gilbert856fb912018-05-15 20:44:45 +0000507 ret = sg_convert_errno(res);
508 }
509fini:
510 if (0 == do_verbose) {
511 if (! sg_if_can2stderr("sg_rdac failed: ", ret))
512 pr2serr("Some error occurred, try again with '-v' "
513 "or '-vv' for more information\n");
Douglas Gilbert71e6e2d2007-06-27 03:24:23 +0000514 }
515 return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
516}