예제 #1
0
/* Invokes a SCSI SYNCHRONIZE CACHE (10) command. Return of 0 -> success,
 * various SG_LIB_CAT_* positive values or -1 -> other errors */
int
sg_ll_sync_cache_10(int sg_fd, int sync_nv, int immed, int group,
                    unsigned int lba, unsigned int count, int noisy,
                    int verbose)
{
    static const char * const cdb_name_s = "synchronize cache(10)";
    int res, ret, k, sense_cat;
    unsigned char sc_cdb[SYNCHRONIZE_CACHE_CMDLEN] =
                {SYNCHRONIZE_CACHE_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    unsigned char sense_b[SENSE_BUFF_LEN];
    struct sg_pt_base * ptvp;

    if (sync_nv)
        sc_cdb[1] |= 4;
    if (immed)
        sc_cdb[1] |= 2;
    sg_put_unaligned_be32((uint32_t)lba, sc_cdb + 2);
    sc_cdb[6] = group & 0x1f;
    if (count > 0xffff) {
        pr2ws("count too big\n");
        return -1;
    }
    sg_put_unaligned_be16((int16_t)count, sc_cdb + 7);

    if (verbose) {
        pr2ws("    %s cdb: ", cdb_name_s);
        for (k = 0; k < SYNCHRONIZE_CACHE_CMDLEN; ++k)
            pr2ws("%02x ", sc_cdb[k]);
        pr2ws("\n");
    }
    if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
        return -1;
    set_scsi_pt_cdb(ptvp, sc_cdb, sizeof(sc_cdb));
    set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
    res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
    ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, 0, sense_b, noisy,
                               verbose, &sense_cat);
    if (-1 == ret)
        ;
    else if (-2 == ret) {
        switch (sense_cat) {
        case SG_LIB_CAT_RECOVERED:
        case SG_LIB_CAT_NO_SENSE:
            ret = 0;
            break;
        default:
            ret = sense_cat;
            break;
        }
    } else
        ret = 0;

    destruct_scsi_pt_obj(ptvp);
    return ret;
}
예제 #2
0
static int
ll_sync_cache_16(int sg_fd, int sync_nv, int immed, int group,
                 uint64_t lba, unsigned int num_lb, int to_secs,
                 int noisy, int verbose)
{
    int res, ret, k, sense_cat;
    unsigned char sc_cdb[SYNCHRONIZE_CACHE16_CMDLEN] =
    {   SYNCHRONIZE_CACHE16_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0
    };
    unsigned char sense_b[SENSE_BUFF_LEN];
    struct sg_pt_base * ptvp;

    if (sync_nv)
        sc_cdb[1] |= 4;       /* obsolete in sbc3r35d */
    if (immed)
        sc_cdb[1] |= 2;
    sg_put_unaligned_be64(lba, sc_cdb + 2);
    sc_cdb[14] = group & 0x1f;
    sg_put_unaligned_be32((uint32_t)num_lb, sc_cdb + 10);

    if (verbose) {
        pr2serr("    synchronize cache(16) cdb: ");
        for (k = 0; k < SYNCHRONIZE_CACHE16_CMDLEN; ++k)
            pr2serr("%02x ", sc_cdb[k]);
        pr2serr("\n");
    }
    ptvp = construct_scsi_pt_obj();
    if (NULL == ptvp) {
        pr2serr("synchronize cache(16): out of memory\n");
        return -1;
    }
    set_scsi_pt_cdb(ptvp, sc_cdb, sizeof(sc_cdb));
    set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
    res = do_scsi_pt(ptvp, sg_fd, to_secs, verbose);
    ret = sg_cmds_process_resp(ptvp, "synchronize cache(16)", res, 0,
                               sense_b, noisy, verbose, &sense_cat);
    if (-1 == ret)
        ;
    else if (-2 == ret) {
        switch (sense_cat) {
        case SG_LIB_CAT_RECOVERED:
        case SG_LIB_CAT_NO_SENSE:
            ret = 0;
            break;
        default:
            ret = sense_cat;
            break;
        }
    } else
        ret = 0;

    destruct_scsi_pt_obj(ptvp);
    return ret;
}
예제 #3
0
/* Invokes a SCSI REPORT TIMESTAMP command.  Return of 0 -> success,
 * various SG_LIB_CAT_* positive values or -1 -> other errors */
