/* Yields most of first 36 bytes of a standard INQUIRY (evpd==0) response. * Returns 0 when successful, various SG_LIB_CAT_* positive values, negated * errno or -1 -> other errors */ int sg_simple_inquiry(int sg_fd, struct sg_simple_inquiry_resp * inq_data, bool noisy, int verbose) { int ret; uint8_t * inq_resp = NULL; uint8_t * free_irp = NULL; if (inq_data) { memset(inq_data, 0, sizeof(* inq_data)); inq_data->peripheral_qualifier = 0x3; inq_data->peripheral_type = 0x1f; } inq_resp = sg_memalign(SAFE_STD_INQ_RESP_LEN, 0, &free_irp, verbose > 4); if (NULL == inq_resp) { pr2ws("%s: out of memory\n", __func__); return sg_convert_errno(ENOMEM); } ret = sg_ll_inquiry_v2(sg_fd, false, 0, inq_resp, SAFE_STD_INQ_RESP_LEN, 0, NULL, noisy, verbose); if (inq_data && (0 == ret)) { inq_data->peripheral_qualifier = (inq_resp[0] >> 5) & 0x7; inq_data->peripheral_type = inq_resp[0] & 0x1f; inq_data->byte_1 = inq_resp[1]; inq_data->version = inq_resp[2]; inq_data->byte_3 = inq_resp[3]; inq_data->byte_5 = inq_resp[5]; inq_data->byte_6 = inq_resp[6]; inq_data->byte_7 = inq_resp[7]; memcpy(inq_data->vendor, inq_resp + 8, 8); memcpy(inq_data->product, inq_resp + 16, 16); memcpy(inq_data->revision, inq_resp + 32, 4); }
static int prin_work(int sg_fd, const struct opts_t * op) { int k, j, num, add_len, add_desc_len; int res = 0; unsigned int pr_gen; uint8_t * bp; uint8_t * pr_buff = NULL; uint8_t * free_pr_buff = NULL; pr_buff = sg_memalign(op->alloc_len, 0 /* page aligned */, &free_pr_buff, false); if (NULL == pr_buff) { pr2serr("%s: unable to allocate %d bytes on heap\n", __func__, op->alloc_len); return sg_convert_errno(ENOMEM); } res = sg_ll_persistent_reserve_in(sg_fd, op->prin_sa, pr_buff, op->alloc_len, true, op->verbose); if (res) { char b[64]; char bb[80]; if (op->prin_sa < num_prin_sa_strs) snprintf(b, sizeof(b), "%s", prin_sa_strs[op->prin_sa]); else snprintf(b, sizeof(b), "service action=0x%x", op->prin_sa); if (SG_LIB_CAT_INVALID_OP == res) pr2serr("PR in (%s): command not supported\n", b); else if (SG_LIB_CAT_ILLEGAL_REQ == res) pr2serr("PR in (%s): bad field in cdb or parameter list (perhaps " "unsupported service action)\n", b); else { sg_get_category_sense_str(res, sizeof(bb), bb, op->verbose); pr2serr("PR in (%s): %s\n", b, bb); } goto fini; } if (PRIN_RCAP_SA == op->prin_sa) { if (8 != pr_buff[1]) { pr2serr("Unexpected response for PRIN Report Capabilities\n"); if (op->hex) hex2stdout(pr_buff, pr_buff[1], 1); res = SG_LIB_CAT_MALFORMED; goto fini; } if (op->hex) hex2stdout(pr_buff, 8, 1); else { printf("Report capabilities response:\n"); printf(" Replace Lost Reservation Capable(RLR_C): %d\n", !!(pr_buff[2] & 0x80)); /* added spc4r26 */ printf(" Compatible Reservation Handling(CRH): %d\n", !!(pr_buff[2] & 0x10)); printf(" Specify Initiator Ports Capable(SIP_C): %d\n", !!(pr_buff[2] & 0x8)); printf(" All Target Ports Capable(ATP_C): %d\n", !!(pr_buff[2] & 0x4)); printf(" Persist Through Power Loss Capable(PTPL_C): %d\n", !!(pr_buff[2] & 0x1)); printf(" Type Mask Valid(TMV): %d\n", !!(pr_buff[3] & 0x80)); printf(" Allow Commands: %d\n", (pr_buff[3] >> 4) & 0x7); printf(" Persist Through Power Loss Active(PTPL_A): %d\n", !!(pr_buff[3] & 0x1)); if (pr_buff[3] & 0x80) { printf(" Support indicated in Type mask:\n"); 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 {
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; }
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[]) { bool do_16 = false; bool dpo = false; bool first_time; bool given_do_16 = false; bool has_filename = false; bool lba_given = false; bool repeat = false; bool verbose_given = false; bool version_given = false; int sg_fd, res, c, n; int bytchk = 0; int group = 0; int ilen = -1; int ifd = -1; int b_p_lb = 512; int ret = 1; int timeout = DEF_TIMEOUT_SECS; int tnum_lb_wr = 0; int verbose = 0; int wrprotect = 0; uint32_t num_lb = 1; uint32_t snum_lb = 1; uint64_t llba = 0; int64_t ll; uint8_t * wvb = NULL; uint8_t * wrkBuff = NULL; uint8_t * free_wrkBuff = NULL; const char * device_name = NULL; const char * ifnp; char cmd_name[32]; ifnp = ""; /* keep MinGW quiet */ while (1) { int option_index = 0; c = getopt_long(argc, argv, "b:dg:hi:I:l:n:RSt:w:vV", long_options, &option_index); if (c == -1) break; switch (c) { case 'b': /* Only bytchk=0 and =1 are meaningful for this command in * sbc4r02 (not =2 nor =3) but that may change in the future. */ bytchk = sg_get_num(optarg); if ((bytchk < 0) || (bytchk > 3)) { pr2serr("argument to '--bytchk' expected to be 0 to 3\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'd': dpo = true; break; case 'g': group = sg_get_num(optarg); if ((group < 0) || (group > 63)) { pr2serr("argument to '--group' expected to be 0 to 63\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'h': case '?': usage(); return 0; case 'i': ifnp = optarg; has_filename = true; break; case 'I': ilen = sg_get_num(optarg); if (-1 == ilen) { pr2serr("bad argument to '--ilen'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'l': if (lba_given) { pr2serr("must have one and only one '--lba'\n"); return SG_LIB_SYNTAX_ERROR; } ll = sg_get_llnum(optarg); if (ll < 0) { pr2serr("bad argument to '--lba'\n"); return SG_LIB_SYNTAX_ERROR; } llba = (uint64_t)ll; lba_given = true; break; case 'n': n = sg_get_num(optarg); if (-1 == n) { pr2serr("bad argument to '--num'\n"); return SG_LIB_SYNTAX_ERROR; } num_lb = (uint32_t)n; break; case 'R': repeat = true; break; case 'S': do_16 = true; given_do_16 = true; break; case 't': timeout = sg_get_num(optarg); if (timeout < 1) { pr2serr("bad argument to '--timeout'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'v': verbose_given = true; ++verbose; break; case 'V': version_given = true; break; case 'w': wrprotect = sg_get_num(optarg); if ((wrprotect < 0) || (wrprotect > 7)) { pr2serr("wrprotect (%d) is out of range ( < %d)\n", wrprotect, 7); 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; } } #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(ME "version: %s\n", version_str); return 0; } if (NULL == device_name) { pr2serr("Missing device name!\n\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (! lba_given) { pr2serr("need a --lba=LBA option\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (repeat) { if (! has_filename) { pr2serr("with '--repeat' need '--in=IF' option\n"); usage(); return SG_LIB_CONTRADICT; } if (ilen < 1) { pr2serr("with '--repeat' need '--ilen=ILEN' option\n"); usage(); return SG_LIB_CONTRADICT; } else { b_p_lb = ilen / num_lb; if (b_p_lb < 64) { pr2serr("calculated %d bytes per logical block, too small\n", b_p_lb); usage(); return SG_LIB_SYNTAX_ERROR; } } } sg_fd = sg_cmds_open_device(device_name, false /* rw */, verbose); if (sg_fd < 0) { ret = sg_convert_errno(-sg_fd); pr2serr(ME "open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); goto err_out; } if ((! do_16) && (llba > UINT_MAX)) do_16 = true; if ((! do_16) && (num_lb > 0xffff)) do_16 = true; snprintf(cmd_name, sizeof(cmd_name), "Write and verify(%d)", (do_16 ? 16 : 10)); if (verbose && (! given_do_16) && do_16) pr2serr("Switching to %s because LBA or NUM too large\n", cmd_name); if (verbose) { pr2serr("Issue %s to device %s\n\tilen=%d", cmd_name, device_name, ilen); if (ilen > 0) pr2serr(" [0x%x]", ilen); pr2serr(", lba=%" PRIu64 " [0x%" PRIx64 "]\n\twrprotect=%d, dpo=%d, " "bytchk=%d, group=%d, repeat=%d\n", llba, llba, wrprotect, (int)dpo, bytchk, group, (int)repeat); } first_time = true; do { if (first_time) { //If a file with data to write has been provided if (has_filename) { struct stat a_stat; if ((1 == strlen(ifnp)) && ('-' == ifnp[0])) { ifd = STDIN_FILENO; ifnp = "<stdin>"; if (verbose > 1) pr2serr("Reading input data from stdin\n"); } else { ifd = open_if(ifnp, 0); if (ifd < 0) { ret = -ifd; goto err_out; } } if (ilen < 1) { if (fstat(ifd, &a_stat) < 0) { pr2serr("Could not fstat(%s)\n", ifnp); goto err_out; } if (! S_ISREG(a_stat.st_mode)) { pr2serr("Cannot determine IF size, please give " "'--ilen='\n"); goto err_out; } ilen = (int)a_stat.st_size; if (ilen < 1) { pr2serr("%s file size too small\n", ifnp); goto err_out; } else if (verbose) pr2serr("Using file size of %d bytes\n", ilen); } if (NULL == (wrkBuff = (uint8_t *)sg_memalign(ilen, 0, &free_wrkBuff, verbose > 3))) { pr2serr(ME "out of memory\n"); ret = sg_convert_errno(ENOMEM); goto err_out; } wvb = (uint8_t *)wrkBuff; res = read(ifd, wvb, ilen); if (res < 0) { pr2serr("Could not read from %s", ifnp); goto err_out; } if (res < ilen) { pr2serr("Read only %d bytes (expected %d) from %s\n", res, ilen, ifnp); if (repeat) pr2serr("Will scale subsequent pieces when " "repeat=true, but this is first\n"); goto err_out; } } else { if (ilen < 1) { if (verbose) pr2serr("Default write length to %d*%d=%d bytes\n", num_lb, 512, 512 * num_lb); ilen = 512 * num_lb; } if (NULL == (wrkBuff = (uint8_t *)sg_memalign(ilen, 0, &free_wrkBuff, verbose > 3))) { pr2serr(ME "out of memory\n"); ret = sg_convert_errno(ENOMEM); goto err_out; } wvb = (uint8_t *)wrkBuff; /* Not sure about this: default contents to 0xff bytes */ memset(wrkBuff, 0xff, ilen); } first_time = false; snum_lb = num_lb; } else { /* repeat=true, first_time=false, must be reading file */ llba += snum_lb; res = read(ifd, wvb, ilen); if (res < 0) { pr2serr("Could not read from %s", ifnp); goto err_out; } else { if (verbose > 1) pr2serr("Subsequent read from %s got %d bytes\n", ifnp, res); if (0 == res) break; if (res < ilen) { snum_lb = (uint32_t)(res / b_p_lb); n = res % b_p_lb; if (0 != n) pr2serr(">>> warning: ignoring last %d bytes of %s\n", n, ifnp); if (snum_lb < 1) break; } } } if (do_16) res = sg_ll_write_verify16(sg_fd, wrprotect, dpo, bytchk, llba, snum_lb, group, wvb, ilen, timeout, verbose > 0, verbose); else res = sg_ll_write_verify10(sg_fd, wrprotect, dpo, bytchk, (unsigned int)llba, snum_lb, group, wvb, ilen, timeout, verbose > 0, verbose); ret = res; if (repeat && (0 == ret)) tnum_lb_wr += snum_lb; if (ret || (snum_lb != num_lb)) break; } while (repeat); err_out: if (repeat) pr2serr("%d [0x%x] logical blocks written, in total\n", tnum_lb_wr, tnum_lb_wr); if (free_wrkBuff) free(free_wrkBuff); if ((ifd >= 0) && (STDIN_FILENO != ifd)) close(ifd); 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 (ret && (0 == verbose)) { if (! sg_if_can2stderr("sg_write_verify 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 verbose_given = true; bool version_given = true; int sg_fd, res; const char * device_name = NULL; int times = 1; int ret = 0; int k = 0; int err; while (1) { int option_index = 0; int c; c = getopt_long(argc, argv, "hqr:s:t:w:vV", long_options, &option_index); if (c == -1) break; switch (c) { case 'h': usage(); return 0; case 'q': do_quick = true; break; case 'r': addread = sg_get_num(optarg); if (-1 == addread) { pr2serr("bad argument to '--addrd'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 's': size = sg_get_num(optarg); if (-1 == size) { pr2serr("bad argument to '--size'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 't': times = sg_get_num(optarg); if (-1 == times) { pr2serr("bad argument to '--times'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'v': verbose_given = true; verbose++; break; case 'V': version_given = true; break; case 'w': addwrite = sg_get_num(optarg); if (-1 == addwrite) { pr2serr("bad argument to '--addwr'\n"); return SG_LIB_SYNTAX_ERROR; } break; default: usage(); return SG_LIB_SYNTAX_ERROR; } } if (optind < argc) { if (NULL == device_name) { device_name = argv[optind]; ++optind; } } if (optind < argc) { if (-1 == size) { size = sg_get_num(argv[optind]); if (-1 == size) { pr2serr("bad <sz>\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (++optind < argc) { addwrite = sg_get_num(argv[optind]); if (-1 == addwrite) { pr2serr("bad [addwr]\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (++optind < argc) { addread = sg_get_num(argv[optind]); if (-1 == addread) { pr2serr("bad [addrd]\n"); usage(); return SG_LIB_SYNTAX_ERROR; } } } } 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(ME "version: %s\n", version_str); return 0; } if (NULL == device_name) { pr2serr("no device name given\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if ((size <= 0) && (! do_quick)) { pr2serr("must give '--size' or '--quick' options or <sz> " "argument\n"); usage(); return SG_LIB_SYNTAX_ERROR; } sg_fd = open(device_name, O_RDWR | O_NONBLOCK); if (sg_fd < 0) { err = errno; perror("sg_test_rwbuf: open error"); return sg_convert_errno(err); } ret = find_out_about_buffer(sg_fd); if (ret) goto err_out; if (do_quick) { printf ("READ BUFFER read descriptor reports a buffer " "of %d bytes [%d KiB]\n", buf_capacity, buf_capacity / 1024); goto err_out; } if (size > buf_capacity) { pr2serr (ME "sz=%i > buf_capacity=%i\n", size, buf_capacity); ret = SG_LIB_CAT_OTHER; goto err_out; } cmpbuf = (uint8_t *)sg_memalign(size, 0, &free_cmpbuf, false); for (k = 0; k < times; ++k) { ret = write_buffer (sg_fd, size); if (ret) { goto err_out; } ret = read_buffer (sg_fd, size); if (ret) { if (2222 == ret) ret = SG_LIB_CAT_MALFORMED; goto err_out; } } err_out: if (free_cmpbuf) free(free_cmpbuf); res = close(sg_fd); if (res < 0) { perror(ME "close error"); if (0 == ret) ret = sg_convert_errno(errno); } if ((0 == ret) && (! do_quick)) printf ("Success\n"); else if (times > 1) printf ("Failed after %d successful cycles\n", k); return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; }
int write_buffer (int sg_fd, unsigned ssize) { uint8_t wb_cdb[] = {WRITE_BUFFER, 0, 0, 0, 0, 0, 0, 0, 0, 0}; int bufSize = ssize + addwrite; uint8_t * free_wbBuff = NULL; uint8_t * wbBuff = (uint8_t *)sg_memalign(bufSize, 0, &free_wbBuff, false); uint8_t sense_buffer[32]; struct sg_io_hdr io_hdr; int k, res; if (NULL == wbBuff) return -1; memset(wbBuff, 0, bufSize); do_fill_buffer ((int*)wbBuff, ssize); wb_cdb[1] = RWB_MODE_DATA; sg_put_unaligned_be24((uint32_t)bufSize, wb_cdb + 6); memset(&io_hdr, 0, sizeof(struct sg_io_hdr)); io_hdr.interface_id = 'S'; io_hdr.cmd_len = sizeof(wb_cdb); io_hdr.mx_sb_len = sizeof(sense_buffer); io_hdr.dxfer_direction = SG_DXFER_TO_DEV; io_hdr.dxfer_len = bufSize; io_hdr.dxferp = wbBuff; io_hdr.cmdp = wb_cdb; io_hdr.sbp = sense_buffer; io_hdr.pack_id = 1; io_hdr.timeout = 60000; /* 60000 millisecs == 60 seconds */ if (verbose) { pr2serr(" write buffer [mode data] cdb: "); for (k = 0; k < (int)sizeof(wb_cdb); ++k) pr2serr("%02x ", wb_cdb[k]); pr2serr("\n"); } if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { perror(ME "SG_IO WRITE BUFFER data error"); free(wbBuff); return -1; } /* now for the error processing */ res = sg_err_category3(&io_hdr); switch (res) { case SG_LIB_CAT_RECOVERED: sg_chk_n_print3("WRITE BUFFER data, continuing", &io_hdr, true); #if defined(__GNUC__) #if (__GNUC__ >= 7) __attribute__((fallthrough)); /* FALL THROUGH */ #endif #endif case SG_LIB_CAT_CLEAN: break; default: /* won't bother decoding other categories */ sg_chk_n_print3("WRITE BUFFER data error", &io_hdr, true); free(wbBuff); return res; } if (free_wbBuff) free(free_wbBuff); return res; }
int main(int argc, char * argv[]) { bool correct = false; bool do_16 = false; bool pblock = false; bool readonly = false; bool got_stdout; bool verbose_given = false; bool version_given = false; int outfd, res, c; int sg_fd = -1; int ret = 0; int xfer_len = 520; int verbose = 0; uint64_t llba = 0; int64_t ll; uint8_t * readLongBuff = NULL; uint8_t * rawp = NULL; uint8_t * free_rawp = NULL; const char * device_name = NULL; char out_fname[256]; char ebuff[EBUFF_SZ]; memset(out_fname, 0, sizeof out_fname); while (1) { int option_index = 0; c = getopt_long(argc, argv, "chl:o:prSvVx:", long_options, &option_index); if (c == -1) break; switch (c) { case 'c': correct = true; break; case 'h': case '?': usage(); return 0; case 'l': ll = sg_get_llnum(optarg); if (-1 == ll) { pr2serr("bad argument to '--lba'\n"); return SG_LIB_SYNTAX_ERROR; } llba = (uint64_t)ll; break; case 'o': strncpy(out_fname, optarg, sizeof(out_fname) - 1); break; case 'p': pblock = true; break; case 'r': readonly = true; break; case 'S': do_16 = true; break; case 'v': verbose_given = true; ++verbose; break; case 'V': version_given = true; break; case 'x': xfer_len = sg_get_num(optarg); if (-1 == xfer_len) { pr2serr("bad argument to '--xfer_len'\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; } } #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(ME "version: %s\n", version_str); return 0; } if (NULL == device_name) { pr2serr("Missing device name!\n\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (xfer_len >= MAX_XFER_LEN){ pr2serr("xfer_len (%d) is out of range ( < %d)\n", xfer_len, MAX_XFER_LEN); usage(); return SG_LIB_SYNTAX_ERROR; } sg_fd = sg_cmds_open_device(device_name, readonly, verbose); if (sg_fd < 0) { if (verbose) pr2serr(ME "open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); goto err_out; } if (NULL == (rawp = (uint8_t *)sg_memalign(MAX_XFER_LEN, 0, &free_rawp, false))) { if (verbose) pr2serr(ME "out of memory\n"); ret = sg_convert_errno(ENOMEM); goto err_out; } readLongBuff = (uint8_t *)rawp; memset(rawp, 0x0, MAX_XFER_LEN); pr2serr(ME "issue read long (%s) to device %s\n xfer_len=%d (0x%x), " "lba=%" PRIu64 " (0x%" PRIx64 "), correct=%d\n", (do_16 ? "16" : "10"), device_name, xfer_len, xfer_len, llba, llba, (int)correct); if ((ret = process_read_long(sg_fd, do_16, pblock, correct, llba, readLongBuff, xfer_len, verbose))) goto err_out; if ('\0' == out_fname[0]) hex2stdout((const uint8_t *)rawp, xfer_len, 0); else { got_stdout = (0 == strcmp(out_fname, "-")); if (got_stdout) outfd = STDOUT_FILENO; else { if ((outfd = open(out_fname, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) { snprintf(ebuff, EBUFF_SZ, ME "could not open %s for writing", out_fname); perror(ebuff); goto err_out; } } if (sg_set_binary_mode(outfd) < 0) { perror("sg_set_binary_mode"); goto err_out; } res = write(outfd, readLongBuff, xfer_len); if (res < 0) { snprintf(ebuff, EBUFF_SZ, ME "couldn't write to %s", out_fname); perror(ebuff); goto err_out; } if (! got_stdout) close(outfd); } err_out: if (free_rawp) free(free_rawp); 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_long 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_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; }