/* MODE SENSE commands yield a response that has header then zero or more * block descriptors followed by mode pages. In most cases users are * interested in the first mode page. This function returns the (byte) * offset of the start of the first mode page. Set mode_sense_6 to true for * MODE SENSE (6) and false for MODE SENSE (10). Returns >= 0 is successful * or -1 if failure. If there is a failure a message is written to err_buff * if it is non-NULL and err_buff_len > 0. */ int sg_mode_page_offset(const uint8_t * resp, int resp_len, bool mode_sense_6, char * err_buff, int err_buff_len) { int bd_len, calc_len, offset; bool err_buff_ok = ((err_buff_len > 0) && err_buff); if ((NULL == resp) || (resp_len < 4)) goto too_short; if (mode_sense_6) { calc_len = resp[0] + 1; bd_len = resp[3]; offset = bd_len + MODE6_RESP_HDR_LEN; } else { /* Mode sense(10) */ if (resp_len < 8) goto too_short; calc_len = sg_get_unaligned_be16(resp) + 2; bd_len = sg_get_unaligned_be16(resp + 6); /* LongLBA doesn't change this calculation */ offset = bd_len + MODE10_RESP_HDR_LEN; } if ((offset + 2) > calc_len) { if (err_buff_ok) snprintf(err_buff, err_buff_len, "calculated response " "length too small, offset=%d calc_len=%d bd_len=%d\n", offset, calc_len, bd_len); offset = -1; } return offset; too_short: if (err_buff_ok) snprintf(err_buff, err_buff_len, "given MS(%d) response length (%d) " "too short\n", (mode_sense_6 ? 6 : 10), resp_len); return -1; }
/* MODE SENSE commands yield a response that has header then zero or more * block descriptors followed by mode pages. This functions returns the * length (in bytes) of those three components. Note that the return value * can exceed resp_len in which case the MODE SENSE command should be * re-issued with a larger response buffer. If bd_lenp is non-NULL and if * successful the block descriptor length (in bytes) is written to *bd_lenp. * Set mode_sense_6 to true for MODE SENSE (6) and false for MODE SENSE (10) * responses. Returns -1 if there is an error (e.g. response too short). */ int sg_msense_calc_length(const uint8_t * resp, int resp_len, bool mode_sense_6, int * bd_lenp) { int calc_len; if (NULL == resp) goto an_err; if (mode_sense_6) { if (resp_len < 4) goto an_err; calc_len = resp[0] + 1; } else { if (resp_len < 8) goto an_err; calc_len = sg_get_unaligned_be16(resp + 0) + 2; } if (bd_lenp) *bd_lenp = mode_sense_6 ? resp[3] : sg_get_unaligned_be16(resp + 6); return calc_len; an_err: if (bd_lenp) *bd_lenp = 0; return -1; }
/* Decodes given user data referral segment descriptor * the number of blocks and returns the number of bytes processed, * -1 for error. */ static int decode_referral_desc(const uint8_t * bp, int bytes) { int j, n; uint64_t first, last; if (NULL == bp) return -1; if (bytes < 20) return -1; first = sg_get_unaligned_be64(bp + 4); last = sg_get_unaligned_be64(bp + 12); printf(" target port descriptors: %d\n", bp[3]); printf(" user data segment: first lba %" PRIu64 ", last lba %" PRIu64 "\n", first, last); n = 20; bytes -= n; for (j = 0; j < bp[3]; j++) { if (bytes < 4) return -1; printf(" target port descriptor %d:\n", j); printf(" port group %x state (%s)\n", sg_get_unaligned_be16(bp + n + 2), decode_tpgs_state(bp[n] & 0xf)); n += 4; bytes -= 4; } return n; }
/* MODE SENSE commands yield a response that has block descriptors followed * by mode pages. In most cases users are interested in the first mode page. * This function returns the (byte) offset of the start of the first mode * page. Set mode_sense_6 to 1 for MODE SENSE (6) and 0 for MODE SENSE (10). * Returns >= 0 is successful or -1 if failure. If there is a failure * a message is written to err_buff if err_buff_len > 0. */ int sg_mode_page_offset(const unsigned char * resp, int resp_len, int mode_sense_6, char * err_buff, int err_buff_len) { int bd_len, calc_len, offset; if ((NULL == resp) || (resp_len < 4) || ((! mode_sense_6) && (resp_len < 8))) { if ((err_buff_len > 0) && err_buff) snprintf(err_buff, err_buff_len, "given response length too " "short: %d\n", resp_len); return -1; } if (mode_sense_6) { calc_len = resp[0] + 1; bd_len = resp[3]; offset = bd_len + MODE6_RESP_HDR_LEN; } else { calc_len = sg_get_unaligned_be16(resp) + 2; bd_len = sg_get_unaligned_be16(resp + 6); /* LongLBA doesn't change this calculation */ offset = bd_len + MODE10_RESP_HDR_LEN; } if ((offset + 2) > resp_len) { if ((err_buff_len > 0) && err_buff) snprintf(err_buff, err_buff_len, "given response length " "too small, offset=%d given_len=%d bd_len=%d\n", offset, resp_len, bd_len); offset = -1; } else if ((offset + 2) > calc_len) { if ((err_buff_len > 0) && err_buff) snprintf(err_buff, err_buff_len, "calculated response " "length too small, offset=%d calc_len=%d bd_len=%d\n", offset, calc_len, bd_len); offset = -1; } return offset; }
/* Buffer ID 0x03: Read Device Insertions (optional) */ static int do_safte_slot_insertions(int sg_fd, int do_hex, int do_raw, int verbose) { int res, i; unsigned int rb_len; unsigned char *rb_buff, slot_status; rb_len = safte_cfg.slots * 2; rb_buff = (unsigned char *)malloc(rb_len); if (verbose > 1) pr2serr("Use READ BUFFER,mode=vendor_specific,buff_id=3 to read " "device insertions\n"); res = sg_ll_read_buffer(sg_fd, RWB_MODE_VENDOR, 3, 0, rb_buff, rb_len, 0, verbose); if (res ) { if (res == SG_LIB_CAT_ILLEGAL_REQ) { printf("Slot insertions:\n\tNot implemented\n"); return 0; } if (res != SG_LIB_CAT_RECOVERED) { free(rb_buff); return res; } } if (do_raw > 1) { dStrRaw((const char *)rb_buff, buf_capacity); return 0; } if (do_hex > 1) { dStrHex((const char *)rb_buff, buf_capacity, 1); return 0; } printf("Slot insertions:\n"); for (i = 0; i < safte_cfg.slots; i++) { slot_status = sg_get_unaligned_be16(rb_buff + (i * 2)); printf("\tSlot %d: %d insertions", i, slot_status); } free(rb_buff); return 0; }
static void decode_attr_list(const unsigned char * alp, int len, bool supported, const struct opts_t * op) { int id; char b[160]; char * cp; char * c2p; const char * leadin = supported ? "Supported a" : "A"; if (op->verbose) printf("%sttribute list: [len=%d]\n", leadin, len); else if (0 == op->quiet) printf("%sttribute list:\n", leadin); if (op->do_hex) { dStrHex((const char *)alp, len, 0); return; } for ( ; len > 0; alp += 2, len -= 2) { id = sg_get_unaligned_be16(alp + 0); if ((op->filter >= 0) && (op->filter != id)) continue; if (op->verbose) printf(" 0x%.4x:\t", id); cp = attr_id_lookup(id, NULL, sizeof(b), b); c2p = strchr(cp, '\t'); if (c2p) { printf(" %.*s -\n", (int)(c2p - cp), cp); if (op->verbose) printf("\t\t %s\n", c2p + 1); else printf(" %s\n", c2p + 1); } else printf(" %s\n", cp); } }
int main(int argc, char * argv[]) { int 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; 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, 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[]) { 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; }
static int send_then_receive(int sg_fd, uint32_t gen_code, int off_off, const uint8_t * dmp, int dmp_len, struct dout_buff_t * wp, uint8_t * dip, int din_len, bool last, const struct opts_t * op) { bool send_data = false; int do_len, rem, res, rsp_len, k, n, num, mc_status, resid, act_len, verb; int ret = 0; uint32_t rec_gen_code; const uint8_t * bp; const char * cp; verb = (op->verbose > 1) ? op->verbose - 1 : 0; switch (op->mc_mode) { case MODE_DNLD_MC_OFFS: case MODE_DNLD_MC_OFFS_SAVE: case MODE_DNLD_MC_OFFS_DEFER: send_data = true; do_len = 24 + dmp_len; rem = do_len % 4; if (rem) do_len += (4 - rem); break; case MODE_ACTIVATE_MC: case MODE_ABORT_MC: do_len = 24; break; default: pr2serr("%s: unexpected mc_mode=0x%x\n", __func__, op->mc_mode); return SG_LIB_SYNTAX_ERROR; } if (do_len > wp->dout_len) { if (wp->doutp) free(wp->doutp); wp->doutp = sg_memalign(do_len, 0, &wp->free_doutp, op->verbose > 3); if (! wp->doutp) { pr2serr("%s: unable to alloc %d bytes\n", __func__, do_len); return SG_LIB_CAT_OTHER; } wp->dout_len = do_len; } else memset(wp->doutp, 0, do_len); wp->doutp[0] = DPC_DOWNLOAD_MICROCODE; wp->doutp[1] = op->mc_subenc; sg_put_unaligned_be16(do_len - 4, wp->doutp + 2); sg_put_unaligned_be32(gen_code, wp->doutp + 4); wp->doutp[8] = op->mc_mode; wp->doutp[11] = op->mc_id; if (send_data) sg_put_unaligned_be32(op->mc_offset + off_off, wp->doutp + 12); sg_put_unaligned_be32(op->mc_tlen, wp->doutp + 16); sg_put_unaligned_be32(dmp_len, wp->doutp + 20); if (send_data && (dmp_len > 0)) memcpy(wp->doutp + 24, dmp, dmp_len); if ((op->verbose > 2) || (op->dry_run && op->verbose)) { pr2serr("send diag: sub-enc id=%u exp_gen=%u download_mc_code=%u " "buff_id=%u\n", op->mc_subenc, gen_code, op->mc_mode, op->mc_id); pr2serr(" buff_off=%u image_len=%u this_mc_data_len=%u " "dout_len=%u\n", op->mc_offset + off_off, op->mc_tlen, dmp_len, do_len); } /* select long duration timeout (7200 seconds) */ if (op->dry_run) { if (op->mc_subenc < 4) { int s = op->mc_offset + off_off + dmp_len; n = 8 + (op->mc_subenc * 16); dummy_rd_resp[n + 11] = op->mc_id; sg_put_unaligned_be32(((send_data && (! last)) ? s : 0), dummy_rd_resp + n + 12); if (MODE_ABORT_MC == op->mc_mode) dummy_rd_resp[n + 2] = 0x80; else if (MODE_ACTIVATE_MC == op->mc_mode) dummy_rd_resp[n + 2] = 0x0; /* done */ else dummy_rd_resp[n + 2] = (s >= op->mc_tlen) ? 0x13 : 0x1; } res = 0; } else res = sg_ll_send_diag(sg_fd, 0 /* st_code */, true /* pf */, false /* st */, false /* devofl */, false /* unitofl */, 1 /* long_duration */, wp->doutp, do_len, true /* noisy */, verb); if (op->mc_non) { /* If non-standard, only call RDR after failed SD */ if (0 == res) return 0; /* If RDR error after SD error, prefer reporting SD error */ ret = res; } else { switch (op->mc_mode) { case MODE_DNLD_MC_OFFS: case MODE_DNLD_MC_OFFS_SAVE: if (res) return res; else if (last) { if (op->ealsd) return 0; /* RDR after last may hit a device reset */ } break; case MODE_DNLD_MC_OFFS_DEFER: if (res) return res; break; case MODE_ACTIVATE_MC: case MODE_ABORT_MC: if (0 == res) { if (op->ealsd) return 0; /* RDR after this may hit a device reset */ } /* SD has failed, so do a RDR but return SD's error */ ret = res; break; default: pr2serr("%s: mc_mode=0x%x\n", __func__, op->mc_mode); return SG_LIB_SYNTAX_ERROR; } } if (op->dry_run) { n = sizeof(dummy_rd_resp); n = (n < din_len) ? n : din_len; memcpy(dip, dummy_rd_resp, n); resid = din_len - n; res = 0; } else res = sg_ll_receive_diag_v2(sg_fd, true /* pcv */, DPC_DOWNLOAD_MICROCODE, dip, din_len, 0 /* default timeout */, &resid, true, verb); if (res) return ret ? ret : res; rsp_len = sg_get_unaligned_be16(dip + 2) + 4; act_len = din_len - resid; if (rsp_len > din_len) { pr2serr("<<< warning response buffer too small [%d but need " "%d]>>>\n", din_len, rsp_len); rsp_len = din_len; } if (rsp_len > act_len) { pr2serr("<<< warning response too short [actually got %d but need " "%d]>>>\n", act_len, rsp_len); rsp_len = act_len; } if (rsp_len < 8) { pr2serr("Download microcode status dpage too short [%d]\n", rsp_len); return ret ? ret : SG_LIB_CAT_OTHER; } rec_gen_code = sg_get_unaligned_be32(dip + 4); if ((op->verbose > 2) || (op->dry_run && op->verbose)) { n = 8 + (op->mc_subenc * 16); pr2serr("rec diag: rsp_len=%d, num_sub-enc=%u rec_gen_code=%u " "exp_buff_off=%u\n", rsp_len, dip[1], sg_get_unaligned_be32(dip + 4), sg_get_unaligned_be32(dip + n + 12)); } if (rec_gen_code != gen_code) pr2serr("gen_code changed from %" PRIu32 " to %" PRIu32 ", continuing but may fail\n", gen_code, rec_gen_code); num = (rsp_len - 8) / 16; if ((rsp_len - 8) % 16) pr2serr("Found %d Download microcode status descriptors, but there " "is residual\n", num); bp = dip + 8; for (k = 0; k < num; ++k, bp += 16) { if ((unsigned int)op->mc_subenc == (unsigned int)bp[1]) { mc_status = bp[2]; cp = get_mc_status_str(mc_status); if ((mc_status >= 0x80) || op->verbose) pr2serr("mc offset=%u: status: %s [0x%x, additional=0x%x]\n", sg_get_unaligned_be32(bp + 12), cp, mc_status, bp[3]); if (op->verbose > 1) pr2serr(" subenc_id=%d, expected_buffer_id=%d, " "expected_offset=0x%" PRIx32 "\n", bp[1], bp[11], sg_get_unaligned_be32(bp + 12)); if (mc_status >= 0x80) ret = ret ? ret : SG_LIB_CAT_OTHER; } } return ret; }
int main(int argc, char * argv[]) { bool last, got_stdin, is_reg; bool want_file = false; bool verbose_given = false; bool version_given = false; int res, c, len, k, n, rsp_len, resid, act_len, din_len, verb; int sg_fd = -1; int infd = -1; int do_help = 0; int ret = 0; uint32_t gen_code = 0; const char * device_name = NULL; const char * file_name = NULL; uint8_t * dmp = NULL; uint8_t * dip = NULL; uint8_t * free_dip = NULL; char * cp; char ebuff[EBUFF_SZ]; struct stat a_stat; struct dout_buff_t dout; struct opts_t opts; struct opts_t * op; const struct mode_s * mp; op = &opts; memset(op, 0, sizeof(opts)); memset(&dout, 0, sizeof(dout)); din_len = DEF_DIN_LEN; while (1) { int option_index = 0; c = getopt_long(argc, argv, "b:dehi:I:l:m:No:s:S:t:vV", long_options, &option_index); if (c == -1) break; switch (c) { case 'b': op->bpw = sg_get_num(optarg); if (op->bpw < 0) { pr2serr("argument to '--bpw' should be in a positive " "number\n"); return SG_LIB_SYNTAX_ERROR; } if ((cp = strchr(optarg, ','))) { if (0 == strncmp("act", cp + 1, 3)) op->bpw_then_activate = true; } break; case 'd': op->dry_run = true; break; case 'e': op->ealsd = true; break; case 'h': case '?': ++do_help; break; case 'i': op->mc_id = sg_get_num_nomult(optarg); if ((op->mc_id < 0) || (op->mc_id > 255)) { pr2serr("argument to '--id' should be in the range 0 to " "255\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'I': file_name = optarg; break; case 'l': op->mc_len = sg_get_num(optarg); if (op->mc_len < 0) { pr2serr("bad argument to '--length'\n"); return SG_LIB_SYNTAX_ERROR; } op->mc_len_given = true; break; case 'm': if (isdigit(*optarg)) { op->mc_mode = sg_get_num_nomult(optarg); if ((op->mc_mode < 0) || (op->mc_mode > 255)) { pr2serr("argument to '--mode' should be in the range 0 " "to 255\n"); return SG_LIB_SYNTAX_ERROR; } } else { len = strlen(optarg); for (mp = mode_arr; mp->mode_string; ++mp) { if (0 == strncmp(mp->mode_string, optarg, len)) { op->mc_mode = mp->mode; break; } } if (! mp->mode_string) { print_modes(); return SG_LIB_SYNTAX_ERROR; } } break; case 'N': op->mc_non = true; break; case 'o': op->mc_offset = sg_get_num(optarg); if (op->mc_offset < 0) { pr2serr("bad argument to '--offset'\n"); return SG_LIB_SYNTAX_ERROR; } if (0 != (op->mc_offset % 4)) { pr2serr("'--offset' value needs to be a multiple of 4\n"); return SG_LIB_SYNTAX_ERROR; } break; case 's': op->mc_skip = sg_get_num(optarg); if (op->mc_skip < 0) { pr2serr("bad argument to '--skip'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'S': op->mc_subenc = sg_get_num_nomult(optarg); if ((op->mc_subenc < 0) || (op->mc_subenc > 255)) { pr2serr("expected argument to '--subenc' to be 0 to 255\n"); return SG_LIB_SYNTAX_ERROR; } break; case 't': op->mc_tlen = sg_get_num(optarg); if (op->mc_tlen < 0) { pr2serr("bad argument to '--tlength'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'v': verbose_given = true; ++op->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; op->verbose = 0; } else if (! verbose_given) { pr2serr("set '-vv'\n"); op->verbose = 2; } else pr2serr("keep verbose=%d\n", op->verbose); #else if (verbose_given && version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (version_given) { pr2serr(ME "version: %s\n", version_str); return 0; } if (NULL == device_name) { pr2serr("missing device name!\n\n"); usage(); return SG_LIB_SYNTAX_ERROR; } switch (op->mc_mode) { case MODE_DNLD_MC_OFFS: case MODE_DNLD_MC_OFFS_SAVE: case MODE_DNLD_MC_OFFS_DEFER: want_file = true; break; case MODE_DNLD_STATUS: case MODE_ACTIVATE_MC: case MODE_ABORT_MC: want_file = false; break; default: pr2serr("%s: mc_mode=0x%x, continue for now\n", __func__, op->mc_mode); break; } if ((op->mc_len > 0) && (op->bpw > op->mc_len)) { pr2serr("trim chunk size (CS) to be the same as LEN\n"); op->bpw = op->mc_len; } if ((op->mc_offset > 0) && (op->bpw > 0)) { op->mc_offset = 0; pr2serr("WARNING: --offset= ignored (set back to 0) when --bpw= " "argument given (and > 0)\n"); } #ifdef SG_LIB_WIN32 #ifdef SG_LIB_WIN32_DIRECT if (op->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, false /* rw */, op->verbose); if (sg_fd < 0) { if (op->verbose) pr2serr(ME "open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); goto fini; } if (file_name && (! want_file)) pr2serr("ignoring --in=FILE option\n"); else if (file_name) { got_stdin = (0 == strcmp(file_name, "-")); if (got_stdin) infd = STDIN_FILENO; else { if ((infd = open(file_name, O_RDONLY)) < 0) { ret = sg_convert_errno(errno); snprintf(ebuff, EBUFF_SZ, ME "could not open %s for reading", file_name); perror(ebuff); goto fini; } else if (sg_set_binary_mode(infd) < 0) perror("sg_set_binary_mode"); } if ((0 == fstat(infd, &a_stat)) && S_ISREG(a_stat.st_mode)) { is_reg = true; if (0 == op->mc_len) { if (op->mc_skip >= a_stat.st_size) { pr2serr("skip exceeds file size of %d bytes\n", (int)a_stat.st_size); ret = SG_LIB_FILE_ERROR; goto fini; } op->mc_len = (int)(a_stat.st_size) - op->mc_skip; } } else { is_reg = false; if (0 == op->mc_len) op->mc_len = DEF_XFER_LEN; } if (op->mc_len > MAX_XFER_LEN) { pr2serr("file size or requested length (%d) exceeds " "MAX_XFER_LEN of %d bytes\n", op->mc_len, MAX_XFER_LEN); ret = SG_LIB_FILE_ERROR; goto fini; } if (NULL == (dmp = (uint8_t *)malloc(op->mc_len))) { pr2serr(ME "out of memory to hold microcode read from FILE\n"); ret = SG_LIB_CAT_OTHER; goto fini; } /* Don't remember why this is preset to 0xff, from write_buffer */ memset(dmp, 0xff, op->mc_len); if (op->mc_skip > 0) { if (! is_reg) { if (got_stdin) pr2serr("Can't skip on stdin\n"); else pr2serr(ME "not a 'regular' file so can't apply skip\n"); ret = SG_LIB_FILE_ERROR; goto fini; } if (lseek(infd, op->mc_skip, SEEK_SET) < 0) { ret = sg_convert_errno(errno); snprintf(ebuff, EBUFF_SZ, ME "couldn't skip to " "required position on %s", file_name); perror(ebuff); goto fini; } } res = read(infd, dmp, op->mc_len); if (res < 0) { ret = sg_convert_errno(errno); snprintf(ebuff, EBUFF_SZ, ME "couldn't read from %s", file_name); perror(ebuff); goto fini; } if (res < op->mc_len) { if (op->mc_len_given) { pr2serr("tried to read %d bytes from %s, got %d bytes\n", op->mc_len, file_name, res); pr2serr("pad with 0xff bytes and continue\n"); } else { if (op->verbose) { pr2serr("tried to read %d bytes from %s, got %d " "bytes\n", op->mc_len, file_name, res); pr2serr("will send %d bytes", res); if ((op->bpw > 0) && (op->bpw < op->mc_len)) pr2serr(", %d bytes per WRITE BUFFER command\n", op->bpw); else pr2serr("\n"); } op->mc_len = res; } } if (! got_stdin) close(infd); infd = -1; } else if (want_file) { pr2serr("need --in=FILE option with given mode\n"); ret = SG_LIB_CONTRADICT; goto fini; } if (op->mc_tlen < op->mc_len) op->mc_tlen = op->mc_len; if (op->mc_non && (MODE_DNLD_STATUS == op->mc_mode)) { pr2serr("Do nothing because '--non' given so fetching the Download " "microcode status\ndpage might be dangerous\n"); goto fini; } dip = sg_memalign(din_len, 0, &free_dip, op->verbose > 3); if (NULL == dip) { pr2serr(ME "out of memory (data-in buffer)\n"); ret = SG_LIB_CAT_OTHER; goto fini; } verb = (op->verbose > 1) ? op->verbose - 1 : 0; /* Fetch Download microcode status dpage for generation code ++ */ if (op->dry_run) { n = sizeof(dummy_rd_resp); n = (n < din_len) ? n : din_len; memcpy(dip, dummy_rd_resp, n); resid = din_len - n; res = 0; } else res = sg_ll_receive_diag_v2(sg_fd, true /* pcv */, DPC_DOWNLOAD_MICROCODE, dip, din_len, 0 /*default timeout */, &resid, true, verb); if (0 == res) { rsp_len = sg_get_unaligned_be16(dip + 2) + 4; act_len = din_len - resid; if (rsp_len > din_len) { pr2serr("<<< warning response buffer too small [%d but need " "%d]>>>\n", din_len, rsp_len); rsp_len = din_len; } if (rsp_len > act_len) { pr2serr("<<< warning response too short [actually got %d but " "need %d]>>>\n", act_len, rsp_len); rsp_len = act_len; } if (rsp_len < 8) { pr2serr("Download microcode status dpage too short\n"); ret = SG_LIB_CAT_OTHER; goto fini; } if ((op->verbose > 2) || (op->dry_run && op->verbose)) pr2serr("rec diag(ini): rsp_len=%d, num_sub-enc=%u " "rec_gen_code=%u\n", rsp_len, dip[1], sg_get_unaligned_be32(dip + 4)); } else { ret = res; goto fini; } gen_code = sg_get_unaligned_be32(dip + 4); if (MODE_DNLD_STATUS == op->mc_mode) { show_download_mc_sdg(dip, rsp_len, gen_code); goto fini; } else if (! want_file) { /* ACTIVATE and ABORT */ res = send_then_receive(sg_fd, gen_code, 0, NULL, 0, &dout, dip, din_len, true, op); ret = res; goto fini; } res = 0; if (op->bpw > 0) { for (k = 0, last = false; k < op->mc_len; k += n) { n = op->mc_len - k; if (n > op->bpw) n = op->bpw; else last = true; if (op->verbose) pr2serr("bpw loop: mode=0x%x, id=%d, off_off=%d, len=%d, " "last=%d\n", op->mc_mode, op->mc_id, k, n, last); res = send_then_receive(sg_fd, gen_code, k, dmp + k, n, &dout, dip, din_len, last, op); if (res) break; } if (op->bpw_then_activate && (0 == res)) { op->mc_mode = MODE_ACTIVATE_MC; if (op->verbose) pr2serr("sending Activate deferred microcode [0xf]\n"); res = send_then_receive(sg_fd, gen_code, 0, NULL, 0, &dout, dip, din_len, true, op); } } else { if (op->verbose) pr2serr("single: mode=0x%x, id=%d, offset=%d, len=%d\n", op->mc_mode, op->mc_id, op->mc_offset, op->mc_len); res = send_then_receive(sg_fd, gen_code, 0, dmp, op->mc_len, &dout, dip, din_len, true, op); } if (res) ret = res; fini: if ((infd >= 0) && (! got_stdin)) close(infd); if (dmp) free(dmp); if (dout.free_doutp) free(dout.free_doutp); if (free_dip) free(free_dip); 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 == op->verbose) { if (! sg_if_can2stderr("sg_ses_mocrocode 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, res, c, len, k, n, got_stdin, is_reg, rsp_len, verb, last; int infd = -1; int do_help = 0; const char * device_name = NULL; const char * file_name = NULL; unsigned char * dmp = NULL; unsigned char * dip = NULL; char * cp; char ebuff[EBUFF_SZ]; struct stat a_stat; struct dout_buff_t dout; struct opts_t opts; struct opts_t * op; const struct mode_s * mp; uint32_t gen_code = 0; int ret = 0; op = &opts; memset(op, 0, sizeof(opts)); memset(&dout, 0, sizeof(dout)); while (1) { int option_index = 0; c = getopt_long(argc, argv, "b:hi:I:l:m:No:s:S:t:vV", long_options, &option_index); if (c == -1) break; switch (c) { case 'b': op->bpw = sg_get_num(optarg); if (op->bpw < 0) { pr2serr("argument to '--bpw' should be in a positive " "number\n"); return SG_LIB_SYNTAX_ERROR; } if ((cp = strchr(optarg, ','))) { if (0 == strncmp("act", cp + 1, 3)) ++op->bpw_then_activate; } break; case 'h': case '?': ++do_help; break; case 'i': op->mc_id = sg_get_num(optarg); if ((op->mc_id < 0) || (op->mc_id > 255)) { pr2serr("argument to '--id' should be in the range 0 to " "255\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'I': file_name = optarg; break; case 'l': op->mc_len = sg_get_num(optarg); if (op->mc_len < 0) { pr2serr("bad argument to '--length'\n"); return SG_LIB_SYNTAX_ERROR; } op->mc_len_given = 1; break; case 'm': if (isdigit(*optarg)) { op->mc_mode = sg_get_num(optarg); if ((op->mc_mode < 0) || (op->mc_mode > 255)) { pr2serr("argument to '--mode' should be in the range 0 " "to 255\n"); return SG_LIB_SYNTAX_ERROR; } } else { len = strlen(optarg); for (mp = mode_arr; mp->mode_string; ++mp) { if (0 == strncmp(mp->mode_string, optarg, len)) { op->mc_mode = mp->mode; break; } } if (! mp->mode_string) { print_modes(); return SG_LIB_SYNTAX_ERROR; } } break; case 'N': ++op->mc_non; break; case 'o': op->mc_offset = sg_get_num(optarg); if (op->mc_offset < 0) { pr2serr("bad argument to '--offset'\n"); return SG_LIB_SYNTAX_ERROR; } if (0 != (op->mc_offset % 4)) { pr2serr("'--offset' value needs to be a multiple of 4\n"); return SG_LIB_SYNTAX_ERROR; } break; case 's': op->mc_skip = sg_get_num(optarg); if (op->mc_skip < 0) { pr2serr("bad argument to '--skip'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'S': op->mc_subenc = sg_get_num(optarg); if ((op->mc_subenc < 0) || (op->mc_subenc > 255)) { pr2serr("expected argument to '--subenc' to be 0 to 255\n"); return SG_LIB_SYNTAX_ERROR; } break; case 't': op->mc_tlen = sg_get_num(optarg); if (op->mc_tlen < 0) { pr2serr("bad argument to '--tlength'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'v': ++op->verbose; break; case 'V': pr2serr(ME "version: %s\n", version_str); return 0; 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; } } if (NULL == device_name) { pr2serr("missing device name!\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if ((op->mc_len > 0) && (op->bpw > op->mc_len)) { pr2serr("trim chunk size (CS) to be the same as LEN\n"); op->bpw = op->mc_len; } #ifdef SG_LIB_WIN32 #ifdef SG_LIB_WIN32_DIRECT if (op->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, 0 /* rw */, op->verbose); if (sg_fd < 0) { pr2serr(ME "open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } if (file_name && ((MODE_DNLD_STATUS == op->mc_mode) || (MODE_ACTIVATE_MC == op->mc_mode))) pr2serr("ignoring --in=FILE option\n"); else if (file_name) { got_stdin = (0 == strcmp(file_name, "-")) ? 1 : 0; if (got_stdin) infd = STDIN_FILENO; else { if ((infd = open(file_name, O_RDONLY)) < 0) { snprintf(ebuff, EBUFF_SZ, ME "could not open %s for reading", file_name); perror(ebuff); ret = SG_LIB_FILE_ERROR; goto fini; } else if (sg_set_binary_mode(infd) < 0) perror("sg_set_binary_mode"); } if ((0 == fstat(infd, &a_stat)) && S_ISREG(a_stat.st_mode)) { is_reg = 1; if (0 == op->mc_len) { if (op->mc_skip >= a_stat.st_size) { pr2serr("skip exceeds file size of %d bytes\n", (int)a_stat.st_size); ret = SG_LIB_FILE_ERROR; goto fini; } op->mc_len = (int)(a_stat.st_size) - op->mc_skip; } } else { is_reg = 0; if (0 == op->mc_len) op->mc_len = DEF_XFER_LEN; } if (op->mc_len > MAX_XFER_LEN) { pr2serr("file size or requested length (%d) exceeds " "MAX_XFER_LEN of %d bytes\n", op->mc_len, MAX_XFER_LEN); ret = SG_LIB_FILE_ERROR; goto fini; } if (NULL == (dmp = (unsigned char *)malloc(op->mc_len))) { pr2serr(ME "out of memory (to hold microcode)\n"); ret = SG_LIB_CAT_OTHER; goto fini; } /* Don't remember why this is preset to 0xff, from write_buffer */ memset(dmp, 0xff, op->mc_len); if (op->mc_skip > 0) { if (! is_reg) { if (got_stdin) pr2serr("Can't skip on stdin\n"); else pr2serr(ME "not a 'regular' file so can't apply skip\n"); ret = SG_LIB_FILE_ERROR; goto fini; } if (lseek(infd, op->mc_skip, SEEK_SET) < 0) { snprintf(ebuff, EBUFF_SZ, ME "couldn't skip to " "required position on %s", file_name); perror(ebuff); ret = SG_LIB_FILE_ERROR; goto fini; } } res = read(infd, dmp, op->mc_len); if (res < 0) { snprintf(ebuff, EBUFF_SZ, ME "couldn't read from %s", file_name); perror(ebuff); ret = SG_LIB_FILE_ERROR; goto fini; } if (res < op->mc_len) { if (op->mc_len_given) { pr2serr("tried to read %d bytes from %s, got %d bytes\n", op->mc_len, file_name, res); pr2serr("pad with 0xff bytes and continue\n"); } else { if (op->verbose) { pr2serr("tried to read %d bytes from %s, got %d " "bytes\n", op->mc_len, file_name, res); pr2serr("will send %d bytes", res); if ((op->bpw > 0) && (op->bpw < op->mc_len)) pr2serr(", %d bytes per WRITE BUFFER command\n", op->bpw); else pr2serr("\n"); } op->mc_len = res; } } if (! got_stdin) close(infd); infd = -1; } else if (! ((MODE_DNLD_STATUS == op->mc_mode) || (MODE_ACTIVATE_MC == op->mc_mode))) { pr2serr("need --in=FILE option with given mode\n"); ret = SG_LIB_SYNTAX_ERROR; goto fini; } if (op->mc_tlen < op->mc_len) op->mc_tlen = op->mc_len; if (op->mc_non && (MODE_DNLD_STATUS == op->mc_mode)) { pr2serr("Do nothing because '--non' given so fetching the Download " "microcode status\ndpage might be dangerous\n"); goto fini; } if (NULL == (dip = (unsigned char *)malloc(DEF_DI_LEN))) { pr2serr(ME "out of memory (data-in buffer)\n"); ret = SG_LIB_CAT_OTHER; goto fini; } memset(dip, 0, DEF_DI_LEN); verb = (op->verbose > 1) ? op->verbose - 1 : 0; /* Fetch Download microcode status dpage for generation code ++ */ res = sg_ll_receive_diag(sg_fd, 1 /* pcv */, DPC_DOWNLOAD_MICROCODE, dip, DEF_DI_LEN, 1, verb); if (0 == res) { rsp_len = sg_get_unaligned_be16(dip + 2) + 4; if (rsp_len > DEF_DI_LEN) { pr2serr("<<< warning response buffer too small [%d but need " "%d]>>>\n", DEF_DI_LEN, rsp_len); rsp_len = DEF_DI_LEN; } if (rsp_len < 8) { pr2serr("Download microcode status dpage too short\n"); ret = SG_LIB_CAT_OTHER; goto fini; } } else { ret = res; goto fini; } gen_code = sg_get_unaligned_be32(dip + 4); if (MODE_DNLD_STATUS == op->mc_mode) { ses_download_code_sdg(dip, rsp_len, gen_code); goto fini; } else if (MODE_ACTIVATE_MC == op->mc_mode) { res = send_then_receive(sg_fd, gen_code, 0, NULL, 0, &dout, dip, 1, op); ret = res; goto fini; } res = 0; if (op->bpw > 0) { for (k = 0, last = 0; k < op->mc_len; k += n) { n = op->mc_len - k; if (n > op->bpw) n = op->bpw; else last = 1; if (op->verbose) pr2serr("bpw loop: mode=0x%x, id=%d, off_off=%d, len=%d, " "last=%d\n", op->mc_mode, op->mc_id, k, n, last); res = send_then_receive(sg_fd, gen_code, k, dmp + k, n, &dout, dip, last, op); if (res) break; } if (op->bpw_then_activate && (0 == res)) { op->mc_mode = MODE_ACTIVATE_MC; if (op->verbose) pr2serr("sending Activate deferred microcode [0xf]\n"); res = send_then_receive(sg_fd, gen_code, 0, NULL, 0, &dout, dip, 1, op); } } else { if (op->verbose) pr2serr("single: mode=0x%x, id=%d, offset=%d, len=%d\n", op->mc_mode, op->mc_id, op->mc_offset, op->mc_len); res = send_then_receive(sg_fd, gen_code, 0, dmp, op->mc_len, &dout, dip, 1, op); } if (res) ret = res; fini: if ((infd >= 0) && (! got_stdin)) close(infd); if (dmp) free(dmp); if (dout.doutp) free(dout.doutp); 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; } if (ret && (0 == op->verbose)) { if (SG_LIB_CAT_INVALID_OP == ret) pr2serr("%sRECEIVE DIAGNOSTIC RESULTS command not supported\n", ((MODE_DNLD_STATUS == op->mc_mode) ? "" : "SEND DIAGNOSTIC or ")); else if (ret > 0) pr2serr("Failed, exit status %d\n", ret); else if (ret < 0) pr2serr("Some error occurred\n"); } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; }
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; }
/* Fetches current, changeable, default and/or saveable modes pages as * indicated by pcontrol_arr for given pg_code and sub_pg_code. If * mode6==0 then use MODE SENSE (10) else use MODE SENSE (6). If * flexible set and mode data length seems wrong then try and * fix (compensating hack for bad device or driver). pcontrol_arr * should have 4 elements for output of current, changeable, default * and saved values respectively. Each element should be NULL or * at least mx_mpage_len bytes long. * Return of 0 -> overall success, various SG_LIB_CAT_* positive values or * -1 -> other errors. * If success_mask pointer is not NULL then first zeros it. Then set bits * 0, 1, 2 and/or 3 if the current, changeable, default and saved values * respectively have been fetched. If error on current page * then stops and returns that error; otherwise continues if an error is * detected but returns the first error encountered. */ int sg_get_mode_page_controls(int sg_fd, int mode6, int pg_code, int sub_pg_code, int dbd, int flexible, int mx_mpage_len, int * success_mask, void * pcontrol_arr[], int * reported_len, int verbose) { int k, n, res, offset, calc_len, xfer_len, resp_mode6; unsigned char buff[MODE_RESP_ARB_LEN]; char ebuff[EBUFF_SZ]; int first_err = 0; if (success_mask) *success_mask = 0; if (reported_len) *reported_len = 0; if (mx_mpage_len < 4) return 0; memset(ebuff, 0, sizeof(ebuff)); /* first try to find length of current page response */ memset(buff, 0, MODE10_RESP_HDR_LEN); if (mode6) /* want first 8 bytes just in case */ res = sg_ll_mode_sense6(sg_fd, dbd, 0 /* pc */, pg_code, sub_pg_code, buff, MODE10_RESP_HDR_LEN, 1, verbose); else res = sg_ll_mode_sense10(sg_fd, 0 /* llbaa */, dbd, 0 /* pc */, pg_code, sub_pg_code, buff, MODE10_RESP_HDR_LEN, 1, verbose); if (0 != res) return res; n = buff[0]; if (reported_len) *reported_len = mode6 ? (n + 1) : (sg_get_unaligned_be16(buff) + 2); resp_mode6 = mode6; if (flexible) { if (mode6 && (n < 3)) { resp_mode6 = 0; if (verbose) pr2ws(">>> msense(6) but resp[0]=%d so try msense(10) " "response processing\n", n); } if ((0 == mode6) && (n > 5)) { if ((n > 11) && (0 == (n % 2)) && (0 == buff[4]) && (0 == buff[5]) && (0 == buff[6])) { buff[1] = n; buff[0] = 0; if (verbose) pr2ws(">>> msense(10) but resp[0]=%d and not msense(6) " "response so fix length\n", n); } else resp_mode6 = 1; } } if (verbose && (resp_mode6 != mode6)) pr2ws(">>> msense(%d) but resp[0]=%d so switch response " "processing\n", (mode6 ? 6 : 10), buff[0]); calc_len = resp_mode6 ? (buff[0] + 1) : (sg_get_unaligned_be16(buff) + 2); if (calc_len > MODE_RESP_ARB_LEN) calc_len = MODE_RESP_ARB_LEN; offset = sg_mode_page_offset(buff, calc_len, resp_mode6, ebuff, EBUFF_SZ); if (offset < 0) { if (('\0' != ebuff[0]) && (verbose > 0)) pr2ws("%s: %s\n", __func__, ebuff); return SG_LIB_CAT_MALFORMED; } xfer_len = calc_len - offset; if (xfer_len > mx_mpage_len) xfer_len = mx_mpage_len; for (k = 0; k < 4; ++k) { if (NULL == pcontrol_arr[k]) continue; memset(pcontrol_arr[k], 0, mx_mpage_len); if (mode6) res = sg_ll_mode_sense6(sg_fd, dbd, k /* pc */, pg_code, sub_pg_code, buff, calc_len, 1, verbose); else res = sg_ll_mode_sense10(sg_fd, 0 /* llbaa */, dbd, k /* pc */, pg_code, sub_pg_code, buff, calc_len, 1, verbose); if (0 != res) { if (0 == first_err) first_err = res; if (0 == k) break; /* if problem on current page, it won't improve */ else continue; } if (xfer_len > 0) memcpy(pcontrol_arr[k], buff + offset, xfer_len); if (success_mask) *success_mask |= (1 << k); } return first_err; }
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, rsp_len, res, rsp_buff_size, pg; int read_in_len = 0; int ret = 0; struct opts_t opts; struct opts_t * op; unsigned char * rsp_buff = NULL; const char * cp; unsigned char * read_in = NULL; op = &opts; memset(op, 0, sizeof(opts)); op->maxlen = DEF_ALLOC_LEN; op->page_code = -1; res = process_cl(op, argc, argv); if (res) return SG_LIB_SYNTAX_ERROR; if (op->do_help) { if (op->opt_new) usage(); else usage_old(); return 0; } if (op->do_version) { fprintf(stderr, "Version string: %s\n", version_str); return 0; } rsp_buff_size = op->maxlen; if (NULL == op->device_name) { if (op->do_list) { list_page_codes(); return 0; } fprintf(stderr, "No DEVICE argument given\n"); if (op->opt_new) usage(); else usage_old(); return SG_LIB_SYNTAX_ERROR; } if (op->do_raw) { read_in = (unsigned char *)calloc(op->maxlen, 1); if (NULL == read_in) { fprintf(stderr, "unable to allocate %d bytes\n", op->maxlen); return SG_LIB_CAT_OTHER; } if (build_diag_page(op->raw_arg, read_in, &read_in_len, op->maxlen)) { if (op->opt_new) { printf("Bad sequence after '--raw=' option\n"); usage(); } else { printf("Bad sequence after '-raw=' option\n"); usage_old(); } return SG_LIB_SYNTAX_ERROR; } } if ((op->do_doff || op->do_uoff) && (! op->do_deftest)) { if (op->opt_new) { printf("setting --doff or --uoff only useful when -t is set\n"); usage(); } else { printf("setting -doff or -uoff only useful when -t is set\n"); usage_old(); } return SG_LIB_SYNTAX_ERROR; } if ((op->do_selftest > 0) && op->do_deftest) { if (op->opt_new) { printf("either set --selftest=SF or --test (not both)\n"); usage(); } else { printf("either set -s=SF or -t (not both)\n"); usage_old(); } return SG_LIB_SYNTAX_ERROR; } if (op->do_raw) { if ((op->do_selftest > 0) || op->do_deftest || op->do_extdur || op->do_list) { if (op->opt_new) { printf("'--raw=' cannot be used with self-tests, '-e' or " "'-l'\n"); usage(); } else { printf("'-raw=' cannot be used with self-tests, '-e' or " "'-l'\n"); usage_old(); } return SG_LIB_SYNTAX_ERROR; } if (! op->do_pf) { if (op->opt_new) printf(">>> warning, '--pf' probably should be used with " "'--raw='\n"); else printf(">>> warning, '-pf' probably should be used with " "'-raw='\n"); } } #ifdef SG_LIB_WIN32 #ifdef SG_LIB_WIN32_DIRECT if (op->do_verbose > 4) fprintf(stderr, "Initial win32 SPT interface state: %s\n", scsi_pt_win32_spt_state() ? "direct" : "indirect"); if (op->maxlen >= 16384) scsi_pt_win32_direct(SG_LIB_WIN32_DIRECT /* SPT pt interface */); #endif #endif if ((sg_fd = sg_cmds_open_device(op->device_name, 0 /* rw */, op->do_verbose)) < 0) { fprintf(stderr, ME "error opening file: %s: %s\n", op->device_name, safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } rsp_buff = (unsigned char *)calloc(op->maxlen, 1); if (NULL == rsp_buff) { fprintf(stderr, "unable to allocate %d bytes (2)\n", op->maxlen); return SG_LIB_CAT_OTHER; } if (op->do_extdur) { res = do_modes_0a(sg_fd, rsp_buff, 32, 1, 0, op->do_verbose); if (0 == res) { /* Assume mode sense(10) response without block descriptors */ num = sg_get_unaligned_be16(rsp_buff) - 6; if (num >= 0xc) { int secs; secs = sg_get_unaligned_be16(rsp_buff + 18); #ifdef SG_LIB_MINGW printf("Expected extended self-test duration=%d seconds " "(%g minutes)\n", secs, secs / 60.0); #else printf("Expected extended self-test duration=%d seconds " "(%.2f minutes)\n", secs, secs / 60.0); #endif } else printf("Extended self-test duration not available\n"); } else { ret = res; printf("Extended self-test duration (mode page 0xa) failed\n"); goto err_out9; } } else if ((op->do_list) || (op->page_code >= 0x0)) { pg = op->page_code; if (pg < 0) res = do_senddiag(sg_fd, 0, 1 /* pf */, 0, 0, 0, rsp_buff, 4, 1, op->do_verbose); else res = 0; if (0 == res) { if (0 == sg_ll_receive_diag(sg_fd, (pg >= 0x0), ((pg >= 0x0) ? pg : 0), rsp_buff, rsp_buff_size, 1, op->do_verbose)) { rsp_len = sg_get_unaligned_be16(rsp_buff + 2) + 4; if (op->do_hex > 1) dStrHex((const char *)rsp_buff, rsp_len, (2 == op->do_hex) ? 0 : -1); else if (pg < 0x1) { printf("Supported diagnostic pages response:\n"); if (op->do_hex) dStrHex((const char *)rsp_buff, rsp_len, 1); else { for (k = 0; k < (rsp_len - 4); ++k) { cp = find_page_code_desc(rsp_buff[k + 4]); printf(" 0x%02x %s\n", rsp_buff[k + 4], (cp ? cp : "<unknown>")); } } } else { cp = find_page_code_desc(pg); if (cp) printf("%s diagnostic page [0x%x] response in " "hex:\n", cp, pg); else printf("diagnostic page 0x%x response in hex:\n", pg); dStrHex((const char *)rsp_buff, rsp_len, 1); } } else { ret = res; fprintf(stderr, "RECEIVE DIAGNOSTIC RESULTS command " "failed\n"); goto err_out9; } } else { ret = res; goto err_out; } } else if (op->do_raw) { res = do_senddiag(sg_fd, 0, op->do_pf, 0, 0, 0, read_in, read_in_len, 1, op->do_verbose); if (res) { ret = res; goto err_out; } } else { res = do_senddiag(sg_fd, op->do_selftest, op->do_pf, op->do_deftest, op->do_doff, op->do_uoff, NULL, 0, 1, op->do_verbose); if (0 == res) { if ((5 == op->do_selftest) || (6 == op->do_selftest)) printf("Foreground self-test returned GOOD status\n"); else if (op->do_deftest && (! op->do_doff) && (! op->do_uoff)) printf("Default self-test returned GOOD status\n"); } else { ret = res; goto err_out; } } res = sg_cmds_close_device(sg_fd); if ((res < 0) && (0 == ret)) return SG_LIB_SYNTAX_ERROR; return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; err_out: if (SG_LIB_CAT_UNIT_ATTENTION == res) fprintf(stderr, "SEND DIAGNOSTIC, unit attention\n"); else if (SG_LIB_CAT_ABORTED_COMMAND == res) fprintf(stderr, "SEND DIAGNOSTIC, aborted command\n"); else if (SG_LIB_CAT_NOT_READY == res) fprintf(stderr, "SEND DIAGNOSTIC, device not " "ready\n"); else fprintf(stderr, "SEND DIAGNOSTIC command, failed\n"); err_out9: if (op->do_verbose < 2) fprintf(stderr, " try again with '-vv' for more information\n"); res = sg_cmds_close_device(sg_fd); if ((res < 0) && (0 == ret)) return SG_LIB_FILE_ERROR; if (read_in) free(read_in); if (rsp_buff) free(rsp_buff); return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; }
int main(int argc, char *argv[]) { int k; int ret = 0; unsigned int ui; size_t s; struct opts_t opts; struct opts_t * op; char b[2048]; FILE * fp = NULL; const char * cp; op = &opts; memset(op, 0, sizeof(opts)); memset(b, 0, sizeof(b)); ret = process_cl(op, argc, argv); if (ret != 0) { usage(); return ret; } else if (op->do_help) { usage(); return 0; } else if (op->do_version) { pr2serr("version: %s\n", version_str); return 0; } if (op->do_status) { sg_get_scsi_status_str(op->sstatus, sizeof(b) - 1, b); printf("SCSI status: %s\n", b); } if ((0 == op->sense_len) && op->no_space_str) { if (op->do_verbose > 2) pr2serr("no_space str: %s\n", op->no_space_str); cp = op->no_space_str; for (k = 0; isxdigit(cp[k]) && isxdigit(cp[k + 1]); k += 2) { if (1 != sscanf(cp + k, "%2x", &ui)) { pr2serr("bad no_space hex string: %s\n", cp); return SG_LIB_SYNTAX_ERROR; } op->sense[op->sense_len++] = (unsigned char)ui; } } if ((0 == op->sense_len) && (! op->do_binary) && (! op->do_file)) { if (op->do_status) return 0; pr2serr(">> Need sense data on the command line or in a file\n\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (op->sense_len && (op->do_binary || op->do_file)) { pr2serr(">> Need sense data on command line or in a file, not " "both\n\n"); return SG_LIB_SYNTAX_ERROR; } if (op->do_binary && op->do_file) { pr2serr(">> Either a binary file or a ASCII hexadecimal, file not " "both\n\n"); return SG_LIB_SYNTAX_ERROR; } if (op->do_binary) { fp = fopen(op->fname, "r"); if (NULL == fp) { pr2serr("unable to open file: %s\n", op->fname); return SG_LIB_SYNTAX_ERROR; } s = fread(op->sense, 1, MAX_SENSE_LEN, fp); fclose(fp); if (0 == s) { pr2serr("read nothing from file: %s\n", op->fname); return SG_LIB_SYNTAX_ERROR; } op->sense_len = s; } else if (op->do_file) { ret = f2hex_arr(op->fname, op->no_space, op->sense, &op->sense_len, MAX_SENSE_LEN); if (ret) { pr2serr("unable to decode ASCII hex from file: %s\n", op->fname); return SG_LIB_SYNTAX_ERROR; } } if (op->sense_len) { if (op->wfname) { if ((fp = fopen(op->wfname, "w"))) { write2wfn(fp, op); fclose(fp); } else { perror("open"); pr2serr("trying to write to %s\n", op->wfname); } } if (op->do_cdb) { int sa, opcode; opcode = op->sense[0]; if ((0x75 == opcode) || (0x7e == opcode) || (op->sense_len > 16)) sa = sg_get_unaligned_be16(op->sense + 8); else if (op->sense_len > 1) sa = op->sense[1] & 0x1f; else sa = 0; sg_get_opcode_sa_name(opcode, sa, 0, sizeof(b), b); } else sg_get_sense_str(NULL, op->sense, op->sense_len, op->do_verbose, sizeof(b) - 1, b); printf("%s\n", b); } 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, 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; }
static void decode_attr_vals(const unsigned char * alp, int len, const struct opts_t * op) { int bump, id, alen; uint64_t ull; char * cp; char * c2p; const struct attr_name_info_t * anip; char b[160]; if (op->verbose) printf("Attribute values: [len=%d]\n", len); else if (op->filter < 0) { if (0 == op->quiet) printf("Attribute values:\n"); if (op->do_hex) { /* only expect -HH to get through here */ dStrHex((const char *)alp, len, 0); return; } } for ( ; len > 4; alp += bump, len -= bump) { id = sg_get_unaligned_be16(alp + 0); bump = sg_get_unaligned_be16(alp + 3) + 5; alen = bump - 5; if ((op->filter >= 0) && (op->filter != id)) { if (id < op->filter) continue; else break; /* Assume array is ascending id order */ } anip = NULL; cp = attr_id_lookup(id, &anip, sizeof(b), b); if (op->quiet < 2) { c2p = strchr(cp, '\t'); if (c2p) { printf(" %.*s -\n", (int)(c2p - cp), cp); printf(" %s: ", c2p + 1); } else printf(" %s: ", cp); } if (op->verbose) printf("[r%c] ", (0x80 & alp[2]) ? 'o' : 'w'); if (anip) { if ((RA_FMT_BINARY == anip->format) && (bump <= 13)) { ull = sg_get_unaligned_be(alen, alp + 5); if (0 == anip->process) printf("%" PRIu64 "\n", ull); else if (1 == anip->process) printf("0x%" PRIx64 "\n", ull); else helper_full_attr(alp, bump, id, anip, op); if (op->verbose) { if ((anip->len > 0) && (alen > 0) && (alen != anip->len)) printf(" <<< T10 length (%d) differs from length in " "response (%d) >>>\n", anip->len, alen); } } else if (RA_FMT_BINARY == anip->format) { if (2 == anip->process) helper_full_attr(alp, bump, id, anip, op); else { printf("\n"); dStrHex((const char *)(alp + 5), alen, 0); } } else { if (2 == anip->process) helper_full_attr(alp, bump, id, anip, op); else { printf("%.*s\n", alen, alp + 5); if (op->verbose) { if ((anip->len > 0) && (alen > 0) && (alen != anip->len)) printf(" <<< T10 length (%d) differs from length " "in response (%d) >>>\n", anip->len, alen); } } } } else { if (op->verbose > 1) printf("Attribute id lookup failed, in hex:\n"); else printf("\n"); dStrHex((const char *)(alp + 5), alen, 0); } } if (op->verbose && (len > 0) && (len <= 4)) pr2serr("warning: iterate of attributes should end a residual of " "%d\n", len); }
static int send_then_receive(int sg_fd, uint32_t gen_code, int off_off, const unsigned char * dmp, int dmp_len, struct dout_buff_t * wp, unsigned char * dip, int last, const struct opts_t * op) { int do_len, rem, res, rsp_len, k, num, mc_status, verb; int send_data = 0; int ret = 0; uint32_t rec_gen_code; const unsigned char * ucp; const char * cp; verb = (op->verbose > 1) ? op->verbose - 1 : 0; switch (op->mc_mode) { case MODE_DNLD_MC_OFFS: case MODE_DNLD_MC_OFFS_SAVE: case MODE_DNLD_MC_OFFS_DEFER: send_data = 1; do_len = 24 + dmp_len; rem = do_len % 4; if (rem) do_len += (4 - rem); break; case MODE_ACTIVATE_MC: do_len = 24; break; default: pr2serr("send_then_receive: unexpected mc_mode=0x%x\n", op->mc_mode); return SG_LIB_SYNTAX_ERROR; } if (do_len > wp->dout_len) { if (wp->doutp) free(wp->doutp); wp->doutp = (unsigned char *)malloc(do_len); if (! wp->doutp) { pr2serr("send_then_receive: unable to malloc %d bytes\n", do_len); return SG_LIB_CAT_OTHER; } wp->dout_len = do_len; } memset(wp->doutp, 0, do_len); wp->doutp[0] = DPC_DOWNLOAD_MICROCODE; wp->doutp[1] = op->mc_subenc; sg_put_unaligned_be16(do_len - 4, wp->doutp + 2); sg_put_unaligned_be32(gen_code, wp->doutp + 4); wp->doutp[8] = op->mc_mode; wp->doutp[11] = op->mc_id; if (send_data) sg_put_unaligned_be32(op->mc_offset + off_off, wp->doutp + 12); sg_put_unaligned_be32(op->mc_tlen, wp->doutp + 16); sg_put_unaligned_be32(dmp_len, wp->doutp + 20); if (send_data && (dmp_len > 0)) memcpy(wp->doutp + 24, dmp, dmp_len); /* select long duration timeout (7200 seconds) */ res = sg_ll_send_diag(sg_fd, 0 /* sf_code */, 1 /* pf */, 0 /* sf */, 0 /* devofl */, 0 /* unitofl */, 1 /* long_duration */, wp->doutp, do_len, 1 /* noisy */, verb); if (op->mc_non) { /* If non-standard, only call RDR after failed SD */ if (0 == res) return 0; /* If RDR error after SD error, prefer reporting SD error */ ret = res; } else { switch (op->mc_mode) { case MODE_DNLD_MC_OFFS: case MODE_DNLD_MC_OFFS_SAVE: if (res) return res; else if (last) return 0; /* RDR after last may hit a device reset */ break; case MODE_DNLD_MC_OFFS_DEFER: if (res) return res; break; case MODE_ACTIVATE_MC: if (0 == res) return 0; /* RDR after ACTIVATE_MC may hit a device reset */ /* SD has failed, so do a RDR but return SD's error */ ret = res; break; default: pr2serr("send_then_receive: mc_mode=0x%x\n", op->mc_mode); return SG_LIB_SYNTAX_ERROR; } } res = sg_ll_receive_diag(sg_fd, 1 /* pcv */, DPC_DOWNLOAD_MICROCODE, dip, DEF_DI_LEN, 1, verb); if (res) return ret ? ret : res; rsp_len = sg_get_unaligned_be16(dip + 2) + 4; if (rsp_len > DEF_DI_LEN) { pr2serr("<<< warning response buffer too small [%d but need " "%d]>>>\n", DEF_DI_LEN, rsp_len); rsp_len = DEF_DI_LEN; } if (rsp_len < 8) { pr2serr("Download microcode status dpage too short\n"); return ret ? ret : SG_LIB_CAT_OTHER; } rec_gen_code = sg_get_unaligned_be32(dip + 4); if (rec_gen_code != gen_code) pr2serr("gen_code changed from %" PRIu32 " to %" PRIu32 ", continuing but may fail\n", gen_code, rec_gen_code); num = (rsp_len - 8) / 16; if ((rsp_len - 8) % 16) pr2serr("Found %d Download microcode status descriptors, but there " "is residual\n", num); ucp = dip + 8; for (k = 0; k < num; ++k, ucp += 16) { if ((unsigned int)op->mc_subenc == (unsigned int)ucp[1]) { mc_status = ucp[2]; cp = get_mc_status_str(mc_status); if ((mc_status >= 0x80) || op->verbose) pr2serr("mc offset=%d: status: %s [0x%x, additional=0x%x]\n", off_off, cp, mc_status, ucp[3]); if (op->verbose > 1) pr2serr(" subenc_id=%d, expected_buffer_id=%d, " "expected_offset=0x%" PRIx32 "\n", ucp[1], ucp[11], sg_get_unaligned_be32(ucp + 12)); if (mc_status >= 0x80) ret = ret ? ret : SG_LIB_CAT_OTHER; } } return ret; }
static int process_cl(struct opts_t * op, int argc, char *argv[]) { while (1) { int c, n; c = getopt_long(argc, argv, "behi:k:no:r:Rs:t:vV", long_options, NULL); if (c == -1) break; switch (c) { case 'b': op->datain_binary = true; break; case 'e': op->do_enumerate = true; break; case 'h': case '?': op->do_help = true; return 0; case 'i': if (op->dataout_file) { pr2serr("Too many '--infile=' options\n"); return SG_LIB_SYNTAX_ERROR; } op->dataout_file = optarg; break; case 'k': n = sg_get_num(optarg); if (n < 0) { pr2serr("Invalid argument to '--skip'\n"); return SG_LIB_SYNTAX_ERROR; } op->dataout_offset = n; break; case 'n': op->no_sense = true; break; case 'o': if (op->datain_file) { pr2serr("Too many '--outfile=' options\n"); return SG_LIB_SYNTAX_ERROR; } op->datain_file = optarg; break; case 'r': op->do_datain = true; n = sg_get_num(optarg); if (n < 0 || n > MAX_SCSI_DXLEN) { pr2serr("Invalid argument to '--request'\n"); return SG_LIB_SYNTAX_ERROR; } op->datain_len = n; break; case 'R': ++op->readonly; break; case 's': op->do_dataout = true; n = sg_get_num(optarg); if (n < 0 || n > MAX_SCSI_DXLEN) { pr2serr("Invalid argument to '--send'\n"); return SG_LIB_SYNTAX_ERROR; } op->dataout_len = n; break; case 't': n = sg_get_num(optarg); if (n < 0) { pr2serr("Invalid argument to '--timeout'\n"); return SG_LIB_SYNTAX_ERROR; } op->timeout = n; break; case 'v': ++op->verbose; break; case 'V': op->do_version = true; return 0; default: return SG_LIB_SYNTAX_ERROR; } } if (optind >= argc) { pr2serr("No device specified\n"); return SG_LIB_SYNTAX_ERROR; } op->device_name = argv[optind]; ++optind; while (optind < argc) { char *opt = argv[optind++]; char *endptr; int cmd = strtol(opt, &endptr, 16); if (*opt == '\0' || *endptr != '\0' || cmd < 0x00 || cmd > 0xff) { pr2serr("Invalid command byte '%s'\n", opt); return SG_LIB_SYNTAX_ERROR; } if (op->cdb_length > MAX_SCSI_CDBSZ) { pr2serr("CDB too long (max. %d bytes)\n", MAX_SCSI_CDBSZ); return SG_LIB_SYNTAX_ERROR; } op->cdb[op->cdb_length] = cmd; ++op->cdb_length; } if (op->cdb_length < MIN_SCSI_CDBSZ) { pr2serr("CDB too short (min. %d bytes)\n", MIN_SCSI_CDBSZ); return SG_LIB_SYNTAX_ERROR; } if (op->do_enumerate || (op->verbose > 1)) { int sa; char b[80]; if (op->cdb_length > 16) { sa = sg_get_unaligned_be16(op->cdb + 8); if ((0x7f != op->cdb[0]) && (0x7e != op->cdb[0])) printf(">>> Unlikely to be SCSI CDB since all over 16 " "bytes long should\n>>> start with 0x7f or 0x7e\n"); } else sa = op->cdb[1] & 0x1f; sg_get_opcode_sa_name(op->cdb[0], sa, 0, sizeof(b), b); printf("Attempt to decode cdb name: %s\n", b); } return 0; }