예제 #1
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;
}
예제 #2
0
파일: sg_io_linux.c 프로젝트: fortsage/nio
int
sg_err_category_new(int scsi_status, int host_status, int driver_status,
                    const unsigned char * sense_buffer, int sb_len)
{
    int masked_driver_status = (SG_LIB_DRIVER_MASK & driver_status);

    scsi_status &= 0x7e;
    if ((0 == scsi_status) && (0 == host_status) &&
        (0 == masked_driver_status))
        return SG_LIB_CAT_CLEAN;
    if ((SAM_STAT_CHECK_CONDITION == scsi_status) ||
        (SAM_STAT_COMMAND_TERMINATED == scsi_status) ||
        (SG_LIB_DRIVER_SENSE == masked_driver_status))
        return sg_err_category_sense(sense_buffer, sb_len);
    if (0 != host_status) {
        if ((SG_LIB_DID_NO_CONNECT == host_status) ||
            (SG_LIB_DID_BUS_BUSY == host_status) ||
            (SG_LIB_DID_TIME_OUT == host_status))
            return SG_LIB_CAT_TIMEOUT;
    }
    if (SG_LIB_DRIVER_TIMEOUT == masked_driver_status)
        return SG_LIB_CAT_TIMEOUT;
    return SG_LIB_CAT_OTHER;
}
예제 #3
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;
    }
}
예제 #4
0
int main(int argc, char * argv[])
{
    int bsg_fd, k, ok;
    unsigned char inqCmdBlk[INQ_CMD_LEN] =
                                {0x12, 0, 0, 0, INQ_REPLY_LEN, 0};
    unsigned char sdiagCmdBlk[SDIAG_CMD_LEN] =
                                {0x1d, 0, 0, 0, 0, 0};
    unsigned char inqBuff[16][INQ_REPLY_LEN];
    struct sg_io_v4 io_hdr[16];
    struct sg_io_v4 rio_hdr;
    char * file_name = 0;
    char ebuff[EBUFF_SZ];
    unsigned char sense_buffer[16][SENSE_BUFFER_LEN];
    int q_at_tail = 0;

    for (k = 1; k < argc; ++k) {
        if (0 == memcmp("-t", argv[k], 2))
            ++q_at_tail;
        else if (*argv[k] == '-') {
            printf("Unrecognized switch: %s\n", argv[k]);
            file_name = 0;
            break;
        }
        else if (0 == file_name)
            file_name = argv[k];
        else {
            printf("too many arguments\n");
            file_name = 0;
            break;
        }
    }
    if (0 == file_name) {
        printf("Usage: 'bsg_queue_tst [-t] <bsg_device>'\n"
               "where:\n      -t   queue_at_tail (def: q_at_head)\n");
        return 1;
    }

    /* An access mode of O_RDWR is required for write()/read() interface */
    if ((bsg_fd = open(file_name, O_RDWR)) < 0) {
        snprintf(ebuff, EBUFF_SZ,
                 "bsg_queue_tst: error opening file: %s", file_name);
        perror(ebuff);
        return 1;
    }

    for (k = 0; k < 16; ++k) {
        /* Prepare INQUIRY command */
        memset(&io_hdr[k], 0, sizeof(struct sg_io_v4));
        io_hdr[k].guard = 'Q';
        /* io_hdr[k].iovec_count = 0; */  /* memset takes care of this */
        if (0 == (k % 3)) {
            io_hdr[k].request_len = sizeof(sdiagCmdBlk);
            io_hdr[k].request = (uint64_t)(long)sdiagCmdBlk;
        } else {
            io_hdr[k].request_len = sizeof(inqCmdBlk);
            io_hdr[k].request = (uint64_t)(long)inqCmdBlk;
            io_hdr[k].din_xfer_len = INQ_REPLY_LEN;
            io_hdr[k].din_xferp = (uint64_t)(long)inqBuff[k];
        }
        io_hdr[k].response = (uint64_t)(long)sense_buffer[k];
        io_hdr[k].max_response_len = SENSE_BUFFER_LEN;
        io_hdr[k].timeout = 20000;     /* 20000 millisecs == 20 seconds */
        io_hdr[k].usr_ptr = k;
        /* default is to queue at head (in SCSI mid level) */
        if (q_at_tail)
            io_hdr[k].flags |= BSG_FLAG_Q_AT_TAIL;
        else
            io_hdr[k].flags |= BSG_FLAG_Q_AT_HEAD;

        if (write(bsg_fd, &io_hdr[k], sizeof(struct sg_io_v4)) < 0) {
            perror("bsg_queue_tst: bsg write error");
            close(bsg_fd);
            return 1;
        }
    }
    /* sleep(3); */
    for (k = 0; k < 16; ++k) {
        memset(&rio_hdr, 0, sizeof(struct sg_io_v4));
        rio_hdr.guard = 'Q';
        if (read(bsg_fd, &rio_hdr, sizeof(struct sg_io_v4)) < 0) {
            perror("bsg_queue_tst: bsg read error");
            close(bsg_fd);
            return 1;
        }
        /* now for the error processing */
        ok = 0;
        if (0 == rio_hdr.device_status)
            ok = 1;
        else {
            switch (sg_err_category_sense((unsigned char *)(long)
                    rio_hdr.response, rio_hdr.response_len)) {
            case SG_LIB_CAT_CLEAN:
                ok = 1;
                break;
            case SG_LIB_CAT_RECOVERED:
                printf("Recovered error, continuing\n");
                ok = 1;
                break;
            default: /* won't bother decoding other categories */
                fprintf(stderr, "command error:\n");
                sg_print_sense(NULL, (unsigned char *)(long)rio_hdr.response,
                               rio_hdr.response_len, 1);
                break;
            }
        }

        if (ok) { /* output result if it is available */
            /* if (0 == rio_hdr.pack_id) */
            if (0 == (rio_hdr.usr_ptr % 3))
                printf("SEND DIAGNOSTIC %d duration=%u\n",
                       (int)rio_hdr.usr_ptr, rio_hdr.duration);
            else
                printf("INQUIRY %d duration=%u\n", (int)rio_hdr.usr_ptr,
                       rio_hdr.duration);
        }
    }

    close(bsg_fd);
    return 0;
}
예제 #5
0
파일: sg_raw.c 프로젝트: fortsage/nio
int
main(int argc, char *argv[])
{
    int ret = 0;
    int res_cat, status, slen, k, ret2;
    int sg_fd = -1;
    struct sg_pt_base *ptvp = NULL;
    unsigned char sense_buffer[32];
    unsigned char * dxfer_buffer_in = NULL;
    unsigned char * dxfer_buffer_out = NULL;
    unsigned char *wrkBuf = NULL;
    struct opts_t opts;
    struct opts_t * op;
    char b[128];

    op = &opts;
    memset(op, 0, sizeof(opts));
    op->timeout = DEFAULT_TIMEOUT;
    ret = process_cl(op, argc, argv);
    if (ret != 0) {
        usage();
        goto done;
    } else if (op->do_help) {
        usage();
        goto done;
    } else if (op->do_version) {
        version();
        goto done;
    }

    sg_fd = scsi_pt_open_device(op->device_name, op->readonly,
                                op->do_verbose);
    if (sg_fd < 0) {
        fprintf(stderr, "%s: %s\n", op->device_name, safe_strerror(-sg_fd));
        ret = SG_LIB_FILE_ERROR;
        goto done;
    }

    ptvp = construct_scsi_pt_obj();
    if (ptvp == NULL) {
        fprintf(stderr, "out of memory\n");
        ret = SG_LIB_CAT_OTHER;
        goto done;
    }
    if (op->do_verbose) {
        fprintf(stderr, "    cdb to send: ");
        for (k = 0; k < op->cdb_length; ++k)
            fprintf(stderr, "%02x ", op->cdb[k]);
        fprintf(stderr, "\n");
        if (op->do_verbose > 2) {
            sg_get_command_name(op->cdb, 0, sizeof(b) - 1, b);
            b[sizeof(b) - 1] = '\0';
            fprintf(stderr, "    Command name: %s\n", b);
        }
    }
    set_scsi_pt_cdb(ptvp, op->cdb, op->cdb_length);
    set_scsi_pt_sense(ptvp, sense_buffer, sizeof(sense_buffer));

    if (op->do_dataout) {
        dxfer_buffer_out = fetch_dataout(op);
        if (dxfer_buffer_out == NULL) {
            ret = SG_LIB_CAT_OTHER;
            goto done;
        }
        set_scsi_pt_data_out(ptvp, dxfer_buffer_out, op->dataout_len);
    }
    if (op->do_datain) {
        dxfer_buffer_in = my_memalign(op->datain_len, &wrkBuf);
        if (dxfer_buffer_in == NULL) {
            perror("malloc");
            ret = SG_LIB_CAT_OTHER;
            goto done;
        }
        set_scsi_pt_data_in(ptvp, dxfer_buffer_in, op->datain_len);
    }

    ret = do_scsi_pt(ptvp, sg_fd, op->timeout, op->do_verbose);
    if (ret > 0) {
        if (SCSI_PT_DO_BAD_PARAMS == ret) {
            fprintf(stderr, "do_scsi_pt: bad pass through setup\n");
            ret = SG_LIB_CAT_OTHER;
        } else if (SCSI_PT_DO_TIMEOUT == ret) {
            fprintf(stderr, "do_scsi_pt: timeout\n");
            ret = SG_LIB_CAT_TIMEOUT;
        } else
            ret = SG_LIB_CAT_OTHER;
        goto done;
    } else if (ret < 0) {
        fprintf(stderr, "do_scsi_pt: %s\n", safe_strerror(-ret));
        ret = SG_LIB_CAT_OTHER;
        goto done;
    }

    slen = 0;
    res_cat = get_scsi_pt_result_category(ptvp);
    switch (res_cat) {
    case SCSI_PT_RESULT_GOOD:
        ret = 0;
        break;
    case SCSI_PT_RESULT_SENSE:
        slen = get_scsi_pt_sense_len(ptvp);
        ret = sg_err_category_sense(sense_buffer, slen);
        break;
    case SCSI_PT_RESULT_TRANSPORT_ERR:
        get_scsi_pt_transport_err_str(ptvp, sizeof(b), b);
        fprintf(stderr, ">>> transport error: %s\n", b);
        ret = SG_LIB_CAT_OTHER;
        break;
    case SCSI_PT_RESULT_OS_ERR:
        get_scsi_pt_os_err_str(ptvp, sizeof(b), b);
        fprintf(stderr, ">>> os error: %s\n", b);
        ret = SG_LIB_CAT_OTHER;
        break;
    default:
        fprintf(stderr, ">>> unknown pass through result category (%d)\n",
                res_cat);
        ret = SG_LIB_CAT_OTHER;
        break;
    }

    status = get_scsi_pt_status_response(ptvp);
    fprintf(stderr, "SCSI Status: ");
    sg_print_scsi_status(status);
    fprintf(stderr, "\n\n");
    if ((SAM_STAT_CHECK_CONDITION == status) && (! op->no_sense)) {
        if (SCSI_PT_RESULT_SENSE != res_cat)
            slen = get_scsi_pt_sense_len(ptvp);
        if (0 == slen)
            fprintf(stderr, ">>> Strange: status is CHECK CONDITION but no "
                    "Sense Information\n");
        else {
            fprintf(stderr, "Sense Information:\n");
            sg_print_sense(NULL, sense_buffer, slen, (op->do_verbose > 0));
            fprintf(stderr, "\n");
        }
    }
    if (SAM_STAT_RESERVATION_CONFLICT == status)
        ret = SG_LIB_CAT_RES_CONFLICT;

    if (op->do_datain) {
        int data_len = op->datain_len - get_scsi_pt_resid(ptvp);

        if (ret && !(SG_LIB_CAT_RECOVERED == ret ||
                     SG_LIB_CAT_NO_SENSE == ret))
            fprintf(stderr, "Error %d occurred, no data received\n", ret);
        else if (data_len == 0) {
            fprintf(stderr, "No data received\n");
        } else {
            if (op->datain_file == NULL && !op->datain_binary) {
                fprintf(stderr, "Received %d bytes of data:\n", data_len);
                dStrHexErr((const char *)dxfer_buffer_in, data_len, 0);
            } else {
                const char * cp = "stdout";

                if (op->datain_file &&
                    ! ((1 == strlen(op->datain_file)) &&
                       ('-' == op->datain_file[0])))
                    cp = op->datain_file;
                fprintf(stderr, "Writing %d bytes of data to %s\n", data_len,
                        cp);
                ret2 = write_dataout(op->datain_file, dxfer_buffer_in,
                                     data_len);
                if (0 != ret2) {
                    if (0 == ret)
                        ret = ret2;
                    goto done;
                }
            }
        }
    }

done:
    if (op->do_verbose) {
        sg_get_category_sense_str(ret, sizeof(b), b, op->do_verbose - 1);
        fprintf(stderr, "%s\n", b);
    }
    if (wrkBuf)
        free(wrkBuf);
    if (ptvp)
        destruct_scsi_pt_obj(ptvp);
    if (sg_fd >= 0)
        scsi_pt_close_device(sg_fd);
    return ret;
}