static void decode_all_sa_s(const unsigned char * rabp, int len, const struct opts_t * op) { if (op->do_hex && (2 != op->do_hex)) { dStrHex((const char *)rabp, len, ((1 == op->do_hex) ? 1 : -1)); return; } switch (op->sa) { case RA_ATTR_VAL_SA: decode_attr_vals(rabp + 4, len - 4, op); break; case RA_ATTR_LIST_SA: decode_attr_list(rabp + 4, len - 4, false, op); break; case RA_LV_LIST_SA: if ((0 == op->quiet) || op->verbose) printf("Logical volume list:\n"); if (len < 4) { pr2serr(">>> response length unexpectedly short: %d bytes\n", len); break; } printf(" First logical volume number: %u\n", rabp[2]); printf(" Number of logical volumes available: %u\n", rabp[3]); break; case RA_PART_LIST_SA: if ((0 == op->quiet) || op->verbose) printf("Partition number list:\n"); if (len < 4) { pr2serr(">>> response length unexpectedly short: %d bytes\n", len); break; } printf(" First partition number: %u\n", rabp[2]); printf(" Number of partitions available: %u\n", rabp[3]); break; case RA_SMC2_SA: printf("Used by SMC-2, not information, output in hex:\n"); dStrHex((const char *)rabp, len, 0); break; case RA_SUP_ATTR_SA: decode_attr_list(rabp + 4, len - 4, true, op); break; default: printf("Unrecognized service action [0x%x], response in hex:\n", op->sa); dStrHex((const char *)rabp, len, 0); break; } }
static int examine_pages(int sg_fd, int inq_pdt, int inq_byte6, const struct opts_t * optsp) { int k, res, header, mresp_len, len; unsigned char rbuf[256]; const char * cp; mresp_len = (optsp->do_raw || optsp->do_hex) ? sizeof(rbuf) : 4; for (header = 0, k = 0; k < PG_CODE_MAX; ++k) { if (optsp->do_six) { res = sg_ll_mode_sense6(sg_fd, 0, 0, k, 0, rbuf, mresp_len, 1, optsp->do_verbose); if (SG_LIB_CAT_INVALID_OP == res) { fprintf(stderr, ">>>>>> try again without the '-6' " "switch for a 10 byte MODE SENSE command\n"); return res; } else if (SG_LIB_CAT_NOT_READY == res) { fprintf(stderr, "MODE SENSE (6) failed, device not ready\n"); return res; } } else { res = sg_ll_mode_sense10(sg_fd, 0, 0, 0, k, 0, rbuf, mresp_len, 1, optsp->do_verbose); if (SG_LIB_CAT_INVALID_OP == res) { fprintf(stderr, ">>>>>> try again with a '-6' " "switch for a 6 byte MODE SENSE command\n"); return res; } else if (SG_LIB_CAT_NOT_READY == res) { fprintf(stderr, "MODE SENSE (10) failed, device not ready\n"); return res; } } if (0 == res) { len = optsp->do_six ? (rbuf[0] + 1) : ((rbuf[0] << 8) + rbuf[1] + 2); if (len > mresp_len) len = mresp_len; if (optsp->do_raw) { dStrRaw((const char *)rbuf, len); continue; } if (0 == header) { printf("Discovered mode pages:\n"); header = 1; } cp = find_page_code_desc(k, 0, inq_pdt, inq_byte6, -1); if (cp) printf(" %s\n", cp); else printf(" [0x%x]\n", k); if (optsp->do_hex) dStrHex((const char *)rbuf, len, 1); } } return res; }
/* Buffer ID 0x04: Read Device Slot Status (mandatory) */ static int do_safte_slot_status(int sg_fd, int do_hex, int do_raw, int verbose) { int res, i; unsigned int rb_len; unsigned char *rb_buff, slot_status; rb_len = safte_cfg.slots * 4; rb_buff = (unsigned char *)malloc(rb_len); if (verbose > 1) pr2serr("Use READ BUFFER,mode=vendor_specific,buff_id=4 to read " "device slot status\n"); res = sg_ll_read_buffer(sg_fd, RWB_MODE_VENDOR, 4, 0, rb_buff, rb_len, 0, verbose); if (res && res != SG_LIB_CAT_RECOVERED) { free(rb_buff); return res; } if (do_raw > 1) { dStrRaw((const char *)rb_buff, buf_capacity); return 0; } if (do_hex > 1) { dStrHex((const char *)rb_buff, buf_capacity, 1); return 0; } printf("Slot status:\n"); for (i = 0; i < safte_cfg.slots; i++) { slot_status = rb_buff[i * 4 + 3]; printf("\tSlot %d: ", i); if (slot_status & 0x7) { if (slot_status & 0x1) printf("inserted "); if (slot_status & 0x2) printf("ready "); if (slot_status & 0x4) printf("activated "); printf("\n"); } else { printf("empty\n"); } } free(rb_buff); return 0; }
/* Buffer ID 0x02: Read Usage Statistics (optional) */ static int do_safte_usage_statistics(int sg_fd, int do_hex, int do_raw, int verbose) { int res; unsigned int rb_len; unsigned char *rb_buff; unsigned int minutes; rb_len = 16 + safte_cfg.vendor_specific; rb_buff = (unsigned char *)malloc(rb_len); if (verbose > 1) fprintf(stderr, "Use READ BUFFER,mode=vendor_specific,buff_id=2 " "to read usage statistics\n"); res = sg_ll_read_buffer(sg_fd, RWB_MODE_VENDOR, 2, 0, rb_buff, rb_len, 0, verbose); if (res) { if (res == SG_LIB_CAT_ILLEGAL_REQ) { printf("Usage Statistics:\n\tNot implemented\n"); return 0; } if (res != SG_LIB_CAT_RECOVERED) { free(rb_buff); return res; } } if (do_raw > 1) { dStrRaw((const char *)rb_buff, buf_capacity); return 0; } if (do_hex > 1) { dStrHex((const char *)rb_buff, buf_capacity, 1); return 0; } printf("Usage Statistics:\n"); minutes = (rb_buff[0] << 24) + (rb_buff[1] << 16) + (rb_buff[2] << 8) + rb_buff[3]; printf("\tPower on Minutes: %u\n", minutes); minutes = (rb_buff[4] << 24) + (rb_buff[5] << 16) + (rb_buff[6] << 8) + rb_buff[7]; printf("\tPower on Cycles: %u\n", minutes); free(rb_buff); return 0; }
/* Buffer ID 0x03: Read Device Insertions (optional) */ static int do_safte_slot_insertions(int sg_fd, int do_hex, int do_raw, int verbose) { int res, i; unsigned int rb_len; unsigned char *rb_buff, slot_status; rb_len = safte_cfg.slots * 2; rb_buff = (unsigned char *)malloc(rb_len); if (verbose > 1) pr2serr("Use READ BUFFER,mode=vendor_specific,buff_id=3 to read " "device insertions\n"); res = sg_ll_read_buffer(sg_fd, RWB_MODE_VENDOR, 3, 0, rb_buff, rb_len, 0, verbose); if (res ) { if (res == SG_LIB_CAT_ILLEGAL_REQ) { printf("Slot insertions:\n\tNot implemented\n"); return 0; } if (res != SG_LIB_CAT_RECOVERED) { free(rb_buff); return res; } } if (do_raw > 1) { dStrRaw((const char *)rb_buff, buf_capacity); return 0; } if (do_hex > 1) { dStrHex((const char *)rb_buff, buf_capacity, 1); return 0; } printf("Slot insertions:\n"); for (i = 0; i < safte_cfg.slots; i++) { slot_status = sg_get_unaligned_be16(rb_buff + (i * 2)); printf("\tSlot %d: %d insertions", i, slot_status); } free(rb_buff); return 0; }
static void decode_attr_list(const unsigned char * alp, int len, bool supported, const struct opts_t * op) { int id; char b[160]; char * cp; char * c2p; const char * leadin = supported ? "Supported a" : "A"; if (op->verbose) printf("%sttribute list: [len=%d]\n", leadin, len); else if (0 == op->quiet) printf("%sttribute list:\n", leadin); if (op->do_hex) { dStrHex((const char *)alp, len, 0); return; } for ( ; len > 0; alp += 2, len -= 2) { id = sg_get_unaligned_be16(alp + 0); if ((op->filter >= 0) && (op->filter != id)) continue; if (op->verbose) printf(" 0x%.4x:\t", id); cp = attr_id_lookup(id, NULL, sizeof(b), b); c2p = strchr(cp, '\t'); if (c2p) { printf(" %.*s -\n", (int)(c2p - cp), cp); if (op->verbose) printf("\t\t %s\n", c2p + 1); else printf(" %s\n", c2p + 1); } else printf(" %s\n", cp); } }
int main(int argc, char * argv[]) { int res, c, k, len, off, decoded, act_resplen; int rcount = 1; int enhanced = 0; int do_hex = 0; int rindex = 0; int phy_id = 0; int do_raw = 0; int rtype = 0; int verbose = 0; int64_t sa_ll; uint64_t sa = 0; char i_params[256]; char device_name[512]; unsigned char smp_req[] = {SMP_FRAME_TYPE_REQ, SMP_FN_READ_GPIO_REG, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; unsigned char smp_resp[SMP_MAX_RESP_LEN]; struct smp_target_obj tobj; struct smp_req_resp smp_rr; int subvalue = 0; char * cp; int ret = 0; char b[128]; memset(device_name, 0, sizeof device_name); memset(i_params, 0, sizeof i_params); while (1) { int option_index = 0; c = getopt_long(argc, argv, "c:EhHi:I:p:rs:t:vV", long_options, &option_index); if (c == -1) break; switch (c) { case 'c': rcount = smp_get_num(optarg); if ((rcount < 1) || (rcount > 255)) { pr2serr("bad argument to '--count'\n"); return SMP_LIB_SYNTAX_ERROR; } break; case 'E': ++enhanced; break; case 'h': case '?': usage(); return 0; case 'H': ++do_hex; break; case 'i': rindex = smp_get_num(optarg); if ((rindex < 0) || (rindex > 255)) { pr2serr("bad argument to '--index'\n"); return SMP_LIB_SYNTAX_ERROR; } break; case 'I': strncpy(i_params, optarg, sizeof(i_params)); i_params[sizeof(i_params) - 1] = '\0'; break; case 'p': phy_id = smp_get_num(optarg); if ((phy_id < 0) || (phy_id > 254)) { pr2serr("bad argument to '--phy', expect value from 0 to " "254\n"); return SMP_LIB_SYNTAX_ERROR; } if (verbose) pr2serr("'--phy=<n>' option not needed so ignored\n"); break; case 'r': ++do_raw; break; case 's': sa_ll = smp_get_llnum(optarg); if (-1LL == sa_ll) { pr2serr("bad argument to '--sa'\n"); return SMP_LIB_SYNTAX_ERROR; } sa = (uint64_t)sa_ll; break; case 't': rtype = smp_get_num(optarg); if ((rtype < 0) || (rtype > 255)) { pr2serr("bad argument to '--type'\n"); return SMP_LIB_SYNTAX_ERROR; } break; case 'v': ++verbose; break; case 'V': pr2serr("version: %s\n", version_str); return 0; default: pr2serr("unrecognised switch code 0x%x ??\n", c); usage(); return SMP_LIB_SYNTAX_ERROR; } } if (optind < argc) { if ('\0' == device_name[0]) { strncpy(device_name, argv[optind], sizeof(device_name) - 1); device_name[sizeof(device_name) - 1] = '\0'; ++optind; } if (optind < argc) { for (; optind < argc; ++optind) pr2serr("Unexpected extra argument: %s\n", argv[optind]); usage(); return SMP_LIB_SYNTAX_ERROR; } } if (0 == device_name[0]) { cp = getenv("SMP_UTILS_DEVICE"); if (cp) strncpy(device_name, cp, sizeof(device_name) - 1); else { pr2serr("missing device name on command line\n [Could use " "environment variable SMP_UTILS_DEVICE instead]\n"); usage(); return SMP_LIB_SYNTAX_ERROR; } } if ((cp = strchr(device_name, SMP_SUBVALUE_SEPARATOR))) { *cp = '\0'; if (1 != sscanf(cp + 1, "%d", &subvalue)) { pr2serr("expected number after separator in SMP_DEVICE name\n"); return SMP_LIB_SYNTAX_ERROR; } } if (0 == sa) { cp = getenv("SMP_UTILS_SAS_ADDR"); if (cp) { sa_ll = smp_get_llnum(cp); if (-1LL == sa_ll) { pr2serr("bad value in environment variable " "SMP_UTILS_SAS_ADDR\n use 0\n"); sa_ll = 0; } sa = (uint64_t)sa_ll; } } if (sa > 0) { if (! smp_is_naa5(sa)) { pr2serr("SAS (target) address not in naa-5 format (may need " "leading '0x')\n"); if ('\0' == i_params[0]) { pr2serr(" use '--interface=' to override\n"); return SMP_LIB_SYNTAX_ERROR; } } } res = smp_initiator_open(device_name, subvalue, i_params, sa, &tobj, verbose); if (res < 0) return SMP_LIB_FILE_ERROR; if (enhanced) { smp_req[1] = SMP_FN_READ_GPIO_REG_ENH; smp_req[2] = rcount; /* response payload in dwords */ smp_req[3] = 0x1; /* 12 byte request */ off = 2; } else off = 0; smp_req[2 + off] = rtype; smp_req[3 + off] = rindex; smp_req[4 + off] = rcount; if (verbose) { pr2serr(" Read GPIO register%s request: ", (enhanced ? " enhanced" : "")); for (k = 0; k < (int)sizeof(smp_req); ++k) pr2serr("%02x ", smp_req[k]); pr2serr("\n"); } memset(&smp_rr, 0, sizeof(smp_rr)); smp_rr.request_len = sizeof(smp_req); smp_rr.request = smp_req; smp_rr.max_response_len = sizeof(smp_resp); smp_rr.response = smp_resp; res = smp_send_req(&tobj, &smp_rr, verbose); if (res) { pr2serr("smp_send_req failed, res=%d\n", res); if (0 == verbose) pr2serr(" try adding '-v' option for more debug\n"); ret = -1; goto err_out; } if (smp_rr.transport_err) { pr2serr("smp_send_req transport_error=%d\n", smp_rr.transport_err); ret = -1; goto err_out; } act_resplen = smp_rr.act_response_len; if ((act_resplen >= 0) && (act_resplen < 4)) { pr2serr("response too short, len=%d\n", act_resplen); ret = SMP_LIB_CAT_MALFORMED; goto err_out; } if (enhanced) { len = smp_resp[3]; if ((len != rcount) && verbose) pr2serr("requested %d dwords but received %d\n", rcount, len); } else len = rcount; len = 4 + (len * 4); /* length in bytes, excluding 4 byte CRC */ if ((act_resplen >= 0) && (len > act_resplen)) { if (verbose) pr2serr("actual response length [%d] less than deduced length " "[%d]\n", act_resplen, len); len = act_resplen; } if (do_hex || do_raw) { if (do_hex) dStrHex((const char *)smp_resp, len, 1); else dStrRaw((const char *)smp_resp, len); if (SMP_FRAME_TYPE_RESP != smp_resp[0]) ret = SMP_LIB_CAT_MALFORMED; else if (smp_resp[1] != smp_req[1]) ret = SMP_LIB_CAT_MALFORMED; else if (smp_resp[2]) ret = smp_resp[2]; goto err_out; } if (SMP_FRAME_TYPE_RESP != smp_resp[0]) { pr2serr("expected SMP frame response type, got=0x%x\n", smp_resp[0]); ret = SMP_LIB_CAT_MALFORMED; goto err_out; } if (smp_resp[1] != smp_req[1]) { pr2serr("Expected function code=0x%x, got=0x%x\n", smp_req[1], smp_resp[1]); ret = SMP_LIB_CAT_MALFORMED; goto err_out; } if (smp_resp[2]) { ret = smp_resp[2]; cp = smp_get_func_res_str(ret, sizeof(b), b); pr2serr("Read gpio register%s result: %s\n", (enhanced ? " enhanced" : ""), cp); goto err_out; } printf("Read GPIO register%s response:\n", (enhanced ? " enhanced" : "")); decoded = 0; if (0 == rtype) { off = 4; if (0 == rindex) { printf(" GPIO_CFG[0]:\n"); printf(" version: %d\n", (smp_resp[off + 1] & 0xf)); printf(" GPIO enable: %d\n", !!(smp_resp[off + 2] & 0x80)); printf(" cfg register count: %d\n", ((smp_resp[off + 2] >> 4) & 0x7)); printf(" gp register count: %d\n", (smp_resp[off + 2] & 0xf)); printf(" supported drive count: %d\n", smp_resp[off + 3]); ++decoded; off += 4; }
int main(int argc, char * argv[]) { int res, c, k, len, act_resplen; int aff_context = 0; int do_hex = 0; int phy_id = 0; int phy_id_given = 0; int do_raw = 0; int verbose = 0; int do_zero = 0; int64_t sa_ll; uint64_t sa = 0; char i_params[256]; char device_name[512]; char b[256]; unsigned char smp_req[] = {SMP_FRAME_TYPE_REQ, SMP_FN_REPORT_PHY_SATA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; unsigned char smp_resp[SMP_FN_REPORT_PHY_SATA_RESP_LEN]; struct smp_req_resp smp_rr; struct smp_target_obj tobj; int subvalue = 0; char * cp; int ret = 0; memset(device_name, 0, sizeof device_name); while (1) { int option_index = 0; c = getopt_long(argc, argv, "ahHI:p:rs:vVz", long_options, &option_index); if (c == -1) break; switch (c) { case 'a': aff_context = smp_get_num(optarg); if ((aff_context < 0) || (aff_context > 255)) { pr2serr("bad argument to '--affiliation'\n"); return SMP_LIB_SYNTAX_ERROR; } break; case 'h': case '?': usage(); return 0; case 'H': ++do_hex; break; case 'I': strncpy(i_params, optarg, sizeof(i_params)); i_params[sizeof(i_params) - 1] = '\0'; break; case 'p': phy_id = smp_get_num(optarg); if ((phy_id < 0) || (phy_id > 254)) { pr2serr("bad argument to '--phy', expect value from 0 to " "254\n"); return SMP_LIB_SYNTAX_ERROR; } ++phy_id_given; break; case 'r': ++do_raw; break; case 's': sa_ll = smp_get_llnum(optarg); if (-1LL == sa_ll) { pr2serr("bad argument to '--sa'\n"); return SMP_LIB_SYNTAX_ERROR; } sa = (uint64_t)sa_ll; break; case 'v': ++verbose; break; case 'V': pr2serr("version: %s\n", version_str); return 0; case 'z': ++do_zero; break; default: pr2serr("unrecognised switch code 0x%x ??\n", c); usage(); return SMP_LIB_SYNTAX_ERROR; } } if (optind < argc) { if ('\0' == device_name[0]) { strncpy(device_name, argv[optind], sizeof(device_name) - 1); device_name[sizeof(device_name) - 1] = '\0'; ++optind; } if (optind < argc) { for (; optind < argc; ++optind) pr2serr("Unexpected extra argument: %s\n", argv[optind]); usage(); return SMP_LIB_SYNTAX_ERROR; } } if (0 == device_name[0]) { cp = getenv("SMP_UTILS_DEVICE"); if (cp) strncpy(device_name, cp, sizeof(device_name) - 1); else { pr2serr("missing device name on command line\n [Could use " "environment variable SMP_UTILS_DEVICE instead]\n"); usage(); return SMP_LIB_SYNTAX_ERROR; } } if ((cp = strchr(device_name, SMP_SUBVALUE_SEPARATOR))) { *cp = '\0'; if (1 != sscanf(cp + 1, "%d", &subvalue)) { pr2serr("expected number after separator in SMP_DEVICE name\n"); return SMP_LIB_SYNTAX_ERROR; } } if (0 == sa) { cp = getenv("SMP_UTILS_SAS_ADDR"); if (cp) { sa_ll = smp_get_llnum(cp); if (-1LL == sa_ll) { pr2serr("bad value in environment variable " "SMP_UTILS_SAS_ADDR\n use 0\n"); sa_ll = 0; } sa = (uint64_t)sa_ll; } } if (sa > 0) { if (! smp_is_naa5(sa)) { pr2serr("SAS (target) address not in naa-5 format (may need " "leading '0x')\n"); if ('\0' == i_params[0]) { pr2serr(" use '--interface=' to override\n"); return SMP_LIB_SYNTAX_ERROR; } } } res = smp_initiator_open(device_name, subvalue, i_params, sa, &tobj, verbose); if (res < 0) return SMP_LIB_FILE_ERROR; if (! do_zero) { /* SAS-2 or later */ len = (sizeof(smp_resp) - 8) / 4; smp_req[2] = (len < 0x100) ? len : 0xff; /* Allocated Response Len */ smp_req[3] = 2; /* Request Length: in dwords */ } smp_req[9] = phy_id; smp_req[10] = aff_context; if (verbose) { pr2serr(" Report phy SATA request: "); for (k = 0; k < (int)sizeof(smp_req); ++k) pr2serr("%02x ", smp_req[k]); pr2serr("\n"); } memset(&smp_rr, 0, sizeof(smp_rr)); smp_rr.request_len = sizeof(smp_req); smp_rr.request = smp_req; smp_rr.max_response_len = sizeof(smp_resp); smp_rr.response = smp_resp; res = smp_send_req(&tobj, &smp_rr, verbose); if (res) { pr2serr("smp_send_req failed, res=%d\n", res); if (0 == verbose) pr2serr(" try adding '-v' option for more debug\n"); ret = -1; goto err_out; } if (smp_rr.transport_err) { pr2serr("smp_send_req transport_error=%d\n", smp_rr.transport_err); ret = -1; goto err_out; } act_resplen = smp_rr.act_response_len; if ((act_resplen >= 0) && (act_resplen < 4)) { pr2serr("response too short, len=%d\n", act_resplen); ret = SMP_LIB_CAT_MALFORMED; goto err_out; } len = smp_resp[3]; if ((0 == len) && (0 == smp_resp[2])) { len = smp_get_func_def_resp_len(smp_resp[1]); if (len < 0) { len = 0; if (verbose > 0) pr2serr("unable to determine response length\n"); } } len = 4 + (len * 4); /* length in bytes, excluding 4 byte CRC */ if ((act_resplen >= 0) && (len > act_resplen)) { if (verbose) pr2serr("actual response length [%d] less than deduced length " "[%d]\n", act_resplen, len); len = act_resplen; } if (do_hex || do_raw) { if (do_hex) dStrHex((const char *)smp_resp, len, 1); else dStrRaw((const char *)smp_resp, len); if (SMP_FRAME_TYPE_RESP != smp_resp[0]) ret = SMP_LIB_CAT_MALFORMED; else if (smp_resp[1] != smp_req[1]) ret = SMP_LIB_CAT_MALFORMED; else if (smp_resp[2]) { if (verbose) pr2serr("Report phy SATA result: %s\n", smp_get_func_res_str(smp_resp[2], sizeof(b), b)); ret = smp_resp[2]; } goto err_out; } if (SMP_FRAME_TYPE_RESP != smp_resp[0]) { pr2serr("expected SMP frame response type, got=0x%x\n", smp_resp[0]); ret = SMP_LIB_CAT_MALFORMED; goto err_out; } if (smp_resp[1] != smp_req[1]) { pr2serr("Expected function code=0x%x, got=0x%x\n", smp_req[1], smp_resp[1]); ret = SMP_LIB_CAT_MALFORMED; goto err_out; } if (smp_resp[2]) { cp = smp_get_func_res_str(smp_resp[2], sizeof(b), b); pr2serr("Report phy SATA result%s: %s\n", (phy_id_given ? "" : " (for phy_id=0)"), cp); ret = smp_resp[2]; goto err_out; } printf("Report phy SATA response:\n"); res = sg_get_unaligned_be16(smp_resp + 4); if (verbose || (res > 0)) printf(" expander change count: %d\n", res); printf(" phy identifier: %d\n", smp_resp[9]); printf(" STP I_T nexus loss occurred: %d\n", !!(smp_resp[11] & 0x4)); printf(" affiliations supported: %d\n", !!(smp_resp[11] & 0x2)); printf(" affiliation valid: %d\n", !!(smp_resp[11] & 0x1)); printf(" STP SAS address: 0x%" PRIx64 "\n", sg_get_unaligned_be64(smp_resp + 16)); printf(" register device to host FIS:\n "); for (k = 0; k < 20; ++k) printf("%02x ", smp_resp[24 + k]); printf("\n"); printf(" affiliated STP initiator SAS address: 0x%" PRIx64 "\n", sg_get_unaligned_be64(smp_resp + 48)); if (len > 63) printf(" STP I_T nexus loss SAS address: 0x%" PRIx64 "\n", sg_get_unaligned_be64(smp_resp + 56)); if (len > 67) { printf(" affiliation context: %d\n", smp_resp[65]); printf(" current affiliation contexts: %d\n", smp_resp[66]); printf(" maximum affiliation contexts: %d\n", smp_resp[67]); } err_out: res = smp_initiator_close(&tobj); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(errno)); if (0 == ret) return SMP_LIB_FILE_ERROR; } if (ret < 0) ret = SMP_LIB_CAT_OTHER; if (verbose && ret) pr2serr("Exit status %d indicates error detected\n", ret); return ret; }
int main(int argc, char * argv[]) { int res, c, k, j, m, len, desc_len, num_desc, numzg, max_sszg; int desc_per_resp, first, rtype, act_resplen; int do_append = 0; int do_hex = 0; int multiple = 0; int nocomma = 0; int mndesc = DEF_MAX_NUM_DESC; int mndesc_given = 0; const char * permf = NULL; int do_raw = 0; int report_type = 0; int sszg = 0; int bits_col = 0; int verbose = 0; int64_t sa_ll; uint64_t sa = 0; char i_params[256]; char device_name[512]; char b[256]; unsigned char smp_req[12]; unsigned char smp_resp[SMP_FN_REPORT_ZONE_PERMISSION_TBL_RESP_LEN]; struct smp_req_resp smp_rr; struct smp_target_obj tobj; int subvalue = 0; char * cp; unsigned char * descp; FILE * foutp = stdout; int ret = 0; memset(device_name, 0, sizeof device_name); memset(smp_resp, 0, sizeof smp_resp); while (1) { int option_index = 0; c = getopt_long(argc, argv, "aB:f:hHI:mn:NP:rR:s:vV", long_options, &option_index); if (c == -1) break; switch (c) { case 'a': ++do_append; break; case 'B': bits_col = smp_get_num(optarg); if ((bits_col < 1) || (bits_col > 256)) { pr2serr("bad argument to '--bits=', expect 1 to 256\n"); return SMP_LIB_SYNTAX_ERROR; } break; case 'f': /* note: maps to '--start=SS' option */ sszg = smp_get_num(optarg); if ((sszg < 0) || (sszg > 255)) { pr2serr("bad argument to '--start=', expect 0 to 255\n"); return SMP_LIB_SYNTAX_ERROR; } break; case 'h': case '?': usage(); return 0; case 'H': ++do_hex; break; case 'I': strncpy(i_params, optarg, sizeof(i_params)); i_params[sizeof(i_params) - 1] = '\0'; break; case 'n': mndesc = smp_get_num(optarg); if ((mndesc < 0) || (mndesc > 63)) { pr2serr("bad argument to '--num=', expect 0 to 63\n"); return SMP_LIB_SYNTAX_ERROR; } if (0 == mndesc) mndesc = DEF_MAX_NUM_DESC; else ++mndesc_given; break; case 'm': ++multiple; break; case 'N': ++nocomma; break; case 'P': permf = optarg; break; case 'r': ++do_raw; break; case 'R': report_type = smp_get_num(optarg); if ((report_type < 0) || (report_type > 3)) { pr2serr("bad argument to '--report=', expect 0 to 3\n"); return SMP_LIB_SYNTAX_ERROR; } break; case 's': sa_ll = smp_get_llnum(optarg); if (-1LL == sa_ll) { pr2serr("bad argument to '--sa'\n"); return SMP_LIB_SYNTAX_ERROR; } sa = (uint64_t)sa_ll; break; case 'v': ++verbose; break; case 'V': pr2serr("version: %s\n", version_str); return 0; default: pr2serr("unrecognised switch code 0x%x ??\n", c); usage(); return SMP_LIB_SYNTAX_ERROR; } } if (optind < argc) { if ('\0' == device_name[0]) { strncpy(device_name, argv[optind], sizeof(device_name) - 1); device_name[sizeof(device_name) - 1] = '\0'; ++optind; } if (optind < argc) { for (; optind < argc; ++optind) pr2serr("Unexpected extra argument: %s\n", argv[optind]); usage(); return SMP_LIB_SYNTAX_ERROR; } } if (0 == device_name[0]) { cp = getenv("SMP_UTILS_DEVICE"); if (cp) strncpy(device_name, cp, sizeof(device_name) - 1); else { pr2serr("missing device name on command line\n [Could use " "environment variable SMP_UTILS_DEVICE instead]\n"); usage(); return SMP_LIB_SYNTAX_ERROR; } } if ((cp = strchr(device_name, SMP_SUBVALUE_SEPARATOR))) { *cp = '\0'; if (1 != sscanf(cp + 1, "%d", &subvalue)) { pr2serr("expected number after separator in SMP_DEVICE name\n"); return SMP_LIB_SYNTAX_ERROR; } } if (0 == sa) { cp = getenv("SMP_UTILS_SAS_ADDR"); if (cp) { sa_ll = smp_get_llnum(cp); if (-1LL == sa_ll) { pr2serr("bad value in environment variable " "SMP_UTILS_SAS_ADDR\n use 0\n"); sa_ll = 0; } sa = (uint64_t)sa_ll; } } if (sa > 0) { if (! smp_is_naa5(sa)) { pr2serr("SAS (target) address not in naa-5 format (may need " "leading '0x')\n"); if ('\0' == i_params[0]) { pr2serr(" use '--interface=' to override\n"); return SMP_LIB_SYNTAX_ERROR; } } } if (multiple && mndesc_given) { pr2serr("--multiple and --num clash, give one or the other\n"); return SMP_LIB_SYNTAX_ERROR; } res = smp_initiator_open(device_name, subvalue, i_params, sa, &tobj, verbose); if (res < 0) return SMP_LIB_FILE_ERROR; if (permf) { if ((1 == strlen(permf)) && (0 == strcmp("-", permf))) ; else { foutp = fopen(permf, (do_append ? "a" : "w")); if (NULL == foutp) { pr2serr("unable to open %s, error: %s\n", permf, safe_strerror(errno)); ret = SMP_LIB_FILE_ERROR; goto err_out; } } } max_sszg = 256; desc_per_resp = 63; for (j = sszg, first = 1; j < max_sszg; j += desc_per_resp) { memset(smp_req, 0, sizeof smp_req); smp_req[0] = SMP_FRAME_TYPE_REQ; smp_req[1] = SMP_FN_REPORT_ZONE_PERMISSION_TBL; len = (sizeof(smp_resp) - 8) / 4; smp_req[2] = (len < 0x100) ? len : 0xff; /* Allocated Response Len */ smp_req[3] = 0x1; smp_req[4] = report_type & 0x3; smp_req[6] = j & 0xff; numzg = max_sszg - j; if (desc_per_resp < numzg) numzg = desc_per_resp; if (mndesc < numzg) numzg = mndesc; smp_req[7] = numzg & 0xff; if (verbose) { pr2serr(" Report zone permission table request: "); for (k = 0; k < (int)sizeof(smp_req); ++k) pr2serr("%02x ", smp_req[k]); pr2serr("\n"); } memset(&smp_rr, 0, sizeof(smp_rr)); smp_rr.request_len = sizeof(smp_req); smp_rr.request = smp_req; smp_rr.max_response_len = sizeof(smp_resp); smp_rr.response = smp_resp; res = smp_send_req(&tobj, &smp_rr, verbose); if (res) { pr2serr("smp_send_req failed, res=%d\n", res); if (0 == verbose) pr2serr(" try adding '-v' option for more debug\n"); ret = -1; goto err_out; } if (smp_rr.transport_err) { pr2serr("smp_send_req transport_error=%d\n", smp_rr.transport_err); ret = -1; goto err_out; } act_resplen = smp_rr.act_response_len; if ((act_resplen >= 0) && (act_resplen < 4)) { pr2serr("response too short, len=%d\n", act_resplen); ret = SMP_LIB_CAT_MALFORMED; goto err_out; } len = smp_resp[3]; if ((0 == len) && (0 == smp_resp[2])) { len = smp_get_func_def_resp_len(smp_resp[1]); if (len < 0) { len = 0; if (verbose > 0) pr2serr("unable to determine response length\n"); } } len = 4 + (len * 4); /* length in bytes, excluding 4 byte CRC */ if ((act_resplen >= 0) && (len > act_resplen)) { if (verbose) pr2serr("actual response length [%d] less than deduced " "length [%d]\n", act_resplen, len); len = act_resplen; } if (do_hex || do_raw) { if (do_hex) dStrHex((const char *)smp_resp, len, 1); else dStrRaw((const char *)smp_resp, len); if (SMP_FRAME_TYPE_RESP != smp_resp[0]) ret = SMP_LIB_CAT_MALFORMED; if (smp_resp[1] != smp_req[1]) ret = SMP_LIB_CAT_MALFORMED; if (smp_resp[2]) { ret = smp_resp[2]; if (verbose) pr2serr("Report zone permission table result: %s\n", smp_get_func_res_str(ret, sizeof(b), b)); } goto err_out; } if (SMP_FRAME_TYPE_RESP != smp_resp[0]) { pr2serr("expected SMP frame response type, got=0x%x\n", smp_resp[0]); ret = SMP_LIB_CAT_MALFORMED; goto err_out; } if (smp_resp[1] != smp_req[1]) { pr2serr("Expected function code=0x%x, got=0x%x\n", smp_req[1], smp_resp[1]); ret = SMP_LIB_CAT_MALFORMED; goto err_out; } if (smp_resp[2]) { cp = smp_get_func_res_str(smp_resp[2], sizeof(b), b); pr2serr("Report zone permission table result: %s\n", cp); ret = smp_resp[2]; goto err_out; } numzg = (0xc0 & smp_resp[7]) >> 6; desc_len = smp_resp[13] * 4; num_desc = smp_resp[15]; rtype = 0x3 & smp_resp[6]; if (first) { first = 0; if (0 == numzg) { max_sszg = 128; desc_per_resp = 63; } else { max_sszg = 256; desc_per_resp = 31; } fprintf(foutp, "# Report zone permission table response:\n"); res = sg_get_unaligned_be16(smp_resp + 4); if (verbose || res) fprintf(foutp, "# Expander change count: %d\n", res); fprintf(foutp, "# zone locked: %d\n", !! (0x80 & smp_resp[6])); fprintf(foutp, "# report type: %d [%s]\n", rtype, decode_rtype[rtype]); fprintf(foutp, "# number of zone groups: %d (%s)\n", numzg, decode_numzg[numzg]); if (verbose) { fprintf(foutp, "# zone permission descriptor length: %d " "dwords\n", smp_resp[13]); fprintf(foutp, "# starting source zone group%s: %d\n", (multiple ? " (of first request)" : ""), smp_resp[14]); fprintf(foutp, "# number of zone permission descriptors%s: " "%d\n", (multiple ? " (of first request)" : ""), num_desc); } else if (! multiple) fprintf(foutp, "# number of zone permission descriptors: " "%d\n", num_desc); if (sszg > 0) fprintf(foutp, "--start=%d\n", sszg); if (bits_col) { fprintf(foutp, "\n\nOutput unsuitable for " "smp_conf_zone_perm_tbl utility\n\n "); for (k = 0; k < bits_col; ++k) fprintf(foutp, "%d", k % 10); fprintf(foutp, "\n\n"); } if (0 == numzg_blen[numzg]) { pr2serr("unexpected number of zone groups: %d\n", numzg); goto err_out; } } descp = smp_resp + 16; for (k = 0; k < num_desc; ++k, descp += desc_len) { if (0 == bits_col) { for (m = 0; m < desc_len; ++m) { if (nocomma) fprintf(foutp, "%02x", descp[m]); else { if (0 == m) fprintf(foutp, "%x", descp[m]); else fprintf(foutp, ",%x", descp[m]); } } } else { /* --bit=<bits_col> given */ int by, bi; if ((k + j) >= bits_col) break; fprintf(foutp, "%-4d", j + k); for (m = 0; m < bits_col; ++m) { by = (m / 8) + 1; bi = m % 8; fprintf(foutp, "%d", (descp[desc_len - by] >> bi) & 0x1); } } fprintf(foutp, "\n"); } if ((0 == multiple) || (mndesc < desc_per_resp)) break; } err_out: if (foutp && (stdout != foutp)) { fclose(foutp); foutp = NULL; } res = smp_initiator_close(&tobj); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(errno)); if (0 == ret) return SMP_LIB_FILE_ERROR; } if (ret < 0) ret = SMP_LIB_CAT_OTHER; if (verbose && ret) pr2serr("Exit status %d indicates error detected\n", ret); return ret; }
static int do_read_gplog(int sg_fd, int ata_cmd, unsigned char *inbuff, const struct opts_t * op) { int res, ret; int extend = 1; int protocol; int t_dir = 1; /* 0 -> to device, 1 -> from device */ int byte_block = 1; /* 0 -> bytes, 1 -> 512 byte blocks */ int t_length = 2; /* 0 -> no data transferred, 2 -> sector count */ int t_type = 0; /* 0 -> 512 byte blocks, 1 -> logical sectors */ int resid = 0; int got_ard = 0; /* got ATA result descriptor */ int sb_sz; struct sg_scsi_sense_hdr ssh; unsigned char sense_buffer[64]; unsigned char ata_return_desc[16]; unsigned char apt_cdb[SAT_ATA_PASS_THROUGH16_LEN] = {SAT_ATA_PASS_THROUGH16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; unsigned char apt12_cdb[SAT_ATA_PASS_THROUGH12_LEN] = {SAT_ATA_PASS_THROUGH12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; char cmd_name[32]; snprintf(cmd_name, sizeof(cmd_name), "ATA PASS-THROUGH (%d)", op->cdb_len); if (ata_cmd == ATA_READ_LOG_DMA_EXT) { protocol = 6; /* DMA */ } else { protocol = 4; /* PIO Data-In */ } sb_sz = sizeof(sense_buffer); memset(sense_buffer, 0, sb_sz); memset(ata_return_desc, 0, sizeof(ata_return_desc)); memset(inbuff, 0, op->count * 512); if (op->verbose > 1) pr2serr("Building ATA READ LOG%s EXT command; la=0x%x, pn=0x%x\n", ((ata_cmd == ATA_READ_LOG_DMA_EXT) ? " DMA" : ""), op->la, op->pn); if (op->cdb_len == 16) { /* Prepare ATA PASS-THROUGH COMMAND (16) command */ apt_cdb[14] = ata_cmd; sg_put_unaligned_be16((uint16_t)op->count, apt_cdb + 5); apt_cdb[8] = op->la; sg_put_unaligned_be16((uint16_t)op->pn, apt_cdb + 9); apt_cdb[1] = (protocol << 1) | extend; apt_cdb[2] = (op->ck_cond << 5) | (t_type << 4) | (t_dir << 3) | (byte_block << 2) | t_length; res = sg_ll_ata_pt(sg_fd, apt_cdb, op->cdb_len, DEF_TIMEOUT, inbuff, NULL, op->count * 512, sense_buffer, sb_sz, ata_return_desc, sizeof(ata_return_desc), &resid, op->verbose); } else { /* Prepare ATA PASS-THROUGH COMMAND (12) command */ /* Cannot map upper 8 bits of the pn since no LBA (39:32) field */ apt12_cdb[9] = ata_cmd; apt12_cdb[4] = op->count; apt12_cdb[5] = op->la; apt12_cdb[6] = op->pn & 0xff; /* apt12_cdb[7] = (op->pn >> 8) & 0xff; */ apt12_cdb[1] = (protocol << 1); apt12_cdb[2] = (op->ck_cond << 5) | (t_type << 4) | (t_dir << 3) | (byte_block << 2) | t_length; res = sg_ll_ata_pt(sg_fd, apt12_cdb, op->cdb_len, DEF_TIMEOUT, inbuff, NULL, op->count * 512, sense_buffer, sb_sz, ata_return_desc, sizeof(ata_return_desc), &resid, op->verbose); } if (0 == res) { if (op->verbose > 2) pr2serr("command completed with SCSI GOOD status\n"); if ((0 == op->hex) || (2 == op->hex)) dWordHex((const unsigned short *)inbuff, op->count * 256, 0, sg_is_big_endian()); else if (1 == op->hex) dStrHex((const char *)inbuff, 512, 0); else if (3 == op->hex) /* '-HHH' suitable for "hdparm --Istdin" */ dWordHex((const unsigned short *)inbuff, 256, -2, sg_is_big_endian()); else /* '-HHHH' hex bytes only */ dStrHex((const char *)inbuff, 512, -1); } else if ((res > 0) && (res & SAM_STAT_CHECK_CONDITION)) { if (op->verbose > 1) { pr2serr("ATA pass through:\n"); sg_print_sense(NULL, sense_buffer, sb_sz, ((op->verbose > 2) ? 1 : 0)); } if (sg_scsi_normalize_sense(sense_buffer, sb_sz, &ssh)) { switch (ssh.sense_key) { case SPC_SK_ILLEGAL_REQUEST: if ((0x20 == ssh.asc) && (0x0 == ssh.ascq)) { ret = SG_LIB_CAT_INVALID_OP; if (op->verbose < 2) pr2serr("%s not supported\n", cmd_name); } else { ret = SG_LIB_CAT_ILLEGAL_REQ; if (op->verbose < 2) pr2serr("%s, bad field in cdb\n", cmd_name); } return ret; case SPC_SK_NO_SENSE: case SPC_SK_RECOVERED_ERROR: if ((0x0 == ssh.asc) && (ASCQ_ATA_PT_INFO_AVAILABLE == ssh.ascq)) { if (SAT_ATA_RETURN_DESC != ata_return_desc[0]) { if (op->verbose) pr2serr("did not find ATA Return (sense) " "Descriptor\n"); return SG_LIB_CAT_RECOVERED; } got_ard = 1; break; } else if (SPC_SK_RECOVERED_ERROR == ssh.sense_key) return SG_LIB_CAT_RECOVERED; else { if ((0x0 == ssh.asc) && (0x0 == ssh.ascq)) break; return SG_LIB_CAT_SENSE; } case SPC_SK_UNIT_ATTENTION: if (op->verbose < 2) pr2serr("%s, Unit Attention detected\n", cmd_name); return SG_LIB_CAT_UNIT_ATTENTION; case SPC_SK_NOT_READY: if (op->verbose < 2) pr2serr("%s, device not ready\n", cmd_name); return SG_LIB_CAT_NOT_READY; case SPC_SK_MEDIUM_ERROR: case SPC_SK_HARDWARE_ERROR: if (op->verbose < 2) pr2serr("%s, medium or hardware error\n", cmd_name); return SG_LIB_CAT_MEDIUM_HARD; case SPC_SK_ABORTED_COMMAND: if (0x10 == ssh.asc) { pr2serr("Aborted command: protection information\n"); return SG_LIB_CAT_PROTECTION; } else { pr2serr("Aborted command\n"); return SG_LIB_CAT_ABORTED_COMMAND; } case SPC_SK_DATA_PROTECT: pr2serr("%s: data protect, read only media?\n", cmd_name); return SG_LIB_CAT_DATA_PROTECT; default: if (op->verbose < 2) pr2serr("%s, some sense data, use '-v' for more " "information\n", cmd_name); return SG_LIB_CAT_SENSE; } } else { pr2serr("CHECK CONDITION without response code ??\n"); return SG_LIB_CAT_SENSE; } if (0x72 != (sense_buffer[0] & 0x7f)) { pr2serr("expected descriptor sense format, response " "code=0x%x\n", sense_buffer[0]); return SG_LIB_CAT_MALFORMED; } } else if (res > 0) { if (SAM_STAT_RESERVATION_CONFLICT == res) { pr2serr("SCSI status: RESERVATION CONFLICT\n"); return SG_LIB_CAT_RES_CONFLICT; } else { pr2serr("Unexpected SCSI status=0x%x\n", res); return SG_LIB_CAT_MALFORMED; } } else { pr2serr("%s failed\n", cmd_name); if (op->verbose < 2) pr2serr(" try adding '-v' for more information\n"); return -1; } if ((SAT_ATA_RETURN_DESC == ata_return_desc[0]) && (0 == got_ard)) pr2serr("Seem to have got ATA Result Descriptor but it was not " "indicated\n"); if (got_ard) { if (ata_return_desc[3] & 0x4) { pr2serr("error indication in returned FIS: aborted " "command\n"); return SG_LIB_CAT_ABORTED_COMMAND; } } return 0; }
int main(int argc, char * argv[]) { int sg_fd, k, j, off, res, c, report_len, tgt_port_count; unsigned char reportTgtGrpBuff[REPORT_TGT_GRP_BUFF_LEN]; unsigned char * ucp; int decode = 0; int hex = 0; int raw = 0; int o_readonly = 0; int verbose = 0; int extended = 0; const char * device_name = NULL; int ret = 0; while (1) { int option_index = 0; c = getopt_long(argc, argv, "dehHrRvV", long_options, &option_index); if (c == -1) break; switch (c) { case 'd': decode = 1; break; case 'e': extended = 1; break; case 'h': case '?': usage(); return 0; case 'H': hex = 1; break; case 'r': raw = 1; break; case 'R': ++o_readonly; break; case 'v': ++verbose; break; case 'V': fprintf(stderr, "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 (raw) { if (sg_set_binary_mode(STDOUT_FILENO) < 0) { perror("sg_set_binary_mode"); return SG_LIB_FILE_ERROR; } } sg_fd = sg_cmds_open_device(device_name, o_readonly, verbose); if (sg_fd < 0) { fprintf(stderr, "open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } memset(reportTgtGrpBuff, 0x0, sizeof(reportTgtGrpBuff)); /* trunc = 0; */ res = sg_ll_report_tgt_prt_grp2(sg_fd, reportTgtGrpBuff, sizeof(reportTgtGrpBuff), extended, 1, verbose); ret = res; if (0 == res) { report_len = (reportTgtGrpBuff[0] << 24) + (reportTgtGrpBuff[1] << 16) + (reportTgtGrpBuff[2] << 8) + reportTgtGrpBuff[3] + 4; if (report_len > (int)sizeof(reportTgtGrpBuff)) { /* trunc = 1; */ fprintf(stderr, " <<report too long for internal buffer," " output truncated\n"); report_len = (int)sizeof(reportTgtGrpBuff); } if (raw) { dStrRaw((const char *)reportTgtGrpBuff, report_len); goto err_out; } if (verbose) printf("Report list length = %d\n", report_len); if (hex) { if (verbose) printf("\nOutput response in hex:\n"); dStrHex((const char *)reportTgtGrpBuff, report_len, 1); goto err_out; } printf("Report target port groups:\n"); ucp = reportTgtGrpBuff + 4; if (extended) { if (0x10 != (ucp[0] & 0x70)) { fprintf(stderr, " <<invalid extended header format\n"); goto err_out; } printf(" Implicit transition time: %d\n", ucp[1]); ucp += 4; } for (k = ucp - reportTgtGrpBuff; k < report_len; k += off, ucp += off) { printf(" target port group id : 0x%x , Pref=%d, Rtpg_fmt=%d\n", (ucp[2] << 8) + ucp[3], !!(ucp[0] & 0x80), (ucp[0] >> 4) & 0x07); printf(" target port group asymmetric access state : "); printf("0x%02x", ucp[0] & 0x0f); if (decode) decode_tpgs_state(ucp[0] & 0x0f); printf("\n"); printf(" T_SUP : %d, ", !!(ucp[1] & 0x80)); printf("O_SUP : %d, ", !!(ucp[1] & 0x40)); printf("LBD_SUP : %d, ", !!(ucp[1] & 0x10)); printf("U_SUP : %d, ", !!(ucp[1] & 0x08)); printf("S_SUP : %d, ", !!(ucp[1] & 0x04)); printf("AN_SUP : %d, ", !!(ucp[1] & 0x02)); printf("AO_SUP : %d\n", !!(ucp[1] & 0x01)); printf(" status code : "); printf("0x%02x", ucp[5]); if (decode) decode_status(ucp[5]); printf("\n"); printf(" vendor unique status : "); printf("0x%02x\n", ucp[6]); printf(" target port count : "); tgt_port_count = ucp[7]; printf("%02x\n", tgt_port_count); for (j = 0; j < tgt_port_count * 4; j += 4) { if (0 == j) printf(" Relative target port ids:\n"); printf(" 0x%02x\n", (ucp[8 + j + 2] << 8) + ucp[8 + j + 3]); } off = 8 + j; } } else if (SG_LIB_CAT_INVALID_OP == res)
/* Buffer ID 0x05: Read Global Flags (optional) */ static int do_safte_global_flags(int sg_fd, int do_hex, int do_raw, int verbose) { int res; unsigned int rb_len; unsigned char *rb_buff; rb_len = 16; rb_buff = (unsigned char *)malloc(rb_len); if (verbose > 1) pr2serr("Use READ BUFFER,mode=vendor_specific,buff_id=5 to read " "global flags\n"); res = sg_ll_read_buffer(sg_fd, RWB_MODE_VENDOR, 5, 0, rb_buff, rb_len, 0, verbose); if (res ) { if (res == SG_LIB_CAT_ILLEGAL_REQ) { printf("Global Flags:\n\tNot implemented\n"); return 0; } if (res != SG_LIB_CAT_RECOVERED) { free(rb_buff); return res; } } if (do_raw > 1) { dStrRaw((const char *)rb_buff, buf_capacity); return 0; } if (do_hex > 1) { dStrHex((const char *)rb_buff, buf_capacity, 1); return 0; } printf("Global Flags:\n"); printf("\tAudible Alarm Control: %s\n", rb_buff[0] & 0x1?"on":"off"); printf("\tGlobal Failure Indicator: %s\n", rb_buff[0] & 0x2?"on":"off"); printf("\tGlobal Warning Indicator: %s\n", rb_buff[0] & 0x4?"on":"off"); printf("\tEnclosure Power: %s\n", rb_buff[0] & 0x8?"on":"off"); printf("\tCooling Failure: %s\n", rb_buff[0] & 0x10?"yes":"no"); printf("\tPower Failure: %s\n", rb_buff[0] & 0x20?"yes":"no"); printf("\tDrive Failure: %s\n", rb_buff[0] & 0x40?"yes":"no"); printf("\tDrive Warning: %s\n", rb_buff[0] & 0x80?"yes":"no"); printf("\tArray Failure: %s\n", rb_buff[1] & 0x1?"yes":"no"); printf("\tArray Warning: %s\n", rb_buff[0] & 0x2?"yes":"no"); printf("\tEnclosure Lock: %s\n", rb_buff[0] & 0x4?"on":"off"); printf("\tEnclosure Identify: %s\n", rb_buff[0] & 0x8?"on":"off"); free(rb_buff); return 0; }
static int do_identify_dev(int sg_fd, int do_packet, int cdb_len, int ck_cond, int extend, int do_indent, int do_hex, int do_raw, int verbose) { int ok, j, res, ret; /* Following for ATA READ/WRITE MULTIPLE (EXT) cmds, normally 0 */ int multiple_count = 0; int protocol = 4; /* PIO data-in */ int t_type = 0; /* 0 -> 512 byte blocks, 1 -> device's LB size */ int t_dir = 1; /* 0 -> to device, 1 -> from device */ int byte_block = 1; /* 0 -> bytes, 1 -> 512 byte blocks (if t_type=0) */ int t_length = 2; /* 0 -> no data transferred, 2 -> sector count */ int resid = 0; int got_ard = 0; /* got ATA result descriptor */ int got_fixsense = 0; /* got ATA result in fixed format sense */ int sb_sz; struct sg_scsi_sense_hdr ssh; unsigned char inBuff[ID_RESPONSE_LEN]; unsigned char sense_buffer[64]; unsigned char ata_return_desc[16]; unsigned char aptCmdBlk[SAT_ATA_PASS_THROUGH16_LEN] = {SAT_ATA_PASS_THROUGH16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; unsigned char apt12CmdBlk[SAT_ATA_PASS_THROUGH12_LEN] = {SAT_ATA_PASS_THROUGH12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; const unsigned short * usp; uint64_t ull; sb_sz = sizeof(sense_buffer); memset(sense_buffer, 0, sb_sz); memset(ata_return_desc, 0, sizeof(ata_return_desc)); ok = 0; if (SAT_ATA_PASS_THROUGH16_LEN == cdb_len) { /* Prepare ATA PASS-THROUGH COMMAND (16) command */ aptCmdBlk[6] = 1; /* sector count */ aptCmdBlk[14] = (do_packet ? ATA_IDENTIFY_PACKET_DEVICE : ATA_IDENTIFY_DEVICE); aptCmdBlk[1] = (multiple_count << 5) | (protocol << 1) | extend; aptCmdBlk[2] = (ck_cond << 5) | (t_type << 4) | (t_dir << 3) | (byte_block << 2) | t_length; res = sg_ll_ata_pt(sg_fd, aptCmdBlk, cdb_len, DEF_TIMEOUT, inBuff, NULL /* doutp */, ID_RESPONSE_LEN, sense_buffer, sb_sz, ata_return_desc, sizeof(ata_return_desc), &resid, verbose); } else { /* Prepare ATA PASS-THROUGH COMMAND (12) command */ apt12CmdBlk[4] = 1; /* sector count */ apt12CmdBlk[9] = (do_packet ? ATA_IDENTIFY_PACKET_DEVICE : ATA_IDENTIFY_DEVICE); apt12CmdBlk[1] = (multiple_count << 5) | (protocol << 1); apt12CmdBlk[2] = (ck_cond << 5) | (t_type << 4) | (t_dir << 3) | (byte_block << 2) | t_length; res = sg_ll_ata_pt(sg_fd, apt12CmdBlk, cdb_len, DEF_TIMEOUT, inBuff, NULL /* doutp */, ID_RESPONSE_LEN, sense_buffer, sb_sz, ata_return_desc, sizeof(ata_return_desc), &resid, verbose); } if (0 == res) { ok = 1; if (verbose > 2) pr2serr("command completed with SCSI GOOD status\n"); } else if ((res > 0) && (res & SAM_STAT_CHECK_CONDITION)) { if (verbose > 1) { pr2serr("ATA pass through:\n"); sg_print_sense(NULL, sense_buffer, sb_sz, ((verbose > 2) ? 1 : 0)); } if (sg_scsi_normalize_sense(sense_buffer, sb_sz, &ssh)) { switch (ssh.sense_key) { case SPC_SK_ILLEGAL_REQUEST: if ((0x20 == ssh.asc) && (0x0 == ssh.ascq)) { ret = SG_LIB_CAT_INVALID_OP; if (verbose < 2) pr2serr("ATA PASS-THROUGH (%d) not supported\n", cdb_len); } else { ret = SG_LIB_CAT_ILLEGAL_REQ; if (verbose < 2) pr2serr("ATA PASS-THROUGH (%d), bad field in cdb\n", cdb_len); } return ret; case SPC_SK_NO_SENSE: case SPC_SK_RECOVERED_ERROR: if ((0x0 == ssh.asc) && (ASCQ_ATA_PT_INFO_AVAILABLE == ssh.ascq)) { if (0x72 == ssh.response_code) { if (SAT_ATA_RETURN_DESC != ata_return_desc[0]) { if (verbose) pr2serr("did not find ATA Return (sense) " "Descriptor\n"); return SG_LIB_CAT_RECOVERED; } got_ard = 1; break; } else if (0x70 == ssh.response_code) { got_fixsense = 1; break; } else { if (verbose < 2) pr2serr("ATA PASS-THROUGH (%d), unexpected " "response_code=0x%x\n", ssh.response_code, cdb_len); return SG_LIB_CAT_RECOVERED; } } else if (SPC_SK_RECOVERED_ERROR == ssh.sense_key) return SG_LIB_CAT_RECOVERED; else { if ((0x0 == ssh.asc) && (0x0 == ssh.ascq)) break; return SG_LIB_CAT_SENSE; } case SPC_SK_UNIT_ATTENTION: if (verbose < 2) pr2serr("ATA PASS-THROUGH (%d), Unit Attention detected\n", cdb_len); return SG_LIB_CAT_UNIT_ATTENTION; case SPC_SK_NOT_READY: if (verbose < 2) pr2serr("ATA PASS-THROUGH (%d), device not ready\n", cdb_len); return SG_LIB_CAT_NOT_READY; case SPC_SK_MEDIUM_ERROR: case SPC_SK_HARDWARE_ERROR: if (verbose < 2) pr2serr("ATA PASS-THROUGH (%d), medium or hardware " "error\n", cdb_len); return SG_LIB_CAT_MEDIUM_HARD; case SPC_SK_ABORTED_COMMAND: if (0x10 == ssh.asc) { pr2serr("Aborted command: protection information\n"); return SG_LIB_CAT_PROTECTION; } else { pr2serr("Aborted command: try again with%s '-p' option\n", (do_packet ? "out" : "")); return SG_LIB_CAT_ABORTED_COMMAND; } case SPC_SK_DATA_PROTECT: pr2serr("ATA PASS-THROUGH (%d): data protect, read only " "media?\n", cdb_len); return SG_LIB_CAT_DATA_PROTECT; default: if (verbose < 2) pr2serr("ATA PASS-THROUGH (%d), some sense data, use " "'-v' for more information\n", cdb_len); return SG_LIB_CAT_SENSE; } } else { pr2serr("CHECK CONDITION without response code ??\n"); return SG_LIB_CAT_SENSE; } if (0x72 != (sense_buffer[0] & 0x7f)) { pr2serr("expected descriptor sense format, response code=0x%x\n", sense_buffer[0]); return SG_LIB_CAT_MALFORMED; } } else if (res > 0) { if (SAM_STAT_RESERVATION_CONFLICT == res) { pr2serr("SCSI status: RESERVATION CONFLICT\n"); return SG_LIB_CAT_RES_CONFLICT; } else { pr2serr("Unexpected SCSI status=0x%x\n", res); return SG_LIB_CAT_MALFORMED; } } else { pr2serr("ATA pass through (%d) failed\n", cdb_len); if (verbose < 2) pr2serr(" try adding '-v' for more information\n"); return -1; } if ((SAT_ATA_RETURN_DESC == ata_return_desc[0]) && (0 == got_ard)) pr2serr("Seem to have got ATA Result Descriptor but it was not " "indicated\n"); if (got_ard) { if (ata_return_desc[3] & 0x4) { pr2serr("error indication in returned FIS: aborted command\n"); pr2serr(" try again with%s '-p' option\n", (do_packet ? "out" : "")); return SG_LIB_CAT_ABORTED_COMMAND; } ok = 1; } if (got_fixsense) { if (0x4 & sense_buffer[3]) { /* Error is MSB of Info field */ pr2serr("error indication in returned FIS: aborted command\n"); pr2serr(" try again with%s '-p' option\n", (do_packet ? "out" : "")); return SG_LIB_CAT_ABORTED_COMMAND; } ok = 1; } if (ok) { /* output result if it is available */ if (do_raw) dStrRaw((const char *)inBuff, 512); else if (0 == do_hex) { if (do_indent) { usp = (const unsigned short *)inBuff; ull = 0; for (j = 0; j < 4; ++j) { if (j > 0) ull <<= 16; ull |= usp[108 + j]; } printf("0x%016" PRIx64 "\n", ull); } else { printf("Response for IDENTIFY %sDEVICE ATA command:\n", (do_packet ? "PACKET " : "")); dWordHex((const unsigned short *)inBuff, 256, 0, sg_is_big_endian()); } } else if (1 == do_hex) dStrHex((const char *)inBuff, 512, 0); else if (2 == do_hex) dWordHex((const unsigned short *)inBuff, 256, 0, sg_is_big_endian()); else if (3 == do_hex) /* '-HHH' suitable for "hdparm --Istdin" */ dWordHex((const unsigned short *)inBuff, 256, -2, sg_is_big_endian()); else /* '-HHHH' hex bytes only */ dStrHex((const char *)inBuff, 512, -1); } return 0; }
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; }
int main(int argc, const char ** argv) { char buff[8192]; int num = 8192; long start = 0; int res, k, u, len, n; int inFile = STDIN_FILENO; int doHelp = 0; int doHex = 0; int noAddr = 0; int doVersion = 0; int hasFilename = 0; int ret = 0; const char * cp; for (k = 1; k < argc; k++) { cp = argv[k]; len = strlen(cp); if (0 == strncmp("-b=", cp, 3)) { res = sscanf(cp + 3, "%d", &u); if ((1 != res) || (u < 1)) { fprintf(stderr, "Bad value after '-b=' option\n"); usage(); return 1; } bytes_per_line = u; } else if ((len > 1) && ('-' == cp[0]) && ('-' != cp[1])) { res = 0; n = num_chs_in_str(cp + 1, len - 1, 'h'); doHelp += n; res += n; n = num_chs_in_str(cp + 1, len - 1, 'H'); doHex += n; res += n; n = num_chs_in_str(cp + 1, len - 1, 'N'); noAddr += n; res += n; n = num_chs_in_str(cp + 1, len - 1, 'V'); doVersion += n; res += n; n = num_chs_in_str(cp + 1, len - 1, '?'); doHelp += n; res += n; if (0 == res) { fprintf(stderr, "No option recognized in str: %s\n", cp); usage(); return 1; } } else if (0 == strcmp("-?", argv[k])) ++doHelp; else if (*argv[k] == '-') { fprintf(stderr, "unknown switch: %s\n", argv[k]); usage(); return 1; } else { hasFilename = 1; break; } } if (doVersion) { printf("%s\n", version_str); return 0; } if (doHelp) { usage(); return 0; } /* Make sure num to fetch is integral multiple of bytes_per_line */ if (0 != (num % bytes_per_line)) num = (num / bytes_per_line) * bytes_per_line; if (hasFilename) { for ( ; k < argc; k++) { inFile = open(argv[k], O_RDONLY); if (inFile < 0) { fprintf(stderr, "Couldn't open file: %s\n", argv[k]); ret = 1; } else { sg_set_binary_mode(inFile); start = 0; if (! doHex) printf("ASCII hex dump of file: %s\n", argv[k]); while ((res = read(inFile, buff, num)) > 0) { if (doHex) dStrHexOnly(buff, res, start, noAddr); else dStrHex(buff, res, start, noAddr); start += (long)res; } } close(inFile); } } else { sg_set_binary_mode(inFile); while ((res = read(inFile, buff, num)) > 0) { if (doHex) dStrHexOnly(buff, res, start, noAddr); else dStrHex(buff, res, start, noAddr); start += (long)res; } } return ret; }
int main(int argc, char * argv[]) { int res, c, len, k; int sg_fd = -1; int do_help = 0; int do_hex = 0; int do_long = 0; int o_readonly = 0; int rb_id = 0; int rb_len = 4; int rb_mode = 0; int rb_mode_sp = 0; int64_t ll; uint64_t rb_offset = 0; int do_raw = 0; int resid = 0; int verbose = 0; int ret = 0; const char * device_name = NULL; unsigned char * resp; const struct mode_s * mp; while (1) { int option_index = 0; c = getopt_long(argc, argv, "hHi:l:Lm:o:rRS:vV", long_options, &option_index); if (c == -1) break; switch (c) { case 'h': case '?': ++do_help; break; case 'H': ++do_hex; break; case 'i': rb_id = sg_get_num(optarg); if ((rb_id < 0) || (rb_id > 255)) { fprintf(stderr, "argument to '--id' should be in the range " "0 to 255\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'l': rb_len = sg_get_num(optarg); if (rb_len < 0) { fprintf(stderr, "bad argument to '--length'\n"); return SG_LIB_SYNTAX_ERROR; } if (rb_len > 0xffffff) { fprintf(stderr, "argument to '--length' must be <= " "0xffffff\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'L': ++do_long; break; case 'm': if (isdigit(*optarg)) { rb_mode = sg_get_num(optarg); if ((rb_mode < 0) || (rb_mode > 31)) { fprintf(stderr, "argument to '--mode' should be in the " "range 0 to 31\n"); return SG_LIB_SYNTAX_ERROR; } } else { len = strlen(optarg); for (mp = modes; mp->mode_string; ++mp) { if (0 == strncmp(mp->mode_string, optarg, len)) { rb_mode = mp->mode; break; } } if (NULL == mp) { print_modes(); return SG_LIB_SYNTAX_ERROR; } } break; case 'o': ll = sg_get_llnum(optarg); if (ll < 0) { fprintf(stderr, "bad argument to '--offset'\n"); return SG_LIB_SYNTAX_ERROR; } rb_offset = ll; break; case 'r': ++do_raw; break; case 'R': ++o_readonly; break; case 'S': rb_mode_sp = sg_get_num(optarg); if ((rb_mode_sp < 0) || (rb_mode_sp > 7)) { fprintf(stderr, "expected argument to '--specific' to be 0 " "to 7\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'v': ++verbose; break; case 'V': fprintf(stderr, "version: %s\n", version_str); return 0; default: fprintf(stderr, "unrecognised option code 0x%x ??\n", c); usage(); return SG_LIB_SYNTAX_ERROR; } } if (do_help) { if (do_help > 1) { usage(); fprintf(stderr, "\n"); print_modes(); } else usage(); return 0; } 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 (rb_len > 0) { resp = (unsigned char *)malloc(rb_len); if (NULL == resp) { fprintf(stderr, "unable to allocate %d bytes on the heap\n", rb_len); return SG_LIB_CAT_OTHER; } memset(resp, 0, rb_len); } else resp = NULL; if (do_raw) { if (sg_set_binary_mode(STDOUT_FILENO) < 0) { perror("sg_set_binary_mode"); ret = SG_LIB_FILE_ERROR; goto fini; } } #ifdef SG_LIB_WIN32 #ifdef SG_LIB_WIN32_DIRECT if (verbose > 4) fprintf(stderr, "Initial win32 SPT interface state: %s\n", scsi_pt_win32_spt_state() ? "direct" : "indirect"); scsi_pt_win32_direct(SG_LIB_WIN32_DIRECT /* SPT pt interface */); #endif #endif sg_fd = sg_cmds_open_device(device_name, o_readonly, verbose); if (sg_fd < 0) { fprintf(stderr, "open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); ret = SG_LIB_FILE_ERROR; goto fini; } if (do_long) res = ll_read_buffer_16(sg_fd, rb_mode, rb_mode_sp, rb_id, rb_offset, resp, rb_len, &resid, 1, verbose); else if (rb_offset > 0xffffff) { fprintf(stderr, "--offset value is too large for READ BUFFER(10), " "try --16\n"); ret = SG_LIB_SYNTAX_ERROR; goto fini; } else res = ll_read_buffer_10(sg_fd, rb_mode, rb_mode_sp, rb_id, (uint32_t)rb_offset, resp, rb_len, &resid, 1, verbose); if (0 != res) { char b[80]; ret = res; if (res > 0) { sg_get_category_sense_str(res, sizeof(b), b, verbose); fprintf(stderr, "Read buffer(%d) failed: %s\n", (do_long ? 16 : 10), b); } goto fini; } if (resid > 0) rb_len -= resid; /* got back less than requested */ if (rb_len > 0) { if (do_raw) dStrRaw((const char *)resp, rb_len); else if (do_hex || (rb_len < 4)) dStrHex((const char *)resp, rb_len, ((do_hex > 1) ? 0 : 1)); else { switch (rb_mode) { case MODE_DESCRIPTOR: k = (resp[1] << 16) | (resp[2] << 8) | resp[3]; printf("OFFSET BOUNDARY: %d, Buffer offset alignment: " "%d-byte\n", resp[0], (1 << resp[0])); printf("BUFFER CAPACITY: %d (0x%x)\n", k, k); break; case MODE_ECHO_BDESC: k = ((resp[2] & 0x1F) << 8) | resp[3]; printf("EBOS:%d\n", resp[0] & 1 ? 1 : 0); printf("Echo buffer capacity: %d (0x%x)\n", k, k); break; default: dStrHex((const char *)resp, rb_len, (verbose > 1 ? 0 : 1)); break; } } } fini: if (resp) free(resp); if (sg_fd >= 0) { 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; }
int main(int argc, char * argv[]) { int sg_fd, outfd, res, c; unsigned char * readLongBuff = NULL; void * rawp = NULL; int correct = 0; int xfer_len = 520; int do_16 = 0; int pblock = 0; uint64_t llba = 0; int readonly = 0; int verbose = 0; int64_t ll; int got_stdout; const char * device_name = NULL; char out_fname[256]; char ebuff[EBUFF_SZ]; int ret = 0; memset(out_fname, 0, sizeof out_fname); while (1) { int option_index = 0; c = getopt_long(argc, argv, "chl:o:prSvVx:", long_options, &option_index); if (c == -1) break; switch (c) { case 'c': correct = 1; break; case 'h': case '?': usage(); return 0; case 'l': ll = sg_get_llnum(optarg); if (-1 == ll) { fprintf(stderr, "bad argument to '--lba'\n"); return SG_LIB_SYNTAX_ERROR; } llba = (uint64_t)ll; break; case 'o': strncpy(out_fname, optarg, sizeof(out_fname) - 1); break; case 'p': pblock = 1; break; case 'r': ++readonly; break; case 'S': do_16 = 1; break; case 'v': ++verbose; break; case 'V': fprintf(stderr, ME "version: %s\n", version_str); return 0; case 'x': xfer_len = sg_get_num(optarg); if (-1 == xfer_len) { fprintf(stderr, "bad argument to '--xfer_len'\n"); return SG_LIB_SYNTAX_ERROR; } break; 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 (xfer_len >= MAX_XFER_LEN){ fprintf(stderr, "xfer_len (%d) is out of range ( < %d)\n", xfer_len, MAX_XFER_LEN); usage(); return SG_LIB_SYNTAX_ERROR; } sg_fd = sg_cmds_open_device(device_name, readonly, 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 (NULL == (rawp = malloc(MAX_XFER_LEN))) { fprintf(stderr, ME "out of memory\n"); sg_cmds_close_device(sg_fd); return SG_LIB_SYNTAX_ERROR; } readLongBuff = (unsigned char *)rawp; memset(rawp, 0x0, MAX_XFER_LEN); fprintf(stderr, ME "issue read long (%s) to device %s\n xfer_len=%d " "(0x%x), lba=%" PRIu64 " (0x%" PRIx64 "), correct=%d\n", (do_16 ? "16" : "10"), device_name, xfer_len, xfer_len, llba, llba, correct); if ((ret = process_read_long(sg_fd, do_16, pblock, correct, llba, readLongBuff, xfer_len, verbose))) goto err_out; if ('\0' == out_fname[0]) dStrHex((const char *)rawp, xfer_len, 0); else { got_stdout = (0 == strcmp(out_fname, "-")) ? 1 : 0; if (got_stdout) outfd = STDOUT_FILENO; else { if ((outfd = open(out_fname, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) { snprintf(ebuff, EBUFF_SZ, ME "could not open %s for writing", out_fname); perror(ebuff); goto err_out; } } if (sg_set_binary_mode(outfd) < 0) { perror("sg_set_binary_mode"); goto err_out; } res = write(outfd, readLongBuff, xfer_len); if (res < 0) { snprintf(ebuff, EBUFF_SZ, ME "couldn't write to %s", out_fname); perror(ebuff); goto err_out; } if (! got_stdout) close(outfd); } err_out: if (rawp) free(rawp); 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 void decode_attr_vals(const unsigned char * alp, int len, const struct opts_t * op) { int bump, id, alen; uint64_t ull; char * cp; char * c2p; const struct attr_name_info_t * anip; char b[160]; if (op->verbose) printf("Attribute values: [len=%d]\n", len); else if (op->filter < 0) { if (0 == op->quiet) printf("Attribute values:\n"); if (op->do_hex) { /* only expect -HH to get through here */ dStrHex((const char *)alp, len, 0); return; } } for ( ; len > 4; alp += bump, len -= bump) { id = sg_get_unaligned_be16(alp + 0); bump = sg_get_unaligned_be16(alp + 3) + 5; alen = bump - 5; if ((op->filter >= 0) && (op->filter != id)) { if (id < op->filter) continue; else break; /* Assume array is ascending id order */ } anip = NULL; cp = attr_id_lookup(id, &anip, sizeof(b), b); if (op->quiet < 2) { c2p = strchr(cp, '\t'); if (c2p) { printf(" %.*s -\n", (int)(c2p - cp), cp); printf(" %s: ", c2p + 1); } else printf(" %s: ", cp); } if (op->verbose) printf("[r%c] ", (0x80 & alp[2]) ? 'o' : 'w'); if (anip) { if ((RA_FMT_BINARY == anip->format) && (bump <= 13)) { ull = sg_get_unaligned_be(alen, alp + 5); if (0 == anip->process) printf("%" PRIu64 "\n", ull); else if (1 == anip->process) printf("0x%" PRIx64 "\n", ull); else helper_full_attr(alp, bump, id, anip, op); if (op->verbose) { if ((anip->len > 0) && (alen > 0) && (alen != anip->len)) printf(" <<< T10 length (%d) differs from length in " "response (%d) >>>\n", anip->len, alen); } } else if (RA_FMT_BINARY == anip->format) { if (2 == anip->process) helper_full_attr(alp, bump, id, anip, op); else { printf("\n"); dStrHex((const char *)(alp + 5), alen, 0); } } else { if (2 == anip->process) helper_full_attr(alp, bump, id, anip, op); else { printf("%.*s\n", alen, alp + 5); if (op->verbose) { if ((anip->len > 0) && (alen > 0) && (alen != anip->len)) printf(" <<< T10 length (%d) differs from length " "in response (%d) >>>\n", anip->len, alen); } } } } else { if (op->verbose > 1) printf("Attribute id lookup failed, in hex:\n"); else printf("\n"); dStrHex((const char *)(alp + 5), alen, 0); } } if (op->verbose && (len > 0) && (len <= 4)) pr2serr("warning: iterate of attributes should end a residual of " "%d\n", len); }
static void helper_full_attr(const unsigned char * alp, int len, int id, const struct attr_name_info_t * anip, const struct opts_t * op) { int k; const unsigned char * bp; if (op->verbose) printf("[r%c] ", (0x80 & alp[2]) ? 'o' : 'w'); if (op->verbose > 3) pr2serr("%s: id=0x%x, len=%d, anip->format=%d, anip->len=%d\n", __func__, id, len, anip->format, anip->len); switch (id) { case 0x224: /* logical position of first encrypted block */ k = all_ffs_or_last_fe(alp + 5, len - 5); if (1 == k) printf("<unknown> [ff]\n"); else if (2 == k) printf("<unknown [fe]>\n"); else { if ((len - 5) <= 8) printf("%" PRIx64, sg_get_unaligned_be(len - 5, alp + 5)); else { printf("\n"); dStrHex((const char *)(alp + 5), len - 5, 0); } } break; case 0x225: /* logical position of first unencrypted block * after first encrypted block */ k = all_ffs_or_last_fe(alp + 5, len - 5); if (1 == k) printf("<unknown> [ff]\n"); else if (2 == k) printf("<unknown [fe]>\n"); else { if ((len - 5) <= 8) printf("%" PRIx64, sg_get_unaligned_be(len - 5, alp + 5)); else { printf("\n"); dStrHex((const char *)(alp + 5), len - 5, 0); } } break; case 0x340: /* Medium Usage history */ bp = alp + 5; printf("\n"); if ((len - 5) < 90) { pr2serr("%s: expected 90 bytes, got %d\n", __func__, len - 5); break; } printf(" Current amount of data written [MiB]: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 0)); printf(" Current write retry count: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 6)); printf(" Current amount of data read [MiB]: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 12)); printf(" Current read retry count: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 18)); printf(" Previous amount of data written [MiB]: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 24)); printf(" Previous write retry count: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 30)); printf(" Previous amount of data read [MiB]: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 36)); printf(" Previous read retry count: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 42)); printf(" Total amount of data written [MiB]: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 48)); printf(" Total write retry count: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 54)); printf(" Total amount of data read [MiB]: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 60)); printf(" Total read retry count: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 66)); printf(" Load count: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 72)); printf(" Total change partition count: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 78)); printf(" Total partition initialization count: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 84)); break; case 0x341: /* Partition Usage history */ bp = alp + 5; printf("\n"); if ((len - 5) < 60) { pr2serr("%s: expected 60 bytes, got %d\n", __func__, len - 5); break; } printf(" Current amount of data written [MiB]: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 0)); printf(" Current write retry count: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 4)); printf(" Current amount of data read [MiB]: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 8)); printf(" Current read retry count: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 12)); printf(" Previous amount of data written [MiB]: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 16)); printf(" Previous write retry count: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 20)); printf(" Previous amount of data read [MiB]: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 24)); printf(" Previous read retry count: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 28)); printf(" Total amount of data written [MiB]: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 32)); printf(" Total write retry count: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 36)); printf(" Total amount of data read [MiB]: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 40)); printf(" Total read retry count: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 44)); printf(" Load count: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 48)); printf(" change partition count: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 52)); printf(" partition initialization count: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 56)); break; default: pr2serr("%s: unknown attribute id: 0x%x\n", __func__, id); printf(" In hex:\n"); dStrHex((const char *)alp, len, 0); break; } }
int main(int argc, char * argv[]) { int sg_fd, k, num, len, res, md_len, bd_len, longlba, page_num, spf; char ebuff[EBUFF_SZ]; const char * descp; unsigned char * rsp_buff = NULL; unsigned char def_rsp_buff[DEF_ALLOC_LEN]; unsigned char * malloc_rsp_buff = NULL; int rsp_buff_size = DEF_ALLOC_LEN; int ret = 0; int density_code_off, t_proto, inq_pdt, inq_byte6, resp_mode6; int num_ua_pages; unsigned char * ucp; unsigned char uc; struct sg_simple_inquiry_resp inq_out; char pdt_name[64]; struct opts_t opts; memset(&opts, 0, sizeof(opts)); opts.pg_code = -1; res = process_cl(&opts, argc, argv); if (res) return SG_LIB_SYNTAX_ERROR; if (opts.do_help) { usage_for(&opts); return 0; } if (opts.do_version) { fprintf(stderr, "Version string: %s\n", version_str); return 0; } if (NULL == opts.device_name) { if (opts.do_list) { if ((opts.pg_code < 0) || (opts.pg_code > PG_CODE_MAX)) { printf(" Assume peripheral device type: disk\n"); list_page_codes(0, 0, -1); } else { printf(" peripheral device type: %s\n", sg_get_pdt_str(opts.pg_code, sizeof(pdt_name), pdt_name)); if (opts.subpg_code_set) list_page_codes(opts.pg_code, 0, opts.subpg_code); else list_page_codes(opts.pg_code, 0, -1); } return 0; } fprintf(stderr, "No DEVICE argument given\n"); usage_for(&opts); return SG_LIB_SYNTAX_ERROR; } if (opts.do_examine && (opts.pg_code >= 0)) { fprintf(stderr, "can't give '-e' and a page number\n"); return SG_LIB_SYNTAX_ERROR; } if ((opts.do_six) && (opts.do_llbaa)) { fprintf(stderr, "LLBAA not defined for MODE SENSE 6, try " "without '-L'\n"); return SG_LIB_SYNTAX_ERROR; } if (opts.maxlen > 0) { if (opts.do_six && (opts.maxlen > 255)) { fprintf(stderr, "For Mode Sense (6) maxlen cannot exceed " "255\n"); return SG_LIB_SYNTAX_ERROR; } if (opts.maxlen > DEF_ALLOC_LEN) { malloc_rsp_buff = (unsigned char *)malloc(opts.maxlen); if (NULL == malloc_rsp_buff) { fprintf(stderr, "Unable to malloc maxlen=%d bytes\n", opts.maxlen); return SG_LIB_SYNTAX_ERROR; } rsp_buff = malloc_rsp_buff; } else rsp_buff = def_rsp_buff; rsp_buff_size = opts.maxlen; } else { /* maxlen == 0 */ rsp_buff_size = opts.do_six ? DEF_6_ALLOC_LEN : DEF_ALLOC_LEN; rsp_buff = def_rsp_buff; } /* If no pages or list selected than treat as 'a' */ if (! ((opts.pg_code >= 0) || opts.do_all || opts.do_list || opts.do_examine)) opts.do_all = 1; if (opts.do_raw) { if (sg_set_binary_mode(STDOUT_FILENO) < 0) { perror("sg_set_binary_mode"); return SG_LIB_FILE_ERROR; } } if ((sg_fd = sg_cmds_open_device(opts.device_name, 1 /* ro */, opts.do_verbose)) < 0) { fprintf(stderr, "error opening file: %s: %s\n", opts.device_name, safe_strerror(-sg_fd)); if (malloc_rsp_buff) free(malloc_rsp_buff); return SG_LIB_FILE_ERROR; } if (sg_simple_inquiry(sg_fd, &inq_out, 1, opts.do_verbose)) { fprintf(stderr, "%s doesn't respond to a SCSI INQUIRY\n", opts.device_name); ret = SG_LIB_CAT_OTHER; goto finish; } inq_pdt = inq_out.peripheral_type; inq_byte6 = inq_out.byte_6; if (0 == opts.do_raw) printf(" %.8s %.16s %.4s peripheral_type: %s [0x%x]\n", inq_out.vendor, inq_out.product, inq_out.revision, sg_get_pdt_str(inq_pdt, sizeof(pdt_name), pdt_name), inq_pdt); if (opts.do_list) { if (opts.subpg_code_set) list_page_codes(inq_pdt, inq_byte6, opts.subpg_code); else list_page_codes(inq_pdt, inq_byte6, -1); goto finish; } if (opts.do_examine) { ret = examine_pages(sg_fd, inq_pdt, inq_byte6, &opts); goto finish; } if (PG_CODE_ALL == opts.pg_code) { if (0 == opts.do_all) ++opts.do_all; } else if (opts.do_all) opts.pg_code = PG_CODE_ALL; if (opts.do_all > 1) opts.subpg_code = SPG_CODE_ALL; if (opts.do_raw > 1) { if (opts.do_all) { if (opts.opt_new) fprintf(stderr, "'-R' requires a specific (sub)page, not " "all\n"); else fprintf(stderr, "'-r' requires a specific (sub)page, not " "all\n"); usage_for(&opts); ret = SG_LIB_SYNTAX_ERROR; goto finish; } } memset(rsp_buff, 0, sizeof(rsp_buff)); if (opts.do_six) { res = sg_ll_mode_sense6(sg_fd, opts.do_dbd, opts.page_control, opts.pg_code, opts.subpg_code, rsp_buff, rsp_buff_size, 1, opts.do_verbose); if (SG_LIB_CAT_INVALID_OP == res) fprintf(stderr, ">>>>>> try again without the '-6' " "switch for a 10 byte MODE SENSE command\n"); } else { res = sg_ll_mode_sense10(sg_fd, opts.do_llbaa, opts.do_dbd, opts.page_control, opts.pg_code, opts.subpg_code, rsp_buff, rsp_buff_size, 1, opts.do_verbose); if (SG_LIB_CAT_INVALID_OP == res) fprintf(stderr, ">>>>>> try again with a '-6' " "switch for a 6 byte MODE SENSE command\n"); } if (SG_LIB_CAT_ILLEGAL_REQ == res) { if (opts.subpg_code > 0) fprintf(stderr, "invalid field in cdb (perhaps subpages " "not supported)\n"); else if (opts.page_control > 0) fprintf(stderr, "invalid field in cdb (perhaps " "page control (PC) not supported)\n"); else fprintf(stderr, "invalid field in cdb (perhaps " "page 0x%x not supported)\n", opts.pg_code); } else if (SG_LIB_CAT_NOT_READY == res) fprintf(stderr, "device not ready\n"); else if (SG_LIB_CAT_UNIT_ATTENTION == res) fprintf(stderr, "unit attention\n"); else if (SG_LIB_CAT_ABORTED_COMMAND == res) fprintf(stderr, "aborted command\n"); ret = res; if (0 == res) { int medium_type, specific, headerlen; ret = 0; resp_mode6 = opts.do_six; if (opts.do_flexible) { num = rsp_buff[0]; if (opts.do_six && (num < 3)) resp_mode6 = 0; if ((0 == opts.do_six) && (num > 5)) { if ((num > 11) && (0 == (num % 2)) && (0 == rsp_buff[4]) && (0 == rsp_buff[5]) && (0 == rsp_buff[6])) { rsp_buff[1] = num; rsp_buff[0] = 0; fprintf(stderr, ">>> msense(10) but resp[0]=%d and " "not msense(6) response so fix length\n", num); } else resp_mode6 = 1; } } if ((! opts.do_raw) && (1 != opts.do_hex)) { if (resp_mode6 == opts.do_six) printf("Mode parameter header from MODE SENSE(%s):\n", (opts.do_six ? "6" : "10")); else printf(" >>> Mode parameter header from MODE SENSE(%s),\n" " decoded as %s byte response:\n", (opts.do_six ? "6" : "10"), (resp_mode6 ? "6" : "10")); } if (resp_mode6) { headerlen = 4; md_len = rsp_buff[0] + 1; bd_len = rsp_buff[3]; medium_type = rsp_buff[1]; specific = rsp_buff[2]; longlba = 0; } else { headerlen = 8; md_len = (rsp_buff[0] << 8) + rsp_buff[1] + 2; bd_len = (rsp_buff[6] << 8) + rsp_buff[7]; medium_type = rsp_buff[2]; specific = rsp_buff[3]; longlba = rsp_buff[4] & 1; } if ((bd_len + headerlen) > md_len) { fprintf(stderr, "Invalid block descriptor length=%d, ignore\n", bd_len); bd_len = 0; } if (opts.do_raw) { if (1 == opts.do_raw) dStrRaw((const char *)rsp_buff, md_len); else { ucp = rsp_buff + bd_len + headerlen; md_len -= bd_len + headerlen; spf = ((ucp[0] & 0x40) ? 1 : 0); len = (spf ? ((ucp[2] << 8) + ucp[3] + 4) : (ucp[1] + 2)); len = (len < md_len) ? len : md_len; for (k = 0; k < len; ++k) printf("%02x\n", ucp[k]); } goto finish; } if (1 == opts.do_hex) { dStrHex((const char *)rsp_buff, md_len, 1); goto finish; } else if (opts.do_hex > 1) dStrHex((const char *)rsp_buff, headerlen, 1); if (0 == inq_pdt) printf(" Mode data length=%d, medium type=0x%.2x, WP=%d," " DpoFua=%d, longlba=%d\n", md_len, medium_type, !!(specific & 0x80), !!(specific & 0x10), longlba); else printf(" Mode data length=%d, medium type=0x%.2x, specific" " param=0x%.2x, longlba=%d\n", md_len, medium_type, specific, longlba); if (md_len > rsp_buff_size) { printf("Only fetched %d bytes of response, truncate output\n", rsp_buff_size); md_len = rsp_buff_size; if (bd_len + headerlen > rsp_buff_size) bd_len = rsp_buff_size - headerlen; } if (! opts.do_dbout) { printf(" Block descriptor length=%d\n", bd_len); if (bd_len > 0) { len = 8; density_code_off = 0; num = bd_len; if (longlba) { printf("> longlba direct access device block " "descriptors:\n"); len = 16; density_code_off = 8; } else if (0 == inq_pdt) { printf("> Direct access device block descriptors:\n"); density_code_off = 4; } else printf("> General mode parameter block descriptors:\n"); ucp = rsp_buff + headerlen; while (num > 0) { printf(" Density code=0x%x\n", *(ucp + density_code_off)); dStrHex((const char *)ucp, len, 1); ucp += len; num -= len; } printf("\n"); } } ucp = rsp_buff + bd_len + headerlen; /* start of mode page(s) */ md_len -= bd_len + headerlen; /* length of mode page(s) */ num_ua_pages = 0; for (k = 0; md_len > 0; ++k) { /* got mode page(s) */ if ((k > 0) && (! opts.do_all) && (SPG_CODE_ALL != opts.subpg_code)) { fprintf(stderr, "Unexpectedly received extra mode page " "responses, ignore\n"); break; } uc = *ucp; spf = ((uc & 0x40) ? 1 : 0); len = (spf ? ((ucp[2] << 8) + ucp[3] + 4) : (ucp[1] + 2)); page_num = ucp[0] & PG_CODE_MASK; if (0x0 == page_num) { ++num_ua_pages; if((num_ua_pages > 3) && (md_len > 0xa00)) { fprintf(stderr, ">>> Seen 3 unit attention pages " "(only one should be at end)\n and mpage " "length=%d, looks malformed, try '-f' option\n", md_len); break; } } if (opts.do_hex) { if (spf) printf(">> page_code=0x%x, subpage_code=0x%x, page_cont" "rol=%d\n", page_num, ucp[1], opts.page_control); else printf(">> page_code=0x%x, page_control=%d\n", page_num, opts.page_control); } else { descp = NULL; if ((0x18 == page_num) || (0x19 == page_num)) { t_proto = (spf ? ucp[5] : ucp[2]) & 0xf; descp = find_page_code_desc(page_num, (spf ? ucp[1] : 0), inq_pdt, inq_byte6, t_proto); } else descp = find_page_code_desc(page_num, (spf ? ucp[1] : 0), inq_pdt, inq_byte6, -1); if (NULL == descp) { if (spf) snprintf(ebuff, EBUFF_SZ, "0x%x, subpage_code: 0x%x", page_num, ucp[1]); else snprintf(ebuff, EBUFF_SZ, "0x%x", page_num); } if (descp) printf(">> %s, page_control: %s\n", descp, pg_control_str_arr[opts.page_control]); else printf(">> page_code: %s, page_control: %s\n", ebuff, pg_control_str_arr[opts.page_control]); } num = (len > md_len) ? md_len : len; if ((k > 0) && (num > 256)) { num = 256; fprintf(stderr, ">>> page length (%d) > 256 bytes, unlikely " "trim\n Try '-f' option\n", len); } dStrHex((const char *)ucp, num , 1); ucp += len; md_len -= len; } } finish: sg_cmds_close_device(sg_fd); if (malloc_rsp_buff) free(malloc_rsp_buff); return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; }
int main(int argc, char * argv[]) { int sg_fd, k, j, res, c, rlen, num_descs; int do_brief = 0; int do_hex = 0; int64_t ll; uint64_t lba = 0; uint64_t d_lba = 0; uint32_t d_blocks = 0; int maxlen = DEF_GLBAS_BUFF_LEN; int do_raw = 0; int o_readonly = 0; int verbose = 0; const char * device_name = NULL; const unsigned char * ucp; int ret = 0; while (1) { int option_index = 0; c = getopt_long(argc, argv, "bhHl:m:rRvV", long_options, &option_index); if (c == -1) break; switch (c) { case 'b': ++do_brief; break; case 'h': case '?': usage(); return 0; case 'H': ++do_hex; break; case 'l': ll = sg_get_llnum(optarg); if (-1 == ll) { fprintf(stderr, "bad argument to '--lba'\n"); return SG_LIB_SYNTAX_ERROR; } lba = (uint64_t)ll; break; case 'm': maxlen = sg_get_num(optarg); if ((maxlen < 0) || (maxlen > MAX_GLBAS_BUFF_LEN)) { fprintf(stderr, "argument to '--maxlen' should be %d or " "less\n", MAX_GLBAS_BUFF_LEN); return SG_LIB_SYNTAX_ERROR; } break; case 'r': ++do_raw; break; case 'R': ++o_readonly; break; case 'v': ++verbose; break; case 'V': fprintf(stderr, "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 (maxlen > DEF_GLBAS_BUFF_LEN) { glbasBuffp = (unsigned char *)calloc(maxlen, 1); if (NULL == glbasBuffp) { fprintf(stderr, "unable to allocate %d bytes on heap\n", maxlen); return SG_LIB_SYNTAX_ERROR; } } if (do_raw) { if (sg_set_binary_mode(STDOUT_FILENO) < 0) { perror("sg_set_binary_mode"); ret = SG_LIB_FILE_ERROR; goto free_buff; } } sg_fd = sg_cmds_open_device(device_name, o_readonly, verbose); if (sg_fd < 0) { fprintf(stderr, "open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); ret = SG_LIB_FILE_ERROR; goto free_buff; } res = sg_ll_get_lba_status(sg_fd, lba, glbasBuffp, maxlen, 1, verbose); ret = res; if (0 == res) { /* in sbc3r25 offset for calculating the 'parameter data length' * (rlen variable below) was reduced from 8 to 4. */ if (maxlen >= 4) rlen = (glbasBuffp[0] << 24) + (glbasBuffp[1] << 16) + (glbasBuffp[2] << 8) + glbasBuffp[3] + 4; else rlen = maxlen; k = (rlen > maxlen) ? maxlen : rlen; if (do_raw) { dStrRaw((const char *)glbasBuffp, k); goto the_end; } if (do_hex) { dStrHex((const char *)glbasBuffp, k, 1); goto the_end; } if (maxlen < 4) { if (verbose) fprintf(stderr, "Exiting because allocation length (maxlen) " " less than 4\n"); goto the_end; } if ((verbose > 1) || (verbose && (rlen > maxlen))) { fprintf(stderr, "response length %d bytes\n", rlen); if (rlen > maxlen) fprintf(stderr, " ... which is greater than maxlen " "(allocation length %d), truncation\n", maxlen); } if (rlen > maxlen) rlen = maxlen; if (do_brief > 1) { if (rlen < 24) { fprintf(stderr, "Need maxlen and response length to " " be at least 24, have %d bytes\n", rlen); ret = SG_LIB_CAT_OTHER; goto the_end; } res = decode_lba_status_desc(glbasBuffp + 8, &d_lba, &d_blocks); if ((res < 0) || (res > 15)) { fprintf(stderr, "first LBA status descriptor returned %d " "??\n", res); ret = SG_LIB_CAT_OTHER; goto the_end; } if ((lba < d_lba) || (lba >= (d_lba + d_blocks))) { fprintf(stderr, "given LBA not in range of first " "descriptor:\n" " descriptor LBA: 0x"); for (j = 0; j < 8; ++j) fprintf(stderr, "%02x", glbasBuffp[8 + j]); fprintf(stderr, " blocks: 0x%x p_status: %d\n", (unsigned int)d_blocks, res); ret = SG_LIB_CAT_OTHER; goto the_end; } printf("%d\n", res); goto the_end; } if (rlen < 24) { printf("No complete LBA status descriptors available\n"); goto the_end; } num_descs = (rlen - 8) / 16; if (verbose) fprintf(stderr, "%d complete LBA status descriptors found\n", num_descs); for (ucp = glbasBuffp + 8, k = 0; k < num_descs; ucp += 16, ++k) { res = decode_lba_status_desc(ucp, &d_lba, &d_blocks); if ((res < 0) || (res > 15)) fprintf(stderr, "descriptor %d: bad LBA status descriptor " "returned %d\n", k + 1, res); if (do_brief) { printf("0x"); for (j = 0; j < 8; ++j) printf("%02x", ucp[j]); printf(" 0x%x %d\n", (unsigned int)d_blocks, res); } else { printf("descriptor LBA: 0x"); for (j = 0; j < 8; ++j) printf("%02x", ucp[j]); printf(" blocks: %u", (unsigned int)d_blocks); switch (res) { case 0: printf(" mapped\n"); break; case 1: printf(" deallocated\n"); break; case 2: printf(" anchored\n"); break; default: printf(" Provisioning status: %d\n", res); break; } } } if ((num_descs * 16) + 8 < rlen) fprintf(stderr, "incomplete trailing LBA status descriptors " "found\n"); } else if (SG_LIB_CAT_INVALID_OP == res) fprintf(stderr, "Get LBA Status command not supported\n"); else if (SG_LIB_CAT_ILLEGAL_REQ == res) fprintf(stderr, "Get LBA Status command: bad field in cdb\n"); else { char b[80]; sg_get_category_sense_str(res, sizeof(b), b, verbose); fprintf(stderr, "Get LBA Status command: %s\n", b); } the_end: res = sg_cmds_close_device(sg_fd); if (res < 0) { fprintf(stderr, "close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = SG_LIB_FILE_ERROR; } free_buff: if (glbasBuffp && (glbasBuffp != glbasBuff)) free(glbasBuffp); return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; }
int main(int argc, char * argv[]) { int res, c, k, len, act_resplen; const char * fpass = NULL; int do_hex = 0; int do_phex = 0; int do_raw = 0; int rtype = 0; int verbose = 0; int64_t sa_ll; uint64_t sa = 0; char i_params[256]; char device_name[512]; char b[256]; unsigned char smp_req[] = {SMP_FRAME_TYPE_REQ, SMP_FN_REPORT_ZONE_MANAGER_PASS, 9, 1, 0, 0, 0, 0, 0, 0, 0, 0}; unsigned char smp_resp[SMP_FN_REPORT_ZONE_MAN_PASS_RESP_LEN]; struct smp_req_resp smp_rr; struct smp_target_obj tobj; int subvalue = 0; char * cp; FILE * foutp = stdout; int ret = 0; memset(device_name, 0, sizeof device_name); while (1) { int option_index = 0; c = getopt_long(argc, argv, "F:hHI:prR:s:vV", long_options, &option_index); if (c == -1) break; switch (c) { case 'F': fpass = optarg; break; case 'h': case '?': usage(); return 0; case 'H': ++do_hex; break; case 'I': strncpy(i_params, optarg, sizeof(i_params)); i_params[sizeof(i_params) - 1] = '\0'; break; case 'p': ++do_phex; break; case 'r': ++do_raw; break; case 'R': rtype = smp_get_num(optarg); if ((rtype < 0) || (rtype > 3)) { pr2serr("bad argument to '--report=', expect 0 to 3\n"); return SMP_LIB_SYNTAX_ERROR; } break; case 's': sa_ll = smp_get_llnum(optarg); if (-1LL == sa_ll) { pr2serr("bad argument to '--sa'\n"); return SMP_LIB_SYNTAX_ERROR; } sa = (uint64_t)sa_ll; break; case 'v': ++verbose; break; case 'V': pr2serr("version: %s\n", version_str); return 0; default: pr2serr("unrecognised switch code 0x%x ??\n", c); usage(); return SMP_LIB_SYNTAX_ERROR; } } if (optind < argc) { if ('\0' == device_name[0]) { strncpy(device_name, argv[optind], sizeof(device_name) - 1); device_name[sizeof(device_name) - 1] = '\0'; ++optind; } if (optind < argc) { for (; optind < argc; ++optind) pr2serr("Unexpected extra argument: %s\n", argv[optind]); usage(); return SMP_LIB_SYNTAX_ERROR; } } if (0 == device_name[0]) { cp = getenv("SMP_UTILS_DEVICE"); if (cp) strncpy(device_name, cp, sizeof(device_name) - 1); else { pr2serr("missing device name on command line\n [Could use " "environment variable SMP_UTILS_DEVICE instead]\n"); usage(); return SMP_LIB_SYNTAX_ERROR; } } if ((cp = strchr(device_name, SMP_SUBVALUE_SEPARATOR))) { *cp = '\0'; if (1 != sscanf(cp + 1, "%d", &subvalue)) { pr2serr("expected number after separator in SMP_DEVICE name\n"); return SMP_LIB_SYNTAX_ERROR; } } if (0 == sa) { cp = getenv("SMP_UTILS_SAS_ADDR"); if (cp) { sa_ll = smp_get_llnum(cp); if (-1LL == sa_ll) { pr2serr("bad value in environment variable " "SMP_UTILS_SAS_ADDR\n use 0\n"); sa_ll = 0; } sa = (uint64_t)sa_ll; } } if (sa > 0) { if (! smp_is_naa5(sa)) { pr2serr("SAS (target) address not in naa-5 format (may need " "leading '0x')\n"); if ('\0' == i_params[0]) { pr2serr(" use '--interface=' to override\n"); return SMP_LIB_SYNTAX_ERROR; } } } res = smp_initiator_open(device_name, subvalue, i_params, sa, &tobj, verbose); if (res < 0) return SMP_LIB_FILE_ERROR; len = (sizeof(smp_resp) - 8) / 4; smp_req[2] = (len < 0x100) ? len : 0xff; /* Allocated Response Len */ smp_req[4] = rtype & 0x3; if (verbose) { pr2serr(" Report zone manager password request: "); for (k = 0; k < (int)sizeof(smp_req); ++k) pr2serr("%02x ", smp_req[k]); pr2serr("\n"); } memset(&smp_rr, 0, sizeof(smp_rr)); smp_rr.request_len = sizeof(smp_req); smp_rr.request = smp_req; smp_rr.max_response_len = sizeof(smp_resp); smp_rr.response = smp_resp; res = smp_send_req(&tobj, &smp_rr, verbose); if (res) { pr2serr("smp_send_req failed, res=%d\n", res); if (0 == verbose) pr2serr(" try adding '-v' option for more debug\n"); ret = -1; goto err_out; } if (smp_rr.transport_err) { pr2serr("smp_send_req transport_error=%d\n", smp_rr.transport_err); ret = -1; goto err_out; } act_resplen = smp_rr.act_response_len; if ((act_resplen >= 0) && (act_resplen < 4)) { pr2serr("response too short, len=%d\n", act_resplen); ret = SMP_LIB_CAT_MALFORMED; goto err_out; } len = smp_resp[3]; if ((0 == len) && (0 == smp_resp[2])) { len = smp_get_func_def_resp_len(smp_resp[1]); if (len < 0) { len = 0; if (verbose > 0) pr2serr("unable to determine response length\n"); } } len = 4 + (len * 4); /* length in bytes, excluding 4 byte CRC */ if ((act_resplen >= 0) && (len > act_resplen)) { if (verbose) pr2serr("actual response length [%d] less than deduced length " "[%d]\n", act_resplen, len); len = act_resplen; } if (do_hex || do_raw) { if (do_hex) dStrHex((const char *)smp_resp, len, 1); else dStrRaw((const char *)smp_resp, len); if (SMP_FRAME_TYPE_RESP != smp_resp[0]) ret = SMP_LIB_CAT_MALFORMED; if (smp_resp[1] != smp_req[1]) ret = SMP_LIB_CAT_MALFORMED; if (smp_resp[2]) { ret = smp_resp[2]; if (verbose) pr2serr("Report zone manager password result: %s\n", smp_get_func_res_str(ret, sizeof(b), b)); } goto err_out; } if (SMP_FRAME_TYPE_RESP != smp_resp[0]) { pr2serr("expected SMP frame response type, got=0x%x\n", smp_resp[0]); ret = SMP_LIB_CAT_MALFORMED; goto err_out; } if (smp_resp[1] != smp_req[1]) { pr2serr("Expected function code=0x%x, got=0x%x\n", smp_req[1], smp_resp[1]); ret = SMP_LIB_CAT_MALFORMED; goto err_out; } if (smp_resp[2]) { cp = smp_get_func_res_str(smp_resp[2], sizeof(b), b); pr2serr("Report zone manager password result: %s\n", cp); ret = smp_resp[2]; goto err_out; } if (fpass) { if ((1 == strlen(fpass)) && (0 == strcmp("-", fpass))) ; /* accept "-" as synonym for stdout */ else { foutp = fopen(fpass, "w"); if (NULL == foutp) { pr2serr("unable to open %s, error: %s\n", fpass, safe_strerror(errno)); ret = SMP_LIB_FILE_ERROR; goto err_out; } } } if (fpass) { fprintf(foutp, "# Report zone manager password response:\n"); res = sg_get_unaligned_be16(smp_resp + 4); if (verbose || res) fprintf(foutp, "# Expander change count: %d\n", res); fprintf(foutp, "# Report type: %d\n", smp_resp[6] & 0x3); } if (do_phex) { for (k = 0; k < 32; ++k) { if (0 == k) fprintf(foutp, "%x", smp_resp[8 + k]); else fprintf(foutp, ",%x", smp_resp[8 + k]); } fprintf(foutp, "\n"); } else { len = strlen((const char *)(smp_resp + 8)); fprintf(foutp, "'%.*s'\n", len, smp_resp + 8); } err_out: if (foutp && (stdout != foutp)) { fclose(foutp); foutp = NULL; } res = smp_initiator_close(&tobj); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(errno)); if (0 == ret) return SMP_LIB_FILE_ERROR; } if (ret < 0) ret = SMP_LIB_CAT_OTHER; if (verbose && ret) pr2serr("Exit status %d indicates error detected\n", ret); return ret; }
static int do_cmd_sense(int sg_fd, int hex, int quiet, int verbose) { int res, resp_len, sk, asc, ascq, progress, something; unsigned char buff[32]; char b[128]; memset(buff, 0, sizeof(buff)); res = sg_ll_request_sense(sg_fd, 0 /* fixed format */, buff, sizeof(buff), 1, verbose); if (0 == res) { resp_len = buff[7] + 8; if (resp_len > (int)sizeof(buff)) resp_len = sizeof(buff); sk = (0xf & buff[2]); if (hex) { dStrHex((const char *)buff, resp_len, 1); return 0; } something = 0; if (verbose) { fprintf(stderr, "Decode response as sense data:\n"); sg_print_sense(NULL, buff, resp_len, 0); if (verbose > 1) { fprintf(stderr, "\nOutput response in hex\n"); dStrHex((const char *)buff, resp_len, 1); } something = 1; } asc = (resp_len > 12) ? buff[12] : 0; ascq = (resp_len > 13) ? buff[13] : 0; if (sg_get_sense_progress_fld(buff, resp_len, &progress)) { printf("Operation in progress, %d%% done\n", progress * 100 / 65536); something = 1; } if (0 == sk) { /* NO SENSE */ /* check for hardware threshold exceeded or warning */ if ((0xb == asc) || (0x5d == asc)) printf("%s\n", sg_get_asc_ascq_str(asc, ascq, (int)sizeof(b), b)); /* check for low power conditions */ if (0x5e == asc) printf("%s\n", sg_get_asc_ascq_str(asc, ascq, (int)sizeof(b), b)); return 0; } else { if (! (something || verbose || quiet)) { fprintf(stderr, "Decode response as sense data:\n"); sg_print_sense(NULL, buff, resp_len, 0); } return 0; } } else if (SG_LIB_CAT_INVALID_OP == res) fprintf(stderr, "Request Sense command not supported\n"); else if (SG_LIB_CAT_ILLEGAL_REQ == res) fprintf(stderr, "bad field in Request Sense cdb\n"); else if (SG_LIB_CAT_NOT_READY == res) fprintf(stderr, "Request Sense failed, device not ready\n"); else if (SG_LIB_CAT_ABORTED_COMMAND == res) fprintf(stderr, "Request Sense failed, aborted command\n"); else { fprintf(stderr, "Request Sense command failed\n"); if (0 == verbose) fprintf(stderr, " try the '-v' option for " "more information\n"); } return res; }
int main(int argc, char * argv[]) { int res, c, k, len, sas1_1, sas2, act_resplen; int do_hex = 0; int do_raw = 0; int verbose = 0; int do_zero = 0; int64_t sa_ll; uint64_t sa = 0; char i_params[256]; char device_name[512]; char b[256]; unsigned char smp_req[] = {SMP_FRAME_TYPE_REQ, SMP_FN_REPORT_MANUFACTURER, 0, 0, 0, 0, 0, 0}; unsigned char smp_resp[SMP_FN_REPORT_MANUFACTURER_RESP_LEN]; struct smp_req_resp smp_rr; struct smp_target_obj tobj; int subvalue = 0; char * cp; int ret = 0; memset(device_name, 0, sizeof device_name); while (1) { int option_index = 0; c = getopt_long(argc, argv, "hHI:p:rs:vVz", long_options, &option_index); if (c == -1) break; switch (c) { case 'h': case '?': usage(); return 0; case 'H': ++do_hex; break; case 'I': strncpy(i_params, optarg, sizeof(i_params)); i_params[sizeof(i_params) - 1] = '\0'; break; case 'r': ++do_raw; break; case 's': sa_ll = smp_get_llnum(optarg); if (-1LL == sa_ll) { pr2serr("bad argument to '--sa'\n"); return SMP_LIB_SYNTAX_ERROR; } sa = (uint64_t)sa_ll; break; case 'v': ++verbose; break; case 'V': pr2serr("version: %s\n", version_str); return 0; case 'z': ++do_zero; break; default: pr2serr("unrecognised switch code 0x%x ??\n", c); usage(); return SMP_LIB_SYNTAX_ERROR; } } if (optind < argc) { if ('\0' == device_name[0]) { strncpy(device_name, argv[optind], sizeof(device_name) - 1); device_name[sizeof(device_name) - 1] = '\0'; ++optind; } if (optind < argc) { for (; optind < argc; ++optind) pr2serr("Unexpected extra argument: %s\n", argv[optind]); usage(); return SMP_LIB_SYNTAX_ERROR; } } if (0 == device_name[0]) { cp = getenv("SMP_UTILS_DEVICE"); if (cp) strncpy(device_name, cp, sizeof(device_name) - 1); else { pr2serr("missing device name on command line\n [Could use " "environment variable SMP_UTILS_DEVICE instead]\n"); usage(); return SMP_LIB_SYNTAX_ERROR; } } if ((cp = strchr(device_name, SMP_SUBVALUE_SEPARATOR))) { *cp = '\0'; if (1 != sscanf(cp + 1, "%d", &subvalue)) { pr2serr("expected number after separator in SMP_DEVICE name\n"); return SMP_LIB_SYNTAX_ERROR; } } if (0 == sa) { cp = getenv("SMP_UTILS_SAS_ADDR"); if (cp) { sa_ll = smp_get_llnum(cp); if (-1LL == sa_ll) { pr2serr("bad value in environment variable " "SMP_UTILS_SAS_ADDR\n use 0\n"); sa_ll = 0; } sa = (uint64_t)sa_ll; } } if (sa > 0) { if (! smp_is_naa5(sa)) { pr2serr("SAS (target) address not in naa-5 format (may need " "leading '0x')\n"); if ('\0' == i_params[0]) { pr2serr(" use '--interface=' to override\n"); return SMP_LIB_SYNTAX_ERROR; } } } res = smp_initiator_open(device_name, subvalue, i_params, sa, &tobj, verbose); if (res < 0) return SMP_LIB_FILE_ERROR; if (! do_zero) { len = (sizeof(smp_resp) - 8) / 4; smp_req[2] = (len < 0x100) ? len : 0xff; } if (verbose) { pr2serr(" Report manufacturer information request: "); for (k = 0; k < (int)sizeof(smp_req); ++k) pr2serr("%02x ", smp_req[k]); pr2serr("\n"); } memset(&smp_rr, 0, sizeof(smp_rr)); smp_rr.request_len = sizeof(smp_req); smp_rr.request = smp_req; smp_rr.max_response_len = sizeof(smp_resp); smp_rr.response = smp_resp; res = smp_send_req(&tobj, &smp_rr, verbose); if (res) { pr2serr("smp_send_req failed, res=%d\n", res); if (0 == verbose) pr2serr(" try adding '-v' option for more debug\n"); ret = -1; goto err_out; } if (smp_rr.transport_err) { pr2serr("smp_send_req transport_error=%d\n", smp_rr.transport_err); ret = -1; goto err_out; } act_resplen = smp_rr.act_response_len; if ((act_resplen >= 0) && (act_resplen < 4)) { pr2serr("response too short, len=%d\n", act_resplen); ret = SMP_LIB_CAT_MALFORMED; goto err_out; } len = smp_resp[3]; if ((0 == len) && (0 == smp_resp[2])) { len = smp_get_func_def_resp_len(smp_resp[1]); if (len < 0) { len = 0; if (verbose > 0) pr2serr("unable to determine response length\n"); } } len = 4 + (len * 4); /* length in bytes, excluding 4 byte CRC */ if ((act_resplen >= 0) && (len > act_resplen)) { if (verbose) pr2serr("actual response length [%d] less than deduced length " "[%d]\n", act_resplen, len); len = act_resplen; } if (do_hex || do_raw) { if (do_hex) dStrHex((const char *)smp_resp, len, 1); else dStrRaw((const char *)smp_resp, len); if (SMP_FRAME_TYPE_RESP != smp_resp[0]) ret = SMP_LIB_CAT_MALFORMED; else if (smp_resp[1] != smp_req[1]) ret = SMP_LIB_CAT_MALFORMED; else if (smp_resp[2]) { if (verbose) pr2serr("Report manufacturer information result: %s\n", smp_get_func_res_str(smp_resp[2], sizeof(b), b)); ret = smp_resp[2]; } goto err_out; } if (SMP_FRAME_TYPE_RESP != smp_resp[0]) { pr2serr("expected SMP frame response type, got=0x%x\n", smp_resp[0]); ret = SMP_LIB_CAT_MALFORMED; goto err_out; } if (smp_resp[1] != smp_req[1]) { pr2serr("Expected function code=0x%x, got=0x%x\n", smp_req[1], smp_resp[1]); ret = SMP_LIB_CAT_MALFORMED; goto err_out; } if (smp_resp[2]) { cp = smp_get_func_res_str(smp_resp[2], sizeof(b), b); pr2serr("Report manufacturer information result: %s\n", cp); ret = smp_resp[2]; goto err_out; } sas1_1 = smp_resp[8] & 1; sas2 = !! (smp_resp[3]); printf("Report manufacturer response:\n"); if (sas2 || (verbose > 3)) { res = sg_get_unaligned_be16(smp_resp + 4); if (verbose || res) printf(" Expander change count: %d\n", res); } printf(" SAS-1.1 format: %d\n", sas1_1); printf(" vendor identification: %.8s\n", smp_resp + 12); printf(" product identification: %.16s\n", smp_resp + 20); printf(" product revision level: %.4s\n", smp_resp + 36); if (sas1_1) { if (smp_resp[40]) printf(" component vendor identification: %.8s\n", smp_resp + 40); res = sg_get_unaligned_be16(smp_resp + 48); if (res) printf(" component id: %d\n", res); if (smp_resp[50]) printf(" component revision level: %d\n", smp_resp[50]); } err_out: res = smp_initiator_close(&tobj); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(errno)); if (0 == ret) return SMP_LIB_FILE_ERROR; } if (ret < 0) ret = SMP_LIB_CAT_OTHER; if (verbose && ret) pr2serr("Exit status %d indicates error detected\n", ret); return ret; }
/* Buffer ID 0x01: Read Enclosure Status (mandatory) */ static int do_safte_encl_status(int sg_fd, int do_hex, int do_raw, int verbose) { int res, i, offset; unsigned int rb_len; unsigned char *rb_buff; rb_len = safte_cfg.fans + safte_cfg.psupplies + safte_cfg.slots + safte_cfg.temps + 5 + safte_cfg.vendor_specific; rb_buff = (unsigned char *)malloc(rb_len); if (verbose > 1) pr2serr("Use READ BUFFER,mode=vendor_specific,buff_id=1 to read " "enclosure status\n"); res = sg_ll_read_buffer(sg_fd, RWB_MODE_VENDOR, 1, 0, rb_buff, rb_len, 0, verbose); if (res && res != SG_LIB_CAT_RECOVERED) return res; if (do_raw > 1) { dStrRaw((const char *)rb_buff, buf_capacity); return 0; } if (do_hex > 1) { dStrHex((const char *)rb_buff, buf_capacity, 1); return 0; } printf("Enclosure Status:\n"); offset = 0; for (i = 0; i < safte_cfg.fans; i++) { printf("\tFan %d status: ", i); switch(rb_buff[i]) { case 0: printf("operational\n"); break; case 1: printf("malfunctioning\n"); break; case 2: printf("not installed\n"); break; case 80: printf("not reportable\n"); break; default: printf("unknown\n"); break; } } offset += safte_cfg.fans; for (i = 0; i < safte_cfg.psupplies; i++) { printf("\tPower supply %d status: ", i); switch(rb_buff[i + offset]) { case 0: printf("operational / on\n"); break; case 1: printf("operational / off\n"); break; case 0x10: printf("malfunctioning / on\n"); break; case 0x11: printf("malfunctioning / off\n"); break; case 0x20: printf("not present\n"); break; case 0x21: printf("present\n"); break; case 0x80: printf("not reportable\n"); break; default: printf("unknown\n"); break; } } offset += safte_cfg.psupplies; for (i = 0; i < safte_cfg.slots; i++) { printf("\tDevice Slot %d: SCSI ID %d\n", i, rb_buff[i + offset]); } offset += safte_cfg.slots; if (safte_cfg.flags & SAFTE_CFG_FLAG_DOORLOCK) { switch(rb_buff[offset]) { case 0x0: printf("\tDoor lock status: locked\n"); break; case 0x01: printf("\tDoor lock status: unlocked\n"); break; case 0x80: printf("\tDoor lock status: not reportable\n"); break; } } else { printf("\tDoor lock status: not installed\n"); } offset++; if (!(safte_cfg.flags & SAFTE_CFG_FLAG_ALARM)) { printf("\tSpeaker status: not installed\n"); } else { switch(rb_buff[offset]) { case 0x0: printf("\tSpeaker status: off\n"); break; case 0x01: printf("\tSpeaker status: on\n"); break; } } offset++; for (i = 0; i < safte_cfg.temps; i++) { int temp = rb_buff[i + offset]; int is_celsius = !!(safte_cfg.flags & SAFTE_CFG_FLAG_CELSIUS); if (! is_celsius) temp -= 10; printf("\tTemperature sensor %d: %d deg %c\n", i, temp, is_celsius ? 'C' : 'F'); } offset += safte_cfg.temps; if (safte_cfg.thermostats) { if (rb_buff[offset] & 0x80) { printf("\tEnclosure Temperature alert status: abnormal\n"); } else { printf("\tEnclosure Temperature alert status: normal\n"); } } return 0; }
int main(int argc, char * argv[]) { int sg_fd, k, num, rsp_len, res, rsp_buff_size, pg; int read_in_len = 0; int ret = 0; struct opts_t opts; struct opts_t * op; unsigned char * rsp_buff = NULL; const char * cp; unsigned char * read_in = NULL; op = &opts; memset(op, 0, sizeof(opts)); op->maxlen = DEF_ALLOC_LEN; op->page_code = -1; res = process_cl(op, argc, argv); if (res) return SG_LIB_SYNTAX_ERROR; if (op->do_help) { if (op->opt_new) usage(); else usage_old(); return 0; } if (op->do_version) { fprintf(stderr, "Version string: %s\n", version_str); return 0; } rsp_buff_size = op->maxlen; if (NULL == op->device_name) { if (op->do_list) { list_page_codes(); return 0; } fprintf(stderr, "No DEVICE argument given\n"); if (op->opt_new) usage(); else usage_old(); return SG_LIB_SYNTAX_ERROR; } if (op->do_raw) { read_in = (unsigned char *)calloc(op->maxlen, 1); if (NULL == read_in) { fprintf(stderr, "unable to allocate %d bytes\n", op->maxlen); return SG_LIB_CAT_OTHER; } if (build_diag_page(op->raw_arg, read_in, &read_in_len, op->maxlen)) { if (op->opt_new) { printf("Bad sequence after '--raw=' option\n"); usage(); } else { printf("Bad sequence after '-raw=' option\n"); usage_old(); } return SG_LIB_SYNTAX_ERROR; } } if ((op->do_doff || op->do_uoff) && (! op->do_deftest)) { if (op->opt_new) { printf("setting --doff or --uoff only useful when -t is set\n"); usage(); } else { printf("setting -doff or -uoff only useful when -t is set\n"); usage_old(); } return SG_LIB_SYNTAX_ERROR; } if ((op->do_selftest > 0) && op->do_deftest) { if (op->opt_new) { printf("either set --selftest=SF or --test (not both)\n"); usage(); } else { printf("either set -s=SF or -t (not both)\n"); usage_old(); } return SG_LIB_SYNTAX_ERROR; } if (op->do_raw) { if ((op->do_selftest > 0) || op->do_deftest || op->do_extdur || op->do_list) { if (op->opt_new) { printf("'--raw=' cannot be used with self-tests, '-e' or " "'-l'\n"); usage(); } else { printf("'-raw=' cannot be used with self-tests, '-e' or " "'-l'\n"); usage_old(); } return SG_LIB_SYNTAX_ERROR; } if (! op->do_pf) { if (op->opt_new) printf(">>> warning, '--pf' probably should be used with " "'--raw='\n"); else printf(">>> warning, '-pf' probably should be used with " "'-raw='\n"); } } #ifdef SG_LIB_WIN32 #ifdef SG_LIB_WIN32_DIRECT if (op->do_verbose > 4) fprintf(stderr, "Initial win32 SPT interface state: %s\n", scsi_pt_win32_spt_state() ? "direct" : "indirect"); if (op->maxlen >= 16384) scsi_pt_win32_direct(SG_LIB_WIN32_DIRECT /* SPT pt interface */); #endif #endif if ((sg_fd = sg_cmds_open_device(op->device_name, 0 /* rw */, op->do_verbose)) < 0) { fprintf(stderr, ME "error opening file: %s: %s\n", op->device_name, safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } rsp_buff = (unsigned char *)calloc(op->maxlen, 1); if (NULL == rsp_buff) { fprintf(stderr, "unable to allocate %d bytes (2)\n", op->maxlen); return SG_LIB_CAT_OTHER; } if (op->do_extdur) { res = do_modes_0a(sg_fd, rsp_buff, 32, 1, 0, op->do_verbose); if (0 == res) { /* Assume mode sense(10) response without block descriptors */ num = sg_get_unaligned_be16(rsp_buff) - 6; if (num >= 0xc) { int secs; secs = sg_get_unaligned_be16(rsp_buff + 18); #ifdef SG_LIB_MINGW printf("Expected extended self-test duration=%d seconds " "(%g minutes)\n", secs, secs / 60.0); #else printf("Expected extended self-test duration=%d seconds " "(%.2f minutes)\n", secs, secs / 60.0); #endif } else printf("Extended self-test duration not available\n"); } else { ret = res; printf("Extended self-test duration (mode page 0xa) failed\n"); goto err_out9; } } else if ((op->do_list) || (op->page_code >= 0x0)) { pg = op->page_code; if (pg < 0) res = do_senddiag(sg_fd, 0, 1 /* pf */, 0, 0, 0, rsp_buff, 4, 1, op->do_verbose); else res = 0; if (0 == res) { if (0 == sg_ll_receive_diag(sg_fd, (pg >= 0x0), ((pg >= 0x0) ? pg : 0), rsp_buff, rsp_buff_size, 1, op->do_verbose)) { rsp_len = sg_get_unaligned_be16(rsp_buff + 2) + 4; if (op->do_hex > 1) dStrHex((const char *)rsp_buff, rsp_len, (2 == op->do_hex) ? 0 : -1); else if (pg < 0x1) { printf("Supported diagnostic pages response:\n"); if (op->do_hex) dStrHex((const char *)rsp_buff, rsp_len, 1); else { for (k = 0; k < (rsp_len - 4); ++k) { cp = find_page_code_desc(rsp_buff[k + 4]); printf(" 0x%02x %s\n", rsp_buff[k + 4], (cp ? cp : "<unknown>")); } } } else { cp = find_page_code_desc(pg); if (cp) printf("%s diagnostic page [0x%x] response in " "hex:\n", cp, pg); else printf("diagnostic page 0x%x response in hex:\n", pg); dStrHex((const char *)rsp_buff, rsp_len, 1); } } else { ret = res; fprintf(stderr, "RECEIVE DIAGNOSTIC RESULTS command " "failed\n"); goto err_out9; } } else { ret = res; goto err_out; } } else if (op->do_raw) { res = do_senddiag(sg_fd, 0, op->do_pf, 0, 0, 0, read_in, read_in_len, 1, op->do_verbose); if (res) { ret = res; goto err_out; } } else { res = do_senddiag(sg_fd, op->do_selftest, op->do_pf, op->do_deftest, op->do_doff, op->do_uoff, NULL, 0, 1, op->do_verbose); if (0 == res) { if ((5 == op->do_selftest) || (6 == op->do_selftest)) printf("Foreground self-test returned GOOD status\n"); else if (op->do_deftest && (! op->do_doff) && (! op->do_uoff)) printf("Default self-test returned GOOD status\n"); } else { ret = res; goto err_out; } } res = sg_cmds_close_device(sg_fd); if ((res < 0) && (0 == ret)) return SG_LIB_SYNTAX_ERROR; return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; err_out: if (SG_LIB_CAT_UNIT_ATTENTION == res) fprintf(stderr, "SEND DIAGNOSTIC, unit attention\n"); else if (SG_LIB_CAT_ABORTED_COMMAND == res) fprintf(stderr, "SEND DIAGNOSTIC, aborted command\n"); else if (SG_LIB_CAT_NOT_READY == res) fprintf(stderr, "SEND DIAGNOSTIC, device not " "ready\n"); else fprintf(stderr, "SEND DIAGNOSTIC command, failed\n"); err_out9: if (op->do_verbose < 2) fprintf(stderr, " try again with '-vv' for more information\n"); res = sg_cmds_close_device(sg_fd); if ((res < 0) && (0 == ret)) return SG_LIB_FILE_ERROR; if (read_in) free(read_in); if (rsp_buff) free(rsp_buff); return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; }
int main(int argc, char * argv[]) { int res, c, k, len, act_resplen; int expected_cc = 0; int do_hex = 0; int do_min = 0; int do_max = 0; int op_val = 0; int sas_pa = 0; int sas_sl = 0; int sata_pa = 0; int sata_sl = 0; int pptv = -1; int phy_id = 0; int pwrdis = 0; int do_raw = 0; int verbose = 0; int64_t sa_ll; uint64_t sa = 0; uint64_t adn = 0; char i_params[256]; char device_name[512]; char b[256]; unsigned char smp_req[] = {SMP_FRAME_TYPE_REQ, SMP_FN_PHY_CONTROL, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; unsigned char smp_resp[8]; struct smp_req_resp smp_rr; struct smp_target_obj tobj; struct smp_val_name * vnp; int subvalue = 0; char * cp; int ret = 0; memset(device_name, 0, sizeof device_name); while (1) { int option_index = 0; c = getopt_long(argc, argv, "a:D:E:hHI:l:L:m:M:o:p:P:q:Q;rs:vV", long_options, &option_index); if (c == -1) break; switch (c) { case 'a': sa_ll = smp_get_llnum(optarg); if (-1LL == sa_ll) { pr2serr("bad argument to '--attached'\n"); return SMP_LIB_SYNTAX_ERROR; } adn = (uint64_t)sa_ll; break; case 'D': pwrdis = smp_get_num(optarg); if ((pwrdis < 0) || (pwrdis > 3)) { pr2serr("bad argument to '--pwrdis'\n"); return SMP_LIB_SYNTAX_ERROR; } break; case 'E': expected_cc = smp_get_num(optarg); if ((expected_cc < 0) || (expected_cc > 65535)) { pr2serr("bad argument to '--expected'\n"); return SMP_LIB_SYNTAX_ERROR; } break; case 'h': case '?': usage(); return 0; case 'H': ++do_hex; break; case 'I': strncpy(i_params, optarg, sizeof(i_params)); i_params[sizeof(i_params) - 1] = '\0'; break; case 'm': do_min = smp_get_num(optarg); switch (do_min) { case 0: case 8: case 9: case 10: case 11: case 12: break; default: pr2serr("bad argument to '--min', want 0, 8, 9, 10, 11 or " "12\n"); return SMP_LIB_SYNTAX_ERROR; } break; case 'M': do_max = smp_get_num(optarg); switch (do_max) { case 0: case 8: case 9: case 10: case 11: case 12: break; default: pr2serr("bad argument to '--max', want 0, 8, 9, 10, 11 or " "12\n"); return SMP_LIB_SYNTAX_ERROR; } break; case 'l': sas_sl = smp_get_num(optarg); if ((sas_sl < 0) || (sas_sl > 3)) { pr2serr("bad argument to '--sas_sl'\n"); return SMP_LIB_SYNTAX_ERROR; } break; case 'L': sata_sl = smp_get_num(optarg); if ((sata_sl < 0) || (sata_sl > 3)) { pr2serr("bad argument to '--sata_sl'\n"); return SMP_LIB_SYNTAX_ERROR; } break; case 'o': if (isalpha(optarg[0])) { for (vnp = op_abbrev; vnp->name; ++vnp) { if (0 == strncmp(optarg, vnp->name, 2)) break; } if (vnp->name) op_val = vnp->value; else { pr2serr("bad argument to '--op'\n"); list_op_abbrevs(); return SMP_LIB_SYNTAX_ERROR; } } else { op_val = smp_get_num(optarg); if ((op_val < 0) || (op_val > 255)) { pr2serr("bad numeric argument to '--op'\n"); return SMP_LIB_SYNTAX_ERROR; } } break; case 'p': phy_id = smp_get_num(optarg); if ((phy_id < 0) || (phy_id > 254)) { pr2serr("bad argument to '--phy', expect value from 0 to " "254\n"); return SMP_LIB_SYNTAX_ERROR; } break; case 'P': pptv = smp_get_num(optarg); if ((pptv < 0) || (pptv > 15)) { pr2serr("bad argument to '--pptv', want value from 0 to 15 " "inclusive\n"); return SMP_LIB_SYNTAX_ERROR; } break; case 'q': sas_pa = smp_get_num(optarg); if ((sas_pa < 0) || (sas_pa > 3)) { pr2serr("bad argument to '--sas_pa'\n"); return SMP_LIB_SYNTAX_ERROR; } break; case 'Q': sata_pa = smp_get_num(optarg); if ((sata_pa < 0) || (sata_pa > 3)) { pr2serr("bad argument to '--sata_pa'\n"); return SMP_LIB_SYNTAX_ERROR; } break; case 'r': ++do_raw; break; case 's': sa_ll = smp_get_llnum(optarg); if (-1LL == sa_ll) { pr2serr("bad argument to '--sa'\n"); return SMP_LIB_SYNTAX_ERROR; } sa = (uint64_t)sa_ll; break; case 'v': ++verbose; break; case 'V': pr2serr("version: %s\n", version_str); return 0; default: pr2serr("unrecognised switch code 0x%x ??\n", c); usage(); return SMP_LIB_SYNTAX_ERROR; } } if (optind < argc) { if ('\0' == device_name[0]) { strncpy(device_name, argv[optind], sizeof(device_name) - 1); device_name[sizeof(device_name) - 1] = '\0'; ++optind; } if (optind < argc) { for (; optind < argc; ++optind) pr2serr("Unexpected extra argument: %s\n", argv[optind]); usage(); return SMP_LIB_SYNTAX_ERROR; } } if (0 == device_name[0]) { cp = getenv("SMP_UTILS_DEVICE"); if (cp) strncpy(device_name, cp, sizeof(device_name) - 1); else { pr2serr("missing device name on command line\n [Could use " "environment variable SMP_UTILS_DEVICE instead]\n"); usage(); return SMP_LIB_SYNTAX_ERROR; } } if ((cp = strchr(device_name, SMP_SUBVALUE_SEPARATOR))) { *cp = '\0'; if (1 != sscanf(cp + 1, "%d", &subvalue)) { pr2serr("expected number after separator in SMP_DEVICE name\n"); return SMP_LIB_SYNTAX_ERROR; } } if (0 == sa) { cp = getenv("SMP_UTILS_SAS_ADDR"); if (cp) { sa_ll = smp_get_llnum(cp); if (-1LL == sa_ll) { pr2serr("bad value in environment variable " "SMP_UTILS_SAS_ADDR\n use 0\n"); sa_ll = 0; } sa = (uint64_t)sa_ll; } } if (sa > 0) { if (! smp_is_naa5(sa)) { pr2serr("SAS (target) address not in naa-5 format (may need " "leading '0x')\n"); if ('\0' == i_params[0]) { pr2serr(" use '--interface=' to override\n"); return SMP_LIB_SYNTAX_ERROR; } } } res = smp_initiator_open(device_name, subvalue, i_params, sa, &tobj, verbose); if (res < 0) return SMP_LIB_FILE_ERROR; sg_put_unaligned_be16(expected_cc, smp_req + 4); smp_req[9] = phy_id; smp_req[10] = op_val; if (pptv >= 0) { smp_req[11] |= 1; smp_req[36] |= (pptv & 0xf); } if (adn) sg_put_unaligned_be64(adn, smp_req + 24); smp_req[32] |= (do_min << 4); smp_req[33] |= (do_max << 4); smp_req[34] = (sas_sl << 6) | (sas_pa << 4) | (sata_sl << 2) | sata_pa; smp_req[35] = (pwrdis << 6); /* added spl3r3 */ if (verbose) { pr2serr(" Phy control request: "); for (k = 0; k < (int)sizeof(smp_req); ++k) { if (0 == (k % 16)) pr2serr("\n "); else if (0 == (k % 8)) pr2serr(" "); pr2serr("%02x ", smp_req[k]); } pr2serr("\n"); } memset(&smp_rr, 0, sizeof(smp_rr)); smp_rr.request_len = sizeof(smp_req); smp_rr.request = smp_req; smp_rr.max_response_len = sizeof(smp_resp); smp_rr.response = smp_resp; res = smp_send_req(&tobj, &smp_rr, verbose); if (res) { pr2serr("smp_send_req failed, res=%d\n", res); if (0 == verbose) pr2serr(" try adding '-v' option for more debug\n"); ret = -1; goto err_out; } if (smp_rr.transport_err) { pr2serr("smp_send_req transport_error=%d\n", smp_rr.transport_err); ret = -1; goto err_out; } act_resplen = smp_rr.act_response_len; if ((act_resplen >= 0) && (act_resplen < 4)) { pr2serr("response too short, len=%d\n", act_resplen); ret = SMP_LIB_CAT_MALFORMED; goto err_out; } len = smp_resp[3]; if ((0 == len) && (0 == smp_resp[2])) { len = smp_get_func_def_resp_len(smp_resp[1]); if (len < 0) { len = 0; if (verbose > 0) pr2serr("unable to determine response length\n"); } } len = 4 + (len * 4); /* length in bytes, excluding 4 byte CRC */ if ((act_resplen >= 0) && (len > act_resplen)) { if (verbose) pr2serr("actual response length [%d] less than deduced length " "[%d]\n", act_resplen, len); len = act_resplen; } if (do_hex || do_raw) { if (do_hex) dStrHex((const char *)smp_resp, len, 1); else dStrRaw((const char *)smp_resp, len); if (SMP_FRAME_TYPE_RESP != smp_resp[0]) ret = SMP_LIB_CAT_MALFORMED; else if (smp_resp[1] != smp_req[1]) ret = SMP_LIB_CAT_MALFORMED; else if (smp_resp[2]) { if (verbose) pr2serr("Phy control result: %s\n", smp_get_func_res_str(smp_resp[2], sizeof(b), b)); ret = smp_resp[2]; } goto err_out; } if (SMP_FRAME_TYPE_RESP != smp_resp[0]) { pr2serr("expected SMP frame response type, got=0x%x\n", smp_resp[0]); ret = SMP_LIB_CAT_MALFORMED; goto err_out; } if (smp_resp[1] != smp_req[1]) { pr2serr("Expected function code=0x%x, got=0x%x\n", smp_req[1], smp_resp[1]); ret = SMP_LIB_CAT_MALFORMED; goto err_out; } if (smp_resp[2]) { cp = smp_get_func_res_str(smp_resp[2], sizeof(b), b); pr2serr("Phy control result: %s\n", cp); ret = smp_resp[2]; goto err_out; } err_out: res = smp_initiator_close(&tobj); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(errno)); if (0 == ret) return SMP_LIB_FILE_ERROR; } if (ret < 0) ret = SMP_LIB_CAT_OTHER; if (verbose && ret) pr2serr("Exit status %d indicates error detected\n", ret); return ret; }
int main(int argc, char * argv[]) { int sg_fd, k, num, rsp_len, res; unsigned char rsp_buff[MX_ALLOC_LEN]; int rsp_buff_size = MX_ALLOC_LEN; int read_in_len = 0; const char * cp; unsigned char read_in[MX_ALLOC_LEN]; int ret = 0; struct opts_t opts; memset(&opts, 0, sizeof(opts)); res = process_cl(&opts, argc, argv); if (res) return SG_LIB_SYNTAX_ERROR; if (opts.do_help) { if (opts.opt_new) usage(); else usage_old(); return 0; } if (opts.do_version) { fprintf(stderr, "Version string: %s\n", version_str); return 0; } if (NULL == opts.device_name) { fprintf(stderr, "No DEVICE argument given\n"); if (opts.opt_new) usage(); else usage_old(); return SG_LIB_SYNTAX_ERROR; } if (opts.do_raw) { if (build_diag_page(opts.raw_arg, read_in, &read_in_len, sizeof(read_in))) { if (opts.opt_new) { printf("Bad sequence after '--raw=' option\n"); usage(); } else { printf("Bad sequence after '-raw=' option\n"); usage_old(); } return SG_LIB_SYNTAX_ERROR; } } if ((opts.do_doff || opts.do_uoff) && (! opts.do_deftest)) { if (opts.opt_new) { printf("setting --doff or --uoff only useful when -t is set\n"); usage(); } else { printf("setting -doff or -uoff only useful when -t is set\n"); usage_old(); } return SG_LIB_SYNTAX_ERROR; } if ((opts.do_selftest > 0) && opts.do_deftest) { if (opts.opt_new) { printf("either set --selftest=SF or --test (not both)\n"); usage(); } else { printf("either set -s=SF or -t (not both)\n"); usage_old(); } return SG_LIB_SYNTAX_ERROR; } if (opts.do_raw) { if ((opts.do_selftest > 0) || opts.do_deftest || opts.do_extdur || opts.do_list) { if (opts.opt_new) { printf("'--raw=' cannot be used with self-tests, '-e' or " "'-l'\n"); usage(); } else { printf("'-raw=' cannot be used with self-tests, '-e' or " "'-l'\n"); usage_old(); } return SG_LIB_SYNTAX_ERROR; } if (! opts.do_pf) { if (opts.opt_new) printf(">>> warning, '--pf' probably should be used with " "'--raw='\n"); else printf(">>> warning, '-pf' probably should be used with " "'-raw='\n"); } } if (NULL == opts.device_name) { if (opts.do_list) { list_page_codes(); return 0; } fprintf(stderr, "No DEVICE argument given\n"); if (opts.opt_new) usage(); else usage_old(); return SG_LIB_SYNTAX_ERROR; } if ((sg_fd = sg_cmds_open_device(opts.device_name, 0 /* rw */, opts.do_verbose)) < 0) { fprintf(stderr, ME "error opening file: %s: %s\n", opts.device_name, safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } if (opts.do_extdur) { res = do_modes_0a(sg_fd, rsp_buff, 32, 1, 0, opts.do_verbose); if (0 == res) { /* Assume mode sense(10) response without block descriptors */ num = (rsp_buff[0] << 8) + rsp_buff[1] - 6; if (num >= 0xc) { int secs; secs = (rsp_buff[18] << 8) + rsp_buff[19]; #ifdef SG_LIB_MINGW printf("Expected extended self-test duration=%d seconds " "(%g minutes)\n", secs, secs / 60.0); #else printf("Expected extended self-test duration=%d seconds " "(%.2f minutes)\n", secs, secs / 60.0); #endif } else printf("Extended self-test duration not available\n"); } else { ret = res; printf("Extended self-test duration (mode page 0xa) failed\n"); goto err_out9; } } else if (opts.do_list) { memset(rsp_buff, 0, sizeof(rsp_buff)); res = do_senddiag(sg_fd, 0, 1 /* pf */, 0, 0, 0, rsp_buff, 4, 1, opts.do_verbose); if (0 == res) { if (0 == sg_ll_receive_diag(sg_fd, 0, 0, rsp_buff, rsp_buff_size, 1, opts.do_verbose)) { printf("Supported diagnostic pages response:\n"); rsp_len = (rsp_buff[2] << 8) + rsp_buff[3] + 4; if (opts.do_hex) dStrHex((const char *)rsp_buff, rsp_len, 1); else { for (k = 0; k < (rsp_len - 4); ++k) { cp = find_page_code_desc(rsp_buff[k + 4]); printf(" 0x%02x %s\n", rsp_buff[k + 4], (cp ? cp : "<unknown>")); } } } else { ret = res; fprintf(stderr, "RECEIVE DIAGNOSTIC RESULTS command " "failed\n"); goto err_out9; } } else { ret = res; goto err_out; } } else if (opts.do_raw) { res = do_senddiag(sg_fd, 0, opts.do_pf, 0, 0, 0, read_in, read_in_len, 1, opts.do_verbose); if (res) { ret = res; goto err_out; } } else { res = do_senddiag(sg_fd, opts.do_selftest, opts.do_pf, opts.do_deftest, opts.do_doff, opts.do_uoff, NULL, 0, 1, opts.do_verbose); if (0 == res) { if ((5 == opts.do_selftest) || (6 == opts.do_selftest)) printf("Foreground self-test returned GOOD status\n"); else if (opts.do_deftest && (! opts.do_doff) && (! opts.do_uoff)) printf("Default self-test returned GOOD status\n"); } else { ret = res; goto err_out; } } res = sg_cmds_close_device(sg_fd); if ((res < 0) && (0 == ret)) return SG_LIB_SYNTAX_ERROR; return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; err_out: if (SG_LIB_CAT_UNIT_ATTENTION == res) fprintf(stderr, "SEND DIAGNOSTIC, unit attention\n"); else if (SG_LIB_CAT_ABORTED_COMMAND == res) fprintf(stderr, "SEND DIAGNOSTIC, aborted command\n"); else if (SG_LIB_CAT_NOT_READY == res) fprintf(stderr, "SEND DIAGNOSTIC, device not " "ready\n"); else fprintf(stderr, "SEND DIAGNOSTIC command, failed\n"); err_out9: if (opts.do_verbose < 2) fprintf(stderr, " try again with '-vv' for more information\n"); res = sg_cmds_close_device(sg_fd); if ((res < 0) && (0 == ret)) return SG_LIB_FILE_ERROR; return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; }
int main(int argc, char * argv[]) { int sg_fd, c, ret, peri_type, no_hex_raw; int res = SG_LIB_CAT_OTHER; const char * device_name = NULL; char ebuff[EBUFF_SZ]; unsigned char *rb_buff; int do_config = 0; int do_status = 0; int do_slots = 0; int do_flags = 0; int do_usage = 0; int do_hex = 0; int do_raw = 0; int verbose = 0; int do_insertions = 0; const char * cp; char buff[48]; char b[80]; struct sg_simple_inquiry_resp inq_resp; const char op_name[] = "READ BUFFER"; while (1) { int option_index = 0; c = getopt_long(argc, argv, "cdfhHirsuvV?", long_options, &option_index); if (c == -1) break; switch (c) { case 'c': do_config = 1; break; case 'd': do_slots = 1; break; case 'f': do_flags = 1; break; case 'h': case '?': usage(); return 0; case 'H': ++do_hex; break; case 'i': do_insertions = 1; break; case 'r': ++do_raw; break; case 's': do_status = 1; break; case 'u': do_usage = 1; break; case 'v': ++verbose; break; case 'V': pr2serr("Version string: %s\n", version_str); exit(0); default: pr2serr("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) pr2serr("Unexpected extra argument: %s\n", argv[optind]); usage(); return SG_LIB_SYNTAX_ERROR; } } if (NULL == device_name) { pr2serr("missing device name!\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (do_raw) { if (sg_set_binary_mode(STDOUT_FILENO) < 0) { perror("sg_set_binary_mode"); return SG_LIB_FILE_ERROR; } } if ((sg_fd = sg_cmds_open_device(device_name, 0 /* rw */, verbose)) < 0) { snprintf(ebuff, EBUFF_SZ, "sg_safte: error opening file: %s (rw)", device_name); perror(ebuff); return SG_LIB_FILE_ERROR; } no_hex_raw = ((0 == do_hex) && (0 == do_raw)); if (no_hex_raw) { if (0 == sg_simple_inquiry(sg_fd, &inq_resp, 1, verbose)) { printf(" %.8s %.16s %.4s\n", inq_resp.vendor, inq_resp.product, inq_resp.revision); peri_type = inq_resp.peripheral_type; cp = sg_get_pdt_str(peri_type, sizeof(buff), buff); if (strlen(cp) > 0) printf(" Peripheral device type: %s\n", cp); else printf(" Peripheral device type: 0x%x\n", peri_type); } else { pr2serr("sg_safte: %s doesn't respond to a SCSI INQUIRY\n", device_name); return SG_LIB_CAT_OTHER; } } rb_buff = (unsigned char *)malloc(buf_capacity); if (!rb_buff) goto err_out; memset(rb_buff, 0, buf_capacity); res = read_safte_configuration(sg_fd, rb_buff, buf_capacity, verbose); switch (res) { case 0: case SG_LIB_CAT_RECOVERED: break; default: goto err_out; } if (1 == do_raw) { dStrRaw((const char *)rb_buff, buf_capacity); goto finish; } if (1 == do_hex) { dStrHex((const char *)rb_buff, buf_capacity, 1); goto finish; } if (do_config && no_hex_raw) print_safte_configuration(); if (do_status) { res = do_safte_encl_status(sg_fd, do_hex, do_raw, verbose); switch (res) { case 0: case SG_LIB_CAT_RECOVERED: break; default: goto err_out; } } if (do_usage) { res = do_safte_usage_statistics(sg_fd, do_hex, do_raw, verbose); switch (res) { case 0: case SG_LIB_CAT_RECOVERED: break; default: goto err_out; } } if (do_insertions) { res = do_safte_slot_insertions(sg_fd, do_hex, do_raw, verbose); switch (res) { case 0: case SG_LIB_CAT_RECOVERED: break; default: goto err_out; } } if (do_slots) { res = do_safte_slot_status(sg_fd, do_hex, do_raw, verbose); switch (res) { case 0: case SG_LIB_CAT_RECOVERED: break; default: goto err_out; } } if (do_flags) { res = do_safte_global_flags(sg_fd, do_hex, do_raw, verbose); switch (res) { case 0: case SG_LIB_CAT_RECOVERED: break; default: goto err_out; } } finish: res = 0; err_out: switch (res) { case 0: case SG_LIB_CAT_RECOVERED: break; default: sg_get_category_sense_str(res, sizeof(b), b, verbose); pr2serr("%s failed: %s\n", op_name, b); break; } ret = res; res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) return SG_LIB_FILE_ERROR; } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; }
int main(int argc, char * argv[]) { int res, c, k, len, act_resplen; int do_disable = 0; int expected_cc = 0; int do_hex = 0; int er_ind = 0; int phy_id = 0; int do_raw = 0; int verbose = 0; int64_t sa_ll; uint64_t sa = 0; uint64_t routed = 0; char i_params[256]; char device_name[512]; char b[256]; unsigned char smp_req[] = {SMP_FRAME_TYPE_REQ, SMP_FN_CONFIG_ROUTE_INFO, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; unsigned char smp_resp[8]; struct smp_req_resp smp_rr; struct smp_target_obj tobj; int subvalue = 0; char * cp; int ret = 0; memset(device_name, 0, sizeof device_name); while (1) { int option_index = 0; c = getopt_long(argc, argv, "dE:hHi:I:p:rR:s:vV", long_options, &option_index); if (c == -1) break; switch (c) { case 'd': do_disable = 1; break; case 'E': expected_cc = smp_get_num(optarg); if ((expected_cc < 0) || (expected_cc > 65535)) { pr2serr("bad argument to '--expected'\n"); return SMP_LIB_SYNTAX_ERROR; } break; case 'h': case '?': usage(); return 0; case 'H': ++do_hex; break; case 'I': strncpy(i_params, optarg, sizeof(i_params)); i_params[sizeof(i_params) - 1] = '\0'; break; case 'i': er_ind = smp_get_num(optarg); if ((er_ind < 0) || (er_ind > 65535)) { pr2serr("bad argument to '--index'\n"); return SMP_LIB_SYNTAX_ERROR; } break; case 'p': phy_id = smp_get_num(optarg); if ((phy_id < 0) || (phy_id > 254)) { pr2serr("bad argument to '--phy', expect value from 0 to " "254\n"); return SMP_LIB_SYNTAX_ERROR; } break; case 'r': ++do_raw; break; case 'R': sa_ll = smp_get_llnum(optarg); if (-1LL == sa_ll) { pr2serr("bad argument to '--routed'\n"); return SMP_LIB_SYNTAX_ERROR; } routed = (uint64_t)sa_ll; break; case 's': sa_ll = smp_get_llnum(optarg); if (-1LL == sa_ll) { pr2serr("bad argument to '--sa'\n"); return SMP_LIB_SYNTAX_ERROR; } sa = (uint64_t)sa_ll; break; case 'v': ++verbose; break; case 'V': pr2serr("version: %s\n", version_str); return 0; default: pr2serr("unrecognised switch code 0x%x ??\n", c); usage(); return SMP_LIB_SYNTAX_ERROR; } } if (optind < argc) { if ('\0' == device_name[0]) { strncpy(device_name, argv[optind], sizeof(device_name) - 1); device_name[sizeof(device_name) - 1] = '\0'; ++optind; } if (optind < argc) { for (; optind < argc; ++optind) pr2serr("Unexpected extra argument: %s\n", argv[optind]); usage(); return SMP_LIB_SYNTAX_ERROR; } } if (0 == device_name[0]) { cp = getenv("SMP_UTILS_DEVICE"); if (cp) strncpy(device_name, cp, sizeof(device_name) - 1); else { pr2serr("missing device name on command line\n [Could use " "environment variable SMP_UTILS_DEVICE instead]\n"); usage(); return SMP_LIB_SYNTAX_ERROR; } } if ((cp = strchr(device_name, SMP_SUBVALUE_SEPARATOR))) { *cp = '\0'; if (1 != sscanf(cp + 1, "%d", &subvalue)) { pr2serr("expected number after separator in SMP_DEVICE name\n"); return SMP_LIB_SYNTAX_ERROR; } } if (0 == sa) { cp = getenv("SMP_UTILS_SAS_ADDR"); if (cp) { sa_ll = smp_get_llnum(cp); if (-1LL == sa_ll) { pr2serr("bad value in environment variable " "SMP_UTILS_SAS_ADDR\n use 0\n"); sa_ll = 0; } sa = (uint64_t)sa_ll; } } if (sa > 0) { if (! smp_is_naa5(sa)) { pr2serr("SAS (target) address not in naa-5 format (may need " "leading '0x')\n"); if ('\0' == i_params[0]) { pr2serr(" use '--interface=' to override\n"); return SMP_LIB_SYNTAX_ERROR; } } } if (routed) { if (! smp_is_naa5(routed)) { pr2serr("routed SAS address not in naa-5 format\n"); if ('\0' == i_params[0]) { pr2serr(" use any '--interface=' to continue\n"); return SMP_LIB_SYNTAX_ERROR; } } } res = smp_initiator_open(device_name, subvalue, i_params, sa, &tobj, verbose); if (res < 0) return SMP_LIB_FILE_ERROR; sg_put_unaligned_be16(expected_cc, smp_req + 4); sg_put_unaligned_be16(er_ind, smp_req + 6); smp_req[9] = phy_id; if (do_disable) smp_req[12] |= 0x80; if (routed) { sg_put_unaligned_be64(routed, smp_req + 16); } if (verbose) { pr2serr(" Configure route information request: "); for (k = 0; k < (int)sizeof(smp_req); ++k) { if (0 == (k % 16)) pr2serr("\n "); else if (0 == (k % 8)) pr2serr(" "); pr2serr("%02x ", smp_req[k]); } pr2serr("\n"); } memset(&smp_rr, 0, sizeof(smp_rr)); smp_rr.request_len = sizeof(smp_req); smp_rr.request = smp_req; smp_rr.max_response_len = sizeof(smp_resp); smp_rr.response = smp_resp; res = smp_send_req(&tobj, &smp_rr, verbose); if (res) { pr2serr("smp_send_req failed, res=%d\n", res); if (0 == verbose) pr2serr(" try adding '-v' option for more debug\n"); ret = -1; goto err_out; } if (smp_rr.transport_err) { pr2serr("smp_send_req transport_error=%d\n", smp_rr.transport_err); ret = -1; goto err_out; } act_resplen = smp_rr.act_response_len; if ((act_resplen >= 0) && (act_resplen < 4)) { pr2serr("response too short, len=%d\n", act_resplen); ret = SMP_LIB_CAT_MALFORMED; goto err_out; } len = smp_resp[3]; if ((0 == len) && (0 == smp_resp[2])) { len = smp_get_func_def_resp_len(smp_resp[1]); if (len < 0) { len = 0; if (verbose > 0) pr2serr("unable to determine response length\n"); } } len = 4 + (len * 4); /* length in bytes, excluding 4 byte CRC */ if ((act_resplen >= 0) && (len > act_resplen)) { if (verbose) pr2serr("actual response length [%d] less than deduced length " "[%d]\n", act_resplen, len); len = act_resplen; } if (do_hex || do_raw) { if (do_hex) dStrHex((const char *)smp_resp, len, 1); else dStrRaw((const char *)smp_resp, len); if (SMP_FRAME_TYPE_RESP != smp_resp[0]) ret = SMP_LIB_CAT_MALFORMED; else if (smp_resp[1] != smp_req[1]) ret = SMP_LIB_CAT_MALFORMED; else if (smp_resp[2]) { if (verbose) pr2serr("Configure route information result: %s\n", smp_get_func_res_str(smp_resp[2], sizeof(b), b)); ret = smp_resp[2]; } goto err_out; } if (SMP_FRAME_TYPE_RESP != smp_resp[0]) { pr2serr("expected SMP frame response type, got=0x%x\n", smp_resp[0]); ret = SMP_LIB_CAT_MALFORMED; goto err_out; } if (smp_resp[1] != smp_req[1]) { pr2serr("Expected function code=0x%x, got=0x%x\n", smp_req[1], smp_resp[1]); ret = SMP_LIB_CAT_MALFORMED; goto err_out; } if (smp_resp[2]) { cp = smp_get_func_res_str(smp_resp[2], sizeof(b), b); pr2serr("Configure route information result: %s\n", cp); ret = smp_resp[2]; goto err_out; } err_out: res = smp_initiator_close(&tobj); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(errno)); if (0 == ret) return SMP_LIB_FILE_ERROR; } if (ret < 0) ret = SMP_LIB_CAT_OTHER; if (verbose && ret) pr2serr("Exit status %d indicates error detected\n", ret); return ret; }