/* Return of 0 -> success, see sg_ll_read_capacity*() otherwise */ static int scsi_read_capacity(int sg_fd, int64_t * num_sect, int * sect_sz) { int res; unsigned int ui; unsigned char rcBuff[RCAP16_REPLY_LEN]; int verb; verb = (verbose ? verbose - 1: 0); res = sg_ll_readcap_10(sg_fd, 0, 0, rcBuff, READ_CAP_REPLY_LEN, 0, verb); if (0 != res) return res; if ((0xff == rcBuff[0]) && (0xff == rcBuff[1]) && (0xff == rcBuff[2]) && (0xff == rcBuff[3])) { res = sg_ll_readcap_16(sg_fd, 0, 0, rcBuff, RCAP16_REPLY_LEN, 0, verb); if (0 != res) return res; *num_sect = sg_get_unaligned_be64(rcBuff + 0) + 1; *sect_sz = sg_get_unaligned_be32(rcBuff + 8); } else { ui = sg_get_unaligned_be32(rcBuff + 0); /* take care not to sign extend values > 0x7fffffff */ *num_sect = (int64_t)ui + 1; *sect_sz = sg_get_unaligned_be32(rcBuff + 4); } if (verbose) pr2serr(" number of blocks=%" PRId64 " [0x%" PRIx64 "], block " "size=%d\n", *num_sect, *num_sect, *sect_sz); return 0; }
/* Buffer ID 0x02: Read Usage Statistics (optional) */ static int do_safte_usage_statistics(int sg_fd, int do_hex, int do_raw, int verbose) { int res; unsigned int rb_len; unsigned char *rb_buff; unsigned int minutes; rb_len = 16 + safte_cfg.vendor_specific; rb_buff = (unsigned char *)malloc(rb_len); if (verbose > 1) pr2serr("Use READ BUFFER,mode=vendor_specific,buff_id=2 to read " "usage statistics\n"); res = sg_ll_read_buffer(sg_fd, RWB_MODE_VENDOR, 2, 0, rb_buff, rb_len, 0, verbose); if (res) { if (res == SG_LIB_CAT_ILLEGAL_REQ) { printf("Usage Statistics:\n\tNot implemented\n"); return 0; } if (res != SG_LIB_CAT_RECOVERED) { free(rb_buff); return res; } } if (do_raw > 1) { dStrRaw((const char *)rb_buff, buf_capacity); return 0; } if (do_hex > 1) { dStrHex((const char *)rb_buff, buf_capacity, 1); return 0; } printf("Usage Statistics:\n"); minutes = sg_get_unaligned_be32(rb_buff + 0); printf("\tPower on Minutes: %u\n", minutes); minutes = sg_get_unaligned_be32(rb_buff + 4); printf("\tPower on Cycles: %u\n", minutes); free(rb_buff); return 0; }
/* display DPC_DOWNLOAD_MICROCODE status dpage [0xe] */ static void show_download_mc_sdg(const uint8_t * resp, int resp_len, uint32_t gen_code) { int k, num_subs, num; const uint8_t * bp; const char * cp; printf("Download microcode status diagnostic page:\n"); if (resp_len < 8) goto truncated; num_subs = resp[1]; /* primary is additional one) */ num = (resp_len - 8) / 16; if ((resp_len - 8) % 16) pr2serr("Found %d Download microcode status descriptors, but there " "is residual\n", num); printf(" number of secondary subenclosures: %d\n", num_subs); printf(" generation code: 0x%" PRIx32 "\n", gen_code); bp = resp + 8; for (k = 0; k < num; ++k, bp += 16) { cp = (0 == bp[1]) ? " [primary]" : ""; printf(" subenclosure identifier: %d%s\n", bp[1], cp); cp = get_mc_status_str(bp[2]); if (strlen(cp) > 0) { printf(" download microcode status: %s [0x%x]\n", cp, bp[2]); printf(" download microcode additional status: 0x%x\n", bp[3]); } else printf(" download microcode status: 0x%x [additional " "status: 0x%x]\n", bp[2], bp[3]); printf(" download microcode maximum size: %" PRIu32 " bytes\n", sg_get_unaligned_be32(bp + 4)); printf(" download microcode expected buffer id: 0x%x\n", bp[11]); printf(" download microcode expected buffer id offset: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 12)); } return; truncated: pr2serr(" <<<download status: response too short>>>\n"); return; }
/* Return of 0 -> success, -1 -> failure, 2 -> try again */ static int read_capacity(int sg_fd, int * num_sect, int * sect_sz) { int res; uint8_t rc_cdb [10] = {0x25, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t rcBuff[64]; uint8_t sense_b[64]; sg_io_hdr_t io_hdr; memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); io_hdr.interface_id = 'S'; io_hdr.cmd_len = sizeof(rc_cdb); io_hdr.mx_sb_len = sizeof(sense_b); io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; io_hdr.dxfer_len = sizeof(rcBuff); io_hdr.dxferp = rcBuff; io_hdr.cmdp = rc_cdb; io_hdr.sbp = sense_b; io_hdr.timeout = DEF_TIMEOUT; if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { perror("read_capacity (SG_IO) error"); return -1; } res = sg_err_category3(&io_hdr); if (SG_LIB_CAT_UNIT_ATTENTION == res) return 2; /* probably have another go ... */ else if (SG_LIB_CAT_CLEAN != res) { sg_chk_n_print3("read capacity", &io_hdr, 1); return -1; } *num_sect = 1 + sg_get_unaligned_be32(rcBuff + 0); *sect_sz = sg_get_unaligned_be32(rcBuff + 4); #ifdef DEBUG fprintf(stderr, "number of sectors=%d, sector size=%d\n", *num_sect, *sect_sz); #endif return 0; }
int main(int argc, char * argv[]) { bool got_stdin = false; bool if_given = false; bool lba_given = false; bool num_given = false; bool prot_en; int res, c, infd, act_cdb_len, vb, err; int sg_fd = -1; int ret = -1; uint32_t block_size; int64_t ll; const char * device_name = NULL; struct opts_t * op; uint8_t * wBuff = NULL; uint8_t * free_wBuff = NULL; char ebuff[EBUFF_SZ]; char b[80]; uint8_t resp_buff[RCAP16_RESP_LEN]; struct opts_t opts; struct stat a_stat; op = &opts; memset(op, 0, sizeof(opts)); op->numblocks = DEF_WS_NUMBLOCKS; op->pref_cdb_size = DEF_WS_CDB_SIZE; op->timeout = DEF_TIMEOUT_SECS; while (1) { int option_index = 0; c = getopt_long(argc, argv, "ag:hi:l:Ln:NPRSt:TUvVw:x:", long_options, &option_index); if (c == -1) break; switch (c) { case 'a': op->anchor = true; break; case 'g': op->grpnum = sg_get_num(optarg); if ((op->grpnum < 0) || (op->grpnum > 63)) { pr2serr("bad argument to '--grpnum'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'h': case '?': usage(); return 0; case 'i': strncpy(op->ifilename, optarg, sizeof(op->ifilename) - 1); op->ifilename[sizeof(op->ifilename) - 1] = '\0'; if_given = true; break; case 'l': ll = sg_get_llnum(optarg); if (-1 == ll) { pr2serr("bad argument to '--lba'\n"); return SG_LIB_SYNTAX_ERROR; } op->lba = (uint64_t)ll; lba_given = true; break; case 'L': op->lbdata = true; break; case 'n': op->numblocks = sg_get_num(optarg); if (op->numblocks < 0) { pr2serr("bad argument to '--num'\n"); return SG_LIB_SYNTAX_ERROR; } num_given = true; break; case 'N': op->ndob = true; break; case 'P': op->pbdata = true; break; case 'R': op->want_ws10 = true; break; case 'S': if (DEF_WS_CDB_SIZE != op->pref_cdb_size) { pr2serr("only one '--10', '--16' or '--32' please\n"); return SG_LIB_CONTRADICT; } op->pref_cdb_size = 16; break; case 't': op->timeout = sg_get_num(optarg); if (op->timeout < 0) { pr2serr("bad argument to '--timeout'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'T': if (DEF_WS_CDB_SIZE != op->pref_cdb_size) { pr2serr("only one '--10', '--16' or '--32' please\n"); return SG_LIB_CONTRADICT; } op->pref_cdb_size = 32; break; case 'U': op->unmap = true; break; case 'v': op->verbose_given = true; ++op->verbose; break; case 'V': op->version_given = true; break; case 'w': op->wrprotect = sg_get_num(optarg); if ((op->wrprotect < 0) || (op->wrprotect > 7)) { pr2serr("bad argument to '--wrprotect'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'x': op->xfer_len = sg_get_num(optarg); if (op->xfer_len < 0) { pr2serr("bad argument to '--xferlen'\n"); return SG_LIB_SYNTAX_ERROR; } break; default: pr2serr("unrecognised option code 0x%x ??\n", c); usage(); return SG_LIB_SYNTAX_ERROR; } } if (optind < argc) { if (NULL == device_name) { device_name = argv[optind]; ++optind; } if (optind < argc) { for (; optind < argc; ++optind) pr2serr("Unexpected extra argument: %s\n", argv[optind]); usage(); return SG_LIB_SYNTAX_ERROR; } } if (op->want_ws10 && (DEF_WS_CDB_SIZE != op->pref_cdb_size)) { pr2serr("only one '--10', '--16' or '--32' please\n"); return SG_LIB_CONTRADICT; } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (op->verbose_given && op->version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); op->verbose_given = false; op->version_given = false; op->verbose = 0; } else if (! op->verbose_given) { pr2serr("set '-vv'\n"); op->verbose = 2; } else pr2serr("keep verbose=%d\n", op->verbose); #else if (op->verbose_given && op->version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (op->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; } vb = op->verbose; if ((! if_given) && (! lba_given) && (! num_given)) { pr2serr("As a precaution, one of '--in=', '--lba=' or '--num=' is " "required\n"); return SG_LIB_CONTRADICT; } if (op->ndob) { if (if_given) { pr2serr("Can't have both --ndob and '--in='\n"); return SG_LIB_CONTRADICT; } if (0 != op->xfer_len) { pr2serr("With --ndob only '--xferlen=0' (or not given) is " "acceptable\n"); return SG_LIB_CONTRADICT; } } else if (op->ifilename[0]) { got_stdin = (0 == strcmp(op->ifilename, "-")); if (! got_stdin) { memset(&a_stat, 0, sizeof(a_stat)); if (stat(op->ifilename, &a_stat) < 0) { err = errno; if (vb) pr2serr("unable to stat(%s): %s\n", op->ifilename, safe_strerror(err)); return sg_convert_errno(err); } if (op->xfer_len <= 0) op->xfer_len = (int)a_stat.st_size; } } sg_fd = sg_cmds_open_device(device_name, false /* rw */, vb); 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 err_out; } if (! op->ndob) { prot_en = false; if (0 == op->xfer_len) { res = sg_ll_readcap_16(sg_fd, false /* pmi */, 0 /* llba */, resp_buff, RCAP16_RESP_LEN, true, (vb ? (vb - 1): 0)); if (SG_LIB_CAT_UNIT_ATTENTION == res) { pr2serr("Read capacity(16) unit attention, try again\n"); res = sg_ll_readcap_16(sg_fd, false, 0, resp_buff, RCAP16_RESP_LEN, true, (vb ? (vb - 1): 0)); } if (0 == res) { if (vb > 3) hex2stderr(resp_buff, RCAP16_RESP_LEN, 1); block_size = sg_get_unaligned_be32(resp_buff + 8); prot_en = !!(resp_buff[12] & 0x1); op->xfer_len = block_size; if (prot_en && (op->wrprotect > 0)) op->xfer_len += 8; } else if ((SG_LIB_CAT_INVALID_OP == res) || (SG_LIB_CAT_ILLEGAL_REQ == res)) { if (vb) pr2serr("Read capacity(16) not supported, try Read " "capacity(10)\n"); res = sg_ll_readcap_10(sg_fd, false /* pmi */, 0 /* lba */, resp_buff, RCAP10_RESP_LEN, true, (vb ? (vb - 1): 0)); if (0 == res) { if (vb > 3) hex2stderr(resp_buff, RCAP10_RESP_LEN, 1); block_size = sg_get_unaligned_be32(resp_buff + 4); op->xfer_len = block_size; } else { sg_get_category_sense_str(res, sizeof(b), b, vb); pr2serr("Read capacity(10): %s\n", b); pr2serr("Unable to calculate block size\n"); } } else if (vb) { sg_get_category_sense_str(res, sizeof(b), b, vb); pr2serr("Read capacity(16): %s\n", b); pr2serr("Unable to calculate block size\n"); } } if (op->xfer_len < 1) { pr2serr("unable to deduce block size, please give '--xferlen=' " "argument\n"); ret = SG_LIB_SYNTAX_ERROR; goto err_out; } if (op->xfer_len > MAX_XFER_LEN) { pr2serr("'--xferlen=%d is out of range ( want <= %d)\n", op->xfer_len, MAX_XFER_LEN); ret = SG_LIB_SYNTAX_ERROR; goto err_out; } wBuff = (uint8_t *)sg_memalign(op->xfer_len, 0, &free_wBuff, vb > 3); if (NULL == wBuff) { pr2serr("unable to allocate %d bytes of memory with " "sg_memalign()\n", op->xfer_len); ret = sg_convert_errno(ENOMEM); goto err_out; } if (op->ifilename[0]) { if (got_stdin) { infd = STDIN_FILENO; if (sg_set_binary_mode(STDIN_FILENO) < 0) perror("sg_set_binary_mode"); } else { if ((infd = open(op->ifilename, O_RDONLY)) < 0) { ret = sg_convert_errno(errno); snprintf(ebuff, EBUFF_SZ, ME "could not open %.400s for " "reading", op->ifilename); perror(ebuff); goto err_out; } else if (sg_set_binary_mode(infd) < 0) perror("sg_set_binary_mode"); } res = read(infd, wBuff, op->xfer_len); if (res < 0) { ret = sg_convert_errno(errno); snprintf(ebuff, EBUFF_SZ, ME "couldn't read from %.400s", op->ifilename); perror(ebuff); if (! got_stdin) close(infd); goto err_out; } if (res < op->xfer_len) { pr2serr("tried to read %d bytes from %s, got %d bytes\n", op->xfer_len, op->ifilename, res); pr2serr(" so pad with 0x0 bytes and continue\n"); } if (! got_stdin) close(infd); } else { if (vb) pr2serr("Default data-out buffer set to %d zeros\n", op->xfer_len); if (prot_en && (op->wrprotect > 0)) { /* default for protection is 0xff, rest get 0x0 */ memset(wBuff + op->xfer_len - 8, 0xff, 8); if (vb) pr2serr(" ... apart from last 8 bytes which are set to " "0xff\n"); } } } ret = do_write_same(sg_fd, op, wBuff, &act_cdb_len); if (ret) { sg_get_category_sense_str(ret, sizeof(b), b, vb); pr2serr("Write same(%d): %s\n", act_cdb_len, b); } err_out: if (free_wBuff) free(free_wBuff); 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_write_same failed: ", ret)) pr2serr("Some error occurred, try again with '-v' " "or '-vv' for more information\n"); } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; }
printf(" %s: %d\n", pr_type_strs[7], !!(pr_buff[4] & 0x80)); /* WR_EX_AR */ printf(" %s: %d\n", pr_type_strs[6], !!(pr_buff[4] & 0x40)); /* EX_AC_RO */ printf(" %s: %d\n", pr_type_strs[5], !!(pr_buff[4] & 0x20)); /* WR_EX_RO */ printf(" %s: %d\n", pr_type_strs[3], !!(pr_buff[4] & 0x8)); /* EX_AC */ printf(" %s: %d\n", pr_type_strs[1], !!(pr_buff[4] & 0x2)); /* WR_EX */ printf(" %s: %d\n", pr_type_strs[8], !!(pr_buff[5] & 0x1)); /* EX_AC_AR */ } } } else { pr_gen = sg_get_unaligned_be32(pr_buff + 0); add_len = sg_get_unaligned_be32(pr_buff + 4); if (op->hex) { if (op->hex > 1) hex2stdout(pr_buff, add_len + 8, ((2 == op->hex) ? 1 : -1)); else { printf(" PR generation=0x%x, ", pr_gen); if (add_len <= 0) printf("Additional length=%d\n", add_len); if ((uint32_t)add_len > (op->alloc_len - 8)) { printf("Additional length too large=%d, truncate\n", add_len); hex2stdout((pr_buff + 8), op->alloc_len - 8, 1); } else { printf("Additional length=%d\n", add_len); hex2stdout((pr_buff + 8), add_len, 1);
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; }
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[]) { 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; }
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; }
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 helper_full_attr(const unsigned char * alp, int len, int id, const struct attr_name_info_t * anip, const struct opts_t * op) { int k; const unsigned char * bp; if (op->verbose) printf("[r%c] ", (0x80 & alp[2]) ? 'o' : 'w'); if (op->verbose > 3) pr2serr("%s: id=0x%x, len=%d, anip->format=%d, anip->len=%d\n", __func__, id, len, anip->format, anip->len); switch (id) { case 0x224: /* logical position of first encrypted block */ k = all_ffs_or_last_fe(alp + 5, len - 5); if (1 == k) printf("<unknown> [ff]\n"); else if (2 == k) printf("<unknown [fe]>\n"); else { if ((len - 5) <= 8) printf("%" PRIx64, sg_get_unaligned_be(len - 5, alp + 5)); else { printf("\n"); dStrHex((const char *)(alp + 5), len - 5, 0); } } break; case 0x225: /* logical position of first unencrypted block * after first encrypted block */ k = all_ffs_or_last_fe(alp + 5, len - 5); if (1 == k) printf("<unknown> [ff]\n"); else if (2 == k) printf("<unknown [fe]>\n"); else { if ((len - 5) <= 8) printf("%" PRIx64, sg_get_unaligned_be(len - 5, alp + 5)); else { printf("\n"); dStrHex((const char *)(alp + 5), len - 5, 0); } } break; case 0x340: /* Medium Usage history */ bp = alp + 5; printf("\n"); if ((len - 5) < 90) { pr2serr("%s: expected 90 bytes, got %d\n", __func__, len - 5); break; } printf(" Current amount of data written [MiB]: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 0)); printf(" Current write retry count: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 6)); printf(" Current amount of data read [MiB]: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 12)); printf(" Current read retry count: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 18)); printf(" Previous amount of data written [MiB]: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 24)); printf(" Previous write retry count: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 30)); printf(" Previous amount of data read [MiB]: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 36)); printf(" Previous read retry count: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 42)); printf(" Total amount of data written [MiB]: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 48)); printf(" Total write retry count: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 54)); printf(" Total amount of data read [MiB]: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 60)); printf(" Total read retry count: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 66)); printf(" Load count: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 72)); printf(" Total change partition count: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 78)); printf(" Total partition initialization count: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 84)); break; case 0x341: /* Partition Usage history */ bp = alp + 5; printf("\n"); if ((len - 5) < 60) { pr2serr("%s: expected 60 bytes, got %d\n", __func__, len - 5); break; } printf(" Current amount of data written [MiB]: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 0)); printf(" Current write retry count: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 4)); printf(" Current amount of data read [MiB]: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 8)); printf(" Current read retry count: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 12)); printf(" Previous amount of data written [MiB]: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 16)); printf(" Previous write retry count: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 20)); printf(" Previous amount of data read [MiB]: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 24)); printf(" Previous read retry count: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 28)); printf(" Total amount of data written [MiB]: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 32)); printf(" Total write retry count: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 36)); printf(" Total amount of data read [MiB]: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 40)); printf(" Total read retry count: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 44)); printf(" Load count: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 48)); printf(" change partition count: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 52)); printf(" partition initialization count: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 56)); break; default: pr2serr("%s: unknown attribute id: 0x%x\n", __func__, id); printf(" In hex:\n"); dStrHex((const char *)alp, len, 0); break; } }
int main(int argc, char * argv[]) { bool do_one_segment = false; bool o_readonly = false; bool do_raw = false; bool verbose_given = false; bool version_given = false; int k, res, c, rlen; int sg_fd = -1; int do_hex = 0; int maxlen = DEF_REFER_BUFF_LEN; int verbose = 0; int desc = 0; int ret = 0; int64_t ll; uint64_t lba = 0; const char * device_name = NULL; const uint8_t * bp; uint8_t * referralBuffp = referralBuff; uint8_t * free_referralBuffp = NULL; while (1) { int option_index = 0; c = getopt_long(argc, argv, "hHl:m:rRsvV", long_options, &option_index); if (c == -1) break; switch (c) { case 'h': case '?': usage(); return 0; case 'H': ++do_hex; break; case 'l': ll = sg_get_llnum(optarg); if (-1 == ll) { pr2serr("bad argument to '--lba'\n"); return SG_LIB_SYNTAX_ERROR; } lba = (uint64_t)ll; break; case 'm': maxlen = sg_get_num(optarg); if ((maxlen < 0) || (maxlen > MAX_REFER_BUFF_LEN)) { pr2serr("argument to '--maxlen' should be %d or less\n", MAX_REFER_BUFF_LEN); return SG_LIB_SYNTAX_ERROR; } break; case 's': do_one_segment = true; break; case 'r': do_raw = true; break; case 'R': o_readonly = true; break; case 'v': verbose_given = true; ++verbose; break; case 'V': version_given = true; break; default: pr2serr("unrecognised option code 0x%x ??\n", c); usage(); return SG_LIB_SYNTAX_ERROR; } } if (optind < argc) { if (NULL == device_name) { device_name = argv[optind]; ++optind; } if (optind < argc) { for (; optind < argc; ++optind) pr2serr("Unexpected extra argument: %s\n", argv[optind]); usage(); return SG_LIB_SYNTAX_ERROR; } } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (verbose_given && version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); verbose_given = false; version_given = false; verbose = 0; } else if (! verbose_given) { pr2serr("set '-vv'\n"); verbose = 2; } else pr2serr("keep verbose=%d\n", verbose); #else if (verbose_given && version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (version_given) { pr2serr("version: %s\n", version_str); return 0; } if (NULL == device_name) { pr2serr("No DEVICE argument given\n\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (maxlen > DEF_REFER_BUFF_LEN) { referralBuffp = (uint8_t *)sg_memalign(maxlen, 0, &free_referralBuffp, verbose > 3); if (NULL == referralBuffp) { pr2serr("unable to allocate %d bytes on heap\n", maxlen); return sg_convert_errno(ENOMEM); } } if (do_raw) { if (sg_set_binary_mode(STDOUT_FILENO) < 0) { perror("sg_set_binary_mode"); ret = SG_LIB_FILE_ERROR; goto free_buff; } } sg_fd = sg_cmds_open_device(device_name, o_readonly, verbose); if (sg_fd < 0) { if (verbose) pr2serr("open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); goto free_buff; } res = sg_ll_report_referrals(sg_fd, lba, do_one_segment, referralBuffp, maxlen, true, verbose); ret = res; if (0 == res) { if (maxlen >= 4) /* * This is strictly speaking incorrect. However, the * spec reserved bytes 0 and 1, so some implementations * might want to use them to increase the number of * possible user segments. * And maybe someone takes a pity and updates the spec ... */ rlen = sg_get_unaligned_be32(referralBuffp + 0) + 4; else rlen = maxlen; k = (rlen > maxlen) ? maxlen : rlen; if (do_raw) { dStrRaw(referralBuffp, k); goto the_end; } if (do_hex) { hex2stdout(referralBuffp, k, 1); goto the_end; } if (maxlen < 4) { if (verbose) pr2serr("Exiting because allocation length (maxlen) less " "than 4\n"); goto the_end; } if ((verbose > 1) || (verbose && (rlen > maxlen))) { pr2serr("response length %d bytes\n", rlen); if (rlen > maxlen) pr2serr(" ... which is greater than maxlen (allocation " "length %d), truncation\n", maxlen); } if (rlen > maxlen) rlen = maxlen; bp = referralBuffp + 4; k = 0; printf("Report referrals:\n"); while (k < rlen - 4) { printf(" descriptor %d:\n", desc); res = decode_referral_desc(bp + k, rlen - 4 - k); if (res < 0) { pr2serr("bad user data segment referral descriptor\n"); break; } k += res; desc++; } } else { char b[80]; sg_get_category_sense_str(res, sizeof(b), b, verbose); pr2serr("Report Referrals command failed: %s\n", b); } the_end: res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = sg_convert_errno(-res); } free_buff: if (free_referralBuffp) free(free_referralBuffp); if (0 == verbose) { if (! sg_if_can2stderr("sg_referrals failed: ", ret)) pr2serr("Some error occurred, try again with '-v' " "or '-vv' for more information\n"); } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; }
int main(int argc, char * argv[]) { 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 res, c, k, len, act_resplen; 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_ERR_LOG, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; unsigned char smp_resp[SMP_FN_REPORT_PHY_ERR_LOG_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 '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; if (verbose) { pr2serr(" Report phy error log 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 error log 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 error log result%s: %s\n", (phy_id_given ? "" : " (for phy_id=0)"), cp); ret = smp_resp[2]; goto err_out; } printf("Report phy error log response:\n"); res = sg_get_unaligned_be16(smp_resp + 4); if (verbose || res) printf(" Expander change count: %d\n", res); printf(" phy identifier: %d\n", smp_resp[9]); printf(" invalid dword count: %u\n", sg_get_unaligned_be32(smp_resp + 12)); printf(" running disparity error count: %u\n", sg_get_unaligned_be32(smp_resp + 16)); printf(" loss of dword synchronization count: %u\n", sg_get_unaligned_be32(smp_resp + 20)); printf(" phy reset problem count: %u\n", sg_get_unaligned_be32(smp_resp + 24)); 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; }