static int
sg_ll_rep_timestamp(int sg_fd, void * resp, int mx_resp_len, int * residp,
                    int noisy, int verbose)
{
    int k, ret, res, sense_cat;
    unsigned char rtCmdBlk[REP_TIMESTAMP_CMDLEN] =
          {SG_MAINTENANCE_IN, REP_TIMESTAMP_SA, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0};
    unsigned char sense_b[SENSE_BUFF_LEN];
    struct sg_pt_base * ptvp;

    sg_put_unaligned_be32((uint32_t)mx_resp_len, rtCmdBlk + 6);
    if (verbose) {
        pr2serr("    Report timestamp cdb: ");
        for (k = 0; k < REP_TIMESTAMP_CMDLEN; ++k)
            pr2serr("%02x ", rtCmdBlk[k]);
        pr2serr("\n");
    }

    ptvp = construct_scsi_pt_obj();
    if (NULL == ptvp) {
        pr2serr("%s: out of memory\n", __func__);
        return -1;
    }
    set_scsi_pt_cdb(ptvp, rtCmdBlk, sizeof(rtCmdBlk));
    set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
    set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
    res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
    ret = sg_cmds_process_resp(ptvp, "report timestamp", res, mx_resp_len,
                               sense_b, noisy, verbose, &sense_cat);
    if (-1 == ret)
        ;
    else if (-2 == ret) {
        switch (sense_cat) {
        case SG_LIB_CAT_RECOVERED:
        case SG_LIB_CAT_NO_SENSE:
            ret = 0;
            break;
        default:
            ret = sense_cat;
            break;
        }
    } else
        ret = 0;
    k = get_scsi_pt_resid(ptvp);
    if (residp)
        *residp = k;
    if ((verbose > 2) && ((mx_resp_len - k) > 0)) {
        pr2serr("Parameter data returned:\n");
        dStrHexErr((const char *)resp, mx_resp_len - k,
                   ((verbose > 3) ? -1 : 1));
    }
    destruct_scsi_pt_obj(ptvp);
    return ret;
}
예제 #4
0
/* Invokes the SET TIMESTAMP command.  Return of 0 -> success, various
 * SG_LIB_CAT_* positive values or -1 -> other errors */
static int
sg_ll_set_timestamp(int sg_fd, void * paramp, int param_len, int noisy,
                    int verbose)
{
    int k, ret, res, sense_cat;
    unsigned char stCmdBlk[SET_TIMESTAMP_CMDLEN] =
          {SG_MAINTENANCE_OUT, SET_TIMESTAMP_SA, 0, 0,  0, 0, 0, 0,
           0, 0, 0, 0};
    unsigned char sense_b[SENSE_BUFF_LEN];
    struct sg_pt_base * ptvp;

    sg_put_unaligned_be32(param_len, stCmdBlk + 6);
    if (verbose) {
        pr2serr("    Set timestamp cdb: ");
        for (k = 0; k < SET_TIMESTAMP_CMDLEN; ++k)
            pr2serr("%02x ", stCmdBlk[k]);
        pr2serr("\n");
        if ((verbose > 1) && paramp && param_len) {
            pr2serr("    set timestamp parameter list:\n");
            dStrHexErr((const char *)paramp, param_len, -1);
        }
    }

    ptvp = construct_scsi_pt_obj();
    if (NULL == ptvp) {
        pr2serr("%s: out of memory\n", __func__);
        return -1;
    }
    set_scsi_pt_cdb(ptvp, stCmdBlk, sizeof(stCmdBlk));
    set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
    set_scsi_pt_data_out(ptvp, (unsigned char *)paramp, param_len);
    res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
    ret = sg_cmds_process_resp(ptvp, "set timestamp", res, 0, sense_b, noisy,
                               verbose, &sense_cat);
    if (-1 == ret)
        ;
    else if (-2 == ret) {
        switch (sense_cat) {
        case SG_LIB_CAT_RECOVERED:
        case SG_LIB_CAT_NO_SENSE:
            ret = 0;
            break;
        default:
            ret = sense_cat;
            break;
        }
    } else
        ret = 0;
    destruct_scsi_pt_obj(ptvp);
    return ret;
}
예제 #5
0
/* Invokes a SCSI READ CAPACITY (16) command. Returns 0 -> success,
 * various SG_LIB_CAT_* positive values or -1 -> other errors */
