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; }
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; }
int main(int argc, char * argv[]) { bool do_long = false; bool o_readonly = false; bool do_raw = false; bool verbose_given = false; bool version_given = false; int res, c, len, k; int sg_fd = -1; int do_help = 0; int do_hex = 0; int rb_id = 0; int rb_len = 4; int rb_mode = 0; int rb_mode_sp = 0; int resid = 0; int verbose = 0; int ret = 0; int64_t ll; uint64_t rb_offset = 0; const char * device_name = NULL; uint8_t * 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)) { pr2serr("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) { pr2serr("bad argument to '--length'\n"); return SG_LIB_SYNTAX_ERROR; } if (rb_len > 0xffffff) { pr2serr("argument to '--length' must be <= 0xffffff\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'L': do_long = true; break; case 'm': if (isdigit(*optarg)) { rb_mode = sg_get_num(optarg); if ((rb_mode < 0) || (rb_mode > 31)) { pr2serr("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->mode_string) { print_modes(); return SG_LIB_SYNTAX_ERROR; } } break; case 'o': ll = sg_get_llnum(optarg); if (ll < 0) { pr2serr("bad argument to '--offset'\n"); return SG_LIB_SYNTAX_ERROR; } rb_offset = ll; break; case 'r': do_raw = true; break; case 'R': o_readonly = true; break; case 'S': rb_mode_sp = sg_get_num(optarg); if ((rb_mode_sp < 0) || (rb_mode_sp > 7)) { pr2serr("expected argument to '--specific' to be 0 to 7\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'v': verbose_given = true; ++verbose; break; case 'V': version_given = true; break; default: pr2serr("unrecognised option code 0x%x ??\n", c); usage(); return SG_LIB_SYNTAX_ERROR; } } if (do_help) { if (do_help > 1) { usage(); pr2serr("\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) pr2serr("Unexpected extra argument: %s\n", argv[optind]); usage(); return SG_LIB_SYNTAX_ERROR; } } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (verbose_given && version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); verbose_given = false; version_given = false; verbose = 0; } else if (! verbose_given) { pr2serr("set '-vv'\n"); verbose = 2; } else pr2serr("keep verbose=%d\n", verbose); #else if (verbose_given && version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (version_given) { pr2serr("version: %s\n", version_str); return 0; } if (NULL == device_name) { pr2serr("Missing device name!\n\n"); usage(); return SG_LIB_SYNTAX_ERROR; } len = rb_len ? rb_len : 8; resp = (uint8_t *)malloc(len); if (NULL == resp) { pr2serr("unable to allocate %d bytes on the heap\n", len); return SG_LIB_CAT_OTHER; } memset(resp, 0, len); 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) pr2serr("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) { if (verbose) pr2serr("open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); goto fini; } if (do_long) res = sg_ll_read_buffer_16(sg_fd, rb_mode, rb_mode_sp, rb_id, rb_offset, resp, rb_len, &resid, true, verbose); else if (rb_offset > 0xffffff) { pr2serr("--offset value is too large for READ BUFFER(10), try " "--16\n"); ret = SG_LIB_SYNTAX_ERROR; goto fini; } else res = sg_ll_read_buffer_10(sg_fd, rb_mode, rb_mode_sp, rb_id, (uint32_t)rb_offset, resp, rb_len, &resid, true, verbose); if (0 != res) { char b[80]; ret = res; if (res > 0) { sg_get_category_sense_str(res, sizeof(b), b, verbose); pr2serr("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(resp, rb_len); else if (do_hex || (rb_len < 4)) hex2stdout((const uint8_t *)resp, rb_len, ((do_hex > 1) ? 0 : 1)); else { switch (rb_mode) { case MODE_DESCRIPTOR: k = sg_get_unaligned_be24(resp + 1); 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 = sg_get_unaligned_be16(resp + 2) & 0x1fff; printf("EBOS:%d\n", resp[0] & 1 ? 1 : 0); printf("Echo buffer capacity: %d (0x%x)\n", k, k); break; default: hex2stdout((const uint8_t *)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) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = sg_convert_errno(-res); } } if (0 == verbose) { if (! sg_if_can2stderr("sg_read_buffer failed: ", ret)) pr2serr("Some error occurred, try again with '-v' " "or '-vv' for more information\n"); } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; }
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; }
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, 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, res, c, len, resid, rlen, in_len; unsigned int ra_len; int ret = 0; const char * device_name = NULL; const char * fname = NULL; unsigned char * rabp = NULL; struct opts_t opts; struct opts_t * op; char b[80]; op = &opts; memset(op, 0, sizeof(opts)); op->filter = -1; while (1) { int option_index = 0; c = getopt_long(argc, argv, "ceE:f:F:hHi:l:m:p:qrRs:vV", long_options, &option_index); if (c == -1) break; switch (c) { case 'c': ++op->cache; break; case 'e': ++op->enumerate; break; case 'E': op->ea = sg_get_num(optarg); if ((op->ea < 0) || (op->ea > 65535)) { pr2serr("bad argument to '--ea=EA', expect 0 to 65535\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'f': op->filter = sg_get_num(optarg); if ((op->filter < -3) || (op->filter > 65535)) { pr2serr("bad argument to '--filter=FL', expect -3 to " "65535\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'F': op->fai = sg_get_num(optarg); if ((op->fai < 0) || (op->fai > 65535)) { pr2serr("bad argument to '--first=FAI', expect 0 to 65535\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'h': case '?': usage(); return 0; case 'H': ++op->do_hex; break; case 'i': fname = optarg; break; case 'l': op->lvn = sg_get_num(optarg); if ((op->lvn < 0) || (op->lvn > 255)) { pr2serr("bad argument to '--lvn=LVN', expect 0 to 255\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'm': op->maxlen = sg_get_num(optarg); if ((op->maxlen < 0) || (op->maxlen > MAX_RATTR_BUFF_LEN)) { pr2serr("argument to '--maxlen' should be %d or " "less\n", MAX_RATTR_BUFF_LEN); return SG_LIB_SYNTAX_ERROR; } break; case 'p': op->pn = sg_get_num(optarg); if ((op->pn < 0) || (op->pn > 255)) { pr2serr("bad argument to '--pn=PN', expect 0 to 255\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'q': ++op->quiet; break; case 'r': ++op->do_raw; break; case 'R': ++op->o_readonly; break; case 's': if (isdigit(*optarg)) { op->sa = sg_get_num(optarg); if ((op->sa < 0) || (op->sa > 63)) { pr2serr("bad argument to '--sa=SA', expect 0 to 63\n"); return SG_LIB_SYNTAX_ERROR; } } else { res = find_sa_acron(optarg); if (res < 0) { enum_sa_acrons(); return SG_LIB_SYNTAX_ERROR; } op->sa = res; } break; case 'v': ++op->verbose; break; case 'V': pr2serr("version: %s\n", version_str); return 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 (op->enumerate) { enum_attributes(); printf("\n"); enum_sa_acrons(); return 0; } if (fname && device_name) { pr2serr("since '--in=FN' given, ignoring DEVICE\n"); device_name = NULL; } if (0 == op->maxlen) op->maxlen = DEF_RATTR_BUFF_LEN; rabp = (unsigned char *)calloc(1, op->maxlen); if (NULL == rabp) { pr2serr("unable to calloc %d bytes\n", op->maxlen); return SG_LIB_CAT_OTHER; } if (NULL == device_name) { if (fname) { if (f2hex_arr(fname, op->do_raw, 0, rabp, &in_len, op->maxlen)) { ret = SG_LIB_FILE_ERROR; goto clean_up; } if (op->do_raw) op->do_raw = 0; /* can interfere on decode */ if (in_len < 4) { pr2serr("--in=%s only decoded %d bytes (needs 4 at least)\n", fname, in_len); ret = SG_LIB_SYNTAX_ERROR; goto clean_up; } decode_all_sa_s(rabp, in_len, op); goto clean_up; } pr2serr("missing device name!\n"); usage(); ret = SG_LIB_SYNTAX_ERROR; goto clean_up; } if (op->do_raw) { if (sg_set_binary_mode(STDOUT_FILENO) < 0) { perror("sg_set_binary_mode"); ret = SG_LIB_FILE_ERROR; goto clean_up; } } sg_fd = sg_cmds_open_device(device_name, op->o_readonly, op->verbose); if (sg_fd < 0) { pr2serr("open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); ret = SG_LIB_FILE_ERROR; goto clean_up; } res = sg_ll_read_attr(sg_fd, rabp, &resid, op); ret = res; if (0 == res) { rlen = op->maxlen - resid; if (rlen < 4) { pr2serr("Response length (%d) too short\n", rlen); ret = SG_LIB_CAT_MALFORMED; goto close_then_end; } if ((op->sa <= RA_HIGHEST_SA) && (op->sa != RA_SMC2_SA)) { ra_len = ((RA_LV_LIST_SA == op->sa) || (RA_PART_LIST_SA == op->sa)) ? (unsigned int)sg_get_unaligned_be16(rabp + 0) : sg_get_unaligned_be32(rabp + 0) + 2; ra_len += 2; } else ra_len = rlen; if ((int)ra_len > rlen) { if (op->verbose) pr2serr("ra_len available is %d, response length is %d\n", ra_len, rlen); len = rlen; } else len = (int)ra_len; if (op->do_raw) { dStrRaw((const char *)rabp, len); goto close_then_end; } decode_all_sa_s(rabp, len, op); } else if (SG_LIB_CAT_INVALID_OP == res) pr2serr("Read attribute command not supported\n"); else { sg_get_category_sense_str(res, sizeof(b), b, op->verbose); pr2serr("Read attribute command: %s\n", b); } close_then_end: res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = SG_LIB_FILE_ERROR; } clean_up: if (rabp) free(rabp); return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; }
int main(int argc, char * argv[]) { bool do_one_segment = false; bool o_readonly = false; bool do_raw = false; bool verbose_given = false; bool version_given = false; int k, res, c, rlen; int sg_fd = -1; int do_hex = 0; int maxlen = DEF_REFER_BUFF_LEN; int verbose = 0; int desc = 0; int ret = 0; int64_t ll; uint64_t lba = 0; const char * device_name = NULL; const uint8_t * bp; uint8_t * referralBuffp = referralBuff; uint8_t * free_referralBuffp = NULL; while (1) { int option_index = 0; c = getopt_long(argc, argv, "hHl:m:rRsvV", long_options, &option_index); if (c == -1) break; switch (c) { case 'h': case '?': usage(); return 0; case 'H': ++do_hex; break; case 'l': ll = sg_get_llnum(optarg); if (-1 == ll) { pr2serr("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_REFER_BUFF_LEN)) { pr2serr("argument to '--maxlen' should be %d or less\n", MAX_REFER_BUFF_LEN); return SG_LIB_SYNTAX_ERROR; } break; case 's': do_one_segment = true; break; case 'r': do_raw = true; break; case 'R': o_readonly = true; break; case 'v': verbose_given = true; ++verbose; break; case 'V': version_given = true; break; 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; } } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (verbose_given && version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); verbose_given = false; version_given = false; verbose = 0; } else if (! verbose_given) { pr2serr("set '-vv'\n"); verbose = 2; } else pr2serr("keep verbose=%d\n", verbose); #else if (verbose_given && version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (version_given) { pr2serr("version: %s\n", version_str); return 0; } if (NULL == device_name) { pr2serr("No DEVICE argument given\n\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (maxlen > DEF_REFER_BUFF_LEN) { referralBuffp = (uint8_t *)sg_memalign(maxlen, 0, &free_referralBuffp, verbose > 3); if (NULL == referralBuffp) { pr2serr("unable to allocate %d bytes on heap\n", maxlen); return sg_convert_errno(ENOMEM); } } 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) { if (verbose) pr2serr("open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); goto free_buff; } res = sg_ll_report_referrals(sg_fd, lba, do_one_segment, referralBuffp, maxlen, true, verbose); ret = res; if (0 == res) { if (maxlen >= 4) /* * This is strictly speaking incorrect. However, the * spec reserved bytes 0 and 1, so some implementations * might want to use them to increase the number of * possible user segments. * And maybe someone takes a pity and updates the spec ... */ rlen = sg_get_unaligned_be32(referralBuffp + 0) + 4; else rlen = maxlen; k = (rlen > maxlen) ? maxlen : rlen; if (do_raw) { dStrRaw(referralBuffp, k); goto the_end; } if (do_hex) { hex2stdout(referralBuffp, k, 1); goto the_end; } if (maxlen < 4) { if (verbose) pr2serr("Exiting because allocation length (maxlen) less " "than 4\n"); goto the_end; } if ((verbose > 1) || (verbose && (rlen > maxlen))) { pr2serr("response length %d bytes\n", rlen); if (rlen > maxlen) pr2serr(" ... which is greater than maxlen (allocation " "length %d), truncation\n", maxlen); } if (rlen > maxlen) rlen = maxlen; bp = referralBuffp + 4; k = 0; printf("Report referrals:\n"); while (k < rlen - 4) { printf(" descriptor %d:\n", desc); res = decode_referral_desc(bp + k, rlen - 4 - k); if (res < 0) { pr2serr("bad user data segment referral descriptor\n"); break; } k += res; desc++; } } else { char b[80]; sg_get_category_sense_str(res, sizeof(b), b, verbose); pr2serr("Report Referrals command failed: %s\n", b); } the_end: res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = sg_convert_errno(-res); } free_buff: if (free_referralBuffp) free(free_referralBuffp); if (0 == verbose) { if (! sg_if_can2stderr("sg_referrals failed: ", ret)) pr2serr("Some error occurred, try again with '-v' " "or '-vv' for more information\n"); } 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; }
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[]) { bool do_raw = false; bool readonly = false; bool verbose_given = false; bool version_given = false; int sg_fd, k, m, res, c; int do_hex = 0; int verbose = 0; int ret = 0; uint32_t max_block_size; uint16_t min_block_size; const char * device_name = NULL; while (1) { int option_index = 0; c = getopt_long(argc, argv, "hHrRvV", long_options, &option_index); if (c == -1) break; switch (c) { case 'h': case '?': usage(); return 0; case 'H': ++do_hex; break; case 'r': do_raw = true; break; case 'R': readonly = true; break; case 'v': verbose_given = true; ++verbose; break; case 'V': version_given = true; break; default: pr2serr("invalid option -%c ??\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; } } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (verbose_given && version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); verbose_given = false; version_given = false; verbose = 0; } else if (! verbose_given) { pr2serr("set '-vv'\n"); verbose = 2; } else pr2serr("keep verbose=%d\n", verbose); #else if (verbose_given && version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (version_given) { pr2serr("version: %s\n", version_str); return 0; } if (NULL == device_name) { pr2serr("missing device name!\n"); usage(); return SG_LIB_SYNTAX_ERROR; } sg_fd = sg_cmds_open_device(device_name, readonly, verbose); if (sg_fd < 0) { if (verbose) pr2serr("open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); goto the_end2; } memset(readBlkLmtBuff, 0x0, 6); res = sg_ll_read_block_limits(sg_fd, readBlkLmtBuff, 6, true, verbose); ret = res; if (0 == res) { if (do_hex) { hex2stdout(readBlkLmtBuff, sizeof(readBlkLmtBuff), 1); goto the_end; } else if (do_raw) { dStrRaw((const char *)readBlkLmtBuff, sizeof(readBlkLmtBuff)); goto the_end; } max_block_size = sg_get_unaligned_be32(readBlkLmtBuff + 0); min_block_size = sg_get_unaligned_be16(readBlkLmtBuff + 4); k = min_block_size / 1024; pr2serr("Read Block Limits results:\n"); pr2serr("\tMinimum block size: %u byte(s)", (unsigned int)min_block_size); if (k != 0) pr2serr(", %d KB", k); pr2serr("\n"); k = max_block_size / 1024; m = max_block_size / 1048576; pr2serr("\tMaximum block size: %u byte(s)", (unsigned int)max_block_size); if (k != 0) pr2serr(", %d KB", k); if (m != 0) pr2serr(", %d MB", m); pr2serr("\n"); } else { char b[80]; sg_get_category_sense_str(res, sizeof(b), b, verbose); pr2serr("Read block limits: %s\n", b); if (0 == verbose) pr2serr(" try '-v' option for more information\n"); } the_end: res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = sg_convert_errno(-res); } the_end2: if (0 == verbose) { if (! sg_if_can2stderr("sg_read_block_limits failed: ", ret)) pr2serr("Some error occurred, try again with '-v' or '-vv' for " "more information\n"); } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; }
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; }
static int do_identify_dev(int sg_fd, bool do_packet, int cdb_len, bool ck_cond, bool extend, bool do_ident, int do_hex, bool do_raw, int verbose) { bool t_type = false;/* false -> 512 byte blocks, true -> device's LB size */ bool t_dir = true; /* false -> to device, true -> from device */ bool byte_block = true; /* false -> bytes, true -> 512 byte blocks (if t_type=false) */ bool got_ard = false; /* got ATA result descriptor */ bool got_fixsense = false; /* got ATA result in fixed format sense */ bool ok; int j, res, ret, sb_sz; /* Following for ATA READ/WRITE MULTIPLE (EXT) cmds, normally 0 */ int multiple_count = 0; int protocol = 4; /* PIO data-in */ int t_length = 2; /* 0 -> no data transferred, 2 -> sector count */ int resid = 0; uint64_t ull; struct sg_scsi_sense_hdr ssh; uint8_t inBuff[ID_RESPONSE_LEN]; uint8_t sense_buffer[64]; uint8_t ata_return_desc[16]; uint8_t 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}; uint8_t apt12_cdb[SAT_ATA_PASS_THROUGH12_LEN] = {SAT_ATA_PASS_THROUGH12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t apt32_cdb[SAT_ATA_PASS_THROUGH32_LEN]; const unsigned short * usp; sb_sz = sizeof(sense_buffer); memset(sense_buffer, 0, sb_sz); memset(apt32_cdb, 0, sizeof(apt32_cdb)); memset(ata_return_desc, 0, sizeof(ata_return_desc)); ok = false; switch (cdb_len) { case SAT_ATA_PASS_THROUGH32_LEN: /* SAT-4 revision 5 or later */ /* Prepare SCSI ATA PASS-THROUGH COMMAND(32) command */ sg_put_unaligned_be16(1, apt32_cdb + 22); /* count=1 */ apt32_cdb[25] = (do_packet ? ATA_IDENTIFY_PACKET_DEVICE : ATA_IDENTIFY_DEVICE); apt32_cdb[10] = (multiple_count << 5) | (protocol << 1); if (extend) apt32_cdb[10] |= 0x1; apt32_cdb[11] = t_length; if (ck_cond) apt32_cdb[11] |= 0x20; if (t_type) apt32_cdb[11] |= 0x10; if (t_dir) apt32_cdb[11] |= 0x8; if (byte_block) apt32_cdb[11] |= 0x4; /* following call takes care of all bytes below offset 10 in cdb */ res = sg_ll_ata_pt(sg_fd, apt32_cdb, cdb_len, DEF_TIMEOUT, inBuff, NULL /* doutp */, ID_RESPONSE_LEN, sense_buffer, sb_sz, ata_return_desc, sizeof(ata_return_desc), &resid, verbose); break; case SAT_ATA_PASS_THROUGH16_LEN: /* Prepare SCSI ATA PASS-THROUGH COMMAND(16) command */ apt_cdb[6] = 1; /* sector count */ apt_cdb[14] = (do_packet ? ATA_IDENTIFY_PACKET_DEVICE : ATA_IDENTIFY_DEVICE); apt_cdb[1] = (multiple_count << 5) | (protocol << 1); if (extend) apt_cdb[1] |= 0x1; apt_cdb[2] = t_length; if (ck_cond) apt_cdb[2] |= 0x20; if (t_type) apt_cdb[2] |= 0x10; if (t_dir) apt_cdb[2] |= 0x8; if (byte_block) apt_cdb[2] |= 0x4; res = sg_ll_ata_pt(sg_fd, apt_cdb, cdb_len, DEF_TIMEOUT, inBuff, NULL /* doutp */, ID_RESPONSE_LEN, sense_buffer, sb_sz, ata_return_desc, sizeof(ata_return_desc), &resid, verbose); break; case SAT_ATA_PASS_THROUGH12_LEN: /* Prepare SCSI ATA PASS-THROUGH COMMAND(12) command */ apt12_cdb[4] = 1; /* sector count */ apt12_cdb[9] = (do_packet ? ATA_IDENTIFY_PACKET_DEVICE : ATA_IDENTIFY_DEVICE); apt12_cdb[1] = (multiple_count << 5) | (protocol << 1); apt12_cdb[2] = t_length; if (ck_cond) apt12_cdb[2] |= 0x20; if (t_type) apt12_cdb[2] |= 0x10; if (t_dir) apt12_cdb[2] |= 0x8; if (byte_block) apt12_cdb[2] |= 0x4; res = sg_ll_ata_pt(sg_fd, apt12_cdb, cdb_len, DEF_TIMEOUT, inBuff, NULL /* doutp */, ID_RESPONSE_LEN, sense_buffer, sb_sz, ata_return_desc, sizeof(ata_return_desc), &resid, verbose); break; default: pr2serr("%s: bad cdb_len=%d\n", __func__, cdb_len); return -1; } if (0 == res) { ok = true; 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 = true; break; } else if (0x70 == ssh.response_code) { got_fixsense = true; 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]) && (! 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 = true; } 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 = true; } if (ok) { /* output result if it is available */ if (do_raw) dStrRaw(inBuff, 512); else if (0 == do_hex) { if (do_ident) { 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) hex2stdout(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 */ hex2stdout(inBuff, 512, -1); } return 0; }
/* 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 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; }
int main(int argc, char * argv[]) { int sg_fd, res, c; int do_origin = 0; int do_set = 0; int do_srep = 0; int do_raw = 0; int readonly = 0; bool secs_given = false; int verbose = 0; uint64_t secs = 0; uint64_t msecs = 0; int64_t ll; const char * device_name = NULL; const char * cmd_name; int ret = 0; while (1) { int option_index = 0; c = getopt_long(argc, argv, "hm:orRs:SvV", long_options, &option_index); if (c == -1) break; switch (c) { case 'h': case '?': usage(); return 0; case 'm': ll = sg_get_llnum(optarg); if (-1 == ll) { pr2serr("bad argument to '--milliseconds=MS'\n"); return SG_LIB_SYNTAX_ERROR; } msecs = (uint64_t)ll; ++do_set; break; case 'o': ++do_origin; break; case 'r': ++do_raw; break; case 'R': ++readonly; break; case 's': ll = sg_get_llnum(optarg); if (-1 == ll) { pr2serr("bad argument to '--seconds=SEC'\n"); return SG_LIB_SYNTAX_ERROR; } secs = (uint64_t)ll; ++do_set; secs_given = true; break; case 'S': ++do_srep; break; case 'v': ++verbose; break; case 'V': pr2serr("version: %s\n", version_str); return 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 (do_set > 1) { pr2serr("either --milliseconds=MS or --seconds=SEC may be given, " "not both\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (NULL == device_name) { pr2serr("missing device name!\n"); usage(); return SG_LIB_SYNTAX_ERROR; } sg_fd = sg_cmds_open_device(device_name, readonly, verbose); if (sg_fd < 0) { pr2serr("open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } memset(d_buff, 0, 12); if (do_set) { cmd_name = "Set timestamp"; sg_put_unaligned_be48(secs_given ? (secs * 1000) : msecs, d_buff + 4); res = sg_ll_set_timestamp(sg_fd, d_buff, 12, 1, verbose); } else { cmd_name = "Report timestamp"; res = sg_ll_rep_timestamp(sg_fd, d_buff, 12, NULL, 1, verbose); if (0 == res) { if (do_raw) dStrRaw((const char *)d_buff, 12); else { int len = sg_get_unaligned_be16(d_buff + 0); if (len < 8) pr2serr("timestamp parameter data length too short, " "expect >= 10, got %d\n", len + 2); else { if (do_origin) printf("Device clock %s\n", ts_origin_arr[0x7 & d_buff[2]]); msecs = sg_get_unaligned_be48(d_buff + 4); printf("%" PRIu64 "\n", do_srep ? (msecs / 1000) : msecs); } } } } ret = res; if (res) { if (SG_LIB_CAT_INVALID_OP == res) pr2serr("%s command not supported\n", cmd_name); else { char b[80]; sg_get_category_sense_str(res, sizeof(b), b, verbose); pr2serr("%s command: %s\n", cmd_name, b); } } 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 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, 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; }