示例#1
0
/* Invokes a SCSI LOG SELECT command. Return of 0 -> success,
 * various SG_LIB_CAT_* positive values or -1 -> other errors */
int
sg_ll_log_select(int sg_fd, int pcr, int sp, int pc, int pg_code,
                 int subpg_code, unsigned char * paramp, int param_len,
                 int noisy, int verbose)
{
    static const char * const cdb_name_s = "log select";
    int res, ret, k, sense_cat;
    unsigned char logs_cdb[LOG_SELECT_CMDLEN] =
        {LOG_SELECT_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    unsigned char sense_b[SENSE_BUFF_LEN];
    struct sg_pt_base * ptvp;

    if (param_len > 0xffff) {
        pr2ws("%s: param_len too big\n", cdb_name_s);
        return -1;
    }
    logs_cdb[1] = (unsigned char)((pcr ? 2 : 0) | (sp ? 1 : 0));
    logs_cdb[2] = (unsigned char)(((pc << 6) & 0xc0) | (pg_code & 0x3f));
    logs_cdb[3] = (unsigned char)(subpg_code & 0xff);
    sg_put_unaligned_be16((int16_t)param_len, logs_cdb + 7);
    if (verbose) {
        pr2ws("    %s cdb: ", cdb_name_s);
        for (k = 0; k < LOG_SELECT_CMDLEN; ++k)
            pr2ws("%02x ", logs_cdb[k]);
        pr2ws("\n");
    }
    if ((verbose > 1) && (param_len > 0)) {
        pr2ws("    %s parameter list\n", cdb_name_s);
        dStrHexErr((const char *)paramp, param_len, -1);
    }

    if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
        return -1;
    set_scsi_pt_cdb(ptvp, logs_cdb, sizeof(logs_cdb));
    set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
    set_scsi_pt_data_out(ptvp, paramp, param_len);
    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
void
sg_print_host_status(int host_status)
{
    pr2ws("Host_status=0x%02x ", host_status);
    if ((host_status < 0) || (host_status >= LINUX_HOST_BYTES_SZ))
        pr2ws("is invalid ");
    else
        pr2ws("[%s] ", linux_host_bytes[host_status]);
}
示例#3
0
static int
sg_cmds_process_helper(const char * leadin, int mx_di_len, int resid,
                       const uint8_t * sbp, int slen, bool noisy,
                       int verbose, int * o_sense_cat)
{
    int scat, got;
    bool n = false;
    bool check_data_in = false;
    char b[512];

    scat = sg_err_category_sense(sbp, slen);
    switch (scat) {
    case SG_LIB_CAT_NOT_READY:
    case SG_LIB_CAT_INVALID_OP:
    case SG_LIB_CAT_ILLEGAL_REQ:
    case SG_LIB_LBA_OUT_OF_RANGE:
    case SG_LIB_CAT_ABORTED_COMMAND:
    case SG_LIB_CAT_COPY_ABORTED:
    case SG_LIB_CAT_DATA_PROTECT:
    case SG_LIB_CAT_PROTECTION:
    case SG_LIB_CAT_NO_SENSE:
    case SG_LIB_CAT_MISCOMPARE:
        n = false;
        break;
    case SG_LIB_CAT_RECOVERED:
    case SG_LIB_CAT_MEDIUM_HARD:
        check_data_in = true;
#if defined(__GNUC__)
#if (__GNUC__ >= 7)
        __attribute__((fallthrough));
        /* FALL THROUGH */
#endif
#endif
    case SG_LIB_CAT_UNIT_ATTENTION:
    case SG_LIB_CAT_SENSE:
    default:
        n = noisy;
        break;
    }
    if (verbose || n) {
        if (leadin && (strlen(leadin) > 0))
            pr2ws("%s:\n", leadin);
        sg_get_sense_str(NULL, sbp, slen, (verbose > 1),
                         sizeof(b), b);
        pr2ws("%s", b);
        if ((mx_di_len > 0) && (resid > 0)) {
            got = mx_di_len - resid;
            if ((verbose > 2) || check_data_in || (got > 0))
                pr2ws("    %s requested %d bytes (data-in) but got %d "
                      "bytes\n", pass_through_s, mx_di_len, got);
        }
    }
    if (o_sense_cat)
        *o_sense_cat = scat;
    return -2;
}
示例#4
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;
}
示例#5
0
/* Invokes a SCSI MODE SELECT (10) command.  Return of 0 -> success,
 * various SG_LIB_CAT_* positive values or -1 -> other errors,
 * v2 adds rtd (revert to defaults) bit (spc5r11).  */
int
sg_ll_mode_select10_v2(int sg_fd, bool pf, bool rtd, bool sp, void * paramp,
                       int param_len, bool noisy, int verbose)
{
    static const char * const cdb_s = "mode select(10)";
    int res, ret, k, sense_cat;
    uint8_t modes_cdb[MODE_SELECT10_CMDLEN] =
        {MODE_SELECT10_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    uint8_t sense_b[SENSE_BUFF_LEN];
    struct sg_pt_base * ptvp;

    modes_cdb[1] = (uint8_t)((pf ? 0x10 : 0x0) | (sp ? 0x1 : 0x0));
    if (rtd)
        modes_cdb[1] |= 0x2;
    sg_put_unaligned_be16((int16_t)param_len, modes_cdb + 7);
    if (param_len > 0xffff) {
        pr2ws("%s: param_len too big\n", cdb_s);
        return -1;
    }
    if (verbose) {
        pr2ws("    %s cdb: ", cdb_s);
        for (k = 0; k < MODE_SELECT10_CMDLEN; ++k)
            pr2ws("%02x ", modes_cdb[k]);
        pr2ws("\n");
    }
    if (verbose > 1) {
        pr2ws("    %s parameter list\n", cdb_s);
        hex2stderr((const uint8_t *)paramp, param_len, -1);
    }

    if (NULL == ((ptvp = create_pt_obj(cdb_s))))
        return -1;
    set_scsi_pt_cdb(ptvp, modes_cdb, sizeof(modes_cdb));
    set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
    set_scsi_pt_data_out(ptvp, (uint8_t *)paramp, param_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;
}
示例#6
0
/* Invokes a SCSI MODE SELECT (6) command.  Return of 0 -> success,
 * various SG_LIB_CAT_* positive values or -1 -> other errors */
int
sg_ll_mode_select6(int sg_fd, int pf, int sp, void * paramp, int param_len,
                   int noisy, int verbose)
{
    static const char * const cdb_name_s = "mode select(6)";
    int res, ret, k, sense_cat;
    unsigned char modes_cdb[MODE_SELECT6_CMDLEN] =
        {MODE_SELECT6_CMD, 0, 0, 0, 0, 0};
    unsigned char sense_b[SENSE_BUFF_LEN];
    struct sg_pt_base * ptvp;

    modes_cdb[1] = (unsigned char)(((pf << 4) & 0x10) | (sp & 0x1));
    modes_cdb[4] = (unsigned char)(param_len & 0xff);
    if (param_len > 0xff) {
        pr2ws("%s: param_len too big\n", cdb_name_s);
        return -1;
    }
    if (verbose) {
        pr2ws("    %s cdb: ", cdb_name_s);
        for (k = 0; k < MODE_SELECT6_CMDLEN; ++k)
            pr2ws("%02x ", modes_cdb[k]);
        pr2ws("\n");
    }
    if (verbose > 1) {
        pr2ws("    %s parameter list\n", cdb_name_s);
        dStrHexErr((const char *)paramp, param_len, -1);
    }

    if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
        return -1;
    set_scsi_pt_cdb(ptvp, modes_cdb, sizeof(modes_cdb));
    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, 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;
}
示例#7
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;
}
示例#8
0
/* Invokes a SCSI START STOP UNIT command (SBC + MMC).
 * Return of 0 -> success,
 * various SG_LIB_CAT_* positive values or -1 -> other errors.
 * SBC-3 and MMC partially overlap on the power_condition_modifier(sbc) and
 * format_layer_number(mmc) fields. They also overlap on the noflush(sbc)
 * and fl(mmc) one bit field. This is the cause of the awkardly named
 * pc_mod__fl_num and noflush__fl arguments to this function.
 *  */
int
sg_ll_start_stop_unit_pt(struct sg_pt_base * ptvp, bool immed,
                         int pc_mod__fl_num, int power_cond, bool noflush__fl,
                         bool loej, bool start, bool noisy, int verbose)
{
    static const char * const cdb_s = "start stop unit";
    int k, res, ret, sense_cat;
    uint8_t ssuBlk[START_STOP_CMDLEN] = {START_STOP_CMD, 0, 0, 0, 0, 0};
    uint8_t sense_b[SENSE_BUFF_LEN];

    if (immed)
        ssuBlk[1] = 0x1;
    ssuBlk[3] = pc_mod__fl_num & 0xf;  /* bits 2 and 3 are reserved in MMC */
    ssuBlk[4] = ((power_cond & 0xf) << 4);
    if (noflush__fl)
        ssuBlk[4] |= 0x4;
    if (loej)
        ssuBlk[4] |= 0x2;
    if (start)
        ssuBlk[4] |= 0x1;
    if (verbose) {
        pr2ws("    %s command:", cdb_s);
        for (k = 0; k < (int)sizeof(ssuBlk); ++k)
                pr2ws(" %02x", ssuBlk[k]);
        pr2ws("\n");
    }

    clear_scsi_pt_obj(ptvp);
    set_scsi_pt_cdb(ptvp, ssuBlk, sizeof(ssuBlk));
    set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
    res = do_scsi_pt(ptvp, -1, START_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;
    return ret;
}
示例#9
0
/* Returns 1 if no errors found and thus nothing printed; otherwise
   prints error/warning (prefix by 'leadin') and returns 0. */
static int
sg_linux_sense_print(const char * leadin, int scsi_status, int host_status,
                     int driver_status, const unsigned char * sense_buffer,
                     int sb_len, int raw_sinfo)
{
    int done_leadin = 0;
    int done_sense = 0;

    scsi_status &= 0x7e; /*sanity */
    if ((0 == scsi_status) && (0 == host_status) && (0 == driver_status))
        return 1;       /* No problems */
    if (0 != scsi_status) {
        if (leadin)
            pr2ws("%s: ", leadin);
        done_leadin = 1;
        pr2ws("SCSI status: ");
        sg_print_scsi_status(scsi_status);
        pr2ws("\n");
        if (sense_buffer && ((scsi_status == SAM_STAT_CHECK_CONDITION) ||
                             (scsi_status == SAM_STAT_COMMAND_TERMINATED))) {
            /* SAM_STAT_COMMAND_TERMINATED is obsolete */
            sg_print_sense(0, sense_buffer, sb_len, raw_sinfo);
            done_sense = 1;
        }
    }
    if (0 != host_status) {
        if (leadin && (! done_leadin))
            pr2ws("%s: ", leadin);
        if (done_leadin)
            pr2ws("plus...: ");
        else
            done_leadin = 1;
        sg_print_host_status(host_status);
        pr2ws("\n");
    }
    if (0 != driver_status) {
        if (done_sense &&
            (SG_LIB_DRIVER_SENSE == (SG_LIB_DRIVER_MASK & driver_status)))
            return 0;
        if (leadin && (! done_leadin))
            pr2ws("%s: ", leadin);
        if (done_leadin)
            pr2ws("plus...: ");
        else
            done_leadin = 1;
        sg_print_driver_status(driver_status);
        pr2ws("\n");
        if (sense_buffer && (! done_sense) &&
            (SG_LIB_DRIVER_SENSE == (SG_LIB_DRIVER_MASK & driver_status)))
            sg_print_sense(0, sense_buffer, sb_len, raw_sinfo);
    }
    return 0;
}
示例#10
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);
    }
示例#11
0
void
sg_print_driver_status(int driver_status)
{
    int driv, sugg;
    const char * driv_cp = "invalid";
    const char * sugg_cp = "invalid";

    driv = driver_status & SG_LIB_DRIVER_MASK;
    if (driv < LINUX_DRIVER_BYTES_SZ)
        driv_cp = linux_driver_bytes[driv];
    sugg = (driver_status & SG_LIB_SUGGEST_MASK) >> 4;
    if (sugg < LINUX_DRIVER_SUGGESTS_SZ)
        sugg_cp = linux_driver_suggests[sugg];
    pr2ws("Driver_status=0x%02x", driver_status);
    pr2ws(" [%s, %s] ", driv_cp, sugg_cp);
}
示例#12
0
static struct sg_pt_base *
create_pt_obj(const char * cname)
{
    struct sg_pt_base * ptvp = construct_scsi_pt_obj();
    if (NULL == ptvp)
        pr2ws("%s: out of memory\n", cname);
    return ptvp;
}
示例#13
0
/* Invokes a SCSI PREVENT ALLOW MEDIUM REMOVAL command
 * [was in SPC-3 but displaced from SPC-4 into SBC-3, MMC-5, SSC-3]
 * prevent==0 allows removal, prevent==1 prevents removal ...
 * Return of 0 -> success,
 * various SG_LIB_CAT_* positive values or -1 -> other errors */
int
sg_ll_prevent_allow(int sg_fd, int prevent, int noisy, int verbose)
{
    static const char * const cdb_name_s = "prevent allow medium removal";
    int k, res, ret, sense_cat;
    unsigned char p_cdb[PREVENT_ALLOW_CMDLEN] =
                {PREVENT_ALLOW_CMD, 0, 0, 0, 0, 0};
    unsigned char sense_b[SENSE_BUFF_LEN];
    struct sg_pt_base * ptvp;

    if ((prevent < 0) || (prevent > 3)) {
        pr2ws("prevent argument should be 0, 1, 2 or 3\n");
        return -1;
    }
    p_cdb[4] |= (prevent & 0x3);
    if (verbose) {
        pr2ws("    %s cdb: ", cdb_name_s);
        for (k = 0; k < PREVENT_ALLOW_CMDLEN; ++k)
            pr2ws("%02x ", p_cdb[k]);
        pr2ws("\n");
    }

    if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
        return -1;
    set_scsi_pt_cdb(ptvp, p_cdb, sizeof(p_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;
}
示例#14
0
/* Invokes a SCSI START STOP UNIT command (SBC + MMC).
 * Return of 0 -> success,
 * various SG_LIB_CAT_* positive values or -1 -> other errors.
 * SBC-3 and MMC partially overlap on the power_condition_modifier(sbc) and
 * format_layer_number(mmc) fields. They also overlap on the noflush(sbc)
 * and fl(mmc) one bit field. This is the cause of the awkardly named
 * pc_mod__fl_num and noflush__fl arguments to this function.
 *  */
int
sg_ll_start_stop_unit(int sg_fd, int immed, int pc_mod__fl_num,
                      int power_cond, int noflush__fl, int loej, int start,
                      int noisy, int verbose)
{
    static const char * const cdb_name_s = "start stop unit";
    int k, res, ret, sense_cat;
    struct sg_pt_base * ptvp;
    unsigned char ssuBlk[START_STOP_CMDLEN] = {START_STOP_CMD, 0, 0, 0, 0, 0};
    unsigned char sense_b[SENSE_BUFF_LEN];

    ssuBlk[1] = immed & 1;
    ssuBlk[3] = pc_mod__fl_num & 0xf;  /* bits 2 and 3 are reserved in MMC */
    ssuBlk[4] = ((power_cond & 0xf) << 4) | (noflush__fl ? 0x4 : 0) |
                 (loej ? 0x2 : 0) | (start ? 0x1 : 0);
    if (verbose) {
        pr2ws("    %s command:", cdb_name_s);
        for (k = 0; k < (int)sizeof(ssuBlk); ++k)
                pr2ws(" %02x", ssuBlk[k]);
        pr2ws("\n");
    }

    if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
        return -1;
    set_scsi_pt_cdb(ptvp, ssuBlk, sizeof(ssuBlk));
    set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
    res = do_scsi_pt(ptvp, sg_fd, START_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;
}
示例#15
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;
}
示例#16
0
/* Invokes a SCSI LOG SENSE command. Return of 0 -> success,
 * various SG_LIB_CAT_* positive values or -1 -> other errors */
int
sg_ll_log_sense(int sg_fd, int ppc, int sp, int pc, int pg_code,
                int subpg_code, int paramp, unsigned char * resp,
                int mx_resp_len, int noisy, int verbose)
{
    static const char * const cdb_name_s = "log sense";
    int res, ret, k, sense_cat, resid;
    unsigned char logs_cdb[LOG_SENSE_CMDLEN] =
        {LOG_SENSE_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    unsigned char sense_b[SENSE_BUFF_LEN];
    struct sg_pt_base * ptvp;

    if (mx_resp_len > 0xffff) {
        pr2ws("mx_resp_len too big\n");
        return -1;
    }
    logs_cdb[1] = (unsigned char)((ppc ? 2 : 0) | (sp ? 1 : 0));
    logs_cdb[2] = (unsigned char)(((pc << 6) & 0xc0) | (pg_code & 0x3f));
    logs_cdb[3] = (unsigned char)(subpg_code & 0xff);
    sg_put_unaligned_be16((int16_t)paramp, logs_cdb + 5);
    sg_put_unaligned_be16((int16_t)mx_resp_len, logs_cdb + 7);
    if (verbose) {
        pr2ws("    %s cdb: ", cdb_name_s);
        for (k = 0; k < LOG_SENSE_CMDLEN; ++k)
            pr2ws("%02x ", logs_cdb[k]);
        pr2ws("\n");
    }

    if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
        return -1;
    set_scsi_pt_cdb(ptvp, logs_cdb, sizeof(logs_cdb));
    set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
    set_scsi_pt_data_in(ptvp, 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);
    resid = get_scsi_pt_resid(ptvp);
    destruct_scsi_pt_obj(ptvp);
    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 {
        if ((mx_resp_len > 3) && (ret < 4)) {
            /* resid indicates LOG SENSE response length bad, so zero it */
            resp[2] = 0;
            resp[3] = 0;
        }
        ret = 0;
    }

    if (resid > 0) {
        if (resid > mx_resp_len) {
            pr2ws("%s: resid (%d) should never exceed requested len=%d\n",
                  cdb_name_s, resid, mx_resp_len);
            return ret ? ret : SG_LIB_CAT_MALFORMED;
        }
        /* zero unfilled section of response buffer */
        memset((unsigned char *)resp + (mx_resp_len - resid), 0, resid);
    }
    return ret;
}
示例#17
0
/* Fetches current, changeable, default and/or saveable modes pages as
 * indicated by pcontrol_arr for given pg_code and sub_pg_code. If
 * mode6==0 then use MODE SENSE (10) else use MODE SENSE (6). If
 * flexible set and mode data length seems wrong then try and
 * fix (compensating hack for bad device or driver). pcontrol_arr
 * should have 4 elements for output of current, changeable, default
 * and saved values respectively. Each element should be NULL or
 * at least mx_mpage_len bytes long.
 * Return of 0 -> overall success, various SG_LIB_CAT_* positive values or
 * -1 -> other errors.
 * If success_mask pointer is not NULL then first zeros it. Then set bits
 * 0, 1, 2 and/or 3 if the current, changeable, default and saved values
 * respectively have been fetched. If error on current page
 * then stops and returns that error; otherwise continues if an error is
 * detected but returns the first error encountered.  */
int
sg_get_mode_page_controls(int sg_fd, int mode6, int pg_code, int sub_pg_code,
                          int dbd, int flexible, int mx_mpage_len,
                          int * success_mask, void * pcontrol_arr[],
                          int * reported_len, int verbose)
{
    int k, n, res, offset, calc_len, xfer_len, resp_mode6;
    unsigned char buff[MODE_RESP_ARB_LEN];
    char ebuff[EBUFF_SZ];
    int first_err = 0;

    if (success_mask)
        *success_mask = 0;
    if (reported_len)
        *reported_len = 0;
    if (mx_mpage_len < 4)
        return 0;
    memset(ebuff, 0, sizeof(ebuff));
    /* first try to find length of current page response */
    memset(buff, 0, MODE10_RESP_HDR_LEN);
    if (mode6)  /* want first 8 bytes just in case */
        res = sg_ll_mode_sense6(sg_fd, dbd, 0 /* pc */, pg_code,
                                sub_pg_code, buff, MODE10_RESP_HDR_LEN, 1,
                                verbose);
    else
        res = sg_ll_mode_sense10(sg_fd, 0 /* llbaa */, dbd,
                                 0 /* pc */, pg_code, sub_pg_code, buff,
                                 MODE10_RESP_HDR_LEN, 1, verbose);
    if (0 != res)
        return res;
    n = buff[0];
    if (reported_len)
        *reported_len = mode6 ? (n + 1) : (sg_get_unaligned_be16(buff) + 2);
    resp_mode6 = mode6;
    if (flexible) {
        if (mode6 && (n < 3)) {
            resp_mode6 = 0;
            if (verbose)
                pr2ws(">>> msense(6) but resp[0]=%d so try msense(10) "
                      "response processing\n", n);
        }
        if ((0 == mode6) && (n > 5)) {
            if ((n > 11) && (0 == (n % 2)) && (0 == buff[4]) &&
                (0 == buff[5]) && (0 == buff[6])) {
                buff[1] = n;
                buff[0] = 0;
                if (verbose)
                    pr2ws(">>> msense(10) but resp[0]=%d and not msense(6) "
                          "response so fix length\n", n);
            } else
                resp_mode6 = 1;
        }
    }
    if (verbose && (resp_mode6 != mode6))
        pr2ws(">>> msense(%d) but resp[0]=%d so switch response "
              "processing\n", (mode6 ? 6 : 10), buff[0]);
    calc_len = resp_mode6 ? (buff[0] + 1) : (sg_get_unaligned_be16(buff) + 2);
    if (calc_len > MODE_RESP_ARB_LEN)
        calc_len = MODE_RESP_ARB_LEN;
    offset = sg_mode_page_offset(buff, calc_len, resp_mode6,
                                 ebuff, EBUFF_SZ);
    if (offset < 0) {
        if (('\0' != ebuff[0]) && (verbose > 0))
            pr2ws("%s: %s\n", __func__, ebuff);
        return SG_LIB_CAT_MALFORMED;
    }
    xfer_len = calc_len - offset;
    if (xfer_len > mx_mpage_len)
        xfer_len = mx_mpage_len;

    for (k = 0; k < 4; ++k) {
        if (NULL == pcontrol_arr[k])
            continue;
        memset(pcontrol_arr[k], 0, mx_mpage_len);
        if (mode6)
            res = sg_ll_mode_sense6(sg_fd, dbd, k /* pc */,
                                    pg_code, sub_pg_code, buff,
                                    calc_len, 1, verbose);
        else
            res = sg_ll_mode_sense10(sg_fd, 0 /* llbaa */, dbd,
                                     k /* pc */, pg_code, sub_pg_code,
                                     buff, calc_len, 1, verbose);
        if (0 != res) {
            if (0 == first_err)
                first_err = res;
            if (0 == k)
                break;  /* if problem on current page, it won't improve */
            else
                continue;
        }
        if (xfer_len > 0)
            memcpy(pcontrol_arr[k], buff + offset, xfer_len);
        if (success_mask)
            *success_mask |= (1 << k);
    }
    return first_err;
}
示例#18
0
/* Invokes a SCSI MODE SENSE (10) command. Return of 0 -> success,
 * various SG_LIB_CAT_* positive values or -1 -> other errors */
int
sg_ll_mode_sense10(int sg_fd, int llbaa, int dbd, int pc, int pg_code,
                   int sub_pg_code, void * resp, int mx_resp_len,
                   int noisy, int verbose)
{
    static const char * const cdb_name_s = "mode sense(10)";
    int res, ret, k, sense_cat, resid;
    unsigned char modes_cdb[MODE_SENSE10_CMDLEN] =
        {MODE_SENSE10_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    unsigned char sense_b[SENSE_BUFF_LEN];
    struct sg_pt_base * ptvp;

    modes_cdb[1] = (unsigned char)((dbd ? 0x8 : 0) | (llbaa ? 0x10 : 0));
    modes_cdb[2] = (unsigned char)(((pc << 6) & 0xc0) | (pg_code & 0x3f));
    modes_cdb[3] = (unsigned char)(sub_pg_code & 0xff);
    sg_put_unaligned_be16((int16_t)mx_resp_len, modes_cdb + 7);
    if (mx_resp_len > 0xffff) {
        pr2ws("mx_resp_len too big\n");
        return -1;
    }
    if (verbose) {
        pr2ws("    %s cdb: ", cdb_name_s);
        for (k = 0; k < MODE_SENSE10_CMDLEN; ++k)
            pr2ws("%02x ", modes_cdb[k]);
        pr2ws("\n");
    }
    if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
        return -1;
    set_scsi_pt_cdb(ptvp, modes_cdb, sizeof(modes_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);
    resid = get_scsi_pt_resid(ptvp);
    destruct_scsi_pt_obj(ptvp);
    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 {
        if ((verbose > 2) && (ret > 0)) {
            pr2ws("    %s: response", cdb_name_s);
            if (3 == verbose) {
                pr2ws("%s:\n", (ret > 256 ? ", first 256 bytes" : ""));
                dStrHexErr((const char *)resp, (ret > 256 ? 256 : ret), -1);
            } else {
                pr2ws(":\n");
                dStrHexErr((const char *)resp, ret, 0);
            }
        }
        ret = 0;
    }

    if (resid > 0) {
        if (resid > mx_resp_len) {
            pr2ws("%s: resid (%d) should never exceed requested len=%d\n",
                  cdb_name_s, resid, mx_resp_len);
            return ret ? ret : SG_LIB_CAT_MALFORMED;
        }
        /* zero unfilled section of response buffer */
        memset((unsigned char *)resp + (mx_resp_len - resid), 0, resid);
    }
    return ret;
}
示例#19
0
/* Fetches current, changeable, default and/or saveable modes pages as
 * indicated by pcontrol_arr for given pg_code and sub_pg_code. If
 * mode6==false then use MODE SENSE (10) else use MODE SENSE (6). If
 * flexible set and mode data length seems wrong then try and
 * fix (compensating hack for bad device or driver). pcontrol_arr
 * should have 4 elements for output of current, changeable, default
 * and saved values respectively. Each element should be NULL or
 * at least mx_mpage_len bytes long.
 * Return of 0 -> overall success, various SG_LIB_CAT_* positive values or
 * -1 -> other errors.
 * If success_mask pointer is not NULL then first zeros it. Then set bits
 * 0, 1, 2 and/or 3 if the current, changeable, default and saved values
 * respectively have been fetched. If error on current page
 * then stops and returns that error; otherwise continues if an error is
 * detected but returns the first error encountered.  */
int
sg_get_mode_page_controls(int sg_fd, bool mode6, int pg_code, int sub_pg_code,
                          bool dbd, bool flexible, int mx_mpage_len,
                          int * success_mask, void * pcontrol_arr[],
                          int * reported_lenp, int verbose)
{
    bool resp_mode6;
    int k, n, res, offset, calc_len, xfer_len;
    int resid = 0;
    const int msense10_hlen = MODE10_RESP_HDR_LEN;
    uint8_t buff[MODE_RESP_ARB_LEN];
    char ebuff[EBUFF_SZ];
    int first_err = 0;

    if (success_mask)
        *success_mask = 0;
    if (reported_lenp)
        *reported_lenp = 0;
    if (mx_mpage_len < 4)
        return 0;
    memset(ebuff, 0, sizeof(ebuff));
    /* first try to find length of current page response */
    memset(buff, 0, msense10_hlen);
    if (mode6)  /* want first 8 bytes just in case */
        res = sg_ll_mode_sense6(sg_fd, dbd, 0 /* pc */, pg_code,
                                sub_pg_code, buff, msense10_hlen, true,
                                verbose);
    else        /* MODE SENSE(10) obviously */
        res = sg_ll_mode_sense10_v2(sg_fd, false /* llbaa */, dbd,
                                    0 /* pc */, pg_code, sub_pg_code, buff,
                                    msense10_hlen, 0, &resid, true, verbose);
    if (0 != res)
        return res;
    n = buff[0];
    if (reported_lenp) {
        int m;

        m = sg_msense_calc_length(buff, msense10_hlen, mode6, NULL) - resid;
        if (m < 0)      /* Grrr, this should not happen */
            m = 0;
        *reported_lenp = m;
    }
    resp_mode6 = mode6;
    if (flexible) {
        if (mode6 && (n < 3)) {
            resp_mode6 = false;
            if (verbose)
                pr2ws(">>> msense(6) but resp[0]=%d so try msense(10) "
                      "response processing\n", n);
        }
        if ((! mode6) && (n > 5)) {
            if ((n > 11) && (0 == (n % 2)) && (0 == buff[4]) &&
                (0 == buff[5]) && (0 == buff[6])) {
                buff[1] = n;
                buff[0] = 0;
                if (verbose)
                    pr2ws(">>> msense(10) but resp[0]=%d and not msense(6) "
                          "response so fix length\n", n);
            } else
                resp_mode6 = true;
        }
    }
    if (verbose && (resp_mode6 != mode6))
        pr2ws(">>> msense(%d) but resp[0]=%d so switch response "
              "processing\n", (mode6 ? 6 : 10), buff[0]);
    calc_len = sg_msense_calc_length(buff, msense10_hlen, resp_mode6, NULL);
    if (calc_len > MODE_RESP_ARB_LEN)
        calc_len = MODE_RESP_ARB_LEN;
    offset = sg_mode_page_offset(buff, calc_len, resp_mode6, ebuff, EBUFF_SZ);
    if (offset < 0) {
        if (('\0' != ebuff[0]) && (verbose > 0))
            pr2ws("%s: %s\n", __func__, ebuff);
        return SG_LIB_CAT_MALFORMED;
    }
    xfer_len = calc_len - offset;
    if (xfer_len > mx_mpage_len)
        xfer_len = mx_mpage_len;

    for (k = 0; k < 4; ++k) {
        if (NULL == pcontrol_arr[k])
            continue;
        memset(pcontrol_arr[k], 0, mx_mpage_len);
        resid = 0;
        if (mode6)
            res = sg_ll_mode_sense6(sg_fd, dbd, k /* pc */,
                                    pg_code, sub_pg_code, buff,
                                    calc_len, true, verbose);
        else
            res = sg_ll_mode_sense10_v2(sg_fd, false /* llbaa */, dbd,
                                        k /* pc */, pg_code, sub_pg_code,
                                        buff, calc_len, 0, &resid, true,
                                        verbose);
        if (res || resid) {
            if (0 == first_err) {
                if (res)
                    first_err = res;
                else {
                    first_err = -49;    /* unexpected resid != 0 */
                    if (verbose)
                        pr2ws("%s: unexpected resid=%d, page=0x%x, "
                              "pcontrol=%d\n", __func__, resid, pg_code, k);
                }
            }
            if (0 == k)
                break;  /* if problem on current page, it won't improve */
            else
                continue;
        }
        if (xfer_len > 0)
            memcpy(pcontrol_arr[k], buff + offset, xfer_len);
        if (success_mask)
            *success_mask |= (1 << k);
    }
    return first_err;
}
示例#20
0
/* This is a helper function used by sg_cmds_* implementations after the
 * call to the pass-through. pt_res is returned from do_scsi_pt(). If valid
 * sense data is found it is decoded and output to sg_warnings_strm (def:
 * stderr); depending on the 'noisy' and 'verbose' settings. Returns -2 for
 * "sense" category (may not be fatal), -1 for failed, 0, or a positive
 * number. If 'mx_di_len > 0' then asks pass-through for resid and returns
 * (mx_di_len - resid); otherwise returns 0. So for data-in it should return
 * the actual number of bytes received. For data-out (to device) or no data
 * call with 'mx_di_len' set to 0 or less. If -2 returned then sense category
 * output via 'o_sense_cat' pointer (if not NULL). Note that several sense
 * categories also have data in bytes received; -2 is still returned. */
int
sg_cmds_process_resp(struct sg_pt_base * ptvp, const char * leadin,
                     int pt_res, int mx_di_len, const uint8_t * sbp,
                     bool noisy, int verbose, int * o_sense_cat)
{
    int got, cat, duration, slen, resid, resp_code, sstat;
    bool transport_sense;
    char b[1024];

    if (NULL == leadin)
        leadin = "";
    if (pt_res < 0) {
#ifdef SG_LIB_LINUX
        if (verbose)
            pr2ws("%s: %s os error: %s\n", leadin, pass_through_s,
                  safe_strerror(-pt_res));
        if ((-ENXIO == pt_res) && o_sense_cat) {
            if (verbose > 2)
                pr2ws("map ENXIO to SG_LIB_CAT_NOT_READY\n");
            *o_sense_cat = SG_LIB_CAT_NOT_READY;
            return -2;
        } else if (noisy && (0 == verbose))
            pr2ws("%s: %s os error: %s\n", leadin, pass_through_s,
                  safe_strerror(-pt_res));
#else
        if (noisy || verbose)
            pr2ws("%s: %s os error: %s\n", leadin, pass_through_s,
                  safe_strerror(-pt_res));
#endif
        return -1;
    } else if (SCSI_PT_DO_BAD_PARAMS == pt_res) {
        pr2ws("%s: bad %s setup\n", leadin, pass_through_s);
        return -1;
    } else if (SCSI_PT_DO_TIMEOUT == pt_res) {
        pr2ws("%s: %s timeout\n", leadin, pass_through_s);
        return -1;
    }
    if ((verbose > 2) && ((duration = get_scsi_pt_duration_ms(ptvp)) >= 0))
        pr2ws("      duration=%d ms\n", duration);
    resid = (mx_di_len > 0) ? get_scsi_pt_resid(ptvp) : 0;
    slen = get_scsi_pt_sense_len(ptvp);
    switch ((cat = get_scsi_pt_result_category(ptvp))) {
    case SCSI_PT_RESULT_GOOD:
        if (sbp && (slen > 7)) {
            resp_code = sbp[0] & 0x7f;
            /* SBC referrals can have status=GOOD and sense_key=COMPLETED */
            if (resp_code >= 0x70) {
                if (resp_code < 0x72) {
                    if (SPC_SK_NO_SENSE != (0xf & sbp[2]))
                        sg_err_category_sense(sbp, slen);
                } else if (resp_code < 0x74) {
                    if (SPC_SK_NO_SENSE != (0xf & sbp[1]))
                        sg_err_category_sense(sbp, slen);
                }
            }
        }
        if (mx_di_len > 0) {
            got = mx_di_len - resid;
            if ((verbose > 1) && (resid != 0))
                pr2ws("    %s: %s requested %d bytes (data-in) but got %d "
                      "bytes\n", leadin, pass_through_s, mx_di_len, got);
            if (got >= 0)
                return got;
            else {
                if (verbose)
                    pr2ws("    %s: %s can't get negative bytes, say it got "
                          "none\n", leadin, pass_through_s);
                return 0;
            }
        } else
            return 0;
    case SCSI_PT_RESULT_STATUS: /* other than GOOD and CHECK CONDITION */
        sstat = get_scsi_pt_status_response(ptvp);
        if (o_sense_cat) {
            switch (sstat) {
            case SAM_STAT_RESERVATION_CONFLICT:
                *o_sense_cat = SG_LIB_CAT_RES_CONFLICT;
                return -2;
            case SAM_STAT_CONDITION_MET:
                *o_sense_cat = SG_LIB_CAT_CONDITION_MET;
                return -2;
            case SAM_STAT_BUSY:
                *o_sense_cat = SG_LIB_CAT_BUSY;
                return -2;
            case SAM_STAT_TASK_SET_FULL:
                *o_sense_cat = SG_LIB_CAT_TS_FULL;
                return -2;
            case SAM_STAT_ACA_ACTIVE:
                *o_sense_cat = SG_LIB_CAT_ACA_ACTIVE;
                return -2;
            case SAM_STAT_TASK_ABORTED:
                *o_sense_cat = SG_LIB_CAT_TASK_ABORTED;
                return -2;
            default:
                break;
            }
        }
        if (verbose || noisy) {
            sg_get_scsi_status_str(sstat, sizeof(b), b);
            pr2ws("%s: scsi status: %s\n", leadin, b);
        }
        return -1;
    case SCSI_PT_RESULT_SENSE:
        return sg_cmds_process_helper(leadin, mx_di_len, resid, sbp, slen,
                                      noisy, verbose, o_sense_cat);
    case SCSI_PT_RESULT_TRANSPORT_ERR:
        if (verbose || noisy) {
            get_scsi_pt_transport_err_str(ptvp, sizeof(b), b);
            pr2ws("%s: transport: %s\n", leadin, b);
        }
#ifdef SG_LIB_LINUX
        transport_sense = (slen > 0);
#else
        transport_sense = ((SAM_STAT_CHECK_CONDITION ==
                            get_scsi_pt_status_response(ptvp)) && (slen > 0));
#endif
        if (transport_sense)
            return sg_cmds_process_helper(leadin, mx_di_len, resid, sbp,
                                          slen, noisy, verbose, o_sense_cat);
        else
            return -1;
    case SCSI_PT_RESULT_OS_ERR:
        if (verbose || noisy) {
            get_scsi_pt_os_err_str(ptvp, sizeof(b), b);
            pr2ws("%s: os: %s\n", leadin, b);
        }
        return -1;
    default:
        pr2ws("%s: unknown %s result category (%d)\n", leadin, pass_through_s,
               cat);
        return -1;
    }
}
示例#21
0
/* Returns 0 on success, while positive values are SG_LIB_CAT_* errors
 * (e.g. SG_LIB_CAT_MALFORMED). If OS error, returns negated errno or -1. */
static int
sg_ll_inquiry_com(struct sg_pt_base * ptvp, bool cmddt, bool evpd, int pg_op,
                  void * resp, int mx_resp_len, int timeout_secs,
                  int * residp, bool noisy, int verbose)
{
    int res, ret, k, sense_cat, resid;
    uint8_t inq_cdb[INQUIRY_CMDLEN] = {INQUIRY_CMD, 0, 0, 0, 0, 0};
    uint8_t sense_b[SENSE_BUFF_LEN];
    uint8_t * up;

    if (cmddt)
        inq_cdb[1] |= 0x2;
    if (evpd)
        inq_cdb[1] |= 0x1;
    inq_cdb[2] = (uint8_t)pg_op;
    /* 16 bit allocation length (was 8, increased in spc3r09, 200209) */
    sg_put_unaligned_be16((uint16_t)mx_resp_len, inq_cdb + 3);
    if (verbose) {
        pr2ws("    %s cdb: ", inquiry_s);
        for (k = 0; k < INQUIRY_CMDLEN; ++k)
            pr2ws("%02x ", inq_cdb[k]);
        pr2ws("\n");
    }
    if (resp && (mx_resp_len > 0)) {
        up = (uint8_t *)resp;
        up[0] = 0x7f;   /* defensive prefill */
        if (mx_resp_len > 4)
            up[4] = 0;
    }
    if (timeout_secs <= 0)
        timeout_secs = DEF_PT_TIMEOUT;
    set_scsi_pt_cdb(ptvp, inq_cdb, sizeof(inq_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, -1, timeout_secs, verbose);
    ret = sg_cmds_process_resp(ptvp, inquiry_s, res, mx_resp_len, sense_b,
                               noisy, verbose, &sense_cat);
    resid = get_scsi_pt_resid(ptvp);
    if (residp)
        *residp = resid;
    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 if (ret < 4) {
        if (verbose)
            pr2ws("%s: got too few bytes (%d)\n", __func__, ret);
        ret = SG_LIB_CAT_MALFORMED;
    } else
        ret = 0;

    if (resid > 0) {
        if (resid > mx_resp_len) {
            pr2ws("%s resid (%d) should never exceed requested "
                    "len=%d\n", inquiry_s, resid, mx_resp_len);
            return ret ? ret : SG_LIB_CAT_MALFORMED;
        }
        /* zero unfilled section of response buffer, based on resid */
        memset((uint8_t *)resp + (mx_resp_len - resid), 0, resid);
    }
    return ret;
}