int
sg_ll_readcap_16(int sg_fd, int pmi, uint64_t llba, void * resp,
                 int mx_resp_len, int noisy, int verbose)
{
    static const char * const cdb_name_s = "read capacity(16)";
    int k, ret, res, sense_cat;
    unsigned char rc_cdb[SERVICE_ACTION_IN_16_CMDLEN] =
                        {SERVICE_ACTION_IN_16_CMD, READ_CAPACITY_16_SA,
                         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    unsigned char sense_b[SENSE_BUFF_LEN];
    struct sg_pt_base * ptvp;

    if (pmi) { /* lbs only valid when pmi set */
        rc_cdb[14] |= 1;
        sg_put_unaligned_be64(llba, rc_cdb + 2);
    }
    /* Allocation length, no guidance in SBC-2 rev 15b */
    sg_put_unaligned_be32((uint32_t)mx_resp_len, rc_cdb + 10);
    if (verbose) {
        pr2ws("    %s cdb: ", cdb_name_s);
        for (k = 0; k < SERVICE_ACTION_IN_16_CMDLEN; ++k)
            pr2ws("%02x ", rc_cdb[k]);
        pr2ws("\n");
    }
    if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
        return -1;
    set_scsi_pt_cdb(ptvp, rc_cdb, sizeof(rc_cdb));
    set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
    set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
    res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
    ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, mx_resp_len, sense_b,
                               noisy, verbose, &sense_cat);
    if (-1 == ret)
        ;
    else if (-2 == ret) {
        switch (sense_cat) {
        case SG_LIB_CAT_RECOVERED:
        case SG_LIB_CAT_NO_SENSE:
            ret = 0;
            break;
        default:
            ret = sense_cat;
            break;
        }
    } else
        ret = 0;

    destruct_scsi_pt_obj(ptvp);
    return ret;
}
예제 #6
0
/* Invokes a SCSI READ CAPACITY (10) command. Returns 0 -> success,
 * various SG_LIB_CAT_* positive values or -1 -> other errors */
