static int fail_all_paths(int fd, int use_6_byte) { unsigned char fail_paths_pg[308]; struct rdac_legacy_page *rdac_page; struct rdac_expanded_page *rdac_page_exp; struct rdac_page_common *rdac_common = NULL; int res; char b[80]; memset(fail_paths_pg, 0, 308); if (use_6_byte) { memcpy(fail_paths_pg, mode6_hdr, 4); memcpy(fail_paths_pg + 4, block_descriptor, 8); rdac_page = (struct rdac_legacy_page *)(fail_paths_pg + 4 + 8); rdac_page->page_code = RDAC_CONTROLLER_PAGE; rdac_page->page_length = RDAC_CONTROLLER_PAGE_LEN; rdac_common = &rdac_page->attr; } else { memcpy(fail_paths_pg, mode10_hdr, 8); rdac_page_exp = (struct rdac_expanded_page *) (fail_paths_pg + 8); rdac_page_exp->page_code = RDAC_CONTROLLER_PAGE | 0x40; rdac_page_exp->subpage_code = 0x1; rdac_page_exp->page_length[0] = EXPANDED_LUN_SPACE_PAGE_LEN >> 8; rdac_page_exp->page_length[1] = EXPANDED_LUN_SPACE_PAGE_LEN & 0xFF; rdac_common = &rdac_page_exp->attr; } rdac_common->current_mode_lsb = RDAC_FAIL_ALL_PATHS; rdac_common->quiescence = RDAC_QUIESCENCE_TIME; rdac_common->options = RDAC_FORCE_QUIESCENCE; if (use_6_byte) { res = sg_ll_mode_select6(fd, 1 /* pf */, 0 /* sp */, fail_paths_pg, 118, 1, (do_verbose ? 2 : 0)); } else { res = sg_ll_mode_select10(fd, 1 /* pf */, 0 /* sp */, fail_paths_pg, 308, 1, (do_verbose ? 2: 0)); } switch (res) { case 0: if (do_verbose) fprintf(stderr, "fail paths successful\n"); break; default: sg_get_category_sense_str(res, sizeof(b), b, do_verbose); fprintf(stderr, "fail paths failed: %s\n", b); break; } return res; }
int main(int argc, char * argv[]) { int sg_fd, res, c, num, alloc_len, off, pdt; int k, md_len, hdr_len, bd_len, mask_in_len; unsigned u, uu; int dbd = 0; int got_contents = 0; int force = 0; int got_mask = 0; int mode_6 = 0; int pg_code = -1; int sub_pg_code = 0; int save = 0; int verbose = 0; int read_in_len = 0; const char * device_name = NULL; unsigned char read_in[MX_ALLOC_LEN]; unsigned char mask_in[MX_ALLOC_LEN]; unsigned char ref_md[MX_ALLOC_LEN]; char ebuff[EBUFF_SZ]; struct sg_simple_inquiry_resp inq_data; int ret = 0; while (1) { int option_index = 0; c = getopt_long(argc, argv, "c:dfhl:m:p:svV", long_options, &option_index); if (c == -1) break; switch (c) { case 'c': memset(read_in, 0, sizeof(read_in)); if (0 != build_mode_page(optarg, read_in, &read_in_len, sizeof(read_in))) { fprintf(stderr, "bad argument to '--contents'\n"); return SG_LIB_SYNTAX_ERROR; } got_contents = 1; break; case 'd': dbd = 1; break; case 'f': force = 1; break; case 'h': case '?': usage(); return 0; case 'l': num = sscanf(optarg, "%d", &res); if ((1 == num) && ((6 == res) || (10 == res))) mode_6 = (6 == res) ? 1 : 0; else { fprintf(stderr, "length (of cdb) must be 6 or 10\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'm': memset(mask_in, 0xff, sizeof(mask_in)); if (0 != build_mask(optarg, mask_in, &mask_in_len, sizeof(mask_in))) { fprintf(stderr, "bad argument to '--mask'\n"); return SG_LIB_SYNTAX_ERROR; } got_mask = 1; break; case 'p': if (NULL == strchr(optarg, ',')) { num = sscanf(optarg, "%x", &u); if ((1 != num) || (u > 62)) { fprintf(stderr, "Bad page code value after '--page' " "switch\n"); return SG_LIB_SYNTAX_ERROR; } pg_code = u; } else if (2 == sscanf(optarg, "%x,%x", &u, &uu)) { if (uu > 254) { fprintf(stderr, "Bad sub page code value after '--page'" " switch\n"); return SG_LIB_SYNTAX_ERROR; } pg_code = u; sub_pg_code = uu; } else { fprintf(stderr, "Bad page code, subpage code sequence after " "'--page' switch\n"); return SG_LIB_SYNTAX_ERROR; } break; case 's': save = 1; break; case 'v': ++verbose; break; case 'V': fprintf(stderr, ME "version: %s\n", version_str); return 0; default: fprintf(stderr, "unrecognised option code 0x%x ??\n", c); usage(); return SG_LIB_SYNTAX_ERROR; } } if (optind < argc) { if (NULL == device_name) { device_name = argv[optind]; ++optind; } if (optind < argc) { for (; optind < argc; ++optind) fprintf(stderr, "Unexpected extra argument: %s\n", argv[optind]); usage(); return SG_LIB_SYNTAX_ERROR; } } if (NULL == device_name) { fprintf(stderr, "missing device name!\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (pg_code < 0) { fprintf(stderr, "need page code (see '--page=')\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (got_mask && force) { fprintf(stderr, "cannot use both '--force' and '--mask'\n"); usage(); return SG_LIB_SYNTAX_ERROR; } sg_fd = sg_cmds_open_device(device_name, 0 /* rw */, verbose); if (sg_fd < 0) { fprintf(stderr, ME "open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } if (0 == sg_simple_inquiry(sg_fd, &inq_data, 0, verbose)) pdt = inq_data.peripheral_type; else pdt = 0x1f; /* do MODE SENSE to fetch current values */ memset(ref_md, 0, MX_ALLOC_LEN); alloc_len = mode_6 ? SHORT_ALLOC_LEN : MX_ALLOC_LEN; if (mode_6) res = sg_ll_mode_sense6(sg_fd, dbd, 0 /*current */, pg_code, sub_pg_code, ref_md, alloc_len, 1, verbose); else res = sg_ll_mode_sense10(sg_fd, 0 /* llbaa */, dbd, 0 /* current */, pg_code, sub_pg_code, ref_md, alloc_len, 1, verbose); ret = res; if (SG_LIB_CAT_INVALID_OP == res) { fprintf(stderr, "MODE SENSE (%d) not supported, try '--len=%d'\n", (mode_6 ? 6 : 10), (mode_6 ? 10 : 6)); goto err_out; } else if (SG_LIB_CAT_NOT_READY == res) { fprintf(stderr, "MODE SENSE (%d) failed, device not ready\n", (mode_6 ? 6 : 10)); goto err_out; } else if (SG_LIB_CAT_UNIT_ATTENTION == res) { fprintf(stderr, "MODE SENSE (%d) failed, unit attention\n", (mode_6 ? 6 : 10)); goto err_out; } else if (SG_LIB_CAT_ABORTED_COMMAND == res) { fprintf(stderr, "MODE SENSE (%d) failed, aborted command\n", (mode_6 ? 6 : 10)); goto err_out; } else if (SG_LIB_CAT_ILLEGAL_REQ == res) { fprintf(stderr, "bad field in MODE SENSE (%d) command\n", (mode_6 ? 6 : 10)); goto err_out; } else if (0 != res) { fprintf(stderr, "MODE SENSE (%d) failed\n", (mode_6 ? 6 : 10)); goto err_out; } off = sg_mode_page_offset(ref_md, alloc_len, mode_6, ebuff, EBUFF_SZ); if (off < 0) { fprintf(stderr, "MODE SENSE (%d): %s\n", (mode_6 ? 6 : 10), ebuff); goto err_out; } if (mode_6) { hdr_len = 4; md_len = ref_md[0] + 1; bd_len = ref_md[3]; } else { hdr_len = 8; md_len = (ref_md[0] << 8) + ref_md[1] + 2; bd_len = (ref_md[6] << 8) + ref_md[7]; } if (got_contents) { if (read_in_len < 2) { fprintf(stderr, "contents length=%d too short\n", read_in_len); goto err_out; } ref_md[0] = 0; /* mode data length reserved for mode select */ if (! mode_6) ref_md[1] = 0; /* mode data length reserved for mode select */ if (0 == pdt) /* for disks mask out DPOFUA bit */ ref_md[mode_6 ? 2 : 3] &= 0xef; if (md_len > alloc_len) { fprintf(stderr, "mode data length=%d exceeds allocation " "length=%d\n", md_len, alloc_len); goto err_out; } if (got_mask) { for (k = 0; k < (md_len - off); ++k) { if ((0x0 == mask_in[k]) || (k > read_in_len)) read_in[k] = ref_md[off + k]; else if (mask_in[k] < 0xff) { c = (ref_md[off + k] & (0xff & ~mask_in[k])); read_in[k] = (c | (read_in[k] & mask_in[k])); } } read_in_len = md_len - off; } if (! force) { if ((! (ref_md[off] & 0x80)) && save) { fprintf(stderr, "PS bit in existing mode page indicates that " "it is not saveable\n but '--save' option given\n"); goto err_out; } read_in[0] &= 0x7f; /* mask out PS bit, reserved in mode select */ if ((md_len - off) != read_in_len) { fprintf(stderr, "contents length=%d but reference mode page " "length=%d\n", read_in_len, md_len - off); goto err_out; } if (pg_code != (read_in[0] & 0x3f)) { fprintf(stderr, "contents page_code=0x%x but reference " "page_code=0x%x\n", (read_in[0] & 0x3f), pg_code); goto err_out; } if ((read_in[0] & 0x40) != (ref_md[off] & 0x40)) { fprintf(stderr, "contents flags subpage but reference page" "does not (or vice versa)\n"); goto err_out; } if ((read_in[0] & 0x40) && (read_in[1] != sub_pg_code)) { fprintf(stderr, "contents subpage_code=0x%x but reference " "sub_page_code=0x%x\n", read_in[1], sub_pg_code); goto err_out; } } else md_len = off + read_in_len; /* force length */ memcpy(ref_md + off, read_in, read_in_len); if (mode_6) res = sg_ll_mode_select6(sg_fd, 1, save, ref_md, md_len, 1, verbose); else res = sg_ll_mode_select10(sg_fd, 1, save, ref_md, md_len, 1, verbose); ret = res; if (SG_LIB_CAT_INVALID_OP == res) { fprintf(stderr, "MODE SELECT (%d) not supported\n", (mode_6 ? 6 : 10)); goto err_out; } else if (SG_LIB_CAT_NOT_READY == res) { fprintf(stderr, "MODE SELECT (%d) failed, device not ready\n", (mode_6 ? 6 : 10)); goto err_out; } else if (SG_LIB_CAT_UNIT_ATTENTION == res) { fprintf(stderr, "MODE SELECT (%d) failed, unit attention\n", (mode_6 ? 6 : 10)); goto err_out; } else if (SG_LIB_CAT_ABORTED_COMMAND == res) { fprintf(stderr, "MODE SELECT (%d) failed, aborted command\n", (mode_6 ? 6 : 10)); goto err_out; } else if (SG_LIB_CAT_ILLEGAL_REQ == res) { fprintf(stderr, "bad field in MODE SELECT (%d) command\n", (mode_6 ? 6 : 10)); goto err_out; } else if (0 != res) { fprintf(stderr, "MODE SELECT (%d) failed\n", (mode_6 ? 6 : 10)); goto err_out; } } else { printf(">>> No contents given, so show current mode page data:\n"); printf(" header:\n"); dStrHex((const char *)ref_md, hdr_len, -1); if (bd_len) { printf(" block descriptor(s):\n"); dStrHex((const char *)(ref_md + hdr_len), bd_len, -1); } else printf(" << no block descriptors >>\n"); printf(" mode page:\n"); dStrHex((const char *)(ref_md + off), md_len - off, -1); } err_out: res = sg_cmds_close_device(sg_fd); if (res < 0) { fprintf(stderr, "close error: %s\n", safe_strerror(-res)); if (0 == ret) return SG_LIB_FILE_ERROR; } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; }
static int fail_this_path(int fd, int lun, int use_6_byte) { unsigned char fail_paths_pg[308]; struct rdac_legacy_page *rdac_page; struct rdac_expanded_page *rdac_page_exp; struct rdac_page_common *rdac_common = NULL; int res; char b[80]; if (use_6_byte && lun > 32) { pr2serr("must use 10 byte cdb to fail luns over 32\n"); return -1; } memset(fail_paths_pg, 0, 308); if (use_6_byte) { memcpy(fail_paths_pg, mode6_hdr, 4); memcpy(fail_paths_pg + 4, block_descriptor, 8); rdac_page = (struct rdac_legacy_page *)(fail_paths_pg + 4 + 8); rdac_page->page_code = RDAC_CONTROLLER_PAGE; rdac_page->page_length = RDAC_CONTROLLER_PAGE_LEN; rdac_common = &rdac_page->attr; memset(rdac_page->lun_table, 0x0, 32); rdac_page->lun_table[lun] = 0x81; } else { memcpy(fail_paths_pg, mode10_hdr, 8); rdac_page_exp = (struct rdac_expanded_page *) (fail_paths_pg + 8); rdac_page_exp->page_code = RDAC_CONTROLLER_PAGE | 0x40; rdac_page_exp->subpage_code = 0x1; sg_put_unaligned_be16(EXPANDED_LUN_SPACE_PAGE_LEN, rdac_page_exp->page_length + 0); rdac_common = &rdac_page_exp->attr; memset(rdac_page_exp->lun_table, 0x0, 256); rdac_page_exp->lun_table[lun] = 0x81; } rdac_common->current_mode_lsb = RDAC_FAIL_SELECTED_PATHS; rdac_common->quiescence = RDAC_QUIESCENCE_TIME; rdac_common->options = RDAC_FORCE_QUIESCENCE; if (use_6_byte) { res = sg_ll_mode_select6(fd, 1 /* pf */, 0 /* sp */, fail_paths_pg, 118, 1, (do_verbose ? 2 : 0)); } else { res = sg_ll_mode_select10(fd, 1 /* pf */, 0 /* sp */, fail_paths_pg, 308, 1, (do_verbose ? 2: 0)); } switch (res) { case 0: if (do_verbose) pr2serr("fail paths successful\n"); break; default: sg_get_category_sense_str(res, sizeof(b), b, do_verbose); pr2serr("fail paths page (lun=%d) failed: %s\n", lun, b); break; } return res; }