Example #1
0
/* 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);
    }
Example #2
0
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 {
Example #3
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;
}
Example #4
0
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;
}
Example #5
0
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;
}
Example #6
0
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;
}
Example #7
0
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;
}
Example #8
0
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;
}
Example #9
0
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;
}
Example #10
0
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;
}