int
sg_ll_readcap_10(int sg_fd, bool pmi, unsigned int lba, void * resp,
                 int mx_resp_len, bool noisy, int verbose)
{
    static const char * const cdb_s = "read capacity(10)";
    int k, ret, res, sense_cat;
    uint8_t rc_cdb[READ_CAPACITY_10_CMDLEN] =
                         {READ_CAPACITY_10_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    uint8_t sense_b[SENSE_BUFF_LEN];
    struct sg_pt_base * ptvp;

    if (pmi) { /* lbs only valid when pmi set */
        rc_cdb[8] |= 1;
        sg_put_unaligned_be32((uint32_t)lba, rc_cdb + 2);
    }
    if (verbose) {
        pr2ws("    %s cdb: ", cdb_s);
        for (k = 0; k < READ_CAPACITY_10_CMDLEN; ++k)
            pr2ws("%02x ", rc_cdb[k]);
        pr2ws("\n");
    }
    if (NULL == ((ptvp = create_pt_obj(cdb_s))))
        return -1;
    set_scsi_pt_cdb(ptvp, rc_cdb, sizeof(rc_cdb));
    set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
    set_scsi_pt_data_in(ptvp, (uint8_t *)resp, mx_resp_len);
    res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
    ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, verbose, &sense_cat);
    if (-1 == ret)
        ret = sg_convert_errno(get_scsi_pt_os_err(ptvp));
    else if (-2 == ret) {
        switch (sense_cat) {
        case SG_LIB_CAT_RECOVERED:
        case SG_LIB_CAT_NO_SENSE:
            ret = 0;
            break;
        default:
            ret = sense_cat;
            break;
        }
    } else
        ret = 0;

    destruct_scsi_pt_obj(ptvp);
    return ret;
}
예제 #7
0
static int
sg_start_io(Rq_elem * rep)
{
    sg_io_hdr_t * hp = &rep->io_hdr;
    int res;

    rep->qstate = rep->wr ? QS_OUT_STARTED : QS_IN_STARTED;
    memset(rep->cmd, 0, sizeof(rep->cmd));
    rep->cmd[0] = rep->wr ? SGP_WRITE10 : SGP_READ10;
    sg_put_unaligned_be32((uint32_t)rep->blk, rep->cmd + 2);
    sg_put_unaligned_be16((uint16_t)rep->num_blks, rep->cmd + 7);
    memset(hp, 0, sizeof(sg_io_hdr_t));
    hp->interface_id = 'S';
    hp->cmd_len = sizeof(rep->cmd);
    hp->cmdp = rep->cmd;
    hp->dxfer_direction = rep->wr ? SG_DXFER_TO_DEV : SG_DXFER_FROM_DEV;
    hp->dxfer_len = rep->bs * rep->num_blks;
    hp->dxferp = rep->buffp;
    hp->mx_sb_len = sizeof(rep->sb);
    hp->sbp = rep->sb;
    hp->timeout = DEF_TIMEOUT;
    hp->usr_ptr = rep;
    hp->pack_id = rep->blk;
    if (rep->dio)
        hp->flags |= SG_FLAG_DIRECT_IO;
    if (rep->debug > 8) {
        fprintf(stderr, "sg_start_io: SCSI %s, blk=%d num_blks=%d\n",
               rep->wr ? "WRITE" : "READ", rep->blk, rep->num_blks);
        sg_print_command(hp->cmdp);
        fprintf(stderr, " len=%d, dxfrp=%p, cmd_len=%d\n",
                hp->dxfer_len, hp->dxferp, hp->cmd_len);
    }

    while (((res = write(rep->wr ? rep->outfd : rep->infd, hp,
                         sizeof(sg_io_hdr_t))) < 0) && (EINTR == errno))
        ;
    if (res < 0) {
        if (ENOMEM == errno)
            return 1;
        return res;
    }
    return 0;
}
예제 #8
0
/* Invokes a SCSI WRITE AND VERIFY (16) command (SBC). Returns 0 -> success,
* various SG_LIB_CAT_* positive values or -1 -> other errors */
static int
sg_ll_write_verify16(int sg_fd, int wrprotect, bool dpo, int bytchk,
                     uint64_t llba, int num_lb, int group, uint8_t *dop,
                     int do_len, int timeout, bool noisy, int verbose)
{
    int ret;
    uint8_t wv_cdb[WRITE_VERIFY16_CMDLEN];


    memset(wv_cdb, 0, sizeof(wv_cdb));
    wv_cdb[0] = WRITE_VERIFY16_CMD;
    wv_cdb[1] = ((wrprotect & WRPROTECT_MASK) << WRPROTECT_SHIFT);
    if (dpo)
        wv_cdb[1] |= 0x10;
    if (bytchk)
        wv_cdb[1] |= ((bytchk & 0x3) << 1);

    sg_put_unaligned_be64(llba, wv_cdb + 2);
    sg_put_unaligned_be32((uint32_t)num_lb, wv_cdb + 10);
    wv_cdb[14] = group & 0x1f;
    ret = run_scsi_transaction(sg_fd, wv_cdb, sizeof(wv_cdb), dop, do_len,
                               timeout, noisy, verbose);
    return ret;
}
예제 #9
0
static int
sg_build_scsi_cdb(unsigned char * cdbp, int cdb_sz, unsigned int blocks,
                  int64_t start_block, int write_true, int fua, int dpo)
{
    int rd_opcode[] = {0x8, 0x28, 0xa8, 0x88};
    int wr_opcode[] = {0xa, 0x2a, 0xaa, 0x8a};
    int sz_ind;

    memset(cdbp, 0, cdb_sz);
    if (dpo)
        cdbp[1] |= 0x10;
    if (fua)
        cdbp[1] |= 0x8;
    switch (cdb_sz) {
    case 6:
        sz_ind = 0;
        cdbp[0] = (unsigned char)(write_true ? wr_opcode[sz_ind] :
                                  rd_opcode[sz_ind]);
        sg_put_unaligned_be24(0x1fffff & start_block, cdbp + 1);
        cdbp[4] = (256 == blocks) ? 0 : (unsigned char)blocks;
        if (blocks > 256) {
            pr2serr(ME "for 6 byte commands, maximum number of blocks is "
                    "256\n");
            return 1;
        }
        if ((start_block + blocks - 1) & (~0x1fffff)) {
            pr2serr(ME "for 6 byte commands, can't address blocks beyond "
                    "%d\n", 0x1fffff);
            return 1;
        }
        if (dpo || fua) {
            pr2serr(ME "for 6 byte commands, neither dpo nor fua bits "
                    "supported\n");
            return 1;
        }
        break;
    case 10:
        sz_ind = 1;
        cdbp[0] = (unsigned char)(write_true ? wr_opcode[sz_ind] :
                                  rd_opcode[sz_ind]);
        sg_put_unaligned_be32((uint32_t)start_block, cdbp + 2);
        sg_put_unaligned_be16((uint16_t)blocks, cdbp + 7);
        if (blocks & (~0xffff)) {
            pr2serr(ME "for 10 byte commands, maximum number of blocks is "
                    "%d\n", 0xffff);
            return 1;
        }
        break;
    case 12:
        sz_ind = 2;
        cdbp[0] = (unsigned char)(write_true ? wr_opcode[sz_ind] :
                                  rd_opcode[sz_ind]);
        sg_put_unaligned_be32((uint32_t)start_block, cdbp + 2);
        sg_put_unaligned_be32((uint32_t)blocks, cdbp + 6);
        break;
    case 16:
        sz_ind = 3;
        cdbp[0] = (unsigned char)(write_true ? wr_opcode[sz_ind] :
                                  rd_opcode[sz_ind]);
        sg_put_unaligned_be64((uint64_t)start_block, cdbp + 2);
        sg_put_unaligned_be32((uint32_t)blocks, cdbp + 10);
        break;
    default:
        pr2serr(ME "expected cdb size of 6, 10, 12, or 16 but got %d\n",
                cdb_sz);
        return 1;
    }
    return 0;
}
예제 #10
0
static int
do_write_same(int sg_fd, const struct opts_t * op, const void * dataoutp,
              int * act_cdb_lenp)
{
    int k, ret, res, sense_cat, cdb_len;
    uint64_t llba;
    uint8_t ws_cdb[WRITE_SAME32_LEN];
    uint8_t sense_b[SENSE_BUFF_LEN];
    struct sg_pt_base * ptvp;

    cdb_len = op->pref_cdb_size;
    if (WRITE_SAME10_LEN == cdb_len) {
        llba = op->lba + op->numblocks;
        if ((op->numblocks > 0xffff) || (llba > UINT32_MAX) ||
            op->ndob || (op->unmap && (! op->want_ws10))) {
            cdb_len = WRITE_SAME16_LEN;
            if (op->verbose) {
                const char * cp = "use WRITE SAME(16) instead of 10 byte "
                                  "cdb";

                if (op->numblocks > 0xffff)
                    pr2serr("%s since blocks exceed 65535\n", cp);
                else if (llba > UINT32_MAX)
                    pr2serr("%s since LBA may exceed 32 bits\n", cp);
                else
                    pr2serr("%s due to ndob or unmap settings\n", cp);
            }
        }
    }
    if (act_cdb_lenp)
        *act_cdb_lenp = cdb_len;
    memset(ws_cdb, 0, sizeof(ws_cdb));
    switch (cdb_len) {
    case WRITE_SAME10_LEN:
        ws_cdb[0] = WRITE_SAME10_OP;
        ws_cdb[1] = ((op->wrprotect & 0x7) << 5);
        /* ANCHOR + UNMAP not allowed for WRITE_SAME10 in sbc3r24+r25 but
         * a proposal has been made to allow it. Anticipate approval. */
        if (op->anchor)
            ws_cdb[1] |= 0x10;
        if (op->unmap)
            ws_cdb[1] |= 0x8;
        if (op->pbdata)
            ws_cdb[1] |= 0x4;
        if (op->lbdata)
            ws_cdb[1] |= 0x2;
        sg_put_unaligned_be32((uint32_t)op->lba, ws_cdb + 2);
        ws_cdb[6] = (op->grpnum & 0x1f);
        sg_put_unaligned_be16((uint16_t)op->numblocks, ws_cdb + 7);
        break;
    case WRITE_SAME16_LEN:
        ws_cdb[0] = WRITE_SAME16_OP;
        ws_cdb[1] = ((op->wrprotect & 0x7) << 5);
        if (op->anchor)
            ws_cdb[1] |= 0x10;
        if (op->unmap)
            ws_cdb[1] |= 0x8;
        if (op->pbdata)
            ws_cdb[1] |= 0x4;
        if (op->lbdata)
            ws_cdb[1] |= 0x2;
        if (op->ndob)
            ws_cdb[1] |= 0x1;
        sg_put_unaligned_be64(op->lba, ws_cdb + 2);
        sg_put_unaligned_be32((uint32_t)op->numblocks, ws_cdb + 10);
        ws_cdb[14] = (op->grpnum & 0x1f);
        break;
    case WRITE_SAME32_LEN:
        ws_cdb[0] = VARIABLE_LEN_OP;
        ws_cdb[6] = (op->grpnum & 0x1f);
        ws_cdb[7] = WRITE_SAME32_ADD;
        sg_put_unaligned_be16((uint16_t)WRITE_SAME32_SA, ws_cdb + 8);
        ws_cdb[10] = ((op->wrprotect & 0x7) << 5);
        if (op->anchor)
            ws_cdb[10] |= 0x10;
        if (op->unmap)
            ws_cdb[10] |= 0x8;
        if (op->pbdata)
            ws_cdb[10] |= 0x4;
        if (op->lbdata)
            ws_cdb[10] |= 0x2;
        if (op->ndob)
            ws_cdb[10] |= 0x1;
        sg_put_unaligned_be64(op->lba, ws_cdb + 12);
        sg_put_unaligned_be32((uint32_t)op->numblocks, ws_cdb + 28);
        break;
    default:
        pr2serr("do_write_same: bad cdb length %d\n", cdb_len);
        return -1;
    }

    if (op->verbose > 1) {
        pr2serr("    Write same(%d) cdb: ", cdb_len);
        for (k = 0; k < cdb_len; ++k)
            pr2serr("%02x ", ws_cdb[k]);
        pr2serr("\n    Data-out buffer length=%d\n",
                op->xfer_len);
    }
    if ((op->verbose > 3) && (op->xfer_len > 0)) {
        pr2serr("    Data-out buffer contents:\n");
        hex2stderr((const uint8_t *)dataoutp, op->xfer_len, 1);
    }
    ptvp = construct_scsi_pt_obj();
    if (NULL == ptvp) {
        pr2serr("Write same(%d): out of memory\n", cdb_len);
        return -1;
    }
    set_scsi_pt_cdb(ptvp, ws_cdb, cdb_len);
    set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
    set_scsi_pt_data_out(ptvp, (uint8_t *)dataoutp, op->xfer_len);
    res = do_scsi_pt(ptvp, sg_fd, op->timeout, op->verbose);
    ret = sg_cmds_process_resp(ptvp, "Write same", res, SG_NO_DATA_IN,
                               sense_b, true /*noisy */, op->verbose,
                               &sense_cat);
    if (-1 == ret)
        get_scsi_pt_os_err(ptvp);
    else if (-2 == ret) {
        switch (sense_cat) {
        case SG_LIB_CAT_RECOVERED:
        case SG_LIB_CAT_NO_SENSE:
            ret = 0;
            break;
        case SG_LIB_CAT_MEDIUM_HARD:
            {
                bool valid;
                int slen;
                uint64_t ull = 0;

                slen = get_scsi_pt_sense_len(ptvp);
                valid = sg_get_sense_info_fld(sense_b, slen, &ull);
                if (valid)
                    pr2serr("Medium or hardware error starting at lba=%"
                            PRIu64 " [0x%" PRIx64 "]\n", ull, ull);
            }
            ret = sense_cat;
            break;
        default:
            ret = sense_cat;
            break;
        }
    } else
        ret = 0;

    destruct_scsi_pt_obj(ptvp);
    return ret;
}
예제 #11
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;
}
예제 #12
0
static int
send_then_receive(int sg_fd, uint32_t gen_code, int off_off,
                  const unsigned char * dmp, int dmp_len,
                  struct dout_buff_t * wp, unsigned char * dip,
                  int last, const struct opts_t * op)
{
    int do_len, rem, res, rsp_len, k, num, mc_status, verb;
    int send_data = 0;
    int ret = 0;
    uint32_t rec_gen_code;
    const unsigned char * ucp;
    const char * cp;

    verb = (op->verbose > 1) ? op->verbose - 1 : 0;
    switch (op->mc_mode) {
    case MODE_DNLD_MC_OFFS:
    case MODE_DNLD_MC_OFFS_SAVE:
    case MODE_DNLD_MC_OFFS_DEFER:
        send_data = 1;
        do_len = 24 + dmp_len;
        rem = do_len % 4;
        if (rem)
            do_len += (4 - rem);
        break;
    case MODE_ACTIVATE_MC:
        do_len = 24;
        break;
    default:
        pr2serr("send_then_receive: unexpected mc_mode=0x%x\n", op->mc_mode);
        return SG_LIB_SYNTAX_ERROR;
    }
    if (do_len > wp->dout_len) {
        if (wp->doutp)
            free(wp->doutp);
        wp->doutp = (unsigned char *)malloc(do_len);
        if (! wp->doutp) {
            pr2serr("send_then_receive: unable to malloc %d bytes\n", do_len);
            return SG_LIB_CAT_OTHER;
        }
        wp->dout_len = do_len;
    }
    memset(wp->doutp, 0, do_len);
    wp->doutp[0] = DPC_DOWNLOAD_MICROCODE;
    wp->doutp[1] = op->mc_subenc;
    sg_put_unaligned_be16(do_len - 4, wp->doutp + 2);
    sg_put_unaligned_be32(gen_code, wp->doutp + 4);
    wp->doutp[8] = op->mc_mode;
    wp->doutp[11] = op->mc_id;
    if (send_data)
        sg_put_unaligned_be32(op->mc_offset + off_off, wp->doutp + 12);
    sg_put_unaligned_be32(op->mc_tlen, wp->doutp + 16);
    sg_put_unaligned_be32(dmp_len, wp->doutp + 20);
    if (send_data && (dmp_len > 0))
        memcpy(wp->doutp + 24, dmp, dmp_len);
    /* select long duration timeout (7200 seconds) */
    res = sg_ll_send_diag(sg_fd, 0 /* sf_code */, 1 /* pf */, 0 /* sf */,
                          0 /* devofl */, 0 /* unitofl */,
                          1 /* long_duration */, wp->doutp, do_len,
                          1 /* noisy */, verb);
    if (op->mc_non) {
        /* If non-standard, only call RDR after failed SD */
        if (0 == res)
            return 0;
        /* If RDR error after SD error, prefer reporting SD error */
        ret = res;
    } else {
        switch (op->mc_mode) {
        case MODE_DNLD_MC_OFFS:
        case MODE_DNLD_MC_OFFS_SAVE:
            if (res)
                return res;
            else if (last)
                return 0;   /* RDR after last may hit a device reset */
            break;
        case MODE_DNLD_MC_OFFS_DEFER:
            if (res)
                return res;
            break;
        case MODE_ACTIVATE_MC:
            if (0 == res)
                return 0;   /* RDR after ACTIVATE_MC may hit a device reset */
            /* SD has failed, so do a RDR but return SD's error */
            ret = res;
            break;
        default:
            pr2serr("send_then_receive: mc_mode=0x%x\n", op->mc_mode);
            return SG_LIB_SYNTAX_ERROR;
        }
    }

    res = sg_ll_receive_diag(sg_fd, 1 /* pcv */, DPC_DOWNLOAD_MICROCODE, dip,
                             DEF_DI_LEN, 1, verb);
    if (res)
        return ret ? ret : res;
    rsp_len = sg_get_unaligned_be16(dip + 2) + 4;
    if (rsp_len > DEF_DI_LEN) {
        pr2serr("<<< warning response buffer too small [%d but need "
                "%d]>>>\n", DEF_DI_LEN, rsp_len);
        rsp_len = DEF_DI_LEN;
    }
    if (rsp_len < 8) {
        pr2serr("Download microcode status dpage too short\n");
        return ret ? ret : SG_LIB_CAT_OTHER;
    }
    rec_gen_code = sg_get_unaligned_be32(dip + 4);
    if (rec_gen_code != gen_code)
        pr2serr("gen_code changed from %" PRIu32 " to %" PRIu32
                ", continuing but may fail\n", gen_code, rec_gen_code);
    num = (rsp_len - 8) / 16;
    if ((rsp_len - 8) % 16)
        pr2serr("Found %d Download microcode status descriptors, but there "
                "is residual\n", num);
    ucp = dip + 8;
    for (k = 0; k < num; ++k, ucp += 16) {
        if ((unsigned int)op->mc_subenc == (unsigned int)ucp[1]) {
            mc_status = ucp[2];
            cp = get_mc_status_str(mc_status);
            if ((mc_status >= 0x80) || op->verbose)
                pr2serr("mc offset=%d: status: %s [0x%x, additional=0x%x]\n",
                        off_off, cp, mc_status, ucp[3]);
            if (op->verbose > 1)
                pr2serr("  subenc_id=%d, expected_buffer_id=%d, "
                        "expected_offset=0x%" PRIx32 "\n", ucp[1], ucp[11],
                        sg_get_unaligned_be32(ucp + 12));
            if (mc_status >= 0x80)
                ret = ret ? ret : SG_LIB_CAT_OTHER;
        }
    }
    return ret;
}
예제 #13
0
/* Invokes a SCSI READ ATTRIBUTE command (SPC+SMC).  Return of 0 -> success,
 * various SG_LIB_CAT_* positive values or -1 -> other errors */
static int
sg_ll_read_attr(int sg_fd, void * resp, int * residp,
                const struct opts_t * op)
{
    int k, ret, res, sense_cat;
    int noisy = 1;
    unsigned char ra_cdb[SG_READ_ATTRIBUTE_CMDLEN] =
          {SG_READ_ATTRIBUTE_CMD, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,
           0, 0, 0, 0};
    unsigned char sense_b[SENSE_BUFF_LEN];
    struct sg_pt_base * ptvp;

    ra_cdb[1] = 0x1f & op->sa;
    if (op->ea)
        sg_put_unaligned_be16(op->ea, ra_cdb + 2);
    if (op->lvn)
        ra_cdb[5] = 0xff & op->lvn;
    if (op->pn)
        ra_cdb[7] = 0xff & op->pn;
    if (op->fai)
        sg_put_unaligned_be16(op->fai, ra_cdb + 8);
    sg_put_unaligned_be32((uint32_t)op->maxlen, ra_cdb + 10);
    if (op->cache)
        ra_cdb[14] |= 0x1;
    if (op->verbose) {
        pr2serr("    Read attribute cdb: ");
        for (k = 0; k < SG_READ_ATTRIBUTE_CMDLEN; ++k)
            pr2serr("%02x ", ra_cdb[k]);
        pr2serr("\n");
    }

    ptvp = construct_scsi_pt_obj();
    if (NULL == ptvp) {
        pr2serr("%s: out of memory\n", __func__);
        return -1;
    }
    set_scsi_pt_cdb(ptvp, ra_cdb, sizeof(ra_cdb));
    set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
    set_scsi_pt_data_in(ptvp, (unsigned char *)resp, op->maxlen);
    res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, op->verbose);
    ret = sg_cmds_process_resp(ptvp, "read attribute", res, op->maxlen,
                               sense_b, noisy, op->verbose, &sense_cat);
    if (-1 == ret)
        ;
    else if (-2 == ret) {
        switch (sense_cat) {
        case SG_LIB_CAT_RECOVERED:
        case SG_LIB_CAT_NO_SENSE:
            ret = 0;
            break;
        default:
            ret = sense_cat;
            break;
        }
    } else
        ret = 0;
    if (residp)
        *residp = get_scsi_pt_resid(ptvp);
    destruct_scsi_pt_obj(ptvp);
    return ret;
}